[Freeswitch-svn] [commit] r3774 - in freeswitch/trunk: libs/sofia-sip libs/sofia-sip/docs libs/sofia-sip/libsofia-sip-ua libs/sofia-sip/libsofia-sip-ua-glib libs/sofia-sip/libsofia-sip-ua-glib/docs libs/sofia-sip/libsofia-sip-ua-glib/su-glib libs/sofia-sip/libsofia-sip-ua-glib/su-glib/sofia-sip libs/sofia-sip/libsofia-sip-ua/bnf libs/sofia-sip/libsofia-sip-ua/bnf/sofia-sip libs/sofia-sip/libsofia-sip-ua/docs libs/sofia-sip/libsofia-sip-ua/docs/pictures libs/sofia-sip/libsofia-sip-ua/features libs/sofia-sip/libsofia-sip-ua/features/sofia-sip libs/sofia-sip/libsofia-sip-ua/http libs/sofia-sip/libsofia-sip-ua/http/sofia-sip libs/sofia-sip/libsofia-sip-ua/ipt libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip libs/sofia-sip/libsofia-sip-ua/iptsec libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip libs/sofia-sip/libsofia-sip-ua/msg libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip libs/sofia-sip/libsofia-sip-ua/nea libs/sofia-sip/libsofia-sip-ua/nea/sofia-sip libs/sofia-sip/libsofia-sip-ua/nta libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip libs/sofia-sip/libsofia-sip-ua/nth libs/sofia-sip/libsofia-sip-ua/nth/sofia-sip libs/sofia-sip/libsofia-sip-ua/nua libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip libs/sofia-sip/libsofia-sip-ua/sdp libs/sofia-sip/libsofia-sip-ua/sdp/sofia-sip libs/sofia-sip/libsofia-sip-ua/sdp/tests libs/sofia-sip/libsofia-sip-ua/sip libs/sofia-sip/libsofia-sip-ua/sip/images libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip libs/sofia-sip/libsofia-sip-ua/sip/tests libs/sofia-sip/libsofia-sip-ua/soa libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip libs/sofia-sip/libsofia-sip-ua/sresolv libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-sip libs/sofia-sip/libsofia-sip-ua/stun libs/sofia-sip/libsofia-sip-ua/stun/sofia-sip libs/sofia-sip/libsofia-sip-ua/su libs/sofia-sip/libsofia-sip-ua/su/sofia-sip libs/sofia-sip/libsofia-sip-ua/tport libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip libs/sofia-sip/libsofia-sip-ua/url libs/sofia-sip/libsofia-sip-ua/url/sofia-sip libs/sofia-sip/m4 libs/sofia-sip/packages libs/sofia-sip/scripts libs/sofia-sip/utils libs/sofia-sip/win32 libs/sofia-sip/win32/libsofia-sip-ua libs/sofia-sip/win32/libsofia-sip-ua-static libs/sofia-sip/win32/sofia-sip libs/sofia-sip/win32/tests libs/sofia-sip/win32/tests/test_htable libs/sofia-sip/win32/tests/test_memmem libs/sofia-sip/win32/tests/test_nta libs/sofia-sip/win32/tests/test_nua libs/sofia-sip/win32/tests/test_su libs/sofia-sip/win32/tests/test_tport libs/sofia-sip/win32/tests/torture_rbtree libs/sofia-sip/win32/tests/torture_su libs/sofia-sip/win32/tests/torture_su_alloc libs/sofia-sip/win32/tests/torture_su_bm libs/sofia-sip/win32/tests/torture_su_port libs/sofia-sip/win32/tests/torture_su_root libs/sofia-sip/win32/tests/torture_su_tag libs/sofia-sip/win32/tests/torture_su_time libs/sofia-sip/win32/tests/torture_su_timer libs/sofia-sip/win32/utils libs/sofia-sip/win32/utils/localinfo libs/sofia-sip/win32/utils/sip_dig libs/sofia-sip/win32/utils/sip_options libs/sofia-sip/win32/utils/sip_options_static libs/sofia-sip/win32/utils/stunc src/mod/endpoints/mod_sofia
Freeswitch SVN
mikej at freeswitch.org
Thu Dec 21 01:30:40 EST 2006
Author: mikej
Date: Thu Dec 21 01:30:28 2006
New Revision: 3774
Added:
freeswitch/trunk/libs/sofia-sip/ (props changed)
freeswitch/trunk/libs/sofia-sip/AUTHORS
freeswitch/trunk/libs/sofia-sip/COPYING
freeswitch/trunk/libs/sofia-sip/COPYRIGHTS
freeswitch/trunk/libs/sofia-sip/ChangeLog
freeswitch/trunk/libs/sofia-sip/ChangeLog.ext-trees
freeswitch/trunk/libs/sofia-sip/Makefile.am
freeswitch/trunk/libs/sofia-sip/Makefile.in
freeswitch/trunk/libs/sofia-sip/README
freeswitch/trunk/libs/sofia-sip/README.developers
freeswitch/trunk/libs/sofia-sip/RELEASE
freeswitch/trunk/libs/sofia-sip/RELEASE.template
freeswitch/trunk/libs/sofia-sip/TODO
freeswitch/trunk/libs/sofia-sip/aclocal.m4
freeswitch/trunk/libs/sofia-sip/autogen.sh
freeswitch/trunk/libs/sofia-sip/compile (contents, props changed)
freeswitch/trunk/libs/sofia-sip/config.guess (contents, props changed)
freeswitch/trunk/libs/sofia-sip/config.h.in
freeswitch/trunk/libs/sofia-sip/config.sub (contents, props changed)
freeswitch/trunk/libs/sofia-sip/configure (contents, props changed)
freeswitch/trunk/libs/sofia-sip/configure.ac
freeswitch/trunk/libs/sofia-sip/depcomp (contents, props changed)
freeswitch/trunk/libs/sofia-sip/docs/
freeswitch/trunk/libs/sofia-sip/docs/build_system.txt
freeswitch/trunk/libs/sofia-sip/docs/devel_platform_notes.txt
freeswitch/trunk/libs/sofia-sip/docs/release_management.txt
freeswitch/trunk/libs/sofia-sip/install-sh (contents, props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ (props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/ (props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/ChangeLog
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/Makefile.am
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/Makefile.in
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/docs/
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/docs/Doxyfile.aliases
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/docs/Doxyfile.conf
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/docs/Doxyfile.version
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/ (props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/Doxyfile
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/Makefile.am
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/Makefile.in
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/sofia-sip/
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/sofia-sip/su_glib.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/sofia-sip/su_source.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/su_glib.docs
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/su_source.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/su_source_test.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ChangeLog
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/Makefile.am
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/Makefile.in
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/ (props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/ChangeLog
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/Doxyfile
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/Makefile.am
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/Makefile.in
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/bnf.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/bnf.docs
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/sofia-sip/
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/sofia-sip/bnf.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/sofia-sip/hostdomain.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/torture_bnf.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/ (props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/ChangeLog
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/Doxyfile
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/Doxyfile.aliases
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/Doxyfile.conf
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/Doxyfile.version.in
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/Makefile.am
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/Makefile.in
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/conformance.docs
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/docguide.docs
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/hide_emails.sh
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/mainpage.docs
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_basic_incoming_operation.eps (contents, props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_basic_incoming_operation.gif (contents, props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_basic_incoming_operation.vsd (contents, props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_basic_outgoing_operation.eps (contents, props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_basic_outgoing_operation.gif (contents, props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_basic_outgoing_operation.vsd (contents, props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_incoming_call.eps (contents, props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_incoming_call.gif (contents, props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_incoming_call.vsd (contents, props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_outgoing_call.eps (contents, props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_outgoing_call.gif (contents, props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_outgoing_call.vsd (contents, props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_outgoing_operation_with_auth.eps (contents, props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_outgoing_operation_with_auth.gif (contents, props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_outgoing_operation_with_auth.vsd (contents, props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/autotools.eps (contents, props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/autotools.gif (contents, props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/autotools.vsd (contents, props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/nta-receiving-message.eps (contents, props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/nta-receiving-message.gif (contents, props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/sofia-footer.html.in
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/ (props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/ChangeLog
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/Doxyfile
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/Makefile.am
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/Makefile.in
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/features.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/features.docs
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/sofia-sip/ (props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/sofia-sip/sofia_features.h.in
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/ (props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/ChangeLog
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/Doxyfile
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/Makefile.am
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/Makefile.in
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/headers
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http.def.in
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http.docs
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_basic.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_extra.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_header.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_parser.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_parser_table.c.in
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_status.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_tag.c.in
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_tag_class.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/ (props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_hclasses.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_header.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_parser.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_protos.h.in
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_status.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_tag.h.in
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_tag_class.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/test_http.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/ (props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/ChangeLog
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/Doxyfile
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/Makefile.am
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/Makefile.in
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/base64.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/ipt.docs
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/rc4.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/base64.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/rc4.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/string0.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/token64.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/uniqueid.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/utf8.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/string0.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/token64.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/torture_base64.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/ucs2.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/ucs4.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/utf8.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/utf8internal.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/utf8test.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/ (props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/ChangeLog
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/Doxyfile
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/Makefile.am
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/Makefile.in
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_client.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_client_ntlm.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_common.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_digest.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_module.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_module_http.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_module_sip.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_ntlm.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_plugin.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_plugin_delayed.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_plugin_ntlm.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_tag.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/iptsec.docs
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/iptsec_debug.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/iptsec_debug.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_client.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_client_plugin.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_common.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_digest.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_module.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_ntlm.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_plugin.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/test_auth_digest.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/testpasswd
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/ (props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/ChangeLog
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/Doxyfile
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/Makefile.am
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/Makefile.in
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg.docs
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_auth.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_basic.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_date.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_generic.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_header_copy.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_header_make.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_internal.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_mclass.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_mime.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_mime_table.c.in
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_name_hash.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_parser.awk
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_parser.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_parser_util.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_tag.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/ (props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_addr.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_buffer.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_date.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_header.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mclass.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mclass_hash.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mime.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mime_protos.h.in
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_parser.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_protos.h.in
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_tag_class.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_types.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/test_class.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/test_class.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/test_msg.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/test_protos.h.in
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/test_table.c.in
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/ (props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/ChangeLog
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/Doxyfile
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/Makefile.am
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/Makefile.in
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/nea.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/nea.docs
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/nea_debug.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/nea_debug.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/nea_event.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/nea_server.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/nea_tag.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/sofia-sip/
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/sofia-sip/nea.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/sofia-sip/nea_tag.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/ (props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/ChangeLog
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/Doxyfile
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/Makefile.am
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/Makefile.in
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/agent.pem
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/cafile.pem
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/invite.msc
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta.docs
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta_check.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta_compat.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta_compat.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta_internal.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta_tag.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/portbind.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/run_test_nta
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/run_test_nta_api
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sl_read_payload.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sl_utils.docs
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sl_utils_log.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sl_utils_print.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/nta.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/nta_stateless.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/nta_tag.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/nta_tport.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/sl_utils.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/test_nta.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/test_nta_api.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/ (props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/ChangeLog
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/Doxyfile
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/Makefile.am
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/Makefile.in
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/agent.pem
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/cafile.pem
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/http-client.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/http-server.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/nth.docs
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/nth_client.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/nth_server.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/nth_tag.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/sofia-sip/
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/sofia-sip/nth.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/sofia-sip/nth_tag.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/test_nth.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/ (props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/ChangeLog
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/Doxyfile
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/Makefile.am
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/Makefile.in
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua.docs
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_common.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_event_server.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_extension.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_message.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_notifier.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_options.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_publish.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_register.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_registrar.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_subnotref.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_tag.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/outbound.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/outbound.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua_tag.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_100rel.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_basic_call.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_call_hold.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_call_reject.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_cancel_bye.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_extension.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_init.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nat.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nat.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nat_tags.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nua.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nua.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nua_api.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nua_params.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_ops.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_refer.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_register.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_session_timer.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_simple.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_sip_events.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/ (props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/ChangeLog
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/Doxyfile
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/Makefile.am
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/Makefile.in
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/README
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/errata
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/rfc2327.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/run_test_sdp
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sdp.bnf
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sdp.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sdp.docs
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_parse.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_print.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_tag.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sofia-sip/
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sofia-sip/sdp.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sofia-sip/sdp_tag.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/test_sdp.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-1.sdp
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-10.sdp
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-2.sdp
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-3.sdp
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-4.sdp
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-5.sdp
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-6.sdp
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-7.sdp
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-8.sdp
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-9.sdp
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/torture_sdp.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/ (props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/ADD-A-HEADER
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/ChangeLog
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/Doxyfile
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/GRAMMAR
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/Makefile.am
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/Makefile.in
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/date_test.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/images/
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser.eps (contents, props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser.gif (contents, props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser2.eps (contents, props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser2.gif (contents, props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser3.eps (contents, props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser3.gif (contents, props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser4.eps (contents, props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser4.gif (contents, props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/rfc2543.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/run-tests
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/run_date_test
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip.docs
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip.doxyaliases
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_bad_mask
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_basic.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_caller_prefs.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_event.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_extra.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_extra_headers.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_feature.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_header.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_mime.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_parser.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_parser.docs
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_parser_table.c.in
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_prack.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_pref_util.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_reason.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_refer.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_security.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_session.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_status.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_tag.c.in
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_tag_class.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_time.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_util.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/ (props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_extra.h.in
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_hclasses.h.in
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_header.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_parser.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_protos.h.in
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_status.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_tag.h.in
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_tag_class.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_util.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own0.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own1.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own2.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own3.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own4.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own5.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own6.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own8.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test-ack-1.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test1.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test10.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test10b.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test10c.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test11.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test12.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test13.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test14-req.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test14.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test15.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test16.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test17.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test18.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test19.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test1a.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test2.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test20.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test21.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test22.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test23.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test24.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test25.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test26.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test27.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test28.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test29.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test3.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test30.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test31.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test32.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test33.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test34.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test35.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test36.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test37.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test38.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test39.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test4.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test40.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test41.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test42.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test5.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test6.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test7.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test8.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test9.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/torture_sip.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/validator.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/ (props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/ChangeLog
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/Doxyfile
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/Makefile.am
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/Makefile.in
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/soa.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/soa.docs
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/soa_asynch.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/soa_static.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/soa_tag.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa_add.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa_session.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa_tag.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/test_soa.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sofia.am
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/ (props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/127.zone
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/194.2.188
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/3.f.f.e.1.2.0.0.3.0.1.2.c.0.0.0
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/3.f.f.e.1.2.0.0.3.0.1.2.c.0.0.0.arpa
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/ChangeLog
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/Doxyfile
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/Makefile.am
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/Makefile.in
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/example.com
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/named.conf
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/resolv_timeout.conf
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/resolve_sip.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/rfc1034.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/rfc1035.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/rfc2671.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/rndc.conf
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/root.zone
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/run_test_sresolv
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv/
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv/sres.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv/sres_async.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv/sres_cache.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv/sres_config.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv/sres_record.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-sip/
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-sip/sresolv.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sres.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sres_blocking.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sres_cache.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sresolv.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sresolv.docs
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/test_sresolv.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/ (props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/ChangeLog
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/Doxyfile
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/Makefile.am
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/Makefile.in
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/cert.pem
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/key.pem
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/lookup_stun_server.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/rfc3489.txt
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/sofia-sip/
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/sofia-sip/stun.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/sofia-sip/stun_common.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/sofia-sip/stun_tag.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stun.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stun.docs
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stun_common.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stun_dns.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stun_internal.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stun_mini.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stun_tag.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stunc.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/ (props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/ChangeLog
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/Doxyfile
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/Makefile.am
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/Makefile.in
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/addrinfo.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/getopt.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/inet_ntop.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/inet_pton.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/localinfo.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/memccpy.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/memcspn.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/memmem.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/memspn.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/run_addrinfo
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/run_localinfo
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/run_test_su
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/ (props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/htable.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/htable2.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/rbtree.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_addrinfo.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_alloc.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_alloc_stat.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_bm.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_config.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_configure.h.in
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_debug.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_errno.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_localinfo.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_log.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_md5.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_os_nw.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_osx_runloop.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_strlst.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tag.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tag_class.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tag_inline.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tag_io.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tagarg.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_time.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_types.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_uniqueid.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_vector.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_wait.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/tstdef.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/strcasestr.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/strtoull.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su.docs
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_addrinfo.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_alloc.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_alloc_lock.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_bm.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_default_log.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_errno.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_global_log.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_localinfo.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_log.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_md5.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_module_debug.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_os_nw.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_osx_runloop.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_perf.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_port.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_port.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_proxy.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_root.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_sprintf.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_strdup.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_strlst.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_tag.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_tag_io.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_taglist.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_time.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_time0.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_timer.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_uniqueid.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_vector.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_wait.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/tag_dll.awk
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/test_htable.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/test_memmem.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/test_poll.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/test_su.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/test_su_osx.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_rbtree.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_alloc.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_bm.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_port.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_root.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_root_osx.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_tag.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_time.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_timer.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/ (props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/ChangeLog
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/Doxyfile
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/Makefile.am
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/Makefile.in
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/agent.pem
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/cafile.pem
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/certificates.html
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/make_node_cert.pl
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/make_root_cert.pl
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/make_test_certs.sh
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport_plugins.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport_tag.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/test_tport.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tls_test_client.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tls_test_server.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport.docs
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_internal.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_logging.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_rand.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_sigcomp.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_stub_sigcomp.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_stub_stun.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_tag.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_threadpool.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_tls.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_tls.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_tls_test.sh
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_connect.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_sctp.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_stun.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_tcp.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_tls.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_udp.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/ (props changed)
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/ChangeLog
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/Doxyfile
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/Makefile.am
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/Makefile.in
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/sofia-sip/
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/sofia-sip/url.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/sofia-sip/url_tag.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/sofia-sip/url_tag_class.h
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/torture_url.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/url.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/url.docs
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/url_tag.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/urlmap.c
freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/urlmap.h
freeswitch/trunk/libs/sofia-sip/ltmain.sh (contents, props changed)
freeswitch/trunk/libs/sofia-sip/m4/
freeswitch/trunk/libs/sofia-sip/m4/sac-general.m4
freeswitch/trunk/libs/sofia-sip/m4/sac-openssl.m4
freeswitch/trunk/libs/sofia-sip/m4/sac-su.m4
freeswitch/trunk/libs/sofia-sip/m4/sac-su2.m4
freeswitch/trunk/libs/sofia-sip/m4/sac-tport.m4
freeswitch/trunk/libs/sofia-sip/missing (contents, props changed)
freeswitch/trunk/libs/sofia-sip/packages/ (props changed)
freeswitch/trunk/libs/sofia-sip/packages/ChangeLog
freeswitch/trunk/libs/sofia-sip/packages/Makefile.am
freeswitch/trunk/libs/sofia-sip/packages/Makefile.in
freeswitch/trunk/libs/sofia-sip/packages/sofia-sip-ua-glib.pc.in
freeswitch/trunk/libs/sofia-sip/packages/sofia-sip-ua.pc.in
freeswitch/trunk/libs/sofia-sip/packages/sofia-sip.spec.in
freeswitch/trunk/libs/sofia-sip/scripts/
freeswitch/trunk/libs/sofia-sip/scripts/coverage
freeswitch/trunk/libs/sofia-sip/scripts/fix-include-sofia-sip
freeswitch/trunk/libs/sofia-sip/scripts/rpmbuild-snaphot
freeswitch/trunk/libs/sofia-sip/utils/ (props changed)
freeswitch/trunk/libs/sofia-sip/utils/ChangeLog
freeswitch/trunk/libs/sofia-sip/utils/Doxyfile
freeswitch/trunk/libs/sofia-sip/utils/Doxyfile.build.in
freeswitch/trunk/libs/sofia-sip/utils/Makefile.am
freeswitch/trunk/libs/sofia-sip/utils/Makefile.in
freeswitch/trunk/libs/sofia-sip/utils/apps_utils.h
freeswitch/trunk/libs/sofia-sip/utils/sip-date.c
freeswitch/trunk/libs/sofia-sip/utils/sip-dig.c
freeswitch/trunk/libs/sofia-sip/utils/sip-options.c
freeswitch/trunk/libs/sofia-sip/win32/ (props changed)
freeswitch/trunk/libs/sofia-sip/win32/ChangeLog
freeswitch/trunk/libs/sofia-sip/win32/Makefile.am
freeswitch/trunk/libs/sofia-sip/win32/Makefile.in
freeswitch/trunk/libs/sofia-sip/win32/README.txt
freeswitch/trunk/libs/sofia-sip/win32/SofiaSIP.dsw
freeswitch/trunk/libs/sofia-sip/win32/autogen.cmd
freeswitch/trunk/libs/sofia-sip/win32/build_sources.cmd
freeswitch/trunk/libs/sofia-sip/win32/check.cmd
freeswitch/trunk/libs/sofia-sip/win32/config.h.in
freeswitch/trunk/libs/sofia-sip/win32/install.cmd
freeswitch/trunk/libs/sofia-sip/win32/libsofia-sip-ua/
freeswitch/trunk/libs/sofia-sip/win32/libsofia-sip-ua-static/
freeswitch/trunk/libs/sofia-sip/win32/libsofia-sip-ua-static/libsofia_sip_ua_static.dsp
freeswitch/trunk/libs/sofia-sip/win32/libsofia-sip-ua/libsofia_sip_ua.dsp
freeswitch/trunk/libs/sofia-sip/win32/libsofia-sip-ua/sofia-sip-ua.def
freeswitch/trunk/libs/sofia-sip/win32/sofia-sip/
freeswitch/trunk/libs/sofia-sip/win32/sofia-sip/su_configure.h
freeswitch/trunk/libs/sofia-sip/win32/tests/
freeswitch/trunk/libs/sofia-sip/win32/tests/test_htable/
freeswitch/trunk/libs/sofia-sip/win32/tests/test_htable/test_htable.dsp
freeswitch/trunk/libs/sofia-sip/win32/tests/test_memmem/
freeswitch/trunk/libs/sofia-sip/win32/tests/test_memmem/test_memmem.dsp
freeswitch/trunk/libs/sofia-sip/win32/tests/test_nta/
freeswitch/trunk/libs/sofia-sip/win32/tests/test_nta/test_nta.dsp
freeswitch/trunk/libs/sofia-sip/win32/tests/test_nua/
freeswitch/trunk/libs/sofia-sip/win32/tests/test_nua/test_nat_tags.cpp
freeswitch/trunk/libs/sofia-sip/win32/tests/test_nua/test_nua.dsp
freeswitch/trunk/libs/sofia-sip/win32/tests/test_su/
freeswitch/trunk/libs/sofia-sip/win32/tests/test_su/test_su.dsp
freeswitch/trunk/libs/sofia-sip/win32/tests/test_tport/
freeswitch/trunk/libs/sofia-sip/win32/tests/test_tport/test_class.cpp
freeswitch/trunk/libs/sofia-sip/win32/tests/test_tport/test_table.cpp
freeswitch/trunk/libs/sofia-sip/win32/tests/test_tport/test_tport.dsp
freeswitch/trunk/libs/sofia-sip/win32/tests/torture_rbtree/
freeswitch/trunk/libs/sofia-sip/win32/tests/torture_rbtree/torture_rbtree.dsp
freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su/
freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su/torture_su.dsp
freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_alloc/
freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_alloc/torture_su_alloc.dsp
freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_bm/
freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_bm/torture_su_bm.dsp
freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_port/
freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_port/torture_su_port.dsp
freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_root/
freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_root/torture_su_root.dsp
freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_tag/
freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_tag/torture_su_tag.dsp
freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_time/
freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_time/torture_su_time.dsp
freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_timer/
freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_timer/torture_su_timer.dsp
freeswitch/trunk/libs/sofia-sip/win32/unistd.h
freeswitch/trunk/libs/sofia-sip/win32/utils/
freeswitch/trunk/libs/sofia-sip/win32/utils/localinfo/
freeswitch/trunk/libs/sofia-sip/win32/utils/localinfo/localinfo.dsp
freeswitch/trunk/libs/sofia-sip/win32/utils/sip_dig/
freeswitch/trunk/libs/sofia-sip/win32/utils/sip_dig/sip_dig.dsp
freeswitch/trunk/libs/sofia-sip/win32/utils/sip_options/
freeswitch/trunk/libs/sofia-sip/win32/utils/sip_options/sip_options.dsp
freeswitch/trunk/libs/sofia-sip/win32/utils/sip_options_static/
freeswitch/trunk/libs/sofia-sip/win32/utils/sip_options_static/sip_options_static.dsp
freeswitch/trunk/libs/sofia-sip/win32/utils/stunc/
freeswitch/trunk/libs/sofia-sip/win32/utils/stunc/stunc.dsp
freeswitch/trunk/libs/sofia-sip/win32/version.awk
freeswitch/trunk/libs/sofia-sip/win32/version_files.cmd
Modified:
freeswitch/trunk/src/mod/endpoints/mod_sofia/Makefile
Log:
add sofia-sip 1.12.4 (plus some patches through 12/21/2006) to in tree libs
Added: freeswitch/trunk/libs/sofia-sip/AUTHORS
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/AUTHORS Thu Dec 21 01:30:28 2006
@@ -0,0 +1,21 @@
+Current development team
+------------------------
+
+Pekka Pessi <pekka.pessi -at nokia -dot com>
+Martti Mela <martti.mela -at nokia -dot com>
+Kai Vehmanen <kai.vehmanen -at nokia -dot com>
+
+Contributors (in alphabetical order)
+------------------------------------
+
+Chan, Tat
+Haataja, Mikko
+Jacobs, Remeres
+Jalava, Teemu
+Jerris, Michael <mike -at jerris -dot com>
+Prado, Dimitri E. <dprado -at e3c -dot com -dot br>
+Puustinen, Ismo
+Rinne-Rahkola, Pasi
+Saari, Mika
+Selin, Jari
+Urpalainen, Jari
Added: freeswitch/trunk/libs/sofia-sip/COPYING
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/COPYING Thu Dec 21 01:30:28 2006
@@ -0,0 +1,504 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
Added: freeswitch/trunk/libs/sofia-sip/COPYRIGHTS
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/COPYRIGHTS Thu Dec 21 01:30:28 2006
@@ -0,0 +1,223 @@
+This package contains the Sofia-SIP library.
+
+Copyright (C) 2005-2006 Nokia Corporation and others (see the
+in individual files for a detailed list of copyright holders).
+
+Contact: Pekka Pessi <Pekka.Pessi at nokia.com>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public License
+as published by the Free Software Foundation; either version 2.1 of
+the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License (LICENSE) for more details.
+
+----------------------------------------------------------------------------
+
+libsofia-sip-ua/su/inet_ntop.c
+
+The package also contains files licensed by Internet Software Consortium.
+These files are distributed with the following copyright notice:
+
+Copyright (c) 1996 by Internet Software Consortium.
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+----------------------------------------------------------------------------
+
+libsofia-sip-ua/su/inet_pton.c
+
+The package also contains files licensed by Internet Software Consortium and
+Internet Systems Consortium, Inc.. These files are distributed with the
+following copyright notice:
+
+Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+Copyright (c) 1996,1999 by Internet Software Consortium.
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+----------------------------------------------------------------------------
+
+libsofia-sip-ua/su/sofia-sip/su_addrinfo.h
+libsofia-sip-ua/su/su_addrinfo.c
+
+The package also contains files licensed by WIDE Project. These files are
+distributed with the following copyright notice:
+
+Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. Neither the name of the project nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+----------------------------------------------------------------------------
+
+libsofia-sip-ua/su/getopt.c
+
+The package also contains files licensed by IBM Corporation. These files are
+distributed with the following copyright notice:
+
+ This module contains code made available by IBM
+ Corporation on an AS IS basis. Any one receiving the
+ module is considered to be licensed under IBM copyrights
+ to use the IBM-provided source code in any way he or she
+ deems fit, including copying it, compiling it, modifying
+ it, and redistributing it, with or without
+ modifications. No license under any IBM patents or
+ patent applications is to be implied from this copyright
+ license.
+
+ A user of the module should understand that IBM cannot
+ provide technical support for the module and will not be
+ responsible for any consequences of use of the program.
+
+ Any notices, including this one, are not to be removed
+ from the module without the prior written consent of
+ IBM.
+
+----------------------------------------------------------------------------
+
+libsofia-sip-ua/su/su_md5.c
+
+The package also contains files written by Colin Plumb. These files are
+distributed with the following copyright notice:
+
+This code implements the MD5 message-digest algorithm. The algorithm is due
+to Ron Rivest. This code was initially written by Colin Plumb in 1993, no
+copyright is claimed. This code is in the public domain; do with it what you
+wish.
+
+Equivalent code is available from RSA Data Security, Inc. This code has
+been tested against that, and is equivalent, except that you don't need
+to include two pages of legalese with every copy.
+
+----------------------------------------------------------------------------
+
+libsofia-sip-ua/su/strtoull.c
+
+The package also contains files licensed by University of California and Sun
+Microsystems. These files are distributed with the following copyright
+notice:
+
+Copyright (c) 1988 The Regents of the University of California.
+Copyright (c) 1994 Sun Microsystems, Inc.
+
+The following license.terms for information on usage and redistribution
+of this individual file, and for a DISCLAIMER OF ALL WARRANTIES.
+
+This software is copyrighted by the Regents of the University of
+California, Sun Microsystems, Inc., Scriptics Corporation, ActiveState
+Corporation and other parties. The following terms apply to all files
+associated with the software unless explicitly disclaimed in
+individual files.
+
+The authors hereby grant permission to use, copy, modify, distribute,
+and license this software and its documentation for any purpose, provided
+that existing copyright notices are retained in all copies and that this
+notice is included verbatim in any distributions. No written agreement,
+license, or royalty fee is required for any of the authorized uses.
+Modifications to this software may be copyrighted by their authors
+and need not follow the licensing terms described here, provided that
+the new terms are clearly indicated on the first page of each file where
+they apply.
+
+IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
+FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
+DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
+IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
+NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
+MODIFICATIONS.
+
+GOVERNMENT USE: If you are acquiring this software on behalf of the
+U.S. government, the Government shall have only "Restricted Rights"
+in the software and related documentation as defined in the Federal
+Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you
+are acquiring the software on behalf of the Department of Defense, the
+software shall be classified as "Commercial Computer Software" and the
+Government shall have only "Restricted Rights" as defined in Clause
+252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the
+authors grant the U.S. Government and others acting in its behalf
+permission to use and distribute the software in accordance with the
+terms specified in this license.
+
+----------------------------------------------------------------------------
+
+libsofia-sip-ua/ipt/rc4.c
+
+The package also contains files written by Pekka Pessi. These files are
+distributed with the following copyright notice:
+
+Copyright (c) 1996 Pekka Pessi. All rights reserved.
+
+This source code is provided for unrestricted use. Users may copy or
+modify this source code without charge.
+
+THIS SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND
+INCLUDING THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A
+PARTICULAR PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE
+PRACTICE.
+
+This source code is provided with no support and without any obligation
+on the part of author to assist in its use, correction, modification or
+enhancement.
+
+AUTHOR SHALL HAVE NO LIABILITY WITH RESPECT TO THE INFRINGEMENT OF
+COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE OR ANY PART
+THEREOF.
+
+In no event will author be liable for any lost revenue or profits or
+other special, indirect and consequential damages, even if author has
+been advised of the possibility of such damages.
+
+----------------------------------------------------------------------------
Added: freeswitch/trunk/libs/sofia-sip/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/ChangeLog Thu Dec 21 01:30:28 2006
@@ -0,0 +1,18 @@
+===============================================================
+ChangeLog / Sofia-SIP - SIP User-Agent library
+===============================================================
+
+Sofia-SIP library ChangeLog files are available in the
+following places:
+
+- per subdirectory ChangeLog files
+ - all non-trivial changes to files (unless documented
+ elsewhere)
+- version control system changelogs
+ - darcs and CVS tree repositories (see README.developers
+ for latest repository location information)
+- RELEASE files
+ - changes for the current version store in top-level
+ RELEASE files of the source tree
+ - old RELEASE files available at:
+ http://sofia-sip.sourceforge.net/relnotes/
Added: freeswitch/trunk/libs/sofia-sip/ChangeLog.ext-trees
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/ChangeLog.ext-trees Thu Dec 21 01:30:28 2006
@@ -0,0 +1,4578 @@
+2006-05-12 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Release 1.11.8.
+
+ * Updates for win32.
+ Added SOFIAPUBFUN to few functions in msg_parser().
+ Added new C++ wrappers for C files that need C++ linkage in tport_test.
+ Fixed setlocal braino in build_sources.cmd.
+
+ * Compiling and linking torture_su_bm and torture_su_port as static on win32.
+
+ * Added more warnings to ignore on VC to win32/config.h.in.
+
+ * Added files missing from dist to win32/Makefile.am
+
+ * Added msg_get_address() and msg_set_address() functions to <msg_addr.h>
+ Trying to solve ai_addrlen problem.
+
+ * Put last fixes into RELEASE file.
+
+ * Fixed binding problems in nua and nta.c.
+ Returning more appropriate error code from tport_tbind(), too.
+ This patch fixes tracked bugs
+ #1485624 (nua not binding to 5060),
+ #1485625 (nua_create() fails if STUN init fails) and
+ #1485632 (ncorrect error message for nua bind error).
+ Nua now also binds both to NUTAG_URL and NUTAG_SIPS_URL() URIs, nua_create()
+ fails if binding either of them fails.
+
+ * Fixed msg_addrlen() usage.
+
+ msg_addrlen() returns a pointer to ai_addrlen field of struct addrinfo
+ inside the msg_t object. ai_addrlen has type size_t. However, system calls
+ taking a return valur pointer to address length, use type socklen_t.
+ Typically size_t is unsigned long, socklen_t is int, so casting
+ msg_addrlen() return value to (socklen_t *) will break on (high-endian)
+ 64-bit platforms. svsp.
+
+ * Re-enable natify in test_nua.c.
+
+ * Updated nua_register() and NUTAG_OUTBOUND() documentation.
+ Taking NUTAG_OUTBOUND() options correctly into account in outbound.c.
+ Improved the contact validation process in outbound.c, too.
+
+ * Silenced warnings caused by mismatching integral types.
+ In nua_session, unsigned v. sip_time_t.
+ In tport.c, size_t v. socklen_t.
+
+ * Fixed socket semantics on test_nat.c for BSD, too.
+
+ * Fixed type of msg_addrlen() to size_t in msg_addr.h/msg.c.
+ POSIX socklen_t is not used in addrinfo. We use addrinfo.
+
+ * Added Changes to RELEASE.
+
+ * Fixed DIST_SUBDIRS at toplevel Makefile.am.
+
+ * Fixed AM_LDFLAGS in sresolv/Makefile.am.
+
+ * Not declaring inline functions with global scope in <sofia-sip/http_header.h>
+
+ * Added su_source_create() prototype to su-glib/so_source.c.
+
+2006-05-11 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Added more info about outbound, gruu and win32 DLL to RELEASE.
+
+ * sres.c: storing last dot into the error record, too.
+ Bug reported by Thomas Rosenblatt.
+
+ * Added new files to dist, too.
+ - libsofia-sip-ua/sresolv/sofia-resolv/sres_config.h
+ - win32/libsofia-sip-ua-static/libsofia_sip_ua_static.dsp
+ - win32/tests/test_nua/test_nat_tags.cpp
+
+ * Now building libsofia_sip_ua.dll on win32.
+
+ We define both IN_LIBSOFIA_SIP_UA and IN_LIBSOFIA_SRES in
+ libsofia_sip_ua.dsp.
+
+ Because of DLL linkage, we compile tags typedefs as C++
+ (see win32/tests/test_nua/test_nat_tags.cpp).
+
+ Removed LIBSOFIA_SIP_UA_STATIC from win32/sofia-sip/su_configure.h.
+
+ Added libsofia_sip_ua_static.lib, too. If you want to compile against
+ that, you need define LIBSOFIA_SIP_UA_STATIC by yourself.
+
+ Added libsofia-sip-ua-static/libsofia_sip_ua_static.dsp.
+
+ Using multithreaded DLL runtime for all projects.
+
+ * Added SOFIAPUBFUN/SOFIAPUBVAR to stun module, too.
+
+ * Added test_nat_tags.c to nua module.
+
+ * Fixed a memory leak in nta_outgoing_mcreate().
+
+ * Added SRESPUBFUN and sres_config.h to sresolv module.
+
+ * Updated headers.
+
+ Added sofia-sip/ prefix to documentation entries referring to include files.
+
+ Added SOFIAPUBFUN and SOFIAPUBVAR to files that missed them.
+
+ Removed some deprecated functions and macros.
+
+ * Avoid #include ordering problem with sip_parser.h in sip_test_msg.c, too.
+
+ * Silenced warnings in tport_type_tcp.c.
+
+ * Added @deprecated to deprecated sip functions.
+
+ * Moved ntlm functions to auth_ntlm.h from auth_plugin.h> in iptsec module.
+
+ * Reordered #includes in http module.
+ Avoid #include ordering problem with <sofia-sip/http_parser.h>.
+
+ * Removed utf8 and unicode-related stuff from library.
+
+ Source files are still included in source tar.
+
+ * Reordered #includes in sip module.
+ Avoid #include ordering problem with sip_parser.h.
+
+ * Updated ADD-A-HEADER file in sip module.
+
+ * Added SOFIAPUBFUN and SOFIAPUBVAR to all public nua functions and variables.
+
+2006-05-10 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * nua/outbound.c: Adding Accept-Contact (a) to keepalive OPTIONS, too.
+ Just in case the message gets forwarded.
+
+ * Remove dependency to Makefile in targets for marshal file generation in nua_glib.
+
+ * Fixed includes in outbound.[hc].
+
+ * Added Doxyfiles to libsofia-sip-ua-glib.
+
+ Note that the files are not actually commented.
+
+ * nua, soa: Adding Warnings to the response if appropriate.
+
+ * Refactored outbound code in nua module.
+ Added outbound.c, outbound.h.
+
+ * Added registration refresh tests to test_nua.c.
+ Added command line option --expensive and environment variable
+ EXPENSIVE_CHECKS, too.
+
+ * Updated refreshing of publications in nua_publish.c
+ Added nua_publish_usage_refresh(), nua_publish_usage_shutdown().
+
+ * Updated dialog usage refreshes.
+ Updated nua_dialog_usage_refresh(), nh_call_pending().
+
+ * Added expiration time settings to nua/test_proxy.[hc].
+ Added test_proxy_set_expiration() and test_proxy_get_expiration().
+
+ * Fixed timing problem when testing nat binding change.
+
+2006-05-09 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * nua_register.c: use nua-generated contact for refresh interval calculation.
+ Allow SIPS uris in contacts, too.
+
+ * nua_register.c: ignoring bad received parameters in Via header.
+
+ * Updated config file handling in sresolv/sres.c.
+
+ Using reference counting with config structure when copying
+ resolver objects.
+
+ Trying harder to avoid re-parsing resolv.conf and checking for
+ updated servers.
+
+ Changed SRES_UPDATE_INTERVAL_SECS to 5 for non-WIN32 platforms.
+
+ * su/su_alloc.c, su/sofia-sip/su_alloc.h: su_home_ref() takes const pointer.
+
+2006-05-08 kai.vehmanen at nokia.com
+
+ * Added sip_dig and stunc to VC6/win32 workspace file.
+
+ * Fixed sip_dig errors when building on VC6/win32.
+
+ * Fixed STUN bugs when build with VC6/win32.
+
+ * Updated STUN NAT type check interface to utilize current IETF BEHAVE terms.
+
+ * Print sofia-sip version in stunc usage.
+
+2006-05-08 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * url module: using SOFIAPUBFUN and SOFIAPUBVAR instead of URL_DLL.
+
+ * Fixed overflow problem with su_timer_run().
+ After 25 days the su_timer_run() timer started to misbehave,
+ 1 < <31 milliseconds is bit more than 24 days, 20 hours, 31 minutes...
+
+2006-05-06 kai.vehmanen at nokia.com
+
+ * Pretty-print the NAT type check results with STUN stunc.
+
+ * Do not use resend when doing NAT type checking with STUN. The resends do not currently include the request attribute bytes as they should do.
+
+ * Minor mods to STUN module.
+
+ * Added optional local port randomization to stunc. Making repeated checks from the same local port will produce unreliable results.
+
+ * Fixed STUN's Test-IV.
+
+ * Added lots more documentation about the STUN nattype algorithm. Added a Test-IV step that is improved over the RFC3489 algorithm.
+
+ * Refactored the STUN nattype checks. There are still a few cases where the detection fails.
+
+ * Moved req-specific states to stun.c, moved stun_nattype_t to public header, added documentation to all stun enum fields.
+
+ * Removed deprecated STUN function definitions from stun.c.
+
+2006-05-05 kai.vehmanen at nokia.com
+
+ * Removed commented code segments.
+
+ * nua-glib: added bind URL and STUN server parameters for nua_glib_constructor()
+
+ * Fixed compiler warnings in stun.
+
+ * Removed various deprecated functions that were already commented out from the code. Closed sf.net bug #1456403.
+
+ * Fixed stunc argument parsing. It is now possible to given STUN server address as a hostname instead of requiring a dotted decimal IP-address.
+
+ * Always install auth_ntlm.h as it is needed by auth_client.h.
+
+2006-05-04 kai.vehmanen at nokia.com
+
+ * Updated developer docs w.r.t. VCS system. Darcs is now the
+ primary version control system and sf.net CVS is only used as a
+ backup.
+
+ * Fixed header paths and added missing libraries that caused
+ errors with debug/release builds.
+
+ * Added sip_options to the win32 SofiaSIP workspace.
+
+2006-05-04 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * sres_cache.c: fixed problem using macro as offsetof() argument.
+
+ * test_sresolv.v: added more tests for A6 record parsing.
+
+ * sres.c, sres_cache.c: records are now allocated in a single chunk.
+
+ Bug hunted down by Thomas Rosenblatt: strings and domains belonging to
+ record were allocated from resolver home, not from cache home.
+
+ * Fixed problem with config without search domains in sresolv/sres.c.
+
+ * Added information for COPYRIGHTS file to README.developers.
+
+ * Setting send buffer size to at least 64K in Windows in tport_type_tcp.c.
+
+ * Using SOFIAPUBFUN and SOFIAPUBVAR in bnf.h.
+
+ * Silenced sprious warnings by MSG_HEADER_INIT() in msg_header.h.
+
+ * NUTAG_KEEPALIVE() now uses milliseconds.
+ Changes in sofia-sip/nua_tag.h, nua_params.c, nua_register.c, test_nua.c.
+
+ * Renamed su_create_wait as su_wait_create in
+ libsofia-sip-ua-glib/su-glib/su_source_test.c
+
+ * stun/stun.c: s/su_destroy_timer/su_timer_destroy/.
+
+ * Added sofia-sip/auth_ntlm.h auth_ntlm.c to dist in iptsec module.
+
+ * Added license to Makefiles (kv)
+
+ Added copyright lines and reference to LGPL license to the Makefile.am and
+ configure.ac files.
+
+ * poll_test.c: Renamed call s/su_create_wait/su_wait_create/. (kv)
+
+ * Added libsofia-sip-ua-glib/ChangeLog to darcs (kv)
+
+ * Added win32 registry name server discovery (kv)
+
+ Based on a patch from Dimitri E. Prado.
+ Decreased update interval to 180secs (SRES_UPDATE_INTERVAL_SECS).
+
+2006-05-03 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Not using SU_MSG_RINITIALIZER anymore.
+
+ Fixed nta/nta.c, nth/nth_client.c, su/su_root.c.
+
+ * Added SOFIAPUBFUN and SOFIAPUBVAR to public include files in su
+ module.
+
+ * Not compiling tport_threadpool.c in win32.
+
+ * Updated documentation in sip/sip_util.c.
+
+ Updated sip_contact_create_from_via(),
+ sip_contact_string_from_via(), and
+ sip_contact_create_from_via_with_transport() documents.
+
+ * Added _sips._udp SRV records to sresolv/example.com zonefile.
+
+ Updated named.conf so it can be directly used to run bind.
+
+ * Added public prototype for tport_is_dgram() into
+ <sofia-sip/tport.h>.
+
+ * Added nta_outgoing_transport() to nta/nta.c and
+ <sofia-sip/nta_tport.h>.
+
+ * nua module:
+
+ * Improved keepalive timeout handling in nua/nua_register.c.
+
+ * Fixed double free in nua/nua_register.c.
+
+ Let nua_stack_process_response() take care of removing REGISTER
+ dialog usage.
+
+ * Checking for Max-Forwards header and its contents in
+ nua/test_proxy.c.
+
+ * Fixed STUN_ERROR() macro in <stun/stun_internal.h>.
+
+ * Fixed invalid check by nua_stack_init_instance() in
+ nua/nua_params.c.
+
+ * Updated nua/test_nua.c.
+
+ Using nat by default. Added --symmetric and -N options, enabling
+ symmetric nat and logging, respectively.
+
+ * Added tags to nua/test_nat.[hc].
+
+ TESTNATTAG_SYMMETRIC(1) enables symmetric nat.
+ TESTNATTAG_LOGGING(1) enables logging of nat binding changes.
+
+ * Updated outbound protocol engine in nua/nua_register.c
+
+ We enable rport and disable outbound by default. Fixed problem
+ when nat binding was changed. Fixed syntax error problems when
+ creating Accept-Contact header in OPTIONS request used to validate
+ registration.
+
+ * Added nua_generate_instance_identifier() to nua module.
+
+ * Changed default values in nua_params.c.
+
+ NUTAG_OUTBOUND() is "natify", and NUTAG_KEEPALIVE() is 120 seconds.
+
+ * Fixed nua/test_proxy.c.
+
+ Registrar was not returning all contacts in 200 OK to response to
+ REGISTER.
+
+ * iptsec module:
+
+ * Added auc_copy_credentials().
+
+ Implementation in iptsec/auth_client.c, prototype in
+ <iptsec/sofia-sip/auth_client.h>. Replaced msg_param_t with char
+ const *, too.
+
+ * Added SOFIAPUBFUN to auth_struct_copy(), too.
+
+ * iptsec module (by Martti Mela):
+
+ * ntlm support now compiles, not working.
+
+ * added auth_ntlm.[ch]
+
+ * more NTLM methods and header file auth_ntlm.h
+
+ * still more ifdefs for NTLM enabling
+
+ * added configure flag for enabling NTLM (disabled by default)
+
+ * fixed gssapidatas
+
+ * NTLM implementation continued.
+
+2006-05-02 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * iptsec module:
+
+ * Updated headers in iptsec module.
+ Added SOFIAPUBFUN and SOFIAPUBVAR where needed.
+ Removed auc_with_uicc().
+
+ * Fixed memory management problems in iptsec module.
+ The authenticator client in auth_client.c leaked memory when
+ re-challenged. The client did not duplicate strings from
+ challenge, and tried to use freed values after challenge was
+ freed.
+ Now we are actually running the tests in test_auth_digest.c, too.
+ The problem was reported and patch submitted by Colin Whittaker.
+
+ * sresolv module:
+
+ * Updated sresolv API.
+
+ Added sres_search() and sres_search_cached_answers() to the
+ sresolv API. Added sres_blocking_search(). Added ignore_cache
+ parameter to sres_blocking_query() and
+ sres_blocking_query_sockaddr() prototypes. Renumbered
+ SRES_TIMEOUT_ERR and SRES_RECORD_ERR so that they do not overlap
+ with transaction signature errors. Added sres_record_type().
+
+ * Updated sresolv documentation.
+
+ * Making cache threadsafe and locking it during sres_cache_store().
+ Problem reported by Thomas Rosenblatt.
+
+ * Moved sip-dig from libsofia-sip-ua/sresolv/ to utils.
+
+ * Updated utils/sip-dig.c manpage and -p option handling.
+
+ * Added text about preloading and stack use to su/su_alloc.c.
+
+ * Fixed handle leaks in nua_test.c.
+ Added delay before nua_shutdown() in order to ease debugging.
+
+ * Fixed nua handle reference counting problems in nua module.
+ Problem reported by Colin Whittaker.
+
+ * Updated documentation of auc_authorize() in iptsec/auth_client.c.
+
+ * Added null pointer check to auc_authorize() in iptsec/auth_client.c.
+ Patch proposed by Colin Whittaker.
+
+ * Destroying session when initial INVITE is CANCELed.
+ Patch proposed by Colin Whittaker.
+
+2006-04-27 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * sresolv module:
+
+ Added SRESTAG_CACHE() to <sofia-sip/sresolv.h>.
+
+ Added ends0 and no-edns0 options in resolv.conf to sresolv/sres.c.
+
+ Fixed sresolv #includes.
+ Added #include <arpa/inet.h> and <fcntl.h> into sresolv/sres.c
+ Added prerequisite #includes to sresolv files.
+
+ Added @todo about cache poisoning. Updated sresolv documentation.
+
+ Fixed bugs in sresolv/sres_blocking.c.
+
+ Silenced printing spurious network errors in sresolv/sres.c.
+
+ Added sres_is_blocking() to sres_blocking.c. Updated
+ sres_resolver_get_async(), too.
+
+ Added sip-dig.c to sresolv module.
+
+ * tport module:
+
+ Added missing "typedef" keyword to tport_pri_type_t in
+ sofia-sip/tport_tag.h
+
+ Fixed TPTAG_CONNECT() usage in tport/tport.c.
+
+ Now running some SCTP tests in test_tport.c
+
+ Updated tport_tls.c:
+ - Not requiring client certificate in tls.
+ - Tried to improve error handling, too.
+
+ Now using stream-like sending semantics with SCTP.
+
+ Updated datagram reception in tport_type_udp.c. We now avoid
+ peeking and fussing around with message size, and simply allocate
+ 64K buffer, receive(), then reduce the buffer size.
+
+ Updated tport_recv_stun_dgram() in tport_stub_stun.c. Now using
+ already received data within a msg_t.
+
+ Updated SigComp interface in tport_stub_sigcomp.c and tport_sigcomp.c.
+
+ Added a slot for stun handle to all primary transports.
+ Changed tport_primary_t in tport_internal.h, updated tport_type_stun.c.
+
+ Moved rest of the threadpool stuff into tport_threadpool.c.
+ tport_threadpool.c does not work at the moment, disable it.
+
+ Updated tport_connect() interface.
+
+ Calling tport_alloc_seconary() when client socket has been
+ created, making it possible to set socket options before
+ connecting the socket. Currently, this benefits SCTP and TLS. This
+ change affects tport_internal.h, tport.c, tport_type_sctp.c,
+ tport_type_tcp.c, and tport_type_tls.c.
+
+ Added TPORT_DLL to tport_keepalive(), too.
+
+ Added tport_ref() and tport_unref() to tport module.
+
+ Fixed bug #1473936 in tport/tport.c. tport_primary_by_name() now
+ returns transports regardless of their protocol family if
+ tpn->tpn_host is not a literal IP address.
+
+ * msg module:
+
+ Updated msg_recv_buffer() prototype.
+
+ Reclaiming the un-committed part of buffer in msg/msg_parser.c.
+ The allocation pattern for UDP has changed: now we allocate 64K,
+ then realloc to the actual size.
+
+ * nta module:
+
+ Fixed bug #1472683 in nta/nta.c.
+ The rport parameter was missing from ACK.
+ The CANCEL had Via line with duplicate branch parameter.
+
+ Fixed merge artifact in nta/test_nta_api.c.
+
+ Always having NTATAG_SIGCOMP_OPTIONS() and storing its value.
+
+ * nua module:
+
+ Added explicit check for NULL pointers to
+ unregister_expires_contacts().
+
+ Added missing events to nua.docs.
+
+ More fixes to nua/nua_publish.c. nua_unpublish uses tags from
+ initial nua_publish() 900 status is returned when there is no
+ Expires header in 2XX response to PUBLISH.
+
+ Re-indented nua_publish.c.
+
+ Added better error checking to nua_creq_msg().
+ Fixed Service-Route header processing, too.
+
+ Added nua_add_contact_by_aor() to nua_register.c. The
+ nua_add_contact_by_aor() takes care of adding other
+ registration-related headers like Service-Route, too.
+
+ Moved nua_publish() documentation from nua.c/nua.docs to
+ nua_publish.c. Updated documentation, added nua_r_unpublish
+ documentation.
+
+ Improved PUBLISH handling in nua/nua_publish.c. Saving the initial
+ PUBLISH message along with message body and content type. They are
+ re-used if 412 is received or if 2XX response contains Expires: 0.
+ If 2XX response is received without Expires header, we report
+ internal error to application.
+
+ Fixed route handling in SUBSCRIBE in the file nua/nua_subnotref.c.
+ There was a problem using dialog route set when there was an
+ initial route original SUBSCRIBE.
+
+ * Updated copyright year in sofia-footer.html.in.
+
+ * Fixed prototype of host_is_domain().
+
+ * Fixed doxygen warnings in su module.
+
+ * Updated sofia-sip.spec.in.
+ Separated glib library to sofia-sip-glib and sofia-sip-glib-devel packages.
+ Added sofia-sip-docs package.
+
+ * Added su_timer_set_interval() to su/su_timer.c and sofia-sip/su_wait.h.
+
+ * Defining __func__ in stun/stunc.c for the benefit of older C compilers.
+
+ * Removed // comments.
+
+2006-04-25 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Added compilation and run-time checks for MSG_TRUNC.
+
+ M ./libsofia-sip-ua/tport/tport_internal.h -2 +3
+ M ./libsofia-sip-ua/tport/tport_threadpool.c -1 +1
+ M ./libsofia-sip-ua/tport/tport_type_udp.c -4 +34
+ M ./m4/sac-su2.m4 +5
+
+ * Fixed #includes in sresolv files.
+
+ M ./libsofia-sip-ua/sresolv/sres_blocking.c +2
+ M ./libsofia-sip-ua/sresolv/sres_cache.c +3
+ M ./libsofia-sip-ua/sresolv/test_sresolv.c +9
+
+ * Fixed syntax error with G_DEFINE_TYPE(NuaGlib).
+
+ M ./libsofia-sip-ua-glib/nua-glib/nua_glib.c -1 +1
+
+ * Added --with sctp and --without glib to sofia-sip.spec.in.
+
+ M ./packages/sofia-sip.spec.in -3 +10
+
+ * Renumbered test case NUA-9.1.2 in test_nua.c
+
+ M ./libsofia-sip-ua/nua/test_nua.c -2 +2
+
+2006-04-20 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Not trying to set up stun transport unless we have stun server configured.
+ Files: nua/nua_register.c.
+
+ M ./libsofia-sip-ua/nua/Makefile.am +1
+ M ./libsofia-sip-ua/nua/nua_register.c -6 +16
+
+ * Fixed auth-int authentication for INVITE requests.
+ Files: nua/nua_stack.c, nua/nua_session.c, iptsec/auth_client.c.
+
+ M ./libsofia-sip-ua/iptsec/auth_client.c +6
+ M ./libsofia-sip-ua/nua/nua_stack.c -4 +5
+
+ * Added outbound_connect_gruuize() - generate gruu from gruu paramter in our contact.
+ File: nua/nua_register.c.
+
+ M ./libsofia-sip-ua/nua/nua_register.c +53
+
+ * Added "SSL_VERIFY_PEER" environment variable.
+
+ M ./libsofia-sip-ua/tport/tport_tls.c -2 +2
+
+ * Restored SCTP in tport_type_sctp.c. Increased maximum message size to 64 K.
+
+ M ./libsofia-sip-ua/tport/tport_type_sctp.c -7 +7
+
+ * Using SSL_VERIFY_NONE - do not ask for client certificate.
+ It looks like openssl does not allow for client not to have certificate.
+
+ M ./libsofia-sip-ua/tport/tport_tls.c -1 +2
+
+ * More memory management problems in stun.
+
+ M ./libsofia-sip-ua/stun/stun_common.c -1 +1
+
+ * Fixed memory management problems in stun.
+
+ M ./libsofia-sip-ua/stun/stun.c -1
+
+ * Fixed blunder in error record creation.
+ sres_create_error_rr() in in sres.c.
+
+ M ./libsofia-sip-ua/sresolv/sres.c -2 +4
+
+ * Using outbound keepalive interval of 15 seconds.
+ outbound_connect_start_keepalive() in nua/nua_register.c
+
+ M ./libsofia-sip-ua/nua/nua_register.c -2 +1
+
+ * Added nta_agent_init_sigcomp() and nta_agent_deinit_sigcomp().
+
+ M ./libsofia-sip-ua/nta/nta.c -3 +28
+ M ./libsofia-sip-ua/nta/nta_internal.h -9 +21
+
+ * Renamed tport_try_accept_sigcomp() as tport_sigcomp_accept_incomplete().
+
+ M ./libsofia-sip-ua/tport/tport.c -1 +1
+ M ./libsofia-sip-ua/tport/tport_internal.h -1 +1
+ M ./libsofia-sip-ua/tport/tport_stub_sigcomp.c -1 +1
+
+ * Maded tport stun plugin pointer private.
+
+ M ./libsofia-sip-ua/tport/tport_stub_stun.c -2 +7
+
+ * Updated SCTP semantics to use "TCP".
+
+ M ./libsofia-sip-ua/tport/tport.c -3 +8
+ M ./libsofia-sip-ua/tport/tport_type_sctp.c -6 +20
+
+ * Fixed C++ compilation on <sres.h>.
+
+ * Fixed outbound problems.
+ Not unregistering contacts with instance-id and reg-id.
+ Avoiding crash when processing timeout responses.
+
+ M ./libsofia-sip-ua/nua/nua_register.c -16 +31
+
+ * Addeed --enable-sctp.
+
+ M ./m4/sac-tport.m4 -4 +6
+ M ./packages/sofia-sip.spec.in +1
+
+ * Updated compression interface in tport.
+ Added tport_compressor_t type, tport_delivered_with_comp().
+ Removed tpac_sigcomp_accept() and tport_delivered_using_udvm().
+
+ M ./libsofia-sip-ua/tport/sofia-sip/tport.h -10 +8
+ M ./libsofia-sip-ua/tport/sofia-sip/tport_plugins.h -6 +93
+ M ./libsofia-sip-ua/tport/tport.c -24 +11
+ M ./libsofia-sip-ua/tport/tport_internal.h -15 +10
+ M ./libsofia-sip-ua/tport/tport_stub_sigcomp.c -114 +53
+
+ * Removed direct SigComp stuff from nta.c.
+ Added nta_compressor_vtable.
+
+ M ./libsofia-sip-ua/nta/nta.c -209 +100
+ M ./libsofia-sip-ua/nta/nta_internal.h +33
+
+ * Fixed aor/tport handling for sip/sips cases.
+
+ M ./libsofia-sip-ua/nua/nua_register.c -4 +13
+
+ * Disabled ntlm client for now.
+
+2006-04-17 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Removed - from ntlm variable names (mp)
+
+ M ./libsofia-sip-ua/iptsec/auth_module.c -11 +11
+ M ./libsofia-sip-ua/iptsec/sofia-sip/auth_plugin.h -1 +1
+
+ * Fixed --without-sigcomp (mp)
+
+ M ./m4/sac-tport.m4 -1 +1
+
+ * iptsec: started NTLM support (mm)
+
+ M ./libsofia-sip-ua/iptsec/auth_client.c +9
+ M ./libsofia-sip-ua/iptsec/auth_module.c +390
+ M ./libsofia-sip-ua/iptsec/sofia-sip/auth_plugin.h +7
+
+ * Changed internal nua error responses to use 9XX status codes.
+
+ M ./libsofia-sip-ua/nua/nua_event_server.c -9 +10
+ M ./libsofia-sip-ua/nua/nua_message.c -4 +4
+ M ./libsofia-sip-ua/nua/nua_options.c -3 +3
+ M ./libsofia-sip-ua/nua/nua_params.c -3 +3
+ M ./libsofia-sip-ua/nua/nua_publish.c -5 +5
+ M ./libsofia-sip-ua/nua/nua_register.c -6 +6
+ M ./libsofia-sip-ua/nua/nua_session.c -29 +30
+ M ./libsofia-sip-ua/nua/nua_stack.c -2 +4
+ M ./libsofia-sip-ua/nua/nua_stack.h -2 +2
+ M ./libsofia-sip-ua/nua/nua_subnotref.c -5 +7
+
+ * Added test for some of the internal errors.
+
+ M ./libsofia-sip-ua/nua/test_nua.c +138
+
+ * Fixed NTA API test for SigComp options (they are now always processed).
+
+ M ./libsofia-sip-ua/nta/test_nta_api.c -8 +4
+
+ * Added missing #includes to sres.c.
+
+ * Removed experimental code enabling STUN.
+
+ M ./libsofia-sip-ua/tport/tport.c -5
+
+ * Added su_init()/su_deinit() here.
+
+ M ./libsofia-sip-ua/tport/test_tport.c -1 +5
+
+ * Removed some warnings (and fixed a bug) in encoding functions ofb stun_common.c
+
+ M ./libsofia-sip-ua/stun/stun_common.c -9 +11
+
+ * Removed stupid VC98 warning from tport_threadpool.c
+
+ M ./libsofia-sip-ua/tport/tport_threadpool.c -1 +1
+
+ * Added missing __func__ to tport_type_tcp and tport_threadpool.c.
+
+ M ./libsofia-sip-ua/tport/tport.c -1 +1
+ M ./libsofia-sip-ua/tport/tport_threadpool.c +7
+ M ./libsofia-sip-ua/tport/tport_type_tcp.c +7
+
+ * Added inlined IN6_IS_ADDR_LOOPBACK() to su_localinfo.c.
+
+ M ./libsofia-sip-ua/su/su_localinfo.c +16
+
+ * Fixed pointer artithmetics by memccpy() in su_strcat_all().
+ (function in su/su_strdup.c).
+
+ * Added missing Winsock errors to <su_errno.h>
+
+ * Fixed address scoping error in stun_mini.c.
+
+ * Added missing __func__ to stun C files.
+
+ * Added things missing from win32 to new sresolv modules.
+
+ M ./libsofia-sip-ua/sresolv/sres.c -5 +35
+ M ./libsofia-sip-ua/sresolv/sres_blocking.c -4 +28
+ M ./libsofia-sip-ua/sresolv/sres_cache.c -1 +9
+
+ * Fixed C99ism in nua_register.c
+
+ M ./libsofia-sip-ua/nua/nua_register.c -1 +3
+
+ * Removed automatically generated file tport_tag_ref.c from version control system.
+
+ R ./libsofia-sip-ua/tport/tport_tag_ref.c
+
+2006-04-11 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ Synchronizing CVS with darcs (other contributors pp = Pekka Pessi,
+ mm = Martti Mela).
+
+ * NDEBUG oops. (pp)
+
+ M ./libsofia-sip-ua/sresolv/sres.c -1 +1
+
+ * Added sres_resolver_copy(). (pp)
+ Storing application-provided option strings in res_options.
+ Removed warnigns.
+
+ M ./libsofia-sip-ua/sresolv/sofia-resolv/sres.h +3
+ M ./libsofia-sip-ua/sresolv/sres.c -9 +90
+ M ./libsofia-sip-ua/sresolv/test_sresolv.c -1 +1
+
+ * Fixed stun miniserver (and stun stub in tport). (pp)
+
+ M ./libsofia-sip-ua/stun/stun_common.c -12 +7
+ M ./libsofia-sip-ua/stun/stun_mini.c -4 +4
+ M ./libsofia-sip-ua/tport/tport_stub_stun.c -1 +1
+
+ * Updated copyrights for nua-glib.
+
+ M ./COPYRIGHTS -1 +2
+ M ./libsofia-sip-ua-glib/nua-glib/nua_glib.c +2
+ M ./libsofia-sip-ua-glib/nua-glib/sofia-sip/nua_glib.h -1 +2
+
+ * Fixed segfault with stun_handle_destroy() on a NULL handle.
+
+ M ./libsofia-sip-ua/tport/tport_type_stun.c -1 +2
+
+ * Updated RELEASE. (pp)
+
+ M ./RELEASE -4 +13
+
+ * Disabled SIGCOMP until tport plugin is ready. (pp)
+ Handling sigcomp options regarless of HAVE_SIGCOMP value.
+
+ M ./libsofia-sip-ua/nta/nta.c -27 +30
+
+ * Added stun server and compression plugins. (pp)
+ Added TPORT_STUN_SERVER().
+ Having stun server dependencies in <tport_stub_stun.c>.
+ Moved sigcomp dependencies into <tport_stub_sigcomp.c>.
+
+ M ./libsofia-sip-ua/tport/Makefile.am -1 +3
+ M ./libsofia-sip-ua/tport/sofia-sip/tport.h -23 +15
+ A ./libsofia-sip-ua/tport/sofia-sip/tport_plugins.h
+ M ./libsofia-sip-ua/tport/sofia-sip/tport_tag.h +7
+ M ./libsofia-sip-ua/tport/test_tport.c -2 +3
+ M ./libsofia-sip-ua/tport/tport.c -136 +82
+ M ./libsofia-sip-ua/tport/tport_internal.h -35 +72
+ M ./libsofia-sip-ua/tport/tport_sigcomp.c -150 +193
+ A ./libsofia-sip-ua/tport/tport_stub_sigcomp.c
+ A ./libsofia-sip-ua/tport/tport_stub_stun.c
+ M ./libsofia-sip-ua/tport/tport_tag.c +1
+ M ./libsofia-sip-ua/tport/tport_tag_ref.c +3
+ M ./libsofia-sip-ua/tport/tport_type_stun.c -3 +21
+ M ./libsofia-sip-ua/tport/tport_type_udp.c -144 +4
+
+ * http_add_tl() now accepts NULL http struct pointer. (pp)
+
+ M ./libsofia-sip-ua/http/http_tag_class.c -1 +3
+
+ * Update documentation of msg_copy() and msg_dup(). (pp)
+
+ M ./libsofia-sip-ua/msg/msg_header_copy.c -4 +7
+
+ * Removed some HAVE_SIGCOMP code. (pp)
+
+ M ./libsofia-sip-ua/nta/nta.c -42 +13
+ M ./libsofia-sip-ua/nta/nta_internal.h -9 +2
+
+ * Added su_sockaddr_scope(). (pp)
+ Using su_sockaddr_scope() in stun_mini.c.
+
+ M ./libsofia-sip-ua/stun/stun_mini.c -15 +38
+ M ./libsofia-sip-ua/su/sofia-sip/su_localinfo.h +3
+ M ./libsofia-sip-ua/su/su_localinfo.c -1 +18
+
+ * Fixed nat testing code. (pp)
+
+ M ./libsofia-sip-ua/nua/test_nat.c -4 +2
+ M ./libsofia-sip-ua/nua/test_nua.c +1
+
+ * Updated stack initialization. (pp)
+ Transports are initialized by nua_stack_init_transport() in nua_register.c.
+ UICC (you don't want to know) is initialized by nua_stack_set_from() in
+ nua_params.c.
+
+ M ./libsofia-sip-ua/nua/nua_params.c -4 +15
+ M ./libsofia-sip-ua/nua/nua_register.c -1 +70
+ M ./libsofia-sip-ua/nua/nua_stack.c -54 +18
+ M ./libsofia-sip-ua/nua/nua_stack.h -2 +4
+ M ./libsofia-sip-ua/nua/nua_tag.c -2
+ M ./libsofia-sip-ua/nua/sofia-sip/nua_tag.h -7 +6
+
+ * Fixed su_root_run() usage in docs. (pp)
+ Thanks for hint by Julio Auto.
+
+ M ./libsofia-sip-ua/nua/nua.docs -1 +1
+
+ * Fixed allocation bug. (pp)
+
+ M ./libsofia-sip-ua/sresolv/test_sresolv.c -4 +3
+
+ * Change version back to 1.11.7work.
+
+ M ./configure.ac -1 +1
+
+ * Changed outbound_connect_nat_detect() prototype. (pp)
+
+ M ./libsofia-sip-ua/nua/nua_register.c -7 +11
+
+ * Removed obsoleted nua events. (pp)
+
+ Removed nua events nua_i_media_event, nua_r_set_media_param,
+ nua_r_get_media_param, nua_r_media_setup, nua_r_media_describe,
+ nua_r_media_event, nua_i_announce, nua_i_describe, nua_i_get_parameter,
+ nua_i_pause, nua_i_options2, nua_i_play, nua_i_record, nua_i_set_parameter,
+ nua_i_setup, nua_i_teardown, nua_r_setup, nua_r_play, nua_r_record,
+ nua_r_pause, nua_r_describe, nua_r_teardown, nua_r_options2, nua_r_announce,
+ nua_r_get_parameter, and nua_r_set_parameter.
+
+ Removed nua functions nua_announce(), nua_describe(), nua_get_media_param(),
+ nua_get_parameter(), nua_media_describe(), nua_media_event(),
+ nua_media_setup(), nua_options2(), nua_pause(), nua_play(), nua_record(),
+ nua_set_media_param(), nua_set_parameter(), nua_setup(), and nua_teardown(),
+
+ M ./libsofia-sip-ua/nua/sofia-sip/nua.h -33
+
+ * Moved preference/parameter setting/getting into its own nua_params.c module. (pp)
+
+ M ./libsofia-sip-ua/nua/Makefile.am +1
+ M ./libsofia-sip-ua/nua/nua.c -140
+ A ./libsofia-sip-ua/nua/nua_params.c
+ A ./libsofia-sip-ua/nua/nua_params.h
+ M ./libsofia-sip-ua/nua/nua_stack.c -661 +42
+ M ./libsofia-sip-ua/nua/nua_stack.h -125 +10
+ M ./libsofia-sip-ua/nua/nua_tag.c -6 +9
+ M ./libsofia-sip-ua/nua/sofia-sip/nua_tag.h -24 +74
+ M ./libsofia-sip-ua/nua/test_nua.c -1 +24
+
+ * Removed obsoleted functions from nua. (pp)
+
+ M ./libsofia-sip-ua/nua/nua.c -110
+ M ./libsofia-sip-ua/nua/sofia-sip/nua.h -54
+
+ * Updated documentation in nua. (pp)
+
+ M ./libsofia-sip-ua/nua/Doxyfile -2 +2
+ M ./libsofia-sip-ua/nua/nua.c -68 +24
+ M ./libsofia-sip-ua/nua/nua.docs -27 +2
+ M ./libsofia-sip-ua/nua/nua_common.c -4 +4
+ M ./libsofia-sip-ua/nua/nua_dialog.c -12 +17
+ M ./libsofia-sip-ua/nua/nua_dialog.h -1 +1
+ M ./libsofia-sip-ua/nua/nua_event_server.c -14 +15
+ M ./libsofia-sip-ua/nua/nua_options.c -2 +2
+ M ./libsofia-sip-ua/nua/nua_register.c -22 +190
+ M ./libsofia-sip-ua/nua/nua_session.c -6 +7
+ M ./libsofia-sip-ua/nua/nua_stack.c -22 +31
+ M ./libsofia-sip-ua/nua/nua_stack.h -11 +1
+ M ./libsofia-sip-ua/nua/nua_subnotref.c -3 +3
+
+ * stun: fixed mem leaks with valgrind (mm)
+
+ M ./libsofia-sip-ua/stun/sofia-sip/stun.h -1 +3
+ M ./libsofia-sip-ua/stun/stun.c -5 +50
+ M ./libsofia-sip-ua/stun/stun_common.c -12 +38
+ M ./libsofia-sip-ua/stun/stunc.c -8 +9
+
+ * changed tport to use stun_discovery_done instead of stun_bind_done (mm)
+
+ M ./libsofia-sip-ua/tport/tport_type_stun.c -1 +1
+
+ * removed stun_bind_ enums and replaced with stun_discovery_ scheisse (mm)
+
+ M ./libsofia-sip-ua/stun/sofia-sip/stun.h +5
+ M ./libsofia-sip-ua/stun/stun.c -6 +8
+ M ./libsofia-sip-ua/stun/stunc.c -3 +4
+
+ * Added test for su_home_unref()ing a cloned home. (pp)
+
+ M ./libsofia-sip-ua/su/su_alloc_test.c -9 +13
+ M ./libsofia-sip-ua/su/su_strlst.c -2 +8
+
+ * Added new sresolv headers to packages. (pp)
+
+ M ./libsofia-sip-ua/sresolv/Makefile.am -1 +6
+ M ./packages/sofia-sip.spec.in +1
+
+ * Update version to 1.11.8work as per new release guidelines.
+
+ M ./configure.ac -1 +1
+
+ * Signal stun_error to the client if STUN DNS-SRV lookup is started but fails.
+
+ M ./libsofia-sip-ua/stun/stun.c -36 +41
+
+ * Fixed stun compilation.
+
+ M ./libsofia-sip-ua/stun/stun.c -3 +6
+
+ * Fixed operations on Transaction-ID. TID is a 128bit opaque value.
+
+ M ./libsofia-sip-ua/stun/sofia-sip/stun_common.h +2
+ M ./libsofia-sip-ua/stun/stun.c -10 +8
+ M ./libsofia-sip-ua/stun/stun_common.c -2 +2
+
+ * Removed ssl headers from stun_common.h. Public headers should not have config.h dependent sections.
+
+ M ./libsofia-sip-ua/stun/sofia-sip/stun_common.h -9
+ M ./libsofia-sip-ua/stun/stun_internal.h +9
+
+ * tls somehow works now (mm)
+
+ M ./libsofia-sip-ua/stun/stun.c -2 +5
+
+ * updated stunc with cool features & cleanup. Removed stun_request_t from public callbacks (mm)
+
+ M ./libsofia-sip-ua/stun/sofia-sip/stun.h -2
+ M ./libsofia-sip-ua/stun/stun.c -33 +69
+ M ./libsofia-sip-ua/stun/stun_internal.h +1
+ M ./libsofia-sip-ua/stun/stunc.c -99 +140
+
+ * Using HAVE_CONFIG_H. (pp)
+
+ M ./libsofia-sip-ua/stun/stun_common.c -2 +2
+
+ * Added test for <sys/select.h>. (pp)
+ Removed HAVE_SU_WAIT_H - nobody is using it anymore.
+
+ M ./m4/sac-su2.m4 -12 +4
+
+ * Updated win32/config.h.in. (pp)
+
+ M ./win32/config.h.in -7 +67
+
+ * Updated (for testing stun). (pp)
+
+ M ./libsofia-sip-ua/nua/test_nat.c -175 +183
+
+ * Added quick hack for using stun. (pp)
+
+ M ./libsofia-sip-ua/tport/tport.c +7
+
+ * Updated tport_stun_bind_done(). (pp)
+
+ M ./libsofia-sip-ua/tport/tport_type_stun.c -11 +9
+
+ * No need to define HAVE_SU_WAIT_H. (pp)
+
+ M ./libsofia-sip-ua/stun/stun_dns.c -1
+
+ * Update documents. (pp)
+
+ M ./libsofia-sip-ua/sresolv/resolve_sip.c -1 +1
+ M ./libsofia-sip-ua/sresolv/sres.c -5 +9
+ M ./libsofia-sip-ua/sresolv/sres_blocking.c -4 +9
+ M ./libsofia-sip-ua/sresolv/sres_cache.c -4 +39
+ M ./libsofia-sip-ua/sresolv/sresolv.c +34
+ M ./libsofia-sip-ua/sresolv/test_sresolv.c -3 +8
+
+ * stunc works, kikkelis kokkelis!! (mm)
+
+ M ./libsofia-sip-ua/stun/sofia-sip/stun.h -1 +3
+ M ./libsofia-sip-ua/stun/stun.c -5 +19
+ M ./libsofia-sip-ua/stun/stunc.c -50 +169
+
+ * Added stun_mini_t. (pp)
+
+ M ./libsofia-sip-ua/stun/Makefile.am -1 +1
+ M ./libsofia-sip-ua/stun/sofia-sip/stun.h -4 +19
+ A ./libsofia-sip-ua/stun/stun_mini.c
+
+ * Updated stun todo-file in stun.docs.
+
+ M ./libsofia-sip-ua/stun/stun.docs -4 +1
+
+ * Also mark deprecated typedefs and defines.
+
+ M ./libsofia-sip-ua/stun/sofia-sip/stun.h -9 +9
+
+ * Adds interface to query active primary server address.
+
+ M ./libsofia-sip-ua/stun/sofia-sip/stun.h +1
+ M ./libsofia-sip-ua/stun/stun.c -30 +39
+ M ./libsofia-sip-ua/stun/stun_internal.h -1 +1
+
+ * Minor update to STUN DNS-SRV interface.
+
+ M ./libsofia-sip-ua/stun/ChangeLog +4
+ M ./libsofia-sip-ua/stun/lookup_stun_server.c -17 +31
+ M ./libsofia-sip-ua/stun/sofia-sip/stun.h -5 +4
+ M ./libsofia-sip-ua/stun/stun.c -3 +4
+ M ./libsofia-sip-ua/stun/stun_dns.c -34 +67
+
+ * Using updated tport_keepalive() prototype. (pp)
+
+ M ./libsofia-sip-ua/nta/nta.c -1 +2
+
+ * Added STUN tport. (pp)
+ Moved upnp stuff to its own file.
+
+ M ./libsofia-sip-ua/tport/Makefile.am -3 +3
+ M ./libsofia-sip-ua/tport/tport.c +1
+ M ./libsofia-sip-ua/tport/tport_type_stun.c -422 +88
+
+ * Updated tport_keepalive() prototype. (pp)
+ Implemented tport_is_updating(), added tport_has_been_updated().
+
+ M ./libsofia-sip-ua/tport/sofia-sip/tport.h -1 +2
+ M ./libsofia-sip-ua/tport/tport.c -8 +40
+ M ./libsofia-sip-ua/tport/tport_internal.h -5 +10
+ M ./libsofia-sip-ua/tport/tport_threadpool.c -2 +2
+ M ./libsofia-sip-ua/tport/tport_type_connect.c -2 +2
+ M ./libsofia-sip-ua/tport/tport_type_sctp.c -4 +4
+ M ./libsofia-sip-ua/tport/tport_type_tcp.c -2 +2
+ M ./libsofia-sip-ua/tport/tport_type_tls.c -6 +6
+ M ./libsofia-sip-ua/tport/tport_type_udp.c -1 +1
+
+ * Removed torture_stun.c.
+
+ M ./libsofia-sip-ua/stun/Makefile.am -10 +1
+ R ./libsofia-sip-ua/stun/torture_stun.c
+
+ * Fix STUNTAG_DOMAIN with test_nattype and test_lifetime processes.
+
+ M ./libsofia-sip-ua/stun/stun.c -7 +28
+
+ * Renamed all get_nattype and get_lifetime functions and enums to test_nattype and test_lifetime.
+
+ M ./libsofia-sip-ua/stun/ChangeLog +4
+ M ./libsofia-sip-ua/stun/sofia-sip/stun.h -14 +8
+ M ./libsofia-sip-ua/stun/stun.c -52 +30
+ M ./libsofia-sip-ua/stun/stunc.c -6 +9
+
+ * Moved deprecated functions at the end of stun.c. Fixed postponing shared-secret and bind discovery processes for DNS-SRV lookups.
+
+ M ./libsofia-sip-ua/stun/stun.c -159 +172
+
+ * stun_request_shared_secret() renamed to stun_obtain_shared_secret().
+
+ M ./libsofia-sip-ua/stun/sofia-sip/stun.h -4 +1
+
+ * stun.h: Deprecated stun_handle_release().
+
+ M ./libsofia-sip-ua/stun/ChangeLog -3 +4
+ M ./libsofia-sip-ua/stun/sofia-sip/stun.h -1 +2
+
+ * tag list stored for stun_obtain_shared_secret (mm)
+
+ M ./libsofia-sip-ua/stun/stun.c -1 +11
+
+ * non-compiling: need args for stun_obtain_shared_secret() (mm)
+
+ M ./libsofia-sip-ua/stun/stun.c -1 +1
+
+ * stun api upd's also for tls; tport (mm)
+
+ M ./libsofia-sip-ua/stun/sofia-sip/stun.h -4 +14
+ M ./libsofia-sip-ua/stun/sofia-sip/stun_tag.h -4 +4
+ M ./libsofia-sip-ua/stun/stun.c -17 +150
+ M ./libsofia-sip-ua/stun/stun_common.c -3 +5
+ M ./libsofia-sip-ua/stun/stun_tag.c -8 +9
+ M ./libsofia-sip-ua/tport/tport_type_stun.c -5 +5
+
+ * Removed separate virtual function for compression initialization. (pp)
+
+ M ./libsofia-sip-ua/tport/tport.c -3
+ M ./libsofia-sip-ua/tport/tport_internal.h -2
+ M ./libsofia-sip-ua/tport/tport_sigcomp.c -2
+ M ./libsofia-sip-ua/tport/tport_threadpool.c -1
+ M ./libsofia-sip-ua/tport/tport_type_connect.c -1
+ M ./libsofia-sip-ua/tport/tport_type_sctp.c -2
+ M ./libsofia-sip-ua/tport/tport_type_stun.c -4 +3
+ M ./libsofia-sip-ua/tport/tport_type_tcp.c -2
+ M ./libsofia-sip-ua/tport/tport_type_tls.c -2
+ M ./libsofia-sip-ua/tport/tport_type_udp.c -2
+
+ * Added su_socket() wrapper function. (pp)
+
+ M ./libsofia-sip-ua/su/sofia-sip/su.h -2
+ M ./libsofia-sip-ua/su/su.c -6 +12
+
+ * Removee v-p from the vtable names. (pp)
+
+ M ./libsofia-sip-ua/tport/tport.c -20 +20
+ M ./libsofia-sip-ua/tport/tport_internal.h -11 +11
+ M ./libsofia-sip-ua/tport/tport_threadpool.c -1 +1
+ M ./libsofia-sip-ua/tport/tport_type_connect.c -4 +1
+ M ./libsofia-sip-ua/tport/tport_type_sctp.c -2 +2
+ M ./libsofia-sip-ua/tport/tport_type_stun.c -1 +1
+ M ./libsofia-sip-ua/tport/tport_type_tcp.c -2 +2
+ M ./libsofia-sip-ua/tport/tport_type_tls.c -2 +2
+ M ./libsofia-sip-ua/tport/tport_type_udp.c -2 +2
+
+ * Removed temp test program from sresolv. (pp)
+
+ M ./libsofia-sip-ua/sresolv/Makefile.am -2 +1
+
+ * Added 3.f.f.e.1.2.0.0.3.0.1.2.c.0.0.0.arpa. (pp)
+
+ A ./libsofia-sip-ua/sresolv/3.f.f.e.1.2.0.0.3.0.1.2.c.0.0.0.arpa
+ M ./libsofia-sip-ua/sresolv/Makefile.am -1 +2
+
+ * Added notes to RELEASE. (pp)
+
+ M ./RELEASE +17
+
+ * Sanitized stun_common.[hc] slightly. (pp)
+
+ M ./libsofia-sip-ua/stun/sofia-sip/stun_common.h -1 +1
+ M ./libsofia-sip-ua/stun/stun_common.c -45 +53
+
+ * Added notes about string and header manipulation function. (pp)
+
+ M! ./RELEASE -10
+
+ * Fixed problem with initial un-REGISTER by test_nua.c in test_proxy.c (pp)
+
+ M ./libsofia-sip-ua/nua/test_proxy.c -4 +7
+
+ * Fixed problems with updated API. Added sres_resolver_update(). (pp)
+
+ M ./libsofia-sip-ua/sresolv/Makefile.am -1 +2
+ M ./libsofia-sip-ua/sresolv/sofia-resolv/sres.h -55 +21
+ A ./libsofia-sip-ua/sresolv/sofia-resolv/sres_async.h
+ M ./libsofia-sip-ua/sresolv/sofia-sip/sresolv.h -2 +3
+ M ./libsofia-sip-ua/sresolv/sres.c -17 +37
+ M ./libsofia-sip-ua/sresolv/sres_blocking.c +1
+ M ./libsofia-sip-ua/sresolv/sresolv.c -36 +52
+ M ./libsofia-sip-ua/sresolv/test_sresolv.c -2 +2
+
+ * Fixed AC_CHECK_HEADERS depending on <sys/socket.h>. (pp)
+
+ M ./m4/sac-su2.m4 -1 +3
+
+ * Fixed HAVE_SOCKADDR_LL in case we have <netpacket/packet.h>. (pp)
+
+ M ./libsofia-sip-ua/su/su_uniqueid.c -1 +1
+
+ * Fixed su_timer_set_for_ever(). (pp)
+
+ M ./libsofia-sip-ua/su/su_timer.c -6 +9
+
+ * Fixed stupid bug with su_home_desctructor(). (pp)
+
+ M ./libsofia-sip-ua/su/su_alloc.c +10
+ M ./libsofia-sip-ua/su/su_alloc_test.c -2 +13
+
+ * New API working with test program. (pp)
+
+ M ./libsofia-sip-ua/sresolv/Makefile.am -1 +1
+ M ./libsofia-sip-ua/sresolv/run_test_sresolv +5
+ M ./libsofia-sip-ua/sresolv/sofia-resolv/sres.h -15 +62
+ M ./libsofia-sip-ua/sresolv/sofia-resolv/sres_cache.h -1 +1
+ M ./libsofia-sip-ua/sresolv/sofia-sip/sresolv.h -14 +1
+ M ./libsofia-sip-ua/sresolv/sres.c -143 +237
+ A ./libsofia-sip-ua/sresolv/sres_blocking.c
+ M ./libsofia-sip-ua/sresolv/sres_cache.c -2 +2
+ M ./libsofia-sip-ua/sresolv/sresolv.c -56 +57
+ M ./libsofia-sip-ua/sresolv/test_sresolv.c -198 +117
+
+ * Initial change for multithreaded and synchronous resolver (pp)
+
+ ./libsofia-sip-ua/sresolv/sofia-sip/sresolv.h -> ./libsofia-sip-ua/sresolv/sofia-resolv/sres.h
+ ./libsofia-sip-ua/sresolv/sresolv.c -> ./libsofia-sip-ua/sresolv/sres.c
+ M ./libsofia-sip-ua/sresolv/Makefile.am -1 +1
+ A ./libsofia-sip-ua/sresolv/sofia-resolv/
+ M ./libsofia-sip-ua/sresolv/sofia-resolv/sres.h -259 +90
+ A ./libsofia-sip-ua/sresolv/sofia-resolv/sres_cache.h
+ A ./libsofia-sip-ua/sresolv/sofia-resolv/sres_record.h
+ A ./libsofia-sip-ua/sresolv/sofia-sip/sresolv.h
+ M ./libsofia-sip-ua/sresolv/sres.c -1075 +852
+ A ./libsofia-sip-ua/sresolv/sres_cache.c
+ A ./libsofia-sip-ua/sresolv/sresolv.c
+ M ./libsofia-sip-ua/sresolv/sresolv.docs -7 +71
+ M ./libsofia-sip-ua/sresolv/test_sresolv.c -29 +20
+
+ * Fixed make top-level rules for manpage creation when doxygen is not installed.
+
+ M ./Makefile.am -1 +1
+
+ * Abort connect timer if socket connect() refused.
+
+ M ./libsofia-sip-ua/stun/stun.c -7 +5
+
+ * Updated nua_stack_tport_update(). (pp)
+
+ M ./libsofia-sip-ua/nua/nua_register.c -6 +6
+
+ * Renamed register_usage as outbound_connect. (pp)
+ Added tags NUTAG_OUTBOUND(), NUTAG_OUTBOUND_SET1(), NUTAG_OUTBOUND_SET2(),
+ NUTAG_OUTBOUND_SET3(), and NUTAG_OUTBOUND_SET4().
+
+ M ./libsofia-sip-ua/nua/nua_options.c -3 +4
+ M ./libsofia-sip-ua/nua/nua_register.c -363 +498
+ M ./libsofia-sip-ua/nua/nua_stack.c -3 +11
+ M ./libsofia-sip-ua/nua/nua_stack.h -10 +8
+ M ./libsofia-sip-ua/nua/nua_tag.c +6
+ M ./libsofia-sip-ua/nua/sofia-sip/nua_tag.h +110
+
+ * Added usage_peer_info method to dialog usage. (pp)
+
+ M ./libsofia-sip-ua/nua/nua_dialog.c +6
+ M ./libsofia-sip-ua/nua/nua_dialog.h +3
+
+ * Added possibility to run tests with external proxy. (pp)
+
+ M ./libsofia-sip-ua/nua/test_nua.c -37 +98
+
+ * Added auth_status_init_with(), as_profile and as_alt_uri. (pp)
+
+ M ./libsofia-sip-ua/iptsec/auth_module.c -4 +16
+ M ./libsofia-sip-ua/iptsec/sofia-sip/auth_module.h -2 +12
+
+ * Fixed url_param(). (pp)
+
+ M ./libsofia-sip-ua/url/url.c -9 +18
+
+ * Use "_" instead of "+" in token64_e(). (pp)
+
+ M ./libsofia-sip-ua/ipt/token64.c -3 +3
+
+ * Added tport with HTTP CONNECT, too. (pp)
+
+ A ./libsofia-sip-ua/tport/tport_type_connect.c
+
+ * Split tport.c into multiple modules. (pp)
+ STUN, UPnP and SigComp still need some polishing.
+
+ M ./libsofia-sip-ua/tport/Makefile.am -3 +7
+ M ./libsofia-sip-ua/tport/test_tport.c -13 +11
+ M ./libsofia-sip-ua/tport/tport.c -4114 +156
+ A ./libsofia-sip-ua/tport/tport_internal.h
+ A ./libsofia-sip-ua/tport/tport_logging.c
+ A ./libsofia-sip-ua/tport/tport_sigcomp.c
+ A ./libsofia-sip-ua/tport/tport_tag_ref.c
+ A ./libsofia-sip-ua/tport/tport_threadpool.c
+ A ./libsofia-sip-ua/tport/tport_type_sctp.c
+ A ./libsofia-sip-ua/tport/tport_type_stun.c
+ A ./libsofia-sip-ua/tport/tport_type_tcp.c
+ A ./libsofia-sip-ua/tport/tport_type_tls.c
+ A ./libsofia-sip-ua/tport/tport_type_udp.c
+
+ * Completed HTTP CONNECT. (pp)
+ Added --http-proxy to sip-options.
+
+ M ./libsofia-sip-ua/tport/sofia-sip/tport_tag.h +1
+ M ./libsofia-sip-ua/tport/tport.c -11 +55
+ M ./utils/sip-options.c -1 +6
+
+ * Generating Contact from public vias if no local Vias are available. (pp)
+
+ M ./libsofia-sip-ua/nta/nta.c -3 +11
+
+ * Added HTTP CONNECT. (pp)
+
+ M ./libsofia-sip-ua/tport/tport.c -682 +981
+
+ * Added http to LDADD and INCLUDE. (pp)
+
+ M ./libsofia-sip-ua/nea/Makefile.am -1 +2
+ M ./libsofia-sip-ua/nta/Makefile.am +1
+ M ./libsofia-sip-ua/nua/Makefile.am -1 +1
+ M ./libsofia-sip-ua/tport/Makefile.am +2
+
+ * Clean up timers upon destroy in stun.
+
+ M ./libsofia-sip-ua/stun/stun.c -9 +20
+
+ * Fixed typo in stun.
+
+ M ./libsofia-sip-ua/stun/stun.c -1 +1
+
+ * Adding Vias belonging to public transport to sa_public_vias list.
+ Now testing nta_agent_public_via(), too. (pp)
+
+ M ./libsofia-sip-ua/nta/Makefile.am +1
+ M ./libsofia-sip-ua/nta/nta.c -26 +63
+ M ./libsofia-sip-ua/nta/test_nta_api.c -1 +14
+
+ * Using tport_tcreate() instead of tport_create(). (pp)
+
+ M ./libsofia-sip-ua/nth/nth_client.c -1 +1
+
+ * Added vtables for transports. (pp)
+ API: tport_is_public().
+
+ M ./libsofia-sip-ua/tport/sofia-sip/tport.h -7 +3
+ M ./libsofia-sip-ua/tport/sofia-sip/tport_tag.h -1 +14
+ M ./libsofia-sip-ua/tport/test_tport.c +7
+ M ./libsofia-sip-ua/tport/tport.c -1069 +1136
+ M ./libsofia-sip-ua/tport/tport_tls.c -43 +22
+
+ * STUN documentation update - no functional changes. (pp)
+
+ M ./libsofia-sip-ua/stun/sofia-sip/stun.h -39 +31
+ M ./libsofia-sip-ua/stun/stun.c -26 +30
+
+ * Fixed bugs STUN DNS-SRV implementation. (pp)
+
+ M ./libsofia-sip-ua/stun/stun.c -20 +38
+
+ * restructured nat scheisse in tport, nta, nua. Lost weight for about 200 lines. (mm)
+
+ M ./libsofia-sip-ua/nta/nta.c -4
+ M ./libsofia-sip-ua/nua/nua_stack.c +4
+ M ./libsofia-sip-ua/tport/sofia-sip/tport.h +8
+ M ./libsofia-sip-ua/tport/sofia-sip/tport_tag.h +7
+ M ./libsofia-sip-ua/tport/tport.c -62 +38
+ M ./libsofia-sip-ua/tport/tport_tag.c +1
+
+ * initial support for dynamic address changes for register (mm)
+
+ M ./libsofia-sip-ua/nua/nua_register.c +18
+ M ./libsofia-sip-ua/tport/sofia-sip/tport_tag.h +7
+ M ./libsofia-sip-ua/tport/tport.c -76 +136
+ M ./libsofia-sip-ua/tport/tport_tag.c +1
+
+ * updated RELEASE (pp)
+
+ M ./RELEASE +9
+
+ * Cleanup STUN headers.
+
+ M ./libsofia-sip-ua/stun/sofia-sip/stun.h -10 +3
+ M ./libsofia-sip-ua/stun/stun.c -1 +3
+ M ./libsofia-sip-ua/stun/stun_dns.c -1
+
+ * Added initial DNS-SRV lookup support to stun.
+
+ M ./libsofia-sip-ua/nth/Makefile.am +1
+ M ./libsofia-sip-ua/stun/Makefile.am +1
+ M ./libsofia-sip-ua/stun/sofia-sip/stun.h -14 +17
+ M ./libsofia-sip-ua/stun/stun.c -82 +196
+ M ./libsofia-sip-ua/stun/stun_dns.c +9
+ M ./libsofia-sip-ua/tport/Makefile.am +1
+
+ * Add direct doxygen links to the public STUN APIs.
+
+ M ./libsofia-sip-ua/stun/stun.docs -4 +8
+
+ * The correct tcp service name for STUN server discovery is 'stun', not 'stun-tls'.
+
+ M ./libsofia-sip-ua/stun/lookup_stun_server.c -1 +1
+ M ./libsofia-sip-ua/stun/stun_dns.c -6 +6
+
+ * Fixed manpage generation rule to work with automake-1.8.5.
+
+ M ./Makefile.am -1 +1
+
+ * updated STUN API, tport-stun-http mods in progress (mm)
+
+ M ./libsofia-sip-ua/nta/nta.c -1 +1
+ M ./libsofia-sip-ua/stun/sofia-sip/stun.h -24 +74
+ M ./libsofia-sip-ua/stun/stun.c -23 +101
+ M ./libsofia-sip-ua/stun/stunc.c -4 +4
+ M ./libsofia-sip-ua/tport/tport.c -30 +122
+
+ * Added STUNTAG_DOMAIN to suitable places. Added more doxygen documentation - especially considering tag params to functions.
+
+ M ./libsofia-sip-ua/stun/stun.c -7 +39
+
+ * Added STUN DNS-SRV functionality to stun module. A simple test app is also provided. This code is not yet used by other parts of the stun module.
+
+ M ./RELEASE +1
+ M ./libsofia-sip-ua/stun/Makefile.am -8 +5
+ A ./libsofia-sip-ua/stun/lookup_stun_server.c
+ M ./libsofia-sip-ua/stun/sofia-sip/stun.h -3 +24
+ A ./libsofia-sip-ua/stun/stun_dns.c
+
+ * Updates to stun module doxygen documentation.
+
+ M ./libsofia-sip-ua/stun/sofia-sip/stun.h -44 +31
+ M ./libsofia-sip-ua/stun/stun.c -15 +38
+
+ * async stun bind in tport, callback to NTA (mm)
+
+ M ./libsofia-sip-ua/nta/nta.c -8 +18
+ M ./libsofia-sip-ua/stun/sofia-sip/stun.h +24
+ M ./libsofia-sip-ua/stun/sofia-sip/stun_tag.h +5
+ M ./libsofia-sip-ua/stun/stun.c -31 +122
+ M ./libsofia-sip-ua/stun/stun_common.c -1
+ M ./libsofia-sip-ua/stun/stun_tag.c +19
+ M ./libsofia-sip-ua/stun/stunc.c -4 +4
+ M ./libsofia-sip-ua/stun/torture_stun.c -1 +1
+ M ./libsofia-sip-ua/tport/tport.c -78 +331
+
+ * Checking for re-registration upon nat binding change. (pp)
+
+ M ./libsofia-sip-ua/nua/test_nua.c -10 +66
+
+ * Added keepalive and probe OPTIONS to registration. (pp)
+
+ M ./libsofia-sip-ua/nua/nua_options.c +3
+ M ./libsofia-sip-ua/nua/nua_register.c -309 +685
+ M ./libsofia-sip-ua/nua/nua_stack.h +6
+
+ * Removed warning. (pp)
+
+ M ./libsofia-sip-ua/nua/nua_subnotref.c -1 +1
+
+ * Removing dialog usages when handle is being destroyed. (pp)
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -2 +7
+
+ * Added nua_dialog_usage_refresh() and nua_dialog_usage_public(). (pp)
+
+ M ./libsofia-sip-ua/nua/nua_dialog.c +15
+ M ./libsofia-sip-ua/nua/nua_dialog.h -2 +13
+
+ * Added test_nat_flush(). (pp)
+
+ M ./libsofia-sip-ua/nua/test_nat.c -14 +109
+ M ./libsofia-sip-ua/nua/test_nat.h +2
+
+ * Handling multiple bindings in test_proxy.c. (pp)
+
+ M ./libsofia-sip-ua/nua/test_proxy.c -46 +244
+
+ * Added nta_agent_bind_tport_update(), nta_agent_tport_is_updating() functions. (pp)
+ Added tport_is_updating(), too. Removed NTATAG_UPDATE_TPORT().
+
+ M ./libsofia-sip-ua/nta/nta.c -5 +19
+ M ./libsofia-sip-ua/nta/nta_internal.h +2
+ M ./libsofia-sip-ua/nta/nta_tag.c -1
+ M ./libsofia-sip-ua/nta/sofia-sip/nta_tag.h -9
+ M ./libsofia-sip-ua/nta/sofia-sip/nta_tport.h -1 +10
+ M ./libsofia-sip-ua/tport/sofia-sip/tport.h -2 +2
+ M ./libsofia-sip-ua/tport/tport.c +6
+
+ * Added nua_prack(). (pp)
+
+ M ./libsofia-sip-ua/nua/nua.c -9 +29
+
+ * Do not log error if su_timer_set() is called with NULL timer. (pp)
+
+ M ./libsofia-sip-ua/su/su_timer.c -3 +1
+
+ * Added su_task_execute(). (pp)
+
+ M ./libsofia-sip-ua/su/sofia-sip/su_wait.h +4
+ M ./libsofia-sip-ua/su/su_root.c +71
+
+ * Fixed event saving and handling. (pp)
+ Now we have a separate list for special events (nua_i_outbound).
+
+ M ./libsofia-sip-ua/nua/test_nua.c -304 +356
+
+ * Added nua_i_outbound. (pp)
+
+ M ./libsofia-sip-ua/nua/nua_common.c +1
+ M ./libsofia-sip-ua/nua/sofia-sip/nua.h +2
+
+ * Deregistering wait events. (pp)
+
+ M ./libsofia-sip-ua/nua/test_nat.c -1 +8
+
+ * Mention Sofia-SIP User Agent Library instead Nokia UA Library in dox. (pp)
+
+ M ./libsofia-sip-ua/nua/nua.c -3 +3
+ M ./libsofia-sip-ua/nua/nua_dialog.h -1 +1
+ M ./libsofia-sip-ua/nua/nua_stack.c -1 +1
+ M ./libsofia-sip-ua/nua/nua_stack.h -1 +1
+ M ./libsofia-sip-ua/nua/sofia-sip/nua.h -1 +2
+ M ./libsofia-sip-ua/nua/sofia-sip/nua_tag.h -2 +2
+
+ * Fixed request line handling bug in nta_msg_request_complete(). (pp)
+
+ M ./libsofia-sip-ua/nta/nta.c -3 +9
+
+ * Using SOFIAPUBFUN in msg_header.h. Avoiding use of msg_param_t where possible. (pp)
+
+ API CHANGE:
+ Allowing NULL as message public pointer (using default) in calls to
+ msg_serialize(), msg_header_add(), msg_header_prepend(),
+ msg_header_add_dup(), msg_header_add_dup_as(), msg_header_add_make(),
+ msg_header_add_str(), msg_header_insert(), msg_header_remove(),
+ msg_header_remove_all(), and msg_header_replace().
+
+ M ./libsofia-sip-ua/msg/msg_parser.c -155 +182
+ M ./libsofia-sip-ua/msg/msg_parser_util.c -3 +3
+ M ./libsofia-sip-ua/msg/sofia-sip/msg_header.h -89 +138
+
+ * Added OPTIONS keepalive to nua_register.c. (pp)
+
+ M ./libsofia-sip-ua/nua/nua_register.c -208 +526
+
+ * Added nta_default_leg(). (pp)
+
+ M ./libsofia-sip-ua/nta/nta.c +7
+ M ./libsofia-sip-ua/nta/sofia-sip/nta.h +2
+
+ * Added process_options() to test_proxy. (pp)
+
+ M ./libsofia-sip-ua/nua/test_proxy.c -28 +132
+
+ * Added nua_creq_save_restart() to nua_stack. (pp)
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -20 +39
+ M ./libsofia-sip-ua/nua/nua_stack.h +6
+
+ * Added url_cmp_all(). (pp)
+
+ M ./libsofia-sip-ua/url/sofia-sip/url.h -1 +5
+ M ./libsofia-sip-ua/url/torture_url.c -3 +21
+ M ./libsofia-sip-ua/url/url.c -15 +177
+
+ * nua_dialog_store_peer_info() now optionally removes peer info. (pp)
+ If the SIP message given to nua_dialog_store_peer_info() is redirection
+ response, reset peer info.
+
+
+ M ./libsofia-sip-ua/nua/nua_dialog.c +14
+
+ * Fixed bug in sip_transport_d() parsing different tls transports. (pp)
+ This bug affected mainly parsing futuristic Via headers.
+
+ M ./libsofia-sip-ua/sip/sip_parser.c -2 +3
+ M ./libsofia-sip-ua/sip/torture_sip.c +48
+
+ * Fixed sip_contact_string_from_via() (pp)
+
+ M ./libsofia-sip-ua/sip/sip_util.c -2 +2
+
+ * Registering successfully behind NAT. (pp)
+
+ M ./libsofia-sip-ua/nua/nua_register.c -125 +589
+ M ./libsofia-sip-ua/nua/nua_stack.c -121 +49
+ M ./libsofia-sip-ua/nua/nua_stack.h +6
+ M ./libsofia-sip-ua/nua/nua_subnotref.c -9 +10
+ M ./libsofia-sip-ua/nua/nua_tag.c +3
+ M ./libsofia-sip-ua/nua/sofia-sip/nua_tag.h +20
+
+ * Added sip_contact_string_from_via(), sip_transport_has_tls(). (pp)
+
+ M ./libsofia-sip-ua/sip/sip_basic.c -53 +1
+ M ./libsofia-sip-ua/sip/sip_util.c -37 +133
+ M ./libsofia-sip-ua/sip/sofia-sip/sip_util.h +11
+
+2006-03-16 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ Synchronizing CVS with darcs.
+
+ * Fixed lib-sofia-sip-ua-glib Makefile.ams.
+ Tried to sanitize glib-less compilation.
+
+ M ./Makefile.am -2 +6
+ M ./libsofia-sip-ua-glib/Makefile.am -12 +4
+ M ./libsofia-sip-ua-glib/nua-glib/Makefile.am -2
+
+ * Added host_has_domain_invalid().
+
+ M ./libsofia-sip-ua/bnf/bnf.c -3 +23
+ M ./libsofia-sip-ua/bnf/sofia-sip/hostdomain.h +1
+ M ./libsofia-sip-ua/bnf/torture_bnf.c +18
+
+ * More string manipulation functions
+ Added:
+ - su_strcat_all()
+ - su_slprintf(), su_slvprintf()
+ - su_strlst_create_with(), su_strlst_vcreate_with()
+ - su_strlst_create_with_dup(), su_strlst_vcreate_with_dup()
+
+ M ./libsofia-sip-ua/su/sofia-sip/su_alloc.h -1 +4
+ M ./libsofia-sip-ua/su/sofia-sip/su_strlst.h -1 +23
+ M ./libsofia-sip-ua/su/su_alloc_test.c -32 +74
+ M ./libsofia-sip-ua/su/su_sprintf.c -1 +1
+ M ./libsofia-sip-ua/su/su_strdup.c -6 +53
+ M ./libsofia-sip-ua/su/su_strlst.c -23 +197
+
+ * Binding the endpoint behind "nat" to both IP families, if possible.
+
+ M ./libsofia-sip-ua/nua/test_nua.c -3 +13
+
+ * Removed nutag_media_subsystem and nutag_media_session.
+
+ M ./libsofia-sip-ua/nua/nua_tag.c -3
+
+ * Using nua_500_error.
+
+ M ./libsofia-sip-ua/nua/nua_event_server.c -2 +2
+
+ * Allowing intending of #include directives in fix-include-sofia-sip.
+
+ M ./scripts/fix-include-sofia-sip -197 +197
+
+2006-03-13 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Release 1.11.7
+
+ * Synchronized CVS with darcs.
+
+ * Added man pages to dist.
+
+ * Updated libsofia-sip-ua-glib dist targets.
+
+ M ./libsofia-sip-ua-glib/Makefile.am -2 +4
+ M ./libsofia-sip-ua-glib/nua-glib/Makefile.am -26 +25
+ M ./libsofia-sip-ua-glib/su-glib/Makefile.am -2 +6
+ M ./libsofia-sip-ua/sofia.am -1 +1
+
+ * Removed warnings on 64bit platforms.
+
+ M ./libsofia-sip-ua/soa/soa.c -3 +3
+ M ./libsofia-sip-ua/stun/stun_common.c -8 +19
+ M ./libsofia-sip-ua/su/su_timer_test.c -2 +1
+
+ * Added missing files to dist.
+
+ M ./libsofia-sip-ua/bnf/Makefile.am -1 +1
+ M ./libsofia-sip-ua/nua/Makefile.am -1 +1
+
+ * Using alarm() with su_test.c.
+
+ * Fixed hc_print usage in msg_header_prepare().
+ Some headers use snprintf() which may return -1 on some platforms if
+ buffer is too small.
+
+ * Fixed problems in test_nua on win32.
+
+ * Fixed problem of using destroying registered handle in su_root.
+ This is a bug showing only in win32.
+
+ * Cleaning ACK transactions in test_proxy
+
+ * Fixed source file building rules for GNU make >= 3.80.
+ The way VPATH is handled and $@ expands has changed between GNU make 3.79
+ and 3.80.
+
+ M ./libsofia-sip-ua/http/Makefile.am -6 +14
+ M ./libsofia-sip-ua/msg/Makefile.am -13 +13
+ M ./libsofia-sip-ua/sip/Makefile.am -7 +18
+ M ./libsofia-sip-ua/sofia.am -1 +1
+
+ * Using sofia-sip/su_errno.h for error codes not present in win32.
+
+ M ./libsofia-sip-ua/msg/msg_mime.c -6 +1
+ M ./libsofia-sip-ua/msg/msg_parser.c -4
+ M ./libsofia-sip-ua/soa/soa.c -8 +1
+ M ./libsofia-sip-ua/su/sofia-sip/su_errno.h +36
+ M ./libsofia-sip-ua/su/su_errno.c -6 +22
+ M ./win32/sofia-sip/su_configure.h -7
+
+ * Fixed problems with nua timers.
+
+ M ./libsofia-sip-ua/nua/nua_dialog.c -2 +2
+ M ./libsofia-sip-ua/nua/nua_session.c -3 +7
+ M ./libsofia-sip-ua/nua/nua_stack.c -1 +1
+
+2006-03-13 Martti Mela <martti.mela at nokia.com>
+
+ * win32 defs, compiles and installs in mingw environment
+
+2006-03-09 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * Synchronized darcs and CVS.
+
+ * Added missing su_source_test.c file.
+
+ A ./libsofia-sip-ua-glib/su-glib/su_source_test.c
+
+ * Added missing Makefile.am for su-glib.
+
+ A ./libsofia-sip-ua-glib/su-glib/Makefile.am
+
+ * Modified Makefile.ams to correctly build the new glib library.
+
+ M ./configure.ac +4
+ A ./libsofia-sip-ua-glib/Makefile.am
+
+ * Added sofia-sip-ua-glib to the packaging files.
+
+ M ./packages/Makefile.am -2 +2
+ A ./packages/sofia-sip-ua-glib.pc.in
+ M ./packages/sofia-sip-ua.pc.in -2 +2
+ M ./packages/sofia-sip.spec.in -4 +7
+
+ * Added nua-glib module to the tree.
+
+ A ./libsofia-sip-ua-glib/nua-glib/
+ A ./libsofia-sip-ua-glib/nua-glib/Doxyfile
+ A ./libsofia-sip-ua-glib/nua-glib/Makefile.am
+ A ./libsofia-sip-ua-glib/nua-glib/nua_glib.c
+ A ./libsofia-sip-ua-glib/nua-glib/nua_glib.docs
+ A ./libsofia-sip-ua-glib/nua-glib/nua_glib_marshal.list
+ A ./libsofia-sip-ua-glib/nua-glib/sofia-sip/
+ A ./libsofia-sip-ua-glib/nua-glib/sofia-sip/nua_glib.h
+ A ./libsofia-sip-ua-glib/nua-glib/test_nua_glib.c
+
+ * Moved glib stuff from libsofia-sip-ua to libsofia-sip-ua-glib.
+
+ ./libsofia-sip-ua/su/su_source.c -> ./libsofia-sip-ua-glib/su-glib/su_source.c
+ ./libsofia-sip-ua/su/sofia-sip/su_source.h -> ./libsofia-sip-ua-glib/su-glib/sofia-sip/su_source.h
+ A ./libsofia-sip-ua-glib/su-glib/
+ A ./libsofia-sip-ua-glib/su-glib/sofia-sip/
+ M ./libsofia-sip-ua-glib/su-glib/su_source.c -1 +3
+ M ./libsofia-sip-ua/Makefile.am -1
+ M ./libsofia-sip-ua/su/Makefile.am -10 +7
+ M ./libsofia-sip-ua/su/sofia-sip/su_configure.h.in -2
+ M ./libsofia-sip-ua/su/su_root_test.c -4
+ M ./libsofia-sip-ua/su/su_test.c -18 +2
+ M ./m4/sac-su2.m4 -5 +9
+
+ * Created libsofia-sip-ua-glib.
+
+ M ./Makefile.am -1 +1
+ A ./libsofia-sip-ua-glib/
+
+2006-03-09 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Updated globally unique identifier (uuid) generation.
+ Using getifaddrs() and /dev/urandom. Added checks for /dev/urandom
+ and <netpacket/packet.h> (for link-level addresses).
+
+ M ./configure.ac -13 +5
+ M ./libsofia-sip-ua/su/sofia-sip/su_uniqueid.h +3
+ M ./libsofia-sip-ua/su/su_uniqueid.c -15 +91
+ M ./m4/sac-general.m4 +16
+ M ./m4/sac-su2.m4 -1 +1
+
+ * Cache checked functions a bit more efficiently in sac-su2.m4.
+
+ M ./m4/sac-su2.m4 -25 +28
+
+ * Added sip_via_port().
+
+ M ./libsofia-sip-ua/nta/nta.c -15 +1
+ M ./libsofia-sip-ua/sip/sip_basic.c +38
+ M ./libsofia-sip-ua/sip/sofia-sip/sip_header.h -1 +4
+
+ * Using sofia-sip/sofia_features.h.
+
+ M ./libsofia-sip-ua/features/features.c -1 +1
+
+ * Using nua_owner_t instead of nua_handle_t with <nua_dialog.h>.
+ Prepare to move nua_dialog.[hc] to nta or to its own module.
+
+ M ./libsofia-sip-ua/nua/nua_dialog.c -114 +75
+ M ./libsofia-sip-ua/nua/nua_dialog.h -28 +19
+ M ./libsofia-sip-ua/nua/nua_register.c -1 +1
+ M ./libsofia-sip-ua/nua/nua_session.c -7 +8
+ M ./libsofia-sip-ua/nua/nua_stack.c -2 +2
+ M ./libsofia-sip-ua/nua/nua_stack.h -5 +5
+ M ./libsofia-sip-ua/nua/nua_subnotref.c -10 +10
+
+ * Added fake "nat" to test_nua
+
+ M ./libsofia-sip-ua/nua/Makefile.am -1 +2
+ A ./libsofia-sip-ua/nua/test_nat.c
+ A ./libsofia-sip-ua/nua/test_nat.h
+ M ./libsofia-sip-ua/nua/test_nua.c -30 +242
+
+ * Removed spurious message when sofia-sip subdirectory is recreated.
+
+ M ./libsofia-sip-ua/http/Makefile.am -1 +1
+ M ./libsofia-sip-ua/msg/Makefile.am -2 +2
+ M ./libsofia-sip-ua/sip/Makefile.am -1 +1
+
+2006-03-08 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Renamed sofia-sip/features.h as sofia-sip/sofia_features.h.
+
+ M ./RELEASE +3
+ M ./configure.ac -1 +1
+ M ./libsofia-sip-ua/features/Makefile.am -1 +1
+ M ./libsofia-sip-ua/features/sofia-sip/features.h.in -2 +4
+ M ./scripts/fix-include-sofia-sip -2 +5
+
+ * Generating man pages in $(srcdir).
+
+ M ./Makefile.am -5 +3
+
+ * Split nua_stack.c into multiple files.
+
+ M ./libsofia-sip-ua/nua/Makefile.am +6
+ M ./libsofia-sip-ua/nua/nua.c -52 +13
+ A ./libsofia-sip-ua/nua/nua_dialog.c
+ A ./libsofia-sip-ua/nua/nua_dialog.h
+ A ./libsofia-sip-ua/nua/nua_event_server.c
+ A ./libsofia-sip-ua/nua/nua_message.c
+ A ./libsofia-sip-ua/nua/nua_options.c
+ A ./libsofia-sip-ua/nua/nua_publish.c
+ A ./libsofia-sip-ua/nua/nua_register.c
+ A ./libsofia-sip-ua/nua/nua_session.c
+ M ./libsofia-sip-ua/nua/nua_stack.c -5026 +177
+ M ./libsofia-sip-ua/nua/nua_stack.h -125 +166
+ A ./libsofia-sip-ua/nua/nua_subnotref.c
+ A ./libsofia-sip-ua/nua/nua_tag_ref.c
+
+ * Added nta_check_*() functions.
+
+ M ./libsofia-sip-ua/nta/Makefile.am -1 +1
+ A ./libsofia-sip-ua/nta/nta_check.c
+ M ./libsofia-sip-ua/nta/sofia-sip/nta.h +26
+
+ * msg_parser.awk was printing spurious errors by SIP-ETag header etc.
+
+ * Removed doxygen crud from <sofia-sip/sl_utils.h>.
+
+ * Added SIPS_DEFAULT_PORT and SIPS_DEFAULT_SERV.
+
+ M ./libsofia-sip-ua/sip/sofia-sip/sip.h -1 +7
+
+ * Removed redundant reference to <sl_utils.h>.
+
+ M ./libsofia-sip-ua/nea/nea.c -2
+ M ./libsofia-sip-ua/nea/nea_server.c -1
+
+ * Added some error checking to the win32 autogen scripts.
+
+ M ./win32/Makefile.am -1 +1
+ M ./win32/autogen.cmd -2 +4
+ M ./win32/build_sources.cmd -22 +53
+ M ./win32/version_files.cmd +1
+
+2006-03-03 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Do not use glib upon --without-glib-dir or --without-glib in configure.
+
+ M ./m4/sac-su2.m4 -4 +4
+
+ * Returning unparsed remote SDP in SOATAG_REMOTE_SDP_STR()
+
+ M ./libsofia-sip-ua/soa/soa.c -2 +2
+
+ * Using SU_HAVE_PTHREADS to check for pthread support in nua_stack.h
+
+ M ./libsofia-sip-ua/nua/nua_stack.h -1 +5
+
+ * Fixed documentation problems.
+
+ M ./Makefile.am -2 +3
+ M ./utils/sip-date.c -2 +2
+
+ * Fixed problems when there is no stun available.
+
+ M ./libsofia-sip-ua/tport/tport.c -9 +5
+
+ * Fixed BDSSOCK checks in sac-su2.m4.
+
+ M ./libsofia-sip-ua/su/su_addrinfo.c -1 +1
+ M ./m4/sac-su2.m4 -55 +73
+
+ * Using int as SOATAG_AF() value.
+
+ M ./libsofia-sip-ua/soa/sofia-sip/soa_tag.h -2 +2
+ M ./libsofia-sip-ua/soa/test_soa.c -1 +1
+
+2006-03-03 Martti Mela martti.mela at nokia.com
+
+ * mingw support
+
+ M ./configure.ac -3 +5
+ M ./libsofia-sip-ua/stun/Makefile.am -4 +4
+ M ./libsofia-sip-ua/su/sofia-sip/su_addrinfo.h +11
+ M ./libsofia-sip-ua/su/su_addrinfo.c +9
+ M ./m4/sac-general.m4 +1
+ M ./m4/sac-su2.m4 -1 +9
+
+ * mingw mods
+
+ M ./configure.ac -1 +2
+ M ./libsofia-sip-ua/stun/Makefile.am -1 +1
+ M ./libsofia-sip-ua/stun/stun.c -3 +34
+ M ./libsofia-sip-ua/stun/stun_common.c +10
+ M ./libsofia-sip-ua/su/su_addrinfo.c -6 +2
+ M ./libsofia-sip-ua/su/su_source.c -1 +5
+ M ./libsofia-sip-ua/su/su_time0.c -1 +7
+ M ./libsofia-sip-ua/tport/tport.c -4 +8
+ M ./m4/sac-general.m4 +30
+ M ./m4/sac-su2.m4 -31 +72
+ M ./packages/sofia-sip.spec.in -1 +1
+
+2006-03-01 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Synchronized darcs and CVS.
+
+ * Added utils/Doxyfile
+
+ A ./utils/Doxyfile
+
+ * Changed output from localinfo so that emacs is not fooled anymore.
+
+ M ./libsofia-sip-ua/su/run_addrinfo -1 +1
+ M ./libsofia-sip-ua/su/run_localinfo -1 +1
+
+ * Added SU_ADDRLEN() macro.
+
+ M ./libsofia-sip-ua/su/sofia-sip/su.h +16
+
+ * Not creating sofia-sip when building sip_parser_table.c
+
+ M ./libsofia-sip-ua/sip/Makefile.am -1
+
+ * Printing warning message if resolv.conf nameserver address is IPv6.
+
+ M ./libsofia-sip-ua/sresolv/sresolv.c -4 +5
+
+ * Fixed problems with sa_len in nth_test.c.
+ Added explicit su_wait() to to send_request().
+
+ M ./libsofia-sip-ua/nth/nth_test.c -2 +8
+
+ * Disabling IPv6 resolving in nta test. Not reying in ICMP in nta test.
+
+ M ./libsofia-sip-ua/nta/run_test_nta -1 +2
+ M ./libsofia-sip-ua/nta/test_nta.c -2 +15
+
+ * Fixed problem of BSD awk returning -0 from 10 % 5.
+
+ M ./libsofia-sip-ua/msg/msg_parser.awk -1 +3
+
+ * Fixed problems in stun/tport.
+
+ M ./libsofia-sip-ua/stun/stun.c +3
+ M ./libsofia-sip-ua/tport/tport.c -9 +12
+
+ * Fixed signedness problem in msg_date_d().
+
+ M ./libsofia-sip-ua/msg/msg_date.c -2 +3
+
+ * Fixed url_cmp() crashing with invalid URLs.
+
+ M ./libsofia-sip-ua/url/sofia-sip/url.h -2 +3
+ M ./libsofia-sip-ua/url/url.c -2 +6
+
+ * Removed warnings on BSDish systems.
+
+ M ./libsofia-sip-ua/su/su.c -2 +2
+
+ * Added tests for getifaddrs(), using it in su_localinfo.c.
+
+ M ./libsofia-sip-ua/su/su_localinfo.c -40 +161
+ M ./libsofia-sip-ua/su/su_port.c +2
+ M ./m4/sac-su2.m4 -11 +8
+
+ * Fixed typo in utils/sip-date.c
+
+ M ./utils/sip-date.c -1 +1
+
+ * Defining missing SOL_TCP.
+
+ M ./libsofia-sip-ua/stun/stun.c +5
+
+ * Fixed A6 record handling, sa_len usage.
+ Removed some warnings, too. Disabled IN6 nameservers for the moment.
+
+ M ./libsofia-sip-ua/sresolv/sresolv.c -15 +20
+
+ * Disabled a badly designed test failing in BSD systems.
+
+ M ./libsofia-sip-ua/sresolv/test_sresolv.c -1 +16
+
+ * Removed debugging feature from msg_parser.awk making it fail with BSD awk.
+
+ M ./libsofia-sip-ua/msg/msg_parser.awk -36 +36
+
+ * Using default sip and sips port in url comparisons if url has IP address
+
+ M ./libsofia-sip-ua/url/torture_url.c +26
+ M ./libsofia-sip-ua/url/url.c +4
+
+2006-02-20 martti.mela at nokia.com
+
+ * stun: initial keepalive support
+
+ M ./libsofia-sip-ua/nta/nta.c +10
+ M ./libsofia-sip-ua/nta/sofia-sip/nta.h +2
+ M ./libsofia-sip-ua/nua/nua_stack.c +4
+ M ./libsofia-sip-ua/stun/ChangeLog +31
+ M ./libsofia-sip-ua/stun/sofia-sip/stun.h -1 +11
+ M ./libsofia-sip-ua/stun/stun.c -79 +219
+ M ./libsofia-sip-ua/stun/stun_internal.h -1
+ M ./libsofia-sip-ua/tport/sofia-sip/tport.h +3
+ M ./libsofia-sip-ua/tport/tport.c -1 +90
+
+ * stun: dst addr improvements
+
+ M! ./libsofia-sip-ua/stun/ChangeLog -18
+ M! ./libsofia-sip-ua/stun/stun.c -7 +16
+
+2006-02-20 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * If opaque is not given, do not include it in challenge (auth_module.c).
+
+ M ./libsofia-sip-ua/iptsec/auth_module.c -2 +4
+
+ * Generating man pages for utilities.
+
+ M ./Makefile.am -4 +22
+ M ./configure.ac +3
+ M ./libsofia-sip-ua/su/Doxyfile -3 +1
+ M ./libsofia-sip-ua/su/addrinfo.c -29 +24
+ M ./libsofia-sip-ua/su/localinfo.c -35 +29
+ M ./utils/Makefile.am +3
+ M ./utils/sip-date.c -44 +34
+ M ./utils/sip-options.c -30 +42
+
+ * Including <unistd.h> for getpid() in test_nta.c.
+
+ * Added install script.
+
+ A ./win32/install.cmd
+ M ./win32/libsofia-sip-ua/libsofia_sip_ua.dsp -4 +4
+
+ * Simplified use of sofia-sip/su_configure.h in win32
+
+ ./win32/su_configure_win32.h -> ./win32/sofia-sip/su_configure.h
+ M ./win32/autogen.cmd -4 +3
+ A ./win32/sofia-sip/
+
+ * Fixed tests of unsigned tag values in test_nua.c
+ Tests pass now on amd64, too.
+
+ M ./libsofia-sip-ua/nua/test_nua.c -4 +4
+
+2006-02-15 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Release 1.11.6.
+
+ * Fixed problems in doxygen documentation and dist.
+
+ * Updated PRACK and nta_outgoing_prack().
+
+ nta_outgoing_prack() accepts now RSeq sequence numbers in NTATAG_RSEQ().
+ When PRACK is sent using nta_outgoing_tmcreate(), there is functions
+ nta_outgoing_setrseq() and nta_outgoing_rseq() for updating the rseq number
+ within transaction.
+
+ * Corrected su_torture.c, Shutdown semantics differ on WINSOCK/BSDSOCK.
+
+ * Fixed su_wait() with 0 wait objects in windows.
+
+ * Fixed win32-compatibility problems in test programs.
+
+ * Not using NULL restart pointer in ua_authenticate().
+
+2006-02-14 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Fixed problems with sofia-sip/ header prefix in win32.
+
+ * Fixed win32/VC configuration problems.
+
+ * Fixed win32 pthread dist.
+
+ * Fixed include paths.
+
+ * Use #include <sofia-sip/su_tag_class.h>.
+
+ * Be explicit with input when generating source files.
+
+ * Added make target clean-built-sources.
+
+ * Fixed #include su_module_debug.h.
+
+ * Moved public include files to sofia-sip subdirectories.
+
+ All public include files installed in ${sofiadir} are now in sofia-sip
+ subdirectories. They are installed to ${sofiadir}/sofia-sip, too.
+
+ ${sofiadir} is defined by configure script relative to your ${prefix}, by
+ default ${sofidir} is ${prefix}/include/sofia-sip-1.11. The default prefix
+ is /usr/local and ${sofiadir} is /usr/local/include/sofia-sip-1.11. When
+ using package manager, the ${prefix} is usually /usr and ${sofiadir} is
+ /usr/include/sofia-sip-1.11.
+
+ The public include files should be referenced using sofia-sip path, e.g.,
+ <sofia-sip/su.h>.
+
+ You can either fix your applications to use the new include file names
+ with the fix-include-sofia-sip sed script found in scripts/ directory, or
+ add both ${sofiadir} and ${sofiadir}/sofia-sip into your include path,
+ e.g.,
+
+ INCLUDES = -I/usr/include/sofia-1.11 -I/usr/include/sofia-1.11/sofia-sip
+
+ At the same time, I took the liberty to rename two include files
+
+ sofia_sip_features.h => sofia-sip/features.h
+ su_memmem.h => sofia-sip/su_bm.h
+
+ The fix-include-sofia-sip sed script takes care of both of them.
+
+ * Improved 100rel handling in nua.
+ Added test_100rel to test_nua.c.
+
+ * Using CONDITION_PARAMS macro instead of CONDITION_FUNCTION in test_nua.c
+
+ * Improving getaddrinfo replacements.
+ Testing functions getaddrinfo()/freeaddrinfo(), getnameinfo() and
+ gai_strerror() separately.
+ There is no gai_strerror() in windows, I think.
+
+2006-02-03 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Code cleanup and memory leak fix in soa/sdp.
+ Fixed memory leak related to parsing sdp in soa.
+ Cleaned up handling of rejected media (related to bug report #1419078).
+
+ ./libsofia-sip-ua/sdp/run-tests -> ./libsofia-sip-ua/sdp/run_test_sdp
+ ./libsofia-sip-ua/sdp/sdp_test.c -> ./libsofia-sip-ua/sdp/test_sdp.c
+ ./libsofia-sip-ua/sdp/sdp_torture.c -> ./libsofia-sip-ua/sdp/torture_sdp.c
+ M ./libsofia-sip-ua/sdp/Makefile.am -4 +4
+ M ./libsofia-sip-ua/sdp/run_test_sdp -4 +4
+ M ./libsofia-sip-ua/sdp/sdp_parse.c -8 +11
+ M ./libsofia-sip-ua/sdp/sdp_print.c -1 +5
+ M ./libsofia-sip-ua/sdp/test_sdp.c -6 +6
+ M ./libsofia-sip-ua/sdp/torture_sdp.c -47 +38
+ M ./libsofia-sip-ua/soa/soa.c -13 +20
+ M ./libsofia-sip-ua/soa/soa_static.c -11
+
+2006-02-02 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Add helper functions to update or modify sdp attributes.
+ Feature request #1420698:
+ Added sdp_attribute_append(), sdp_attribute_replace(), and
+ sdp_attribute_remove().
+
+ M ./libsofia-sip-ua/sdp/sdp.c -18 +115
+ M ./libsofia-sip-ua/sdp/sdp.h -9 +21
+ M ./libsofia-sip-ua/sdp/sdp_torture.c -1 +22
+
+ * Using unsigned in bit fields.
+
+ M ./libsofia-sip-ua/sdp/sdp_print.c -2 +2
+
+ * Fixed bug in sending error response to a request containing Record-Route.
+
+ M ./libsofia-sip-ua/nta/nta.c -30 +33
+
+2006-01-25 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Updated autoconf macros.
+ Using cache for various checks.
+ Deprecated HAVE_LONG_LONG (use #ifdef longlong instead).
+ Collected information used by su_localinfo.c to one place.
+
+ M ./libsofia-sip-ua/su/su_taglist.c -2 +2
+ M ./m4/sac-su2.m4 -64 +103
+
+ * Updated Win32 port.
+ Added autogen.cmd, build_sources.cmd, version_files.cmd and version.awk.
+ Fixed problems with configuration.
+ Updated pthread-w32 to version 2.7.0.
+
+ * Fixed VC/Win32 problems in libsofia-sip-ua.
+ Signedness problems, includes, linkage, winsock initialization.
+
+ M ./libsofia-sip-ua/msg/msg_types.h -1 +2
+ M ./libsofia-sip-ua/nta/nta.c -2 +2
+ M ./libsofia-sip-ua/nua/test_nua.c -5 +5
+ M ./libsofia-sip-ua/nua/test_proxy.c -7 +11
+ M ./libsofia-sip-ua/su/su_root.c +8
+ M ./libsofia-sip-ua/su/su_types.h +2
+ M ./libsofia-sip-ua/su/su_wait.h +2
+
+ * Fixed gawk internal error in msg_parser.awk.
+ It looks like some gawk versions had problems when a function argument
+ was an unitialized variable.
+
+ M ./libsofia-sip-ua/msg/msg_parser.awk -1 +6
+
+ * Defining missing error codes in <su_errno.h>.
+
+ M ./libsofia-sip-ua/msg/msg_mime.c -7
+ M ./libsofia-sip-ua/soa/soa.c -7
+ M ./libsofia-sip-ua/stun/stun.c -6
+ M ./libsofia-sip-ua/su/su_errno.h +12
+ M ./libsofia-sip-ua/su/su_memmem.c -7 +2
+ M ./libsofia-sip-ua/tport/tport.c -5
+
+ * Added checks for different net includes.
+ Checks for sys/ioctl.h, netinet/in.h, net/if.h net/if_types.h and sys/ioctl.h.
+
+ M ./libsofia-sip-ua/su/su_localinfo.c -12 +16
+ M ./m4/sac-su2.m4 -2 +7
+
+ * Fixed rejection of subscriptions in nea server.
+ Event server does not send extra NOTIFY before 403 response anymore.
+
+ M ./libsofia-sip-ua/nea/nea_server.c -1 +1
+
+ * Added functions for scanning domain names and IP addresses.
+ Added span_ip4_address()/scan_ip4_address(),
+ span_ip6_address()/scan_ip6_address(),
+ span_ip6_reference()/scan_ip6_reference(),
+ span_ip_address()/scan_ip_address(),
+ span_domain()/scan_domain(), and
+ span_host()/scan_host().
+
+ M ./libsofia-sip-ua/bnf/bnf.c -2 +588
+ M ./libsofia-sip-ua/bnf/bnf.h -2 +18
+ M ./libsofia-sip-ua/bnf/torture_bnf.c -25 +220
+
+2006-01-23 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Removed *_dll.h files - defining *_DLL macros in <su_config.h>.
+
+ * Using random probe when finding port that is available with all transports.
+
+ * Updated auth_mod API.
+
+ Added auth_status_ref().
+ Removed antique functions auth_mod_check_ireq(), auth_mod_check_ireq2() and
+ auth_mod_check_msg().
+
+2006-01-10 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Fixed doxygen input files (kv).
+
+ * Using su_home_t reference counting in nua.
+
+ * Modified cloned su_home_t semantics.
+
+ Now we allow reference counting for clones as well as threadsafeness for them.
+ Added su_home_is_threadsafe(), modified prototype of su_home_unref().
+
+ * Fixed memory leaks in nea test code.
+
+ * Fixed memory leak in nea_server.c
+
+2006-01-09 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Restorered tag lists for modules.
+
+ M ./libsofia-sip-ua/nta/Makefile.am +2
+ M ./libsofia-sip-ua/nta/nta_tag.h +3
+ M ./libsofia-sip-ua/nth/nth_tag.h +3
+ M ./libsofia-sip-ua/nua/Makefile.am +2
+ M ./libsofia-sip-ua/nua/nua_tag.h +3
+ M ./libsofia-sip-ua/sip/sip_tag.c.in +13
+ M ./libsofia-sip-ua/sip/sip_tag.h.in +3
+ M ./libsofia-sip-ua/soa/Makefile.am +1
+ M ./libsofia-sip-ua/soa/soa_tag.h +3
+ M ./libsofia-sip-ua/stun/Makefile.am -2 +8
+ M ./libsofia-sip-ua/su/tag_dll.awk -3 +5
+ M ./libsofia-sip-ua/tport/tport_tag.h -1 +4
+ M ./utils/Makefile.am +4
+
+ * Fixed test code for pthread_rwlock_trywrlock().
+
+ M ./m4/sac-su2.m4 -3 +3
+
+2006-01-05 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ 2nd sync today for darcs and CVS.
+
+ * Added namespace-specific filter tags.
+
+ * Freeing nua_r_authorize events.
+
+ * Added NSTAG_TYPEDEF(t) and ns_tag_class[].
+
+ * Not using <msg_auth.h>.
+
+ Synching darcs and CVS.
+
+ * Not using msg_auth.h anymore.
+
+ M ./libsofia-sip-ua/msg/msg_auth.c -1
+ M ./libsofia-sip-ua/msg/test_msg.c -1
+
+ * Really adding expires=0 to all contacts when un-registering.
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -1 +1
+ M ./libsofia-sip-ua/nua/test_nua.c -3 +26
+
+ * Removed sip_rfc2543 files.
+
+ R ./libsofia-sip-ua/sip/sip_rfc2543.c
+ R ./libsofia-sip-ua/sip/sip_rfc2543.h.in
+
+ * Adding nua_authenticate() tags to request.
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -2 +1
+ M ./libsofia-sip-ua/nua/test_nua.c +12
+
+ * Using unsigned in sdp_media_t::m_mode bitfield.
+ enum is signed in VC6.
+
+ M ./libsofia-sip-ua/sdp/sdp.h -1 +1
+
+ * Documented sdp_f_mode_manual and sdp_f_mode_always better.
+
+ M ./libsofia-sip-ua/sdp/sdp.h -1 +1
+ M ./libsofia-sip-ua/sdp/sdp_print.c -8 +10
+
+2006-01-03 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ Syncinc darcs and CVS.
+
+ * Added more tests for call hold.
+
+ * Using msg_header_replace_param() in nua_stack.c.
+
+ * Using ss_retry_after in nea.c.
+
+ * Marking two single headers in a message as fatal error.
+
+ * Made headers C++-safe (bug #1376379).
+
+ * Removed dead #include files
+
+ * Removed Last modified things.
+
+ * Removed msg_bnf.h
+
+ * Added NTATAG_TCP_RPORT().
+ Do not use rport with TCP by default.
+
+ * Added test for comp=sigcomp.
+ The comp=sigcomp should not be included if destination does not support
+ compression.
+ Modernized parameter handling, too.
+
+ * Documented TP_AI_ flags.
+ Test our TP_AI_ assumptions.
+ Added a test for asymmetric SigComp on TCP.
+ We use TP_AI_COMPRESSED flag in this test.
+
+ * Added TPTAG_FRESH() and a test for it.
+
+ * Augmented documentation for SIPTAG_HEADER_STR().
+
+ * Use #include <stdio.h> for FILE.
+
+ * Fixed include_sofiadir handling in pkg-config and rpm files.
+
+2005-12-27 Martti Mela <martti.mela at nokia.com
+
+ * stun minor update
+
+ * first working version of STUN transaction engine
+
+ * stun transaction engine, first impressions
+
+
+2005-12-23 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ Syncing darcs and CVS.
+
+ * Added stun_internal.h to dist.
+
+ M ./libsofia-sip-ua/stun/Makefile.am -1 +1
+
+ * Better handling of optional tags in nta_agent_get_params().
+
+ M ./libsofia-sip-ua/nta/nta.c +4
+ M ./libsofia-sip-ua/nta/test_nta_api.c -8 +9
+
+ * Removed warnings from su_perror() (moved to su_log.h).
+
+ M ./libsofia-sip-ua/su/poll_test.c +1
+ M ./libsofia-sip-ua/su/su_test.c +2
+ M ./libsofia-sip-ua/su/su_timer_test.c +1
+
+ * Added su_errno.h and su_errno.c.
+
+ M ./libsofia-sip-ua/su/Makefile.am -2 +2
+ M ./libsofia-sip-ua/su/su.c -103
+ M ./libsofia-sip-ua/su/su.h -15 +3
+ A ./libsofia-sip-ua/su/su_errno.c
+ A ./libsofia-sip-ua/su/su_errno.h
+ M ./libsofia-sip-ua/su/su_log.c -2 +13
+ M ./libsofia-sip-ua/su/su_log.h -2 +6
+
+ * Prepare for 1.11.5pre1.
+
+ M ./RELEASE -2 +41
+ M ./TODO -2 +5
+ M ./configure.ac -2 +9
+
+ * Added su_home_destructor() to su_alloc.[hc].
+
+ M ./libsofia-sip-ua/su/su_alloc.c -9 +56
+ M ./libsofia-sip-ua/su/su_alloc.h -6 +11
+ M ./libsofia-sip-ua/su/su_alloc_lock.c -15 +18
+ M ./libsofia-sip-ua/su/su_alloc_test.c -20 +40
+
+ * Building features module first after su.
+
+ M ./libsofia-sip-ua/Makefile.am -2 +2
+
+ * Using su_home_new(size) instead of su_home_clone(NULL, size).
+
+ M ./libsofia-sip-ua/http/test_http.c -1 +1
+ M ./libsofia-sip-ua/iptsec/auth_module.c -1 +1
+ M ./libsofia-sip-ua/iptsec/test_auth_digest.c -2 +2
+ M ./libsofia-sip-ua/nea/nea.c -1 +1
+ M ./libsofia-sip-ua/nea/nea_server.c -1 +1
+ M ./libsofia-sip-ua/sip/torture_sip.c -7 +7
+
+ * Improved argument checking in sresolv.
+
+ M ./libsofia-sip-ua/sresolv/sresolv.c -67 +118
+ M ./libsofia-sip-ua/sresolv/sresolv.h -4 +3
+ M ./libsofia-sip-ua/sresolv/test_sresolv.c -13 +26
+
+ * Updated function names in conformance.docs.
+
+ M ./libsofia-sip-ua/docs/conformance.docs -17 +17
+
+ * Fixed problems with autogenerating files with header boilerplates.
+
+ M ./libsofia-sip-ua/http/Makefile.am -2 +4
+ M ./libsofia-sip-ua/sip/Makefile.am -2 +5
+
+ * Added explicit dependencies for autogenerated sources.
+
+ M ./libsofia-sip-ua/msg/Makefile.am -2 +6
+
+ * Using parameter manipulation functions and shortcuts.
+
+ M ./libsofia-sip-ua/nea/nea.c -3 +2
+ M ./libsofia-sip-ua/nta/nta.c -5 +5
+ M ./libsofia-sip-ua/nta/test_nta.c -2 +2
+ M ./libsofia-sip-ua/nua/nua_stack.c -6 +18
+
+ * Fixed su_home_auto() problems.
+
+ M ./libsofia-sip-ua/su/su_alloc.c -4 +8
+
+ * Added hc_update member to msg_hclass_t.
+ The hc_update is used to update shortcuts to well-known parameters.
+ Updated manipulation functions for header parameters to use hc_update.
+ Added updating functions for SIP headers.
+
+ M ./libsofia-sip-ua/http/http_parser.h -4 +6
+ M ./libsofia-sip-ua/msg/msg_basic.c -4 +10
+ M ./libsofia-sip-ua/msg/msg_header_copy.c +6
+ M ./libsofia-sip-ua/msg/msg_mime.c -60 +86
+ M ./libsofia-sip-ua/msg/msg_mime.h -2 +2
+ M ./libsofia-sip-ua/msg/msg_mime_protos.h.in +5
+ M ./libsofia-sip-ua/msg/msg_mime_table.c.in -2 +5
+ M ./libsofia-sip-ua/msg/msg_parser.c +3
+ M ./libsofia-sip-ua/msg/msg_parser.h -14 +18
+ M ./libsofia-sip-ua/msg/msg_parser_util.c -20 +152
+ M ./libsofia-sip-ua/msg/msg_tag.c -1 +8
+ M ./libsofia-sip-ua/msg/msg_types.h +4
+ M ./libsofia-sip-ua/msg/test_class.c -2 +4
+ M ./libsofia-sip-ua/msg/test_msg.c -1 +1
+ M ./libsofia-sip-ua/sip/sip.h -4 +5
+ M ./libsofia-sip-ua/sip/sip_basic.c -158 +124
+ M ./libsofia-sip-ua/sip/sip_caller_prefs.c -54 +40
+ M ./libsofia-sip-ua/sip/sip_event.c -53 +49
+ M ./libsofia-sip-ua/sip/sip_extra.c -37 +36
+ M ./libsofia-sip-ua/sip/sip_mime.c -70 +15
+ M ./libsofia-sip-ua/sip/sip_parser.h -7 +10
+ M ./libsofia-sip-ua/sip/sip_prack.c +1
+ M ./libsofia-sip-ua/sip/sip_reason.c -15 +23
+ M ./libsofia-sip-ua/sip/sip_refer.c -36 +53
+ M ./libsofia-sip-ua/sip/sip_security.c -13 +35
+ M ./libsofia-sip-ua/sip/sip_session.c -2 +22
+ M ./libsofia-sip-ua/sip/torture_sip.c -13 +137
+
+ * Added manipulation functions for header parameters.
+ msg_header_find_param(), msg_header_add_param(),
+ msg_header_replace_param(), and msg_header_remove_param().
+
+ M ./libsofia-sip-ua/http/http_basic.c -1 +1
+ M ./libsofia-sip-ua/iptsec/auth_client.c -4 +5
+ M ./libsofia-sip-ua/iptsec/auth_module.c -3 +3
+ M ./libsofia-sip-ua/msg/msg_header.h -5 +9
+ M ./libsofia-sip-ua/msg/msg_mime.c -3 +3
+ M ./libsofia-sip-ua/msg/msg_parser.c -5 +5
+ M ./libsofia-sip-ua/msg/msg_parser_util.c +62
+ M ./libsofia-sip-ua/msg/test_msg.c +24
+
+Tue Dec 20 19:51:57 EET 2005 Pekka.Pessi at nokia.com
+ * Reduced overhead in su_home_auto().
+
+ M ./libsofia-sip-ua/su/su_alloc.c -5 +8
+ M ./libsofia-sip-ua/su/su_alloc.h -2 +5
+ M ./libsofia-sip-ua/su/su_alloc_test.c +12
+
+ * Fixed bug in histogram bucket search.
+ Bug was detected using coverity.
+
+ M ./libsofia-sip-ua/sip/validator.c -2 +2
+
+ * Updated param type and usage in SIP headers.
+ A single param has type "char const *".
+ Via has no "hidden" anymore, but "rport" and "comp" were added.
+ Contact has no "action" anymore.
+
+ M ./libsofia-sip-ua/sip/sip.h -42 +44
+ M ./libsofia-sip-ua/sip/sip_basic.c -12 +23
+ M ./libsofia-sip-ua/sip/sip_header.h -1 +1
+ M ./libsofia-sip-ua/sip/sip_util.c -9 +8
+ M ./libsofia-sip-ua/sip/sip_util.h -8 +5
+ M ./libsofia-sip-ua/sip/torture_sip.c +11
+
+ * Updated documentation of SIP headers.
+
+ M ./libsofia-sip-ua/sip/sip_event.c -10 +11
+ M ./libsofia-sip-ua/sip/sip_extra.c -5 +6
+
+ * Refactored sres_resolver_sockets().
+
+ M ./libsofia-sip-ua/sresolv/sresolv.c -57 +80
+
+ * Added stateless operation to test_proxy.
+ Using nta_incoming_default() and nta_outgoing_default().
+
+ M ./libsofia-sip-ua/nua/test_nua.c -3 +6
+ M ./libsofia-sip-ua/nua/test_proxy.c +46
+ M ./libsofia-sip-ua/nua/test_proxy.h -15 +2
+
+ * Added nta_outgoing_default(), nta_incoming_default().
+ Stateless response processing can be done with default transactions.
+ Also added nta_incoming_method_name(), nta_incoming_method_name() and
+ nta_incoming_gettag(). Deprecated nta_msg_response_complete().
+ Updated API tests.
+
+ M ./libsofia-sip-ua/nta/Makefile.am -3 +5
+ M ./libsofia-sip-ua/nta/nta.c -51 +268
+ M ./libsofia-sip-ua/nta/nta.h +8
+ M ./libsofia-sip-ua/nta/nta_internal.h -1 +5
+ A ./libsofia-sip-ua/nta/run_test_nta_api
+ A ./libsofia-sip-ua/nta/test_nta_api.c
+
+ * Replaced nta_msg_response_complete() with nta_incoming_complete_response().
+
+ M ./libsofia-sip-ua/nta/nta.c -61 +83
+ M ./libsofia-sip-ua/nta/nta.h -5 +9
+ M ./libsofia-sip-ua/nta/test_nta.c -628 +67
+
+ * Documented GUID format.
+
+ M ./libsofia-sip-ua/sip/sip_basic.c +6
+
+ * Added test_sec_ext() for testing security agreement headers.
+
+ M ./libsofia-sip-ua/sip/torture_sip.c +62
+
+ * Fixed handling of 6XX responses in sip_response_terminates_dialog().
+ Bug found by coverity.
+
+ M ./libsofia-sip-ua/sip/sip_util.c -1 +1
+
+ * Fixed bugs with auto allocation.
+ In C89 and later, the automatic variable may go away when block is exited.
+ The buggy code relied on behaviour of K&R C, where automatic variables are
+ reclaimed when function returns.
+
+ M ./libsofia-sip-ua/nea/nea.c -3 +2
+ M ./libsofia-sip-ua/nea/nea_server.c -5 +4
+ M ./libsofia-sip-ua/nta/nta.c -7 +4
+ M ./libsofia-sip-ua/nua/nua_stack.c -8 +6
+ M ./libsofia-sip-ua/su/su_localinfo.c -2 +2
+ M ./libsofia-sip-ua/tport/tport.c -2 +3
+
+ * Added ELI_BADHINTS to su_localinfo.
+
+ M ./libsofia-sip-ua/su/su_localinfo.c +3
+ M ./libsofia-sip-ua/su/su_localinfo.h -2 +3
+
+2005-12-02 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ Again, syncing darcs and CVS.
+
+ * Disabling stun for the moment, use --enable-stun to use it. [pp]
+
+ M ./configure.ac -2 +9
+
+ * working async stun support [mm]
+
+ M ./libsofia-sip-ua/stun/stun.c -139 +131
+ M ./libsofia-sip-ua/stun/stun.h -1 +3
+ M ./libsofia-sip-ua/stun/stun_common.c -14 +18
+ M ./libsofia-sip-ua/stun/stunc.c -21 +15
+ M ./libsofia-sip-ua/stun/torture_stun.c -1 +1
+
+ * initial async stun support. Does not work with tport yet. [mm]
+
+ M ./libsofia-sip-ua/stun/stun.c -269 +350
+ M ./libsofia-sip-ua/stun/stun.h -6 +28
+ M ./libsofia-sip-ua/stun/stun_common.c -5 +23
+ M ./libsofia-sip-ua/stun/stun_common.h -1 +1
+ M ./libsofia-sip-ua/stun/stun_internal.h -4 +5
+ M ./libsofia-sip-ua/stun/stunc.c -3 +10
+ M ./libsofia-sip-ua/stun/torture_stun.c -2 +2
+
+ * async stunning contd. Juhui! [mm]
+
+ M ./libsofia-sip-ua/stun/stun.c -19 +13
+ M ./libsofia-sip-ua/stun/stun_common.c -4 +9
+ M ./libsofia-sip-ua/stun/stun_internal.h -1 +16
+
+ * stun asyncing contd. NOT WORKING [mm]
+
+ M ./libsofia-sip-ua/stun/stun.c -70 +86
+ M ./libsofia-sip-ua/stun/stun.h -9 +7
+ M ./libsofia-sip-ua/stun/stun_common.c -3 +8
+ M ./libsofia-sip-ua/stun/stun_common.h -1 +4
+ M ./libsofia-sip-ua/stun/stun_internal.h -3 +6
+ M ./libsofia-sip-ua/stun/stunc.c -13 +17
+ M ./libsofia-sip-ua/stun/torture_stun.c -12 +15
+
+ * stun async contd. [mm]
+
+ M ./libsofia-sip-ua/stun/stun.c -26 +56
+ M ./libsofia-sip-ua/stun/stun.h +4
+ M ./libsofia-sip-ua/stun/stunc.c -4 +9
+
+ * DON'T APPLY THIS: does not work. I need this for syncing. [mm]
+
+ M ./libsofia-sip-ua/stun/stun.c -81 +209
+ M ./libsofia-sip-ua/stun/stun.h -3 +15
+ M ./libsofia-sip-ua/stun/stun_internal.h -1 +1
+ M ./libsofia-sip-ua/stun/stunc.c -3 +7
+ M ./libsofia-sip-ua/stun/torture_stun.c -4 +4
+
+ * async connect continued [mm]
+
+ M ./libsofia-sip-ua/stun/stun.c -24 +71
+
+ * async stun continued [mm]
+
+ M ./libsofia-sip-ua/stun/stun.c -27 +53
+ M ./libsofia-sip-ua/stun/torture_stun.c +7
+ M ./libsofia-sip-ua/tport/test_tport.c -1 +8
+ M ./libsofia-sip-ua/tport/tport.c -1 +2
+
+ * su_localinfo returns now valid address also in Windows [mm]
+
+ M ./libsofia-sip-ua/nua/test_nua.c +3
+ M ./libsofia-sip-ua/su/su_localinfo.c +4
+
+ * tport cygwin modifications [mm]
+
+ M ./libsofia-sip-ua/tport/tport.c -3 +7
+
+ * Declaring h_errno as a variable imported from DLL (when using WIN32). [pp]
+
+ M ./libsofia-sip-ua/su/su_addrinfo.c -3 +8
+
+ * Try random port next if a port is taken. [pp]
+
+ M ./libsofia-sip-ua/tport/tport.c -1 +2
+
+ * Moved LGPL reference so that it will be included in the autogenerated
+ files. [pp]
+
+ M ./libsofia-sip-ua/http/http_parser_table.c.in -8 +8
+ M ./libsofia-sip-ua/http/http_protos.h.in -6 +6
+ M ./libsofia-sip-ua/http/http_tag.c.in -8 +8
+ M ./libsofia-sip-ua/http/http_tag.h.in -7 +7
+ M ./libsofia-sip-ua/msg/msg_mime_protos.h.in -6 +6
+ M ./libsofia-sip-ua/msg/msg_protos.h.in -6 +6
+ M ./libsofia-sip-ua/msg/test_protos.h.in -7 +7
+ M ./libsofia-sip-ua/sip/sip_hclasses.h.in -6 +7
+ M ./libsofia-sip-ua/sip/sip_parser_table.c.in -7 +7
+ M ./libsofia-sip-ua/sip/sip_protos.h.in -5 +5
+ M ./libsofia-sip-ua/sip/sip_rfc2543.h.in -6 +5
+ M ./libsofia-sip-ua/sip/sip_tag.c.in -7 +7
+ M ./libsofia-sip-ua/sip/sip_tag.h.in -7 +7
+
+ * Collected copyrights belonging someone else but Nokia to COPYRIGHTS
+ file. [pp]
+
+ M ./COPYRIGHTS -1 +223
+ M ./libsofia-sip-ua/ipt/rc4.c -24
+ M ./libsofia-sip-ua/su/getopt.c -24
+ M ./libsofia-sip-ua/su/su_md5.c -11 +14
+
+ * Fixed bug in su_addrinfo.c [FIX]. [pp]
+ Setting ai_addrlen even if there is no sa_len.
+
+ M ./libsofia-sip-ua/su/su_addrinfo.c +1
+
+ * sresolv now compiles without IPv6 [mm]
+
+ M ./libsofia-sip-ua/nua/nua.h -2
+ M ./libsofia-sip-ua/sresolv/sresolv.c -1 +1
+ M ./libsofia-sip-ua/tport/tport.c -1 +1
+
+ * using 500 timers instead of 500000 timers in su_timer_test [mm]
+
+ M ./libsofia-sip-ua/su/su_timer_test.c -2 +2
+
+ * added #include <netinet/tcp.h> to stun_common.h [mm]
+
+ M ./libsofia-sip-ua/nth/Makefile.am -3 +2
+ M ./libsofia-sip-ua/stun/stun_common.h +1
+
+ * added stun_internal.h [mm]
+
+ A ./libsofia-sip-ua/stun/stun_internal.h
+
+ * tport_stun_cb parameter type change [mm]
+
+ R ./libsofia-sip-ua/sip/sip_p_tag.c
+ M ./libsofia-sip-ua/tport/tport.c -1 +1
+
+ * initial async stun, compiles not works. [mm]
+
+ M ./libsofia-sip-ua/nth/Makefile.am -2 +3
+ M ./libsofia-sip-ua/sip/sip_p_tag.c -105
+ M ./libsofia-sip-ua/stun/stun.c -65 +121
+ M ./libsofia-sip-ua/stun/stun.h -23 +18
+ M ./libsofia-sip-ua/stun/stunc.c -2 +26
+ M ./libsofia-sip-ua/stun/torture_stun.c -4 +29
+ M ./libsofia-sip-ua/tport/tport.c -3 +17
+
+ * Removed sip_rfc2543{.h,.h.in,.c} from dist. [pp]
+
+ M ./libsofia-sip-ua/sip/Makefile.am -3 +2
+
+2005-12-02 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ Again, syncing darcs and CVS.
+
+ * Disabling stun for the moment, use --enable-stun to use it. [pp]
+
+ M ./configure.ac -2 +9
+
+ * working async stun support [mm]
+
+ M ./libsofia-sip-ua/stun/stun.c -139 +131
+ M ./libsofia-sip-ua/stun/stun.h -1 +3
+ M ./libsofia-sip-ua/stun/stun_common.c -14 +18
+ M ./libsofia-sip-ua/stun/stunc.c -21 +15
+ M ./libsofia-sip-ua/stun/torture_stun.c -1 +1
+
+ * initial async stun support. Does not work with tport yet. [mm]
+
+ M ./libsofia-sip-ua/stun/stun.c -269 +350
+ M ./libsofia-sip-ua/stun/stun.h -6 +28
+ M ./libsofia-sip-ua/stun/stun_common.c -5 +23
+ M ./libsofia-sip-ua/stun/stun_common.h -1 +1
+ M ./libsofia-sip-ua/stun/stun_internal.h -4 +5
+ M ./libsofia-sip-ua/stun/stunc.c -3 +10
+ M ./libsofia-sip-ua/stun/torture_stun.c -2 +2
+
+ * async stunning contd. Juhui! [mm]
+
+ M ./libsofia-sip-ua/stun/stun.c -19 +13
+ M ./libsofia-sip-ua/stun/stun_common.c -4 +9
+ M ./libsofia-sip-ua/stun/stun_internal.h -1 +16
+
+ * stun asyncing contd. NOT WORKING [mm]
+
+ M ./libsofia-sip-ua/stun/stun.c -70 +86
+ M ./libsofia-sip-ua/stun/stun.h -9 +7
+ M ./libsofia-sip-ua/stun/stun_common.c -3 +8
+ M ./libsofia-sip-ua/stun/stun_common.h -1 +4
+ M ./libsofia-sip-ua/stun/stun_internal.h -3 +6
+ M ./libsofia-sip-ua/stun/stunc.c -13 +17
+ M ./libsofia-sip-ua/stun/torture_stun.c -12 +15
+
+ * stun async contd. [mm]
+
+ M ./libsofia-sip-ua/stun/stun.c -26 +56
+ M ./libsofia-sip-ua/stun/stun.h +4
+ M ./libsofia-sip-ua/stun/stunc.c -4 +9
+
+ * DON'T APPLY THIS: does not work. I need this for syncing. [mm]
+
+ M ./libsofia-sip-ua/stun/stun.c -81 +209
+ M ./libsofia-sip-ua/stun/stun.h -3 +15
+ M ./libsofia-sip-ua/stun/stun_internal.h -1 +1
+ M ./libsofia-sip-ua/stun/stunc.c -3 +7
+ M ./libsofia-sip-ua/stun/torture_stun.c -4 +4
+
+ * async connect continued [mm]
+
+ M ./libsofia-sip-ua/stun/stun.c -24 +71
+
+ * async stun continued [mm]
+
+ M ./libsofia-sip-ua/stun/stun.c -27 +53
+ M ./libsofia-sip-ua/stun/torture_stun.c +7
+ M ./libsofia-sip-ua/tport/test_tport.c -1 +8
+ M ./libsofia-sip-ua/tport/tport.c -1 +2
+
+ * su_localinfo returns now valid address also in Windows [mm]
+
+ M ./libsofia-sip-ua/nua/test_nua.c +3
+ M ./libsofia-sip-ua/su/su_localinfo.c +4
+
+ * tport cygwin modifications [mm]
+
+ M ./libsofia-sip-ua/tport/tport.c -3 +7
+
+ * Declaring h_errno as a variable imported from DLL (when using WIN32). [pp]
+
+ M ./libsofia-sip-ua/su/su_addrinfo.c -3 +8
+
+ * Try random port next if a port is taken. [pp]
+
+ M ./libsofia-sip-ua/tport/tport.c -1 +2
+
+ * Moved LGPL reference so that it will be included in the autogenerated
+ files. [pp]
+
+ M ./libsofia-sip-ua/http/http_parser_table.c.in -8 +8
+ M ./libsofia-sip-ua/http/http_protos.h.in -6 +6
+ M ./libsofia-sip-ua/http/http_tag.c.in -8 +8
+ M ./libsofia-sip-ua/http/http_tag.h.in -7 +7
+ M ./libsofia-sip-ua/msg/msg_mime_protos.h.in -6 +6
+ M ./libsofia-sip-ua/msg/msg_protos.h.in -6 +6
+ M ./libsofia-sip-ua/msg/test_protos.h.in -7 +7
+ M ./libsofia-sip-ua/sip/sip_hclasses.h.in -6 +7
+ M ./libsofia-sip-ua/sip/sip_parser_table.c.in -7 +7
+ M ./libsofia-sip-ua/sip/sip_protos.h.in -5 +5
+ M ./libsofia-sip-ua/sip/sip_rfc2543.h.in -6 +5
+ M ./libsofia-sip-ua/sip/sip_tag.c.in -7 +7
+ M ./libsofia-sip-ua/sip/sip_tag.h.in -7 +7
+
+ * Collected copyrights belonging someone else but Nokia to COPYRIGHTS
+ file. [pp]
+
+ M ./COPYRIGHTS -1 +223
+ M ./libsofia-sip-ua/ipt/rc4.c -24
+ M ./libsofia-sip-ua/su/getopt.c -24
+ M ./libsofia-sip-ua/su/su_md5.c -11 +14
+
+ * Fixed bug in su_addrinfo.c [FIX]. [pp]
+ Setting ai_addrlen even if there is no sa_len.
+
+ M ./libsofia-sip-ua/su/su_addrinfo.c +1
+
+ * sresolv now compiles without IPv6 [mm]
+
+ M ./libsofia-sip-ua/nua/nua.h -2
+ M ./libsofia-sip-ua/sresolv/sresolv.c -1 +1
+ M ./libsofia-sip-ua/tport/tport.c -1 +1
+
+ * using 500 timers instead of 500000 timers in su_timer_test [mm]
+
+ M ./libsofia-sip-ua/su/su_timer_test.c -2 +2
+
+ * added #include <netinet/tcp.h> to stun_common.h [mm]
+
+ M ./libsofia-sip-ua/nth/Makefile.am -3 +2
+ M ./libsofia-sip-ua/stun/stun_common.h +1
+
+ * added stun_internal.h [mm]
+
+ A ./libsofia-sip-ua/stun/stun_internal.h
+
+ * tport_stun_cb parameter type change [mm]
+
+ R ./libsofia-sip-ua/sip/sip_p_tag.c
+ M ./libsofia-sip-ua/tport/tport.c -1 +1
+
+ * initial async stun, compiles not works. [mm]
+
+ M ./libsofia-sip-ua/nth/Makefile.am -2 +3
+ M ./libsofia-sip-ua/sip/sip_p_tag.c -105
+ M ./libsofia-sip-ua/stun/stun.c -65 +121
+ M ./libsofia-sip-ua/stun/stun.h -23 +18
+ M ./libsofia-sip-ua/stun/stunc.c -2 +26
+ M ./libsofia-sip-ua/stun/torture_stun.c -4 +29
+ M ./libsofia-sip-ua/tport/tport.c -3 +17
+
+ * Removed sip_rfc2543{.h,.h.in,.c} from dist. [pp]
+
+ M ./libsofia-sip-ua/sip/Makefile.am -3 +2
+
+2005-12-02 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ Syncing darcs and CVS.
+
+ * Removed debugging printf()s. [pp]
+
+ M ./libsofia-sip-ua/su/su_root.c -16 +2
+
+ * Removed duplicate function msg_params_matching(). [pp]
+
+ M ./libsofia-sip-ua/msg/msg_header.h -2
+ M ./libsofia-sip-ua/msg/msg_parser_util.c -36
+ M ./libsofia-sip-ua/sip/sip_pref_util.c -1 +1
+
+ * Compilation support for non-IPv6 environments [pp]
+
+ M ./libsofia-sip-ua/nta/nta.c +9
+ M ./libsofia-sip-ua/nta/portbind.c -1 +2
+ M ./libsofia-sip-ua/nta/test_nta.c +5
+ M ./libsofia-sip-ua/sip/Makefile.am -2 +2
+ M ./libsofia-sip-ua/soa/soa.c +7
+ M ./libsofia-sip-ua/su/su.h +6
+ M ./libsofia-sip-ua/su/su_root.c +14
+ M ./libsofia-sip-ua/tport/test_tport.c -1 +1
+ M ./libsofia-sip-ua/tport/tport.c -1 +58
+
+ * additional #ifdefs for IPv6 (un)support. [mm]
+
+ M ./libsofia-sip-ua/sresolv/sresolv.c +13
+ M ./libsofia-sip-ua/sresolv/sresolv.h +4
+ M ./libsofia-sip-ua/sresolv/test_sresolv.c +18
+
+ * Added check for socket library. [pp]
+
+ M ./configure.ac -1
+ M ./m4/sac-su.m4 +2
+
+ * Fixed .h file generation. [pp]
+
+ M ./libsofia-sip-ua/msg/Makefile.am -1 +5
+
+ * Added test for recursive pthread_rwlock_rdlock()/pthread_rwlock_unlock().
+
+ M ./m4/sac-su2.m4 +41
+
+ * Using TP_AI flags not overlapping with AI flags in <su_addrinfo.h>. [pp]
+
+ M ./libsofia-sip-ua/tport/tport.c -4 +6
+
+ * Using red-black tree in su_timer.c. [pp]
+ Added test using 500000 timers in su_timer_test.c.
+
+ M ./libsofia-sip-ua/su/su_timer.c -130 +216
+ M ./libsofia-sip-ua/su/su_timer_test.c -13 +54
+
+ * Fixed bug in sdp_rtpmap_find_matching(). [pp]
+
+ M ./libsofia-sip-ua/sdp/sdp.c -3 +1
+
+ * Cleaned up su_addrinfo.c. [pp]
+ Cleaned up comments.
+ Using SU_HAVE_ flags.
+ Added support for SCTP in getaddrinfo() replacement.
+
+ M ./libsofia-sip-ua/su/su_addrinfo.c -10 +38
+
+ * Declaring sockaddr_storage in su.h if it is not provided in environment.
+
+ M ./libsofia-sip-ua/su/su.h +23
+ M ./libsofia-sip-ua/su/su_configure.h.in +3
+ M ./libsofia-sip-ua/su/su_configure_win32.h +6
+ M ./m4/sac-su2.m4 +7
+
+ * Support for CygWin's (buggy) pthread implementation. [mm]
+ Added SU_HAVE_IN6 for disabling IPv6 support from the environments
+ that do not support IPv6.
+
+ M ./libsofia-sip-ua/su/addrinfo.c +11
+ M ./libsofia-sip-ua/su/localinfo.c +6
+ M ./libsofia-sip-ua/su/su_localinfo.c -1 +4
+ M ./libsofia-sip-ua/su/su_port.c -1 +38
+ M ./libsofia-sip-ua/su/su_proxy.c +2
+ M ./libsofia-sip-ua/su/su_root_test.c -1 +3
+ M ./libsofia-sip-ua/su/su_test.c -4 +6
+
+2005-11-30 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ Syncing darcs with CVS.
+
+ * Silenced warning in su_addrinfo.c.
+
+ M ./libsofia-sip-ua/su/su_addrinfo.c -1 +2
+
+ * Added su_getaddrinfo() and su_getnameinfo() replacement functions.
+
+ M ./libsofia-sip-ua/su/Makefile.am -2 +3
+ M ./libsofia-sip-ua/su/su.c -58
+ M ./libsofia-sip-ua/su/su.h -15 +1
+ A ./libsofia-sip-ua/su/su_addrinfo.c
+ A ./libsofia-sip-ua/su/su_addrinfo.h
+ M ./libsofia-sip-ua/su/su_configure.h.in +3
+ M ./libsofia-sip-ua/su/su_localinfo.c -3 +3
+ M ./libsofia-sip-ua/su/su_wait.h -2 +2
+ M ./m4/sac-su2.m4 -2 +8
+
+ * Not using Unix network includes, use Sofia includes.
+
+ M ./libsofia-sip-ua/sresolv/sresolv.c -1 +1
+
+ * Using AC_GNU_SOURCE.
+
+ M ./configure.ac -2 +2
+
+ * Using sip-options consistently in utils/sip-options.c.
+
+ M ./utils/sip-options.c -8 +9
+
+ * Updated RELEASE and TODO.
+
+ M ./RELEASE +4
+ M ./TODO -2 +2
+
+ * Using nua_i_state event in nua_cli.c.
+
+ M ./utils/nua_cli.c -76 +88
+
+ * Updated ABNF grammar for Subscription-State in sip_event.c.
+ Added more tests for Subscription-State.
+
+ M ./libsofia-sip-ua/sip/sip_event.c -12 +17
+ M ./libsofia-sip-ua/sip/torture_sip.c -13 +16
+
+ * Fixed test_class.c documentation.
+
+ M ./libsofia-sip-ua/msg/test_class.c -2 +2
+
+ * Proofread conformance specification.
+
+ M ./libsofia-sip-ua/docs/conformance.docs -375 +547
+
+ * Fixed doxytags for main doxygen pages.
+
+ M ./libsofia-sip-ua/docs/Doxyfile -16 +16
+
+ * Fixed types of NUATAGs
+ Changed type of NUTAG_INVITE_TIMER, NUTAG_SESSION_TIMER, and NUTAG_MIN_SE
+ value to unsigned.
+
+ M ./libsofia-sip-ua/nua/nua_tag.c -3 +3
+
+ * Added test for handlin refer subscriptions.
+
+ M ./libsofia-sip-ua/nua/test_nua.c -1 +58
+
+ * Added test_mime_negotiation() to test_nua.c
+
+ M ./libsofia-sip-ua/nua/test_nua.c +166
+
+ * Cosmetic changes in nua_dialog_usage_t in nua_stack.h.
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -2 +1
+ M ./libsofia-sip-ua/nua/nua_stack.h -3 +3
+
+ * Added NHP_ISSET() to nua_stack.h.
+
+ M ./libsofia-sip-ua/nua/nua_stack.h -1 +5
+
+ * Added process_subsribe() for refer subscriptions in nua_stack.c.
+
+ M ./libsofia-sip-ua/nua/nua_stack.c +88
+
+ * Removed duplicate nua_i_subscription.
+
+ M ./libsofia-sip-ua/nua/nua_common.c -2
+
+ * Renumbered test cases, state transitions in nua.docs and test_nua.c.
+
+ M ./libsofia-sip-ua/nua/nua.docs -79 +79
+ M ./libsofia-sip-ua/nua/nua_stack.c +3
+ M ./libsofia-sip-ua/nua/test_nua.c -78 +131
+
+ * Added NUTAG_REFER_EXPIRES() with default value of 300.
+ Handling expiration of implicit subscriptions created by REFER.
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -1 +75
+ M ./libsofia-sip-ua/nua/nua_stack.h +4
+ M ./libsofia-sip-ua/nua/nua_tag.c +2
+ M ./libsofia-sip-ua/nua/nua_tag.h +26
+
+ * Refactored register_expires_contacts()
+ Fixed memory leak, bug in '*'handling.
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -10 +18
+
+ * Rewrote uas_check_session_content().
+ Returning empty Accept-Encoding header in 415/406 responses.
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -21 +41
+
+ * Do not throttle at termination. [FIX]
+
+ nea_server now sends NOTIFYs that terminate subscription even if the
+ previous NOTIFY transaction has not completed yet.
+
+ This fixes the race condition in nua_terminate() (where terminating NOTIFY
+ was is never sent).
+
+ M ./libsofia-sip-ua/nea/nea_server.c -1 +4
+
+ * Fixed rule to build sip_tag_ref.c.
+
+ M ./libsofia-sip-ua/sip/Makefile.am -2 +1
+
+ * Explicitly saving and destroying messages in ua_signal().
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -23 +23
+ M ./libsofia-sip-ua/nua/nua_stack.h +1
+
+ * Updated Content-Encoding (e) header parsing.
+
+ M ./libsofia-sip-ua/sip/sip.h -1 +1
+ M ./libsofia-sip-ua/sip/sip_mime.c -4 +4
+ M ./libsofia-sip-ua/sip/torture_sip.c -3 +4
+
+ * Updated Session-Expires and Min-SE header to RFC 4028.
+ A parameter list was added to Min-SE header.
+
+ M ./libsofia-sip-ua/sip/sip.h +1
+ M ./libsofia-sip-ua/sip/sip_session.c -18 +30
+ M ./libsofia-sip-ua/sip/torture_sip.c +10
+
+ * Update RELEASE.
+ Added text about API changes related nua_authorize(), nua_i_subscription and
+ NEATAG_SUB(), NUTAG_HOLD(), sdp_rtpmap_t.
+ Mentioning su_getlocalinfo() bug.
+
+ M ./RELEASE -3 +16
+
+ * Fixed installing and distributing m4 files.
+ Not installing m4/sac-su2.m4.
+ Including m4/sac-tport.m4 and m4/sac-openssl.m4 in distribution.
+
+ M ./Makefile.am -1 +2
+
+ * Deprecated NUTAG_HOLD().
+
+ * Updated documentation in nea, nua, nta, sip and tport modules.
+
+ * Updated documentation.
+
+ M ./libsofia-sip-ua/docs/Doxyfile.aliases +1
+ M ./libsofia-sip-ua/docs/conformance.docs -172 +177
+ M ./libsofia-sip-ua/docs/mainpage.docs -5 +7
+
+ * Updated subscriptuion authorization and nua_terminate() semantics.
+ Subscription authorization now rejects SUBSCRIBE if
+ NUTAG_SUBSTATE(nua_substate_terminated) parameter is set.
+ Correct status code is relayed to application, too.
+ nua_terminate() now always terminates whole notifier.
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -49 +65
+
+ * Fixed nua_handle_has_active_call() in nua_stack.c.
+
+ M ./libsofia-sip-ua/nua/nua_stack.c +10
+ M ./libsofia-sip-ua/nua/test_nua.c +32
+
+ * Renamed authenticate_watcher() as authorize_watcher().
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -13 +13
+
+ * Cleanup of subscription logging and comments in nua_stack.c.
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -21 +41
+
+ * Using SIPTAG_END() in nua_stack.c.
+ We now pass NTATAG and TPTAG to lower layers. Beware.
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -28 +29
+
+ * Added NH_PISSET() macro to <nua_stack.h>.
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -2 +8
+ M ./libsofia-sip-ua/nua/nua_stack.h +7
+
+ * Fixed doxytag file names for modules nea and features.
+
+ M ./libsofia-sip-ua/docs/Doxyfile -1 +1
+ M ./libsofia-sip-ua/features/Doxyfile -1 +1
+
+ M ./libsofia-sip-ua/nea/Doxyfile -1 +1
+
+ * Moved typedefs nua_t and nua_handle_t into <nua_tag.h>
+
+ M ./libsofia-sip-ua/nua/nua.h -6
+ M ./libsofia-sip-ua/nua/nua_tag.h -3 +6
+
+ * Added sip_add_tagis() and SIPTAG_END().
+ SIPTAG_END() allows grouping tags into blocks.
+
+ M ./libsofia-sip-ua/sip/sip_header.h +3
+ M ./libsofia-sip-ua/sip/sip_tag.c.in -1 +2
+ M ./libsofia-sip-ua/sip/sip_tag.h.in +4
+ M ./libsofia-sip-ua/sip/sip_tag_class.c -12 +38
+ M ./libsofia-sip-ua/sip/torture_sip.c +12
+
+ * Fixed scope for V4MAPPED and V4COMPAT IP6 addresses in su_localinfo.c.
+
+ M ./libsofia-sip-ua/su/su_localinfo.c -6 +21
+
+ * Cleaned up debug printing in su_memmem.c.
+
+ M ./libsofia-sip-ua/su/su_memmem.c -11 +21
+
+ * Added end_tag_class[].
+
+ M ./libsofia-sip-ua/su/su_tag_class.h -13 +1
+ M ./libsofia-sip-ua/su/su_tag_inline.h -1 +1
+ M ./libsofia-sip-ua/su/su_taglist.c -48 +84
+
+ * Added replacement functions memccpy().
+ Also moved memcspn() to a file of its own.
+
+ M ./libsofia-sip-ua/su/Makefile.am -5 +13
+ A ./libsofia-sip-ua/su/memccpy.c
+ A ./libsofia-sip-ua/su/memcspn.c
+ M ./libsofia-sip-ua/su/memspn.c -50 +1
+ M ./libsofia-sip-ua/su/strcasestr.c -1 +1
+ M ./m4/sac-su2.m4 -2 +13
+
+ * Added win32/config.h.in
+
+ M ./configure.ac +1
+ A ./win32/config.h.in
+
+ * Added AC_TYPE_LONGLONG.
+
+ M ./configure.ac -3 +2
+ M ./m4/sac-general.m4 -7 +5
+
+ * Tried to fix automatic generation of source files.
+
+ M ./libsofia-sip-ua/http/Makefile.am -10 +9
+ M ./libsofia-sip-ua/msg/Makefile.am -22 +14
+ M ./libsofia-sip-ua/sip/Makefile.am -13 +12
+
+ * Moved bitfields last in sdp_rtpmap_t aka struct sdp_rtpmap_s.
+
+ M ./libsofia-sip-ua/sdp/sdp.c -1 +3
+ M ./libsofia-sip-ua/sdp/sdp.h -5 +5
+ M ./libsofia-sip-ua/sdp/sdp_parse.c -2 +2
+ M ./libsofia-sip-ua/sdp/sdp_torture.c -4 +9
+
+ * Removed RFC2543-compatible tag code.
+
+ M ./libsofia-sip-ua/nta/nta.c -95 +46
+ M ./libsofia-sip-ua/nta/nta.h -4 +3
+ M ./libsofia-sip-ua/nta/nta_tag.h -2 +2
+ M ./libsofia-sip-ua/nta/test_nta.c -18 +20
+
+ * Fixed memory leaks in tport.c and nta.c.
+
+ M ./libsofia-sip-ua/nta/nta.c +11
+ M ./libsofia-sip-ua/tport/tport.c +2
+
+ * Fixed a memory leak when processing re-SUBSCRIBE in nea_server.c.
+
+ M ./libsofia-sip-ua/nea/nea_server.c -2 +2
+
+ * Cleaned #including standard headers in msg module.
+
+ M ./libsofia-sip-ua/msg/msg_header.h +1
+ M ./libsofia-sip-ua/msg/test_msg.c -7 +7
+
+ * Removed extra prototype.
+
+ M ./libsofia-sip-ua/iptsec/auth_plugin_delayed.c -4
+
+ * Casting getpid() return type to something accepted by printf().
+
+ M ./libsofia-sip-ua/nua/test_nua.c -1 +1
+
+ * Doing system #include after sofia #include.
+
+ M ./libsofia-sip-ua/nua/test_nua.c -12 +11
+
+ * Not using nta_incoming_tag_3261() anymore.
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -4 +2
+
+ * Added #include <limits.h> to libsofia-sip-ua/su/su.h.
+
+ M ./libsofia-sip-ua/su/su.h -2 +3
+
+ * Added client timeout and NTHTAG_EXPIRES() to nth http client library.
+
+ M ./libsofia-sip-ua/nth/nth_client.c -7 +29
+ M ./libsofia-sip-ua/nth/nth_tag.c -1 +2
+ M ./libsofia-sip-ua/nth/nth_tag.h -1 +7
+ M ./libsofia-sip-ua/nth/nth_test.c -9 +111
+
+ * Fixed RFC 1890/RFC 1891.
+
+ M ./libsofia-sip-ua/docs/Doxyfile.aliases +2
+
+ * Added conformance.docs
+
+ M ./libsofia-sip-ua/docs/Doxyfile -1 +1
+ A ./libsofia-sip-ua/docs/conformance.docs
+
+ * Moved memspn from msg module to su
+
+ ./libsofia-sip-ua/msg/memspn.c -> ./libsofia-sip-ua/su/memspn.c
+
+ * Using package-specific install directory for public header files.
+ Default install directory for public header file has been changed
+ from '${prefix}/include/' to '${prefix}/include/sofia-sip-MAJOR.MINOR'.
+ The pkgconfig .pc file has been updated accordingly.
+
+ * Removed <win32/config.h>
+
+ R ./win32/config.h
+
+2005-11-28 Martti Mela <martti.mela at nokia.com>
+
+ * Added nua_authorize(), enhanced nua_i_subscription. Added
+ nua_notifier test cases for test_nua. With great help from Pekka.
+
+ M ./libsofia-sip-ua/nea/Makefile.am
+ M ./libsofia-sip-ua/nea/nea.h
+ M ./libsofia-sip-ua/nea/nea_tag.c
+ M ./libsofia-sip-ua/nta/test_nta.c
+ M ./libsofia-sip-ua/nua/nua.c
+ M ./libsofia-sip-ua/nua/nua.docs
+ M ./libsofia-sip-ua/nua/nua.h
+ M ./libsofia-sip-ua/nua/nua_common.c
+ M ./libsofia-sip-ua/nua/nua_stack.c
+ M ./libsofia-sip-ua/nua/nua_stack.h
+ M ./libsofia-sip-ua/nua/test_nua.c
+ M ./libsofia-sip-ua/nua/test_proxy.c
+ M ./utils/Makefile.am
+
+2005-11-28 Martti Mela <martti.mela at nokia.com>
+
+ * nua.h: added event nua_i_subscription
+
+ * nua_commmon.c: added event nua_i_subscription
+
+ * nua_stack.c: ua_event for nua_i_subscription (nea subscribers)
+
+ * nea.h, nea_tag.c, nea_tag_ref.c, nea_server.c: support for a new
+ tag, NEATAG_SUB(). Added nea_sub_get_request().
+
+2005-11-15 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * configure.ac: Added VER_LIBSOFIA_SIP_UA variables.
+
+2005-11-14 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ tagged rel-sofia-sip-1_11_4
+
+ * Fixed Win32 includes for XP. Added win32/README.txt.
+
+ M ./libsofia-sip-ua/su/su.h -4 +5
+ M ./win32/Makefile.am -1 +2
+ A ./win32/README.txt
+
+ * Added a blurb about win32 bugs into RELEASE.
+
+ M ./RELEASE -1 +3
+
+2005-11-11 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Updated RELEASE.
+
+ M ./RELEASE -1 +9
+
+ * Updated dua documentation.
+
+ M ./libsofia-sip-ua/nua/nua.c +4
+ M ./libsofia-sip-ua/nua/nua.docs -10 +12
+ M ./libsofia-sip-ua/nua/nua_stack.h -2 +3
+
+ * Fixed warnings in libsofia-sip-ua/tport/tport.c.
+
+ M ./libsofia-sip-ua/tport/tport.c -2 +1
+
+ * Fixed WIN32 test cases in libsofia-sip-ua/su/su_torture.c.
+ Using SU_WAIT_TIMEOUT and correct IP address.
+
+ M ./libsofia-sip-ua/su/su_torture.c -2 +2
+
+ * Added codec-level negotiation and codec selection for RTP media.
+ Added SOATAG_RTP_SELECT(), SOATAG_RTP_SORT() and SOATAG_RTP_MISMATCH() for
+ indicating sdp negotiation preferences. Select the RTP codec according to the
+ preferences when sending or processing the answer.
+
+ M ./libsofia-sip-ua/soa/soa.c -7 +52
+ M ./libsofia-sip-ua/soa/soa_session.h +5
+ M ./libsofia-sip-ua/soa/soa_static.c -21 +320
+ M ./libsofia-sip-ua/soa/soa_tag.c +89
+ M ./libsofia-sip-ua/soa/soa_tag.h +19
+ M ./libsofia-sip-ua/soa/test_soa.c -19 +382
+
+ * Added funtions for rtp payload type management.
+
+ Added sdp_media_uses_rtp(), sdp_rtpmap_match(), sdp_rtpmap_find_matching()
+ and sdp_rtpmap_well_known[]. Fixed RTP timestamp rate for G722: it was 16000
+ but it should be 8000.
+
+ M ./libsofia-sip-ua/sdp/sdp.c -1 +76
+ M ./libsofia-sip-ua/sdp/sdp.h +12
+ M ./libsofia-sip-ua/sdp/sdp_parse.c -37 +94
+ M ./libsofia-sip-ua/sdp/sdp_torture.c -11 +140
+
+ * Generating browsing info for win32 projects.
+
+ M ./win32/libsofia-sip-ua/libsofia_sip_ua.dsp -2 +2
+ M ./win32/nta_test/nta_test.dsp -1 +1
+ M ./win32/su/su_alloc_test/su_alloc_test.dsp -2 +2
+ M ./win32/su/su_root_test/su_root_test.dsp -2 +2
+ M ./win32/su/su_tag_test/su_tag_test.dsp -2 +2
+ M ./win32/su/su_test/su_test.dsp -2 +2
+ M ./win32/su/su_time_test/su_time_test.dsp -2 +2
+ M ./win32/su/su_timer_test/su_timer_test.dsp -2 +2
+ M ./win32/su/su_torture/su_torture.dsp -2 +2
+ M ./win32/su/test_memmem/test_memmem.dsp -2 +2
+ M ./win32/su/torture_htable/torture_htable.dsp -2 +2
+ M ./win32/su/torture_rbtree/torture_rbtree.dsp -2 +2
+ M ./win32/su/torture_su_memmem/torture_su_memmem.dsp -2 +2
+ M ./win32/su/torture_su_port/torture_su_port.dsp -2 +2
+
+ * Added tests for su_vsend() and su_vrecv() in su_torture.c.
+
+ M ./libsofia-sip-ua/su/su_torture.c +89
+
+ * Added #include <limits.h> to nua_stack.c (because MSG_TIME_MAX).
+
+ M ./libsofia-sip-ua/nua/nua_stack.c +1
+
+ * Added SU_WAIT_CONNECT. Fixed su_vrecv() and su_vsend() on Win32.
+
+ M ./libsofia-sip-ua/su/su.c -9 +10
+ M ./libsofia-sip-ua/su/su_wait.h +3
+
+ * Fixed tport.c on Win32 port.
+ Added a separate "connecting" phase.
+ Checking EWOULDBLOCK in addition to EAGAIN.
+ Fixed TP_AI_CLOSE and TP_AI_SHUTDOWN flags.
+ Improved logging.
+
+ M ./libsofia-sip-ua/tport/tport.c -35 +98
+
+ * Removed 1.11.3 stuff from RELEASE.
+
+ M ./RELEASE -16 +2
+
+ * Removed Last modified from ipt module.
+
+ M ./libsofia-sip-ua/ipt/rc4.h -1
+ M ./libsofia-sip-ua/ipt/torture_base64.c -1
+ M ./libsofia-sip-ua/ipt/ucs2.c -1
+ M ./libsofia-sip-ua/ipt/ucs4.c -1
+ M ./libsofia-sip-ua/ipt/uniqueid.h -1
+ M ./libsofia-sip-ua/ipt/utf8.c -1
+ M ./libsofia-sip-ua/ipt/utf8.h -1
+ M ./libsofia-sip-ua/ipt/utf8internal.h -1
+ M ./libsofia-sip-ua/ipt/utf8test.c -1
+
+ * Removed Last modified from sdp module.
+
+ M ./libsofia-sip-ua/sdp/sdp.c -1
+ M ./libsofia-sip-ua/sdp/sdp.h -1
+ M ./libsofia-sip-ua/sdp/sdp_parse.c -1
+ M ./libsofia-sip-ua/sdp/sdp_rtp.h -1
+ M ./libsofia-sip-ua/sdp/sdp_tag.c -1
+ M ./libsofia-sip-ua/sdp/sdp_tag.h -1
+ M ./libsofia-sip-ua/sdp/sdp_test.c -1
+ M ./libsofia-sip-ua/sdp/sdp_torture.c -1
+
+2005-11-10 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Avoid comp=sigcomp in Via in nta/nta.c
+ Not inserting comp=sigcomp in topmost Via of request if there is no
+ comp=sigcomp in request-URI or route-URI.
+
+ M ./libsofia-sip-ua/nta/nta.c -20 +15
+
+ * Added Doxygen entries for SIPTAG_*_REF.
+
+ M ./libsofia-sip-ua/sip/sip_tag.h.in -5 +17
+
+ * Fixed AC_DEFINE([HAVE_SOFIA_SIGCOMP])
+
+ M ./m4/sac-tport.m4 -1 +1
+
+ * Not using $(srcdir)/../ for Makefile.am inclusion.
+
+ M ./libsofia-sip-ua/features/Makefile.am -1 +1
+ M ./libsofia-sip-ua/nua/Makefile.am -1 +1
+ M ./libsofia-sip-ua/sdp/Makefile.am -1 +1
+ M ./libsofia-sip-ua/soa/Makefile.am -1 +1
+
+ * Added PACKAGE_NAME and PACKAGE_VERSION to msg_parser.awk.
+
+ M ./libsofia-sip-ua/msg/msg_parser.awk +2
+
+ * Not using ancient MSG_DUMP and MSG_STREAM_LOG env variables.
+ Use TPORT_DUMP and TPORT_LOG instead.
+
+ M ./utils/nua_env -3 +3
+
+ * Fixed --without-glib case in m4/sac-su2.m4.
+
+ M ./m4/sac-su2.m4 -4 +7
+
+ * Removed m4/sac-glib.m4
+
+ R ./m4/sac-glib.m4
+
+2005-11-09 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Updated documentation of nta_agent_add_tport().
+ The uri parameter to nta_agent_add_tport() is used to control which sockets
+ the tport binds the server sockets as well as which transport, encryption
+ and compression protocols are used.
+
+ M ./libsofia-sip-ua/nta/nta.c -1 +46
+
+2005-11-08 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ tagged rel-sofia-sip-1_11_3
+
+ * Not using sip_params_replace().
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -2 +2
+
+ * Using sip_complete_message instead of sip_message_complete in nua_stack.c.
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -1 +1
+
+ * Removed $(srcdir)s from built_sources targets in libsofia-sip-ua/sofia.am
+
+ M ./libsofia-sip-ua/sofia.am -2 +2
+
+ * Updated nta ChangeLog.
+
+ M ./libsofia-sip-ua/nta/ChangeLog +4
+
+ * Renamed tport_test.c as test_tport.c
+
+ ./libsofia-sip-ua/tport/tport_test.c -> ./libsofia-sip-ua/tport/test_tport.c
+ M ./libsofia-sip-ua/tport/ChangeLog +4
+ M ./libsofia-sip-ua/tport/Doxyfile -1 +1
+ M ./libsofia-sip-ua/tport/Makefile.am -7 +9
+ M ./libsofia-sip-ua/tport/test_tport.c -1 +1
+ R ./libsofia-sip-ua/tport/tport_test.h
+
+ * Renamed test modules and programs.
+ 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).
+
+ ./libsofia-sip-ua/msg/msg_test.c -> ./libsofia-sip-ua/msg/test_msg.c
+ ./libsofia-sip-ua/msg/msg_test_class.c -> ./libsofia-sip-ua/msg/test_class.c
+ ./libsofia-sip-ua/msg/msg_test_class.h -> ./libsofia-sip-ua/msg/test_class.h
+ ./libsofia-sip-ua/msg/msg_test_protos.h.in -> ./libsofia-sip-ua/msg/test_protos.h.in
+ ./libsofia-sip-ua/msg/msg_test_table.c.in -> ./libsofia-sip-ua/msg/test_table.c.in
+ M ./libsofia-sip-ua/msg/ChangeLog +8
+ M ./libsofia-sip-ua/msg/Makefile.am -28 +36
+ M ./libsofia-sip-ua/msg/msg.docs -1 +1
+ M ./libsofia-sip-ua/msg/msg_name_hash.c -1 +1
+ M ./libsofia-sip-ua/msg/test_class.c -8 +8
+ M ./libsofia-sip-ua/msg/test_class.h -3 +3
+ M ./libsofia-sip-ua/msg/test_msg.c -5 +5
+ M ./libsofia-sip-ua/msg/test_protos.h.in -7 +7
+ M ./libsofia-sip-ua/msg/test_table.c.in -7 +7
+ M ./libsofia-sip-ua/tport/tport_test.c -2 +2
+
+ * Renamed auth_digest_test.c as test_auth_digest.c.
+
+ ./libsofia-sip-ua/iptsec/auth_digest_test.c -> ./libsofia-sip-ua/iptsec/test_auth_digest.c
+ M ./libsofia-sip-ua/iptsec/ChangeLog +4
+ M ./libsofia-sip-ua/iptsec/Makefile.am -3 +3
+ M ./libsofia-sip-ua/iptsec/test_auth_digest.c -4 +4
+
+ * Renamed http_test.c as test_http.c.
+
+ ./libsofia-sip-ua/http/http_test.c -> ./libsofia-sip-ua/http/test_http.c
+ M ./libsofia-sip-ua/http/ChangeLog +4
+ M ./libsofia-sip-ua/http/Makefile.am -3 +3
+ M ./libsofia-sip-ua/http/test_http.c -6 +6
+
+2005-11-07 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Using new nta_agent_create() prototype in utils/sip-options.c
+
+ M ./utils/sip-options.c -1 +1
+
+ * Added test proxy to nua module.
+
+ M ./libsofia-sip-ua/nua/Makefile.am +2
+ M ./libsofia-sip-ua/nua/test_nua.c -35 +175
+ A ./libsofia-sip-ua/nua/test_proxy.c
+ A ./libsofia-sip-ua/nua/test_proxy.h
+
+ * Cleaned up sip parser.
+ Renamed msg_name_addr_d/msg_name_addr_e as sip_name_addr_d/sip_name_addr_e
+ (because the function is sip-specific).
+ Not using old sip-specific parser macros.
+
+ M ./libsofia-sip-ua/sip/sip.docs -6 +3
+ M ./libsofia-sip-ua/sip/sip.h -1 +1
+ M ./libsofia-sip-ua/sip/sip_basic.c -100 +284
+ M ./libsofia-sip-ua/sip/sip_caller_prefs.c -13 +13
+ M ./libsofia-sip-ua/sip/sip_event.c -32 +32
+ M ./libsofia-sip-ua/sip/sip_extra.c -13 +13
+ M ./libsofia-sip-ua/sip/sip_feature.c -8 +8
+ M ./libsofia-sip-ua/sip/sip_header.c -36 +3
+ M ./libsofia-sip-ua/sip/sip_mime.c -18 +18
+ M ./libsofia-sip-ua/sip/sip_parser.c -12 +12
+ M ./libsofia-sip-ua/sip/sip_parser.h -3 +14
+ M ./libsofia-sip-ua/sip/sip_prack.c -2 +2
+ M ./libsofia-sip-ua/sip/sip_pref_util.c -2 +2
+ M ./libsofia-sip-ua/sip/sip_reason.c -6 +6
+ M ./libsofia-sip-ua/sip/sip_refer.c -24 +24
+ M ./libsofia-sip-ua/sip/sip_rfc2543.c -2 +2
+ M ./libsofia-sip-ua/sip/sip_security.c -10 +10
+ M ./libsofia-sip-ua/sip/sip_session.c -6 +6
+ M ./libsofia-sip-ua/sip/sip_tag_class.c -11 +14
+ M ./libsofia-sip-ua/sip/sip_time.c -1 +1
+ M ./libsofia-sip-ua/sip/sip_util.c -47 +19
+ M ./libsofia-sip-ua/sip/torture_sip.c -8 +56
+
+ * Updated documentation in url module.
+
+ M ./libsofia-sip-ua/url/torture_url.c -3 +2
+ M ./libsofia-sip-ua/url/url.c -3 +5
+ M ./libsofia-sip-ua/url/url.h -3 +1
+ M ./libsofia-sip-ua/url/url_tag.c -4 +2
+ M ./libsofia-sip-ua/url/url_tag.h -3 +2
+ M ./libsofia-sip-ua/url/url_tag_class.h -3 +2
+
+ * Using updated nta api in nua module.
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -23 +34
+
+ * Not using msg_copy_all().
+
+ M ./libsofia-sip-ua/nth/nth_client.c -11 +6
+
+ * Not misusing SIP_NONE.
+
+ M ./libsofia-sip-ua/sip/torture_sip.c -2 +2
+
+ * Updated documentation in msg module.
+ Removed bogus @ingroup msg.
+
+ M ./libsofia-sip-ua/msg/msg.c -3 +1
+ M ./libsofia-sip-ua/msg/msg.h -4 +1
+ M ./libsofia-sip-ua/msg/msg_addr.h -2 +1
+ M ./libsofia-sip-ua/msg/msg_buffer.h -2 +1
+ M ./libsofia-sip-ua/msg/msg_dll.h -3 +1
+ M ./libsofia-sip-ua/msg/msg_tag.c -2 +1
+ M ./libsofia-sip-ua/msg/msg_tag_class.h -4 +1
+
+ * Updated msg module interfaces.
+ Added msg_header_free(), msg_header_free_all().
+ Removed msg_dup_all() and msg_copy_all().
+
+ M ./libsofia-sip-ua/msg/msg.h -2 +2
+ M ./libsofia-sip-ua/msg/msg_header.h -3 +8
+ M ./libsofia-sip-ua/msg/msg_header_copy.c +159
+ M ./libsofia-sip-ua/msg/msg_internal.h -2 +28
+ M ./libsofia-sip-ua/msg/msg_mime.c -48 +47
+ M ./libsofia-sip-ua/msg/msg_parser.c -198 +21
+ M ./libsofia-sip-ua/msg/msg_parser_util.c -171 +14
+ M ./libsofia-sip-ua/msg/msg_test.c -69 +41
+ M ./libsofia-sip-ua/msg/msg_test_class.c -28 +24
+ M ./libsofia-sip-ua/msg/msg_test_class.h -3 +2
+ M ./libsofia-sip-ua/msg/msg_test_protos.h.in -2 +2
+
+ * Removed msg_clone() from msg module.
+ Moved msg_set_parent() into msg/msg.c.
+
+ M ./libsofia-sip-ua/msg/msg.c +23
+ M ./libsofia-sip-ua/msg/msg.h -2
+ M ./libsofia-sip-ua/msg/msg_parser.c -46
+
+ * Cleaned up nta module interfaces.
+ Use uint32_t instead of sip_u32_t.
+ Removed old funtions not using reference counting with messages:
+ Replaced nta_outgoing_getresponse() with nta_outgoing_getresponse_ref(),
+ and nta_outgoing_getrequest() with nta_outgoing_getrequest_ref().
+ Removed nta_incoming_getresponse(), nta_leg_stateful().
+ Removed nta_outgoing_tmcreate(): use nta_outgoing_mcreate() instead.
+
+ M ./libsofia-sip-ua/nta/nta.c -298 +243
+ M ./libsofia-sip-ua/nta/nta.h -21 +14
+ M ./libsofia-sip-ua/nta/nta_compat.c -6 +132
+ M ./libsofia-sip-ua/nta/nta_compat.h +3
+ M ./libsofia-sip-ua/nta/nta_internal.h -11 +4
+ M ./libsofia-sip-ua/nta/nta_stateless.h -9 +5
+ M ./libsofia-sip-ua/nta/run_test_nta -5 +5
+ M ./libsofia-sip-ua/nta/sl_utils_log.c -1 +1
+ M ./libsofia-sip-ua/nta/sl_utils_print.c -1 +1
+ M ./libsofia-sip-ua/nta/test_nta.c -24 +14
+
+ * Not using msg_clone().
+
+ M ./libsofia-sip-ua/nth/nth_client.c -1 +1
+
+ * Not using stateless functions anymore in nea.
+
+ M ./libsofia-sip-ua/nea/nea.h -12 +3
+ M ./libsofia-sip-ua/nea/nea_server.c -8 +3
+
+ * Removed sip_complete_response().
+
+ M ./libsofia-sip-ua/sip/sip_parser.c -47
+ M ./libsofia-sip-ua/sip/sip_util.h -7
+
+ * Not using sip_none anymore.
+
+ M ./libsofia-sip-ua/sip/sip_header.c -1 +1
+
+ * Fixed sip_object() prototype.
+
+ M ./libsofia-sip-ua/sip/sip_protos.h.in -1 +1
+
+ * Cleaned up sip types.
+ Not using special typedefs sip_u32_t or sip_u16_t.
+
+ M ./libsofia-sip-ua/sip/sip.h -15 +11
+ M ./libsofia-sip-ua/sip/sip_basic.c -4 +4
+ M ./libsofia-sip-ua/sip/sip_header.h -2 +2
+ M ./libsofia-sip-ua/sip/sip_util.c -2 +2
+ M ./libsofia-sip-ua/sip/sip_util.h -1 +1
+
+ * Defining MSG_TIME_MAX both in msg_types.h and msg_time.h.
+
+ M ./libsofia-sip-ua/msg/msg_date.h -3 +6
+ M ./libsofia-sip-ua/msg/msg_types.h -1 +6
+
+ * Removed sip_transport.c.
+
+ R ./libsofia-sip-ua/sip/sip_transport.c
+
+ * Removed annoying Last modified from iptsec.
+
+2005-11-04 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Removed annoying Last modified from msg module.
+
+ * Removed Last modified things from sip module.
+
+ * Removed sip/sip_transport.[hc], not used anymore.
+
+ R ./libsofia-sip-ua/sip/sip_transport.c
+ R ./libsofia-sip-ua/sip/sip_transport.h
+
+2005-11-03 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Renamed nta_test as test_nta.
+
+ ./libsofia-sip-ua/nta/nta_test.c -> ./libsofia-sip-ua/nta/test_nta.c
+ ./libsofia-sip-ua/nta/run_nta_test -> ./libsofia-sip-ua/nta/run_test_nta
+ M ./libsofia-sip-ua/nta/Makefile.am -4 +4
+ M ./libsofia-sip-ua/nta/run_test_nta -2 +2
+
+ * Updated libsofia-sip-ua/nua/ChangeLog.
+
+ M ./libsofia-sip-ua/nua/ChangeLog +21
+
+ * Fixed race in nea/nea_server.c.
+ Do not free subscribers while they are being processed by application.
+
+ M ./libsofia-sip-ua/nea/nea_server.c -5 +7
+
+ * Added unpublish, unregister, do_register to nua/test_nua.c.
+
+ M ./libsofia-sip-ua/nua/test_nua.c -8 +28
+
+ * Added test_events().
+
+ M ./libsofia-sip-ua/nua/test_nua.c +409
+
+ * Added nua_unpublish().
+ Some cosmetic changes, too.
+
+ M ./libsofia-sip-ua/nua/nua.h -1 +4
+ M ./libsofia-sip-ua/nua/nua_stack.c -1 +1
+
+ * Cleaned up allocations in nua/test_nua.c.
+
+ M ./libsofia-sip-ua/nua/test_nua.c -6 +8
+
+ * Added loopback message test.
+
+ M ./libsofia-sip-ua/nua/test_nua.c +49
+
+2005-11-02 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Fixed buglets in su/su_alloc.c.
+ su_alloc() did zero memory. su_realloc() used su_alloc().
+
+ M ./libsofia-sip-ua/su/su_alloc.c -5 +7
+
+ * Closing /proc/net/if_inet6 after use in su/su_localinfo.c.
+
+ M ./libsofia-sip-ua/su/su_localinfo.c +2
+
+ * Using su_home_new().
+
+ M ./libsofia-sip-ua/msg/msg.c -2 +2
+
+ * Fixed allocation code for message parser table.
+ Allocating parser table as a single memory block.
+
+ M ./libsofia-sip-ua/msg/msg_mclass.c -12 +12
+ M ./libsofia-sip-ua/sresolv/test_sresolv.c -3 +15
+
+ * Updated documentation in nta/nta_stateless.h.
+
+ M ./libsofia-sip-ua/nta/nta_stateless.h -4 +4
+
+ * Plugging memory leaks in nta.
+ Plugged memory leaks in 100rel code.
+
+ M ./libsofia-sip-ua/nta/nta.c -38 +63
+ M ./libsofia-sip-ua/nta/nta_test.c -31 +109
+
+ * Moved deprecated functions to nta/nta_compat.c.
+ nta_msg_vsend() and msg_msg_send() should not be used anymore.
+
+ nta_msg_discard() is also deprecated, but getting rid of references to it
+ takes time.
+
+ M ./libsofia-sip-ua/nta/nta.c -43 +42
+ M ./libsofia-sip-ua/nta/nta_compat.c -1 +31
+
+ * Plugged memory leak in nth_engine_create() in nth/nth_client.c
+ Use su_home_new() instead of su_salloc().
+
+ M ./libsofia-sip-ua/nth/nth_client.c -3 +2
+
+2005-11-01 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ tagged rel-sofia-sip_1_11_2+win32
+
+ * Disabled listen-on-v6 in sresolv/run_test_sresolv.
+
+ M ./libsofia-sip-ua/sresolv/run_test_sresolv -4 +15
+
+ * Fixed search path on sresolc/sresolv.c
+ Not invoking callback on main query if subqueries are still running.
+
+ M ./libsofia-sip-ua/sresolv/sresolv.c -11 +20
+
+ * Added ns record for root.zone.
+
+ M ./libsofia-sip-ua/sresolv/root.zone -1 +5
+
+ * Using su_close() instead of close().
+
+ M ./libsofia-sip-ua/sresolv/test_sresolv.c -3 +3
+ M ./libsofia-sip-ua/stun/stun.c -1 +1
+ M ./libsofia-sip-ua/tport/tport.c -1 +1
+
+ * Fixed HAVE_SIGPIPE.
+
+ M ./configure.ac -1 +2
+
+ * Using SU_HAVE_GLIB.
+
+ M ./libsofia-sip-ua/su/su_test.c -2 +2
+
+ * Removed annoying last modified.
+
+ M ./libsofia-sip-ua/sresolv/sresolv.c -2
+ M ./libsofia-sip-ua/sresolv/test_sresolv.c -1
+ M ./libsofia-sip-ua/stun/stun.c -1
+
+ * Using AC_DEFINE with HAVE_SOFIA_STUN.
+
+ M ./configure.ac -1 +1
+
+ * Removed annoying Last modified from su and win32 files.
+
+ * Not using sint32_t.
+
+ M ./libsofia-sip-ua/su/su.c -1
+ M ./libsofia-sip-ua/su/su.h -1
+ M ./libsofia-sip-ua/su/su_localinfo.c -4 +4
+
+ * Fixed ipv6 side on libc replacement libsofia_sip_ua/su/inet_pton.c.
+
+ M ./libsofia-sip-ua/su/inet_pton.c -20 +20
+
+ * Removed ntv6 files from win32 port.
+
+ M ./win32/Makefile.am -23 +13
+
+ * Using win32 include files tpipv6.h and wspiapi.h provided by system.
+
+ M ./win32/libsofia-sip-ua/libsofia_sip_ua.dsp -8
+
+ * Using SU_HAVE_IN6 on win32, too.
+
+ M ./libsofia-sip-ua/su/su.c -1 +1
+ M ./libsofia-sip-ua/su/su.h -6 +6
+ M ./libsofia-sip-ua/su/su_torture.c -1 +1
+ M ./win32/config.h -3 +3
+ M ./win32/su_configure_win32.h -2 +1
+
+ * Added HAVE_SIGPIPE.
+
+ M ./configure.ac +6
+
+ * Removed Microsoft include file win32/wspiapi.h.
+
+ R ./win32/wspiapi.h
+
+ * Removed win32 tpipv6.h file.
+
+ R ./win32/tpipv6.h
+
+ * Fixed win32 socket handling problems in su/su_root_test and torture_su_port.c.
+
+ M ./libsofia-sip-ua/su/su_root_test.c +5
+ M ./libsofia-sip-ua/su/torture_su_port.c +4
+
+ * Renamed SU_SOCKADDR_INADDR_ANY as SU_HAS_INADDR_ANY() in su/su.h.
+
+ M ./libsofia-sip-ua/su/su.h -2 +4
+
+ * Added "su" test programs to win32 port.
+
+ * Fixed win32 config.h.
+
+ M ./win32/config.h -3 +6
+
+ * Added su test programs to win32 workspace.
+
+ M ./win32/SofiaSIP.dsw -1 +166
+
+ * Providing __func__ replacement in su/torture_su_port.c.
+
+ M ./libsofia-sip-ua/su/torture_su_port.c -1 +7
+
+ * Not using IN6 if it is not found by configure.
+
+ M ./libsofia-sip-ua/su/su_torture.c -1 +2
+
+ * Not using SIGPIPE if it is not found by configure.
+
+ M ./libsofia-sip-ua/su/su_timer_test.c +2
+
+ * Not using glib in su/su_test.c if it is not found by configure.
+
+ M ./libsofia-sip-ua/su/su_test.c -2 +6
+
+ * Added inet_pton() and inet_ntop() replacement functions.
+
+ M ./libsofia-sip-ua/su/Makefile.am -1 +2
+ M ./libsofia-sip-ua/su/inet_ntop.c -57 +30
+ A ./libsofia-sip-ua/su/inet_pton.c
+ M ./libsofia-sip-ua/su/su.h -11 +2
+
+ * Removed ntv6 from include path of win32 port.
+
+ M ./win32/libsofia-sip-ua/libsofia_sip_ua.dsp -6 +10
+
+ * Removed ntv6 files.
+
+ R ./libsofia-sip-ua/su/aton.c
+ R ./libsofia-sip-ua/su/ntoa.c
+
+2005-10-31 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Fixed testcases not working with libc implementation.
+
+ M ./libsofia-sip-ua/su/test_memmem.c -6 +6
+
+ * Defining SU_DLL in su/su_config.h for non-WIN32 targets.
+
+ M ./libsofia-sip-ua/su/su_config.h -1 +1
+
+ * Removing libsofia-sip-ua/nea/nea_dll.h from dist, too.
+
+ M ./libsofia-sip-ua/nea/Makefile.am -1 +1
+
+ * Added strtoull.c, strcasestr.c and inet_ntop.c to distribution.
+
+ M ./libsofia-sip-ua/su/Makefile.am -1 +1
+
+ * Added inet_ntop() to libsofia-sip-ua/su
+
+ A ./libsofia-sip-ua/su/inet_ntop.c
+
+ * Not inlining attribute functions in tport/tport.c.
+
+ M ./libsofia-sip-ua/tport/tport.c -4 +4
+
+ * Updated _DLL linkage things.
+ The DLL linkage macros SIP_DLL, NTA_DLL, etc. are now defined in win32-specific
+ config.h file.
+
+ M ./libsofia-sip-ua/bnf/bnf.h -4 +5
+ M ./libsofia-sip-ua/http/http.h -9 +1
+ M ./libsofia-sip-ua/http/http_dll.h -3 +3
+ M ./libsofia-sip-ua/http/http_header.h -2
+ M ./libsofia-sip-ua/http/http_status.h -1
+ M ./libsofia-sip-ua/ipt/utf8.h -4 +6
+ M ./libsofia-sip-ua/iptsec/auth_dll.h -3 +3
+ M ./libsofia-sip-ua/msg/msg_dll.h -6 +6
+ M ./libsofia-sip-ua/nea/nea.h -8 +8
+ M ./libsofia-sip-ua/nta/nta_dll.h -3 +4
+ M ./libsofia-sip-ua/nth/nth_tag.h -3 +3
+ M ./libsofia-sip-ua/sdp/sdp.h -8
+ M ./libsofia-sip-ua/sdp/sdp_tag.h -4 +3
+ M ./libsofia-sip-ua/sip/sip_dll.h -5 +4
+ M ./libsofia-sip-ua/su/su_config.h -7 +3
+ M ./libsofia-sip-ua/tport/tport.h -9
+ M ./libsofia-sip-ua/tport/tport_tag.h -3 +3
+ M ./libsofia-sip-ua/url/url_dll.h -4 +3
+
+ * Removed nea/nea_dll.h
+
+ R ./libsofia-sip-ua/nea/nea_dll.h
+
+ * Added prototype for strcasestr() replacement function.
+
+ M ./libsofia-sip-ua/soa/soa_static.c +3
+
+ * Added tests for strcasestr() replacement function.
+
+ M ./libsofia-sip-ua/su/test_memmem.c -19 +148
+
+ * Removed double const.
+ VC98 does not support ANSI const.
+
+ M ./libsofia-sip-ua/su/su_wait.h -3 +3
+
+ * Fixed __func__ usage.
+ VC98++ does not have __func__. Use innocent value instead.
+
+ M ./libsofia-sip-ua/nua/nua_stack.h +2
+ M ./libsofia-sip-ua/soa/soa.c +7
+
+ * Fixed C99-ism in sdp/sdp_parse.c.
+ A variable was declared in the middle of block.
+
+ M ./libsofia-sip-ua/sdp/sdp_parse.c -4 +6
+
+ * Fixed setsockopt() in tport/tport.c.
+ Explicit (void *) cast for argument of setsockopt().
+
+ M ./libsofia-sip-ua/tport/tport.c -2 +4
+
+ * Added missing replacement functions.
+
+ A ./libsofia-sip-ua/su/strcasestr.c
+ A ./libsofia-sip-ua/su/strtoull.c
+
+ * Using longlong instead of long long.
+ longlong is defined in "config.h".
+
+ M ./libsofia-sip-ua/sdp/sdp_parse.c +4
+ M ./libsofia-sip-ua/sdp/sdp_print.c -1 +1
+ M ./libsofia-sip-ua/soa/soa.c -2 +2
+ M ./libsofia-sip-ua/su/tstdef.h -1 +1
+
+ * Using su_seterrno() and su_errno().
+ Not using directly errno in soa/soa.c and tport/tport.c.
+
+ M ./libsofia-sip-ua/soa/soa.c -37 +38
+ M ./libsofia-sip-ua/tport/tport.c -10 +10
+
+ * Removed whoami from msg/msg_parser.awk.
+ whoami is not used.
+
+ M ./libsofia-sip-ua/msg/msg_parser.awk -1
+
+2005-10-27 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Added coverage files used by gcc 3.4.3 to MOSTLYCLEANFILES.
+
+ M ./m4/sac-general.m4 -1 +1
+
+2005-10-21 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Fixed lib64 problem.
+
+ M ./packages/sofia-sip.spec.in -6 +9
+
+2005-10-13 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Removed RCS/CVS Ids and dates from files in order to allow
+ smoother darcs usage.
+
+2005-10-12 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Defining SU_HAVE_TAGSTACK.
+
+ M ./libsofia-sip-ua/su/su_configure.h.in +3
+ M ./m4/sac-su2.m4 +6
+
+2005-10-10 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Added --without-glib option, added SU_HAVE_GLIB in su_configure.h.
+
+ M ./configure.ac -5
+ M ./libsofia-sip-ua/su/Makefile.am +2
+ M ./libsofia-sip-ua/su/su_configure.h.in +2
+ M ./m4/sac-su2.m4 -1 +22
+
+ * Added --output (and --help) options to coverage script.
+
+ M ./libsofia-sip-ua/sofia.am -1 +1
+ M ./scripts/coverage -2 +25
+
+2005-10-06 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Renamed options as sip-options, sip_date as sip-date.
+
+ ./utils/options.c -> ./utils/sip-options.c
+ ./utils/sip_date.c -> ./utils/sip-date.c
+ M ./utils/Makefile.am -1 +1
+
+ * Added all doc files.
+
+ M ./packages/debian/control -2 +1
+ M ./packages/debian/docs +3
+ M ./packages/sofia-sip.spec.in -24 +22
+
+ * Added a separate Makefile.am in packages.
+
+ A ./COPYRIGHTS
+ M ./Makefile.am -6 +2
+ A ./packages/Makefile.am
+
+ * Cleaned up output.
+
+ M ./scripts/coverage -4 +8
+
+ * Adding +x to all scripts.
+
+ M ./autogen.sh +3
+
+ * Added %{?dist} to release.
+
+ M ./packages/sofia-sip.spec.in -1 +4
+
+ * sofia-sip-ua.pc is in packages, too.
+
+ M ./Makefile.am -1 +1
+
+ * DIST_SUBDIR too deep in directory structure does not work.
+
+ M ./configure.ac -4
+ M ./libsofia-sip-ua/docs/Makefile.am -3 +21
+ R ./libsofia-sip-ua/docs/pictures/Makefile.am
+ M ./libsofia-sip-ua/sdp/Makefile.am -3 +11
+ M ./libsofia-sip-ua/sdp/tests/Makefile.am -11
+ M ./libsofia-sip-ua/sip/Makefile.am -3 +19
+ M ./libsofia-sip-ua/sip/images/Makefile.am -5
+ M ./libsofia-sip-ua/sip/tests/Makefile.am -55
+
+ * Added packages subdirectory for package stuff.
+
+ ./sofia-sip-ua.pc.in -> ./packages/sofia-sip-ua.pc.in
+ ./sofia-sip.spec.in -> ./packages/sofia-sip.spec.in
+ M ./Makefile.am -1 +2
+ M ./configure.ac -2 +2
+ A ./packages/
+
+ * Added coverage and built-sources targets at top-level.
+
+ M ./Makefile.am -2 +2
+
+ * Fixed coverage target in libsofia-sip-ua/Makefile.am.
+
+ M ./libsofia-sip-ua/Makefile.am -4 +6
+ M ./libsofia-sip-ua/bnf/Makefile.am +2
+ M ./libsofia-sip-ua/http/Makefile.am +2
+ M ./libsofia-sip-ua/ipt/Makefile.am +2
+ M ./libsofia-sip-ua/iptsec/Makefile.am +2
+ M ./libsofia-sip-ua/msg/Makefile.am +2
+ M ./libsofia-sip-ua/nea/Makefile.am +2
+ M ./libsofia-sip-ua/nta/Makefile.am +2
+ M ./libsofia-sip-ua/nth/Makefile.am +2
+ M ./libsofia-sip-ua/nua/Makefile.am +2
+ M ./libsofia-sip-ua/sdp/Makefile.am +2
+ M ./libsofia-sip-ua/sip/Makefile.am +2
+ M ./libsofia-sip-ua/soa/Makefile.am +2
+ M ./libsofia-sip-ua/sresolv/Makefile.am +2
+ M ./libsofia-sip-ua/stun/Makefile.am +2
+ M ./libsofia-sip-ua/tport/Makefile.am +2
+ M ./libsofia-sip-ua/url/Makefile.am +2
+
+ * Removed su/su.mak.
+
+ R ./libsofia-sip-ua/su/su.mak
+
+ * Added EXPENSIVE_CHECKS.
+
+ M ./configure.ac +1
+ M ./docs/build_system.txt +11
+ M ./m4/sac-general.m4 +13
+
+ * Moved 'testutils' as 'scripts' in toplevel.
+
+ ./libsofia-sip-ua/testutils -> ./scripts
+ M ./libsofia-sip-ua/sofia.am -1 +1
+
+ * Including only library sources in coverage output.
+
+ M ./libsofia-sip-ua/su/Makefile.am -1 +1
+
+ * coverage prints error if check is not made, doesn't depend on check.
+
+ M ./libsofia-sip-ua/sofia.am -2 +2
+
+ * Including all input files in output.
+
+ M ./libsofia-sip-ua/testutils/coverage -20 +27
+
+2005-10-04 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Importing darcs-to-cvs-2005-10-04.
+
+ * Using DIST_SUBDIRS when including dist-only dirs
+
+ M ./Makefile.am -1 +2
+ M ./libsofia-sip-ua/Makefile.am -1 +4
+ M ./libsofia-sip-ua/docs/Makefile.am -3 +1
+ M ./libsofia-sip-ua/sdp/Makefile.am -1 +1
+ M ./libsofia-sip-ua/sip/Makefile.am -1 +1
+
+2005-10-03 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Importing darcs-to-cvs-2005-10-03.
+
+ * Removed old .def files.
+
+ R ./libsofia-sip-ua/ipt/ipt.def
+ R ./libsofia-sip-ua/iptsec/iptsec.def
+ R ./libsofia-sip-ua/msg/msg.def
+ M ./libsofia-sip-ua/nta/nta.def -92
+ M ./libsofia-sip-ua/nta/sl_utils.def -15
+ R ./libsofia-sip-ua/nua/nua.def
+ M ./libsofia-sip-ua/sdp/sdp.def -42
+ R ./libsofia-sip-ua/sip/sip.def
+ R ./libsofia-sip-ua/su/su.def
+ M ./libsofia-sip-ua/tport/tport.def -21
+
+ * Added automake conditional ENABLE_COVERAGE.
+
+ M ./m4/sac-general.m4 +3
+
+ * Added make target for calculating coverage.
+
+ M ./libsofia-sip-ua/Makefile.am -1 +5
+ M ./libsofia-sip-ua/sofia.am +5
+ M ./libsofia-sip-ua/su/Makefile.am +2
+ A ./libsofia-sip-ua/testutils/
+ A ./libsofia-sip-ua/testutils/coverage
+
+2005-09-29 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Importing darcs-to-cvs-2005-09-29.
+
+2005-09-28 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Added nua improvements.
+
+ M ./TODO +3
+
+2005-09-23 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * darcs changes:
+
+ Fri Sep 23 18:58:29 EEST 2005 Pekka.Pessi at nokia.com
+ * Building msg_test class into msg_test library, use that in tport.
+
+ M ./libsofia-sip-ua/msg/Makefile.am -5 +7
+ M ./libsofia-sip-ua/tport/Makefile.am -6 +2
+
+ Fri Sep 23 18:57:20 EEST 2005 Pekka.Pessi at nokia.com
+ * Using --with-aclocal and ${ACLOCAL} to get correct aclocal
+ install directory.
+
+ M ./Makefile.am -2
+ M ./configure.ac +11
+ M ./sofia-sip.spec.in -1 +1
+
+ Fri Sep 23 18:36:46 EEST 2005 Pekka.Pessi at nokia.com
+ * Added win32 into dist.
+
+ M ./Makefile.am -1 +1
+ M ./configure.ac +1
+ A ./win32/Makefile.am
+
+ Fri Sep 23 18:18:30 EEST 2005 Pekka.Pessi at nokia.com
+ * Added nta/{agent.pem,cafile.pem} to EXTRA_DIST
+
+ M ./libsofia-sip-ua/nta/Makefile.am -1 +2
+
+ Fri Sep 23 18:10:45 EEST 2005 Pekka.Pessi at nokia.com
+ * Respect --without-sigcomp.
+
+ M ./m4/sac-tport.m4 -1 +1
+
+ * darcs changes --from-tag pessi-darcs-2:
+
+ Fri Sep 23 17:46:00 EEST 2005 Pekka.Pessi at nokia.com
+ tagged pessi-darcs-2
+
+ Fri Sep 23 17:20:02 EEST 2005 Pekka.Pessi at nokia.com
+ * Added msg_header_replace().
+
+ M ./libsofia-sip-ua/msg/msg_header.h +4
+ M ./libsofia-sip-ua/msg/msg_parser.c +85
+ M ./libsofia-sip-ua/msg/msg_test.c +76
+
+ Thu Sep 22 13:18:52 EEST 2005 Pekka.Pessi at nokia.com
+ * Added nta_test project
+
+ A ./win32/nta_test/
+ A ./win32/nta_test/nta_test.dsp
+
+ Thu Sep 22 13:17:53 EEST 2005 Pekka.Pessi at nokia.com
+ * Added build directory for win32.
+
+ A ./win32/SofiaSIP.dsw
+ A ./win32/config.h
+ A ./win32/libsofia-sip-ua/
+ A ./win32/libsofia-sip-ua/libsofia_sip_ua.dsp
+ A ./win32/libsofia-sip-ua/sofia-sip-ua.def
+ A ./win32/su_configure_win32.h
+ A ./win32/tpipv6.h
+ A ./win32/unistd.h
+ A ./win32/wspiapi.h
+
+ Thu Sep 22 13:15:32 EEST 2005 Pekka.Pessi at nokia.com
+ * Added win32 pthread library.
+
+ A ./win32/pthread/
+ A ./win32/pthread/ChangeLog
+ A ./win32/pthread/md5.sum.txt
+ A ./win32/pthread/pthread.def
+ A ./win32/pthread/pthread.dll
+ A ./win32/pthread/pthread.h
+ A ./win32/pthread/pthread.lib
+ A ./win32/pthread/sched.h
+ A ./win32/pthread/semaphore.h
+
+ Thu Sep 22 13:13:03 EEST 2005 Pekka.Pessi at nokia.com
+ * Added ntv6 library.
+
+ A ./win32/
+ A ./win32/ntv6/
+ A ./win32/ntv6/include/
+ A ./win32/ntv6/include/icmp6.h
+ A ./win32/ntv6/include/ip6.h
+ A ./win32/ntv6/include/ip6addr.h
+ A ./win32/ntv6/include/ip6exp.h
+ A ./win32/ntv6/include/ipsec.h
+ A ./win32/ntv6/include/ipv6.h
+ A ./win32/ntv6/include/ntddip6.h
+ A ./win32/ntv6/include/ntddnapt.h
+ A ./win32/ntv6/include/ntddtcp.h
+ A ./win32/ntv6/include/packoff.h
+ A ./win32/ntv6/include/packon.h
+ A ./win32/ntv6/include/tcp6info.h
+ A ./win32/ntv6/include/tcpinfo.h
+ A ./win32/ntv6/include/tdi.h
+ A ./win32/ntv6/include/tdistat.h
+ A ./win32/ntv6/include/ws2ip6.h
+ A ./win32/ntv6/include/ws2tcpip-msr.h
+ A ./win32/ntv6/lib/
+ A ./win32/ntv6/lib/wship6.lib
+
+ Tue Sep 20 12:51:58 EEST 2005 Pekka.Pessi at nokia.com
+ * Fixed typo.
+
+ M ./libsofia-sip-ua/soa/soa.docs -1 +1
+
+ Tue Sep 20 12:51:41 EEST 2005 Pekka.Pessi at nokia.com
+ * Added SIPS_PORT()
+
+ M ./libsofia-sip-ua/sip/sip_header.h +3
+
+ Mon Sep 19 20:12:33 EEST 2005 Pekka.Pessi at nokia.com
+ * Updated. Added rules for ignoring SDP. corrected some
+
+ M ./libsofia-sip-ua/soa/soa.docs -8 +18
+
+ Fri Sep 16 10:23:14 EEST 2005 Pekka.Pessi at nokia.com
+ * Parsing URI along with DNS entries in subjectAltName.
+
+ M ./libsofia-sip-ua/tport/tport_tls.c -5 +12
+
+ Fri Sep 16 10:22:39 EEST 2005 Pekka.Pessi at nokia.com
+ * Not requiring client to provide its certificate.
+
+ M ./libsofia-sip-ua/tport/tport_tls.c -1 +1
+
+ Fri Sep 16 10:21:56 EEST 2005 Pekka.Pessi at nokia.com
+ * Removed merge artifact.
+
+ M ./libsofia-sip-ua/tport/tport.c -7
+
+ Fri Sep 16 10:21:32 EEST 2005 Pekka.Pessi at nokia.com
+ * Fixed NAPTR service fields for SIPS/TLS and SIP/SCTP.
+
+ M ./libsofia-sip-ua/nta/nta.c -2 +2
+
+ Thu Sep 15 09:57:38 EEST 2005 Pekka.Pessi at nokia.com
+ * Included m4 files in devel rpm, too.
+
+ M ./sofia-sip.spec.in +4
+
+ Thu Sep 15 09:56:25 EEST 2005 Pekka.Pessi at nokia.com
+ * Added --with-sigcomp to tport.
+
+ M ./m4/sac-tport.m4 +21
+
+ Thu Sep 15 09:55:57 EEST 2005 Pekka.Pessi at nokia.com
+ * Moved SAC_GNU_SOURCE into sac-general.m4
+
+ M ./m4/sac-general.m4 +11
+ M ./m4/sac-su.m4 -10
+
+ Thu Sep 15 09:55:26 EEST 2005 Pekka.Pessi at nokia.com
+ * Fixed debugging output in nua_stack.c.
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -3 +3
+
+ Thu Sep 15 09:53:11 EEST 2005 Pekka.Pessi at nokia.com
+ * Installing m4data into m4dir
+
+ M ./Makefile.am +4
+
+2005-09-09 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * darcs changes --from-tag pessi-darcs-1:
+
+ Fri Sep 9 11:38:44 EEST 2005 Pekka.Pessi at nokia.com
+ * Added --with sigcomp.
+
+ M ./sofia-sip.spec.in +4
+
+ Fri Sep 9 00:33:36 EEST 2005 Pekka.Pessi at nokia.com
+ * Including *.h.in files in devel package.
+
+ M ./sofia-sip.spec.in +1
+
+ Thu Sep 8 18:52:06 EEST 2005 Pekka.Pessi at nokia.com
+ * New version.
+
+ M ./configure.ac -1 +1
+
+ Thu Sep 8 18:51:27 EEST 2005 Pekka.Pessi at nokia.com
+ * Keeping section headers in configure script.
+
+ M ./configure.ac -17 +16
+
+ Thu Sep 8 18:26:35 EEST 2005 Pekka.Pessi at nokia.com
+ * Using autoconf to figure out 64-bit types. Avoid off_t and
+ 64-bit constants.
+
+ M ./configure.ac +6
+ M ./libsofia-sip-ua/nta/sl_read_payload.c -1 +1
+ M ./libsofia-sip-ua/nua/nua_stack.c -6 +5
+ M ./libsofia-sip-ua/sdp/sdp_parse.c -3 +2
+ M ./libsofia-sip-ua/sdp/sdp_print.c -5 +5
+ M ./libsofia-sip-ua/sip/validator.c -18 +18
+ M ./libsofia-sip-ua/soa/soa.c -3 +4
+ M ./libsofia-sip-ua/su/su_time.c -1 +1
+ M ./libsofia-sip-ua/su/tstdef.h -3 +3
+
+ Thu Sep 8 18:17:58 EEST 2005 Pekka.Pessi at nokia.com
+ * Using RETSIGTYPE.
+
+ M ./configure.ac -3 +4
+ M ./libsofia-sip-ua/nth/http-server.c -2 +2
+ M ./libsofia-sip-ua/soa/test_soa.c -1 +3
+ M ./libsofia-sip-ua/su/su_test.c -1 +1
+ M ./libsofia-sip-ua/su/su_timer_test.c -1 +1
+
+ Thu Sep 8 18:02:14 EEST 2005 Pekka.Pessi at nokia.com
+ * Checking for netinet/tcp.h, too.
+
+ M ./m4/sac-tport.m4 +2
+
+2005-09-08 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * Makefile.am: Added requirement for automake-1.6.1
+ or newer.
+
+ * autogen.sh: Fixed interop problem with older automake
+ versions.
+
+ * configure.ac: Do not compile STUN if OpenSSL is not
+ available.
+
+2005-07-20 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Makefile.am: Added doxygen target.
Added: freeswitch/trunk/libs/sofia-sip/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/Makefile.am Thu Dec 21 01:30:28 2006
@@ -0,0 +1,50 @@
+#
+# Makefile.am for sofia-sip package
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+AUTOMAKE_OPTIONS = foreign 1.7
+
+SUBDIRS = libsofia-sip-ua $(GLIB_SUBDIRS) utils packages
+DIST_SUBDIRS = libsofia-sip-ua libsofia-sip-ua-glib utils packages win32
+
+# note: when glib devel files are not available, make should not
+# enter the libsofia-sip-ua-glib subdir at all
+if HAVE_GLIB
+GLIB_SUBDIRS = libsofia-sip-ua-glib
+endif
+
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+
+EXTRA_DIST = AUTHORS COPYING COPYRIGHTS ChangeLog.ext-trees \
+ README README.developers RELEASE TODO
+
+ACLOCAL_AMFLAGS = -I m4
+
+EXTRA_DIST += m4/sac-general.m4 m4/sac-su.m4 \
+ m4/sac-su2.m4 m4/sac-tport.m4 m4/sac-openssl.m4
+
+dist_man_MANS = man/man1/sip-date.1 man/man1/sip-options.1 \
+ man/man1/localinfo.1 man/man1/addrinfo.1 \
+ man/man1/stunc.1 man/man1/sip-dig.1
+
+$(dist_man_MANS): manpages
+
+manpages: built-sources
+ -mkdir -p man man/man1 2> /dev/null
+if HAVE_DOXYGEN
+ cd utils && $(DOXYGEN) Doxyfile.build
+ @rm -f man/man1/_*.1
+else
+ -touch $(dist_man_MANS)
+endif
+
+CLEANFILES = $(dist_man_MANS)
+
+coverage built-sources clean-built-sources doxygen:
+ for i in libsofia-sip-ua $(GLIB_SUBDIRS) ; do $(MAKE) $(AM_MAKEFLAGS) -C $$i $@ ; done
+
+.PHONY: coverage built-sources clean-built-sources doxygen manpages
Added: freeswitch/trunk/libs/sofia-sip/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/Makefile.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1,758 @@
+# 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.
+
+ at SET_MAKE@
+
+#
+# Makefile.am for sofia-sip package
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+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@
+DIST_COMMON = README $(am__configure_deps) $(dist_man_MANS) \
+ $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+ $(srcdir)/config.h.in $(top_srcdir)/configure \
+ $(top_srcdir)/libsofia-sip-ua/features/sofia-sip/sofia_features.h.in \
+ $(top_srcdir)/libsofia-sip-ua/su/sofia-sip/su_configure.h.in \
+ AUTHORS COPYING ChangeLog TODO compile config.guess config.sub \
+ depcomp install-sh ltmain.sh missing
+subdir = .
+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)
+am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
+ configure.lineno configure.status.lineno
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = config.h \
+ $(top_builddir)/libsofia-sip-ua/su/sofia-sip/su_configure.h
+CONFIG_CLEAN_FILES = \
+ libsofia-sip-ua/features/sofia-sip/sofia_features.h
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+ html-recursive info-recursive install-data-recursive \
+ install-exec-recursive install-info-recursive \
+ install-recursive installcheck-recursive installdirs-recursive \
+ pdf-recursive ps-recursive uninstall-info-recursive \
+ uninstall-recursive
+man1dir = $(mandir)/man1
+am__installdirs = "$(DESTDIR)$(man1dir)"
+NROFF = nroff
+MANS = $(dist_man_MANS)
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+am__remove_distdir = \
+ { test ! -d $(distdir) \
+ || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \
+ && rm -fr $(distdir); }; }
+DIST_ARCHIVES = $(distdir).tar.gz
+GZIP_ENV = --best
+distuninstallcheck_listfiles = find . -type f -print
+distcleancheck_listfiles = find . -type f -print
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = -I m4
+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@
+AUTOMAKE_OPTIONS = foreign 1.7
+SUBDIRS = libsofia-sip-ua $(GLIB_SUBDIRS) utils packages
+DIST_SUBDIRS = libsofia-sip-ua libsofia-sip-ua-glib utils packages win32
+
+# note: when glib devel files are not available, make should not
+# enter the libsofia-sip-ua-glib subdir at all
+ at HAVE_GLIB_TRUE@GLIB_SUBDIRS = libsofia-sip-ua-glib
+EXTRA_DIST = AUTHORS COPYING COPYRIGHTS ChangeLog.ext-trees README \
+ README.developers RELEASE TODO m4/sac-general.m4 m4/sac-su.m4 \
+ m4/sac-su2.m4 m4/sac-tport.m4 m4/sac-openssl.m4
+dist_man_MANS = man/man1/sip-date.1 man/man1/sip-options.1 \
+ man/man1/localinfo.1 man/man1/addrinfo.1 \
+ man/man1/stunc.1 man/man1/sip-dig.1
+
+CLEANFILES = $(dist_man_MANS)
+all: config.h
+ $(MAKE) $(AM_MAKEFLAGS) all-recursive
+
+.SUFFIXES:
+am--refresh:
+ @:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ echo ' cd $(srcdir) && $(AUTOMAKE) --foreign '; \
+ cd $(srcdir) && $(AUTOMAKE) --foreign \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --foreign Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ echo ' $(SHELL) ./config.status'; \
+ $(SHELL) ./config.status;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ $(SHELL) ./config.status --recheck
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(srcdir) && $(AUTOCONF)
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
+
+config.h: stamp-h1
+ @if test ! -f $@; then \
+ rm -f stamp-h1; \
+ $(MAKE) stamp-h1; \
+ else :; fi
+
+stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
+ @rm -f stamp-h1
+ cd $(top_builddir) && $(SHELL) ./config.status config.h
+$(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_srcdir) && $(AUTOHEADER)
+ rm -f stamp-h1
+ touch $@
+
+libsofia-sip-ua/su/sofia-sip/su_configure.h: libsofia-sip-ua/su/sofia-sip/stamp-h2
+ @if test ! -f $@; then \
+ rm -f libsofia-sip-ua/su/sofia-sip/stamp-h2; \
+ $(MAKE) libsofia-sip-ua/su/sofia-sip/stamp-h2; \
+ else :; fi
+
+libsofia-sip-ua/su/sofia-sip/stamp-h2: $(top_srcdir)/libsofia-sip-ua/su/sofia-sip/su_configure.h.in $(top_builddir)/config.status
+ @rm -f libsofia-sip-ua/su/sofia-sip/stamp-h2
+ cd $(top_builddir) && $(SHELL) ./config.status libsofia-sip-ua/su/sofia-sip/su_configure.h
+
+distclean-hdr:
+ -rm -f config.h stamp-h1 libsofia-sip-ua/su/sofia-sip/su_configure.h libsofia-sip-ua/su/sofia-sip/stamp-h2
+libsofia-sip-ua/features/sofia-sip/sofia_features.h: $(top_builddir)/config.status $(top_srcdir)/libsofia-sip-ua/features/sofia-sip/sofia_features.h.in
+ cd $(top_builddir) && $(SHELL) ./config.status $@
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+uninstall-info-am:
+install-man1: $(man1_MANS) $(man_MANS)
+ @$(NORMAL_INSTALL)
+ test -z "$(man1dir)" || $(mkdir_p) "$(DESTDIR)$(man1dir)"
+ @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.1*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+ else file=$$i; fi; \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 1*) ;; \
+ *) ext='1' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst"; \
+ done
+uninstall-man1:
+ @$(NORMAL_UNINSTALL)
+ @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.1*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 1*) ;; \
+ *) ext='1' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " rm -f '$(DESTDIR)$(man1dir)/$$inst'"; \
+ rm -f "$(DESTDIR)$(man1dir)/$$inst"; \
+ done
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+# (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+ @set fnord $$MAKEFLAGS; amf=$$2; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+mostlyclean-recursive clean-recursive distclean-recursive \
+maintainer-clean-recursive:
+ @set fnord $$MAKEFLAGS; amf=$$2; \
+ dot_seen=no; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ rev=''; for subdir in $$list; do \
+ if test "$$subdir" = "."; then :; else \
+ rev="$$subdir $$rev"; \
+ fi; \
+ done; \
+ rev="$$rev ."; \
+ target=`echo $@ | sed s/-recursive//`; \
+ for subdir in $$rev; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+ done && test -z "$$fail"
+tags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+ done
+ctags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+ 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: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ list='$(SOURCES) $(HEADERS) config.h.in $(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: ctags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) config.h.in $(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
+
+distdir: $(DISTFILES)
+ $(am__remove_distdir)
+ mkdir $(distdir)
+ $(mkdir_p) $(distdir)/libsofia-sip-ua/docs $(distdir)/libsofia-sip-ua/features/sofia-sip $(distdir)/libsofia-sip-ua/su/sofia-sip $(distdir)/m4 $(distdir)/man/man1 $(distdir)/packages $(distdir)/utils $(distdir)/win32
+ @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
+ list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test -d "$(distdir)/$$subdir" \
+ || $(mkdir_p) "$(distdir)/$$subdir" \
+ || exit 1; \
+ distdir=`$(am__cd) $(distdir) && pwd`; \
+ top_distdir=`$(am__cd) $(top_distdir) && pwd`; \
+ (cd $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$top_distdir" \
+ distdir="$$distdir/$$subdir" \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+ -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \
+ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
+ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \
+ ! -type d ! -perm -444 -exec $(SHELL) $(install_sh) -c -m a+r {} {} \; \
+ || chmod -R a+r $(distdir)
+dist-gzip: distdir
+ tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+ $(am__remove_distdir)
+
+dist-bzip2: distdir
+ tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2
+ $(am__remove_distdir)
+
+dist-tarZ: distdir
+ tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
+ $(am__remove_distdir)
+
+dist-shar: distdir
+ shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
+ $(am__remove_distdir)
+
+dist-zip: distdir
+ -rm -f $(distdir).zip
+ zip -rq $(distdir).zip $(distdir)
+ $(am__remove_distdir)
+
+dist dist-all: distdir
+ tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+ $(am__remove_distdir)
+
+# This target untars the dist file and tries a VPATH configuration. Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+ case '$(DIST_ARCHIVES)' in \
+ *.tar.gz*) \
+ GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\
+ *.tar.bz2*) \
+ bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\
+ *.tar.Z*) \
+ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
+ *.shar.gz*) \
+ GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\
+ *.zip*) \
+ unzip $(distdir).zip ;;\
+ esac
+ chmod -R a-w $(distdir); chmod a+w $(distdir)
+ mkdir $(distdir)/_build
+ mkdir $(distdir)/_inst
+ chmod a-w $(distdir)
+ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
+ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
+ && cd $(distdir)/_build \
+ && ../configure --srcdir=.. --prefix="$$dc_install_base" \
+ $(DISTCHECK_CONFIGURE_FLAGS) \
+ && $(MAKE) $(AM_MAKEFLAGS) \
+ && $(MAKE) $(AM_MAKEFLAGS) dvi \
+ && $(MAKE) $(AM_MAKEFLAGS) check \
+ && $(MAKE) $(AM_MAKEFLAGS) install \
+ && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+ && $(MAKE) $(AM_MAKEFLAGS) uninstall \
+ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
+ distuninstallcheck \
+ && chmod -R a-w "$$dc_install_base" \
+ && ({ \
+ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
+ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
+ } || { rm -rf "$$dc_destdir"; exit 1; }) \
+ && rm -rf "$$dc_destdir" \
+ && $(MAKE) $(AM_MAKEFLAGS) dist \
+ && rm -rf $(DIST_ARCHIVES) \
+ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck
+ $(am__remove_distdir)
+ @(echo "$(distdir) archives ready for distribution: "; \
+ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
+ sed -e '1{h;s/./=/g;p;x;}' -e '$${p;x;}'
+distuninstallcheck:
+ @cd $(distuninstallcheck_dir) \
+ && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \
+ || { echo "ERROR: files left after uninstall:" ; \
+ if test -n "$(DESTDIR)"; then \
+ echo " (check DESTDIR support)"; \
+ fi ; \
+ $(distuninstallcheck_listfiles) ; \
+ exit 1; } >&2
+distcleancheck: distclean
+ @if test '$(srcdir)' = . ; then \
+ echo "ERROR: distcleancheck can only run from a VPATH build" ; \
+ exit 1 ; \
+ fi
+ @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
+ || { echo "ERROR: files left in build directory after distclean:" ; \
+ $(distcleancheck_listfiles) ; \
+ exit 1; } >&2
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(MANS) config.h
+installdirs: installdirs-recursive
+installdirs-am:
+ for dir in "$(DESTDIR)$(man1dir)"; do \
+ test -z "$$dir" || $(mkdir_p) "$$dir"; \
+ done
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+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:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-hdr \
+ distclean-libtool distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+info: info-recursive
+
+info-am:
+
+install-data-am: install-man
+
+install-exec-am:
+
+install-info: install-info-recursive
+
+install-man: install-man1
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -rf $(top_srcdir)/autom4te.cache
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-man
+
+uninstall-info: uninstall-info-recursive
+
+uninstall-man: uninstall-man1
+
+.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am am--refresh check \
+ check-am clean clean-generic clean-libtool clean-recursive \
+ ctags ctags-recursive dist dist-all dist-bzip2 dist-gzip \
+ dist-shar dist-tarZ dist-zip distcheck distclean \
+ distclean-generic distclean-hdr distclean-libtool \
+ distclean-recursive distclean-tags distcleancheck distdir \
+ distuninstallcheck dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-exec \
+ install-exec-am install-info install-info-am install-man \
+ install-man1 install-strip installcheck installcheck-am \
+ installdirs installdirs-am maintainer-clean \
+ maintainer-clean-generic maintainer-clean-recursive \
+ mostlyclean mostlyclean-generic mostlyclean-libtool \
+ mostlyclean-recursive pdf pdf-am ps ps-am tags tags-recursive \
+ uninstall uninstall-am uninstall-info-am uninstall-man \
+ uninstall-man1
+
+
+$(dist_man_MANS): manpages
+
+manpages: built-sources
+ -mkdir -p man man/man1 2> /dev/null
+ at HAVE_DOXYGEN_TRUE@ cd utils && $(DOXYGEN) Doxyfile.build
+ at HAVE_DOXYGEN_TRUE@ @rm -f man/man1/_*.1
+ at HAVE_DOXYGEN_FALSE@ -touch $(dist_man_MANS)
+
+coverage built-sources clean-built-sources doxygen:
+ for i in libsofia-sip-ua $(GLIB_SUBDIRS) ; do $(MAKE) $(AM_MAKEFLAGS) -C $$i $@ ; done
+
+.PHONY: coverage built-sources clean-built-sources doxygen manpages
+# 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:
Added: freeswitch/trunk/libs/sofia-sip/README
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/README Thu Dec 21 01:30:28 2006
@@ -0,0 +1,67 @@
+=============================================================
+README / Sofia-SIP - RFC3261 compliant SIP User-Agent library
+=============================================================
+
+Introduction
+------------
+
+Sofia-SIP is an open-source SIP User-Agent library, compliant
+with the IETF RFC3261 specification. It can be used as
+a building block for SIP client software for uses such as VoIP,
+IM, and many other real-time and person-to-person communication
+services. The primary target platform for Sofia-SIP is
+GNU/Linux. Sofia-SIP is based on a SIP stack developed at
+the Nokia Research Center. Sofia-SIP is licensed under the LGPL.
+
+
+Quick start
+-----------
+
+Sofia-SIP uses the GNU autotools, so building procedure
+is the usual:
+
+sh> sh autogen.sh (if building from darcs)
+sh> ./configure
+sh> make
+sh> make install
+
+See also 'docs/devel_platform_notes.txt' for notes on compiling
+Sofia-SIP in different environments.
+
+See the "options-client-example" (available using darcs at
+http://sofia-sip.org/repos/options-client-example/ or with CVS as
+a module in Sofia-SIP CVS tree) for an example of a small app that
+is utilizing Sofia-SIP, and specifically the libsofia-sip-ua
+library component.
+
+There are also multiple example clients under
+the "sofia-sip/utils" directory:
+
+- sip-options, query using SIP OPTIONS method
+- sip-date, SIP date printer/parser
+
+The Sofia-SIP su submodule also provides some small utilities:
+
+- addrinfo (libsofia-sip-ua/su), resolve host names
+- localinfo (libsofia-sip-ua/su), prints information about
+ local network interfaces
+
+
+References
+----------
+
+Project website:
+- http://sofia-sip.sourceforge.net
+- http://www.sourceforge.net/projects/sofia-sip
+
+Mailing list:
+- http://sourceforge.net/mail/?group_id=143636
+
+Version control repositories:
+- see the project website (link above)
+
+Licensing
+---------
+
+Sofia-SIP is licensed under terms of the GNU LGPL.
+See the file "COPYING" for more information.
Added: freeswitch/trunk/libs/sofia-sip/README.developers
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/README.developers Thu Dec 21 01:30:28 2006
@@ -0,0 +1,134 @@
+===============================================================
+README.developers - Sofia-SIP development practices
+===============================================================
+
+Introduction
+============
+
+This file is a collection of practices and rules for Sofia-SIP
+development. If you have questions, or would like to make
+changes, raise the issue on sofia-sip-devel (see
+http://lists.sourceforge.net/lists/listinfo/sofia-sip-devel ).
+
+
+Important files for developers
+==============================
+
+AUTHORS
+ List of contributors. When contributing new code, add
+ yourself to AUTHORS, and also remember to update the
+ per source file copyright statements.
+
+COPYRIGHTS
+ List of licenses and related copyright statements. While
+ majority of Sofia-SIP is licensed under LGPL, there are
+ a few files with different, but LGPL compatible, licensing
+ terms.
+
+README.developers
+ This file.
+
+TODO
+ Not in active use yet.
+
+<dir>/ChangeLog files
+ All non-trivial changes to the source code should
+ be documented in the ChangeLog files. See also the
+ top-level ChangeLog.
+
+
+Version numbering
+=================
+
+Package version
+---------------
+
+For public releases, the package version is:
+ vMAJOR.MINOR.REVISION, where MINOR is even
+
+For development releases and snaphots the version is one of:
+ vMAJOR.MINOR.REVISION, where minor is odd
+ vMAJOR.MINOR.REVISION.YEAR.MONTH.DAY, where minor is odd
+
+For all releases, the version should be changed in configure.ac
+and committed to Darcs/CVS before making the release package. The person
+doing the release is responsible for updating the version number.
+
+Library interface versions
+--------------------------
+
+Sofia-SIP libraries utilize libtool interface versioning. See
+
+ - http://www.gnu.org/software/libtool/manual.html#Versioning
+ - http://www.gnu.org/software/libtool/manual.html#Using-Automake
+
+The interface versions are set in top-level 'configure.ac' file.
+Additionally, the SONAME version (CURRENT-AGE) is set in the
+same place. These version numbers are available for use as autoconf
+variables (see the library 'Makefile.am' files and
+'packages/sofia-sip.spec.in').
+
+All changes to the library versions should be marked to the
+appropriate library 'ChangeLog' file. The library version should
+be changed at the same time as the first interface change is
+committed since the previous release. The interface version is
+frozen (should be marked to the 'ChangeLog' file) at the time
+the next release is tagged (in other words, intra-release changes
+need not be tracked with libtool versions).
+
+The goal should always be to avoid breaking the API/ABIs until
+absolutely necessary. Interfaces clearly marked as private can
+be changed without change to library interface version, but
+otherwise all public functions, types, variables and definitions
+fall under interface change control.
+
+
+Version control tags
+====================
+
+Tagging releases and snapshots
+------------------------------
+
+- source repository (*)
+ - master Darcs tree at:
+ http://sofia-sip.org/repos/sofia-sip
+ - CVS tree (only used to track major releases) at:
+ http://sourceforge.net/cvs/?group_id=143636
+- tags: rel-sofia-sip-x_y_z
+ - stable and development releases (matches release
+ version sofia-sip-x.y.z)
+- tags: snapshot_rel_YEARMMDD
+ - snapshot releases at
+ http://sofia-sip.sourceforge.net/snapshots/
+
+Notes (*):
+ - Information about Darcs:
+ http://abridgegame.org/darcs/
+ http://lwn.net/Articles/110516/
+
+
+Sending patches
+===============
+
+People without Darcs access
+---------------------------
+
+Send your patches to sofia-sip-devel. Someone from the
+development team (see AUTHORS) will handle the patch.
+
+People with Darcs access
+------------------------
+
+Trivial changes can be committed without review. For non-trivial
+changes, you should first send a proposal to sofia-sip-devel and
+wait for comments. There are no strict approval rules so use of
+common sense is recommended. ;)
+
+Tips for making patches
+-----------------------
+
+- test your patch on a clean checkout from version control system
+- remember to check for updates before pushing your changes
+ to the master repository
+
+
Added: freeswitch/trunk/libs/sofia-sip/RELEASE
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/RELEASE Thu Dec 21 01:30:28 2006
@@ -0,0 +1,96 @@
+==============================================
+Release notes for current version of Sofia-SIP
+==============================================
+
+Changes since last release
+--------------------------
+
+<changes since last written in freshmeat.net "Changes:" style;
+ and in less than 10 lines />
+
+Bugs in blaa and foo have been fixed. The stack now supports
+use of foobar...
+
+API/ABI changes and versioning
+------------------------------
+
+<see previous release notes at
+ http://sofia-sip.sourceforge.net/relnotes/ for examples ;
+ - should include all changes to public headers, and
+ other important information to developers;
+ - and should be updated _continuously_! />
+
+**template**: New features in API are marked with Doxytag macro @VERSION_1_XX_X.
+
+libsofia-sip-ua:
+- **template**: Added foobar() function (sofia-sip/foobar.h).
+- Added sip_is_allowed() function and k_bitmap field to the
+ sip_allow_t structure
+- Added SIP header Refer-Sub and related functions
+- Added <sofia-sip/sip_extra.h> include file
+- Added auc_info() function (sofia-sip/auth_client.h)
+- This release is ABI/API compatible with applications linked against
+ any 1.12.x release. However, applications built against this release won't
+ work against an older library. The ABI has been tested with the nua module
+ unit test (test_nua) built against original 1.12.0 release.
+
+libsofia-sip-ua-glib:
+- The 'nua-glib' module has been removed from the library and moved
+ to a separate package 'sofia-nua-glib'. The remaining library (su-glib)
+ is now considered stable and will be API/ABI compatible with later
+ releases in the 1.12.x series.
+- ABI has been modified and applications built against 1.12.4 and earlier
+ releases need to be rebuilt.
+
+Contributors to this release
+----------------------------
+
+<list of people who contributed to _this_ release
+ - update as people's patches are added, or when you commit stuff
+ - current development team members (see AUTHORS) may be omitted
+ - name of the contributor should be enough (email addresses in AUTHORS),
+ plus a brief description of what was contributed
+ - roughly sorted by number of patches accepted
+/>
+
+- **template**: First Surname (patch to nua/soa/msg)
+- Petteri Puolakka (patch to stun)
+
+See the AUTHORS file in the distribution package.
+
+Notes on new features
+---------------------
+
+RFC 4488 defines the Refer-Sub header. Its datatypes, related functions and
+methods declared in <sofia-sip/sip_extra.h> include file. The Refer-Sub
+header structure can be accessed from sip_t structure with sip_refer_sub()
+method, e.g.,
+
+ if (sip_refer_sub(sip) &&
+ strcasecmp("false", sip_refer_sub(sip)->rs_value) == 0) {
+ /* Do not create implicit subscription */
+ }
+
+<information about major new features
+ - new/changed/removed functionality
+ - links to further documentation
+ - section may be omitted for minor releases
+/>
+
+Bugs fixed in this release
+--------------------------
+
+< notable bugs fixed in this release
+ - check the sf.net bug tracker; see closed bugs,
+ sorted by closing date
+ - other bugs as fixed in CVS/darcs
+/>
+
+- **template**: #9499652 sf.net bug item title
+
+- Fixed crash when nua_bye() was called while a NOTIFY client transaction
+ was in progress. Problem reported by Anthony Minnessale.
+- Not using close() with sockets in sres.c. Problem reported by
+ Roman Filonenko.
+- Bug in zero-padding STUN messages with a message integrity
+ attribute. Patch by Petteri Puolakka.
Added: freeswitch/trunk/libs/sofia-sip/RELEASE.template
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/RELEASE.template Thu Dec 21 01:30:28 2006
@@ -0,0 +1,70 @@
+==============================================
+Release notes for current version of Sofia-SIP
+==============================================
+
+Changes since last release
+--------------------------
+
+<changes since last written in freshmeat.net "Changes:" style;
+ and in less than 10 lines />
+
+Bugs in blaa and foo have been fixed. The stack now supports
+use of foobar...
+
+API/ABI changes and versioning
+------------------------------
+
+<see previous release notes at
+ http://sofia-sip.sourceforge.net/relnotes/ for examples ;
+ - should include all changes to public headers, and
+ other important information to developers;
+ - and should be updated _continuously_! />
+
+**template**: New features in API are marked with Doxytag macro @VERSION_1_XX_X.
+
+libsofia-sip-ua:
+- **template**: Added foobar() function (sofia-sip/foobar.h).
+- This release is ABI/API compatible with applications linked against
+ any 1.12.x release. However, applications built against this release won't
+ work against an older library. The ABI has been tested with the nua module
+ unit test (test_nua) built against original 1.12.0 release.
+
+libsofia-sip-ua-glib:
+- No ABI/API changes, compatible with 1.12.0. Note, libsofia-sip-ua-glib
+ interface is not considered stable and may change in a future 1.12.x
+ release.
+
+Contributors to this release
+----------------------------
+
+<list of people who contributed to _this_ release
+ - update as people's patches are added, or when you commit stuff
+ - current development team members (see AUTHORS) may be omitted
+ - name of the contributor should be enough (email addresses in AUTHORS),
+ plus a brief description of what was contributed
+ - roughly sorted by number of patches accepted
+/>
+
+- **template**: First Surname (patch to nua/soa/msg)
+
+See the AUTHORS file in the distribution package.
+
+Notes on new features
+---------------------
+
+<information about major new features
+ - new/changed/removed functionality
+ - links to further documentation
+ - section may be omitted for minor releases
+/>
+
+Bugs fixed in this release
+--------------------------
+
+< notable bugs fixed in this release
+ - check the sf.net bug tracker; see closed bugs,
+ sorted by closing date
+ - other bugs as fixed in CVS/darcs
+/>
+
+- **template**: #9499652 sf.net bug item title
Added: freeswitch/trunk/libs/sofia-sip/TODO
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/TODO Thu Dec 21 01:30:28 2006
@@ -0,0 +1,29 @@
+===============================================================
+TODO / Sofia-SIP
+===============================================================
+
+version: 20060907-2
+
+Release roadmap
+---------------
+
+1.11/1.12 series
+ - first version of the new nua+soa API
+ - nua_respond_nit() (non-INVITEs)
+ - nua_set_hparams()/nua_get_hparams() [DONE]
+ - session object ownership changes [DONE]
+ - allow multiple registrations (lines) and selecting
+ service route, outbound proxy, and transport independently
+ for each handle; NUTAG_IDENTITY
+ - doxygen documentation updates [DONE]
+ - rpm and dpkg packaging [DONE]
+ - NAT work: STUN fixes (DNS support) [DONE]
+
+not roadmapped:
+ - expand the call-state-change mechanism
+ - update http headers TE, Cookie, Set-Cookie
+
+2.0 serias
+ - a verified stable API (1.12 is the current stable candidate)
+
+See README.developers for information about versioning.
Added: freeswitch/trunk/libs/sofia-sip/aclocal.m4
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/aclocal.m4 Thu Dec 21 01:30:28 2006
@@ -0,0 +1,7048 @@
+# generated automatically by aclocal 1.9.2 -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+# Free Software Foundation, Inc.
+# This file 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.
+
+# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
+
+# serial 47 AC_PROG_LIBTOOL
+
+
+# AC_PROVIDE_IFELSE(MACRO-NAME, IF-PROVIDED, IF-NOT-PROVIDED)
+# -----------------------------------------------------------
+# If this macro is not defined by Autoconf, define it here.
+m4_ifdef([AC_PROVIDE_IFELSE],
+ [],
+ [m4_define([AC_PROVIDE_IFELSE],
+ [m4_ifdef([AC_PROVIDE_$1],
+ [$2], [$3])])])
+
+
+# AC_PROG_LIBTOOL
+# ---------------
+AC_DEFUN([AC_PROG_LIBTOOL],
+[AC_REQUIRE([_AC_PROG_LIBTOOL])dnl
+dnl If AC_PROG_CXX has already been expanded, run AC_LIBTOOL_CXX
+dnl immediately, otherwise, hook it in at the end of AC_PROG_CXX.
+ AC_PROVIDE_IFELSE([AC_PROG_CXX],
+ [AC_LIBTOOL_CXX],
+ [define([AC_PROG_CXX], defn([AC_PROG_CXX])[AC_LIBTOOL_CXX
+ ])])
+dnl And a similar setup for Fortran 77 support
+ AC_PROVIDE_IFELSE([AC_PROG_F77],
+ [AC_LIBTOOL_F77],
+ [define([AC_PROG_F77], defn([AC_PROG_F77])[AC_LIBTOOL_F77
+])])
+
+dnl Quote A][M_PROG_GCJ so that aclocal doesn't bring it in needlessly.
+dnl If either AC_PROG_GCJ or A][M_PROG_GCJ have already been expanded, run
+dnl AC_LIBTOOL_GCJ immediately, otherwise, hook it in at the end of both.
+ AC_PROVIDE_IFELSE([AC_PROG_GCJ],
+ [AC_LIBTOOL_GCJ],
+ [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],
+ [AC_LIBTOOL_GCJ],
+ [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ],
+ [AC_LIBTOOL_GCJ],
+ [ifdef([AC_PROG_GCJ],
+ [define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[AC_LIBTOOL_GCJ])])
+ ifdef([A][M_PROG_GCJ],
+ [define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[AC_LIBTOOL_GCJ])])
+ ifdef([LT_AC_PROG_GCJ],
+ [define([LT_AC_PROG_GCJ],
+ defn([LT_AC_PROG_GCJ])[AC_LIBTOOL_GCJ])])])])
+])])# AC_PROG_LIBTOOL
+
+
+# _AC_PROG_LIBTOOL
+# ----------------
+AC_DEFUN([_AC_PROG_LIBTOOL],
+[AC_REQUIRE([AC_LIBTOOL_SETUP])dnl
+AC_BEFORE([$0],[AC_LIBTOOL_CXX])dnl
+AC_BEFORE([$0],[AC_LIBTOOL_F77])dnl
+AC_BEFORE([$0],[AC_LIBTOOL_GCJ])dnl
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh"
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+AC_SUBST(LIBTOOL)dnl
+
+# Prevent multiple expansion
+define([AC_PROG_LIBTOOL], [])
+])# _AC_PROG_LIBTOOL
+
+
+# AC_LIBTOOL_SETUP
+# ----------------
+AC_DEFUN([AC_LIBTOOL_SETUP],
+[AC_PREREQ(2.50)dnl
+AC_REQUIRE([AC_ENABLE_SHARED])dnl
+AC_REQUIRE([AC_ENABLE_STATIC])dnl
+AC_REQUIRE([AC_ENABLE_FAST_INSTALL])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_PROG_LD])dnl
+AC_REQUIRE([AC_PROG_LD_RELOAD_FLAG])dnl
+AC_REQUIRE([AC_PROG_NM])dnl
+
+AC_REQUIRE([AC_PROG_LN_S])dnl
+AC_REQUIRE([AC_DEPLIBS_CHECK_METHOD])dnl
+# Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers!
+AC_REQUIRE([AC_OBJEXT])dnl
+AC_REQUIRE([AC_EXEEXT])dnl
+dnl
+
+AC_LIBTOOL_SYS_MAX_CMD_LEN
+AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE
+AC_LIBTOOL_OBJDIR
+
+AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl
+_LT_AC_PROG_ECHO_BACKSLASH
+
+case $host_os in
+aix3*)
+ # AIX sometimes has problems with the GCC collect2 program. For some
+ # reason, if we set the COLLECT_NAMES environment variable, the problems
+ # vanish in a puff of smoke.
+ if test "X${COLLECT_NAMES+set}" != Xset; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+ fi
+ ;;
+esac
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed='sed -e s/^X//'
+[sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g']
+
+# Same as above, but do not quote variable references.
+[double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g']
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+
+# Constants:
+rm="rm -f"
+
+# Global variables:
+default_ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a `.a' archive for static linking (except M$VC,
+# which needs '.lib').
+libext=a
+ltmain="$ac_aux_dir/ltmain.sh"
+ofile="$default_ofile"
+with_gnu_ld="$lt_cv_prog_gnu_ld"
+
+AC_CHECK_TOOL(AR, ar, false)
+AC_CHECK_TOOL(RANLIB, ranlib, :)
+AC_CHECK_TOOL(STRIP, strip, :)
+
+old_CC="$CC"
+old_CFLAGS="$CFLAGS"
+
+# Set sane defaults for various variables
+test -z "$AR" && AR=ar
+test -z "$AR_FLAGS" && AR_FLAGS=cru
+test -z "$AS" && AS=as
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+test -z "$LD" && LD=ld
+test -z "$LN_S" && LN_S="ln -s"
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+test -z "$NM" && NM=nm
+test -z "$SED" && SED=sed
+test -z "$OBJDUMP" && OBJDUMP=objdump
+test -z "$RANLIB" && RANLIB=:
+test -z "$STRIP" && STRIP=:
+test -z "$ac_objext" && ac_objext=o
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+ case $host_os in
+ openbsd*)
+ old_postinstall_cmds="\$RANLIB -t \$oldlib~$old_postinstall_cmds"
+ ;;
+ *)
+ old_postinstall_cmds="\$RANLIB \$oldlib~$old_postinstall_cmds"
+ ;;
+ esac
+ old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib"
+fi
+
+# Only perform the check for file, if the check method requires it
+case $deplibs_check_method in
+file_magic*)
+ if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+ AC_PATH_MAGIC
+ fi
+ ;;
+esac
+
+AC_PROVIDE_IFELSE([AC_LIBTOOL_DLOPEN], enable_dlopen=yes, enable_dlopen=no)
+AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL],
+enable_win32_dll=yes, enable_win32_dll=no)
+
+AC_ARG_ENABLE([libtool-lock],
+ [AC_HELP_STRING([--disable-libtool-lock],
+ [avoid locking (might break parallel builds)])])
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+AC_ARG_WITH([pic],
+ [AC_HELP_STRING([--with-pic],
+ [try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
+ [pic_mode="$withval"],
+ [pic_mode=default])
+test -z "$pic_mode" && pic_mode=default
+
+# Use C for the default configuration in the libtool script
+tagname=
+AC_LIBTOOL_LANG_C_CONFIG
+_LT_AC_TAGCONFIG
+])# AC_LIBTOOL_SETUP
+
+
+# _LT_AC_SYS_COMPILER
+# -------------------
+AC_DEFUN([_LT_AC_SYS_COMPILER],
+[AC_REQUIRE([AC_PROG_CC])dnl
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+])# _LT_AC_SYS_COMPILER
+
+
+# _LT_AC_SYS_LIBPATH_AIX
+# ----------------------
+# Links a minimal program and checks the executable
+# for the system default hardcoded library path. In most cases,
+# this is /usr/lib:/lib, but when the MPI compilers are used
+# the location of the communication and MPI libs are included too.
+# If we don't find anything, use the default library path according
+# to the aix ld manual.
+AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX],
+[AC_LINK_IFELSE(AC_LANG_PROGRAM,[
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
+}'`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
+}'`; fi],[])
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+])# _LT_AC_SYS_LIBPATH_AIX
+
+
+# _LT_AC_SHELL_INIT(ARG)
+# ----------------------
+AC_DEFUN([_LT_AC_SHELL_INIT],
+[ifdef([AC_DIVERSION_NOTICE],
+ [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)],
+ [AC_DIVERT_PUSH(NOTICE)])
+$1
+AC_DIVERT_POP
+])# _LT_AC_SHELL_INIT
+
+
+# _LT_AC_PROG_ECHO_BACKSLASH
+# --------------------------
+# Add some code to the start of the generated configure script which
+# will find an echo command which doesn't interpret backslashes.
+AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH],
+[_LT_AC_SHELL_INIT([
+# Check that we are running under the correct shell.
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+case X$ECHO in
+X*--fallback-echo)
+ # Remove one level of quotation (which was required for Make).
+ ECHO=`echo "$ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','`
+ ;;
+esac
+
+echo=${ECHO-echo}
+if test "X[$]1" = X--no-reexec; then
+ # Discard the --no-reexec flag, and continue.
+ shift
+elif test "X[$]1" = X--fallback-echo; then
+ # Avoid inline document here, it may be left over
+ :
+elif test "X`($echo '\t') 2>/dev/null`" = 'X\t' ; then
+ # Yippee, $echo works!
+ :
+else
+ # Restart under the correct shell.
+ exec $SHELL "[$]0" --no-reexec ${1+"[$]@"}
+fi
+
+if test "X[$]1" = X--fallback-echo; then
+ # used as fallback echo
+ shift
+ cat <<EOF
+[$]*
+EOF
+ exit 0
+fi
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+if test "X${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi
+
+if test -z "$ECHO"; then
+if test "X${echo_test_string+set}" != Xset; then
+# find a string as large as possible, as long as the shell can cope with it
+ for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do
+ # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ...
+ if (echo_test_string="`eval $cmd`") 2>/dev/null &&
+ echo_test_string="`eval $cmd`" &&
+ (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null
+ then
+ break
+ fi
+ done
+fi
+
+if test "X`($echo '\t') 2>/dev/null`" = 'X\t' &&
+ echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ :
+else
+ # The Solaris, AIX, and Digital Unix default echo programs unquote
+ # backslashes. This makes it impossible to quote backslashes using
+ # echo "$something" | sed 's/\\/\\\\/g'
+ #
+ # So, first we look for a working echo in the user's PATH.
+
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for dir in $PATH /usr/ucb; do
+ IFS="$lt_save_ifs"
+ if (test -f $dir/echo || test -f $dir/echo$ac_exeext) &&
+ test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' &&
+ echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ echo="$dir/echo"
+ break
+ fi
+ done
+ IFS="$lt_save_ifs"
+
+ if test "X$echo" = Xecho; then
+ # We didn't find a better echo, so look for alternatives.
+ if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' &&
+ echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ # This shell has a builtin print -r that does the trick.
+ echo='print -r'
+ elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) &&
+ test "X$CONFIG_SHELL" != X/bin/ksh; then
+ # If we have ksh, try running configure again with it.
+ ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh}
+ export ORIGINAL_CONFIG_SHELL
+ CONFIG_SHELL=/bin/ksh
+ export CONFIG_SHELL
+ exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"}
+ else
+ # Try using printf.
+ echo='printf %s\n'
+ if test "X`($echo '\t') 2>/dev/null`" = 'X\t' &&
+ echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ # Cool, printf works
+ :
+ elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` &&
+ test "X$echo_testing_string" = 'X\t' &&
+ echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL
+ export CONFIG_SHELL
+ SHELL="$CONFIG_SHELL"
+ export SHELL
+ echo="$CONFIG_SHELL [$]0 --fallback-echo"
+ elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` &&
+ test "X$echo_testing_string" = 'X\t' &&
+ echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ echo="$CONFIG_SHELL [$]0 --fallback-echo"
+ else
+ # maybe with a smaller string...
+ prev=:
+
+ for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do
+ if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null
+ then
+ break
+ fi
+ prev="$cmd"
+ done
+
+ if test "$prev" != 'sed 50q "[$]0"'; then
+ echo_test_string=`eval $prev`
+ export echo_test_string
+ exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"}
+ else
+ # Oops. We lost completely, so just stick with echo.
+ echo=echo
+ fi
+ fi
+ fi
+ fi
+fi
+fi
+
+# Copy echo and quote the copy suitably for passing to libtool from
+# the Makefile, instead of quoting the original, which is used later.
+ECHO=$echo
+if test "X$ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then
+ ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo"
+fi
+
+AC_SUBST(ECHO)
+])])# _LT_AC_PROG_ECHO_BACKSLASH
+
+
+# _LT_AC_LOCK
+# -----------
+AC_DEFUN([_LT_AC_LOCK],
+[AC_ARG_ENABLE([libtool-lock],
+ [AC_HELP_STRING([--disable-libtool-lock],
+ [avoid locking (might break parallel builds)])])
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *ELF-32*)
+ HPUX_IA64_MODE="32"
+ ;;
+ *ELF-64*)
+ HPUX_IA64_MODE="64"
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+*-*-irix6*)
+ # Find out which ABI we are using.
+ echo '[#]line __oline__ "configure"' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -melf32bsmip"
+ ;;
+ *N32*)
+ LD="${LD-ld} -melf32bmipn32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -melf64bmip"
+ ;;
+ esac
+ else
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -32"
+ ;;
+ *N32*)
+ LD="${LD-ld} -n32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -64"
+ ;;
+ esac
+ fi
+ fi
+ rm -rf conftest*
+ ;;
+
+x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ case "`/usr/bin/file conftest.o`" in
+ *32-bit*)
+ case $host in
+ x86_64-*linux*)
+ LD="${LD-ld} -m elf_i386"
+ ;;
+ ppc64-*linux*|powerpc64-*linux*)
+ LD="${LD-ld} -m elf32ppclinux"
+ ;;
+ s390x-*linux*)
+ LD="${LD-ld} -m elf_s390"
+ ;;
+ sparc64-*linux*)
+ LD="${LD-ld} -m elf32_sparc"
+ ;;
+ esac
+ ;;
+ *64-bit*)
+ case $host in
+ x86_64-*linux*)
+ LD="${LD-ld} -m elf_x86_64"
+ ;;
+ ppc*-*linux*|powerpc*-*linux*)
+ LD="${LD-ld} -m elf64ppc"
+ ;;
+ s390*-*linux*)
+ LD="${LD-ld} -m elf64_s390"
+ ;;
+ sparc*-*linux*)
+ LD="${LD-ld} -m elf64_sparc"
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+
+*-*-sco3.2v5*)
+ # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+ SAVE_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -belf"
+ AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
+ [AC_LANG_PUSH(C)
+ AC_TRY_LINK([],[],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])
+ AC_LANG_POP])
+ if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+ # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+ CFLAGS="$SAVE_CFLAGS"
+ fi
+ ;;
+AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL],
+[*-*-cygwin* | *-*-mingw* | *-*-pw32*)
+ AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+ AC_CHECK_TOOL(AS, as, false)
+ AC_CHECK_TOOL(OBJDUMP, objdump, false)
+ ;;
+ ])
+esac
+
+need_locks="$enable_libtool_lock"
+
+])# _LT_AC_LOCK
+
+
+# AC_LIBTOOL_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------------------
+# Check whether the given compiler option works
+AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION],
+[AC_REQUIRE([LT_AC_PROG_SED])
+AC_CACHE_CHECK([$1], [$2],
+ [$2=no
+ ifelse([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4])
+ printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="$3"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test ! -s conftest.err; then
+ $2=yes
+ fi
+ fi
+ $rm conftest*
+])
+
+if test x"[$]$2" = xyes; then
+ ifelse([$5], , :, [$5])
+else
+ ifelse([$6], , :, [$6])
+fi
+])# AC_LIBTOOL_COMPILER_OPTION
+
+
+# AC_LIBTOOL_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+# [ACTION-SUCCESS], [ACTION-FAILURE])
+# ------------------------------------------------------------
+# Check whether the given compiler option works
+AC_DEFUN([AC_LIBTOOL_LINKER_OPTION],
+[AC_CACHE_CHECK([$1], [$2],
+ [$2=no
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS $3"
+ printf "$lt_simple_link_test_code" > conftest.$ac_ext
+ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s conftest.err; then
+ # Append any errors to the config.log.
+ cat conftest.err 1>&AS_MESSAGE_LOG_FD
+ else
+ $2=yes
+ fi
+ fi
+ $rm conftest*
+ LDFLAGS="$save_LDFLAGS"
+])
+
+if test x"[$]$2" = xyes; then
+ ifelse([$4], , :, [$4])
+else
+ ifelse([$5], , :, [$5])
+fi
+])# AC_LIBTOOL_LINKER_OPTION
+
+
+# AC_LIBTOOL_SYS_MAX_CMD_LEN
+# --------------------------
+AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN],
+[# find the maximum length of command line arguments
+AC_MSG_CHECKING([the maximum length of command line arguments])
+AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
+ i=0
+ teststring="ABCD"
+
+ case $build_os in
+ msdosdjgpp*)
+ # On DJGPP, this test can blow up pretty badly due to problems in libc
+ # (any single argument exceeding 2000 bytes causes a buffer overrun
+ # during glob expansion). Even if it were fixed, the result of this
+ # check would be larger than it should be.
+ lt_cv_sys_max_cmd_len=12288; # 12K is about right
+ ;;
+
+ gnu*)
+ # Under GNU Hurd, this test is not required because there is
+ # no limit to the length of command line arguments.
+ # Libtool will interpret -1 as no limit whatsoever
+ lt_cv_sys_max_cmd_len=-1;
+ ;;
+
+ cygwin* | mingw*)
+ # On Win9x/ME, this test blows up -- it succeeds, but takes
+ # about 5 minutes as the teststring grows exponentially.
+ # Worse, since 9x/ME are not pre-emptively multitasking,
+ # you end up with a "frozen" computer, even though with patience
+ # the test eventually succeeds (with a max line length of 256k).
+ # Instead, let's just punt: use the minimum linelength reported by
+ # all of the supported platforms: 8192 (on NT/2K/XP).
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ amigaos*)
+ # On AmigaOS with pdksh, this test takes hours, literally.
+ # So we just punt and use a minimum line length of 8192.
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ *)
+ # If test is not a shell built-in, we'll probably end up computing a
+ # maximum length that is only half of the actual maximum length, but
+ # we can't tell.
+ while (test "X"`$CONFIG_SHELL [$]0 --fallback-echo "X$teststring" 2>/dev/null` \
+ = "XX$teststring") >/dev/null 2>&1 &&
+ new_result=`expr "X$teststring" : ".*" 2>&1` &&
+ lt_cv_sys_max_cmd_len=$new_result &&
+ test $i != 17 # 1/2 MB should be enough
+ do
+ i=`expr $i + 1`
+ teststring=$teststring$teststring
+ done
+ teststring=
+ # Add a significant safety factor because C++ compilers can tack on massive
+ # amounts of additional arguments before passing them to the linker.
+ # It appears as though 1/2 is a usable value.
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+ ;;
+ esac
+])
+if test -n $lt_cv_sys_max_cmd_len ; then
+ AC_MSG_RESULT($lt_cv_sys_max_cmd_len)
+else
+ AC_MSG_RESULT(none)
+fi
+])# AC_LIBTOOL_SYS_MAX_CMD_LEN
+
+
+# _LT_AC_CHECK_DLFCN
+# --------------------
+AC_DEFUN([_LT_AC_CHECK_DLFCN],
+[AC_CHECK_HEADERS(dlfcn.h)dnl
+])# _LT_AC_CHECK_DLFCN
+
+
+# _LT_AC_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE,
+# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING)
+# ------------------------------------------------------------------
+AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF],
+[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl
+if test "$cross_compiling" = yes; then :
+ [$4]
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<EOF
+[#line __oline__ "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+#ifdef __cplusplus
+extern "C" void exit (int);
+#endif
+
+void fnord() { int i=42;}
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ /* dlclose (self); */
+ }
+
+ exit (status);
+}]
+EOF
+ if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then
+ (./conftest; exit; ) 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) $1 ;;
+ x$lt_dlneed_uscore) $2 ;;
+ x$lt_unknown|x*) $3 ;;
+ esac
+ else :
+ # compilation failed
+ $3
+ fi
+fi
+rm -fr conftest*
+])# _LT_AC_TRY_DLOPEN_SELF
+
+
+# AC_LIBTOOL_DLOPEN_SELF
+# -------------------
+AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF],
+[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl
+if test "x$enable_dlopen" != xyes; then
+ enable_dlopen=unknown
+ enable_dlopen_self=unknown
+ enable_dlopen_self_static=unknown
+else
+ lt_cv_dlopen=no
+ lt_cv_dlopen_libs=
+
+ case $host_os in
+ beos*)
+ lt_cv_dlopen="load_add_on"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+ ;;
+
+ mingw* | pw32*)
+ lt_cv_dlopen="LoadLibrary"
+ lt_cv_dlopen_libs=
+ ;;
+
+ cygwin*)
+ lt_cv_dlopen="dlopen"
+ lt_cv_dlopen_libs=
+ ;;
+
+ darwin*)
+ # if libdl is installed we need to link against it
+ AC_CHECK_LIB([dl], [dlopen],
+ [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[
+ lt_cv_dlopen="dyld"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+ ])
+ ;;
+
+ *)
+ AC_CHECK_FUNC([shl_load],
+ [lt_cv_dlopen="shl_load"],
+ [AC_CHECK_LIB([dld], [shl_load],
+ [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"],
+ [AC_CHECK_FUNC([dlopen],
+ [lt_cv_dlopen="dlopen"],
+ [AC_CHECK_LIB([dl], [dlopen],
+ [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],
+ [AC_CHECK_LIB([svld], [dlopen],
+ [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"],
+ [AC_CHECK_LIB([dld], [dld_link],
+ [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"])
+ ])
+ ])
+ ])
+ ])
+ ])
+ ;;
+ esac
+
+ if test "x$lt_cv_dlopen" != xno; then
+ enable_dlopen=yes
+ else
+ enable_dlopen=no
+ fi
+
+ case $lt_cv_dlopen in
+ dlopen)
+ save_CPPFLAGS="$CPPFLAGS"
+ test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+ save_LDFLAGS="$LDFLAGS"
+ eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+ save_LIBS="$LIBS"
+ LIBS="$lt_cv_dlopen_libs $LIBS"
+
+ AC_CACHE_CHECK([whether a program can dlopen itself],
+ lt_cv_dlopen_self, [dnl
+ _LT_AC_TRY_DLOPEN_SELF(
+ lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes,
+ lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross)
+ ])
+
+ if test "x$lt_cv_dlopen_self" = xyes; then
+ LDFLAGS="$LDFLAGS $link_static_flag"
+ AC_CACHE_CHECK([whether a statically linked program can dlopen itself],
+ lt_cv_dlopen_self_static, [dnl
+ _LT_AC_TRY_DLOPEN_SELF(
+ lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes,
+ lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross)
+ ])
+ fi
+
+ CPPFLAGS="$save_CPPFLAGS"
+ LDFLAGS="$save_LDFLAGS"
+ LIBS="$save_LIBS"
+ ;;
+ esac
+
+ case $lt_cv_dlopen_self in
+ yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+ *) enable_dlopen_self=unknown ;;
+ esac
+
+ case $lt_cv_dlopen_self_static in
+ yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+ *) enable_dlopen_self_static=unknown ;;
+ esac
+fi
+])# AC_LIBTOOL_DLOPEN_SELF
+
+
+# AC_LIBTOOL_PROG_CC_C_O([TAGNAME])
+# ---------------------------------
+# Check to see if options -c and -o are simultaneously supported by compiler
+AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O],
+[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl
+AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext],
+ [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)],
+ [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no
+ $rm -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&AS_MESSAGE_LOG_FD
+ echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test ! -s out/conftest.err; then
+ _LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+ fi
+ fi
+ chmod u+w .
+ $rm conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files
+ $rm out/* && rmdir out
+ cd ..
+ rmdir conftest
+ $rm conftest*
+])
+])# AC_LIBTOOL_PROG_CC_C_O
+
+
+# AC_LIBTOOL_SYS_HARD_LINK_LOCKS([TAGNAME])
+# -----------------------------------------
+# Check to see if we can do hard links to lock some files if needed
+AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS],
+[AC_REQUIRE([_LT_AC_LOCK])dnl
+
+hard_links="nottested"
+if test "$_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then
+ # do not overwrite the value of need_locks provided by the user
+ AC_MSG_CHECKING([if we can lock with hard links])
+ hard_links=yes
+ $rm conftest*
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ touch conftest.a
+ ln conftest.a conftest.b 2>&5 || hard_links=no
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ AC_MSG_RESULT([$hard_links])
+ if test "$hard_links" = no; then
+ AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe])
+ need_locks=warn
+ fi
+else
+ need_locks=no
+fi
+])# AC_LIBTOOL_SYS_HARD_LINK_LOCKS
+
+
+# AC_LIBTOOL_OBJDIR
+# -----------------
+AC_DEFUN([AC_LIBTOOL_OBJDIR],
+[AC_CACHE_CHECK([for objdir], [lt_cv_objdir],
+[rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+ lt_cv_objdir=.libs
+else
+ # MS-DOS does not allow filenames that begin with a dot.
+ lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null])
+objdir=$lt_cv_objdir
+])# AC_LIBTOOL_OBJDIR
+
+
+# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH([TAGNAME])
+# ----------------------------------------------
+# Check hardcoding attributes.
+AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH],
+[AC_MSG_CHECKING([how to hardcode library paths into programs])
+_LT_AC_TAGVAR(hardcode_action, $1)=
+if test -n "$_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)" || \
+ test -n "$_LT_AC_TAGVAR(runpath_var $1)" || \
+ test "X$_LT_AC_TAGVAR(hardcode_automatic, $1)"="Xyes" ; then
+
+ # We can hardcode non-existant directories.
+ if test "$_LT_AC_TAGVAR(hardcode_direct, $1)" != no &&
+ # If the only mechanism to avoid hardcoding is shlibpath_var, we
+ # have to relink, otherwise we might link with an installed library
+ # when we should be linking with a yet-to-be-installed one
+ ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)" != no &&
+ test "$_LT_AC_TAGVAR(hardcode_minus_L, $1)" != no; then
+ # Linking always hardcodes the temporary library directory.
+ _LT_AC_TAGVAR(hardcode_action, $1)=relink
+ else
+ # We can link without hardcoding, and we can hardcode nonexisting dirs.
+ _LT_AC_TAGVAR(hardcode_action, $1)=immediate
+ fi
+else
+ # We cannot hardcode anything, or else we can only hardcode existing
+ # directories.
+ _LT_AC_TAGVAR(hardcode_action, $1)=unsupported
+fi
+AC_MSG_RESULT([$_LT_AC_TAGVAR(hardcode_action, $1)])
+
+if test "$_LT_AC_TAGVAR(hardcode_action, $1)" = relink; then
+ # Fast installation is not supported
+ enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+ test "$enable_shared" = no; then
+ # Fast installation is not necessary
+ enable_fast_install=needless
+fi
+])# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH
+
+
+# AC_LIBTOOL_SYS_LIB_STRIP
+# ------------------------
+AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP],
+[striplib=
+old_striplib=
+AC_MSG_CHECKING([whether stripping libraries is possible])
+if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then
+ test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+ test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+ AC_MSG_RESULT([yes])
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+ case $host_os in
+ darwin*)
+ if test -n "$STRIP" ; then
+ striplib="$STRIP -x"
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+fi
+ ;;
+ *)
+ AC_MSG_RESULT([no])
+ ;;
+ esac
+fi
+])# AC_LIBTOOL_SYS_LIB_STRIP
+
+
+# AC_LIBTOOL_SYS_DYNAMIC_LINKER
+# -----------------------------
+# PORTME Fill in your ld.so characteristics
+AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER],
+[AC_MSG_CHECKING([dynamic linker characteristics])
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+if test "$GCC" = yes; then
+ sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+ if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then
+ # if the path contains ";" then we assume it to be the separator
+ # otherwise default to the standard path separator (i.e. ":") - it is
+ # assumed that no part of a normal pathname contains ";" but that should
+ # okay in the real world where ";" in dirpaths is itself problematic.
+ sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+ else
+ sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ fi
+else
+ sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+ shlibpath_var=LIBPATH
+
+ # AIX 3 has no versioning support, so we append a major version to the name.
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+
+aix4* | aix5*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ hardcode_into_libs=yes
+ if test "$host_cpu" = ia64; then
+ # AIX 5 supports IA64
+ library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ else
+ # With GCC up to 2.95.x, collect2 would create an import file
+ # for dependence libraries. The import file would start with
+ # the line `#! .'. This would cause the generated library to
+ # depend on `.', always an invalid library. This was fixed in
+ # development snapshots of GCC prior to 3.0.
+ case $host_os in
+ aix4 | aix4.[[01]] | aix4.[[01]].*)
+ if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+ echo ' yes '
+ echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then
+ :
+ else
+ can_build_shared=no
+ fi
+ ;;
+ esac
+ # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+ # soname into executable. Probably we can add versioning support to
+ # collect2, so additional links can be useful in future.
+ if test "$aix_use_runtimelinking" = yes; then
+ # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+ # instead of lib<name>.a to let people know that these are not
+ # typical AIX shared libraries.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ else
+ # We preserve .a as extension for shared libraries through AIX4.2
+ # and later when we are not doing run time linking.
+ library_names_spec='${libname}${release}.a $libname.a'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ fi
+ shlibpath_var=LIBPATH
+ fi
+ ;;
+
+amigaos*)
+ library_names_spec='$libname.ixlibrary $libname.a'
+ # Create ${libname}_ixlibrary.a entries in /sys/libs.
+ finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+ ;;
+
+beos*)
+ library_names_spec='${libname}${shared_ext}'
+ dynamic_linker="$host_os ld.so"
+ shlibpath_var=LIBRARY_PATH
+ ;;
+
+bsdi4*)
+ version_type=linux
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+ # the default ld.so.conf also contains /usr/contrib/lib and
+ # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+ # libtool to hard-code these into programs
+ ;;
+
+cygwin* | mingw* | pw32*)
+ version_type=windows
+ shrext_cmds=".dll"
+ need_version=no
+ need_lib_prefix=no
+
+ case $GCC,$host_os in
+ yes,cygwin* | yes,mingw* | yes,pw32*)
+ library_names_spec='$libname.dll.a'
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \${file}`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $rm \$dlpath'
+ shlibpath_overrides_runpath=yes
+
+ case $host_os in
+ cygwin*)
+ # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+ soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+ sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib"
+ ;;
+ mingw*)
+ # MinGW DLLs use traditional 'lib' prefix
+ soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+ sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+ if echo "$sys_lib_search_path_spec" | [grep ';[c-zC-Z]:/' >/dev/null]; then
+ # It is most probably a Windows format PATH printed by
+ # mingw gcc, but we are running on Cygwin. Gcc prints its search
+ # path with ; separators, and with drive letters. We can handle the
+ # drive letters (cygwin fileutils understands them), so leave them,
+ # especially as we might pass files found there to a mingw objdump,
+ # which wouldn't understand a cygwinified path. Ahh.
+ sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+ else
+ sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ fi
+ ;;
+ pw32*)
+ # pw32 DLLs use 'pw' prefix rather than 'lib'
+ library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ ;;
+ esac
+ ;;
+
+ *)
+ library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib'
+ ;;
+ esac
+ dynamic_linker='Win32 ld.exe'
+ # FIXME: first we should search . and the directory the executable is in
+ shlibpath_var=PATH
+ ;;
+
+darwin* | rhapsody*)
+ dynamic_linker="$host_os dyld"
+ version_type=darwin
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+ soname_spec='${libname}${release}${major}$shared_ext'
+ shlibpath_overrides_runpath=yes
+ shlibpath_var=DYLD_LIBRARY_PATH
+ shrext_cmds='$(test .$module = .yes && echo .so || echo .dylib)'
+ # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same.
+ if test "$GCC" = yes; then
+ sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"`
+ else
+ sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib'
+ fi
+ sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+ ;;
+
+dgux*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+freebsd1*)
+ dynamic_linker=no
+ ;;
+
+kfreebsd*-gnu)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='GNU ld.so'
+ ;;
+
+freebsd*)
+ objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout`
+ version_type=freebsd-$objformat
+ case $version_type in
+ freebsd-elf*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ need_version=no
+ need_lib_prefix=no
+ ;;
+ freebsd-*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+ need_version=yes
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_os in
+ freebsd2*)
+ shlibpath_overrides_runpath=yes
+ ;;
+ freebsd3.[01]* | freebsdelf3.[01]*)
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ *) # from 3.2 on
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+ esac
+ ;;
+
+gnu*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ hardcode_into_libs=yes
+ ;;
+
+hpux9* | hpux10* | hpux11*)
+ # Give a soname corresponding to the major version so that dld.sl refuses to
+ # link against other versions.
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ case "$host_cpu" in
+ ia64*)
+ shrext_cmds='.so'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ if test "X$HPUX_IA64_MODE" = X32; then
+ sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+ else
+ sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+ fi
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ hppa*64*)
+ shrext_cmds='.sl'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ *)
+ shrext_cmds='.sl'
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=SHLIB_PATH
+ shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+ esac
+ # HP-UX runs *really* slowly unless shared libraries are mode 555.
+ postinstall_cmds='chmod 555 $lib'
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $host_os in
+ nonstopux*) version_type=nonstopux ;;
+ *)
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ version_type=linux
+ else
+ version_type=irix
+ fi ;;
+ esac
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+ case $host_os in
+ irix5* | nonstopux*)
+ libsuff= shlibsuff=
+ ;;
+ *)
+ case $LD in # libtool.m4 will add one of these switches to LD
+ *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+ libsuff= shlibsuff= libmagic=32-bit;;
+ *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+ libsuff=32 shlibsuff=N32 libmagic=N32;;
+ *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+ libsuff=64 shlibsuff=64 libmagic=64-bit;;
+ *) libsuff= shlibsuff= libmagic=never-match;;
+ esac
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+ sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+ hardcode_into_libs=yes
+ ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+ dynamic_linker=no
+ ;;
+
+# This must be Linux ELF.
+linux*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ # This implies no fast_install, which is unacceptable.
+ # Some rework will be needed to allow for fast_install
+ # before this can be enabled.
+ hardcode_into_libs=yes
+
+ # find out which ABI we are using
+ libsuff=
+ case "$host_cpu" in
+ x86_64*|s390x*|powerpc64*)
+ echo '[#]line __oline__ "configure"' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *64-bit*)
+ libsuff=64
+ sys_lib_search_path_spec="/lib${libsuff} /usr/lib${libsuff} /usr/local/lib${libsuff}"
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+ esac
+
+ # Append ld.so.conf contents to the search path
+ if test -f /etc/ld.so.conf; then
+ lt_ld_extra=`$SED -e 's/[:,\t]/ /g;s/=[^=]*$//;s/=[^= ]* / /g' /etc/ld.so.conf | tr '\n' ' '`
+ sys_lib_dlsearch_path_spec="/lib${libsuff} /usr/lib${libsuff} $lt_ld_extra"
+ fi
+
+ # We used to test for /lib/ld.so.1 and disable shared libraries on
+ # powerpc, because MkLinux only supported shared libraries with the
+ # GNU dynamic linker. Since this was broken with cross compilers,
+ # most powerpc-linux boxes support dynamic linking these days and
+ # people can always --disable-shared, the test was removed, and we
+ # assume the GNU/Linux dynamic linker is in use.
+ dynamic_linker='GNU/Linux ld.so'
+ ;;
+
+knetbsd*-gnu)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='GNU ld.so'
+ ;;
+
+netbsd*)
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ dynamic_linker='NetBSD (a.out) ld.so'
+ else
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='NetBSD ld.elf_so'
+ fi
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+
+newsos6)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+nto-qnx*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+openbsd*)
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=yes
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ case $host_os in
+ openbsd2.[[89]] | openbsd2.[[89]].*)
+ shlibpath_overrides_runpath=no
+ ;;
+ *)
+ shlibpath_overrides_runpath=yes
+ ;;
+ esac
+ else
+ shlibpath_overrides_runpath=yes
+ fi
+ ;;
+
+os2*)
+ libname_spec='$name'
+ shrext_cmds=".dll"
+ need_lib_prefix=no
+ library_names_spec='$libname${shared_ext} $libname.a'
+ dynamic_linker='OS/2 ld.exe'
+ shlibpath_var=LIBPATH
+ ;;
+
+osf3* | osf4* | osf5*)
+ version_type=osf
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+ sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+ ;;
+
+sco3.2v5*)
+ version_type=osf
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+solaris*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ # ldd complains unless libraries are executable
+ postinstall_cmds='chmod +x $lib'
+ ;;
+
+sunos4*)
+ version_type=sunos
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ if test "$with_gnu_ld" = yes; then
+ need_lib_prefix=no
+ fi
+ need_version=yes
+ ;;
+
+sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_vendor in
+ sni)
+ shlibpath_overrides_runpath=no
+ need_lib_prefix=no
+ export_dynamic_flag_spec='${wl}-Blargedynsym'
+ runpath_var=LD_RUN_PATH
+ ;;
+ siemens)
+ need_lib_prefix=no
+ ;;
+ motorola)
+ need_lib_prefix=no
+ need_version=no
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+ ;;
+ esac
+ ;;
+
+sysv4*MP*)
+ if test -d /usr/nec ;then
+ version_type=linux
+ library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+ soname_spec='$libname${shared_ext}.$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ fi
+ ;;
+
+uts4*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+*)
+ dynamic_linker=no
+ ;;
+esac
+AC_MSG_RESULT([$dynamic_linker])
+test "$dynamic_linker" = no && can_build_shared=no
+])# AC_LIBTOOL_SYS_DYNAMIC_LINKER
+
+
+# _LT_AC_TAGCONFIG
+# ----------------
+AC_DEFUN([_LT_AC_TAGCONFIG],
+[AC_ARG_WITH([tags],
+ [AC_HELP_STRING([--with-tags@<:@=TAGS@:>@],
+ [include additional configurations @<:@automatic@:>@])],
+ [tagnames="$withval"])
+
+if test -f "$ltmain" && test -n "$tagnames"; then
+ if test ! -f "${ofile}"; then
+ AC_MSG_WARN([output file `$ofile' does not exist])
+ fi
+
+ if test -z "$LTCC"; then
+ eval "`$SHELL ${ofile} --config | grep '^LTCC='`"
+ if test -z "$LTCC"; then
+ AC_MSG_WARN([output file `$ofile' does not look like a libtool script])
+ else
+ AC_MSG_WARN([using `LTCC=$LTCC', extracted from `$ofile'])
+ fi
+ fi
+
+ # Extract list of available tagged configurations in $ofile.
+ # Note that this assumes the entire list is on one line.
+ available_tags=`grep "^available_tags=" "${ofile}" | $SED -e 's/available_tags=\(.*$\)/\1/' -e 's/\"//g'`
+
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for tagname in $tagnames; do
+ IFS="$lt_save_ifs"
+ # Check whether tagname contains only valid characters
+ case `$echo "X$tagname" | $Xsed -e 's:[[-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890,/]]::g'` in
+ "") ;;
+ *) AC_MSG_ERROR([invalid tag name: $tagname])
+ ;;
+ esac
+
+ if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "${ofile}" > /dev/null
+ then
+ AC_MSG_ERROR([tag name \"$tagname\" already exists])
+ fi
+
+ # Update the list of available tags.
+ if test -n "$tagname"; then
+ echo appending configuration tag \"$tagname\" to $ofile
+
+ case $tagname in
+ CXX)
+ if test -n "$CXX" && test "X$CXX" != "Xno"; then
+ AC_LIBTOOL_LANG_CXX_CONFIG
+ else
+ tagname=""
+ fi
+ ;;
+
+ F77)
+ if test -n "$F77" && test "X$F77" != "Xno"; then
+ AC_LIBTOOL_LANG_F77_CONFIG
+ else
+ tagname=""
+ fi
+ ;;
+
+ GCJ)
+ if test -n "$GCJ" && test "X$GCJ" != "Xno"; then
+ AC_LIBTOOL_LANG_GCJ_CONFIG
+ else
+ tagname=""
+ fi
+ ;;
+
+ RC)
+ AC_LIBTOOL_LANG_RC_CONFIG
+ ;;
+
+ *)
+ AC_MSG_ERROR([Unsupported tag name: $tagname])
+ ;;
+ esac
+
+ # Append the new tag name to the list of available tags.
+ if test -n "$tagname" ; then
+ available_tags="$available_tags $tagname"
+ fi
+ fi
+ done
+ IFS="$lt_save_ifs"
+
+ # Now substitute the updated list of available tags.
+ if eval "sed -e 's/^available_tags=.*\$/available_tags=\"$available_tags\"/' \"$ofile\" > \"${ofile}T\""; then
+ mv "${ofile}T" "$ofile"
+ chmod +x "$ofile"
+ else
+ rm -f "${ofile}T"
+ AC_MSG_ERROR([unable to update list of available tagged configurations.])
+ fi
+fi
+])# _LT_AC_TAGCONFIG
+
+
+# AC_LIBTOOL_DLOPEN
+# -----------------
+# enable checks for dlopen support
+AC_DEFUN([AC_LIBTOOL_DLOPEN],
+ [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])
+])# AC_LIBTOOL_DLOPEN
+
+
+# AC_LIBTOOL_WIN32_DLL
+# --------------------
+# declare package support for building win32 dll's
+AC_DEFUN([AC_LIBTOOL_WIN32_DLL],
+[AC_BEFORE([$0], [AC_LIBTOOL_SETUP])
+])# AC_LIBTOOL_WIN32_DLL
+
+
+# AC_ENABLE_SHARED([DEFAULT])
+# ---------------------------
+# implement the --enable-shared flag
+# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
+AC_DEFUN([AC_ENABLE_SHARED],
+[define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl
+AC_ARG_ENABLE([shared],
+ [AC_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
+ [build shared libraries @<:@default=]AC_ENABLE_SHARED_DEFAULT[@:>@])],
+ [p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_shared=yes ;;
+ no) enable_shared=no ;;
+ *)
+ enable_shared=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_shared=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac],
+ [enable_shared=]AC_ENABLE_SHARED_DEFAULT)
+])# AC_ENABLE_SHARED
+
+
+# AC_DISABLE_SHARED
+# -----------------
+#- set the default shared flag to --disable-shared
+AC_DEFUN([AC_DISABLE_SHARED],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+AC_ENABLE_SHARED(no)
+])# AC_DISABLE_SHARED
+
+
+# AC_ENABLE_STATIC([DEFAULT])
+# ---------------------------
+# implement the --enable-static flag
+# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
+AC_DEFUN([AC_ENABLE_STATIC],
+[define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl
+AC_ARG_ENABLE([static],
+ [AC_HELP_STRING([--enable-static@<:@=PKGS@:>@],
+ [build static libraries @<:@default=]AC_ENABLE_STATIC_DEFAULT[@:>@])],
+ [p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_static=yes ;;
+ no) enable_static=no ;;
+ *)
+ enable_static=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_static=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac],
+ [enable_static=]AC_ENABLE_STATIC_DEFAULT)
+])# AC_ENABLE_STATIC
+
+
+# AC_DISABLE_STATIC
+# -----------------
+# set the default static flag to --disable-static
+AC_DEFUN([AC_DISABLE_STATIC],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+AC_ENABLE_STATIC(no)
+])# AC_DISABLE_STATIC
+
+
+# AC_ENABLE_FAST_INSTALL([DEFAULT])
+# ---------------------------------
+# implement the --enable-fast-install flag
+# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
+AC_DEFUN([AC_ENABLE_FAST_INSTALL],
+[define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl
+AC_ARG_ENABLE([fast-install],
+ [AC_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
+ [optimize for fast installation @<:@default=]AC_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
+ [p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_fast_install=yes ;;
+ no) enable_fast_install=no ;;
+ *)
+ enable_fast_install=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_fast_install=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac],
+ [enable_fast_install=]AC_ENABLE_FAST_INSTALL_DEFAULT)
+])# AC_ENABLE_FAST_INSTALL
+
+
+# AC_DISABLE_FAST_INSTALL
+# -----------------------
+# set the default to --disable-fast-install
+AC_DEFUN([AC_DISABLE_FAST_INSTALL],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+AC_ENABLE_FAST_INSTALL(no)
+])# AC_DISABLE_FAST_INSTALL
+
+
+# AC_LIBTOOL_PICMODE([MODE])
+# --------------------------
+# implement the --with-pic flag
+# MODE is either `yes' or `no'. If omitted, it defaults to `both'.
+AC_DEFUN([AC_LIBTOOL_PICMODE],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+pic_mode=ifelse($#,1,$1,default)
+])# AC_LIBTOOL_PICMODE
+
+
+# AC_PROG_EGREP
+# -------------
+# This is predefined starting with Autoconf 2.54, so this conditional
+# definition can be removed once we require Autoconf 2.54 or later.
+m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP],
+[AC_CACHE_CHECK([for egrep], [ac_cv_prog_egrep],
+ [if echo a | (grep -E '(a|b)') >/dev/null 2>&1
+ then ac_cv_prog_egrep='grep -E'
+ else ac_cv_prog_egrep='egrep'
+ fi])
+ EGREP=$ac_cv_prog_egrep
+ AC_SUBST([EGREP])
+])])
+
+
+# AC_PATH_TOOL_PREFIX
+# -------------------
+# find a file program which can recognise shared library
+AC_DEFUN([AC_PATH_TOOL_PREFIX],
+[AC_REQUIRE([AC_PROG_EGREP])dnl
+AC_MSG_CHECKING([for $1])
+AC_CACHE_VAL(lt_cv_path_MAGIC_CMD,
+[case $MAGIC_CMD in
+[[\\/*] | ?:[\\/]*])
+ lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+ ;;
+*)
+ lt_save_MAGIC_CMD="$MAGIC_CMD"
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+dnl $ac_dummy forces splitting on constant user-supplied paths.
+dnl POSIX.2 word splitting is done only on the output of word expansions,
+dnl not every word. This closes a longstanding sh security hole.
+ ac_dummy="ifelse([$2], , $PATH, [$2])"
+ for ac_dir in $ac_dummy; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$1; then
+ lt_cv_path_MAGIC_CMD="$ac_dir/$1"
+ if test -n "$file_magic_test_file"; then
+ case $deplibs_check_method in
+ "file_magic "*)
+ file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`"
+ MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+ if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ :
+ else
+ cat <<EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such. This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem. Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool at gnu.org
+
+EOF
+ fi ;;
+ esac
+ fi
+ break
+ fi
+ done
+ IFS="$lt_save_ifs"
+ MAGIC_CMD="$lt_save_MAGIC_CMD"
+ ;;
+esac])
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+ AC_MSG_RESULT($MAGIC_CMD)
+else
+ AC_MSG_RESULT(no)
+fi
+])# AC_PATH_TOOL_PREFIX
+
+
+# AC_PATH_MAGIC
+# -------------
+# find a file program which can recognise a shared library
+AC_DEFUN([AC_PATH_MAGIC],
+[AC_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH)
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+ if test -n "$ac_tool_prefix"; then
+ AC_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH)
+ else
+ MAGIC_CMD=:
+ fi
+fi
+])# AC_PATH_MAGIC
+
+
+# AC_PROG_LD
+# ----------
+# find the pathname to the GNU or non-GNU linker
+AC_DEFUN([AC_PROG_LD],
+[AC_ARG_WITH([gnu-ld],
+ [AC_HELP_STRING([--with-gnu-ld],
+ [assume the C compiler uses GNU ld @<:@default=no@:>@])],
+ [test "$withval" = no || with_gnu_ld=yes],
+ [with_gnu_ld=no])
+AC_REQUIRE([LT_AC_PROG_SED])dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+ac_prog=ld
+if test "$GCC" = yes; then
+ # Check if gcc -print-prog-name=ld gives a path.
+ AC_MSG_CHECKING([for ld used by $CC])
+ case $host in
+ *-*-mingw*)
+ # gcc leaves a trailing carriage return which upsets mingw
+ ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+ *)
+ ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+ esac
+ case $ac_prog in
+ # Accept absolute paths.
+ [[\\/]]* | ?:[[\\/]]*)
+ re_direlt='/[[^/]][[^/]]*/\.\./'
+ # Canonicalize the pathname of ld
+ ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'`
+ while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do
+ ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"`
+ done
+ test -z "$LD" && LD="$ac_prog"
+ ;;
+ "")
+ # If it fails, then pretend we aren't using GCC.
+ ac_prog=ld
+ ;;
+ *)
+ # If it is relative, then search for the first ld in PATH.
+ with_gnu_ld=unknown
+ ;;
+ esac
+elif test "$with_gnu_ld" = yes; then
+ AC_MSG_CHECKING([for GNU ld])
+else
+ AC_MSG_CHECKING([for non-GNU ld])
+fi
+AC_CACHE_VAL(lt_cv_path_LD,
+[if test -z "$LD"; then
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+ lt_cv_path_LD="$ac_dir/$ac_prog"
+ # Check to see if the program is GNU ld. I'd rather use --version,
+ # but apparently some GNU ld's only accept -v.
+ # Break only if it was the GNU/non-GNU ld that we prefer.
+ case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+ *GNU* | *'with BFD'*)
+ test "$with_gnu_ld" != no && break
+ ;;
+ *)
+ test "$with_gnu_ld" != yes && break
+ ;;
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+else
+ lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi])
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+ AC_MSG_RESULT($LD)
+else
+ AC_MSG_RESULT(no)
+fi
+test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
+AC_PROG_LD_GNU
+])# AC_PROG_LD
+
+
+# AC_PROG_LD_GNU
+# --------------
+AC_DEFUN([AC_PROG_LD_GNU],
+[AC_REQUIRE([AC_PROG_EGREP])dnl
+AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
+[# I'd rather use --version here, but apparently some GNU ld's only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+ lt_cv_prog_gnu_ld=yes
+ ;;
+*)
+ lt_cv_prog_gnu_ld=no
+ ;;
+esac])
+with_gnu_ld=$lt_cv_prog_gnu_ld
+])# AC_PROG_LD_GNU
+
+
+# AC_PROG_LD_RELOAD_FLAG
+# ----------------------
+# find reload flag for linker
+# -- PORTME Some linkers may need a different reload flag.
+AC_DEFUN([AC_PROG_LD_RELOAD_FLAG],
+[AC_CACHE_CHECK([for $LD option to reload object files],
+ lt_cv_ld_reload_flag,
+ [lt_cv_ld_reload_flag='-r'])
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+])# AC_PROG_LD_RELOAD_FLAG
+
+
+# AC_DEPLIBS_CHECK_METHOD
+# -----------------------
+# how to check for library dependencies
+# -- PORTME fill in with the dynamic library characteristics
+AC_DEFUN([AC_DEPLIBS_CHECK_METHOD],
+[AC_CACHE_CHECK([how to recognise dependent libraries],
+lt_cv_deplibs_check_method,
+[lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# `unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# which responds to the $file_magic_cmd with a given extended regex.
+# If you have `file' or equivalent on your system and you're not sure
+# whether `pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix4* | aix5*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+beos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+bsdi4*)
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)'
+ lt_cv_file_magic_cmd='/usr/bin/file -L'
+ lt_cv_file_magic_test_file=/shlib/libc.so
+ ;;
+
+cygwin*)
+ # func_win32_libid is a shell function defined in ltmain.sh
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ ;;
+
+mingw* | pw32*)
+ # Base MSYS/MinGW do not provide the 'file' command needed by
+ # func_win32_libid shell function, so use a weaker test based on 'objdump'.
+ lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?'
+ lt_cv_file_magic_cmd='$OBJDUMP -f'
+ ;;
+
+darwin* | rhapsody*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+freebsd* | kfreebsd*-gnu)
+ if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then
+ case $host_cpu in
+ i*86 )
+ # Not sure whether the presence of OpenBSD here was a mistake.
+ # Let's accept both of them until this is cleared up.
+ lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD)/i[[3-9]]86 (compact )?demand paged shared library'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+ ;;
+ esac
+ else
+ lt_cv_deplibs_check_method=pass_all
+ fi
+ ;;
+
+gnu*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+hpux10.20* | hpux11*)
+ lt_cv_file_magic_cmd=/usr/bin/file
+ case "$host_cpu" in
+ ia64*)
+ lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64'
+ lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+ ;;
+ hppa*64*)
+ [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]']
+ lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+ ;;
+ *)
+ lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library'
+ lt_cv_file_magic_test_file=/usr/lib/libc.sl
+ ;;
+ esac
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $LD in
+ *-32|*"-32 ") libmagic=32-bit;;
+ *-n32|*"-n32 ") libmagic=N32;;
+ *-64|*"-64 ") libmagic=64-bit;;
+ *) libmagic=never-match;;
+ esac
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+# This must be Linux ELF.
+linux*)
+ case $host_cpu in
+ alpha*|hppa*|i*86|ia64*|m68*|mips*|powerpc*|sparc*|s390*|sh*|x86_64*)
+ lt_cv_deplibs_check_method=pass_all ;;
+ *)
+ # glibc up to 2.1.1 does not perform some relocations on ARM
+ # this will be overridden with pass_all, but let us keep it just in case
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' ;;
+ esac
+ lt_cv_file_magic_test_file=`echo /lib/libc.so* /lib/libc-*.so`
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+netbsd*)
+ if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$'
+ fi
+ ;;
+
+newos6*)
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=/usr/lib/libnls.so
+ ;;
+
+nto-qnx*)
+ lt_cv_deplibs_check_method=unknown
+ ;;
+
+openbsd*)
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB shared object'
+ else
+ lt_cv_deplibs_check_method='file_magic OpenBSD.* shared library'
+ fi
+ ;;
+
+osf3* | osf4* | osf5*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sco3.2v5*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+solaris*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ case $host_vendor in
+ motorola)
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]'
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+ ;;
+ ncr)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ sequent)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )'
+ ;;
+ sni)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib"
+ lt_cv_file_magic_test_file=/lib/libc.so
+ ;;
+ siemens)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ esac
+ ;;
+
+sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[[78]]* | unixware7* | sysv4*uw2*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+esac
+])
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+])# AC_DEPLIBS_CHECK_METHOD
+
+
+# AC_PROG_NM
+# ----------
+# find the pathname to a BSD-compatible name lister
+AC_DEFUN([AC_PROG_NM],
+[AC_CACHE_CHECK([for BSD-compatible nm], lt_cv_path_NM,
+[if test -n "$NM"; then
+ # Let the user override the test.
+ lt_cv_path_NM="$NM"
+else
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ tmp_nm="$ac_dir/${ac_tool_prefix}nm"
+ if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+ # Check to see if the nm accepts a BSD-compat flag.
+ # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+ # nm: unknown option "B" ignored
+ # Tru64's nm complains that /dev/null is an invalid object file
+ case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+ */dev/null* | *'Invalid file or object type'*)
+ lt_cv_path_NM="$tmp_nm -B"
+ break
+ ;;
+ *)
+ case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+ */dev/null*)
+ lt_cv_path_NM="$tmp_nm -p"
+ break
+ ;;
+ *)
+ lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+ continue # so that we can try to find one that supports BSD flags
+ ;;
+ esac
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+ test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm
+fi])
+NM="$lt_cv_path_NM"
+])# AC_PROG_NM
+
+
+# AC_CHECK_LIBM
+# -------------
+# check for math library
+AC_DEFUN([AC_CHECK_LIBM],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+LIBM=
+case $host in
+*-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*)
+ # These system don't have libm, or don't need it
+ ;;
+*-ncr-sysv4.3*)
+ AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw")
+ AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm")
+ ;;
+*)
+ AC_CHECK_LIB(m, cos, LIBM="-lm")
+ ;;
+esac
+])# AC_CHECK_LIBM
+
+
+# AC_LIBLTDL_CONVENIENCE([DIRECTORY])
+# -----------------------------------
+# sets LIBLTDL to the link flags for the libltdl convenience library and
+# LTDLINCL to the include flags for the libltdl header and adds
+# --enable-ltdl-convenience to the configure arguments. Note that LIBLTDL
+# and LTDLINCL are not AC_SUBSTed, nor is AC_CONFIG_SUBDIRS called. If
+# DIRECTORY is not provided, it is assumed to be `libltdl'. LIBLTDL will
+# be prefixed with '${top_builddir}/' and LTDLINCL will be prefixed with
+# '${top_srcdir}/' (note the single quotes!). If your package is not
+# flat and you're not using automake, define top_builddir and
+# top_srcdir appropriately in the Makefiles.
+AC_DEFUN([AC_LIBLTDL_CONVENIENCE],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+ case $enable_ltdl_convenience in
+ no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;;
+ "") enable_ltdl_convenience=yes
+ ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;;
+ esac
+ LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdlc.la
+ LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl'])
+ # For backwards non-gettext consistent compatibility...
+ INCLTDL="$LTDLINCL"
+])# AC_LIBLTDL_CONVENIENCE
+
+
+# AC_LIBLTDL_INSTALLABLE([DIRECTORY])
+# -----------------------------------
+# sets LIBLTDL to the link flags for the libltdl installable library and
+# LTDLINCL to the include flags for the libltdl header and adds
+# --enable-ltdl-install to the configure arguments. Note that LIBLTDL
+# and LTDLINCL are not AC_SUBSTed, nor is AC_CONFIG_SUBDIRS called. If
+# DIRECTORY is not provided and an installed libltdl is not found, it is
+# assumed to be `libltdl'. LIBLTDL will be prefixed with '${top_builddir}/'
+# and LTDLINCL will be prefixed with '${top_srcdir}/' (note the single
+# quotes!). If your package is not flat and you're not using automake,
+# define top_builddir and top_srcdir appropriately in the Makefiles.
+# In the future, this macro may have to be called after AC_PROG_LIBTOOL.
+AC_DEFUN([AC_LIBLTDL_INSTALLABLE],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+ AC_CHECK_LIB(ltdl, lt_dlinit,
+ [test x"$enable_ltdl_install" != xyes && enable_ltdl_install=no],
+ [if test x"$enable_ltdl_install" = xno; then
+ AC_MSG_WARN([libltdl not installed, but installation disabled])
+ else
+ enable_ltdl_install=yes
+ fi
+ ])
+ if test x"$enable_ltdl_install" = x"yes"; then
+ ac_configure_args="$ac_configure_args --enable-ltdl-install"
+ LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdl.la
+ LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl'])
+ else
+ ac_configure_args="$ac_configure_args --enable-ltdl-install=no"
+ LIBLTDL="-lltdl"
+ LTDLINCL=
+ fi
+ # For backwards non-gettext consistent compatibility...
+ INCLTDL="$LTDLINCL"
+])# AC_LIBLTDL_INSTALLABLE
+
+
+# AC_LIBTOOL_CXX
+# --------------
+# enable support for C++ libraries
+AC_DEFUN([AC_LIBTOOL_CXX],
+[AC_REQUIRE([_LT_AC_LANG_CXX])
+])# AC_LIBTOOL_CXX
+
+
+# _LT_AC_LANG_CXX
+# ---------------
+AC_DEFUN([_LT_AC_LANG_CXX],
+[AC_REQUIRE([AC_PROG_CXX])
+AC_REQUIRE([AC_PROG_CXXCPP])
+_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}CXX])
+])# _LT_AC_LANG_CXX
+
+
+# AC_LIBTOOL_F77
+# --------------
+# enable support for Fortran 77 libraries
+AC_DEFUN([AC_LIBTOOL_F77],
+[AC_REQUIRE([_LT_AC_LANG_F77])
+])# AC_LIBTOOL_F77
+
+
+# _LT_AC_LANG_F77
+# ---------------
+AC_DEFUN([_LT_AC_LANG_F77],
+[AC_REQUIRE([AC_PROG_F77])
+_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}F77])
+])# _LT_AC_LANG_F77
+
+
+# AC_LIBTOOL_GCJ
+# --------------
+# enable support for GCJ libraries
+AC_DEFUN([AC_LIBTOOL_GCJ],
+[AC_REQUIRE([_LT_AC_LANG_GCJ])
+])# AC_LIBTOOL_GCJ
+
+
+# _LT_AC_LANG_GCJ
+# ---------------
+AC_DEFUN([_LT_AC_LANG_GCJ],
+[AC_PROVIDE_IFELSE([AC_PROG_GCJ],[],
+ [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],[],
+ [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ],[],
+ [ifdef([AC_PROG_GCJ],[AC_REQUIRE([AC_PROG_GCJ])],
+ [ifdef([A][M_PROG_GCJ],[AC_REQUIRE([A][M_PROG_GCJ])],
+ [AC_REQUIRE([A][C_PROG_GCJ_OR_A][M_PROG_GCJ])])])])])])
+_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}GCJ])
+])# _LT_AC_LANG_GCJ
+
+
+# AC_LIBTOOL_RC
+# --------------
+# enable support for Windows resource files
+AC_DEFUN([AC_LIBTOOL_RC],
+[AC_REQUIRE([LT_AC_PROG_RC])
+_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}RC])
+])# AC_LIBTOOL_RC
+
+
+# AC_LIBTOOL_LANG_C_CONFIG
+# ------------------------
+# Ensure that the configuration vars for the C compiler are
+# suitably defined. Those variables are subsequently used by
+# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG], [_LT_AC_LANG_C_CONFIG])
+AC_DEFUN([_LT_AC_LANG_C_CONFIG],
+[lt_save_CC="$CC"
+AC_LANG_PUSH(C)
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+_LT_AC_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;\n"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}\n'
+
+_LT_AC_SYS_COMPILER
+
+#
+# Check for any special shared library compilation flags.
+#
+_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)=
+if test "$GCC" = no; then
+ case $host_os in
+ sco3.2v5*)
+ _LT_AC_TAGVAR(lt_prog_cc_shlib, $1)='-belf'
+ ;;
+ esac
+fi
+if test -n "$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)"; then
+ AC_MSG_WARN([`$CC' requires `$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)' to build shared libraries])
+ if echo "$old_CC $old_CFLAGS " | grep "[[ ]]$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)[[ ]]" >/dev/null; then :
+ else
+ AC_MSG_WARN([add `$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)' to the CC or CFLAGS env variable and reconfigure])
+ _LT_AC_TAGVAR(lt_cv_prog_cc_can_build_shared, $1)=no
+ fi
+fi
+
+
+#
+# Check to make sure the static flag actually works.
+#
+AC_LIBTOOL_LINKER_OPTION([if $compiler static flag $_LT_AC_TAGVAR(lt_prog_compiler_static, $1) works],
+ _LT_AC_TAGVAR(lt_prog_compiler_static_works, $1),
+ $_LT_AC_TAGVAR(lt_prog_compiler_static, $1),
+ [],
+ [_LT_AC_TAGVAR(lt_prog_compiler_static, $1)=])
+
+
+AC_LIBTOOL_PROG_COMPILER_NO_RTTI($1)
+AC_LIBTOOL_PROG_COMPILER_PIC($1)
+AC_LIBTOOL_PROG_CC_C_O($1)
+AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1)
+AC_LIBTOOL_PROG_LD_SHLIBS($1)
+AC_LIBTOOL_SYS_DYNAMIC_LINKER($1)
+AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1)
+AC_LIBTOOL_SYS_LIB_STRIP
+AC_LIBTOOL_DLOPEN_SELF($1)
+
+# Report which librarie types wil actually be built
+AC_MSG_CHECKING([if libtool supports shared libraries])
+AC_MSG_RESULT([$can_build_shared])
+
+AC_MSG_CHECKING([whether to build shared libraries])
+test "$can_build_shared" = "no" && enable_shared=no
+
+# On AIX, shared libraries and static libraries use the same namespace, and
+# are all built from PIC.
+case "$host_os" in
+aix3*)
+ test "$enable_shared" = yes && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+
+aix4* | aix5*)
+ if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+ test "$enable_shared" = yes && enable_static=no
+ fi
+ ;;
+ darwin* | rhapsody*)
+ if test "$GCC" = yes; then
+ _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+ case "$host_os" in
+ rhapsody* | darwin1.[[012]])
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined suppress'
+ ;;
+ *) # Darwin 1.3 on
+ if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress'
+ else
+ case ${MACOSX_DEPLOYMENT_TARGET} in
+ 10.[[012]])
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress'
+ ;;
+ 10.*)
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined dynamic_lookup'
+ ;;
+ esac
+ fi
+ ;;
+ esac
+ output_verbose_link_cmd='echo'
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs$compiler_flags -install_name $rpath/$soname $verstring'
+ _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+ # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs$compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ _LT_AC_TAGVAR(hardcode_direct, $1)=no
+ _LT_AC_TAGVAR(hardcode_automatic, $1)=yes
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-all_load $convenience'
+ _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+ else
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+esac
+AC_MSG_RESULT([$enable_shared])
+
+AC_MSG_CHECKING([whether to build static libraries])
+# Make sure either enable_shared or enable_static is yes.
+test "$enable_shared" = yes || enable_static=yes
+AC_MSG_RESULT([$enable_static])
+
+AC_LIBTOOL_CONFIG($1)
+
+AC_LANG_POP
+CC="$lt_save_CC"
+])# AC_LIBTOOL_LANG_C_CONFIG
+
+
+# AC_LIBTOOL_LANG_CXX_CONFIG
+# --------------------------
+# Ensure that the configuration vars for the C compiler are
+# suitably defined. Those variables are subsequently used by
+# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG], [_LT_AC_LANG_CXX_CONFIG(CXX)])
+AC_DEFUN([_LT_AC_LANG_CXX_CONFIG],
+[AC_LANG_PUSH(C++)
+AC_REQUIRE([AC_PROG_CXX])
+AC_REQUIRE([AC_PROG_CXXCPP])
+
+_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_AC_TAGVAR(allow_undefined_flag, $1)=
+_LT_AC_TAGVAR(always_export_symbols, $1)=no
+_LT_AC_TAGVAR(archive_expsym_cmds, $1)=
+_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_AC_TAGVAR(hardcode_direct, $1)=no
+_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_AC_TAGVAR(hardcode_minus_L, $1)=no
+_LT_AC_TAGVAR(hardcode_automatic, $1)=no
+_LT_AC_TAGVAR(module_cmds, $1)=
+_LT_AC_TAGVAR(module_expsym_cmds, $1)=
+_LT_AC_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_AC_TAGVAR(no_undefined_flag, $1)=
+_LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Dependencies to place before and after the object being linked:
+_LT_AC_TAGVAR(predep_objects, $1)=
+_LT_AC_TAGVAR(postdep_objects, $1)=
+_LT_AC_TAGVAR(predeps, $1)=
+_LT_AC_TAGVAR(postdeps, $1)=
+_LT_AC_TAGVAR(compiler_lib_search_path, $1)=
+
+# Source file extension for C++ test sources.
+ac_ext=cc
+
+# Object file extension for compiled C++ test sources.
+objext=o
+_LT_AC_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;\n"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(int, char *[]) { return(0); }\n'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_AC_SYS_COMPILER
+
+# Allow CC to be a program name with arguments.
+lt_save_CC=$CC
+lt_save_LD=$LD
+lt_save_GCC=$GCC
+GCC=$GXX
+lt_save_with_gnu_ld=$with_gnu_ld
+lt_save_path_LD=$lt_cv_path_LD
+if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
+ lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
+else
+ unset lt_cv_prog_gnu_ld
+fi
+if test -n "${lt_cv_path_LDCXX+set}"; then
+ lt_cv_path_LD=$lt_cv_path_LDCXX
+else
+ unset lt_cv_path_LD
+fi
+test -z "${LDCXX+set}" || LD=$LDCXX
+CC=${CXX-"c++"}
+compiler=$CC
+_LT_AC_TAGVAR(compiler, $1)=$CC
+cc_basename=`$echo X"$compiler" | $Xsed -e 's%^.*/%%'`
+
+# We don't want -fno-exception wen compiling C++ code, so set the
+# no_builtin_flag separately
+if test "$GXX" = yes; then
+ _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
+else
+ _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+fi
+
+if test "$GXX" = yes; then
+ # Set up default GNU C++ configuration
+
+ AC_PROG_LD
+
+ # Check if GNU C++ uses GNU ld as the underlying linker, since the
+ # archiving commands below assume that GNU ld is being used.
+ if test "$with_gnu_ld" = yes; then
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
+ _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
+ # investigate it a little bit more. (MM)
+ wlarc='${wl}'
+
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if eval "`$CC -print-prog-name=ld` --help 2>&1" | \
+ grep 'no-whole-archive' > /dev/null; then
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+ fi
+ else
+ with_gnu_ld=no
+ wlarc=
+
+ # A generic and very simple default shared library creation
+ # command for GNU C++ for the case where it uses the native
+ # linker, instead of GNU ld. If possible, this setting should
+ # overridden to take advantage of the native linker features on
+ # the platform it is being used on.
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+ fi
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"'
+
+else
+ GXX=no
+ with_gnu_ld=no
+ wlarc=
+fi
+
+# PORTME: fill in a description of your system's C++ link characteristics
+AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+_LT_AC_TAGVAR(ld_shlibs, $1)=yes
+case $host_os in
+ aix3*)
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ aix4* | aix5*)
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=""
+ else
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # need to do runtime linking.
+ case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*)
+ for ld_flag in $LDFLAGS; do
+ case $ld_flag in
+ *-brtl*)
+ aix_use_runtimelinking=yes
+ break
+ ;;
+ esac
+ done
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ _LT_AC_TAGVAR(archive_cmds, $1)=''
+ _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+
+ if test "$GXX" = yes; then
+ case $host_os in aix4.[012]|aix4.[012].*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" && \
+ strings "$collect2name" | grep resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+ else
+ # We have old collect2
+ _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+ fi
+ esac
+ shared_flag='-shared'
+ else
+ # not using gcc
+ if test "$host_cpu" = ia64; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag='${wl}-G'
+ else
+ shared_flag='${wl}-bM:SRE'
+ fi
+ fi
+ fi
+
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to export.
+ _LT_AC_TAGVAR(always_export_symbols, $1)=yes
+ if test "$aix_use_runtimelinking" = yes; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok'
+ # Determine the default libpath from the value encoded in an empty executable.
+ _LT_AC_SYS_LIBPATH_AIX
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ else
+ if test "$host_cpu" = ia64; then
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an empty executable.
+ _LT_AC_SYS_LIBPATH_AIX
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+ # -bexpall does not export symbols beginning with underscore (_)
+ _LT_AC_TAGVAR(always_export_symbols, $1)=yes
+ # Exported symbols can be pulled into shared objects from archives
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=' '
+ _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes
+ # This is similar to how AIX traditionally builds it's shared libraries.
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ fi
+ fi
+ ;;
+ chorus*)
+ case $cc_basename in
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ cygwin* | mingw* | pw32*)
+ # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+ # as there is no search path for DLLs.
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_AC_TAGVAR(always_export_symbols, $1)=no
+ _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+
+ if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+ # If the export-symbols file already is a .def file (1st line
+ # is EXPORTS), use it as is; otherwise, prepend...
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+ else
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ darwin* | rhapsody*)
+ if test "$GXX" = yes; then
+ _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+ case "$host_os" in
+ rhapsody* | darwin1.[[012]])
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined suppress'
+ ;;
+ *) # Darwin 1.3 on
+ if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress'
+ else
+ case ${MACOSX_DEPLOYMENT_TARGET} in
+ 10.[[012]])
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress'
+ ;;
+ 10.*)
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined dynamic_lookup'
+ ;;
+ esac
+ fi
+ ;;
+ esac
+ lt_int_apple_cc_single_mod=no
+ output_verbose_link_cmd='echo'
+ if $CC -dumpspecs 2>&1 | grep 'single_module' >/dev/null ; then
+ lt_int_apple_cc_single_mod=yes
+ fi
+ if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+ else
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+ fi
+ _LT_AC_TAGVAR(module_cmds, $1)='$CC ${wl}-bind_at_load $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+
+ # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's
+ if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ else
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ fi
+ _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ _LT_AC_TAGVAR(hardcode_direct, $1)=no
+ _LT_AC_TAGVAR(hardcode_automatic, $1)=yes
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-all_load $convenience'
+ _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+ else
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ dgux*)
+ case $cc_basename in
+ ec++)
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ ghcx)
+ # Green Hills C++ Compiler
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+ freebsd[12]*)
+ # C++ shared libraries reported to be fairly broken before switch to ELF
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ freebsd-elf*)
+ _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+ ;;
+ freebsd* | kfreebsd*-gnu)
+ # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
+ # conventions
+ _LT_AC_TAGVAR(ld_shlibs, $1)=yes
+ ;;
+ gnu*)
+ ;;
+ hpux9*)
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+ _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+ # but as the default
+ # location of the library.
+
+ case $cc_basename in
+ CC)
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ aCC)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "[-]L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+ ;;
+ *)
+ if test "$GXX" = yes; then
+ _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ else
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+ hpux10*|hpux11*)
+ if test $with_gnu_ld = no; then
+ case "$host_cpu" in
+ hppa*64*)
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir'
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+ ;;
+ ia64*)
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ ;;
+ *)
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ ;;
+ esac
+ fi
+ case "$host_cpu" in
+ hppa*64*)
+ _LT_AC_TAGVAR(hardcode_direct, $1)=no
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+ ia64*)
+ _LT_AC_TAGVAR(hardcode_direct, $1)=no
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+ # but as the default
+ # location of the library.
+ ;;
+ *)
+ _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+ _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+ # but as the default
+ # location of the library.
+ ;;
+ esac
+
+ case $cc_basename in
+ CC)
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ aCC)
+ case "$host_cpu" in
+ hppa*64*|ia64*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs'
+ ;;
+ *)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ esac
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+ ;;
+ *)
+ if test "$GXX" = yes; then
+ if test $with_gnu_ld = no; then
+ case "$host_cpu" in
+ ia64*|hppa*64*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs'
+ ;;
+ *)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ esac
+ fi
+ else
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+ irix5* | irix6*)
+ case $cc_basename in
+ CC)
+ # SGI C++
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib'
+
+ # Archives containing C++ object files must be created using
+ # "CC -ar", where "CC" is the IRIX C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs'
+ ;;
+ *)
+ if test "$GXX" = yes; then
+ if test "$with_gnu_ld" = no; then
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib'
+ else
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` -o $lib'
+ fi
+ fi
+ _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+ esac
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+ ;;
+ linux*)
+ case $cc_basename in
+ KCC)
+ # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+ # KCC will only create a shared library if the output file
+ # ends with ".so" (or ".sl" for HP-UX), so rename the library
+ # to its proper name (with version) after linking.
+ _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib'
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | grep "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath,$libdir'
+ _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+
+ # Archives containing C++ object files must be created using
+ # "CC -Bstatic", where "CC" is the KAI C++ compiler.
+ _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
+ ;;
+ icpc)
+ # Intel C++
+ with_gnu_ld=yes
+ _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+ ;;
+ cxx)
+ # Compaq C++
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
+
+ runpath_var=LD_RUN_PATH
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+ ;;
+ esac
+ ;;
+ lynxos*)
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ m88k*)
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ mvs*)
+ case $cc_basename in
+ cxx)
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+ netbsd*)
+ if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
+ wlarc=
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ fi
+ # Workaround some broken pre-1.5 toolchains
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
+ ;;
+ osf3*)
+ case $cc_basename in
+ KCC)
+ # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+ # KCC will only create a shared library if the output file
+ # ends with ".so" (or ".sl" for HP-UX), so rename the library
+ # to its proper name (with version) after linking.
+ _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Archives containing C++ object files must be created using
+ # "CC -Bstatic", where "CC" is the KAI C++ compiler.
+ _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
+
+ ;;
+ RCC)
+ # Rational C++ 2.4.1
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ cxx)
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && echo ${wl}-set_version $verstring` -update_registry ${objdir}/so_locations -o $lib'
+
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+ ;;
+ *)
+ if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib'
+
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"'
+
+ else
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+ osf4* | osf5*)
+ case $cc_basename in
+ KCC)
+ # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+ # KCC will only create a shared library if the output file
+ # ends with ".so" (or ".sl" for HP-UX), so rename the library
+ # to its proper name (with version) after linking.
+ _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Archives containing C++ object files must be created using
+ # the KAI C++ compiler.
+ _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs'
+ ;;
+ RCC)
+ # Rational C++ 2.4.1
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ cxx)
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
+ echo "-hidden">> $lib.exp~
+ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname -Wl,-input -Wl,$lib.exp `test -n "$verstring" && echo -set_version $verstring` -update_registry $objdir/so_locations -o $lib~
+ $rm $lib.exp'
+
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+ ;;
+ *)
+ if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib'
+
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"'
+
+ else
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+ psos*)
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ sco*)
+ _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+ case $cc_basename in
+ CC)
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+ sunos4*)
+ case $cc_basename in
+ CC)
+ # Sun C++ 4.x
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ lcc)
+ # Lucid
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+ solaris*)
+ case $cc_basename in
+ CC)
+ # Sun C++ 4.2, 5.x and Centerline C++
+ _LT_AC_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -nolib -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $CC -G${allow_undefined_flag} -nolib ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
+
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ case $host_os in
+ solaris2.[0-5] | solaris2.[0-5].*) ;;
+ *)
+ # The C++ compiler is used as linker so we must use $wl
+ # flag to pass the commands to the underlying system
+ # linker.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+ ;;
+ esac
+ _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep "\-[[LR]]"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+
+ # Archives containing C++ object files must be created using
+ # "CC -xar", where "CC" is the Sun C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+ ;;
+ gcx)
+ # Green Hills C++ Compiler
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+
+ # The C++ compiler must be used to create the archive.
+ _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
+ ;;
+ *)
+ # GNU C++ compiler with Solaris linker
+ if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+ _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs'
+ if $CC --version | grep -v '^2\.7' > /dev/null; then
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd="$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\""
+ else
+ # g++ 2.7 appears to require `-G' NOT `-shared' on this
+ # platform.
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd="$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\""
+ fi
+
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir'
+ fi
+ ;;
+ esac
+ ;;
+ sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[[78]]* | unixware7*)
+ _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+ ;;
+ tandem*)
+ case $cc_basename in
+ NCC)
+ # NonStop-UX NCC 3.20
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+ vxworks*)
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+esac
+AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)])
+test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+_LT_AC_TAGVAR(GCC, $1)="$GXX"
+_LT_AC_TAGVAR(LD, $1)="$LD"
+
+AC_LIBTOOL_POSTDEP_PREDEP($1)
+AC_LIBTOOL_PROG_COMPILER_PIC($1)
+AC_LIBTOOL_PROG_CC_C_O($1)
+AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1)
+AC_LIBTOOL_PROG_LD_SHLIBS($1)
+AC_LIBTOOL_SYS_DYNAMIC_LINKER($1)
+AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1)
+AC_LIBTOOL_SYS_LIB_STRIP
+AC_LIBTOOL_DLOPEN_SELF($1)
+
+AC_LIBTOOL_CONFIG($1)
+
+AC_LANG_POP
+CC=$lt_save_CC
+LDCXX=$LD
+LD=$lt_save_LD
+GCC=$lt_save_GCC
+with_gnu_ldcxx=$with_gnu_ld
+with_gnu_ld=$lt_save_with_gnu_ld
+lt_cv_path_LDCXX=$lt_cv_path_LD
+lt_cv_path_LD=$lt_save_path_LD
+lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
+lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
+])# AC_LIBTOOL_LANG_CXX_CONFIG
+
+# AC_LIBTOOL_POSTDEP_PREDEP([TAGNAME])
+# ------------------------
+# Figure out "hidden" library dependencies from verbose
+# compiler output when linking a shared library.
+# Parse the compiler output and extract the necessary
+# objects, libraries and library flags.
+AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP],[
+dnl we can't use the lt_simple_compile_test_code here,
+dnl because it contains code intended for an executable,
+dnl not a library. It's possible we should let each
+dnl tag define a new lt_????_link_test_code variable,
+dnl but it's only used here...
+ifelse([$1],[],[cat > conftest.$ac_ext <<EOF
+int a;
+void foo (void) { a = 0; }
+EOF
+],[$1],[CXX],[cat > conftest.$ac_ext <<EOF
+class Foo
+{
+public:
+ Foo (void) { a = 0; }
+private:
+ int a;
+};
+EOF
+],[$1],[F77],[cat > conftest.$ac_ext <<EOF
+ subroutine foo
+ implicit none
+ integer*4 a
+ a=0
+ return
+ end
+EOF
+],[$1],[GCJ],[cat > conftest.$ac_ext <<EOF
+public class foo {
+ private int a;
+ public void bar (void) {
+ a = 0;
+ }
+};
+EOF
+])
+dnl Parse the compiler output and extract the necessary
+dnl objects, libraries and library flags.
+if AC_TRY_EVAL(ac_compile); then
+ # Parse the compiler output and extract the necessary
+ # objects, libraries and library flags.
+
+ # Sentinel used to keep track of whether or not we are before
+ # the conftest object file.
+ pre_test_object_deps_done=no
+
+ # The `*' in the case matches for architectures that use `case' in
+ # $output_verbose_cmd can trigger glob expansion during the loop
+ # eval without this substitution.
+ output_verbose_link_cmd="`$echo \"X$output_verbose_link_cmd\" | $Xsed -e \"$no_glob_subst\"`"
+
+ for p in `eval $output_verbose_link_cmd`; do
+ case $p in
+
+ -L* | -R* | -l*)
+ # Some compilers place space between "-{L,R}" and the path.
+ # Remove the space.
+ if test $p = "-L" \
+ || test $p = "-R"; then
+ prev=$p
+ continue
+ else
+ prev=
+ fi
+
+ if test "$pre_test_object_deps_done" = no; then
+ case $p in
+ -L* | -R*)
+ # Internal compiler library paths should come after those
+ # provided the user. The postdeps already come after the
+ # user supplied libs so there is no need to process them.
+ if test -z "$_LT_AC_TAGVAR(compiler_lib_search_path, $1)"; then
+ _LT_AC_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}"
+ else
+ _LT_AC_TAGVAR(compiler_lib_search_path, $1)="${_LT_AC_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}"
+ fi
+ ;;
+ # The "-l" case would never come before the object being
+ # linked, so don't bother handling this case.
+ esac
+ else
+ if test -z "$_LT_AC_TAGVAR(postdeps, $1)"; then
+ _LT_AC_TAGVAR(postdeps, $1)="${prev}${p}"
+ else
+ _LT_AC_TAGVAR(postdeps, $1)="${_LT_AC_TAGVAR(postdeps, $1)} ${prev}${p}"
+ fi
+ fi
+ ;;
+
+ *.$objext)
+ # This assumes that the test object file only shows up
+ # once in the compiler output.
+ if test "$p" = "conftest.$objext"; then
+ pre_test_object_deps_done=yes
+ continue
+ fi
+
+ if test "$pre_test_object_deps_done" = no; then
+ if test -z "$_LT_AC_TAGVAR(predep_objects, $1)"; then
+ _LT_AC_TAGVAR(predep_objects, $1)="$p"
+ else
+ _LT_AC_TAGVAR(predep_objects, $1)="$_LT_AC_TAGVAR(predep_objects, $1) $p"
+ fi
+ else
+ if test -z "$_LT_AC_TAGVAR(postdep_objects, $1)"; then
+ _LT_AC_TAGVAR(postdep_objects, $1)="$p"
+ else
+ _LT_AC_TAGVAR(postdep_objects, $1)="$_LT_AC_TAGVAR(postdep_objects, $1) $p"
+ fi
+ fi
+ ;;
+
+ *) ;; # Ignore the rest.
+
+ esac
+ done
+
+ # Clean up.
+ rm -f a.out a.exe
+else
+ echo "libtool.m4: error: problem compiling $1 test program"
+fi
+
+$rm -f confest.$objext
+
+case " $_LT_AC_TAGVAR(postdeps, $1) " in
+*" -lc "*) _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no ;;
+esac
+])# AC_LIBTOOL_POSTDEP_PREDEP
+
+# AC_LIBTOOL_LANG_F77_CONFIG
+# ------------------------
+# Ensure that the configuration vars for the C compiler are
+# suitably defined. Those variables are subsequently used by
+# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG], [_LT_AC_LANG_F77_CONFIG(F77)])
+AC_DEFUN([_LT_AC_LANG_F77_CONFIG],
+[AC_REQUIRE([AC_PROG_F77])
+AC_LANG_PUSH(Fortran 77)
+
+_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_AC_TAGVAR(allow_undefined_flag, $1)=
+_LT_AC_TAGVAR(always_export_symbols, $1)=no
+_LT_AC_TAGVAR(archive_expsym_cmds, $1)=
+_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_AC_TAGVAR(hardcode_direct, $1)=no
+_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_AC_TAGVAR(hardcode_minus_L, $1)=no
+_LT_AC_TAGVAR(hardcode_automatic, $1)=no
+_LT_AC_TAGVAR(module_cmds, $1)=
+_LT_AC_TAGVAR(module_expsym_cmds, $1)=
+_LT_AC_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_AC_TAGVAR(no_undefined_flag, $1)=
+_LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for f77 test sources.
+ac_ext=f
+
+# Object file extension for compiled f77 test sources.
+objext=o
+_LT_AC_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code=" subroutine t\n return\n end\n"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code=" program t\n end\n"
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_AC_SYS_COMPILER
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+CC=${F77-"f77"}
+compiler=$CC
+_LT_AC_TAGVAR(compiler, $1)=$CC
+cc_basename=`$echo X"$compiler" | $Xsed -e 's%^.*/%%'`
+
+AC_MSG_CHECKING([if libtool supports shared libraries])
+AC_MSG_RESULT([$can_build_shared])
+
+AC_MSG_CHECKING([whether to build shared libraries])
+test "$can_build_shared" = "no" && enable_shared=no
+
+# On AIX, shared libraries and static libraries use the same namespace, and
+# are all built from PIC.
+case "$host_os" in
+aix3*)
+ test "$enable_shared" = yes && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+aix4* | aix5*)
+ test "$enable_shared" = yes && enable_static=no
+ ;;
+esac
+AC_MSG_RESULT([$enable_shared])
+
+AC_MSG_CHECKING([whether to build static libraries])
+# Make sure either enable_shared or enable_static is yes.
+test "$enable_shared" = yes || enable_static=yes
+AC_MSG_RESULT([$enable_static])
+
+test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+_LT_AC_TAGVAR(GCC, $1)="$G77"
+_LT_AC_TAGVAR(LD, $1)="$LD"
+
+AC_LIBTOOL_PROG_COMPILER_PIC($1)
+AC_LIBTOOL_PROG_CC_C_O($1)
+AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1)
+AC_LIBTOOL_PROG_LD_SHLIBS($1)
+AC_LIBTOOL_SYS_DYNAMIC_LINKER($1)
+AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1)
+AC_LIBTOOL_SYS_LIB_STRIP
+
+
+AC_LIBTOOL_CONFIG($1)
+
+AC_LANG_POP
+CC="$lt_save_CC"
+])# AC_LIBTOOL_LANG_F77_CONFIG
+
+
+# AC_LIBTOOL_LANG_GCJ_CONFIG
+# --------------------------
+# Ensure that the configuration vars for the C compiler are
+# suitably defined. Those variables are subsequently used by
+# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG], [_LT_AC_LANG_GCJ_CONFIG(GCJ)])
+AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG],
+[AC_LANG_SAVE
+
+# Source file extension for Java test sources.
+ac_ext=java
+
+# Object file extension for compiled Java test sources.
+objext=o
+_LT_AC_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="class foo {}\n"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='public class conftest { public static void main(String[] argv) {}; }\n'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_AC_SYS_COMPILER
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+CC=${GCJ-"gcj"}
+compiler=$CC
+_LT_AC_TAGVAR(compiler, $1)=$CC
+
+# GCJ did not exist at the time GCC didn't implicitly link libc in.
+_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+
+AC_LIBTOOL_PROG_COMPILER_NO_RTTI($1)
+AC_LIBTOOL_PROG_COMPILER_PIC($1)
+AC_LIBTOOL_PROG_CC_C_O($1)
+AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1)
+AC_LIBTOOL_PROG_LD_SHLIBS($1)
+AC_LIBTOOL_SYS_DYNAMIC_LINKER($1)
+AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1)
+AC_LIBTOOL_SYS_LIB_STRIP
+AC_LIBTOOL_DLOPEN_SELF($1)
+
+AC_LIBTOOL_CONFIG($1)
+
+AC_LANG_RESTORE
+CC="$lt_save_CC"
+])# AC_LIBTOOL_LANG_GCJ_CONFIG
+
+
+# AC_LIBTOOL_LANG_RC_CONFIG
+# --------------------------
+# Ensure that the configuration vars for the Windows resource compiler are
+# suitably defined. Those variables are subsequently used by
+# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG], [_LT_AC_LANG_RC_CONFIG(RC)])
+AC_DEFUN([_LT_AC_LANG_RC_CONFIG],
+[AC_LANG_SAVE
+
+# Source file extension for RC test sources.
+ac_ext=rc
+
+# Object file extension for compiled RC test sources.
+objext=o
+_LT_AC_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }\n'
+
+# Code to be used in simple link tests
+lt_simple_link_test_code="$lt_simple_compile_test_code"
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_AC_SYS_COMPILER
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+CC=${RC-"windres"}
+compiler=$CC
+_LT_AC_TAGVAR(compiler, $1)=$CC
+_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+
+AC_LIBTOOL_CONFIG($1)
+
+AC_LANG_RESTORE
+CC="$lt_save_CC"
+])# AC_LIBTOOL_LANG_RC_CONFIG
+
+
+# AC_LIBTOOL_CONFIG([TAGNAME])
+# ----------------------------
+# If TAGNAME is not passed, then create an initial libtool script
+# with a default configuration from the untagged config vars. Otherwise
+# add code to config.status for appending the configuration named by
+# TAGNAME from the matching tagged config vars.
+AC_DEFUN([AC_LIBTOOL_CONFIG],
+[# The else clause should only fire when bootstrapping the
+# libtool distribution, otherwise you forgot to ship ltmain.sh
+# with your package, and you will get complaints that there are
+# no rules to generate ltmain.sh.
+if test -f "$ltmain"; then
+ # See if we are running on zsh, and set the options which allow our commands through
+ # without removal of \ escapes.
+ if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+ fi
+ # Now quote all the things that may contain metacharacters while being
+ # careful not to overquote the AC_SUBSTed values. We take copies of the
+ # variables and quote the copies for generation of the libtool script.
+ for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC NM \
+ SED SHELL STRIP \
+ libname_spec library_names_spec soname_spec extract_expsyms_cmds \
+ old_striplib striplib file_magic_cmd finish_cmds finish_eval \
+ deplibs_check_method reload_flag reload_cmds need_locks \
+ lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \
+ lt_cv_sys_global_symbol_to_c_name_address \
+ sys_lib_search_path_spec sys_lib_dlsearch_path_spec \
+ old_postinstall_cmds old_postuninstall_cmds \
+ _LT_AC_TAGVAR(compiler, $1) \
+ _LT_AC_TAGVAR(CC, $1) \
+ _LT_AC_TAGVAR(LD, $1) \
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1) \
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1) \
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1) \
+ _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) \
+ _LT_AC_TAGVAR(export_dynamic_flag_spec, $1) \
+ _LT_AC_TAGVAR(thread_safe_flag_spec, $1) \
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1) \
+ _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1) \
+ _LT_AC_TAGVAR(old_archive_cmds, $1) \
+ _LT_AC_TAGVAR(old_archive_from_new_cmds, $1) \
+ _LT_AC_TAGVAR(predep_objects, $1) \
+ _LT_AC_TAGVAR(postdep_objects, $1) \
+ _LT_AC_TAGVAR(predeps, $1) \
+ _LT_AC_TAGVAR(postdeps, $1) \
+ _LT_AC_TAGVAR(compiler_lib_search_path, $1) \
+ _LT_AC_TAGVAR(archive_cmds, $1) \
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1) \
+ _LT_AC_TAGVAR(postinstall_cmds, $1) \
+ _LT_AC_TAGVAR(postuninstall_cmds, $1) \
+ _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1) \
+ _LT_AC_TAGVAR(allow_undefined_flag, $1) \
+ _LT_AC_TAGVAR(no_undefined_flag, $1) \
+ _LT_AC_TAGVAR(export_symbols_cmds, $1) \
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) \
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1) \
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1) \
+ _LT_AC_TAGVAR(hardcode_automatic, $1) \
+ _LT_AC_TAGVAR(module_cmds, $1) \
+ _LT_AC_TAGVAR(module_expsym_cmds, $1) \
+ _LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1) \
+ _LT_AC_TAGVAR(exclude_expsyms, $1) \
+ _LT_AC_TAGVAR(include_expsyms, $1); do
+
+ case $var in
+ _LT_AC_TAGVAR(old_archive_cmds, $1) | \
+ _LT_AC_TAGVAR(old_archive_from_new_cmds, $1) | \
+ _LT_AC_TAGVAR(archive_cmds, $1) | \
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1) | \
+ _LT_AC_TAGVAR(module_cmds, $1) | \
+ _LT_AC_TAGVAR(module_expsym_cmds, $1) | \
+ _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1) | \
+ _LT_AC_TAGVAR(export_symbols_cmds, $1) | \
+ extract_expsyms_cmds | reload_cmds | finish_cmds | \
+ postinstall_cmds | postuninstall_cmds | \
+ old_postinstall_cmds | old_postuninstall_cmds | \
+ sys_lib_search_path_spec | sys_lib_dlsearch_path_spec)
+ # Double-quote double-evaled strings.
+ eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\""
+ ;;
+ *)
+ eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\""
+ ;;
+ esac
+ done
+
+ case $lt_echo in
+ *'\[$]0 --fallback-echo"')
+ lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\[$]0 --fallback-echo"[$]/[$]0 --fallback-echo"/'`
+ ;;
+ esac
+
+ifelse([$1], [],
+ [cfgfile="${ofile}T"
+ trap "$rm \"$cfgfile\"; exit 1" 1 2 15
+ $rm -f "$cfgfile"
+ AC_MSG_NOTICE([creating $ofile])],
+ [cfgfile="$ofile"])
+
+ cat <<__EOF__ >> "$cfgfile"
+ifelse([$1], [],
+[#! $SHELL
+
+# `$echo "$cfgfile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP)
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+#
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001
+# Free Software Foundation, Inc.
+#
+# This file is part of GNU Libtool:
+# Originally by Gordon Matzigkeit <gord at gnu.ai.mit.edu>, 1996
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# A sed program that does not truncate output.
+SED=$lt_SED
+
+# Sed that helps us avoid accidentally triggering echo(1) options like -n.
+Xsed="$SED -e s/^X//"
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+if test "X\${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi
+
+# The names of the tagged configurations supported by this script.
+available_tags=
+
+# ### BEGIN LIBTOOL CONFIG],
+[# ### BEGIN LIBTOOL TAG CONFIG: $tagname])
+
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+
+# Shell to use when invoking shell scripts.
+SHELL=$lt_SHELL
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)
+
+# Whether or not to disallow shared libs when runtime libs are static
+allow_libtool_libs_with_static_runtimes=$_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)
+
+# Whether or not to optimize for fast installation.
+fast_install=$enable_fast_install
+
+# The host system.
+host_alias=$host_alias
+host=$host
+
+# An echo program that does not interpret backslashes.
+echo=$lt_echo
+
+# The archiver.
+AR=$lt_AR
+AR_FLAGS=$lt_AR_FLAGS
+
+# A C compiler.
+LTCC=$lt_LTCC
+
+# A language-specific compiler.
+CC=$lt_[]_LT_AC_TAGVAR(compiler, $1)
+
+# Is the compiler the GNU C compiler?
+with_gcc=$_LT_AC_TAGVAR(GCC, $1)
+
+# An ERE matcher.
+EGREP=$lt_EGREP
+
+# The linker used to build libraries.
+LD=$lt_[]_LT_AC_TAGVAR(LD, $1)
+
+# Whether we need hard or soft links.
+LN_S=$lt_LN_S
+
+# A BSD-compatible nm program.
+NM=$lt_NM
+
+# A symbol stripping program
+STRIP=$lt_STRIP
+
+# Used to examine libraries when file_magic_cmd begins "file"
+MAGIC_CMD=$MAGIC_CMD
+
+# Used on cygwin: DLL creation program.
+DLLTOOL="$DLLTOOL"
+
+# Used on cygwin: object dumper.
+OBJDUMP="$OBJDUMP"
+
+# Used on cygwin: assembler.
+AS="$AS"
+
+# The name of the directory that contains temporary libtool files.
+objdir=$objdir
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag
+reload_cmds=$lt_reload_cmds
+
+# How to pass a linker flag through the compiler.
+wl=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)
+
+# Object file suffix (normally "o").
+objext="$ac_objext"
+
+# Old archive suffix (normally "a").
+libext="$libext"
+
+# Shared library suffix (normally ".so").
+shrext_cmds='$shrext_cmds'
+
+# Executable file suffix (normally "").
+exeext="$exeext"
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)
+pic_mode=$pic_mode
+
+# What is the maximum length of a command?
+max_cmd_len=$lt_cv_sys_max_cmd_len
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_[]_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)
+
+# Must we lock files when doing compilation ?
+need_locks=$lt_need_locks
+
+# Do we need the lib prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Whether dlopen is supported.
+dlopen_support=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_static, $1)
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_[]_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_[]_LT_AC_TAGVAR(whole_archive_flag_spec, $1)
+
+# Compiler flag to generate thread-safe objects.
+thread_safe_flag_spec=$lt_[]_LT_AC_TAGVAR(thread_safe_flag_spec, $1)
+
+# Library versioning type.
+version_type=$version_type
+
+# Format of library name prefix.
+libname_spec=$lt_libname_spec
+
+# List of archive names. First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME.
+library_names_spec=$lt_library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$lt_soname_spec
+
+# Commands used to build and install an old-style archive.
+RANLIB=$lt_RANLIB
+old_archive_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_cmds, $1)
+old_postinstall_cmds=$lt_old_postinstall_cmds
+old_postuninstall_cmds=$lt_old_postuninstall_cmds
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_new_cmds, $1)
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1)
+
+# Commands used to build and install a shared archive.
+archive_cmds=$lt_[]_LT_AC_TAGVAR(archive_cmds, $1)
+archive_expsym_cmds=$lt_[]_LT_AC_TAGVAR(archive_expsym_cmds, $1)
+postinstall_cmds=$lt_postinstall_cmds
+postuninstall_cmds=$lt_postuninstall_cmds
+
+# Commands used to build a loadable module (assumed same as above if empty)
+module_cmds=$lt_[]_LT_AC_TAGVAR(module_cmds, $1)
+module_expsym_cmds=$lt_[]_LT_AC_TAGVAR(module_expsym_cmds, $1)
+
+# Commands to strip libraries.
+old_striplib=$lt_old_striplib
+striplib=$lt_striplib
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predep_objects=$lt_[]_LT_AC_TAGVAR(predep_objects, $1)
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdep_objects=$lt_[]_LT_AC_TAGVAR(postdep_objects, $1)
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predeps=$lt_[]_LT_AC_TAGVAR(predeps, $1)
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdeps=$lt_[]_LT_AC_TAGVAR(postdeps, $1)
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path=$lt_[]_LT_AC_TAGVAR(compiler_lib_search_path, $1)
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$lt_deplibs_check_method
+
+# Command to use when deplibs_check_method == file_magic.
+file_magic_cmd=$lt_file_magic_cmd
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_[]_LT_AC_TAGVAR(allow_undefined_flag, $1)
+
+# Flag that forces no undefined symbols.
+no_undefined_flag=$lt_[]_LT_AC_TAGVAR(no_undefined_flag, $1)
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$lt_finish_cmds
+
+# Same as above, but a single script fragment to be evaled but not shown.
+finish_eval=$lt_finish_eval
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration
+global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
+
+# Transform the output of nm in a C name address pair
+global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
+
+# This is the shared library runtime path variable.
+runpath_var=$runpath_var
+
+# This is the shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$_LT_AC_TAGVAR(hardcode_action, $1)
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=$hardcode_into_libs
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)
+
+# If ld is used when linking, flag to hardcode \$libdir into
+# a binary during linking. This must work even if \$libdir does
+# not exist.
+hardcode_libdir_flag_spec_ld=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)
+
+# Whether we need a single -rpath flag with a separated argument.
+hardcode_libdir_separator=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_separator, $1)
+
+# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the
+# resulting binary.
+hardcode_direct=$_LT_AC_TAGVAR(hardcode_direct, $1)
+
+# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
+# resulting binary.
+hardcode_minus_L=$_LT_AC_TAGVAR(hardcode_minus_L, $1)
+
+# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into
+# the resulting binary.
+hardcode_shlibpath_var=$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)
+
+# Set to yes if building a shared library automatically hardcodes DIR into the library
+# and all subsequent libraries and executables linked against it.
+hardcode_automatic=$_LT_AC_TAGVAR(hardcode_automatic, $1)
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at relink time.
+variables_saved_for_relink="$variables_saved_for_relink"
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$_LT_AC_TAGVAR(link_all_deplibs, $1)
+
+# Compile-time system search path for libraries
+sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+
+# Run-time system search path for libraries
+sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
+
+# Fix the shell variable \$srcfile for the compiler.
+fix_srcfile_path="$_LT_AC_TAGVAR(fix_srcfile_path, $1)"
+
+# Set to yes if exported symbols are required.
+always_export_symbols=$_LT_AC_TAGVAR(always_export_symbols, $1)
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_[]_LT_AC_TAGVAR(export_symbols_cmds, $1)
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=$lt_extract_expsyms_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_[]_LT_AC_TAGVAR(exclude_expsyms, $1)
+
+# Symbols that must always be exported.
+include_expsyms=$lt_[]_LT_AC_TAGVAR(include_expsyms, $1)
+
+ifelse([$1],[],
+[# ### END LIBTOOL CONFIG],
+[# ### END LIBTOOL TAG CONFIG: $tagname])
+
+__EOF__
+
+ifelse([$1],[], [
+ case $host_os in
+ aix3*)
+ cat <<\EOF >> "$cfgfile"
+
+# AIX sometimes has problems with the GCC collect2 program. For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "X${COLLECT_NAMES+set}" != Xset; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+fi
+EOF
+ ;;
+ esac
+
+ # We use sed instead of cat because bash on DJGPP gets confused if
+ # if finds mixed CR/LF and LF-only lines. Since sed operates in
+ # text mode, it properly converts lines to CR/LF. This bash problem
+ # is reportedly fixed, but why not run on old versions too?
+ sed '$q' "$ltmain" >> "$cfgfile" || (rm -f "$cfgfile"; exit 1)
+
+ mv -f "$cfgfile" "$ofile" || \
+ (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+ chmod +x "$ofile"
+])
+else
+ # If there is no Makefile yet, we rely on a make rule to execute
+ # `config.status --recheck' to rerun these tests and create the
+ # libtool script then.
+ ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'`
+ if test -f "$ltmain_in"; then
+ test -f Makefile && make "$ltmain"
+ fi
+fi
+])# AC_LIBTOOL_CONFIG
+
+
+# AC_LIBTOOL_PROG_COMPILER_NO_RTTI([TAGNAME])
+# -------------------------------------------
+AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI],
+[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl
+
+_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+
+if test "$GCC" = yes; then
+ _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
+
+ AC_LIBTOOL_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions],
+ lt_cv_prog_compiler_rtti_exceptions,
+ [-fno-rtti -fno-exceptions], [],
+ [_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"])
+fi
+])# AC_LIBTOOL_PROG_COMPILER_NO_RTTI
+
+
+# AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE
+# ---------------------------------
+AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE],
+[AC_REQUIRE([AC_CANONICAL_HOST])
+AC_REQUIRE([AC_PROG_NM])
+AC_REQUIRE([AC_OBJEXT])
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+AC_MSG_CHECKING([command to parse $NM output from $compiler object])
+AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe],
+[
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix. What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[[BCDEGRST]]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)'
+
+# Transform the above into a raw symbol and a C symbol.
+symxfrm='\1 \2\3 \3'
+
+# Transform an extracted symbol line into a proper C declaration
+lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern int \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'"
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+ symcode='[[BCDT]]'
+ ;;
+cygwin* | mingw* | pw32*)
+ symcode='[[ABCDGISTW]]'
+ ;;
+hpux*) # Its linker distinguishes data from code symbols
+ if test "$host_cpu" = ia64; then
+ symcode='[[ABCDEGRST]]'
+ fi
+ lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+ lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'"
+ ;;
+irix* | nonstopux*)
+ symcode='[[BCDEGRST]]'
+ ;;
+osf*)
+ symcode='[[BCDEGQRST]]'
+ ;;
+solaris* | sysv5*)
+ symcode='[[BDRT]]'
+ ;;
+sysv4)
+ symcode='[[DFNSTU]]'
+ ;;
+esac
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+ opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+ ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+ symcode='[[ABCDGIRSTW]]' ;;
+esac
+
+# Try without a prefix undercore, then with it.
+for ac_symprfx in "" "_"; do
+
+ # Write the raw and C identifiers.
+ lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*\($ac_symprfx\)$sympat$opt_cr$/$symxfrm/p'"
+
+ # Check to see that the pipe works correctly.
+ pipe_works=no
+
+ rm -f conftest*
+ cat > conftest.$ac_ext <<EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+EOF
+
+ if AC_TRY_EVAL(ac_compile); then
+ # Now try to grab the symbols.
+ nlist=conftest.nm
+ if AC_TRY_EVAL(NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) && test -s "$nlist"; then
+ # Try sorting and uniquifying the output.
+ if sort "$nlist" | uniq > "$nlist"T; then
+ mv -f "$nlist"T "$nlist"
+ else
+ rm -f "$nlist"T
+ fi
+
+ # Make sure that we snagged all the symbols we need.
+ if grep ' nm_test_var$' "$nlist" >/dev/null; then
+ if grep ' nm_test_func$' "$nlist" >/dev/null; then
+ cat <<EOF > conftest.$ac_ext
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+EOF
+ # Now generate the symbol file.
+ eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | grep -v main >> conftest.$ac_ext'
+
+ cat <<EOF >> conftest.$ac_ext
+#if defined (__STDC__) && __STDC__
+# define lt_ptr_t void *
+#else
+# define lt_ptr_t char *
+# define const
+#endif
+
+/* The mapping between symbol names and symbols. */
+const struct {
+ const char *name;
+ lt_ptr_t address;
+}
+lt_preloaded_symbols[[]] =
+{
+EOF
+ $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (lt_ptr_t) \&\2},/" < "$nlist" | grep -v main >> conftest.$ac_ext
+ cat <<\EOF >> conftest.$ac_ext
+ {0, (lt_ptr_t) 0}
+};
+
+#ifdef __cplusplus
+}
+#endif
+EOF
+ # Now try linking the two files.
+ mv conftest.$ac_objext conftstm.$ac_objext
+ lt_save_LIBS="$LIBS"
+ lt_save_CFLAGS="$CFLAGS"
+ LIBS="conftstm.$ac_objext"
+ CFLAGS="$CFLAGS$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)"
+ if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then
+ pipe_works=yes
+ fi
+ LIBS="$lt_save_LIBS"
+ CFLAGS="$lt_save_CFLAGS"
+ else
+ echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD
+ fi
+ else
+ echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD
+ fi
+ else
+ echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD
+ fi
+ else
+ echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD
+ cat conftest.$ac_ext >&5
+ fi
+ rm -f conftest* conftst*
+
+ # Do not use the global_symbol_pipe unless it works.
+ if test "$pipe_works" = yes; then
+ break
+ else
+ lt_cv_sys_global_symbol_pipe=
+ fi
+done
+])
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+ lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+ AC_MSG_RESULT(failed)
+else
+ AC_MSG_RESULT(ok)
+fi
+]) # AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE
+
+
+# AC_LIBTOOL_PROG_COMPILER_PIC([TAGNAME])
+# ---------------------------------------
+AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC],
+[_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)=
+_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+_LT_AC_TAGVAR(lt_prog_compiler_static, $1)=
+
+AC_MSG_CHECKING([for $compiler option to produce PIC])
+ ifelse([$1],[CXX],[
+ # C++ specific cases for pic, static, wl, etc.
+ if test "$GXX" = yes; then
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ fi
+ ;;
+ amigaos*)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the `-m68020' flag to GCC prevents building anything better,
+ # like `-m68040'.
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+ ;;
+ beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+ mingw* | os2* | pw32*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'
+ ;;
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+ ;;
+ *djgpp*)
+ # DJGPP does not support shared libraries at all
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+ ;;
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+ fi
+ ;;
+ hpux*)
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case "$host_cpu" in
+ hppa*64*|ia64*)
+ ;;
+ *)
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+ ;;
+ *)
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+ else
+ case $host_os in
+ aix4* | aix5*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ else
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+ chorus*)
+ case $cc_basename in
+ cxch68)
+ # Green Hills C++ Compiler
+ # _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
+ ;;
+ esac
+ ;;
+ dgux*)
+ case $cc_basename in
+ ec++)
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ ;;
+ ghcx)
+ # Green Hills C++ Compiler
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ freebsd* | kfreebsd*-gnu)
+ # FreeBSD uses GNU C++
+ ;;
+ hpux9* | hpux10* | hpux11*)
+ case $cc_basename in
+ CC)
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive"
+ if test "$host_cpu" != ia64; then
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+ fi
+ ;;
+ aCC)
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive"
+ case "$host_cpu" in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+ ;;
+ esac
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ irix5* | irix6* | nonstopux*)
+ case $cc_basename in
+ CC)
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ # CC pic flag -KPIC is the default.
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ linux*)
+ case $cc_basename in
+ KCC)
+ # KAI C++ Compiler
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ icpc)
+ # Intel C++
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ cxx)
+ # Compaq C++
+ # Make sure the PIC flag is empty. It appears that all Alpha
+ # Linux and Compaq Tru64 Unix objects are PIC.
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ lynxos*)
+ ;;
+ m88k*)
+ ;;
+ mvs*)
+ case $cc_basename in
+ cxx)
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ netbsd*)
+ ;;
+ osf3* | osf4* | osf5*)
+ case $cc_basename in
+ KCC)
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+ ;;
+ RCC)
+ # Rational C++ 2.4.1
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ ;;
+ cxx)
+ # Digital/Compaq C++
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # Make sure the PIC flag is empty. It appears that all Alpha
+ # Linux and Compaq Tru64 Unix objects are PIC.
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ psos*)
+ ;;
+ sco*)
+ case $cc_basename in
+ CC)
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ solaris*)
+ case $cc_basename in
+ CC)
+ # Sun C++ 4.2, 5.x and Centerline C++
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+ ;;
+ gcx)
+ # Green Hills C++ Compiler
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ sunos4*)
+ case $cc_basename in
+ CC)
+ # Sun C++ 4.x
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ lcc)
+ # Lucid
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ tandem*)
+ case $cc_basename in
+ NCC)
+ # NonStop-UX NCC 3.20
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ unixware*)
+ ;;
+ vxworks*)
+ ;;
+ *)
+ _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ ;;
+ esac
+ fi
+],
+[
+ if test "$GCC" = yes; then
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ fi
+ ;;
+
+ amigaos*)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the `-m68020' flag to GCC prevents building anything better,
+ # like `-m68040'.
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+ ;;
+
+ beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+
+ mingw* | pw32* | os2*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'
+ ;;
+
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+ ;;
+
+ msdosdjgpp*)
+ # Just because we use GCC doesn't mean we suddenly get shared libraries
+ # on systems that don't support them.
+ _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ enable_shared=no
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+ fi
+ ;;
+
+ hpux*)
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case "$host_cpu" in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+ ;;
+
+ *)
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+ else
+ # PORTME Check for flag to pass linker flags through the system compiler.
+ case $host_os in
+ aix*)
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ else
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+
+ mingw* | pw32* | os2*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'
+ ;;
+
+ hpux9* | hpux10* | hpux11*)
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case "$host_cpu" in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+ ;;
+ esac
+ # Is there a better lt_prog_compiler_static that works with the bundled CC?
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # PIC (with -KPIC) is the default.
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+
+ newsos6)
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ linux*)
+ case $CC in
+ icc* | ecc*)
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ ccc*)
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # All Alpha code is PIC.
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+ esac
+ ;;
+
+ osf3* | osf4* | osf5*)
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # All OSF/1 code is PIC.
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+
+ sco3.2v5*)
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-Kpic'
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-dn'
+ ;;
+
+ solaris*)
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ sunos4*)
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec ;then
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic'
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ fi
+ ;;
+
+ uts4*)
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ *)
+ _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ ;;
+ esac
+ fi
+])
+AC_MSG_RESULT([$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)])
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)"; then
+ AC_LIBTOOL_COMPILER_OPTION([if $compiler PIC flag $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) works],
+ _LT_AC_TAGVAR(lt_prog_compiler_pic_works, $1),
+ [$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])], [],
+ [case $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) in
+ "" | " "*) ;;
+ *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)" ;;
+ esac],
+ [_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+ _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no])
+fi
+case "$host_os" in
+ # For platforms which do not support PIC, -DPIC is meaningless:
+ *djgpp*)
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+ ;;
+ *)
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])"
+ ;;
+esac
+])
+
+
+# AC_LIBTOOL_PROG_LD_SHLIBS([TAGNAME])
+# ------------------------------------
+# See if the linker supports building shared libraries.
+AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS],
+[AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+ifelse([$1],[CXX],[
+ _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ case $host_os in
+ aix4* | aix5*)
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to AIX nm, but means don't demangle with GNU nm
+ if $NM -V 2>&1 | grep 'GNU' > /dev/null; then
+ _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols'
+ else
+ _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols'
+ fi
+ ;;
+ pw32*)
+ _LT_AC_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds"
+ ;;
+ cygwin* | mingw*)
+ _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGS]] /s/.* \([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols'
+ ;;
+ *)
+ _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ ;;
+ esac
+],[
+ runpath_var=
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)=
+ _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+ _LT_AC_TAGVAR(archive_cmds, $1)=
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)=
+ _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)=
+ _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1)=
+ _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+ _LT_AC_TAGVAR(thread_safe_flag_spec, $1)=
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+ _LT_AC_TAGVAR(hardcode_direct, $1)=no
+ _LT_AC_TAGVAR(hardcode_minus_L, $1)=no
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+ _LT_AC_TAGVAR(link_all_deplibs, $1)=unknown
+ _LT_AC_TAGVAR(hardcode_automatic, $1)=no
+ _LT_AC_TAGVAR(module_cmds, $1)=
+ _LT_AC_TAGVAR(module_expsym_cmds, $1)=
+ _LT_AC_TAGVAR(always_export_symbols, $1)=no
+ _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ # include_expsyms should be a list of space-separated symbols to be *always*
+ # included in the symbol list
+ _LT_AC_TAGVAR(include_expsyms, $1)=
+ # exclude_expsyms can be an extended regexp of symbols to exclude
+ # it will be wrapped by ` (' and `)$', so one must not match beginning or
+ # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+ # as well as any symbol that contains `d'.
+ _LT_AC_TAGVAR(exclude_expsyms, $1)="_GLOBAL_OFFSET_TABLE_"
+ # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+ # platforms (ab)use it in PIC code, but their linkers get confused if
+ # the symbol is explicitly referenced. Since portable code cannot
+ # rely on this symbol name, it's probably fine to never include it in
+ # preloaded symbol tables.
+ extract_expsyms_cmds=
+
+ case $host_os in
+ cygwin* | mingw* | pw32*)
+ # FIXME: the MSVC++ port hasn't been tested in a loooong time
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ if test "$GCC" != yes; then
+ with_gnu_ld=no
+ fi
+ ;;
+ openbsd*)
+ with_gnu_ld=no
+ ;;
+ esac
+
+ _LT_AC_TAGVAR(ld_shlibs, $1)=yes
+ if test "$with_gnu_ld" = yes; then
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ wlarc='${wl}'
+
+ # See if GNU ld supports shared libraries.
+ case $host_os in
+ aix3* | aix4* | aix5*)
+ # On AIX/PPC, the GNU linker is very broken
+ if test "$host_cpu" != ia64; then
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ cat <<EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.9.1, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support. If you
+*** really care for shared libraries, you may want to modify your PATH
+*** so that a non-GNU linker is found, and then restart.
+
+EOF
+ fi
+ ;;
+
+ amigaos*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+
+ # Samuel A. Falvo II <kc5tja at dolphin.openprojects.net> reports
+ # that the semantics of dynamic libraries on AmigaOS, at least up
+ # to version 4, is to share data among multiple programs linked
+ # with the same dynamic library. Since this doesn't match the
+ # behavior of shared libraries on other platforms, we can't use
+ # them.
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+ # Joseph Beckenbach <jrb3 at best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ else
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ cygwin* | mingw* | pw32*)
+ # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+ # as there is no search path for DLLs.
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_AC_TAGVAR(always_export_symbols, $1)=no
+ _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGS]] /s/.* \([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols'
+
+ if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+ # If the export-symbols file already is a .def file (1st line
+ # is EXPORTS), use it as is; otherwise, prepend...
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+ wlarc=
+ else
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ fi
+ ;;
+
+ solaris* | sysv5*)
+ if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ cat <<EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+EOF
+ elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ sunos4*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ wlarc=
+ _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ linux*)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ tmp_archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_AC_TAGVAR(archive_cmds, $1)="$tmp_archive_cmds"
+ supports_anon_versioning=no
+ case `$LD -v 2>/dev/null` in
+ *\ [01].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
+ *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+ *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+ *\ 2.11.*) ;; # other 2.11 versions
+ *) supports_anon_versioning=yes ;;
+ esac
+ if test $supports_anon_versioning = yes; then
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $output_objdir/$libname.ver~
+cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+$echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ else
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)="$tmp_archive_cmds"
+ fi
+ else
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ *)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+
+ if test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = yes; then
+ runpath_var=LD_RUN_PATH
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
+ _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+ fi
+ fi
+ else
+ # PORTME fill in a description of your system's linker (not GNU ld)
+ case $host_os in
+ aix3*)
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_AC_TAGVAR(always_export_symbols, $1)=yes
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+ # Note: this linker hardcodes the directories in LIBPATH if there
+ # are no directories specified by -L.
+ _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+ if test "$GCC" = yes && test -z "$link_static_flag"; then
+ # Neither direct hardcoding nor static linking is supported with a
+ # broken collect2.
+ _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported
+ fi
+ ;;
+
+ aix4* | aix5*)
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=""
+ else
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to AIX nm, but means don't demangle with GNU nm
+ if $NM -V 2>&1 | grep 'GNU' > /dev/null; then
+ _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols'
+ else
+ _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols'
+ fi
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # need to do runtime linking.
+ case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*)
+ for ld_flag in $LDFLAGS; do
+ if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+ aix_use_runtimelinking=yes
+ break
+ fi
+ done
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ _LT_AC_TAGVAR(archive_cmds, $1)=''
+ _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+
+ if test "$GCC" = yes; then
+ case $host_os in aix4.[012]|aix4.[012].*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" && \
+ strings "$collect2name" | grep resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+ else
+ # We have old collect2
+ _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+ fi
+ esac
+ shared_flag='-shared'
+ else
+ # not using gcc
+ if test "$host_cpu" = ia64; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag='${wl}-G'
+ else
+ shared_flag='${wl}-bM:SRE'
+ fi
+ fi
+ fi
+
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to export.
+ _LT_AC_TAGVAR(always_export_symbols, $1)=yes
+ if test "$aix_use_runtimelinking" = yes; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok'
+ # Determine the default libpath from the value encoded in an empty executable.
+ _LT_AC_SYS_LIBPATH_AIX
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ else
+ if test "$host_cpu" = ia64; then
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an empty executable.
+ _LT_AC_SYS_LIBPATH_AIX
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+ # -bexpall does not export symbols beginning with underscore (_)
+ _LT_AC_TAGVAR(always_export_symbols, $1)=yes
+ # Exported symbols can be pulled into shared objects from archives
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=' '
+ _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes
+ # This is similar to how AIX traditionally builds it's shared libraries.
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ fi
+ fi
+ ;;
+
+ amigaos*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+ # see comment about different semantics on the GNU ld section
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ bsdi4*)
+ _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic
+ ;;
+
+ cygwin* | mingw* | pw32*)
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=".dll"
+ # FIXME: Setting linknames here is a bad hack.
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames='
+ # The linker will automatically build a .lib file if we build a DLL.
+ _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='true'
+ # FIXME: Should let the user specify the lib program.
+ _LT_AC_TAGVAR(old_archive_cmds, $1)='lib /OUT:$oldlib$oldobjs$old_deplibs'
+ fix_srcfile_path='`cygpath -w "$srcfile"`'
+ _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ ;;
+
+ darwin* | rhapsody*)
+ if test "$GXX" = yes ; then
+ _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+ case "$host_os" in
+ rhapsody* | darwin1.[[012]])
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined suppress'
+ ;;
+ *) # Darwin 1.3 on
+ if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress'
+ else
+ case ${MACOSX_DEPLOYMENT_TARGET} in
+ 10.[[012]])
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress'
+ ;;
+ 10.*)
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined dynamic_lookup'
+ ;;
+ esac
+ fi
+ ;;
+ esac
+ lt_int_apple_cc_single_mod=no
+ output_verbose_link_cmd='echo'
+ if $CC -dumpspecs 2>&1 | grep 'single_module' >/dev/null ; then
+ lt_int_apple_cc_single_mod=yes
+ fi
+ if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+ else
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+ fi
+ _LT_AC_TAGVAR(module_cmds, $1)='$CC ${wl}-bind_at_load $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+ # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's
+ if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ else
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ fi
+ _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ _LT_AC_TAGVAR(hardcode_direct, $1)=no
+ _LT_AC_TAGVAR(hardcode_automatic, $1)=yes
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-all_load $convenience'
+ _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+ else
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ dgux*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ freebsd1*)
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+ # support. Future versions do this automatically, but an explicit c++rt0.o
+ # does not break anything, and helps significantly (at the cost of a little
+ # extra space).
+ freebsd2.2*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+ freebsd2*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+ _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+ freebsd* | kfreebsd*-gnu)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ hpux9*)
+ if test "$GCC" = yes; then
+ _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ else
+ _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ fi
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ ;;
+
+ hpux10* | hpux11*)
+ if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+ case "$host_cpu" in
+ hppa*64*|ia64*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ else
+ case "$host_cpu" in
+ hppa*64*|ia64*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $libobjs $deplibs $linker_flags'
+ ;;
+ *)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+ ;;
+ esac
+ fi
+ if test "$with_gnu_ld" = no; then
+ case "$host_cpu" in
+ hppa*64*)
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir'
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_AC_TAGVAR(hardcode_direct, $1)=no
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+ ia64*)
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_AC_TAGVAR(hardcode_direct, $1)=no
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+ ;;
+ *)
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+ _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+ ;;
+ esac
+ fi
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ if test "$GCC" = yes; then
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir'
+ fi
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
+ else
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF
+ fi
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ newsos6)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ openbsd*)
+ _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ else
+ case $host_os in
+ openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ ;;
+ *)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ ;;
+ esac
+ fi
+ ;;
+
+ os2*)
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_AC_TAGVAR(archive_cmds, $1)='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+ _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+ ;;
+
+ osf3*)
+ if test "$GCC" = yes; then
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+ fi
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+ ;;
+
+ osf4* | osf5*) # as osf3* with the addition of -msym flag
+ if test "$GCC" = yes; then
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ else
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~
+ $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib~$rm $lib.exp'
+
+ # Both c and cxx compiler support -rpath directly
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+ fi
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+ ;;
+
+ sco3.2v5*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+ runpath_var=LD_RUN_PATH
+ hardcode_runpath_var=yes
+ ;;
+
+ solaris*)
+ _LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text'
+ if test "$GCC" = yes; then
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp'
+ else
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
+ fi
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ case $host_os in
+ solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+ *) # Supported since Solaris 2.6 (maybe 2.5.1?)
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;;
+ esac
+ _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+
+ sunos4*)
+ if test "x$host_vendor" = xsequent; then
+ # Use $CC to link under sequent, because it throws in some extra .o
+ # files that make .init and .fini sections work.
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+ _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ sysv4)
+ case $host_vendor in
+ sni)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_AC_TAGVAR(hardcode_direct, $1)=yes # is this really true???
+ ;;
+ siemens)
+ ## LD is ld it makes a PLAMLIB
+ ## CC just makes a GrossModule.
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+ _LT_AC_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs'
+ _LT_AC_TAGVAR(hardcode_direct, $1)=no
+ ;;
+ motorola)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_AC_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie
+ ;;
+ esac
+ runpath_var='LD_RUN_PATH'
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ sysv4.3*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ runpath_var=LD_RUN_PATH
+ hardcode_runpath_var=yes
+ _LT_AC_TAGVAR(ld_shlibs, $1)=yes
+ fi
+ ;;
+
+ sysv4.2uw2*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+ _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+ _LT_AC_TAGVAR(hardcode_minus_L, $1)=no
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ hardcode_runpath_var=yes
+ runpath_var=LD_RUN_PATH
+ ;;
+
+ sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[[78]]* | unixware7*)
+ _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z ${wl}text'
+ if test "$GCC" = yes; then
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ runpath_var='LD_RUN_PATH'
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ sysv5*)
+ _LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text'
+ # $CC -shared without GNU ld will not create a library from C++
+ # object files and a static libstdc++, better avoid it by now
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ runpath_var='LD_RUN_PATH'
+ ;;
+
+ uts4*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ *)
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ fi
+])
+AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)])
+test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+ variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)" in
+x|xyes)
+ # Assume -lc should be added
+ _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes
+
+ if test "$enable_shared" = yes && test "$GCC" = yes; then
+ case $_LT_AC_TAGVAR(archive_cmds, $1) in
+ *'~'*)
+ # FIXME: we may have to deal with multi-command sequences.
+ ;;
+ '$CC '*)
+ # Test whether the compiler implicitly links with -lc since on some
+ # systems, -lgcc has to come before -lc. If gcc already passes -lc
+ # to ld, don't add -lc before -lgcc.
+ AC_MSG_CHECKING([whether -lc should be explicitly linked in])
+ $rm conftest*
+ printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ if AC_TRY_EVAL(ac_compile) 2>conftest.err; then
+ soname=conftest
+ lib=conftest
+ libobjs=conftest.$ac_objext
+ deplibs=
+ wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)
+ compiler_flags=-v
+ linker_flags=-v
+ verstring=
+ output_objdir=.
+ libname=conftest
+ lt_save_allow_undefined_flag=$_LT_AC_TAGVAR(allow_undefined_flag, $1)
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)=
+ if AC_TRY_EVAL(_LT_AC_TAGVAR(archive_cmds, $1) 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1)
+ then
+ _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+ else
+ _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes
+ fi
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag
+ else
+ cat conftest.err 1>&5
+ fi
+ $rm conftest*
+ AC_MSG_RESULT([$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)])
+ ;;
+ esac
+ fi
+ ;;
+esac
+])# AC_LIBTOOL_PROG_LD_SHLIBS
+
+
+# _LT_AC_FILE_LTDLL_C
+# -------------------
+# Be careful that the start marker always follows a newline.
+AC_DEFUN([_LT_AC_FILE_LTDLL_C], [
+# /* ltdll.c starts here */
+# #define WIN32_LEAN_AND_MEAN
+# #include <windows.h>
+# #undef WIN32_LEAN_AND_MEAN
+# #include <stdio.h>
+#
+# #ifndef __CYGWIN__
+# # ifdef __CYGWIN32__
+# # define __CYGWIN__ __CYGWIN32__
+# # endif
+# #endif
+#
+# #ifdef __cplusplus
+# extern "C" {
+# #endif
+# BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved);
+# #ifdef __cplusplus
+# }
+# #endif
+#
+# #ifdef __CYGWIN__
+# #include <cygwin/cygwin_dll.h>
+# DECLARE_CYGWIN_DLL( DllMain );
+# #endif
+# HINSTANCE __hDllInstance_base;
+#
+# BOOL APIENTRY
+# DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved)
+# {
+# __hDllInstance_base = hInst;
+# return TRUE;
+# }
+# /* ltdll.c ends here */
+])# _LT_AC_FILE_LTDLL_C
+
+
+# _LT_AC_TAGVAR(VARNAME, [TAGNAME])
+# ---------------------------------
+AC_DEFUN([_LT_AC_TAGVAR], [ifelse([$2], [], [$1], [$1_$2])])
+
+
+# old names
+AC_DEFUN([AM_PROG_LIBTOOL], [AC_PROG_LIBTOOL])
+AC_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
+AC_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
+AC_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
+AC_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
+AC_DEFUN([AM_PROG_LD], [AC_PROG_LD])
+AC_DEFUN([AM_PROG_NM], [AC_PROG_NM])
+
+# This is just to silence aclocal about the macro not being used
+ifelse([AC_DISABLE_FAST_INSTALL])
+
+AC_DEFUN([LT_AC_PROG_GCJ],
+[AC_CHECK_TOOL(GCJ, gcj, no)
+ test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2"
+ AC_SUBST(GCJFLAGS)
+])
+
+AC_DEFUN([LT_AC_PROG_RC],
+[AC_CHECK_TOOL(RC, windres, no)
+])
+
+# NOTE: This macro has been submitted for inclusion into #
+# GNU Autoconf as AC_PROG_SED. When it is available in #
+# a released version of Autoconf we should remove this #
+# macro and use it instead. #
+# LT_AC_PROG_SED
+# --------------
+# Check for a fully-functional sed program, that truncates
+# as few characters as possible. Prefer GNU sed if found.
+AC_DEFUN([LT_AC_PROG_SED],
+[AC_MSG_CHECKING([for a sed that does not truncate output])
+AC_CACHE_VAL(lt_cv_path_SED,
+[# Loop through the user's path and test for sed and gsed.
+# Then use that list of sed's as ones to test for truncation.
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for lt_ac_prog in sed gsed; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then
+ lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext"
+ fi
+ done
+ done
+done
+lt_ac_max=0
+lt_ac_count=0
+# Add /usr/xpg4/bin/sed as it is typically found on Solaris
+# along with /bin/sed that truncates output.
+for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
+ test ! -f $lt_ac_sed && break
+ cat /dev/null > conftest.in
+ lt_ac_count=0
+ echo $ECHO_N "0123456789$ECHO_C" >conftest.in
+ # Check for GNU sed and select it if it is found.
+ if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then
+ lt_cv_path_SED=$lt_ac_sed
+ break
+ fi
+ while true; do
+ cat conftest.in conftest.in >conftest.tmp
+ mv conftest.tmp conftest.in
+ cp conftest.in conftest.nl
+ echo >>conftest.nl
+ $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break
+ cmp -s conftest.out conftest.nl || break
+ # 10000 chars as input seems more than enough
+ test $lt_ac_count -gt 10 && break
+ lt_ac_count=`expr $lt_ac_count + 1`
+ if test $lt_ac_count -gt $lt_ac_max; then
+ lt_ac_max=$lt_ac_count
+ lt_cv_path_SED=$lt_ac_sed
+ fi
+ done
+done
+SED=$lt_cv_path_SED
+])
+AC_MSG_RESULT([$SED])
+])
+
+
+dnl PKG_CHECK_MODULES(GSTUFF, gtk+-2.0 >= 1.3 glib = 1.3.4, action-if, action-not)
+dnl defines GSTUFF_LIBS, GSTUFF_CFLAGS, see pkg-config man page
+dnl also defines GSTUFF_PKG_ERRORS on error
+AC_DEFUN([PKG_CHECK_MODULES], [
+ succeeded=no
+
+ if test -z "$PKG_CONFIG"; then
+ AC_PATH_PROG(PKG_CONFIG, pkg-config, no)
+ fi
+
+ if test "$PKG_CONFIG" = "no" ; then
+ echo "*** The pkg-config script could not be found. Make sure it is"
+ echo "*** in your path, or set the PKG_CONFIG environment variable"
+ echo "*** to the full path to pkg-config."
+ echo "*** Or see http://www.freedesktop.org/software/pkgconfig to get pkg-config."
+ else
+ PKG_CONFIG_MIN_VERSION=0.9.0
+ if $PKG_CONFIG --atleast-pkgconfig-version $PKG_CONFIG_MIN_VERSION; then
+ AC_MSG_CHECKING(for $2)
+
+ if $PKG_CONFIG --exists "$2" ; then
+ AC_MSG_RESULT(yes)
+ succeeded=yes
+
+ AC_MSG_CHECKING($1_CFLAGS)
+ $1_CFLAGS=`$PKG_CONFIG --cflags "$2"`
+ AC_MSG_RESULT($$1_CFLAGS)
+
+ AC_MSG_CHECKING($1_LIBS)
+ $1_LIBS=`$PKG_CONFIG --libs "$2"`
+ AC_MSG_RESULT($$1_LIBS)
+ else
+ $1_CFLAGS=""
+ $1_LIBS=""
+ ## If we have a custom action on failure, don't print errors, but
+ ## do set a variable so people can do so.
+ $1_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"`
+ ifelse([$4], ,echo $$1_PKG_ERRORS,)
+ fi
+
+ AC_SUBST($1_CFLAGS)
+ AC_SUBST($1_LIBS)
+ else
+ echo "*** Your version of pkg-config is too old. You need version $PKG_CONFIG_MIN_VERSION or newer."
+ echo "*** See http://www.freedesktop.org/software/pkgconfig"
+ fi
+ fi
+
+ if test $succeeded = yes; then
+ ifelse([$3], , :, [$3])
+ else
+ ifelse([$4], , AC_MSG_ERROR([Library requirements ($2) not met; consider adjusting the PKG_CONFIG_PATH environment variable if your libraries are in a nonstandard prefix so pkg-config can find them.]), [$4])
+ fi
+])
+
+
+
+# -*- Autoconf -*-
+# Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+# Generated from amversion.in; do not edit by hand.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program 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 General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+
+# AM_AUTOMAKE_VERSION(VERSION)
+# ----------------------------
+# Automake X.Y traces this macro to ensure aclocal.m4 has been
+# generated from the m4 files accompanying Automake X.Y.
+AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version="1.9"])
+
+# AM_SET_CURRENT_AUTOMAKE_VERSION
+# -------------------------------
+# Call AM_AUTOMAKE_VERSION so it can be traced.
+# This function is AC_REQUIREd by AC_INIT_AUTOMAKE.
+AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
+ [AM_AUTOMAKE_VERSION([1.9.2])])
+
+# AM_AUX_DIR_EXPAND
+
+# Copyright (C) 2001, 2003 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program 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 General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
+# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to
+# `$srcdir', `$srcdir/..', or `$srcdir/../..'.
+#
+# Of course, Automake must honor this variable whenever it calls a
+# tool from the auxiliary directory. The problem is that $srcdir (and
+# therefore $ac_aux_dir as well) can be either absolute or relative,
+# depending on how configure is run. This is pretty annoying, since
+# it makes $ac_aux_dir quite unusable in subdirectories: in the top
+# source directory, any form will work fine, but in subdirectories a
+# relative path needs to be adjusted first.
+#
+# $ac_aux_dir/missing
+# fails when called from a subdirectory if $ac_aux_dir is relative
+# $top_srcdir/$ac_aux_dir/missing
+# fails if $ac_aux_dir is absolute,
+# fails when called from a subdirectory in a VPATH build with
+# a relative $ac_aux_dir
+#
+# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
+# are both prefixed by $srcdir. In an in-source build this is usually
+# harmless because $srcdir is `.', but things will broke when you
+# start a VPATH build or use an absolute $srcdir.
+#
+# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
+# iff we strip the leading $srcdir from $ac_aux_dir. That would be:
+# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
+# and then we would define $MISSING as
+# MISSING="\${SHELL} $am_aux_dir/missing"
+# This will work as long as MISSING is not called from configure, because
+# unfortunately $(top_srcdir) has no meaning in configure.
+# However there are other variables, like CC, which are often used in
+# configure, and could therefore not use this "fixed" $ac_aux_dir.
+#
+# Another solution, used here, is to always expand $ac_aux_dir to an
+# absolute PATH. The drawback is that using absolute paths prevent a
+# configured tree to be moved without reconfiguration.
+
+AC_DEFUN([AM_AUX_DIR_EXPAND],
+[dnl Rely on autoconf to set up CDPATH properly.
+AC_PREREQ([2.50])dnl
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+])
+
+# AM_CONDITIONAL -*- Autoconf -*-
+
+# Copyright (C) 1997, 2000, 2001, 2003, 2004 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program 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 General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# serial 6
+
+# AM_CONDITIONAL(NAME, SHELL-CONDITION)
+# -------------------------------------
+# Define a conditional.
+AC_DEFUN([AM_CONDITIONAL],
+[AC_PREREQ(2.52)dnl
+ ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])],
+ [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
+AC_SUBST([$1_TRUE])
+AC_SUBST([$1_FALSE])
+if $2; then
+ $1_TRUE=
+ $1_FALSE='#'
+else
+ $1_TRUE='#'
+ $1_FALSE=
+fi
+AC_CONFIG_COMMANDS_PRE(
+[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
+ AC_MSG_ERROR([[conditional "$1" was never defined.
+Usually this means the macro was only invoked conditionally.]])
+fi])])
+
+# serial 7 -*- Autoconf -*-
+
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004
+# Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program 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 General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+
+# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be
+# written in clear, in which case automake, when reading aclocal.m4,
+# will think it sees a *use*, and therefore will trigger all it's
+# C support machinery. Also note that it means that autoscan, seeing
+# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
+
+
+
+# _AM_DEPENDENCIES(NAME)
+# ----------------------
+# See how the compiler implements dependency checking.
+# NAME is "CC", "CXX", "GCJ", or "OBJC".
+# We try a few techniques and use that to set a single cache variable.
+#
+# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
+# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
+# dependency, and given that the user is not expected to run this macro,
+# just rely on AC_PROG_CC.
+AC_DEFUN([_AM_DEPENDENCIES],
+[AC_REQUIRE([AM_SET_DEPDIR])dnl
+AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
+AC_REQUIRE([AM_MAKE_INCLUDE])dnl
+AC_REQUIRE([AM_DEP_TRACK])dnl
+
+ifelse([$1], CC, [depcc="$CC" am_compiler_list=],
+ [$1], CXX, [depcc="$CXX" am_compiler_list=],
+ [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
+ [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'],
+ [depcc="$$1" am_compiler_list=])
+
+AC_CACHE_CHECK([dependency style of $depcc],
+ [am_cv_$1_dependencies_compiler_type],
+[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named `D' -- because `-MD' means `put the output
+ # in D'.
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_$1_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
+ fi
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
+ # Solaris 8's {/usr,}/bin/sh.
+ touch sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ case $depmode in
+ nosideeffect)
+ # after this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ none) break ;;
+ esac
+ # We check with `-c' and `-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle `-M -o', and we need to detect this.
+ if depmode=$depmode \
+ source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_$1_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_$1_dependencies_compiler_type=none
+fi
+])
+AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
+AM_CONDITIONAL([am__fastdep$1], [
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_$1_dependencies_compiler_type" = gcc3])
+])
+
+
+# AM_SET_DEPDIR
+# -------------
+# Choose a directory name for dependency files.
+# This macro is AC_REQUIREd in _AM_DEPENDENCIES
+AC_DEFUN([AM_SET_DEPDIR],
+[AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
+])
+
+
+# AM_DEP_TRACK
+# ------------
+AC_DEFUN([AM_DEP_TRACK],
+[AC_ARG_ENABLE(dependency-tracking,
+[ --disable-dependency-tracking speeds up one-time build
+ --enable-dependency-tracking do not reject slow dependency extractors])
+if test "x$enable_dependency_tracking" != xno; then
+ am_depcomp="$ac_aux_dir/depcomp"
+ AMDEPBACKSLASH='\'
+fi
+AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
+AC_SUBST([AMDEPBACKSLASH])
+])
+
+# Generate code to set up dependency tracking. -*- Autoconf -*-
+
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004
+# Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program 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 General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+#serial 2
+
+# _AM_OUTPUT_DEPENDENCY_COMMANDS
+# ------------------------------
+AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
+[for mf in $CONFIG_FILES; do
+ # Strip MF so we end up with the name of the file.
+ mf=`echo "$mf" | sed -e 's/:.*$//'`
+ # Check whether this is an Automake generated Makefile or not.
+ # We used to match only the files named `Makefile.in', but
+ # some people rename them; so instead we look at the file content.
+ # Grep'ing the first line is not enough: some people post-process
+ # each Makefile.in and add a new line on top of each file to say so.
+ # So let's grep whole file.
+ if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then
+ dirpart=`AS_DIRNAME("$mf")`
+ else
+ continue
+ fi
+ # Extract the definition of DEPDIR, am__include, and am__quote
+ # from the Makefile without running `make'.
+ DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+ test -z "$DEPDIR" && continue
+ am__include=`sed -n 's/^am__include = //p' < "$mf"`
+ test -z "am__include" && continue
+ am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+ # When using ansi2knr, U may be empty or an underscore; expand it
+ U=`sed -n 's/^U = //p' < "$mf"`
+ # Find all dependency output files, they are included files with
+ # $(DEPDIR) in their names. We invoke sed twice because it is the
+ # simplest approach to changing $(DEPDIR) to its actual value in the
+ # expansion.
+ for file in `sed -n "
+ s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
+ # Make sure the directory exists.
+ test -f "$dirpart/$file" && continue
+ fdir=`AS_DIRNAME(["$file"])`
+ AS_MKDIR_P([$dirpart/$fdir])
+ # echo "creating $dirpart/$file"
+ echo '# dummy' > "$dirpart/$file"
+ done
+done
+])# _AM_OUTPUT_DEPENDENCY_COMMANDS
+
+
+# AM_OUTPUT_DEPENDENCY_COMMANDS
+# -----------------------------
+# This macro should only be invoked once -- use via AC_REQUIRE.
+#
+# This code is only required when automatic dependency tracking
+# is enabled. FIXME. This creates each `.P' file that we will
+# need in order to bootstrap the dependency handling code.
+AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
+[AC_CONFIG_COMMANDS([depfiles],
+ [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
+ [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"])
+])
+
+# Do all the work for Automake. -*- Autoconf -*-
+
+# This macro actually does too much some checks are only needed if
+# your package does certain things. But this isn't really a big deal.
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+# Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program 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 General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# serial 11
+
+# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
+# AM_INIT_AUTOMAKE([OPTIONS])
+# -----------------------------------------------
+# The call with PACKAGE and VERSION arguments is the old style
+# call (pre autoconf-2.50), which is being phased out. PACKAGE
+# and VERSION should now be passed to AC_INIT and removed from
+# the call to AM_INIT_AUTOMAKE.
+# We support both call styles for the transition. After
+# the next Automake release, Autoconf can make the AC_INIT
+# arguments mandatory, and then we can depend on a new Autoconf
+# release and drop the old call support.
+AC_DEFUN([AM_INIT_AUTOMAKE],
+[AC_PREREQ([2.58])dnl
+dnl Autoconf wants to disallow AM_ names. We explicitly allow
+dnl the ones we care about.
+m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
+AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
+AC_REQUIRE([AC_PROG_INSTALL])dnl
+# test to see if srcdir already configured
+if test "`cd $srcdir && pwd`" != "`pwd`" &&
+ test -f $srcdir/config.status; then
+ AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+ if (cygpath --version) >/dev/null 2>/dev/null; then
+ CYGPATH_W='cygpath -w'
+ else
+ CYGPATH_W=echo
+ fi
+fi
+AC_SUBST([CYGPATH_W])
+
+# Define the identity of the package.
+dnl Distinguish between old-style and new-style calls.
+m4_ifval([$2],
+[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
+ AC_SUBST([PACKAGE], [$1])dnl
+ AC_SUBST([VERSION], [$2])],
+[_AM_SET_OPTIONS([$1])dnl
+ AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
+ AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
+
+_AM_IF_OPTION([no-define],,
+[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
+ AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl
+
+# Some tools Automake needs.
+AC_REQUIRE([AM_SANITY_CHECK])dnl
+AC_REQUIRE([AC_ARG_PROGRAM])dnl
+AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version})
+AM_MISSING_PROG(AUTOCONF, autoconf)
+AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version})
+AM_MISSING_PROG(AUTOHEADER, autoheader)
+AM_MISSING_PROG(MAKEINFO, makeinfo)
+AM_PROG_INSTALL_SH
+AM_PROG_INSTALL_STRIP
+AC_REQUIRE([AM_PROG_MKDIR_P])dnl
+# We need awk for the "check" target. The system "awk" is bad on
+# some platforms.
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([AC_PROG_MAKE_SET])dnl
+AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
+ [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
+ [_AM_PROG_TAR([v7])])])
+_AM_IF_OPTION([no-dependencies],,
+[AC_PROVIDE_IFELSE([AC_PROG_CC],
+ [_AM_DEPENDENCIES(CC)],
+ [define([AC_PROG_CC],
+ defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_CXX],
+ [_AM_DEPENDENCIES(CXX)],
+ [define([AC_PROG_CXX],
+ defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl
+])
+])
+
+
+# When config.status generates a header, we must update the stamp-h file.
+# This file resides in the same directory as the config header
+# that is generated. The stamp files are numbered to have different names.
+
+# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
+# loop where config.status creates the headers, so we can generate
+# our stamp files there.
+AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
+[# Compute $1's index in $config_headers.
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+ case $_am_header in
+ $1 | $1:* )
+ break ;;
+ * )
+ _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+ esac
+done
+echo "timestamp for $1" >`AS_DIRNAME([$1])`/stamp-h[]$_am_stamp_count])
+
+# AM_PROG_INSTALL_SH
+# ------------------
+# Define $install_sh.
+
+# Copyright (C) 2001, 2003 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program 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 General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+AC_DEFUN([AM_PROG_INSTALL_SH],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+install_sh=${install_sh-"$am_aux_dir/install-sh"}
+AC_SUBST(install_sh)])
+
+# -*- Autoconf -*-
+# Copyright (C) 2003 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program 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 General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# serial 1
+
+# Check whether the underlying file-system supports filenames
+# with a leading dot. For instance MS-DOS doesn't.
+AC_DEFUN([AM_SET_LEADING_DOT],
+[rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+ am__leading_dot=.
+else
+ am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+AC_SUBST([am__leading_dot])])
+
+# Add --enable-maintainer-mode option to configure.
+# From Jim Meyering
+
+# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004
+# Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program 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 General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# serial 3
+
+AC_DEFUN([AM_MAINTAINER_MODE],
+[AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
+ dnl maintainer-mode is disabled by default
+ AC_ARG_ENABLE(maintainer-mode,
+[ --enable-maintainer-mode enable make rules and dependencies not useful
+ (and sometimes confusing) to the casual installer],
+ USE_MAINTAINER_MODE=$enableval,
+ USE_MAINTAINER_MODE=no)
+ AC_MSG_RESULT([$USE_MAINTAINER_MODE])
+ AM_CONDITIONAL(MAINTAINER_MODE, [test $USE_MAINTAINER_MODE = yes])
+ MAINT=$MAINTAINER_MODE_TRUE
+ AC_SUBST(MAINT)dnl
+]
+)
+
+AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE])
+
+# Check to see how 'make' treats includes. -*- Autoconf -*-
+
+# Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program 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 General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# serial 2
+
+# AM_MAKE_INCLUDE()
+# -----------------
+# Check to see how make treats includes.
+AC_DEFUN([AM_MAKE_INCLUDE],
+[am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+ @echo done
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+AC_MSG_CHECKING([for style of include used by $am_make])
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# We grep out `Entering directory' and `Leaving directory'
+# messages which can occur if `w' ends up in MAKEFLAGS.
+# In particular we don't look at `^make:' because GNU make might
+# be invoked under some other name (usually "gmake"), in which
+# case it prints its new name instead of `make'.
+if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then
+ am__include=include
+ am__quote=
+ _am_result=GNU
+fi
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+ echo '.include "confinc"' > confmf
+ if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then
+ am__include=.include
+ am__quote="\""
+ _am_result=BSD
+ fi
+fi
+AC_SUBST([am__include])
+AC_SUBST([am__quote])
+AC_MSG_RESULT([$_am_result])
+rm -f confinc confmf
+])
+
+# -*- Autoconf -*-
+
+
+# Copyright (C) 1997, 1999, 2000, 2001, 2003 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program 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 General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# serial 3
+
+# AM_MISSING_PROG(NAME, PROGRAM)
+# ------------------------------
+AC_DEFUN([AM_MISSING_PROG],
+[AC_REQUIRE([AM_MISSING_HAS_RUN])
+$1=${$1-"${am_missing_run}$2"}
+AC_SUBST($1)])
+
+
+# AM_MISSING_HAS_RUN
+# ------------------
+# Define MISSING if not defined so far and test if it supports --run.
+# If it does, set am_missing_run to use it, otherwise, to nothing.
+AC_DEFUN([AM_MISSING_HAS_RUN],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing"
+# Use eval to expand $SHELL
+if eval "$MISSING --run true"; then
+ am_missing_run="$MISSING --run "
+else
+ am_missing_run=
+ AC_MSG_WARN([`missing' script is too old or missing])
+fi
+])
+
+# AM_PROG_MKDIR_P
+# ---------------
+# Check whether `mkdir -p' is supported, fallback to mkinstalldirs otherwise.
+
+# Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program 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 General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# Automake 1.8 used `mkdir -m 0755 -p --' to ensure that directories
+# created by `make install' are always world readable, even if the
+# installer happens to have an overly restrictive umask (e.g. 077).
+# This was a mistake. There are at least two reasons why we must not
+# use `-m 0755':
+# - it causes special bits like SGID to be ignored,
+# - it may be too restrictive (some setups expect 775 directories).
+#
+# Do not use -m 0755 and let people choose whatever they expect by
+# setting umask.
+#
+# We cannot accept any implementation of `mkdir' that recognizes `-p'.
+# Some implementations (such as Solaris 8's) are not thread-safe: if a
+# parallel make tries to run `mkdir -p a/b' and `mkdir -p a/c'
+# concurrently, both version can detect that a/ is missing, but only
+# one can create it and the other will error out. Consequently we
+# restrict ourselves to GNU make (using the --version option ensures
+# this.)
+AC_DEFUN([AM_PROG_MKDIR_P],
+[if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then
+ # We used to keeping the `.' as first argument, in order to
+ # allow $(mkdir_p) to be used without argument. As in
+ # $(mkdir_p) $(somedir)
+ # where $(somedir) is conditionally defined. However this is wrong
+ # for two reasons:
+ # 1. if the package is installed by a user who cannot write `.'
+ # make install will fail,
+ # 2. the above comment should most certainly read
+ # $(mkdir_p) $(DESTDIR)$(somedir)
+ # so it does not work when $(somedir) is undefined and
+ # $(DESTDIR) is not.
+ # To support the latter case, we have to write
+ # test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir),
+ # so the `.' trick is pointless.
+ mkdir_p='mkdir -p --'
+else
+ # On NextStep and OpenStep, the `mkdir' command does not
+ # recognize any option. It will interpret all options as
+ # directories to create, and then abort because `.' already
+ # exists.
+ for d in ./-p ./--version;
+ do
+ test -d $d && rmdir $d
+ done
+ # $(mkinstalldirs) is defined by Automake if mkinstalldirs exists.
+ if test -f "$ac_aux_dir/mkinstalldirs"; then
+ mkdir_p='$(mkinstalldirs)'
+ else
+ mkdir_p='$(install_sh) -d'
+ fi
+fi
+AC_SUBST([mkdir_p])])
+
+# Helper functions for option handling. -*- Autoconf -*-
+
+# Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program 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 General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# serial 2
+
+# _AM_MANGLE_OPTION(NAME)
+# -----------------------
+AC_DEFUN([_AM_MANGLE_OPTION],
+[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
+
+# _AM_SET_OPTION(NAME)
+# ------------------------------
+# Set option NAME. Presently that only means defining a flag for this option.
+AC_DEFUN([_AM_SET_OPTION],
+[m4_define(_AM_MANGLE_OPTION([$1]), 1)])
+
+# _AM_SET_OPTIONS(OPTIONS)
+# ----------------------------------
+# OPTIONS is a space-separated list of Automake options.
+AC_DEFUN([_AM_SET_OPTIONS],
+[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
+
+# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
+# -------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+AC_DEFUN([_AM_IF_OPTION],
+[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
+
+#
+# Check to make sure that the build environment is sane.
+#
+
+# Copyright (C) 1996, 1997, 2000, 2001, 2003 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program 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 General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# serial 3
+
+# AM_SANITY_CHECK
+# ---------------
+AC_DEFUN([AM_SANITY_CHECK],
+[AC_MSG_CHECKING([whether build environment is sane])
+# Just in case
+sleep 1
+echo timestamp > conftest.file
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null`
+ if test "$[*]" = "X"; then
+ # -L didn't work.
+ set X `ls -t $srcdir/configure conftest.file`
+ fi
+ rm -f conftest.file
+ if test "$[*]" != "X $srcdir/configure conftest.file" \
+ && test "$[*]" != "X conftest.file $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken
+alias in your environment])
+ fi
+
+ test "$[2]" = conftest.file
+ )
+then
+ # Ok.
+ :
+else
+ AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+AC_MSG_RESULT(yes)])
+
+# AM_PROG_INSTALL_STRIP
+
+# Copyright (C) 2001, 2003 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program 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 General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# One issue with vendor `install' (even GNU) is that you can't
+# specify the program used to strip binaries. This is especially
+# annoying in cross-compiling environments, where the build's strip
+# is unlikely to handle the host's binaries.
+# Fortunately install-sh will honor a STRIPPROG variable, so we
+# always use install-sh in `make install-strip', and initialize
+# STRIPPROG with the value of the STRIP variable (set by the user).
+AC_DEFUN([AM_PROG_INSTALL_STRIP],
+[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+# Installed binaries are usually stripped using `strip' when the user
+# run `make install-strip'. However `strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the `STRIP' environment variable to overrule this program.
+dnl Don't test for $cross_compiling = yes, because it might be `maybe'.
+if test "$cross_compiling" != no; then
+ AC_CHECK_TOOL([STRIP], [strip], :)
+fi
+INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s"
+AC_SUBST([INSTALL_STRIP_PROGRAM])])
+
+# Check how to create a tarball. -*- Autoconf -*-
+
+# Copyright (C) 2004 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program 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 General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# serial 1
+
+
+# _AM_PROG_TAR(FORMAT)
+# --------------------
+# Check how to create a tarball in format FORMAT.
+# FORMAT should be one of `v7', `ustar', or `pax'.
+#
+# Substitute a variable $(am__tar) that is a command
+# writing to stdout a FORMAT-tarball containing the directory
+# $tardir.
+# tardir=directory && $(am__tar) > result.tar
+#
+# Substitute a variable $(am__untar) that extract such
+# a tarball read from stdin.
+# $(am__untar) < result.tar
+AC_DEFUN([_AM_PROG_TAR],
+[# Always define AMTAR for backward compatibility.
+AM_MISSING_PROG([AMTAR], [tar])
+m4_if([$1], [v7],
+ [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'],
+ [m4_case([$1], [ustar],, [pax],,
+ [m4_fatal([Unknown tar format])])
+AC_MSG_CHECKING([how to create a $1 tar archive])
+# Loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
+_am_tools=${am_cv_prog_tar_$1-$_am_tools}
+# Do not fold the above two line into one, because Tru64 sh and
+# Solaris sh will not grok spaces in the rhs of `-'.
+for _am_tool in $_am_tools
+do
+ case $_am_tool in
+ gnutar)
+ for _am_tar in tar gnutar gtar;
+ do
+ AM_RUN_LOG([$_am_tar --version]) && break
+ done
+ am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
+ am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
+ am__untar="$_am_tar -xf -"
+ ;;
+ plaintar)
+ # Must skip GNU tar: if it does not support --format= it doesn't create
+ # ustar tarball either.
+ (tar --version) >/dev/null 2>&1 && continue
+ am__tar='tar chf - "$$tardir"'
+ am__tar_='tar chf - "$tardir"'
+ am__untar='tar xf -'
+ ;;
+ pax)
+ am__tar='pax -L -x $1 -w "$$tardir"'
+ am__tar_='pax -L -x $1 -w "$tardir"'
+ am__untar='pax -r'
+ ;;
+ cpio)
+ am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
+ am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
+ am__untar='cpio -i -H $1 -d'
+ ;;
+ none)
+ am__tar=false
+ am__tar_=false
+ am__untar=false
+ ;;
+ esac
+
+ # If the value was cached, stop now. We just wanted to have am__tar
+ # and am__untar set.
+ test -n "${am_cv_prog_tar_$1}" && break
+
+ # tar/untar a dummy directory, and stop if the command works
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ echo GrepMe > conftest.dir/file
+ AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
+ rm -rf conftest.dir
+ if test -s conftest.tar; then
+ AM_RUN_LOG([$am__untar <conftest.tar])
+ grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
+ fi
+done
+rm -rf conftest.dir
+
+AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
+AC_MSG_RESULT([$am_cv_prog_tar_$1])])
+AC_SUBST([am__tar])
+AC_SUBST([am__untar])
+]) # _AM_PROG_TAR
+
+m4_include([m4/sac-general.m4])
+m4_include([m4/sac-openssl.m4])
+m4_include([m4/sac-su.m4])
+m4_include([m4/sac-su2.m4])
+m4_include([m4/sac-tport.m4])
Added: freeswitch/trunk/libs/sofia-sip/autogen.sh
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/autogen.sh Thu Dec 21 01:30:28 2006
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+set -x
+${AUTORECONF:-autoreconf} -i
+find . \( -name 'run*' -o -name '*.sh' \) -a -type f | xargs chmod +x
+chmod +x scripts/*
Added: freeswitch/trunk/libs/sofia-sip/compile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/compile Thu Dec 21 01:30:28 2006
@@ -0,0 +1,140 @@
+#! /bin/sh
+# Wrapper for compilers which do not understand `-c -o'.
+
+scriptversion=2004-09-10.20
+
+# Copyright (C) 1999, 2000, 2003, 2004 Free Software Foundation, Inc.
+# Written by Tom Tromey <tromey at cygnus.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake at gnu.org> or send patches to
+# <automake-patches at gnu.org>.
+
+case $1 in
+ '')
+ echo "$0: No command. Try \`$0 --help' for more information." 1>&2
+ exit 1;
+ ;;
+ -h | --h*)
+ cat <<\EOF
+Usage: compile [--help] [--version] PROGRAM [ARGS]
+
+Wrapper for compilers which do not understand `-c -o'.
+Remove `-o dest.o' from ARGS, run PROGRAM with the remaining
+arguments, and rename the output as expected.
+
+If you are trying to build a whole package this is not the
+right script to run: please start by reading the file `INSTALL'.
+
+Report bugs to <bug-automake at gnu.org>.
+EOF
+ exit 0
+ ;;
+ -v | --v*)
+ echo "compile $scriptversion"
+ exit 0
+ ;;
+esac
+
+ofile=
+cfile=
+eat=
+
+for arg
+do
+ if test -n "$eat"; then
+ eat=
+ else
+ case $1 in
+ -o)
+ # configure might choose to run compile as `compile cc -o foo foo.c'.
+ # So we strip `-o arg' only if arg is an object.
+ eat=1
+ case $2 in
+ *.o | *.obj)
+ ofile=$2
+ ;;
+ *)
+ set x "$@" -o "$2"
+ shift
+ ;;
+ esac
+ ;;
+ *.c)
+ cfile=$1
+ set x "$@" "$1"
+ shift
+ ;;
+ *)
+ set x "$@" "$1"
+ shift
+ ;;
+ esac
+ fi
+ shift
+done
+
+if test -z "$ofile" || test -z "$cfile"; then
+ # If no `-o' option was seen then we might have been invoked from a
+ # pattern rule where we don't need one. That is ok -- this is a
+ # normal compilation that the losing compiler can handle. If no
+ # `.c' file was seen then we are probably linking. That is also
+ # ok.
+ exec "$@"
+fi
+
+# Name of file we expect compiler to create.
+cofile=`echo "$cfile" | sed -e 's|^.*/||' -e 's/\.c$/.o/'`
+
+# Create the lock directory.
+# Note: use `[/.-]' here to ensure that we don't use the same name
+# that we are using for the .o file. Also, base the name on the expected
+# object file name, since that is what matters with a parallel build.
+lockdir=`echo "$cofile" | sed -e 's|[/.-]|_|g'`.d
+while true; do
+ if mkdir "$lockdir" >/dev/null 2>&1; then
+ break
+ fi
+ sleep 1
+done
+# FIXME: race condition here if user kills between mkdir and trap.
+trap "rmdir '$lockdir'; exit 1" 1 2 15
+
+# Run the compile.
+"$@"
+ret=$?
+
+if test -f "$cofile"; then
+ mv "$cofile" "$ofile"
+fi
+
+rmdir "$lockdir"
+exit $ret
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
Added: freeswitch/trunk/libs/sofia-sip/config.guess
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/config.guess Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1411 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+
+timestamp='2003-06-17'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Per Bothner <per at bothner.com>.
+# Please send patches to <config-patches at gnu.org>. Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub. If it succeeds, it prints the system name on stdout, and
+# exits with 0. Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit build system type.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches at gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit 0 ;;
+ --version | -v )
+ echo "$version" ; exit 0 ;;
+ --help | --h* | -h )
+ echo "$usage"; exit 0 ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help" >&2
+ exit 1 ;;
+ * )
+ break ;;
+ esac
+done
+
+if test $# != 0; then
+ echo "$me: too many arguments$help" >&2
+ exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,) echo "int x;" > $dummy.c ;
+ for c in cc gcc c89 c99 ; do
+ if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+ CC_FOR_BUILD="$c"; break ;
+ fi ;
+ done ;
+ if test x"$CC_FOR_BUILD" = x ; then
+ CC_FOR_BUILD=no_compiler_found ;
+ fi
+ ;;
+ ,,*) CC_FOR_BUILD=$CC ;;
+ ,*,*) CC_FOR_BUILD=$HOST_CC ;;
+esac ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi at noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+ PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+## for Red Hat Linux
+if test -f /etc/redhat-release ; then
+ VENDOR=redhat ;
+else
+ VENDOR= ;
+fi
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+ *:NetBSD:*:*)
+ # NetBSD (nbsd) targets should (where applicable) match one or
+ # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+ # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
+ # switched to ELF, *-*-netbsd* would select the old
+ # object file format. This provides both forward
+ # compatibility and a consistent mechanism for selecting the
+ # object file format.
+ #
+ # Note: NetBSD doesn't particularly care about the vendor
+ # portion of the name. We always set it to "unknown".
+ sysctl="sysctl -n hw.machine_arch"
+ UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+ /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+ case "${UNAME_MACHINE_ARCH}" in
+ armeb) machine=armeb-unknown ;;
+ arm*) machine=arm-unknown ;;
+ sh3el) machine=shl-unknown ;;
+ sh3eb) machine=sh-unknown ;;
+ *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+ esac
+ # The Operating System including object format, if it has switched
+ # to ELF recently, or will in the future.
+ case "${UNAME_MACHINE_ARCH}" in
+ arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+ eval $set_cc_for_build
+ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep __ELF__ >/dev/null
+ then
+ # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+ # Return netbsd for either. FIX?
+ os=netbsd
+ else
+ os=netbsdelf
+ fi
+ ;;
+ *)
+ os=netbsd
+ ;;
+ esac
+ # The OS release
+ # Debian GNU/NetBSD machines have a different userland, and
+ # thus, need a distinct triplet. However, they do not need
+ # kernel version information, so it can be replaced with a
+ # suitable tag, in the style of linux-gnu.
+ case "${UNAME_VERSION}" in
+ Debian*)
+ release='-gnu'
+ ;;
+ *)
+ release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ ;;
+ esac
+ # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+ # contains redundant information, the shorter form:
+ # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+ echo "${machine}-${os}${release}"
+ exit 0 ;;
+ amiga:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ arc:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ hp300:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mac68k:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ macppc:OpenBSD:*:*)
+ echo powerpc-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mvme68k:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mvme88k:OpenBSD:*:*)
+ echo m88k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mvmeppc:OpenBSD:*:*)
+ echo powerpc-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ pmax:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ sgi:OpenBSD:*:*)
+ echo mipseb-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ sun3:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ wgrisc:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ *:OpenBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ alpha:OSF1:*:*)
+ if test $UNAME_RELEASE = "V4.0"; then
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+ fi
+ # According to Compaq, /usr/sbin/psrinfo has been available on
+ # OSF/1 and Tru64 systems produced since 1995. I hope that
+ # covers most systems running today. This code pipes the CPU
+ # types through head -n 1, so we only detect the type of CPU 0.
+ ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+ case "$ALPHA_CPU_TYPE" in
+ "EV4 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "EV4.5 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "LCA4 (21066/21068)")
+ UNAME_MACHINE="alpha" ;;
+ "EV5 (21164)")
+ UNAME_MACHINE="alphaev5" ;;
+ "EV5.6 (21164A)")
+ UNAME_MACHINE="alphaev56" ;;
+ "EV5.6 (21164PC)")
+ UNAME_MACHINE="alphapca56" ;;
+ "EV5.7 (21164PC)")
+ UNAME_MACHINE="alphapca57" ;;
+ "EV6 (21264)")
+ UNAME_MACHINE="alphaev6" ;;
+ "EV6.7 (21264A)")
+ UNAME_MACHINE="alphaev67" ;;
+ "EV6.8CB (21264C)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8AL (21264B)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8CX (21264D)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.9A (21264/EV69A)")
+ UNAME_MACHINE="alphaev69" ;;
+ "EV7 (21364)")
+ UNAME_MACHINE="alphaev7" ;;
+ "EV7.9 (21364A)")
+ UNAME_MACHINE="alphaev79" ;;
+ esac
+ # A Vn.n version is a released version.
+ # A Tn.n version is a released field test version.
+ # A Xn.n version is an unreleased experimental baselevel.
+ # 1.2 uses "1.2" for uname -r.
+ echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ exit 0 ;;
+ Alpha*:OpenVMS:*:*)
+ echo alpha-hp-vms
+ exit 0 ;;
+ Alpha\ *:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # Should we change UNAME_MACHINE based on the output of uname instead
+ # of the specific Alpha model?
+ echo alpha-pc-interix
+ exit 0 ;;
+ 21064:Windows_NT:50:3)
+ echo alpha-dec-winnt3.5
+ exit 0 ;;
+ Amiga*:UNIX_System_V:4.0:*)
+ echo m68k-unknown-sysv4
+ exit 0;;
+ *:[Aa]miga[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-amigaos
+ exit 0 ;;
+ *:[Mm]orph[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-morphos
+ exit 0 ;;
+ *:OS/390:*:*)
+ echo i370-ibm-openedition
+ exit 0 ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix${UNAME_RELEASE}
+ exit 0;;
+ SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+ echo hppa1.1-hitachi-hiuxmpp
+ exit 0;;
+ Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+ # akee at wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+ if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ echo pyramid-pyramid-sysv3
+ else
+ echo pyramid-pyramid-bsd
+ fi
+ exit 0 ;;
+ NILE*:*:*:dcosx)
+ echo pyramid-pyramid-svr4
+ exit 0 ;;
+ DRS?6000:unix:4.0:6*)
+ echo sparc-icl-nx6
+ exit 0 ;;
+ DRS?6000:UNIX_SV:4.2*:7*)
+ case `/usr/bin/uname -p` in
+ sparc) echo sparc-icl-nx7 && exit 0 ;;
+ esac ;;
+ sun4H:SunOS:5.*:*)
+ echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+ echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ i86pc:SunOS:5.*:*)
+ echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:6*:*)
+ # According to config.sub, this is the proper way to canonicalize
+ # SunOS6. Hard to guess exactly what SunOS6 will be like, but
+ # it's likely to be more like Solaris than SunOS4.
+ echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:*:*)
+ case "`/usr/bin/arch -k`" in
+ Series*|S4*)
+ UNAME_RELEASE=`uname -v`
+ ;;
+ esac
+ # Japanese Language versions have a version number like `4.1.3-JL'.
+ echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+ exit 0 ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ exit 0 ;;
+ sun*:*:4.2BSD:*)
+ UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+ case "`/bin/arch`" in
+ sun3)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ ;;
+ sun4)
+ echo sparc-sun-sunos${UNAME_RELEASE}
+ ;;
+ esac
+ exit 0 ;;
+ aushp:SunOS:*:*)
+ echo sparc-auspex-sunos${UNAME_RELEASE}
+ exit 0 ;;
+ # The situation for MiNT is a little confusing. The machine name
+ # can be virtually everything (everything which is not
+ # "atarist" or "atariste" at least should have a processor
+ # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
+ # to the lowercase version "mint" (or "freemint"). Finally
+ # the system name "TOS" denotes a system which is actually not
+ # MiNT. But MiNT is downward compatible to TOS, so this should
+ # be no problem.
+ atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit 0 ;;
+ atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit 0 ;;
+ *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit 0 ;;
+ milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+ echo m68k-milan-mint${UNAME_RELEASE}
+ exit 0 ;;
+ hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+ echo m68k-hades-mint${UNAME_RELEASE}
+ exit 0 ;;
+ *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+ echo m68k-unknown-mint${UNAME_RELEASE}
+ exit 0 ;;
+ powerpc:machten:*:*)
+ echo powerpc-apple-machten${UNAME_RELEASE}
+ exit 0 ;;
+ RISC*:Mach:*:*)
+ echo mips-dec-mach_bsd4.3
+ exit 0 ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix${UNAME_RELEASE}
+ exit 0 ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix${UNAME_RELEASE}
+ exit 0 ;;
+ 2020:CLIX:*:* | 2430:CLIX:*:*)
+ echo clipper-intergraph-clix${UNAME_RELEASE}
+ exit 0 ;;
+ mips:*:*:UMIPS | mips:*:*:RISCos)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h> /* for printf() prototype */
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+ #if defined (host_mips) && defined (MIPSEB)
+ #if defined (SYSTYPE_SYSV)
+ printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_SVR4)
+ printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+ printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+ #endif
+ #endif
+ exit (-1);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c \
+ && $dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
+ && exit 0
+ echo mips-mips-riscos${UNAME_RELEASE}
+ exit 0 ;;
+ Motorola:PowerMAX_OS:*:*)
+ echo powerpc-motorola-powermax
+ exit 0 ;;
+ Motorola:*:4.3:PL8-*)
+ echo powerpc-harris-powermax
+ exit 0 ;;
+ Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+ echo powerpc-harris-powermax
+ exit 0 ;;
+ Night_Hawk:Power_UNIX:*:*)
+ echo powerpc-harris-powerunix
+ exit 0 ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit 0 ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit 0 ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit 0 ;;
+ AViiON:dgux:*:*)
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+ then
+ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+ [ ${TARGET_BINARY_INTERFACE}x = x ]
+ then
+ echo m88k-dg-dgux${UNAME_RELEASE}
+ else
+ echo m88k-dg-dguxbcs${UNAME_RELEASE}
+ fi
+ else
+ echo i586-dg-dgux${UNAME_RELEASE}
+ fi
+ exit 0 ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit 0 ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit 0 ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit 0 ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit 0 ;;
+ *:IRIX*:*:*)
+ echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+ exit 0 ;;
+ ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+ echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ i*86:AIX:*:*)
+ echo i386-ibm-aix
+ exit 0 ;;
+ ia64:AIX:*:*)
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+ exit 0 ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <sys/systemcfg.h>
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0
+ echo rs6000-ibm-aix3.2.5
+ elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+ echo rs6000-ibm-aix3.2.4
+ else
+ echo rs6000-ibm-aix3.2
+ fi
+ exit 0 ;;
+ *:AIX:*:[45])
+ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+ if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+ exit 0 ;;
+ *:AIX:*:*)
+ echo rs6000-ibm-aix
+ exit 0 ;;
+ ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+ echo romp-ibm-bsd4.4
+ exit 0 ;;
+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
+ echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
+ exit 0 ;; # report: romp-ibm BSD 4.3
+ *:BOSX:*:*)
+ echo rs6000-bull-bosx
+ exit 0 ;;
+ DPX/2?00:B.O.S.:*:*)
+ echo m68k-bull-sysv3
+ exit 0 ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ echo m68k-hp-bsd
+ exit 0 ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ echo m68k-hp-bsd4.4
+ exit 0 ;;
+ 9000/[34678]??:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ case "${UNAME_MACHINE}" in
+ 9000/31? ) HP_ARCH=m68000 ;;
+ 9000/[34]?? ) HP_ARCH=m68k ;;
+ 9000/[678][0-9][0-9])
+ if [ -x /usr/bin/getconf ]; then
+ sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+ case "${sc_cpu_version}" in
+ 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+ 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+ 532) # CPU_PA_RISC2_0
+ case "${sc_kernel_bits}" in
+ 32) HP_ARCH="hppa2.0n" ;;
+ 64) HP_ARCH="hppa2.0w" ;;
+ '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
+ esac ;;
+ esac
+ fi
+ if [ "${HP_ARCH}" = "" ]; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+
+ #define _HPUX_SOURCE
+ #include <stdlib.h>
+ #include <unistd.h>
+
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
+
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
+EOF
+ (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+ test -z "$HP_ARCH" && HP_ARCH=hppa
+ fi ;;
+ esac
+ if [ ${HP_ARCH} = "hppa2.0w" ]
+ then
+ # avoid double evaluation of $set_cc_for_build
+ test -n "$CC_FOR_BUILD" || eval $set_cc_for_build
+ if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E -) | grep __LP64__ >/dev/null
+ then
+ HP_ARCH="hppa2.0w"
+ else
+ HP_ARCH="hppa64"
+ fi
+ fi
+ echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+ exit 0 ;;
+ ia64:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ echo ia64-hp-hpux${HPUX_REV}
+ exit 0 ;;
+ 3050*:HI-UX:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <unistd.h>
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0
+ echo unknown-hitachi-hiuxwe2
+ exit 0 ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+ echo hppa1.1-hp-bsd
+ exit 0 ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit 0 ;;
+ *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+ echo hppa1.0-hp-mpeix
+ exit 0 ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+ echo hppa1.1-hp-osf
+ exit 0 ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit 0 ;;
+ i*86:OSF1:*:*)
+ if [ -x /usr/sbin/sysversion ] ; then
+ echo ${UNAME_MACHINE}-unknown-osf1mk
+ else
+ echo ${UNAME_MACHINE}-unknown-osf1
+ fi
+ exit 0 ;;
+ parisc*:Lites*:*:*)
+ echo hppa1.1-hp-lites
+ exit 0 ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit 0 ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit 0 ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit 0 ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit 0 ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit 0 ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY*[A-Z]90:*:*:*)
+ echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+ -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY*TS:*:*:*)
+ echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY*T3E:*:*:*)
+ echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY*SV1:*:*:*)
+ echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ *:UNICOS/mp:*:*)
+ echo nv1-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+ FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit 0 ;;
+ i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+ echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+ exit 0 ;;
+ sparc*:BSD/OS:*:*)
+ echo sparc-unknown-bsdi${UNAME_RELEASE}
+ exit 0 ;;
+ *:BSD/OS:*:*)
+ echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+ exit 0 ;;
+ *:FreeBSD:*:*|*:GNU/FreeBSD:*:*)
+ # Determine whether the default compiler uses glibc.
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <features.h>
+ #if __GLIBC__ >= 2
+ LIBC=gnu
+ #else
+ LIBC=
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=`
+ echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`${LIBC:+-$LIBC}
+ exit 0 ;;
+ i*:CYGWIN*:*)
+ echo ${UNAME_MACHINE}-pc-cygwin
+ exit 0 ;;
+ i*:MINGW*:*)
+ echo ${UNAME_MACHINE}-pc-mingw32
+ exit 0 ;;
+ i*:PW*:*)
+ echo ${UNAME_MACHINE}-pc-pw32
+ exit 0 ;;
+ x86:Interix*:[34]*)
+ echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//'
+ exit 0 ;;
+ [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+ echo i${UNAME_MACHINE}-pc-mks
+ exit 0 ;;
+ i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+ # UNAME_MACHINE based on the output of uname instead of i386?
+ echo i586-pc-interix
+ exit 0 ;;
+ i*:UWIN*:*)
+ echo ${UNAME_MACHINE}-pc-uwin
+ exit 0 ;;
+ p*:CYGWIN*:*)
+ echo powerpcle-unknown-cygwin
+ exit 0 ;;
+ prep*:SunOS:5.*:*)
+ echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ *:GNU:*:*)
+ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+ exit 0 ;;
+ i*86:Minix:*:*)
+ echo ${UNAME_MACHINE}-pc-minix
+ exit 0 ;;
+ arm*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit 0 ;;
+ cris:Linux:*:*)
+ echo cris-axis-linux-gnu
+ exit 0 ;;
+ ia64:Linux:*:*)
+ echo ${UNAME_MACHINE}-${VENDOR:-unknown}-linux-gnu
+ exit 0 ;;
+ m68*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit 0 ;;
+ mips:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef mips
+ #undef mipsel
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=mipsel
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=mips
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=`
+ test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0
+ ;;
+ mips64:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef mips64
+ #undef mips64el
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=mips64el
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=mips64
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=`
+ test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0
+ ;;
+ ppc:Linux:*:*)
+ echo powerpc-${VENDOR:-unknown}-linux-gnu
+ exit 0 ;;
+ ppc64:Linux:*:*)
+ echo powerpc64-${VENDOR:-unknown}-linux-gnu
+ exit 0 ;;
+ alpha:Linux:*:*)
+ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+ EV5) UNAME_MACHINE=alphaev5 ;;
+ EV56) UNAME_MACHINE=alphaev56 ;;
+ PCA56) UNAME_MACHINE=alphapca56 ;;
+ PCA57) UNAME_MACHINE=alphapca56 ;;
+ EV6) UNAME_MACHINE=alphaev6 ;;
+ EV67) UNAME_MACHINE=alphaev67 ;;
+ EV68*) UNAME_MACHINE=alphaev68 ;;
+ esac
+ objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
+ if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+ echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+ exit 0 ;;
+ parisc:Linux:*:* | hppa:Linux:*:*)
+ # Look for CPU level
+ case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+ PA7*) echo hppa1.1-unknown-linux-gnu ;;
+ PA8*) echo hppa2.0-unknown-linux-gnu ;;
+ *) echo hppa-unknown-linux-gnu ;;
+ esac
+ exit 0 ;;
+ parisc64:Linux:*:* | hppa64:Linux:*:*)
+ echo hppa64-unknown-linux-gnu
+ exit 0 ;;
+ s390:Linux:*:* | s390x:Linux:*:*)
+ echo ${UNAME_MACHINE}-${VENDOR:-ibm}-linux-gnu
+ exit 0 ;;
+ sh64*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit 0 ;;
+ sh*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit 0 ;;
+ sparc:Linux:*:* | sparc64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit 0 ;;
+ x86_64:Linux:*:*)
+ echo x86_64-${VENDOR:-unknown}-linux-gnu
+ exit 0 ;;
+ i*86:Linux:*:*)
+ # The BFD linker knows what the default object file format is, so
+ # first see if it will tell us. cd to the root directory to prevent
+ # problems with other programs or directories called `ld' in the path.
+ # Set LC_ALL=C to ensure ld outputs messages in English.
+ ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
+ | sed -ne '/supported targets:/!d
+ s/[ ][ ]*/ /g
+ s/.*supported targets: *//
+ s/ .*//
+ p'`
+ case "$ld_supported_targets" in
+ elf32-i386)
+ TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+ ;;
+ a.out-i386-linux)
+ echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+ exit 0 ;;
+ coff-i386)
+ echo "${UNAME_MACHINE}-pc-linux-gnucoff"
+ exit 0 ;;
+ "")
+ # Either a pre-BFD a.out linker (linux-gnuoldld) or
+ # one that does not give us useful --help.
+ echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
+ exit 0 ;;
+ esac
+ # Determine whether the default compiler is a.out or elf
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <features.h>
+ #ifdef __ELF__
+ # ifdef __GLIBC__
+ # if __GLIBC__ >= 2
+ LIBC=gnu
+ # else
+ LIBC=gnulibc1
+ # endif
+ # else
+ LIBC=gnulibc1
+ # endif
+ #else
+ #ifdef __INTEL_COMPILER
+ LIBC=gnu
+ #else
+ LIBC=gnuaout
+ #endif
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=`
+ test x"${LIBC}" != x && echo "${UNAME_MACHINE}-${VENDOR:-pc}-linux-${LIBC}" && exit 0
+ test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0
+ ;;
+ i*86:DYNIX/ptx:4*:*)
+ # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+ # earlier versions are messed up and put the nodename in both
+ # sysname and nodename.
+ echo i386-sequent-sysv4
+ exit 0 ;;
+ i*86:UNIX_SV:4.2MP:2.*)
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
+ # I just have to hope. -- rms.
+ # Use sysv4.2uw... so that sysv4* matches it.
+ echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+ exit 0 ;;
+ i*86:OS/2:*:*)
+ # If we were able to find `uname', then EMX Unix compatibility
+ # is probably installed.
+ echo ${UNAME_MACHINE}-pc-os2-emx
+ exit 0 ;;
+ i*86:XTS-300:*:STOP)
+ echo ${UNAME_MACHINE}-unknown-stop
+ exit 0 ;;
+ i*86:atheos:*:*)
+ echo ${UNAME_MACHINE}-unknown-atheos
+ exit 0 ;;
+ i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
+ echo i386-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ i*86:*DOS:*:*)
+ echo ${UNAME_MACHINE}-pc-msdosdjgpp
+ exit 0 ;;
+ i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+ UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+ else
+ echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+ fi
+ exit 0 ;;
+ i*86:*:5:[78]*)
+ case `/bin/uname -X | grep "^Machine"` in
+ *486*) UNAME_MACHINE=i486 ;;
+ *Pentium) UNAME_MACHINE=i586 ;;
+ *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+ esac
+ echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+ exit 0 ;;
+ i*86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+ elif /bin/uname -X 2>/dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+ && UNAME_MACHINE=i686
+ (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+ && UNAME_MACHINE=i686
+ echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+ else
+ echo ${UNAME_MACHINE}-pc-sysv32
+ fi
+ exit 0 ;;
+ pc:*:*:*)
+ # Left here for compatibility:
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i386.
+ echo i386-pc-msdosdjgpp
+ exit 0 ;;
+ Intel:Mach:3*:*)
+ echo i386-pc-mach3
+ exit 0 ;;
+ paragon:*:*:*)
+ echo i860-intel-osf1
+ exit 0 ;;
+ i860:*:4.*:*) # i860-SVR4
+ if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+ echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+ else # Add other i860-SVR4 vendors below as they are discovered.
+ echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
+ fi
+ exit 0 ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit 0 ;;
+ mc68k:UNIX:SYSTEM5:3.51m)
+ echo m68k-convergent-sysv
+ exit 0 ;;
+ M680?0:D-NIX:5.3:*)
+ echo m68k-diab-dnix
+ exit 0 ;;
+ M68*:*:R3V[567]*:*)
+ test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
+ 3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0)
+ OS_REL=''
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && echo i486-ncr-sysv4.3${OS_REL} && exit 0
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && echo i486-ncr-sysv4 && exit 0 ;;
+ m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+ echo m68k-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit 0 ;;
+ TSUNAMI:LynxOS:2.*:*)
+ echo sparc-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ rs6000:LynxOS:2.*:*)
+ echo rs6000-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
+ echo powerpc-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ SM[BE]S:UNIX_SV:*:*)
+ echo mips-dde-sysv${UNAME_RELEASE}
+ exit 0 ;;
+ RM*:ReliantUNIX-*:*:*)
+ echo mips-sni-sysv4
+ exit 0 ;;
+ RM*:SINIX-*:*:*)
+ echo mips-sni-sysv4
+ exit 0 ;;
+ *:SINIX-*:*:*)
+ if uname -p 2>/dev/null >/dev/null ; then
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ echo ${UNAME_MACHINE}-sni-sysv4
+ else
+ echo ns32k-sni-sysv
+ fi
+ exit 0 ;;
+ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says <Richard.M.Bartel at ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit 0 ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes at openmarket.com>.
+ # How about differentiating between stratus architectures? -djm
+ echo hppa1.1-stratus-sysv4
+ exit 0 ;;
+ *:*:*:FTX*)
+ # From seanf at swdc.stratus.com.
+ echo i860-stratus-sysv4
+ exit 0 ;;
+ *:VOS:*:*)
+ # From Paul.Green at stratus.com.
+ echo hppa1.1-stratus-vos
+ exit 0 ;;
+ mc68*:A/UX:*:*)
+ echo m68k-apple-aux${UNAME_RELEASE}
+ exit 0 ;;
+ news*:NEWS-OS:6*:*)
+ echo mips-sony-newsos6
+ exit 0 ;;
+ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+ if [ -d /usr/nec ]; then
+ echo mips-nec-sysv${UNAME_RELEASE}
+ else
+ echo mips-unknown-sysv${UNAME_RELEASE}
+ fi
+ exit 0 ;;
+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
+ echo powerpc-be-beos
+ exit 0 ;;
+ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
+ echo powerpc-apple-beos
+ exit 0 ;;
+ BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
+ echo i586-pc-beos
+ exit 0 ;;
+ SX-4:SUPER-UX:*:*)
+ echo sx4-nec-superux${UNAME_RELEASE}
+ exit 0 ;;
+ SX-5:SUPER-UX:*:*)
+ echo sx5-nec-superux${UNAME_RELEASE}
+ exit 0 ;;
+ SX-6:SUPER-UX:*:*)
+ echo sx6-nec-superux${UNAME_RELEASE}
+ exit 0 ;;
+ Power*:Rhapsody:*:*)
+ echo powerpc-apple-rhapsody${UNAME_RELEASE}
+ exit 0 ;;
+ *:Rhapsody:*:*)
+ echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+ exit 0 ;;
+ *:Darwin:*:*)
+ case `uname -p` in
+ *86) UNAME_PROCESSOR=i686 ;;
+ powerpc) UNAME_PROCESSOR=powerpc ;;
+ esac
+ echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+ exit 0 ;;
+ *:procnto*:*:* | *:QNX:[0123456789]*:*)
+ UNAME_PROCESSOR=`uname -p`
+ if test "$UNAME_PROCESSOR" = "x86"; then
+ UNAME_PROCESSOR=i386
+ UNAME_MACHINE=pc
+ fi
+ echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+ exit 0 ;;
+ *:QNX:*:4*)
+ echo i386-pc-qnx
+ exit 0 ;;
+ NSR-[DGKLNPTVW]:NONSTOP_KERNEL:*:*)
+ echo nsr-tandem-nsk${UNAME_RELEASE}
+ exit 0 ;;
+ *:NonStop-UX:*:*)
+ echo mips-compaq-nonstopux
+ exit 0 ;;
+ BS2000:POSIX*:*:*)
+ echo bs2000-siemens-sysv
+ exit 0 ;;
+ DS/*:UNIX_System_V:*:*)
+ echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+ exit 0 ;;
+ *:Plan9:*:*)
+ # "uname -m" is not consistent, so use $cputype instead. 386
+ # is converted to i386 for consistency with other x86
+ # operating systems.
+ if test "$cputype" = "386"; then
+ UNAME_MACHINE=i386
+ else
+ UNAME_MACHINE="$cputype"
+ fi
+ echo ${UNAME_MACHINE}-unknown-plan9
+ exit 0 ;;
+ *:TOPS-10:*:*)
+ echo pdp10-unknown-tops10
+ exit 0 ;;
+ *:TENEX:*:*)
+ echo pdp10-unknown-tenex
+ exit 0 ;;
+ KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+ echo pdp10-dec-tops20
+ exit 0 ;;
+ XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+ echo pdp10-xkl-tops20
+ exit 0 ;;
+ *:TOPS-20:*:*)
+ echo pdp10-unknown-tops20
+ exit 0 ;;
+ *:ITS:*:*)
+ echo pdp10-unknown-its
+ exit 0 ;;
+ SEI:*:*:SEIUX)
+ echo mips-sei-seiux${UNAME_RELEASE}
+ exit 0 ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+ /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
+ I don't know.... */
+ printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+ printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+ "4"
+#else
+ ""
+#endif
+ ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+ printf ("arm-acorn-riscix"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+ printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+ int version;
+ version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+ if (version < 4)
+ printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+ else
+ printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+ exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+ printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+ printf ("ns32k-encore-mach\n"); exit (0);
+#else
+ printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+ printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+ printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+ printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+ struct utsname un;
+
+ uname(&un);
+
+ if (strncmp(un.version, "V2", 2) == 0) {
+ printf ("i386-sequent-ptx2\n"); exit (0);
+ }
+ if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+ printf ("i386-sequent-ptx1\n"); exit (0);
+ }
+ printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+# include <sys/param.h>
+# if defined (BSD)
+# if BSD == 43
+ printf ("vax-dec-bsd4.3\n"); exit (0);
+# else
+# if BSD == 199006
+ printf ("vax-dec-bsd4.3reno\n"); exit (0);
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# endif
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# else
+ printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+ printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+ exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && $dummy && exit 0
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+ case `getsysinfo -f cpu_type` in
+ c1*)
+ echo c1-convex-bsd
+ exit 0 ;;
+ c2*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit 0 ;;
+ c34*)
+ echo c34-convex-bsd
+ exit 0 ;;
+ c38*)
+ echo c38-convex-bsd
+ exit 0 ;;
+ c4*)
+ echo c4-convex-bsd
+ exit 0 ;;
+ esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+ ftp://ftp.gnu.org/pub/gnu/config/
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches at gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo = `(hostinfo) 2>/dev/null`
+/bin/universe = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
Added: freeswitch/trunk/libs/sofia-sip/config.h.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/config.h.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1,396 @@
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* Define to the random number source name. */
+#undef DEV_URANDOM
+
+/* Define to 1 if you have addrinfo structure. */
+#undef HAVE_ADDRINFO
+
+/* Define to 1 if you have the `alarm' function. */
+#undef HAVE_ALARM
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#undef HAVE_ARPA_INET_H
+
+/* Define to 1 if you have the `clock_getcpuclockid' function. */
+#undef HAVE_CLOCK_GETCPUCLOCKID
+
+/* Define to 1 if you have the `clock_gettime' function. */
+#undef HAVE_CLOCK_GETTIME
+
+/* Define to 1 if you have /dev/urandom. */
+#undef HAVE_DEV_URANDOM
+
+/* Define to 1 if you have the <dirent.h> header file. */
+#undef HAVE_DIRENT_H
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have epoll interface. */
+#undef HAVE_EPOLL
+
+/* Define to 1 if you have the `epoll_create' function. */
+#undef HAVE_EPOLL_CREATE
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#undef HAVE_FCNTL_H
+
+/* Define to 1 if you have WIN32 FILETIME type and GetSystemTimeAsFileTime().
+ */
+#undef HAVE_FILETIME
+
+/* Define to 1 if you have the `flock' function. */
+#undef HAVE_FLOCK
+
+/* Define to 1 if you have the `freeaddrinfo' function. */
+#undef HAVE_FREEADDRINFO
+
+/* Define to 1 if the C compiler supports __func__ */
+#undef HAVE_FUNC
+
+/* Define to 1 if the C compiler supports __FUNCTION__ */
+#undef HAVE_FUNCTION
+
+/* Define to 1 if you have the `gai_strerror' function. */
+#undef HAVE_GAI_STRERROR
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#undef HAVE_GETADDRINFO
+
+/* Define to 1 if you have the `getdelim' function. */
+#undef HAVE_GETDELIM
+
+/* Define to 1 if you have the `gethostbyname' function. */
+#undef HAVE_GETHOSTBYNAME
+
+/* Define to 1 if you have the `gethostname' function. */
+#undef HAVE_GETHOSTNAME
+
+/* Define to 1 if you have the `getifaddrs' function. */
+#undef HAVE_GETIFADDRS
+
+/* Define to 1 if you have the `getipnodebyname' function. */
+#undef HAVE_GETIPNODEBYNAME
+
+/* Define to 1 if you have the `getline' function. */
+#undef HAVE_GETLINE
+
+/* Define to 1 if you have the `getnameinfo' function. */
+#undef HAVE_GETNAMEINFO
+
+/* Define to 1 if you have the `getpass' function. */
+#undef HAVE_GETPASS
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#undef HAVE_GETTIMEOFDAY
+
+/* Define to 1 if you have the <ifaddr.h> header file. */
+#undef HAVE_IFADDR_H
+
+/* Define to 1 if you have SIOCGIFCONF */
+#undef HAVE_IFCONF
+
+/* Define to 1 if you have SIOCGIFNUM ioctl */
+#undef HAVE_IFNUM
+
+/* Define to 1 if you have ifr_ifindex in <net/if.h> */
+#undef HAVE_IFR_IFINDEX
+
+/* Define to 1 if you have ifr_index in <net/if.h> */
+#undef HAVE_IFR_INDEX
+
+/* Define to 1 if you have the `if_nameindex' function. */
+#undef HAVE_IF_NAMEINDEX
+
+/* Define to 1 if you have the `inet_ntop' function. */
+#undef HAVE_INET_NTOP
+
+/* Define to 1 if you have the `inet_pton' function. */
+#undef HAVE_INET_PTON
+
+/* Define to 1 if you have the `initstate' function. */
+#undef HAVE_INITSTATE
+
+/* Define to 1 if you have inlining compiler */
+#undef HAVE_INLINE
+
+/* Define to 1 if you have WIN32 INTERFACE_INFO_EX type. */
+#undef HAVE_INTERFACE_INFO_EX
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the <iphlpapi.h> header file. */
+#undef HAVE_IPHLPAPI_H
+
+/* Define to 1 if you have IPV6_RECVERR in <netinet/in6.h> */
+#undef HAVE_IPV6_RECVERR
+
+/* Define to 1 if you have IP_RECVERR in <netinet/in.h> */
+#undef HAVE_IP_RECVERR
+
+/* Define to 1 if you have the `crypto' library (-lcrypto). */
+#undef HAVE_LIBCRYPTO
+
+/* Define to 1 if you have the `pthread' library (-lpthread). */
+#undef HAVE_LIBPTHREAD
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+#undef HAVE_LIBSOCKET
+
+/* Define to 1 if you have the `ssl' library (-lssl). */
+#undef HAVE_LIBSSL
+
+/* Define to 1 if you have the `memccpy' function. */
+#undef HAVE_MEMCCPY
+
+/* Define to 1 if you have the `memcspn' function. */
+#undef HAVE_MEMCSPN
+
+/* Define to 1 if you have the `memmem' function. */
+#undef HAVE_MEMMEM
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the `memspn' function. */
+#undef HAVE_MEMSPN
+
+/* Define to 1 if you are compiling in MinGW environment */
+#undef HAVE_MINGW
+
+/* Define to 1 if you have MSG_TRUNC flag */
+#undef HAVE_MSG_TRUNC
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#undef HAVE_NETDB_H
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#undef HAVE_NETINET_IN_H
+
+/* Define to 1 if you have the <netinet/sctp.h> header file. */
+#undef HAVE_NETINET_SCTP_H
+
+/* Define to 1 if you have the <netinet/tcp.h> header file. */
+#undef HAVE_NETINET_TCP_H
+
+/* Define to 1 if you have the <netpacket/packet.h> header file. */
+#undef HAVE_NETPACKET_PACKET_H
+
+/* Define to 1 if you have the <net/if.h> header file. */
+#undef HAVE_NET_IF_H
+
+/* Define to 1 if you have the <net/if_types.h> header file. */
+#undef HAVE_NET_IF_TYPES_H
+
+/* Define to 1 if you have OpenSSL */
+#undef HAVE_OPENSSL
+
+/* Define to 1 if you have the <openssl/tls1.h> header file. */
+#undef HAVE_OPENSSL_TLS1_H
+
+/* Define to 1 if you have the `poll' function. */
+#undef HAVE_POLL
+
+/* Define to 1 if you have /proc/net/if_inet6 control file */
+#undef HAVE_PROC_NET_IF_INET6
+
+/* Define to 1 if you have working pthread_rwlock_t implementation. A thread
+ may hold multiple concurrent read locks on rwlock - that is, successfully
+ call the pthread_rwlock_rdlock() function n times. If so, the application
+ shall ensure that the thread performs matching unlocks - that is, it calls
+ the pthread_rwlock_unlock() function n times. */
+#undef HAVE_PTHREAD_RWLOCK
+
+/* Define to 1 if you have the `random' function. */
+#undef HAVE_RANDOM
+
+/* Define to 1 if you have sa_len in struct sockaddr */
+#undef HAVE_SA_LEN
+
+/* Define to 1 if you have SCTP */
+#undef HAVE_SCTP
+
+/* Define to 1 if you have the `select' function. */
+#undef HAVE_SELECT
+
+/* Define to 1 if you have Sofia sigcomp >= 2.5 */
+#undef HAVE_SIGCOMP
+
+/* Define to 1 if you have the <sigcomp.h> header file. */
+#undef HAVE_SIGCOMP_H
+
+/* Define to 1 if you have SIGPIPE */
+#undef HAVE_SIGPIPE
+
+/* Define to 1 if you have IPv6 structures and constants */
+#undef HAVE_SIN6
+
+/* Define to 1 if you have WIN32 WSAIoctl SIO_ADDRESS_LIST_QUERY. */
+#undef HAVE_SIO_ADDRESS_LIST_QUERY
+
+/* Define to 1 if you have the `socketpair' function. */
+#undef HAVE_SOCKETPAIR
+
+/* Define to 1 if we use NTLM library */
+#undef HAVE_SOFIA_NTLM
+
+/* Define to 1 if you have Sofia sigcomp >= 2.5 */
+#undef HAVE_SOFIA_SIGCOMP
+
+/* Define to 1 always */
+#undef HAVE_SOFIA_SIP
+
+/* Define to 1 if we use S/MIME library */
+#undef HAVE_SOFIA_SMIME
+
+/* Define to 1 if we use DNS library */
+#undef HAVE_SOFIA_SRESOLV
+
+/* Define to 1 if we use STUN library */
+#undef HAVE_SOFIA_STUN
+
+/* Define to 1 if we use SRTP */
+#undef HAVE_SRTP
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the `strcasestr' function. */
+#undef HAVE_STRCASESTR
+
+/* Define to 1 if you have the `strerror' function. */
+#undef HAVE_STRERROR
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the `strtoull' function. */
+#undef HAVE_STRTOULL
+
+/* Define to 1 if your CC supports C99 struct initialization */
+#undef HAVE_STRUCT_KEYWORDS
+
+/* Define to 1 if you have the <sys/filio.h> header file. */
+#undef HAVE_SYS_FILIO_H
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#undef HAVE_SYS_IOCTL_H
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#undef HAVE_SYS_SELECT_H
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#undef HAVE_SYS_SOCKET_H
+
+/* Define to 1 if you have the <sys/sockio.h> header file. */
+#undef HAVE_SYS_SOCKIO_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the `tcsetattr' function. */
+#undef HAVE_TCSETATTR
+
+/* Define to 1 if you have TLS */
+#undef HAVE_TLS
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if we use UPnP */
+#undef HAVE_UPNP
+
+/* Define to 1 you have WIN32 */
+#undef HAVE_WIN32
+
+/* Define to 1 if you have the <windef.h> header file. */
+#undef HAVE_WINDEF_H
+
+/* Define to 1 if you have the <winsock2.h> header file. */
+#undef HAVE_WINSOCK2_H
+
+/* Define to 1 if you have the <ws2tcpip.h> header file. */
+#undef HAVE_WS2TCPIP_H
+
+/* Define to format (%lli) for long long */
+#undef LLI
+
+/* Define to format (%llu) for unsigned long long */
+#undef LLU
+
+/* Define to format (%llx) for long long hex */
+#undef LLX
+
+/* Define printf() modifier for ssize_t */
+#undef MOD_ZD
+
+/* Define printf() modifier for size_t */
+#undef MOD_ZU
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#undef RETSIGTYPE
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Version number of package */
+#undef VERSION
+
+/* Define to 1 if your processor stores words with the most significant byte
+ first (like Motorola and SPARC, unlike Intel and VAX). */
+#undef WORDS_BIGENDIAN
+
+/* Enable GNU extensions on systems that have them. */
+#ifndef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef __cplusplus
+#undef inline
+#endif
+
+/* Define to a at least 64-bit int type */
+#undef longlong
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+#undef size_t
Added: freeswitch/trunk/libs/sofia-sip/config.sub
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/config.sub Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1500 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+
+timestamp='2003-06-18'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine. It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Please send patches to <config-patches at gnu.org>. Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support. The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+ $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches at gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit 0 ;;
+ --version | -v )
+ echo "$version" ; exit 0 ;;
+ --help | --h* | -h )
+ echo "$usage"; exit 0 ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help"
+ exit 1 ;;
+
+ *local*)
+ # First pass through any local machine types.
+ echo $1
+ exit 0;;
+
+ * )
+ break ;;
+ esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+ exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+ exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+ nto-qnx* | linux-gnu* | freebsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*)
+ os=-$maybe_os
+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+ ;;
+ *)
+ basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+ if [ $basic_machine != $1 ]
+ then os=`echo $1 | sed 's/.*-/-/'`
+ else os=; fi
+ ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work. We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+ -sun*os*)
+ # Prevent following clause from handling this invalid input.
+ ;;
+ -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+ -apple | -axis)
+ os=
+ basic_machine=$1
+ ;;
+ -sim | -cisco | -oki | -wec | -winbond)
+ os=
+ basic_machine=$1
+ ;;
+ -scout)
+ ;;
+ -wrs)
+ os=-vxworks
+ basic_machine=$1
+ ;;
+ -chorusos*)
+ os=-chorusos
+ basic_machine=$1
+ ;;
+ -chorusrdb)
+ os=-chorusrdb
+ basic_machine=$1
+ ;;
+ -hiux*)
+ os=-hiuxwe2
+ ;;
+ -sco5)
+ os=-sco3.2v5
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco4)
+ os=-sco3.2v4
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2.[4-9]*)
+ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2v[4-9]*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco*)
+ os=-sco3.2v2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -udk*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -isc)
+ os=-isc2.2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -clix*)
+ basic_machine=clipper-intergraph
+ ;;
+ -isc*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -lynx*)
+ os=-lynxos
+ ;;
+ -ptx*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+ ;;
+ -windowsnt*)
+ os=`echo $os | sed -e 's/windowsnt/winnt/'`
+ ;;
+ -psos*)
+ os=-psos
+ ;;
+ -mint | -mint[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+ # Recognize the basic CPU types without company name.
+ # Some are omitted here because they have special meanings below.
+ 1750a | 580 \
+ | a29k \
+ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \
+ | c4x | clipper \
+ | d10v | d30v | dlx | dsp16xx \
+ | fr30 | frv \
+ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+ | i370 | i860 | i960 | ia64 \
+ | ip2k \
+ | m32r | m68000 | m68k | m88k | mcore \
+ | mips | mipsbe | mipseb | mipsel | mipsle \
+ | mips16 \
+ | mips64 | mips64el \
+ | mips64vr | mips64vrel \
+ | mips64orion | mips64orionel \
+ | mips64vr4100 | mips64vr4100el \
+ | mips64vr4300 | mips64vr4300el \
+ | mips64vr5000 | mips64vr5000el \
+ | mipsisa32 | mipsisa32el \
+ | mipsisa32r2 | mipsisa32r2el \
+ | mipsisa64 | mipsisa64el \
+ | mipsisa64sb1 | mipsisa64sb1el \
+ | mipsisa64sr71k | mipsisa64sr71kel \
+ | mipstx39 | mipstx39el \
+ | mn10200 | mn10300 \
+ | msp430 \
+ | ns16k | ns32k \
+ | openrisc | or32 \
+ | pdp10 | pdp11 | pj | pjl \
+ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+ | pyramid \
+ | s390 | s390x \
+ | sh | sh[1234] | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \
+ | sh64 | sh64le \
+ | sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv9 | sparcv9b \
+ | strongarm \
+ | tahoe | thumb | tic4x | tic80 | tron \
+ | v850 | v850e \
+ | we32k \
+ | x86 | xscale | xstormy16 | xtensa \
+ | z8k)
+ basic_machine=$basic_machine-unknown
+ ;;
+ m6811 | m68hc11 | m6812 | m68hc12)
+ # Motorola 68HC11/12.
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+ ;;
+
+ # We use `pc' rather than `unknown'
+ # because (1) that's what they normally are, and
+ # (2) the word "unknown" tends to confuse beginning users.
+ i*86 | x86_64)
+ basic_machine=$basic_machine-pc
+ ;;
+ # Object if more than one company name word.
+ *-*-*)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+ # Recognize the basic CPU types with company name.
+ 580-* \
+ | a29k-* \
+ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \
+ | avr-* \
+ | bs2000-* \
+ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
+ | clipper-* | cydra-* \
+ | d10v-* | d30v-* | dlx-* \
+ | elxsi-* \
+ | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \
+ | h8300-* | h8500-* \
+ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+ | i*86-* | i860-* | i960-* | ia64-* \
+ | ip2k-* \
+ | m32r-* \
+ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+ | m88110-* | m88k-* | mcore-* \
+ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+ | mips16-* \
+ | mips64-* | mips64el-* \
+ | mips64vr-* | mips64vrel-* \
+ | mips64orion-* | mips64orionel-* \
+ | mips64vr4100-* | mips64vr4100el-* \
+ | mips64vr4300-* | mips64vr4300el-* \
+ | mips64vr5000-* | mips64vr5000el-* \
+ | mipsisa32-* | mipsisa32el-* \
+ | mipsisa32r2-* | mipsisa32r2el-* \
+ | mipsisa64-* | mipsisa64el-* \
+ | mipsisa64sb1-* | mipsisa64sb1el-* \
+ | mipsisa64sr71k-* | mipsisa64sr71kel-* \
+ | mipstx39-* | mipstx39el-* \
+ | msp430-* \
+ | none-* | np1-* | nv1-* | ns16k-* | ns32k-* \
+ | orion-* \
+ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+ | pyramid-* \
+ | romp-* | rs6000-* \
+ | s390-* | s390x-* \
+ | sh-* | sh[1234]-* | sh[23]e-* | sh[34]eb-* | shbe-* \
+ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+ | sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \
+ | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \
+ | tahoe-* | thumb-* \
+ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+ | tron-* \
+ | v850-* | v850e-* | vax-* \
+ | we32k-* \
+ | x86-* | x86_64-* | xps100-* | xscale-* | xstormy16-* \
+ | xtensa-* \
+ | ymp-* \
+ | z8k-*)
+ ;;
+ # Recognize the various machine names and aliases which stand
+ # for a CPU type and a company and sometimes even an OS.
+ 386bsd)
+ basic_machine=i386-unknown
+ os=-bsd
+ ;;
+ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+ basic_machine=m68000-att
+ ;;
+ 3b*)
+ basic_machine=we32k-att
+ ;;
+ a29khif)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ adobe68k)
+ basic_machine=m68010-adobe
+ os=-scout
+ ;;
+ alliant | fx80)
+ basic_machine=fx80-alliant
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ ;;
+ am29k)
+ basic_machine=a29k-none
+ os=-bsd
+ ;;
+ amd64)
+ basic_machine=x86_64-pc
+ ;;
+ amdahl)
+ basic_machine=580-amdahl
+ os=-sysv
+ ;;
+ amiga | amiga-*)
+ basic_machine=m68k-unknown
+ ;;
+ amigaos | amigados)
+ basic_machine=m68k-unknown
+ os=-amigaos
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-unknown
+ os=-sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ os=-sysv
+ ;;
+ apollo68bsd)
+ basic_machine=m68k-apollo
+ os=-bsd
+ ;;
+ aux)
+ basic_machine=m68k-apple
+ os=-aux
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ os=-dynix
+ ;;
+ c90)
+ basic_machine=c90-cray
+ os=-unicos
+ ;;
+ convex-c1)
+ basic_machine=c1-convex
+ os=-bsd
+ ;;
+ convex-c2)
+ basic_machine=c2-convex
+ os=-bsd
+ ;;
+ convex-c32)
+ basic_machine=c32-convex
+ os=-bsd
+ ;;
+ convex-c34)
+ basic_machine=c34-convex
+ os=-bsd
+ ;;
+ convex-c38)
+ basic_machine=c38-convex
+ os=-bsd
+ ;;
+ cray | j90)
+ basic_machine=j90-cray
+ os=-unicos
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ ;;
+ cris | cris-* | etrax*)
+ basic_machine=cris-axis
+ ;;
+ da30 | da30-*)
+ basic_machine=m68k-da30
+ ;;
+ decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ ;;
+ decsystem10* | dec10*)
+ basic_machine=pdp10-dec
+ os=-tops10
+ ;;
+ decsystem20* | dec20*)
+ basic_machine=pdp10-dec
+ os=-tops20
+ ;;
+ delta | 3300 | motorola-3300 | motorola-delta \
+ | 3300-motorola | delta-motorola)
+ basic_machine=m68k-motorola
+ ;;
+ delta88)
+ basic_machine=m88k-motorola
+ os=-sysv3
+ ;;
+ dpx20 | dpx20-*)
+ basic_machine=rs6000-bull
+ os=-bosx
+ ;;
+ dpx2* | dpx2*-bull)
+ basic_machine=m68k-bull
+ os=-sysv3
+ ;;
+ ebmon29k)
+ basic_machine=a29k-amd
+ os=-ebmon
+ ;;
+ elxsi)
+ basic_machine=elxsi-elxsi
+ os=-bsd
+ ;;
+ encore | umax | mmax)
+ basic_machine=ns32k-encore
+ ;;
+ es1800 | OSE68k | ose68k | ose | OSE)
+ basic_machine=m68k-ericsson
+ os=-ose
+ ;;
+ fx2800)
+ basic_machine=i860-alliant
+ ;;
+ genix)
+ basic_machine=ns32k-ns
+ ;;
+ gmicro)
+ basic_machine=tron-gmicro
+ os=-sysv
+ ;;
+ go32)
+ basic_machine=i386-pc
+ os=-go32
+ ;;
+ h3050r* | hiux*)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ h8300hms)
+ basic_machine=h8300-hitachi
+ os=-hms
+ ;;
+ h8300xray)
+ basic_machine=h8300-hitachi
+ os=-xray
+ ;;
+ h8500hms)
+ basic_machine=h8500-hitachi
+ os=-hms
+ ;;
+ harris)
+ basic_machine=m88k-harris
+ os=-sysv3
+ ;;
+ hp300-*)
+ basic_machine=m68k-hp
+ ;;
+ hp300bsd)
+ basic_machine=m68k-hp
+ os=-bsd
+ ;;
+ hp300hpux)
+ basic_machine=m68k-hp
+ os=-hpux
+ ;;
+ hp3k9[0-9][0-9] | hp9[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k2[0-9][0-9] | hp9k31[0-9])
+ basic_machine=m68000-hp
+ ;;
+ hp9k3[2-9][0-9])
+ basic_machine=m68k-hp
+ ;;
+ hp9k6[0-9][0-9] | hp6[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k7[0-79][0-9] | hp7[0-79][0-9])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k78[0-9] | hp78[0-9])
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][13679] | hp8[0-9][13679])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][0-9] | hp8[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hppa-next)
+ os=-nextstep3
+ ;;
+ hppaosf)
+ basic_machine=hppa1.1-hp
+ os=-osf
+ ;;
+ hppro)
+ basic_machine=hppa1.1-hp
+ os=-proelf
+ ;;
+ i370-ibm* | ibm*)
+ basic_machine=i370-ibm
+ ;;
+# I'm not sure what "Sysv32" means. Should this be sysv3.2?
+ i*86v32)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv32
+ ;;
+ i*86v4*)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv4
+ ;;
+ i*86v)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv
+ ;;
+ i*86sol2)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-solaris2
+ ;;
+ i386mach)
+ basic_machine=i386-mach
+ os=-mach
+ ;;
+ i386-vsta | vsta)
+ basic_machine=i386-unknown
+ os=-vsta
+ ;;
+ iris | iris4d)
+ basic_machine=mips-sgi
+ case $os in
+ -irix*)
+ ;;
+ *)
+ os=-irix4
+ ;;
+ esac
+ ;;
+ isi68 | isi)
+ basic_machine=m68k-isi
+ os=-sysv
+ ;;
+ m88k-omron*)
+ basic_machine=m88k-omron
+ ;;
+ magnum | m3230)
+ basic_machine=mips-mips
+ os=-sysv
+ ;;
+ merlin)
+ basic_machine=ns32k-utek
+ os=-sysv
+ ;;
+ mingw32)
+ basic_machine=i386-pc
+ os=-mingw32
+ ;;
+ miniframe)
+ basic_machine=m68000-convergent
+ ;;
+ *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+ mips3*-*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+ ;;
+ mips3*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+ ;;
+ mmix*)
+ basic_machine=mmix-knuth
+ os=-mmixware
+ ;;
+ monitor)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ morphos)
+ basic_machine=powerpc-unknown
+ os=-morphos
+ ;;
+ msdos)
+ basic_machine=i386-pc
+ os=-msdos
+ ;;
+ mvs)
+ basic_machine=i370-ibm
+ os=-mvs
+ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ os=-sysv4
+ ;;
+ netbsd386)
+ basic_machine=i386-unknown
+ os=-netbsd
+ ;;
+ netwinder)
+ basic_machine=armv4l-rebel
+ os=-linux
+ ;;
+ news | news700 | news800 | news900)
+ basic_machine=m68k-sony
+ os=-newsos
+ ;;
+ news1000)
+ basic_machine=m68030-sony
+ os=-newsos
+ ;;
+ news-3600 | risc-news)
+ basic_machine=mips-sony
+ os=-newsos
+ ;;
+ necv70)
+ basic_machine=v70-nec
+ os=-sysv
+ ;;
+ next | m*-next )
+ basic_machine=m68k-next
+ case $os in
+ -nextstep* )
+ ;;
+ -ns2*)
+ os=-nextstep2
+ ;;
+ *)
+ os=-nextstep3
+ ;;
+ esac
+ ;;
+ nh3000)
+ basic_machine=m68k-harris
+ os=-cxux
+ ;;
+ nh[45]000)
+ basic_machine=m88k-harris
+ os=-cxux
+ ;;
+ nindy960)
+ basic_machine=i960-intel
+ os=-nindy
+ ;;
+ mon960)
+ basic_machine=i960-intel
+ os=-mon960
+ ;;
+ nonstopux)
+ basic_machine=mips-compaq
+ os=-nonstopux
+ ;;
+ np1)
+ basic_machine=np1-gould
+ ;;
+ nv1)
+ basic_machine=nv1-cray
+ os=-unicosmp
+ ;;
+ nsr-tandem)
+ basic_machine=nsr-tandem
+ ;;
+ op50n-* | op60c-*)
+ basic_machine=hppa1.1-oki
+ os=-proelf
+ ;;
+ or32 | or32-*)
+ basic_machine=or32-unknown
+ os=-coff
+ ;;
+ OSE68000 | ose68000)
+ basic_machine=m68000-ericsson
+ os=-ose
+ ;;
+ os68k)
+ basic_machine=m68k-none
+ os=-os68k
+ ;;
+ pa-hitachi)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ paragon)
+ basic_machine=i860-intel
+ os=-osf
+ ;;
+ pbd)
+ basic_machine=sparc-tti
+ ;;
+ pbb)
+ basic_machine=m68k-tti
+ ;;
+ pc532 | pc532-*)
+ basic_machine=ns32k-pc532
+ ;;
+ pentium | p5 | k5 | k6 | nexgen | viac3)
+ basic_machine=i586-pc
+ ;;
+ pentiumpro | p6 | 6x86 | athlon | athlon_*)
+ basic_machine=i686-pc
+ ;;
+ pentiumii | pentium2 | pentiumiii | pentium3)
+ basic_machine=i686-pc
+ ;;
+ pentium4)
+ basic_machine=i786-pc
+ ;;
+ pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+ basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumpro-* | p6-* | 6x86-* | athlon-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentium4-*)
+ basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pn)
+ basic_machine=pn-gould
+ ;;
+ power) basic_machine=power-ibm
+ ;;
+ ppc) basic_machine=powerpc-unknown
+ ;;
+ ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppcle | powerpclittle | ppc-le | powerpc-little)
+ basic_machine=powerpcle-unknown
+ ;;
+ ppcle-* | powerpclittle-*)
+ basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64) basic_machine=powerpc64-unknown
+ ;;
+ ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+ basic_machine=powerpc64le-unknown
+ ;;
+ ppc64le-* | powerpc64little-*)
+ basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ps2)
+ basic_machine=i386-ibm
+ ;;
+ pw32)
+ basic_machine=i586-unknown
+ os=-pw32
+ ;;
+ rom68k)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ rm[46]00)
+ basic_machine=mips-siemens
+ ;;
+ rtpc | rtpc-*)
+ basic_machine=romp-ibm
+ ;;
+ sa29200)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ sb1)
+ basic_machine=mipsisa64sb1-unknown
+ ;;
+ sb1el)
+ basic_machine=mipsisa64sb1el-unknown
+ ;;
+ sei)
+ basic_machine=mips-sei
+ os=-seiux
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ ;;
+ sh)
+ basic_machine=sh-hitachi
+ os=-hms
+ ;;
+ sh64)
+ basic_machine=sh64-unknown
+ ;;
+ sparclite-wrs | simso-wrs)
+ basic_machine=sparclite-wrs
+ os=-vxworks
+ ;;
+ sps7)
+ basic_machine=m68k-bull
+ os=-sysv2
+ ;;
+ spur)
+ basic_machine=spur-unknown
+ ;;
+ st2000)
+ basic_machine=m68k-tandem
+ ;;
+ stratus)
+ basic_machine=i860-stratus
+ os=-sysv4
+ ;;
+ sun2)
+ basic_machine=m68000-sun
+ ;;
+ sun2os3)
+ basic_machine=m68000-sun
+ os=-sunos3
+ ;;
+ sun2os4)
+ basic_machine=m68000-sun
+ os=-sunos4
+ ;;
+ sun3os3)
+ basic_machine=m68k-sun
+ os=-sunos3
+ ;;
+ sun3os4)
+ basic_machine=m68k-sun
+ os=-sunos4
+ ;;
+ sun4os3)
+ basic_machine=sparc-sun
+ os=-sunos3
+ ;;
+ sun4os4)
+ basic_machine=sparc-sun
+ os=-sunos4
+ ;;
+ sun4sol2)
+ basic_machine=sparc-sun
+ os=-solaris2
+ ;;
+ sun3 | sun3-*)
+ basic_machine=m68k-sun
+ ;;
+ sun4)
+ basic_machine=sparc-sun
+ ;;
+ sun386 | sun386i | roadrunner)
+ basic_machine=i386-sun
+ ;;
+ sv1)
+ basic_machine=sv1-cray
+ os=-unicos
+ ;;
+ symmetry)
+ basic_machine=i386-sequent
+ os=-dynix
+ ;;
+ t3e)
+ basic_machine=alphaev5-cray
+ os=-unicos
+ ;;
+ t90)
+ basic_machine=t90-cray
+ os=-unicos
+ ;;
+ tic54x | c54x*)
+ basic_machine=tic54x-unknown
+ os=-coff
+ ;;
+ tic55x | c55x*)
+ basic_machine=tic55x-unknown
+ os=-coff
+ ;;
+ tic6x | c6x*)
+ basic_machine=tic6x-unknown
+ os=-coff
+ ;;
+ tx39)
+ basic_machine=mipstx39-unknown
+ ;;
+ tx39el)
+ basic_machine=mipstx39el-unknown
+ ;;
+ toad1)
+ basic_machine=pdp10-xkl
+ os=-tops20
+ ;;
+ tower | tower-32)
+ basic_machine=m68k-ncr
+ ;;
+ udi29k)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ ultra3)
+ basic_machine=a29k-nyu
+ os=-sym1
+ ;;
+ v810 | necv810)
+ basic_machine=v810-nec
+ os=-none
+ ;;
+ vaxv)
+ basic_machine=vax-dec
+ os=-sysv
+ ;;
+ vms)
+ basic_machine=vax-dec
+ os=-vms
+ ;;
+ vpp*|vx|vx-*)
+ basic_machine=f301-fujitsu
+ ;;
+ vxworks960)
+ basic_machine=i960-wrs
+ os=-vxworks
+ ;;
+ vxworks68)
+ basic_machine=m68k-wrs
+ os=-vxworks
+ ;;
+ vxworks29k)
+ basic_machine=a29k-wrs
+ os=-vxworks
+ ;;
+ w65*)
+ basic_machine=w65-wdc
+ os=-none
+ ;;
+ w89k-*)
+ basic_machine=hppa1.1-winbond
+ os=-proelf
+ ;;
+ xps | xps100)
+ basic_machine=xps100-honeywell
+ ;;
+ ymp)
+ basic_machine=ymp-cray
+ os=-unicos
+ ;;
+ z8k-*-coff)
+ basic_machine=z8k-unknown
+ os=-sim
+ ;;
+ none)
+ basic_machine=none-none
+ os=-none
+ ;;
+
+# Here we handle the default manufacturer of certain CPU types. It is in
+# some cases the only manufacturer, in others, it is the most popular.
+ w89k)
+ basic_machine=hppa1.1-winbond
+ ;;
+ op50n)
+ basic_machine=hppa1.1-oki
+ ;;
+ op60c)
+ basic_machine=hppa1.1-oki
+ ;;
+ romp)
+ basic_machine=romp-ibm
+ ;;
+ rs6000)
+ basic_machine=rs6000-ibm
+ ;;
+ vax)
+ basic_machine=vax-dec
+ ;;
+ pdp10)
+ # there are many clones, so DEC is not a safe bet
+ basic_machine=pdp10-unknown
+ ;;
+ pdp11)
+ basic_machine=pdp11-dec
+ ;;
+ we32k)
+ basic_machine=we32k-att
+ ;;
+ sh3 | sh4 | sh[34]eb | sh[1234]le | sh[23]ele)
+ basic_machine=sh-unknown
+ ;;
+ sh64)
+ basic_machine=sh64-unknown
+ ;;
+ sparc | sparcv9 | sparcv9b)
+ basic_machine=sparc-sun
+ ;;
+ cydra)
+ basic_machine=cydra-cydrome
+ ;;
+ orion)
+ basic_machine=orion-highlevel
+ ;;
+ orion105)
+ basic_machine=clipper-highlevel
+ ;;
+ mac | mpw | mac-mpw)
+ basic_machine=m68k-apple
+ ;;
+ pmac | pmac-mpw)
+ basic_machine=powerpc-apple
+ ;;
+ *-unknown)
+ # Make sure to match an already-canonicalized machine name.
+ ;;
+ *)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+ *-digital*)
+ basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+ ;;
+ *-commodore*)
+ basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+ ;;
+ *)
+ ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+ # First match some system type aliases
+ # that might get confused with valid system types.
+ # -solaris* is a basic system type, with this one exception.
+ -solaris1 | -solaris1.*)
+ os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ ;;
+ -solaris)
+ os=-solaris2
+ ;;
+ -svr4*)
+ os=-sysv4
+ ;;
+ -unixware*)
+ os=-sysv4.2uw
+ ;;
+ -gnu/linux*)
+ os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+ ;;
+ # First accept the basic system types.
+ # The portable systems comes first.
+ # Each alternative MUST END IN A *, to match a version number.
+ # -sysv* is not here because it comes later, after sysvr4.
+ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+ | -aos* \
+ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+ | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \
+ | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+ | -chorusos* | -chorusrdb* \
+ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+ | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \
+ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+ | -powermax* | -dnix* | -nx6 | -nx7 | -sei*)
+ # Remember, each alternative MUST END IN *, to match a version number.
+ ;;
+ -qnx*)
+ case $basic_machine in
+ x86-* | i*86-*)
+ ;;
+ *)
+ os=-nto$os
+ ;;
+ esac
+ ;;
+ -nto-qnx*)
+ ;;
+ -nto*)
+ os=`echo $os | sed -e 's|nto|nto-qnx|'`
+ ;;
+ -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+ | -windows* | -osx | -abug | -netware* | -os9* | -beos* \
+ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+ ;;
+ -mac*)
+ os=`echo $os | sed -e 's|mac|macos|'`
+ ;;
+ -linux*)
+ os=`echo $os | sed -e 's|linux|linux-gnu|'`
+ ;;
+ -sunos5*)
+ os=`echo $os | sed -e 's|sunos5|solaris2|'`
+ ;;
+ -sunos6*)
+ os=`echo $os | sed -e 's|sunos6|solaris3|'`
+ ;;
+ -opened*)
+ os=-openedition
+ ;;
+ -wince*)
+ os=-wince
+ ;;
+ -osfrose*)
+ os=-osfrose
+ ;;
+ -osf*)
+ os=-osf
+ ;;
+ -utek*)
+ os=-bsd
+ ;;
+ -dynix*)
+ os=-bsd
+ ;;
+ -acis*)
+ os=-aos
+ ;;
+ -atheos*)
+ os=-atheos
+ ;;
+ -386bsd)
+ os=-bsd
+ ;;
+ -ctix* | -uts*)
+ os=-sysv
+ ;;
+ -nova*)
+ os=-rtmk-nova
+ ;;
+ -ns2 )
+ os=-nextstep2
+ ;;
+ -nsk*)
+ os=-nsk
+ ;;
+ # Preserve the version number of sinix5.
+ -sinix5.*)
+ os=`echo $os | sed -e 's|sinix|sysv|'`
+ ;;
+ -sinix*)
+ os=-sysv4
+ ;;
+ -triton*)
+ os=-sysv3
+ ;;
+ -oss*)
+ os=-sysv3
+ ;;
+ -svr4)
+ os=-sysv4
+ ;;
+ -svr3)
+ os=-sysv3
+ ;;
+ -sysvr4)
+ os=-sysv4
+ ;;
+ # This must come after -sysvr4.
+ -sysv*)
+ ;;
+ -ose*)
+ os=-ose
+ ;;
+ -es1800*)
+ os=-ose
+ ;;
+ -xenix)
+ os=-xenix
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ os=-mint
+ ;;
+ -aros*)
+ os=-aros
+ ;;
+ -kaos*)
+ os=-kaos
+ ;;
+ -none)
+ ;;
+ *)
+ # Get rid of the `-' at the beginning of $os.
+ os=`echo $os | sed 's/[^-]*-//'`
+ echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system. Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+ *-acorn)
+ os=-riscix1.2
+ ;;
+ arm*-rebel)
+ os=-linux
+ ;;
+ arm*-semi)
+ os=-aout
+ ;;
+ c4x-* | tic4x-*)
+ os=-coff
+ ;;
+ # This must come before the *-dec entry.
+ pdp10-*)
+ os=-tops20
+ ;;
+ pdp11-*)
+ os=-none
+ ;;
+ *-dec | vax-*)
+ os=-ultrix4.2
+ ;;
+ m68*-apollo)
+ os=-domain
+ ;;
+ i386-sun)
+ os=-sunos4.0.2
+ ;;
+ m68000-sun)
+ os=-sunos3
+ # This also exists in the configure program, but was not the
+ # default.
+ # os=-sunos4
+ ;;
+ m68*-cisco)
+ os=-aout
+ ;;
+ mips*-cisco)
+ os=-elf
+ ;;
+ mips*-*)
+ os=-elf
+ ;;
+ or32-*)
+ os=-coff
+ ;;
+ *-tti) # must be before sparc entry or we get the wrong os.
+ os=-sysv3
+ ;;
+ sparc-* | *-sun)
+ os=-sunos4.1.1
+ ;;
+ *-be)
+ os=-beos
+ ;;
+ *-ibm)
+ os=-aix
+ ;;
+ *-wec)
+ os=-proelf
+ ;;
+ *-winbond)
+ os=-proelf
+ ;;
+ *-oki)
+ os=-proelf
+ ;;
+ *-hp)
+ os=-hpux
+ ;;
+ *-hitachi)
+ os=-hiux
+ ;;
+ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+ os=-sysv
+ ;;
+ *-cbm)
+ os=-amigaos
+ ;;
+ *-dg)
+ os=-dgux
+ ;;
+ *-dolphin)
+ os=-sysv3
+ ;;
+ m68k-ccur)
+ os=-rtu
+ ;;
+ m88k-omron*)
+ os=-luna
+ ;;
+ *-next )
+ os=-nextstep
+ ;;
+ *-sequent)
+ os=-ptx
+ ;;
+ *-crds)
+ os=-unos
+ ;;
+ *-ns)
+ os=-genix
+ ;;
+ i370-*)
+ os=-mvs
+ ;;
+ *-next)
+ os=-nextstep3
+ ;;
+ *-gould)
+ os=-sysv
+ ;;
+ *-highlevel)
+ os=-bsd
+ ;;
+ *-encore)
+ os=-bsd
+ ;;
+ *-sgi)
+ os=-irix
+ ;;
+ *-siemens)
+ os=-sysv4
+ ;;
+ *-masscomp)
+ os=-rtu
+ ;;
+ f30[01]-fujitsu | f700-fujitsu)
+ os=-uxpv
+ ;;
+ *-rom68k)
+ os=-coff
+ ;;
+ *-*bug)
+ os=-coff
+ ;;
+ *-apple)
+ os=-macos
+ ;;
+ *-atari*)
+ os=-mint
+ ;;
+ *)
+ os=-none
+ ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer. We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+ *-unknown)
+ case $os in
+ -riscix*)
+ vendor=acorn
+ ;;
+ -sunos*)
+ vendor=sun
+ ;;
+ -aix*)
+ vendor=ibm
+ ;;
+ -beos*)
+ vendor=be
+ ;;
+ -hpux*)
+ vendor=hp
+ ;;
+ -mpeix*)
+ vendor=hp
+ ;;
+ -hiux*)
+ vendor=hitachi
+ ;;
+ -unos*)
+ vendor=crds
+ ;;
+ -dgux*)
+ vendor=dg
+ ;;
+ -luna*)
+ vendor=omron
+ ;;
+ -genix*)
+ vendor=ns
+ ;;
+ -mvs* | -opened*)
+ vendor=ibm
+ ;;
+ -ptx*)
+ vendor=sequent
+ ;;
+ -vxsim* | -vxworks* | -windiss*)
+ vendor=wrs
+ ;;
+ -aux*)
+ vendor=apple
+ ;;
+ -hms*)
+ vendor=hitachi
+ ;;
+ -mpw* | -macos*)
+ vendor=apple
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ vendor=atari
+ ;;
+ -vos*)
+ vendor=stratus
+ ;;
+ esac
+ basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+ ;;
+esac
+
+echo $basic_machine$os
+exit 0
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
Added: freeswitch/trunk/libs/sofia-sip/configure
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/configure Thu Dec 21 01:30:28 2006
@@ -0,0 +1,29140 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.59 for sofia-sip 1.12.4work.
+#
+# Copyright (C) 2003 Free Software Foundation, Inc.
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## --------------------- ##
+## M4sh Initialization. ##
+## --------------------- ##
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+ set -o posix
+fi
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+fi
+
+
+# Work around bugs in pre-3.0 UWIN ksh.
+$as_unset ENV MAIL MAILPATH
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+ LC_TELEPHONE LC_TIME
+do
+ if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+ eval $as_var=C; export $as_var
+ else
+ $as_unset $as_var
+ fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)$' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
+ /^X\/\(\/\/\)$/{ s//\1/; q; }
+ /^X\/\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+
+
+# PATH needs CR, and LINENO needs CR and PATH.
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ echo "#! /bin/sh" >conf$$.sh
+ echo "exit 0" >>conf$$.sh
+ chmod +x conf$$.sh
+ if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conf$$.sh
+fi
+
+
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" || {
+ # Find who we are. Look in the path if we contain no path at all
+ # relative or not.
+ case $0 in
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+
+ ;;
+ esac
+ # We did not find ourselves, most probably we were run as `sh COMMAND'
+ # in which case we are not to be found in the path.
+ if test "x$as_myself" = x; then
+ as_myself=$0
+ fi
+ if test ! -f "$as_myself"; then
+ { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2
+ { (exit 1); exit 1; }; }
+ fi
+ case $CONFIG_SHELL in
+ '')
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for as_base in sh bash ksh sh5; do
+ case $as_dir in
+ /*)
+ if ("$as_dir/$as_base" -c '
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then
+ $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; }
+ $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; }
+ CONFIG_SHELL=$as_dir/$as_base
+ export CONFIG_SHELL
+ exec "$CONFIG_SHELL" "$0" ${1+"$@"}
+ fi;;
+ esac
+ done
+done
+;;
+ esac
+
+ # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+ # uniformly replaced by the line number. The first 'sed' inserts a
+ # line-number line before each line; the second 'sed' does the real
+ # work. The second script uses 'N' to pair each line-number line
+ # with the numbered line, and appends trailing '-' during
+ # substitution so that $LINENO is not a special case at line end.
+ # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+ # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-)
+ sed '=' <$as_myself |
+ sed '
+ N
+ s,$,-,
+ : loop
+ s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
+ t loop
+ s,-$,,
+ s,^['$as_cr_digits']*\n,,
+ ' >$as_me.lineno &&
+ chmod +x $as_me.lineno ||
+ { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+ { (exit 1); exit 1; }; }
+
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensible to this).
+ . ./$as_me.lineno
+ # Exit status is that of the last command.
+ exit
+}
+
+
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+ *c*,-n*) ECHO_N= ECHO_C='
+' ECHO_T=' ' ;;
+ *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;;
+ *) ECHO_N= ECHO_C='\c' ECHO_T= ;;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+ # We could just check for DJGPP; but this test a) works b) is more generic
+ # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+ if test -f conf$$.exe; then
+ # Don't use ln at all; we don't have any links
+ as_ln_s='cp -p'
+ else
+ as_ln_s='ln -s'
+ fi
+elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.file
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p=:
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+as_executable_p="test -f"
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS=" $as_nl"
+
+# CDPATH.
+$as_unset CDPATH
+
+
+
+# Check that we are running under the correct shell.
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+case X$ECHO in
+X*--fallback-echo)
+ # Remove one level of quotation (which was required for Make).
+ ECHO=`echo "$ECHO" | sed 's,\\\\\$\\$0,'$0','`
+ ;;
+esac
+
+echo=${ECHO-echo}
+if test "X$1" = X--no-reexec; then
+ # Discard the --no-reexec flag, and continue.
+ shift
+elif test "X$1" = X--fallback-echo; then
+ # Avoid inline document here, it may be left over
+ :
+elif test "X`($echo '\t') 2>/dev/null`" = 'X\t' ; then
+ # Yippee, $echo works!
+ :
+else
+ # Restart under the correct shell.
+ exec $SHELL "$0" --no-reexec ${1+"$@"}
+fi
+
+if test "X$1" = X--fallback-echo; then
+ # used as fallback echo
+ shift
+ cat <<EOF
+$*
+EOF
+ exit 0
+fi
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+if test "X${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi
+
+if test -z "$ECHO"; then
+if test "X${echo_test_string+set}" != Xset; then
+# find a string as large as possible, as long as the shell can cope with it
+ for cmd in 'sed 50q "$0"' 'sed 20q "$0"' 'sed 10q "$0"' 'sed 2q "$0"' 'echo test'; do
+ # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ...
+ if (echo_test_string="`eval $cmd`") 2>/dev/null &&
+ echo_test_string="`eval $cmd`" &&
+ (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null
+ then
+ break
+ fi
+ done
+fi
+
+if test "X`($echo '\t') 2>/dev/null`" = 'X\t' &&
+ echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ :
+else
+ # The Solaris, AIX, and Digital Unix default echo programs unquote
+ # backslashes. This makes it impossible to quote backslashes using
+ # echo "$something" | sed 's/\\/\\\\/g'
+ #
+ # So, first we look for a working echo in the user's PATH.
+
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for dir in $PATH /usr/ucb; do
+ IFS="$lt_save_ifs"
+ if (test -f $dir/echo || test -f $dir/echo$ac_exeext) &&
+ test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' &&
+ echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ echo="$dir/echo"
+ break
+ fi
+ done
+ IFS="$lt_save_ifs"
+
+ if test "X$echo" = Xecho; then
+ # We didn't find a better echo, so look for alternatives.
+ if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' &&
+ echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ # This shell has a builtin print -r that does the trick.
+ echo='print -r'
+ elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) &&
+ test "X$CONFIG_SHELL" != X/bin/ksh; then
+ # If we have ksh, try running configure again with it.
+ ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh}
+ export ORIGINAL_CONFIG_SHELL
+ CONFIG_SHELL=/bin/ksh
+ export CONFIG_SHELL
+ exec $CONFIG_SHELL "$0" --no-reexec ${1+"$@"}
+ else
+ # Try using printf.
+ echo='printf %s\n'
+ if test "X`($echo '\t') 2>/dev/null`" = 'X\t' &&
+ echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ # Cool, printf works
+ :
+ elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` &&
+ test "X$echo_testing_string" = 'X\t' &&
+ echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL
+ export CONFIG_SHELL
+ SHELL="$CONFIG_SHELL"
+ export SHELL
+ echo="$CONFIG_SHELL $0 --fallback-echo"
+ elif echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` &&
+ test "X$echo_testing_string" = 'X\t' &&
+ echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ echo="$CONFIG_SHELL $0 --fallback-echo"
+ else
+ # maybe with a smaller string...
+ prev=:
+
+ for cmd in 'echo test' 'sed 2q "$0"' 'sed 10q "$0"' 'sed 20q "$0"' 'sed 50q "$0"'; do
+ if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null
+ then
+ break
+ fi
+ prev="$cmd"
+ done
+
+ if test "$prev" != 'sed 50q "$0"'; then
+ echo_test_string=`eval $prev`
+ export echo_test_string
+ exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "$0" ${1+"$@"}
+ else
+ # Oops. We lost completely, so just stick with echo.
+ echo=echo
+ fi
+ fi
+ fi
+ fi
+fi
+fi
+
+# Copy echo and quote the copy suitably for passing to libtool from
+# the Makefile, instead of quoting the original, which is used later.
+ECHO=$echo
+if test "X$ECHO" = "X$CONFIG_SHELL $0 --fallback-echo"; then
+ ECHO="$CONFIG_SHELL \\\$\$0 --fallback-echo"
+fi
+
+
+
+
+tagnames=${tagnames+${tagnames},}CXX
+
+tagnames=${tagnames+${tagnames},}F77
+
+# Name of the host.
+# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+exec 6>&1
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_config_libobj_dir=.
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+# Maximum number of lines to put in a shell here document.
+# This variable seems obsolete. It should probably be removed, and
+# only ac_max_sed_lines should be used.
+: ${ac_max_here_lines=38}
+
+# Identity of this package.
+PACKAGE_NAME='sofia-sip'
+PACKAGE_TARNAME='sofia-sip'
+PACKAGE_VERSION='1.12.4work'
+PACKAGE_STRING='sofia-sip 1.12.4work'
+PACKAGE_BUGREPORT=''
+
+ac_unique_file="libsofia-sip-ua/sip/sofia-sip/sip.h"
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#if HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# if HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#if HAVE_STRING_H
+# if !STDC_HEADERS && HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+# include <stdint.h>
+# endif
+#endif
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS VER_LIBSOFIA_SIP_UA_MAJOR_MINOR include_sofiadir LIBVER_SOFIA_SIP_UA_CUR LIBVER_SOFIA_SIP_UA_REV LIBVER_SOFIA_SIP_UA_AGE LIBVER_SOFIA_SIP_UA_SOVER LIBVER_SOFIA_SIP_UA_GLIB_CUR LIBVER_SOFIA_SIP_UA_GLIB_REV LIBVER_SOFIA_SIP_UA_GLIB_AGE LIBVER_SOFIA_SIP_UA_GLIB_SOVER build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE MINGW_ENVIRONMENT HAVE_MINGW32_TRUE HAVE_MINGW32_FALSE CWFLAG SOFIA_CFLAGS ENABLE_COVERAGE_TRUE ENABLE_COVERAGE_FALSE MOSTLYCLEANFILES CPP ETAGS AR ac_ct_AR LD ac_ct_LD EGREP LN_S ECHO RANLIB ac_ct_RANLIB CXX CXXFLAGS ac_ct_CXX CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE CXXCPP F77 FFLAGS ac_ct_F77 LIBTOOL NDEBUG_TRUE NDEBUG_FALSE TESTS_ENVIRONMENT EXPENSIVE_CHECKS_TRUE EXPENSIVE_CHECKS_FALSE ACLOCAL_AMFLAGS DOXYGEN HAVE_DOXYGEN_TRUE HAVE_DOXYGEN_FALSE COREFOUNDATION_TRUE COREFOUNDATION_FALSE PKG_CONFIG GLIB_CFLAGS GLIB_LIBS HAVE_GLIB_TRUE HAVE_GLIB_FALSE GLIB_VERSION SOFIA_GLIB_PKG_REQUIRES REPLACE_LIBADD HAVE_TLS_TRUE HAVE_TLS_FALSE HAVE_NTLM_TRUE HAVE_NTLM_FALSE LIBOBJS LTLIBOBJS'
+ac_subst_files=''
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+ac_prev=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
+
+ ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'`
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_option in
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+ | --da=*)
+ datadir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+ { (exit 1); exit 1; }; }
+ ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+ eval "enable_$ac_feature=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+ { (exit 1); exit 1; }; }
+ ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+ case $ac_option in
+ *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "enable_$ac_feature='$ac_optarg'" ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst \
+ | --locals | --local | --loca | --loc | --lo)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid package name: $ac_package" >&2
+ { (exit 1); exit 1; }; }
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case $ac_option in
+ *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_$ac_package='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid package name: $ac_package" >&2
+ { (exit 1); exit 1; }; }
+ ac_package=`echo $ac_package | sed 's/-/_/g'`
+ eval "with_$ac_package=no" ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) { echo "$as_me: error: unrecognized option: $ac_option
+Try \`$0 --help' for more information." >&2
+ { (exit 1); exit 1; }; }
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid variable name: $ac_envvar" >&2
+ { (exit 1); exit 1; }; }
+ ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`
+ eval "$ac_envvar='$ac_optarg'"
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ { echo "$as_me: error: missing argument to $ac_option" >&2
+ { (exit 1); exit 1; }; }
+fi
+
+# Be sure to have absolute paths.
+for ac_var in exec_prefix prefix
+do
+ eval ac_val=$`echo $ac_var`
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* | NONE | '' ) ;;
+ *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# Be sure to have absolute paths.
+for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \
+ localstatedir libdir includedir oldincludedir infodir mandir
+do
+ eval ac_val=$`echo $ac_var`
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) ;;
+ *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
+ If a cross compiler is detected then cross compile mode will be used." >&2
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then its parent.
+ ac_confdir=`(dirname "$0") 2>/dev/null ||
+$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$0" : 'X\(//\)[^/]' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$0" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r $srcdir/$ac_unique_file; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+ if test "$ac_srcdir_defaulted" = yes; then
+ { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2
+ { (exit 1); exit 1; }; }
+ else
+ { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2
+ { (exit 1); exit 1; }; }
+ fi
+fi
+(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null ||
+ { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2
+ { (exit 1); exit 1; }; }
+srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'`
+ac_env_build_alias_set=${build_alias+set}
+ac_env_build_alias_value=$build_alias
+ac_cv_env_build_alias_set=${build_alias+set}
+ac_cv_env_build_alias_value=$build_alias
+ac_env_host_alias_set=${host_alias+set}
+ac_env_host_alias_value=$host_alias
+ac_cv_env_host_alias_set=${host_alias+set}
+ac_cv_env_host_alias_value=$host_alias
+ac_env_target_alias_set=${target_alias+set}
+ac_env_target_alias_value=$target_alias
+ac_cv_env_target_alias_set=${target_alias+set}
+ac_cv_env_target_alias_value=$target_alias
+ac_env_CC_set=${CC+set}
+ac_env_CC_value=$CC
+ac_cv_env_CC_set=${CC+set}
+ac_cv_env_CC_value=$CC
+ac_env_CFLAGS_set=${CFLAGS+set}
+ac_env_CFLAGS_value=$CFLAGS
+ac_cv_env_CFLAGS_set=${CFLAGS+set}
+ac_cv_env_CFLAGS_value=$CFLAGS
+ac_env_LDFLAGS_set=${LDFLAGS+set}
+ac_env_LDFLAGS_value=$LDFLAGS
+ac_cv_env_LDFLAGS_set=${LDFLAGS+set}
+ac_cv_env_LDFLAGS_value=$LDFLAGS
+ac_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_env_CPPFLAGS_value=$CPPFLAGS
+ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_cv_env_CPPFLAGS_value=$CPPFLAGS
+ac_env_SOFIA_CFLAGS_set=${SOFIA_CFLAGS+set}
+ac_env_SOFIA_CFLAGS_value=$SOFIA_CFLAGS
+ac_cv_env_SOFIA_CFLAGS_set=${SOFIA_CFLAGS+set}
+ac_cv_env_SOFIA_CFLAGS_value=$SOFIA_CFLAGS
+ac_env_CPP_set=${CPP+set}
+ac_env_CPP_value=$CPP
+ac_cv_env_CPP_set=${CPP+set}
+ac_cv_env_CPP_value=$CPP
+ac_env_CXX_set=${CXX+set}
+ac_env_CXX_value=$CXX
+ac_cv_env_CXX_set=${CXX+set}
+ac_cv_env_CXX_value=$CXX
+ac_env_CXXFLAGS_set=${CXXFLAGS+set}
+ac_env_CXXFLAGS_value=$CXXFLAGS
+ac_cv_env_CXXFLAGS_set=${CXXFLAGS+set}
+ac_cv_env_CXXFLAGS_value=$CXXFLAGS
+ac_env_CXXCPP_set=${CXXCPP+set}
+ac_env_CXXCPP_value=$CXXCPP
+ac_cv_env_CXXCPP_set=${CXXCPP+set}
+ac_cv_env_CXXCPP_value=$CXXCPP
+ac_env_F77_set=${F77+set}
+ac_env_F77_value=$F77
+ac_cv_env_F77_set=${F77+set}
+ac_cv_env_F77_value=$F77
+ac_env_FFLAGS_set=${FFLAGS+set}
+ac_env_FFLAGS_value=$FFLAGS
+ac_cv_env_FFLAGS_set=${FFLAGS+set}
+ac_cv_env_FFLAGS_value=$FFLAGS
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures sofia-sip 1.12.4work to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+_ACEOF
+
+ cat <<_ACEOF
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --datadir=DIR read-only architecture-independent data [PREFIX/share]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --infodir=DIR info documentation [PREFIX/info]
+ --mandir=DIR man documentation [PREFIX/man]
+_ACEOF
+
+ cat <<\_ACEOF
+
+Program names:
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM run sed PROGRAM on installed program names
+
+System types:
+ --build=BUILD configure for building on BUILD [guessed]
+ --host=HOST cross-compile to build programs to run on HOST [BUILD]
+ --target=TARGET configure for building compilers for TARGET [HOST]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+ case $ac_init_help in
+ short | recursive ) echo "Configuration of sofia-sip 1.12.4work:";;
+ esac
+ cat <<\_ACEOF
+
+Optional Features:
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --enable-maintainer-mode enable make rules and dependencies not useful
+ (and sometimes confusing) to the casual installer
+ --disable-dependency-tracking speeds up one-time build
+ --enable-dependency-tracking do not reject slow dependency extractors
+ --enable-coverage compile test-coverage (disabled)
+ --enable-shared[=PKGS]
+ build shared libraries [default=yes]
+ --enable-static[=PKGS]
+ build static libraries [default=yes]
+ --enable-fast-install[=PKGS]
+ optimize for fast installation [default=yes]
+ --disable-libtool-lock avoid locking (might break parallel builds)
+ --enable-ndebug compile with NDEBUG (disabled)
+ --enable-expensive-checks run also expensive checks (disabled)
+ --disable-size-compat use compatibility size_t types (enabled)
+ --enable-corefoundation compile with OSX COREFOUNDATION (disabled)
+ --disable-stun disable stun module (enabled)
+ --enable-ntlm enable NTLM support (disabled)
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --with-gnu-ld assume the C compiler uses GNU ld [default=no]
+ --with-pic try to use only PIC/non-PIC objects [default=use
+ both]
+ --with-tags[=TAGS]
+ include additional configurations [automatic]
+ --with-rt use POSIX realtime library (used by default)
+ --with-glib=version use GLib (default=2.0)
+ --with-glib-dir=PREFIX explicitly define GLib path
+ --with-openssl use OpenSSL (enabled)
+ --with-sigcomp=dir use Sofia SigComp package (not used by default)
+ --enable-sctp use LK-SCTP (not used by default)
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ CPPFLAGS C/C++ preprocessor flags, e.g. -I<include dir> if you have
+ headers in a nonstandard directory <include dir>
+ SOFIA_CFLAGS
+ CFLAGS not used during configure
+ CPP C preprocessor
+ CXX C++ compiler command
+ CXXFLAGS C++ compiler flags
+ CXXCPP C++ preprocessor
+ F77 Fortran 77 compiler command
+ FFLAGS Fortran 77 compiler flags
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+_ACEOF
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ ac_popdir=`pwd`
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d $ac_dir || continue
+ ac_builddir=.
+
+if test "$ac_dir" != .; then
+ ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+ ac_dir_suffix= ac_top_builddir=
+fi
+
+case $srcdir in
+ .) # No --srcdir option. We are building in place.
+ ac_srcdir=.
+ if test -z "$ac_top_builddir"; then
+ ac_top_srcdir=.
+ else
+ ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+ fi ;;
+ [\\/]* | ?:[\\/]* ) # Absolute path.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir ;;
+ *) # Relative path.
+ ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+
+# Do not use `cd foo && pwd` to compute absolute paths, because
+# the directories may not exist.
+case `pwd` in
+.) ac_abs_builddir="$ac_dir";;
+*)
+ case "$ac_dir" in
+ .) ac_abs_builddir=`pwd`;;
+ [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";;
+ *) ac_abs_builddir=`pwd`/"$ac_dir";;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_builddir=${ac_top_builddir}.;;
+*)
+ case ${ac_top_builddir}. in
+ .) ac_abs_top_builddir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;;
+ *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_srcdir=$ac_srcdir;;
+*)
+ case $ac_srcdir in
+ .) ac_abs_srcdir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;;
+ *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_srcdir=$ac_top_srcdir;;
+*)
+ case $ac_top_srcdir in
+ .) ac_abs_top_srcdir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;;
+ *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;;
+ esac;;
+esac
+
+ cd $ac_dir
+ # Check for guested configure; otherwise get Cygnus style configure.
+ if test -f $ac_srcdir/configure.gnu; then
+ echo
+ $SHELL $ac_srcdir/configure.gnu --help=recursive
+ elif test -f $ac_srcdir/configure; then
+ echo
+ $SHELL $ac_srcdir/configure --help=recursive
+ elif test -f $ac_srcdir/configure.ac ||
+ test -f $ac_srcdir/configure.in; then
+ echo
+ $ac_configure --help
+ else
+ echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi
+ cd $ac_popdir
+ done
+fi
+
+test -n "$ac_init_help" && exit 0
+if $ac_init_version; then
+ cat <<\_ACEOF
+sofia-sip configure 1.12.4work
+generated by GNU Autoconf 2.59
+
+Copyright (C) 2003 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit 0
+fi
+exec 5>config.log
+cat >&5 <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by sofia-sip $as_me 1.12.4work, which was
+generated by GNU Autoconf 2.59. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+hostinfo = `(hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ echo "PATH: $as_dir"
+done
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_sep=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
+ ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;;
+ 2)
+ ac_configure_args1="$ac_configure_args1 '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'"
+ # Get rid of the leading space.
+ ac_sep=" "
+ ;;
+ esac
+ done
+done
+$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; }
+$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; }
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Be sure not to use single quotes in there, as some shells,
+# such as our DU 5.0 friend, will then `close' the trap.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ cat <<\_ASBOX
+## ---------------- ##
+## Cache variables. ##
+## ---------------- ##
+_ASBOX
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+{
+ (set) 2>&1 |
+ case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ sed -n \
+ "s/'"'"'/'"'"'\\\\'"'"''"'"'/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p"
+ ;;
+ *)
+ sed -n \
+ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+ ;;
+ esac;
+}
+ echo
+
+ cat <<\_ASBOX
+## ----------------- ##
+## Output variables. ##
+## ----------------- ##
+_ASBOX
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=$`echo $ac_var`
+ echo "$ac_var='"'"'$ac_val'"'"'"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ cat <<\_ASBOX
+## ------------- ##
+## Output files. ##
+## ------------- ##
+_ASBOX
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=$`echo $ac_var`
+ echo "$ac_var='"'"'$ac_val'"'"'"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ cat <<\_ASBOX
+## ----------- ##
+## confdefs.h. ##
+## ----------- ##
+_ASBOX
+ echo
+ sed "/^$/d" confdefs.h | sort
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ echo "$as_me: caught signal $ac_signal"
+ echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core &&
+ rm -rf conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+ ' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo >confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+ if test "x$prefix" != xNONE; then
+ CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+ else
+ CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+ fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+ if test -r "$ac_site_file"; then
+ { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5
+echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special
+ # files actually), so we avoid doing that.
+ if test -f "$cache_file"; then
+ { echo "$as_me:$LINENO: loading cache $cache_file" >&5
+echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . $cache_file;;
+ *) . ./$cache_file;;
+ esac
+ fi
+else
+ { echo "$as_me:$LINENO: creating cache $cache_file" >&5
+echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in `(set) 2>&1 |
+ sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val="\$ac_cv_env_${ac_var}_value"
+ eval ac_new_val="\$ac_env_${ac_var}_value"
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5
+echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ { echo "$as_me:$LINENO: former value: $ac_old_val" >&5
+echo "$as_me: former value: $ac_old_val" >&2;}
+ { echo "$as_me:$LINENO: current value: $ac_new_val" >&5
+echo "$as_me: current value: $ac_new_val" >&2;}
+ ac_cache_corrupted=:
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
+ ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5
+echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5
+echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+VER_LIBSOFIA_SIP_UA_MAJOR_MINOR=1.12
+
+include_sofiadir='${includedir}/sofia-sip-1.12'
+
+LIBVER_SOFIA_SIP_UA_CUR=3
+
+LIBVER_SOFIA_SIP_UA_REV=0
+
+LIBVER_SOFIA_SIP_UA_AGE=3
+
+LIBVER_SOFIA_SIP_UA_SOVER=0
+ # CUR-AGE
+LIBVER_SOFIA_SIP_UA_GLIB_CUR=3
+
+LIBVER_SOFIA_SIP_UA_GLIB_REV=0
+
+LIBVER_SOFIA_SIP_UA_GLIB_AGE=0
+
+LIBVER_SOFIA_SIP_UA_GLIB_SOVER=3
+ # CUR-AGE
+
+# dnl calls AC_CANONICAL_ macros that are required by AM_INIT_AUTOMAKE
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+ if test -f $ac_dir/install-sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f $ac_dir/install.sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ elif test -f $ac_dir/shtool; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/shtool install -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5
+echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"
+ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure.
+
+# Make sure we can run config.sub.
+$ac_config_sub sun4 >/dev/null 2>&1 ||
+ { { echo "$as_me:$LINENO: error: cannot run $ac_config_sub" >&5
+echo "$as_me: error: cannot run $ac_config_sub" >&2;}
+ { (exit 1); exit 1; }; }
+
+echo "$as_me:$LINENO: checking build system type" >&5
+echo $ECHO_N "checking build system type... $ECHO_C" >&6
+if test "${ac_cv_build+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_build_alias=$build_alias
+test -z "$ac_cv_build_alias" &&
+ ac_cv_build_alias=`$ac_config_guess`
+test -z "$ac_cv_build_alias" &&
+ { { echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5
+echo "$as_me: error: cannot guess build type; you must specify one" >&2;}
+ { (exit 1); exit 1; }; }
+ac_cv_build=`$ac_config_sub $ac_cv_build_alias` ||
+ { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_build_alias failed" >&5
+echo "$as_me: error: $ac_config_sub $ac_cv_build_alias failed" >&2;}
+ { (exit 1); exit 1; }; }
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_build" >&5
+echo "${ECHO_T}$ac_cv_build" >&6
+build=$ac_cv_build
+build_cpu=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+build_vendor=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+build_os=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+
+echo "$as_me:$LINENO: checking host system type" >&5
+echo $ECHO_N "checking host system type... $ECHO_C" >&6
+if test "${ac_cv_host+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_host_alias=$host_alias
+test -z "$ac_cv_host_alias" &&
+ ac_cv_host_alias=$ac_cv_build_alias
+ac_cv_host=`$ac_config_sub $ac_cv_host_alias` ||
+ { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_host_alias failed" >&5
+echo "$as_me: error: $ac_config_sub $ac_cv_host_alias failed" >&2;}
+ { (exit 1); exit 1; }; }
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_host" >&5
+echo "${ECHO_T}$ac_cv_host" >&6
+host=$ac_cv_host
+host_cpu=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+host_vendor=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+host_os=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+
+
+
+
+echo "$as_me:$LINENO: checking target system type" >&5
+echo $ECHO_N "checking target system type... $ECHO_C" >&6
+if test "${ac_cv_target+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_target_alias=$target_alias
+test "x$ac_cv_target_alias" = "x" &&
+ ac_cv_target_alias=$ac_cv_host_alias
+ac_cv_target=`$ac_config_sub $ac_cv_target_alias` ||
+ { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_target_alias failed" >&5
+echo "$as_me: error: $ac_config_sub $ac_cv_target_alias failed" >&2;}
+ { (exit 1); exit 1; }; }
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_target" >&5
+echo "${ECHO_T}$ac_cv_target" >&6
+target=$ac_cv_target
+target_cpu=`echo $ac_cv_target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+target_vendor=`echo $ac_cv_target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+target_os=`echo $ac_cv_target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+
+# The aliases save the names the user supplied, while $host etc.
+# will get canonicalized.
+test -n "$target_alias" &&
+ test "$program_prefix$program_suffix$program_transform_name" = \
+ NONENONEs,x,x, &&
+ program_prefix=${target_alias}-
+
+
+echo "$as_me:$LINENO: checking cached information" >&5
+echo $ECHO_N "checking cached information... $ECHO_C" >&6
+hostcheck="$host"
+if test "${ac_cv_hostcheck+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_hostcheck="$hostcheck"
+fi
+
+if test "$ac_cv_hostcheck" != "$hostcheck"; then
+ echo "$as_me:$LINENO: result: changed" >&5
+echo "${ECHO_T}changed" >&6
+ { echo "$as_me:$LINENO: WARNING: config.cache exists!" >&5
+echo "$as_me: WARNING: config.cache exists!" >&2;}
+ { { echo "$as_me:$LINENO: error: you must do 'make distclean' first to compile
+ for different host or different parameters." >&5
+echo "$as_me: error: you must do 'make distclean' first to compile
+ for different host or different parameters." >&2;}
+ { (exit 1); exit 1; }; }
+else
+ echo "$as_me:$LINENO: result: ok" >&5
+echo "${ECHO_T}ok" >&6
+fi
+
+
+
+
+am__api_version="1.9"
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5
+echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6
+if test -z "$INSTALL"; then
+if test "${ac_cv_path_install+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in
+ ./ | .// | /cC/* | \
+ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+ ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \
+ /usr/ucb/* ) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
+ if test $ac_prog = install &&
+ grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ elif test $ac_prog = install &&
+ grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # program-specific install script used by HP pwplus--don't use.
+ :
+ else
+ ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+ break 3
+ fi
+ fi
+ done
+ done
+ ;;
+esac
+done
+
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL=$ac_cv_path_install
+ else
+ # As a last resort, use the slow shell script. We don't cache a
+ # path for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the path is relative.
+ INSTALL=$ac_install_sh
+ fi
+fi
+echo "$as_me:$LINENO: result: $INSTALL" >&5
+echo "${ECHO_T}$INSTALL" >&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+echo "$as_me:$LINENO: checking whether build environment is sane" >&5
+echo $ECHO_N "checking whether build environment is sane... $ECHO_C" >&6
+# Just in case
+sleep 1
+echo timestamp > conftest.file
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null`
+ if test "$*" = "X"; then
+ # -L didn't work.
+ set X `ls -t $srcdir/configure conftest.file`
+ fi
+ rm -f conftest.file
+ if test "$*" != "X $srcdir/configure conftest.file" \
+ && test "$*" != "X conftest.file $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ { { echo "$as_me:$LINENO: error: ls -t appears to fail. Make sure there is not a broken
+alias in your environment" >&5
+echo "$as_me: error: ls -t appears to fail. Make sure there is not a broken
+alias in your environment" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+
+ test "$2" = conftest.file
+ )
+then
+ # Ok.
+ :
+else
+ { { echo "$as_me:$LINENO: error: newly created file is older than distributed files!
+Check your system clock" >&5
+echo "$as_me: error: newly created file is older than distributed files!
+Check your system clock" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+test "$program_prefix" != NONE &&
+ program_transform_name="s,^,$program_prefix,;$program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+ program_transform_name="s,\$,$program_suffix,;$program_transform_name"
+# Double any \ or $. echo might interpret backslashes.
+# By default was `s,x,x', remove it if useless.
+cat <<\_ACEOF >conftest.sed
+s/[\\$]/&&/g;s/;s,x,x,$//
+_ACEOF
+program_transform_name=`echo $program_transform_name | sed -f conftest.sed`
+rm conftest.sed
+
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+
+test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing"
+# Use eval to expand $SHELL
+if eval "$MISSING --run true"; then
+ am_missing_run="$MISSING --run "
+else
+ am_missing_run=
+ { echo "$as_me:$LINENO: WARNING: \`missing' script is too old or missing" >&5
+echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;}
+fi
+
+if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then
+ # We used to keeping the `.' as first argument, in order to
+ # allow $(mkdir_p) to be used without argument. As in
+ # $(mkdir_p) $(somedir)
+ # where $(somedir) is conditionally defined. However this is wrong
+ # for two reasons:
+ # 1. if the package is installed by a user who cannot write `.'
+ # make install will fail,
+ # 2. the above comment should most certainly read
+ # $(mkdir_p) $(DESTDIR)$(somedir)
+ # so it does not work when $(somedir) is undefined and
+ # $(DESTDIR) is not.
+ # To support the latter case, we have to write
+ # test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir),
+ # so the `.' trick is pointless.
+ mkdir_p='mkdir -p --'
+else
+ # On NextStep and OpenStep, the `mkdir' command does not
+ # recognize any option. It will interpret all options as
+ # directories to create, and then abort because `.' already
+ # exists.
+ for d in ./-p ./--version;
+ do
+ test -d $d && rmdir $d
+ done
+ # $(mkinstalldirs) is defined by Automake if mkinstalldirs exists.
+ if test -f "$ac_aux_dir/mkinstalldirs"; then
+ mkdir_p='$(mkinstalldirs)'
+ else
+ mkdir_p='$(install_sh) -d'
+ fi
+fi
+
+for ac_prog in gawk mawk nawk awk
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_AWK+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$AWK"; then
+ ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_AWK="$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+AWK=$ac_cv_prog_AWK
+if test -n "$AWK"; then
+ echo "$as_me:$LINENO: result: $AWK" >&5
+echo "${ECHO_T}$AWK" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$AWK" && break
+done
+
+echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,:./+-,___p_,'`
+if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.make <<\_ACEOF
+all:
+ @echo 'ac_maketemp="$(MAKE)"'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+ eval ac_cv_prog_make_${ac_make}_set=yes
+else
+ eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftest.make
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ SET_MAKE=
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+ am__leading_dot=.
+else
+ am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+
+# test to see if srcdir already configured
+if test "`cd $srcdir && pwd`" != "`pwd`" &&
+ test -f $srcdir/config.status; then
+ { { echo "$as_me:$LINENO: error: source directory already configured; run \"make distclean\" there first" >&5
+echo "$as_me: error: source directory already configured; run \"make distclean\" there first" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+ if (cygpath --version) >/dev/null 2>/dev/null; then
+ CYGPATH_W='cygpath -w'
+ else
+ CYGPATH_W=echo
+ fi
+fi
+
+
+# Define the identity of the package.
+ PACKAGE='sofia-sip'
+ VERSION='1.12.4work'
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE "$PACKAGE"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define VERSION "$VERSION"
+_ACEOF
+
+# Some tools Automake needs.
+
+ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"}
+
+
+AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"}
+
+
+AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"}
+
+
+AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"}
+
+
+MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
+
+install_sh=${install_sh-"$am_aux_dir/install-sh"}
+
+# Installed binaries are usually stripped using `strip' when the user
+# run `make install-strip'. However `strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the `STRIP' environment variable to overrule this program.
+if test "$cross_compiling" != no; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_STRIP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$STRIP"; then
+ ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+ echo "$as_me:$LINENO: result: $STRIP" >&5
+echo "${ECHO_T}$STRIP" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+ ac_ct_STRIP=$STRIP
+ # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_STRIP"; then
+ ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_STRIP="strip"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ test -z "$ac_cv_prog_ac_ct_STRIP" && ac_cv_prog_ac_ct_STRIP=":"
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+ echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5
+echo "${ECHO_T}$ac_ct_STRIP" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ STRIP=$ac_ct_STRIP
+else
+ STRIP="$ac_cv_prog_STRIP"
+fi
+
+fi
+INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s"
+
+# We need awk for the "check" target. The system "awk" is bad on
+# some platforms.
+# Always define AMTAR for backward compatibility.
+
+AMTAR=${AMTAR-"${am_missing_run}tar"}
+
+am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'
+
+
+
+
+
+echo "$as_me:$LINENO: checking whether to enable maintainer-specific portions of Makefiles" >&5
+echo $ECHO_N "checking whether to enable maintainer-specific portions of Makefiles... $ECHO_C" >&6
+ # Check whether --enable-maintainer-mode or --disable-maintainer-mode was given.
+if test "${enable_maintainer_mode+set}" = set; then
+ enableval="$enable_maintainer_mode"
+ USE_MAINTAINER_MODE=$enableval
+else
+ USE_MAINTAINER_MODE=no
+fi;
+ echo "$as_me:$LINENO: result: $USE_MAINTAINER_MODE" >&5
+echo "${ECHO_T}$USE_MAINTAINER_MODE" >&6
+
+
+if test $USE_MAINTAINER_MODE = yes; then
+ MAINTAINER_MODE_TRUE=
+ MAINTAINER_MODE_FALSE='#'
+else
+ MAINTAINER_MODE_TRUE='#'
+ MAINTAINER_MODE_FALSE=
+fi
+
+ MAINT=$MAINTAINER_MODE_TRUE
+
+
+ ac_config_headers="$ac_config_headers config.h"
+
+
+
+cat >>confdefs.h <<\_ACEOF
+#define _GNU_SOURCE 1
+_ACEOF
+
+
+
+### checks for programs
+### -------------------
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+DEPDIR="${am__leading_dot}deps"
+
+ ac_config_commands="$ac_config_commands depfiles"
+
+
+am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+ @echo done
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+echo "$as_me:$LINENO: checking for style of include used by $am_make" >&5
+echo $ECHO_N "checking for style of include used by $am_make... $ECHO_C" >&6
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# We grep out `Entering directory' and `Leaving directory'
+# messages which can occur if `w' ends up in MAKEFLAGS.
+# In particular we don't look at `^make:' because GNU make might
+# be invoked under some other name (usually "gmake"), in which
+# case it prints its new name instead of `make'.
+if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then
+ am__include=include
+ am__quote=
+ _am_result=GNU
+fi
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+ echo '.include "confinc"' > confmf
+ if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then
+ am__include=.include
+ am__quote="\""
+ _am_result=BSD
+ fi
+fi
+
+
+echo "$as_me:$LINENO: result: $_am_result" >&5
+echo "${ECHO_T}$_am_result" >&6
+rm -f confinc confmf
+
+# Check whether --enable-dependency-tracking or --disable-dependency-tracking was given.
+if test "${enable_dependency_tracking+set}" = set; then
+ enableval="$enable_dependency_tracking"
+
+fi;
+if test "x$enable_dependency_tracking" != xno; then
+ am_depcomp="$ac_aux_dir/depcomp"
+ AMDEPBACKSLASH='\'
+fi
+
+
+if test "x$enable_dependency_tracking" != xno; then
+ AMDEP_TRUE=
+ AMDEP_FALSE='#'
+else
+ AMDEP_TRUE='#'
+ AMDEP_FALSE=
+fi
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ CC=$ac_ct_CC
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ CC=$ac_ct_CC
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$ac_ct_CC" && break
+done
+
+ CC=$ac_ct_CC
+fi
+
+fi
+
+
+test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&5
+echo "$as_me: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+
+# Provide some information about the compiler.
+echo "$as_me:$LINENO:" \
+ "checking for C compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5
+ (eval $ac_compiler --version </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v </dev/null >&5\"") >&5
+ (eval $ac_compiler -v </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V </dev/null >&5\"") >&5
+ (eval $ac_compiler -V </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+echo "$as_me:$LINENO: checking for C compiler default output file name" >&5
+echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6
+ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5
+ (eval $ac_link_default) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # Find the output, starting from the most likely. This scheme is
+# not robust to junk in `.', hence go to wildcards (a.*) only as a last
+# resort.
+
+# Be careful to initialize this variable, since it used to be cached.
+# Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile.
+ac_cv_exeext=
+# b.out is created by i960 compilers.
+for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj )
+ ;;
+ conftest.$ac_ext )
+ # This is the source file.
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ # FIXME: I believe we export ac_cv_exeext for Libtool,
+ # but it would be cool to find out if it's true. Does anybody
+ # maintain Libtool? --akim.
+ export ac_cv_exeext
+ break;;
+ * )
+ break;;
+ esac
+done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: C compiler cannot create executables
+See \`config.log' for more details." >&5
+echo "$as_me: error: C compiler cannot create executables
+See \`config.log' for more details." >&2;}
+ { (exit 77); exit 77; }; }
+fi
+
+ac_exeext=$ac_cv_exeext
+echo "$as_me:$LINENO: result: $ac_file" >&5
+echo "${ECHO_T}$ac_file" >&6
+
+# Check the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+echo "$as_me:$LINENO: checking whether the C compiler works" >&5
+echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6
+# FIXME: These cross compiler hacks should be removed for Autoconf 3.0
+# If not cross compiling, check that we can run a simple program.
+if test "$cross_compiling" != yes; then
+ if { ac_try='./$ac_file'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { echo "$as_me:$LINENO: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ fi
+fi
+echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+
+rm -f a.out a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+# Check the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+echo "$as_me:$LINENO: checking whether we are cross compiling" >&5
+echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6
+echo "$as_me:$LINENO: result: $cross_compiling" >&5
+echo "${ECHO_T}$cross_compiling" >&6
+
+echo "$as_me:$LINENO: checking for suffix of executables" >&5
+echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ export ac_cv_exeext
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest$ac_cv_exeext
+echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5
+echo "${ECHO_T}$ac_cv_exeext" >&6
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+echo "$as_me:$LINENO: checking for suffix of object files" >&5
+echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6
+if test "${ac_cv_objext+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_objext" >&5
+echo "${ECHO_T}$ac_cv_objext" >&6
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6
+if test "${ac_cv_c_compiler_gnu+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_compiler_gnu=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_compiler_gnu=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6
+GCC=`test $ac_compiler_gnu = yes && echo yes`
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+CFLAGS="-g"
+echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
+echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_g+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_prog_cc_g=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_prog_cc_g=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_g" >&6
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5
+echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_stdc+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_prog_cc_stdc=no
+ac_save_CC=$CC
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std1 is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std1. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX -qlanglvl=ansi
+# Ultrix and OSF/1 -std1
+# HP-UX 10.20 and later -Ae
+# HP-UX older versions -Aa -D_HPUX_SOURCE
+# SVR4 -Xc -D__EXTENSIONS__
+for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_prog_cc_stdc=$ac_arg
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext
+done
+rm -f conftest.$ac_ext conftest.$ac_objext
+CC=$ac_save_CC
+
+fi
+
+case "x$ac_cv_prog_cc_stdc" in
+ x|xno)
+ echo "$as_me:$LINENO: result: none needed" >&5
+echo "${ECHO_T}none needed" >&6 ;;
+ *)
+ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6
+ CC="$CC $ac_cv_prog_cc_stdc" ;;
+esac
+
+# Some people use a C++ compiler to compile C. Since we use `exit',
+# in C++ we need to declare it. In case someone uses the same compiler
+# for both compiling C and C++ we need to have the C++ compiler decide
+# the declaration of exit, since it's the most demanding environment.
+cat >conftest.$ac_ext <<_ACEOF
+#ifndef __cplusplus
+ choke me
+#endif
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ for ac_declaration in \
+ '' \
+ 'extern "C" void std::exit (int) throw (); using std::exit;' \
+ 'extern "C" void std::exit (int); using std::exit;' \
+ 'extern "C" void exit (int) throw ();' \
+ 'extern "C" void exit (int);' \
+ 'void exit (int);'
+do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_declaration
+#include <stdlib.h>
+int
+main ()
+{
+exit (42);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+continue
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_declaration
+int
+main ()
+{
+exit (42);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+rm -f conftest*
+if test -n "$ac_declaration"; then
+ echo '#ifdef __cplusplus' >>confdefs.h
+ echo $ac_declaration >>confdefs.h
+ echo '#endif' >>confdefs.h
+fi
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+depcc="$CC" am_compiler_list=
+
+echo "$as_me:$LINENO: checking dependency style of $depcc" >&5
+echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6
+if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named `D' -- because `-MD' means `put the output
+ # in D'.
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_CC_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+ fi
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
+ # Solaris 8's {/usr,}/bin/sh.
+ touch sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ case $depmode in
+ nosideeffect)
+ # after this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ none) break ;;
+ esac
+ # We check with `-c' and `-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle `-M -o', and we need to detect this.
+ if depmode=$depmode \
+ source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_CC_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_CC_dependencies_compiler_type=none
+fi
+
+fi
+echo "$as_me:$LINENO: result: $am_cv_CC_dependencies_compiler_type" >&5
+echo "${ECHO_T}$am_cv_CC_dependencies_compiler_type" >&6
+CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
+
+
+
+if
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
+ am__fastdepCC_TRUE=
+ am__fastdepCC_FALSE='#'
+else
+ am__fastdepCC_TRUE='#'
+ am__fastdepCC_FALSE=
+fi
+
+
+
+
+echo "$as_me:$LINENO: checking for compilation environment" >&5
+echo $ECHO_N "checking for compilation environment... $ECHO_C" >&6
+if test "${ac_cc_environment+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+machine=`$CC -dumpmachine`
+if test "$machine" = mingw32 ; then
+ ac_cc_environment=$machine
+fi
+
+fi
+echo "$as_me:$LINENO: result: $ac_cc_environment" >&5
+echo "${ECHO_T}$ac_cc_environment" >&6
+
+if test "$ac_cc_environment" = mingw32 ; then
+CFLAGS="$CFLAGS -I\$(top_srcdir)/win32/pthread -DWINVER=0x0501 \
+ -D_WIN32_WINNT=0x0501 -DIN_LIBSOFIA_SIP_UA -DIN_LIBSOFIA_SRES \
+ -mms-bitfields \
+ -pipe -mno-cygwin -mwindows -mconsole -Wall -g -O0"
+LDFLAGS="$LDFLAGS -Wl,--enable-auto-image-base"
+LIBS="-L\$(top_srcdir)/win32/pthread -lpthreadVC2 -lws2_32 \
+ -lwsock32"
+MINGW_ENVIRONMENT=1
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_MINGW 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_WIN32 1
+_ACEOF
+
+fi
+
+
+if test "x$ac_cc_environment" != x; then
+ HAVE_MINGW32_TRUE=
+ HAVE_MINGW32_FALSE='#'
+else
+ HAVE_MINGW32_TRUE='#'
+ HAVE_MINGW32_FALSE=
+fi
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ test -z "$ac_cv_prog_ac_ct_CC" && ac_cv_prog_ac_ct_CC="gcc"
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ CC=$ac_ct_CC
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ test -z "$ac_cv_prog_ac_ct_CC" && ac_cv_prog_ac_ct_CC="cc"
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ CC=$ac_ct_CC
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+ if test -z "$CC"; then
+ case "`uname -s`" in
+ *win32* | *WIN32* ) # Extract the first word of "cl", so it can be a program name with args.
+set dummy cl; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="cl"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+ ;;
+ esac
+ fi
+ test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable cc found in \$PATH" >&5
+echo "$as_me: error: no acceptable cc found in \$PATH" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ CC=$ac_ct_CC
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ CC=$ac_ct_CC
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$ac_ct_CC" && break
+done
+
+ CC=$ac_ct_CC
+fi
+
+fi
+
+
+test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&5
+echo "$as_me: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+
+# Provide some information about the compiler.
+echo "$as_me:$LINENO:" \
+ "checking for C compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5
+ (eval $ac_compiler --version </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v </dev/null >&5\"") >&5
+ (eval $ac_compiler -v </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V </dev/null >&5\"") >&5
+ (eval $ac_compiler -V </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+
+echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6
+if test "${ac_cv_c_compiler_gnu+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_compiler_gnu=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_compiler_gnu=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6
+GCC=`test $ac_compiler_gnu = yes && echo yes`
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+CFLAGS="-g"
+echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
+echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_g+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_prog_cc_g=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_prog_cc_g=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_g" >&6
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5
+echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_stdc+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_prog_cc_stdc=no
+ac_save_CC=$CC
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std1 is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std1. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX -qlanglvl=ansi
+# Ultrix and OSF/1 -std1
+# HP-UX 10.20 and later -Ae
+# HP-UX older versions -Aa -D_HPUX_SOURCE
+# SVR4 -Xc -D__EXTENSIONS__
+for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_prog_cc_stdc=$ac_arg
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext
+done
+rm -f conftest.$ac_ext conftest.$ac_objext
+CC=$ac_save_CC
+
+fi
+
+case "x$ac_cv_prog_cc_stdc" in
+ x|xno)
+ echo "$as_me:$LINENO: result: none needed" >&5
+echo "${ECHO_T}none needed" >&6 ;;
+ *)
+ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6
+ CC="$CC $ac_cv_prog_cc_stdc" ;;
+esac
+
+# Some people use a C++ compiler to compile C. Since we use `exit',
+# in C++ we need to declare it. In case someone uses the same compiler
+# for both compiling C and C++ we need to have the C++ compiler decide
+# the declaration of exit, since it's the most demanding environment.
+cat >conftest.$ac_ext <<_ACEOF
+#ifndef __cplusplus
+ choke me
+#endif
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ for ac_declaration in \
+ '' \
+ 'extern "C" void std::exit (int) throw (); using std::exit;' \
+ 'extern "C" void std::exit (int); using std::exit;' \
+ 'extern "C" void exit (int) throw ();' \
+ 'extern "C" void exit (int);' \
+ 'void exit (int);'
+do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_declaration
+#include <stdlib.h>
+int
+main ()
+{
+exit (42);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+continue
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_declaration
+int
+main ()
+{
+exit (42);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+rm -f conftest*
+if test -n "$ac_declaration"; then
+ echo '#ifdef __cplusplus' >>confdefs.h
+ echo $ac_declaration >>confdefs.h
+ echo '#endif' >>confdefs.h
+fi
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+depcc="$CC" am_compiler_list=
+
+echo "$as_me:$LINENO: checking dependency style of $depcc" >&5
+echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6
+if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named `D' -- because `-MD' means `put the output
+ # in D'.
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_CC_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+ fi
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
+ # Solaris 8's {/usr,}/bin/sh.
+ touch sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ case $depmode in
+ nosideeffect)
+ # after this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ none) break ;;
+ esac
+ # We check with `-c' and `-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle `-M -o', and we need to detect this.
+ if depmode=$depmode \
+ source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_CC_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_CC_dependencies_compiler_type=none
+fi
+
+fi
+echo "$as_me:$LINENO: result: $am_cv_CC_dependencies_compiler_type" >&5
+echo "${ECHO_T}$am_cv_CC_dependencies_compiler_type" >&6
+CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
+
+
+
+if
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
+ am__fastdepCC_TRUE=
+ am__fastdepCC_FALSE='#'
+else
+ am__fastdepCC_TRUE='#'
+ am__fastdepCC_FALSE=
+fi
+
+
+
+#
+# Wall
+#
+echo "$as_me:$LINENO: checking for maximum warnings compiler flag" >&5
+echo $ECHO_N "checking for maximum warnings compiler flag... $ECHO_C" >&6
+if test "${ac_cv_cwflag+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case "${CC-cc}" in
+ *gcc*) ac_cv_cwflag=-Wall;;
+ *) case "$host" in
+ *irix*) ac_cv_cwflag=-fullwarn ;;
+ *solaris*) ac_cv_cwflag="-erroff=%none,E_END_OF_LOOP_CODE_NOT_REACHED -xCC"
+ ;;
+ *) ac_cv_cwflag=;;
+ esac
+ ;;
+esac
+fi
+echo "$as_me:$LINENO: result: $ac_cv_cwflag" >&5
+echo "${ECHO_T}$ac_cv_cwflag" >&6
+CWFLAG=$ac_cv_cwflag
+
+
+
+
+#
+# GCoverage
+#
+# Check whether --enable-coverage or --disable-coverage was given.
+if test "${enable_coverage+set}" = set; then
+ enableval="$enable_coverage"
+
+else
+ enable_coverage=no
+fi;
+
+if test X$enable_coverage != Xno ; then
+case "${CC-cc}" in
+ *gcc*)
+ SOFIA_CFLAGS="$SOFIA_CFLAGS -fprofile-arcs -ftest-coverage"
+ ;;
+ *) { { echo "$as_me:$LINENO: error: --enable-coverage requires gcc" >&5
+echo "$as_me: error: --enable-coverage requires gcc" >&2;}
+ { (exit 1); exit 1; }; }
+esac
+fi
+
+
+
+if test X$enable_coverage != Xno; then
+ ENABLE_COVERAGE_TRUE=
+ ENABLE_COVERAGE_FALSE='#'
+else
+ ENABLE_COVERAGE_TRUE='#'
+ ENABLE_COVERAGE_FALSE=
+fi
+
+
+MOSTLYCLEANFILES="*.bb *.bbg *.da *.gcov *.gcda *.gcno"
+
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5
+echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6
+if test -z "$INSTALL"; then
+if test "${ac_cv_path_install+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in
+ ./ | .// | /cC/* | \
+ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+ ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \
+ /usr/ucb/* ) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
+ if test $ac_prog = install &&
+ grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ elif test $ac_prog = install &&
+ grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # program-specific install script used by HP pwplus--don't use.
+ :
+ else
+ ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+ break 3
+ fi
+ fi
+ done
+ done
+ ;;
+esac
+done
+
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL=$ac_cv_path_install
+ else
+ # As a last resort, use the slow shell script. We don't cache a
+ # path for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the path is relative.
+ INSTALL=$ac_install_sh
+ fi
+fi
+echo "$as_me:$LINENO: result: $INSTALL" >&5
+echo "${ECHO_T}$INSTALL" >&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5
+echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+ if test "${ac_cv_prog_CPP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ # Double quotes because CPP needs to be expanded
+ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether non-existent headers
+ # can be detected and how.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ # Broken: success on invalid input.
+continue
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+ break
+fi
+
+ done
+ ac_cv_prog_CPP=$CPP
+
+fi
+ CPP=$ac_cv_prog_CPP
+else
+ ac_cv_prog_CPP=$CPP
+fi
+echo "$as_me:$LINENO: result: $CPP" >&5
+echo "${ECHO_T}$CPP" >&6
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether non-existent headers
+ # can be detected and how.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ # Broken: success on invalid input.
+continue
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+ :
+else
+ { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&5
+echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+# Extract the first word of "etags", so it can be a program name with args.
+set dummy etags; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ETAGS+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ETAGS"; then
+ ac_cv_prog_ETAGS="$ETAGS" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ETAGS="etags"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ test -z "$ac_cv_prog_ETAGS" && ac_cv_prog_ETAGS="echo"
+fi
+fi
+ETAGS=$ac_cv_prog_ETAGS
+if test -n "$ETAGS"; then
+ echo "$as_me:$LINENO: result: $ETAGS" >&5
+echo "${ECHO_T}$ETAGS" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ar; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_AR+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$AR"; then
+ ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_AR="${ac_tool_prefix}ar"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+AR=$ac_cv_prog_AR
+if test -n "$AR"; then
+ echo "$as_me:$LINENO: result: $AR" >&5
+echo "${ECHO_T}$AR" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_AR"; then
+ ac_ct_AR=$AR
+ # Extract the first word of "ar", so it can be a program name with args.
+set dummy ar; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_AR+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_AR"; then
+ ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_AR="ar"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ test -z "$ac_cv_prog_ac_ct_AR" && ac_cv_prog_ac_ct_AR="ar"
+fi
+fi
+ac_ct_AR=$ac_cv_prog_ac_ct_AR
+if test -n "$ac_ct_AR"; then
+ echo "$as_me:$LINENO: result: $ac_ct_AR" >&5
+echo "${ECHO_T}$ac_ct_AR" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ AR=$ac_ct_AR
+else
+ AR="$ac_cv_prog_AR"
+fi
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ld", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ld; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_LD+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$LD"; then
+ ac_cv_prog_LD="$LD" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_LD="${ac_tool_prefix}ld"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+LD=$ac_cv_prog_LD
+if test -n "$LD"; then
+ echo "$as_me:$LINENO: result: $LD" >&5
+echo "${ECHO_T}$LD" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_LD"; then
+ ac_ct_LD=$LD
+ # Extract the first word of "ld", so it can be a program name with args.
+set dummy ld; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_LD+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_LD"; then
+ ac_cv_prog_ac_ct_LD="$ac_ct_LD" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_LD="ld"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ test -z "$ac_cv_prog_ac_ct_LD" && ac_cv_prog_ac_ct_LD="ld"
+fi
+fi
+ac_ct_LD=$ac_cv_prog_ac_ct_LD
+if test -n "$ac_ct_LD"; then
+ echo "$as_me:$LINENO: result: $ac_ct_LD" >&5
+echo "${ECHO_T}$ac_ct_LD" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ LD=$ac_ct_LD
+else
+ LD="$ac_cv_prog_LD"
+fi
+
+# Check whether --enable-shared or --disable-shared was given.
+if test "${enable_shared+set}" = set; then
+ enableval="$enable_shared"
+ p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_shared=yes ;;
+ no) enable_shared=no ;;
+ *)
+ enable_shared=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_shared=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac
+else
+ enable_shared=yes
+fi;
+
+# Check whether --enable-static or --disable-static was given.
+if test "${enable_static+set}" = set; then
+ enableval="$enable_static"
+ p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_static=yes ;;
+ no) enable_static=no ;;
+ *)
+ enable_static=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_static=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac
+else
+ enable_static=yes
+fi;
+
+# Check whether --enable-fast-install or --disable-fast-install was given.
+if test "${enable_fast_install+set}" = set; then
+ enableval="$enable_fast_install"
+ p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_fast_install=yes ;;
+ no) enable_fast_install=no ;;
+ *)
+ enable_fast_install=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_fast_install=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac
+else
+ enable_fast_install=yes
+fi;
+
+echo "$as_me:$LINENO: checking for a sed that does not truncate output" >&5
+echo $ECHO_N "checking for a sed that does not truncate output... $ECHO_C" >&6
+if test "${lt_cv_path_SED+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ # Loop through the user's path and test for sed and gsed.
+# Then use that list of sed's as ones to test for truncation.
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for lt_ac_prog in sed gsed; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then
+ lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext"
+ fi
+ done
+ done
+done
+lt_ac_max=0
+lt_ac_count=0
+# Add /usr/xpg4/bin/sed as it is typically found on Solaris
+# along with /bin/sed that truncates output.
+for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
+ test ! -f $lt_ac_sed && break
+ cat /dev/null > conftest.in
+ lt_ac_count=0
+ echo $ECHO_N "0123456789$ECHO_C" >conftest.in
+ # Check for GNU sed and select it if it is found.
+ if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then
+ lt_cv_path_SED=$lt_ac_sed
+ break
+ fi
+ while true; do
+ cat conftest.in conftest.in >conftest.tmp
+ mv conftest.tmp conftest.in
+ cp conftest.in conftest.nl
+ echo >>conftest.nl
+ $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break
+ cmp -s conftest.out conftest.nl || break
+ # 10000 chars as input seems more than enough
+ test $lt_ac_count -gt 10 && break
+ lt_ac_count=`expr $lt_ac_count + 1`
+ if test $lt_ac_count -gt $lt_ac_max; then
+ lt_ac_max=$lt_ac_count
+ lt_cv_path_SED=$lt_ac_sed
+ fi
+ done
+done
+SED=$lt_cv_path_SED
+
+fi
+
+echo "$as_me:$LINENO: result: $SED" >&5
+echo "${ECHO_T}$SED" >&6
+
+echo "$as_me:$LINENO: checking for egrep" >&5
+echo $ECHO_N "checking for egrep... $ECHO_C" >&6
+if test "${ac_cv_prog_egrep+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if echo a | (grep -E '(a|b)') >/dev/null 2>&1
+ then ac_cv_prog_egrep='grep -E'
+ else ac_cv_prog_egrep='egrep'
+ fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5
+echo "${ECHO_T}$ac_cv_prog_egrep" >&6
+ EGREP=$ac_cv_prog_egrep
+
+
+
+# Check whether --with-gnu-ld or --without-gnu-ld was given.
+if test "${with_gnu_ld+set}" = set; then
+ withval="$with_gnu_ld"
+ test "$withval" = no || with_gnu_ld=yes
+else
+ with_gnu_ld=no
+fi;
+ac_prog=ld
+if test "$GCC" = yes; then
+ # Check if gcc -print-prog-name=ld gives a path.
+ echo "$as_me:$LINENO: checking for ld used by $CC" >&5
+echo $ECHO_N "checking for ld used by $CC... $ECHO_C" >&6
+ case $host in
+ *-*-mingw*)
+ # gcc leaves a trailing carriage return which upsets mingw
+ ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+ *)
+ ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+ esac
+ case $ac_prog in
+ # Accept absolute paths.
+ [\\/]* | ?:[\\/]*)
+ re_direlt='/[^/][^/]*/\.\./'
+ # Canonicalize the pathname of ld
+ ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'`
+ while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do
+ ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"`
+ done
+ test -z "$LD" && LD="$ac_prog"
+ ;;
+ "")
+ # If it fails, then pretend we aren't using GCC.
+ ac_prog=ld
+ ;;
+ *)
+ # If it is relative, then search for the first ld in PATH.
+ with_gnu_ld=unknown
+ ;;
+ esac
+elif test "$with_gnu_ld" = yes; then
+ echo "$as_me:$LINENO: checking for GNU ld" >&5
+echo $ECHO_N "checking for GNU ld... $ECHO_C" >&6
+else
+ echo "$as_me:$LINENO: checking for non-GNU ld" >&5
+echo $ECHO_N "checking for non-GNU ld... $ECHO_C" >&6
+fi
+if test "${lt_cv_path_LD+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -z "$LD"; then
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+ lt_cv_path_LD="$ac_dir/$ac_prog"
+ # Check to see if the program is GNU ld. I'd rather use --version,
+ # but apparently some GNU ld's only accept -v.
+ # Break only if it was the GNU/non-GNU ld that we prefer.
+ case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+ *GNU* | *'with BFD'*)
+ test "$with_gnu_ld" != no && break
+ ;;
+ *)
+ test "$with_gnu_ld" != yes && break
+ ;;
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+else
+ lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi
+fi
+
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+ echo "$as_me:$LINENO: result: $LD" >&5
+echo "${ECHO_T}$LD" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+test -z "$LD" && { { echo "$as_me:$LINENO: error: no acceptable ld found in \$PATH" >&5
+echo "$as_me: error: no acceptable ld found in \$PATH" >&2;}
+ { (exit 1); exit 1; }; }
+echo "$as_me:$LINENO: checking if the linker ($LD) is GNU ld" >&5
+echo $ECHO_N "checking if the linker ($LD) is GNU ld... $ECHO_C" >&6
+if test "${lt_cv_prog_gnu_ld+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ # I'd rather use --version here, but apparently some GNU ld's only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+ lt_cv_prog_gnu_ld=yes
+ ;;
+*)
+ lt_cv_prog_gnu_ld=no
+ ;;
+esac
+fi
+echo "$as_me:$LINENO: result: $lt_cv_prog_gnu_ld" >&5
+echo "${ECHO_T}$lt_cv_prog_gnu_ld" >&6
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+
+echo "$as_me:$LINENO: checking for $LD option to reload object files" >&5
+echo $ECHO_N "checking for $LD option to reload object files... $ECHO_C" >&6
+if test "${lt_cv_ld_reload_flag+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_cv_ld_reload_flag='-r'
+fi
+echo "$as_me:$LINENO: result: $lt_cv_ld_reload_flag" >&5
+echo "${ECHO_T}$lt_cv_ld_reload_flag" >&6
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+
+echo "$as_me:$LINENO: checking for BSD-compatible nm" >&5
+echo $ECHO_N "checking for BSD-compatible nm... $ECHO_C" >&6
+if test "${lt_cv_path_NM+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$NM"; then
+ # Let the user override the test.
+ lt_cv_path_NM="$NM"
+else
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ tmp_nm="$ac_dir/${ac_tool_prefix}nm"
+ if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+ # Check to see if the nm accepts a BSD-compat flag.
+ # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+ # nm: unknown option "B" ignored
+ # Tru64's nm complains that /dev/null is an invalid object file
+ case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+ */dev/null* | *'Invalid file or object type'*)
+ lt_cv_path_NM="$tmp_nm -B"
+ break
+ ;;
+ *)
+ case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+ */dev/null*)
+ lt_cv_path_NM="$tmp_nm -p"
+ break
+ ;;
+ *)
+ lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+ continue # so that we can try to find one that supports BSD flags
+ ;;
+ esac
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+ test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm
+fi
+fi
+echo "$as_me:$LINENO: result: $lt_cv_path_NM" >&5
+echo "${ECHO_T}$lt_cv_path_NM" >&6
+NM="$lt_cv_path_NM"
+
+echo "$as_me:$LINENO: checking whether ln -s works" >&5
+echo $ECHO_N "checking whether ln -s works... $ECHO_C" >&6
+LN_S=$as_ln_s
+if test "$LN_S" = "ln -s"; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+else
+ echo "$as_me:$LINENO: result: no, using $LN_S" >&5
+echo "${ECHO_T}no, using $LN_S" >&6
+fi
+
+echo "$as_me:$LINENO: checking how to recognise dependent libraries" >&5
+echo $ECHO_N "checking how to recognise dependent libraries... $ECHO_C" >&6
+if test "${lt_cv_deplibs_check_method+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# `unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# which responds to the $file_magic_cmd with a given extended regex.
+# If you have `file' or equivalent on your system and you're not sure
+# whether `pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix4* | aix5*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+beos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+bsdi4*)
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)'
+ lt_cv_file_magic_cmd='/usr/bin/file -L'
+ lt_cv_file_magic_test_file=/shlib/libc.so
+ ;;
+
+cygwin*)
+ # func_win32_libid is a shell function defined in ltmain.sh
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ ;;
+
+mingw* | pw32*)
+ # Base MSYS/MinGW do not provide the 'file' command needed by
+ # func_win32_libid shell function, so use a weaker test based on 'objdump'.
+ lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?'
+ lt_cv_file_magic_cmd='$OBJDUMP -f'
+ ;;
+
+darwin* | rhapsody*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+freebsd* | kfreebsd*-gnu)
+ if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then
+ case $host_cpu in
+ i*86 )
+ # Not sure whether the presence of OpenBSD here was a mistake.
+ # Let's accept both of them until this is cleared up.
+ lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD)/i[3-9]86 (compact )?demand paged shared library'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+ ;;
+ esac
+ else
+ lt_cv_deplibs_check_method=pass_all
+ fi
+ ;;
+
+gnu*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+hpux10.20* | hpux11*)
+ lt_cv_file_magic_cmd=/usr/bin/file
+ case "$host_cpu" in
+ ia64*)
+ lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64'
+ lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+ ;;
+ hppa*64*)
+ lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]'
+ lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+ ;;
+ *)
+ lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9].[0-9]) shared library'
+ lt_cv_file_magic_test_file=/usr/lib/libc.sl
+ ;;
+ esac
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $LD in
+ *-32|*"-32 ") libmagic=32-bit;;
+ *-n32|*"-n32 ") libmagic=N32;;
+ *-64|*"-64 ") libmagic=64-bit;;
+ *) libmagic=never-match;;
+ esac
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+# This must be Linux ELF.
+linux*)
+ case $host_cpu in
+ alpha*|hppa*|i*86|ia64*|m68*|mips*|powerpc*|sparc*|s390*|sh*|x86_64*)
+ lt_cv_deplibs_check_method=pass_all ;;
+ *)
+ # glibc up to 2.1.1 does not perform some relocations on ARM
+ # this will be overridden with pass_all, but let us keep it just in case
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' ;;
+ esac
+ lt_cv_file_magic_test_file=`echo /lib/libc.so* /lib/libc-*.so`
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+netbsd*)
+ if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$'
+ fi
+ ;;
+
+newos6*)
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=/usr/lib/libnls.so
+ ;;
+
+nto-qnx*)
+ lt_cv_deplibs_check_method=unknown
+ ;;
+
+openbsd*)
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB shared object'
+ else
+ lt_cv_deplibs_check_method='file_magic OpenBSD.* shared library'
+ fi
+ ;;
+
+osf3* | osf4* | osf5*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sco3.2v5*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+solaris*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ case $host_vendor in
+ motorola)
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]'
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+ ;;
+ ncr)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ sequent)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )'
+ ;;
+ sni)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib"
+ lt_cv_file_magic_test_file=/lib/libc.so
+ ;;
+ siemens)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ esac
+ ;;
+
+sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[78]* | unixware7* | sysv4*uw2*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+esac
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_deplibs_check_method" >&5
+echo "${ECHO_T}$lt_cv_deplibs_check_method" >&6
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+# Check whether --enable-libtool-lock or --disable-libtool-lock was given.
+if test "${enable_libtool_lock+set}" = set; then
+ enableval="$enable_libtool_lock"
+
+fi;
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *ELF-32*)
+ HPUX_IA64_MODE="32"
+ ;;
+ *ELF-64*)
+ HPUX_IA64_MODE="64"
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+*-*-irix6*)
+ # Find out which ABI we are using.
+ echo '#line 5473 "configure"' > conftest.$ac_ext
+ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -melf32bsmip"
+ ;;
+ *N32*)
+ LD="${LD-ld} -melf32bmipn32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -melf64bmip"
+ ;;
+ esac
+ else
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -32"
+ ;;
+ *N32*)
+ LD="${LD-ld} -n32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -64"
+ ;;
+ esac
+ fi
+ fi
+ rm -rf conftest*
+ ;;
+
+x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ case "`/usr/bin/file conftest.o`" in
+ *32-bit*)
+ case $host in
+ x86_64-*linux*)
+ LD="${LD-ld} -m elf_i386"
+ ;;
+ ppc64-*linux*|powerpc64-*linux*)
+ LD="${LD-ld} -m elf32ppclinux"
+ ;;
+ s390x-*linux*)
+ LD="${LD-ld} -m elf_s390"
+ ;;
+ sparc64-*linux*)
+ LD="${LD-ld} -m elf32_sparc"
+ ;;
+ esac
+ ;;
+ *64-bit*)
+ case $host in
+ x86_64-*linux*)
+ LD="${LD-ld} -m elf_x86_64"
+ ;;
+ ppc*-*linux*|powerpc*-*linux*)
+ LD="${LD-ld} -m elf64ppc"
+ ;;
+ s390*-*linux*)
+ LD="${LD-ld} -m elf64_s390"
+ ;;
+ sparc*-*linux*)
+ LD="${LD-ld} -m elf64_sparc"
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+
+*-*-sco3.2v5*)
+ # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+ SAVE_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -belf"
+ echo "$as_me:$LINENO: checking whether the C compiler needs -belf" >&5
+echo $ECHO_N "checking whether the C compiler needs -belf... $ECHO_C" >&6
+if test "${lt_cv_cc_needs_belf+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ lt_cv_cc_needs_belf=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+lt_cv_cc_needs_belf=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_cc_needs_belf" >&5
+echo "${ECHO_T}$lt_cv_cc_needs_belf" >&6
+ if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+ # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+ CFLAGS="$SAVE_CFLAGS"
+ fi
+ ;;
+
+esac
+
+need_locks="$enable_libtool_lock"
+
+
+
+echo "$as_me:$LINENO: checking for ANSI C header files" >&5
+echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6
+if test "${ac_cv_header_stdc+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_header_stdc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_header_stdc=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "memchr" >/dev/null 2>&1; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "free" >/dev/null 2>&1; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+ if test "$cross_compiling" = yes; then
+ :
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ctype.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+ (('a' <= (c) && (c) <= 'i') \
+ || ('j' <= (c) && (c) <= 'r') \
+ || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ if (XOR (islower (i), ISLOWER (i))
+ || toupper (i) != TOUPPER (i))
+ exit(2);
+ exit (0);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_header_stdc=no
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5
+echo "${ECHO_T}$ac_cv_header_stdc" >&6
+if test $ac_cv_header_stdc = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define STDC_HEADERS 1
+_ACEOF
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+
+
+
+
+
+
+
+
+
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+ inttypes.h stdint.h unistd.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_Header=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_Header=no"
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+for ac_header in dlfcn.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to the sofia-sip lists. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+ac_ext=cc
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ for ac_prog in $CCC g++ c++ gpp aCC CC cxx cc++ cl FCC KCC RCC xlC_r xlC
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CXX+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CXX"; then
+ ac_cv_prog_CXX="$CXX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CXX="$ac_tool_prefix$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CXX=$ac_cv_prog_CXX
+if test -n "$CXX"; then
+ echo "$as_me:$LINENO: result: $CXX" >&5
+echo "${ECHO_T}$CXX" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$CXX" && break
+ done
+fi
+if test -z "$CXX"; then
+ ac_ct_CXX=$CXX
+ for ac_prog in $CCC g++ c++ gpp aCC CC cxx cc++ cl FCC KCC RCC xlC_r xlC
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CXX"; then
+ ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CXX="$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CXX=$ac_cv_prog_ac_ct_CXX
+if test -n "$ac_ct_CXX"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CXX" >&5
+echo "${ECHO_T}$ac_ct_CXX" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$ac_ct_CXX" && break
+done
+test -n "$ac_ct_CXX" || ac_ct_CXX="g++"
+
+ CXX=$ac_ct_CXX
+fi
+
+
+# Provide some information about the compiler.
+echo "$as_me:$LINENO:" \
+ "checking for C++ compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5
+ (eval $ac_compiler --version </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v </dev/null >&5\"") >&5
+ (eval $ac_compiler -v </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V </dev/null >&5\"") >&5
+ (eval $ac_compiler -V </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+
+echo "$as_me:$LINENO: checking whether we are using the GNU C++ compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU C++ compiler... $ECHO_C" >&6
+if test "${ac_cv_cxx_compiler_gnu+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_cxx_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_compiler_gnu=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_compiler_gnu=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_cxx_compiler_gnu=$ac_compiler_gnu
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_cxx_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_cxx_compiler_gnu" >&6
+GXX=`test $ac_compiler_gnu = yes && echo yes`
+ac_test_CXXFLAGS=${CXXFLAGS+set}
+ac_save_CXXFLAGS=$CXXFLAGS
+CXXFLAGS="-g"
+echo "$as_me:$LINENO: checking whether $CXX accepts -g" >&5
+echo $ECHO_N "checking whether $CXX accepts -g... $ECHO_C" >&6
+if test "${ac_cv_prog_cxx_g+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_cxx_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_prog_cxx_g=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_prog_cxx_g=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_cxx_g" >&5
+echo "${ECHO_T}$ac_cv_prog_cxx_g" >&6
+if test "$ac_test_CXXFLAGS" = set; then
+ CXXFLAGS=$ac_save_CXXFLAGS
+elif test $ac_cv_prog_cxx_g = yes; then
+ if test "$GXX" = yes; then
+ CXXFLAGS="-g -O2"
+ else
+ CXXFLAGS="-g"
+ fi
+else
+ if test "$GXX" = yes; then
+ CXXFLAGS="-O2"
+ else
+ CXXFLAGS=
+ fi
+fi
+for ac_declaration in \
+ '' \
+ 'extern "C" void std::exit (int) throw (); using std::exit;' \
+ 'extern "C" void std::exit (int); using std::exit;' \
+ 'extern "C" void exit (int) throw ();' \
+ 'extern "C" void exit (int);' \
+ 'void exit (int);'
+do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_declaration
+#include <stdlib.h>
+int
+main ()
+{
+exit (42);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_cxx_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+continue
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_declaration
+int
+main ()
+{
+exit (42);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_cxx_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+rm -f conftest*
+if test -n "$ac_declaration"; then
+ echo '#ifdef __cplusplus' >>confdefs.h
+ echo $ac_declaration >>confdefs.h
+ echo '#endif' >>confdefs.h
+fi
+
+ac_ext=cc
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+depcc="$CXX" am_compiler_list=
+
+echo "$as_me:$LINENO: checking dependency style of $depcc" >&5
+echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6
+if test "${am_cv_CXX_dependencies_compiler_type+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named `D' -- because `-MD' means `put the output
+ # in D'.
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_CXX_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+ fi
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
+ # Solaris 8's {/usr,}/bin/sh.
+ touch sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ case $depmode in
+ nosideeffect)
+ # after this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ none) break ;;
+ esac
+ # We check with `-c' and `-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle `-M -o', and we need to detect this.
+ if depmode=$depmode \
+ source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_CXX_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_CXX_dependencies_compiler_type=none
+fi
+
+fi
+echo "$as_me:$LINENO: result: $am_cv_CXX_dependencies_compiler_type" >&5
+echo "${ECHO_T}$am_cv_CXX_dependencies_compiler_type" >&6
+CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type
+
+
+
+if
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then
+ am__fastdepCXX_TRUE=
+ am__fastdepCXX_FALSE='#'
+else
+ am__fastdepCXX_TRUE='#'
+ am__fastdepCXX_FALSE=
+fi
+
+
+ac_ext=cc
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+echo "$as_me:$LINENO: checking how to run the C++ preprocessor" >&5
+echo $ECHO_N "checking how to run the C++ preprocessor... $ECHO_C" >&6
+if test -z "$CXXCPP"; then
+ if test "${ac_cv_prog_CXXCPP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ # Double quotes because CXXCPP needs to be expanded
+ for CXXCPP in "$CXX -E" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_cxx_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_cxx_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether non-existent headers
+ # can be detected and how.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_cxx_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ # Broken: success on invalid input.
+continue
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+ break
+fi
+
+ done
+ ac_cv_prog_CXXCPP=$CXXCPP
+
+fi
+ CXXCPP=$ac_cv_prog_CXXCPP
+else
+ ac_cv_prog_CXXCPP=$CXXCPP
+fi
+echo "$as_me:$LINENO: result: $CXXCPP" >&5
+echo "${ECHO_T}$CXXCPP" >&6
+ac_preproc_ok=false
+for ac_cxx_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_cxx_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether non-existent headers
+ # can be detected and how.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_cxx_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ # Broken: success on invalid input.
+continue
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+ :
+else
+ { { echo "$as_me:$LINENO: error: C++ preprocessor \"$CXXCPP\" fails sanity check
+See \`config.log' for more details." >&5
+echo "$as_me: error: C++ preprocessor \"$CXXCPP\" fails sanity check
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+ac_ext=cc
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+
+ac_ext=f
+ac_compile='$F77 -c $FFLAGS conftest.$ac_ext >&5'
+ac_link='$F77 -o conftest$ac_exeext $FFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_f77_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ for ac_prog in g77 f77 xlf frt pgf77 fort77 fl32 af77 f90 xlf90 pgf90 epcf90 f95 fort xlf95 ifc efc pgf95 lf95 gfortran
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_F77+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$F77"; then
+ ac_cv_prog_F77="$F77" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_F77="$ac_tool_prefix$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+F77=$ac_cv_prog_F77
+if test -n "$F77"; then
+ echo "$as_me:$LINENO: result: $F77" >&5
+echo "${ECHO_T}$F77" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$F77" && break
+ done
+fi
+if test -z "$F77"; then
+ ac_ct_F77=$F77
+ for ac_prog in g77 f77 xlf frt pgf77 fort77 fl32 af77 f90 xlf90 pgf90 epcf90 f95 fort xlf95 ifc efc pgf95 lf95 gfortran
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_F77+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_F77"; then
+ ac_cv_prog_ac_ct_F77="$ac_ct_F77" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_F77="$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_F77=$ac_cv_prog_ac_ct_F77
+if test -n "$ac_ct_F77"; then
+ echo "$as_me:$LINENO: result: $ac_ct_F77" >&5
+echo "${ECHO_T}$ac_ct_F77" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$ac_ct_F77" && break
+done
+
+ F77=$ac_ct_F77
+fi
+
+
+# Provide some information about the compiler.
+echo "$as_me:6811:" \
+ "checking for Fortran 77 compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5
+ (eval $ac_compiler --version </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v </dev/null >&5\"") >&5
+ (eval $ac_compiler -v </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V </dev/null >&5\"") >&5
+ (eval $ac_compiler -V </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+rm -f a.out
+
+# If we don't use `.F' as extension, the preprocessor is not run on the
+# input file. (Note that this only needs to work for GNU compilers.)
+ac_save_ext=$ac_ext
+ac_ext=F
+echo "$as_me:$LINENO: checking whether we are using the GNU Fortran 77 compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU Fortran 77 compiler... $ECHO_C" >&6
+if test "${ac_cv_f77_compiler_gnu+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+ program main
+#ifndef __GNUC__
+ choke me
+#endif
+
+ end
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_f77_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_compiler_gnu=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_compiler_gnu=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_f77_compiler_gnu=$ac_compiler_gnu
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_f77_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_f77_compiler_gnu" >&6
+ac_ext=$ac_save_ext
+ac_test_FFLAGS=${FFLAGS+set}
+ac_save_FFLAGS=$FFLAGS
+FFLAGS=
+echo "$as_me:$LINENO: checking whether $F77 accepts -g" >&5
+echo $ECHO_N "checking whether $F77 accepts -g... $ECHO_C" >&6
+if test "${ac_cv_prog_f77_g+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ FFLAGS=-g
+cat >conftest.$ac_ext <<_ACEOF
+ program main
+
+ end
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_f77_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_prog_f77_g=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_prog_f77_g=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_f77_g" >&5
+echo "${ECHO_T}$ac_cv_prog_f77_g" >&6
+if test "$ac_test_FFLAGS" = set; then
+ FFLAGS=$ac_save_FFLAGS
+elif test $ac_cv_prog_f77_g = yes; then
+ if test "x$ac_cv_f77_compiler_gnu" = xyes; then
+ FFLAGS="-g -O2"
+ else
+ FFLAGS="-g"
+ fi
+else
+ if test "x$ac_cv_f77_compiler_gnu" = xyes; then
+ FFLAGS="-O2"
+ else
+ FFLAGS=
+ fi
+fi
+
+G77=`test $ac_compiler_gnu = yes && echo yes`
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+# Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers!
+
+# find the maximum length of command line arguments
+echo "$as_me:$LINENO: checking the maximum length of command line arguments" >&5
+echo $ECHO_N "checking the maximum length of command line arguments... $ECHO_C" >&6
+if test "${lt_cv_sys_max_cmd_len+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ i=0
+ teststring="ABCD"
+
+ case $build_os in
+ msdosdjgpp*)
+ # On DJGPP, this test can blow up pretty badly due to problems in libc
+ # (any single argument exceeding 2000 bytes causes a buffer overrun
+ # during glob expansion). Even if it were fixed, the result of this
+ # check would be larger than it should be.
+ lt_cv_sys_max_cmd_len=12288; # 12K is about right
+ ;;
+
+ gnu*)
+ # Under GNU Hurd, this test is not required because there is
+ # no limit to the length of command line arguments.
+ # Libtool will interpret -1 as no limit whatsoever
+ lt_cv_sys_max_cmd_len=-1;
+ ;;
+
+ cygwin* | mingw*)
+ # On Win9x/ME, this test blows up -- it succeeds, but takes
+ # about 5 minutes as the teststring grows exponentially.
+ # Worse, since 9x/ME are not pre-emptively multitasking,
+ # you end up with a "frozen" computer, even though with patience
+ # the test eventually succeeds (with a max line length of 256k).
+ # Instead, let's just punt: use the minimum linelength reported by
+ # all of the supported platforms: 8192 (on NT/2K/XP).
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ amigaos*)
+ # On AmigaOS with pdksh, this test takes hours, literally.
+ # So we just punt and use a minimum line length of 8192.
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ *)
+ # If test is not a shell built-in, we'll probably end up computing a
+ # maximum length that is only half of the actual maximum length, but
+ # we can't tell.
+ while (test "X"`$CONFIG_SHELL $0 --fallback-echo "X$teststring" 2>/dev/null` \
+ = "XX$teststring") >/dev/null 2>&1 &&
+ new_result=`expr "X$teststring" : ".*" 2>&1` &&
+ lt_cv_sys_max_cmd_len=$new_result &&
+ test $i != 17 # 1/2 MB should be enough
+ do
+ i=`expr $i + 1`
+ teststring=$teststring$teststring
+ done
+ teststring=
+ # Add a significant safety factor because C++ compilers can tack on massive
+ # amounts of additional arguments before passing them to the linker.
+ # It appears as though 1/2 is a usable value.
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+ ;;
+ esac
+
+fi
+
+if test -n $lt_cv_sys_max_cmd_len ; then
+ echo "$as_me:$LINENO: result: $lt_cv_sys_max_cmd_len" >&5
+echo "${ECHO_T}$lt_cv_sys_max_cmd_len" >&6
+else
+ echo "$as_me:$LINENO: result: none" >&5
+echo "${ECHO_T}none" >&6
+fi
+
+
+
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+echo "$as_me:$LINENO: checking command to parse $NM output from $compiler object" >&5
+echo $ECHO_N "checking command to parse $NM output from $compiler object... $ECHO_C" >&6
+if test "${lt_cv_sys_global_symbol_pipe+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix. What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[BCDEGRST]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([_A-Za-z][_A-Za-z0-9]*\)'
+
+# Transform the above into a raw symbol and a C symbol.
+symxfrm='\1 \2\3 \3'
+
+# Transform an extracted symbol line into a proper C declaration
+lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern int \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([^ ]*\) \([^ ]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'"
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+ symcode='[BCDT]'
+ ;;
+cygwin* | mingw* | pw32*)
+ symcode='[ABCDGISTW]'
+ ;;
+hpux*) # Its linker distinguishes data from code symbols
+ if test "$host_cpu" = ia64; then
+ symcode='[ABCDEGRST]'
+ fi
+ lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+ lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'"
+ ;;
+irix* | nonstopux*)
+ symcode='[BCDEGRST]'
+ ;;
+osf*)
+ symcode='[BCDEGQRST]'
+ ;;
+solaris* | sysv5*)
+ symcode='[BDRT]'
+ ;;
+sysv4)
+ symcode='[DFNSTU]'
+ ;;
+esac
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+ opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+ ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+ symcode='[ABCDGIRSTW]' ;;
+esac
+
+# Try without a prefix undercore, then with it.
+for ac_symprfx in "" "_"; do
+
+ # Write the raw and C identifiers.
+ lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*\($ac_symprfx\)$sympat$opt_cr$/$symxfrm/p'"
+
+ # Check to see that the pipe works correctly.
+ pipe_works=no
+
+ rm -f conftest*
+ cat > conftest.$ac_ext <<EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+EOF
+
+ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # Now try to grab the symbols.
+ nlist=conftest.nm
+ if { (eval echo "$as_me:$LINENO: \"$NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist\"") >&5
+ (eval $NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && test -s "$nlist"; then
+ # Try sorting and uniquifying the output.
+ if sort "$nlist" | uniq > "$nlist"T; then
+ mv -f "$nlist"T "$nlist"
+ else
+ rm -f "$nlist"T
+ fi
+
+ # Make sure that we snagged all the symbols we need.
+ if grep ' nm_test_var$' "$nlist" >/dev/null; then
+ if grep ' nm_test_func$' "$nlist" >/dev/null; then
+ cat <<EOF > conftest.$ac_ext
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+EOF
+ # Now generate the symbol file.
+ eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | grep -v main >> conftest.$ac_ext'
+
+ cat <<EOF >> conftest.$ac_ext
+#if defined (__STDC__) && __STDC__
+# define lt_ptr_t void *
+#else
+# define lt_ptr_t char *
+# define const
+#endif
+
+/* The mapping between symbol names and symbols. */
+const struct {
+ const char *name;
+ lt_ptr_t address;
+}
+lt_preloaded_symbols[] =
+{
+EOF
+ $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (lt_ptr_t) \&\2},/" < "$nlist" | grep -v main >> conftest.$ac_ext
+ cat <<\EOF >> conftest.$ac_ext
+ {0, (lt_ptr_t) 0}
+};
+
+#ifdef __cplusplus
+}
+#endif
+EOF
+ # Now try linking the two files.
+ mv conftest.$ac_objext conftstm.$ac_objext
+ lt_save_LIBS="$LIBS"
+ lt_save_CFLAGS="$CFLAGS"
+ LIBS="conftstm.$ac_objext"
+ CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag"
+ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && test -s conftest${ac_exeext}; then
+ pipe_works=yes
+ fi
+ LIBS="$lt_save_LIBS"
+ CFLAGS="$lt_save_CFLAGS"
+ else
+ echo "cannot find nm_test_func in $nlist" >&5
+ fi
+ else
+ echo "cannot find nm_test_var in $nlist" >&5
+ fi
+ else
+ echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5
+ fi
+ else
+ echo "$progname: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ fi
+ rm -f conftest* conftst*
+
+ # Do not use the global_symbol_pipe unless it works.
+ if test "$pipe_works" = yes; then
+ break
+ else
+ lt_cv_sys_global_symbol_pipe=
+ fi
+done
+
+fi
+
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+ lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+ echo "$as_me:$LINENO: result: failed" >&5
+echo "${ECHO_T}failed" >&6
+else
+ echo "$as_me:$LINENO: result: ok" >&5
+echo "${ECHO_T}ok" >&6
+fi
+
+echo "$as_me:$LINENO: checking for objdir" >&5
+echo $ECHO_N "checking for objdir... $ECHO_C" >&6
+if test "${lt_cv_objdir+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+ lt_cv_objdir=.libs
+else
+ # MS-DOS does not allow filenames that begin with a dot.
+ lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null
+fi
+echo "$as_me:$LINENO: result: $lt_cv_objdir" >&5
+echo "${ECHO_T}$lt_cv_objdir" >&6
+objdir=$lt_cv_objdir
+
+
+
+
+
+case $host_os in
+aix3*)
+ # AIX sometimes has problems with the GCC collect2 program. For some
+ # reason, if we set the COLLECT_NAMES environment variable, the problems
+ # vanish in a puff of smoke.
+ if test "X${COLLECT_NAMES+set}" != Xset; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+ fi
+ ;;
+esac
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed='sed -e s/^X//'
+sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+
+# Constants:
+rm="rm -f"
+
+# Global variables:
+default_ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a `.a' archive for static linking (except M$VC,
+# which needs '.lib').
+libext=a
+ltmain="$ac_aux_dir/ltmain.sh"
+ofile="$default_ofile"
+with_gnu_ld="$lt_cv_prog_gnu_ld"
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ar; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_AR+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$AR"; then
+ ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_AR="${ac_tool_prefix}ar"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+AR=$ac_cv_prog_AR
+if test -n "$AR"; then
+ echo "$as_me:$LINENO: result: $AR" >&5
+echo "${ECHO_T}$AR" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_AR"; then
+ ac_ct_AR=$AR
+ # Extract the first word of "ar", so it can be a program name with args.
+set dummy ar; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_AR+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_AR"; then
+ ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_AR="ar"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ test -z "$ac_cv_prog_ac_ct_AR" && ac_cv_prog_ac_ct_AR="false"
+fi
+fi
+ac_ct_AR=$ac_cv_prog_ac_ct_AR
+if test -n "$ac_ct_AR"; then
+ echo "$as_me:$LINENO: result: $ac_ct_AR" >&5
+echo "${ECHO_T}$ac_ct_AR" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ AR=$ac_ct_AR
+else
+ AR="$ac_cv_prog_AR"
+fi
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_RANLIB+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+ echo "$as_me:$LINENO: result: $RANLIB" >&5
+echo "${ECHO_T}$RANLIB" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+ ac_ct_RANLIB=$RANLIB
+ # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_RANLIB"; then
+ ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_RANLIB="ranlib"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ test -z "$ac_cv_prog_ac_ct_RANLIB" && ac_cv_prog_ac_ct_RANLIB=":"
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+ echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5
+echo "${ECHO_T}$ac_ct_RANLIB" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ RANLIB=$ac_ct_RANLIB
+else
+ RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_STRIP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$STRIP"; then
+ ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+ echo "$as_me:$LINENO: result: $STRIP" >&5
+echo "${ECHO_T}$STRIP" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+ ac_ct_STRIP=$STRIP
+ # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_STRIP"; then
+ ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_STRIP="strip"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ test -z "$ac_cv_prog_ac_ct_STRIP" && ac_cv_prog_ac_ct_STRIP=":"
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+ echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5
+echo "${ECHO_T}$ac_ct_STRIP" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ STRIP=$ac_ct_STRIP
+else
+ STRIP="$ac_cv_prog_STRIP"
+fi
+
+
+old_CC="$CC"
+old_CFLAGS="$CFLAGS"
+
+# Set sane defaults for various variables
+test -z "$AR" && AR=ar
+test -z "$AR_FLAGS" && AR_FLAGS=cru
+test -z "$AS" && AS=as
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+test -z "$LD" && LD=ld
+test -z "$LN_S" && LN_S="ln -s"
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+test -z "$NM" && NM=nm
+test -z "$SED" && SED=sed
+test -z "$OBJDUMP" && OBJDUMP=objdump
+test -z "$RANLIB" && RANLIB=:
+test -z "$STRIP" && STRIP=:
+test -z "$ac_objext" && ac_objext=o
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+ case $host_os in
+ openbsd*)
+ old_postinstall_cmds="\$RANLIB -t \$oldlib~$old_postinstall_cmds"
+ ;;
+ *)
+ old_postinstall_cmds="\$RANLIB \$oldlib~$old_postinstall_cmds"
+ ;;
+ esac
+ old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib"
+fi
+
+# Only perform the check for file, if the check method requires it
+case $deplibs_check_method in
+file_magic*)
+ if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+ echo "$as_me:$LINENO: checking for ${ac_tool_prefix}file" >&5
+echo $ECHO_N "checking for ${ac_tool_prefix}file... $ECHO_C" >&6
+if test "${lt_cv_path_MAGIC_CMD+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $MAGIC_CMD in
+[\\/*] | ?:[\\/]*)
+ lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+ ;;
+*)
+ lt_save_MAGIC_CMD="$MAGIC_CMD"
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+ for ac_dir in $ac_dummy; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/${ac_tool_prefix}file; then
+ lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file"
+ if test -n "$file_magic_test_file"; then
+ case $deplibs_check_method in
+ "file_magic "*)
+ file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`"
+ MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+ if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ :
+ else
+ cat <<EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such. This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem. Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool at gnu.org
+
+EOF
+ fi ;;
+ esac
+ fi
+ break
+ fi
+ done
+ IFS="$lt_save_ifs"
+ MAGIC_CMD="$lt_save_MAGIC_CMD"
+ ;;
+esac
+fi
+
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+ echo "$as_me:$LINENO: result: $MAGIC_CMD" >&5
+echo "${ECHO_T}$MAGIC_CMD" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+ if test -n "$ac_tool_prefix"; then
+ echo "$as_me:$LINENO: checking for file" >&5
+echo $ECHO_N "checking for file... $ECHO_C" >&6
+if test "${lt_cv_path_MAGIC_CMD+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $MAGIC_CMD in
+[\\/*] | ?:[\\/]*)
+ lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+ ;;
+*)
+ lt_save_MAGIC_CMD="$MAGIC_CMD"
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+ for ac_dir in $ac_dummy; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/file; then
+ lt_cv_path_MAGIC_CMD="$ac_dir/file"
+ if test -n "$file_magic_test_file"; then
+ case $deplibs_check_method in
+ "file_magic "*)
+ file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`"
+ MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+ if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ :
+ else
+ cat <<EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such. This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem. Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool at gnu.org
+
+EOF
+ fi ;;
+ esac
+ fi
+ break
+ fi
+ done
+ IFS="$lt_save_ifs"
+ MAGIC_CMD="$lt_save_MAGIC_CMD"
+ ;;
+esac
+fi
+
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+ echo "$as_me:$LINENO: result: $MAGIC_CMD" >&5
+echo "${ECHO_T}$MAGIC_CMD" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ else
+ MAGIC_CMD=:
+ fi
+fi
+
+ fi
+ ;;
+esac
+
+enable_dlopen=no
+enable_win32_dll=no
+
+# Check whether --enable-libtool-lock or --disable-libtool-lock was given.
+if test "${enable_libtool_lock+set}" = set; then
+ enableval="$enable_libtool_lock"
+
+fi;
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+
+# Check whether --with-pic or --without-pic was given.
+if test "${with_pic+set}" = set; then
+ withval="$with_pic"
+ pic_mode="$withval"
+else
+ pic_mode=default
+fi;
+test -z "$pic_mode" && pic_mode=default
+
+# Use C for the default configuration in the libtool script
+tagname=
+lt_save_CC="$CC"
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+objext=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;\n"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}\n'
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+#
+# Check for any special shared library compilation flags.
+#
+lt_prog_cc_shlib=
+if test "$GCC" = no; then
+ case $host_os in
+ sco3.2v5*)
+ lt_prog_cc_shlib='-belf'
+ ;;
+ esac
+fi
+if test -n "$lt_prog_cc_shlib"; then
+ { echo "$as_me:$LINENO: WARNING: \`$CC' requires \`$lt_prog_cc_shlib' to build shared libraries" >&5
+echo "$as_me: WARNING: \`$CC' requires \`$lt_prog_cc_shlib' to build shared libraries" >&2;}
+ if echo "$old_CC $old_CFLAGS " | grep "[ ]$lt_prog_cc_shlib[ ]" >/dev/null; then :
+ else
+ { echo "$as_me:$LINENO: WARNING: add \`$lt_prog_cc_shlib' to the CC or CFLAGS env variable and reconfigure" >&5
+echo "$as_me: WARNING: add \`$lt_prog_cc_shlib' to the CC or CFLAGS env variable and reconfigure" >&2;}
+ lt_cv_prog_cc_can_build_shared=no
+ fi
+fi
+
+
+#
+# Check to make sure the static flag actually works.
+#
+echo "$as_me:$LINENO: checking if $compiler static flag $lt_prog_compiler_static works" >&5
+echo $ECHO_N "checking if $compiler static flag $lt_prog_compiler_static works... $ECHO_C" >&6
+if test "${lt_prog_compiler_static_works+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_prog_compiler_static_works=no
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS $lt_prog_compiler_static"
+ printf "$lt_simple_link_test_code" > conftest.$ac_ext
+ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s conftest.err; then
+ # Append any errors to the config.log.
+ cat conftest.err 1>&5
+ else
+ lt_prog_compiler_static_works=yes
+ fi
+ fi
+ $rm conftest*
+ LDFLAGS="$save_LDFLAGS"
+
+fi
+echo "$as_me:$LINENO: result: $lt_prog_compiler_static_works" >&5
+echo "${ECHO_T}$lt_prog_compiler_static_works" >&6
+
+if test x"$lt_prog_compiler_static_works" = xyes; then
+ :
+else
+ lt_prog_compiler_static=
+fi
+
+
+
+
+lt_prog_compiler_no_builtin_flag=
+
+if test "$GCC" = yes; then
+ lt_prog_compiler_no_builtin_flag=' -fno-builtin'
+
+
+echo "$as_me:$LINENO: checking if $compiler supports -fno-rtti -fno-exceptions" >&5
+echo $ECHO_N "checking if $compiler supports -fno-rtti -fno-exceptions... $ECHO_C" >&6
+if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_cv_prog_compiler_rtti_exceptions=no
+ ac_outfile=conftest.$ac_objext
+ printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="-fno-rtti -fno-exceptions"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:7845: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&5
+ echo "$as_me:7849: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test ! -s conftest.err; then
+ lt_cv_prog_compiler_rtti_exceptions=yes
+ fi
+ fi
+ $rm conftest*
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_rtti_exceptions" >&5
+echo "${ECHO_T}$lt_cv_prog_compiler_rtti_exceptions" >&6
+
+if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then
+ lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions"
+else
+ :
+fi
+
+fi
+
+lt_prog_compiler_wl=
+lt_prog_compiler_pic=
+lt_prog_compiler_static=
+
+echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5
+echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
+
+ if test "$GCC" = yes; then
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_static='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static='-Bstatic'
+ fi
+ ;;
+
+ amigaos*)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the `-m68020' flag to GCC prevents building anything better,
+ # like `-m68040'.
+ lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4'
+ ;;
+
+ beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+
+ mingw* | pw32* | os2*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ lt_prog_compiler_pic='-DDLL_EXPORT'
+ ;;
+
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ lt_prog_compiler_pic='-fno-common'
+ ;;
+
+ msdosdjgpp*)
+ # Just because we use GCC doesn't mean we suddenly get shared libraries
+ # on systems that don't support them.
+ lt_prog_compiler_can_build_shared=no
+ enable_shared=no
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ lt_prog_compiler_pic=-Kconform_pic
+ fi
+ ;;
+
+ hpux*)
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case "$host_cpu" in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ lt_prog_compiler_pic='-fPIC'
+ ;;
+ esac
+ ;;
+
+ *)
+ lt_prog_compiler_pic='-fPIC'
+ ;;
+ esac
+ else
+ # PORTME Check for flag to pass linker flags through the system compiler.
+ case $host_os in
+ aix*)
+ lt_prog_compiler_wl='-Wl,'
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static='-Bstatic'
+ else
+ lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+
+ mingw* | pw32* | os2*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ lt_prog_compiler_pic='-DDLL_EXPORT'
+ ;;
+
+ hpux9* | hpux10* | hpux11*)
+ lt_prog_compiler_wl='-Wl,'
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case "$host_cpu" in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ lt_prog_compiler_pic='+Z'
+ ;;
+ esac
+ # Is there a better lt_prog_compiler_static that works with the bundled CC?
+ lt_prog_compiler_static='${wl}-a ${wl}archive'
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ lt_prog_compiler_wl='-Wl,'
+ # PIC (with -KPIC) is the default.
+ lt_prog_compiler_static='-non_shared'
+ ;;
+
+ newsos6)
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ linux*)
+ case $CC in
+ icc* | ecc*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-static'
+ ;;
+ ccc*)
+ lt_prog_compiler_wl='-Wl,'
+ # All Alpha code is PIC.
+ lt_prog_compiler_static='-non_shared'
+ ;;
+ esac
+ ;;
+
+ osf3* | osf4* | osf5*)
+ lt_prog_compiler_wl='-Wl,'
+ # All OSF/1 code is PIC.
+ lt_prog_compiler_static='-non_shared'
+ ;;
+
+ sco3.2v5*)
+ lt_prog_compiler_pic='-Kpic'
+ lt_prog_compiler_static='-dn'
+ ;;
+
+ solaris*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ sunos4*)
+ lt_prog_compiler_wl='-Qoption ld '
+ lt_prog_compiler_pic='-PIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec ;then
+ lt_prog_compiler_pic='-Kconform_pic'
+ lt_prog_compiler_static='-Bstatic'
+ fi
+ ;;
+
+ uts4*)
+ lt_prog_compiler_pic='-pic'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ *)
+ lt_prog_compiler_can_build_shared=no
+ ;;
+ esac
+ fi
+
+echo "$as_me:$LINENO: result: $lt_prog_compiler_pic" >&5
+echo "${ECHO_T}$lt_prog_compiler_pic" >&6
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$lt_prog_compiler_pic"; then
+
+echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5
+echo $ECHO_N "checking if $compiler PIC flag $lt_prog_compiler_pic works... $ECHO_C" >&6
+if test "${lt_prog_compiler_pic_works+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_prog_compiler_pic_works=no
+ ac_outfile=conftest.$ac_objext
+ printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="$lt_prog_compiler_pic -DPIC"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:8078: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&5
+ echo "$as_me:8082: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test ! -s conftest.err; then
+ lt_prog_compiler_pic_works=yes
+ fi
+ fi
+ $rm conftest*
+
+fi
+echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_works" >&5
+echo "${ECHO_T}$lt_prog_compiler_pic_works" >&6
+
+if test x"$lt_prog_compiler_pic_works" = xyes; then
+ case $lt_prog_compiler_pic in
+ "" | " "*) ;;
+ *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;;
+ esac
+else
+ lt_prog_compiler_pic=
+ lt_prog_compiler_can_build_shared=no
+fi
+
+fi
+case "$host_os" in
+ # For platforms which do not support PIC, -DPIC is meaningless:
+ *djgpp*)
+ lt_prog_compiler_pic=
+ ;;
+ *)
+ lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC"
+ ;;
+esac
+
+echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5
+echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6
+if test "${lt_cv_prog_compiler_c_o+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_cv_prog_compiler_c_o=no
+ $rm -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:8138: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&5
+ echo "$as_me:8142: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test ! -s out/conftest.err; then
+ lt_cv_prog_compiler_c_o=yes
+ fi
+ fi
+ chmod u+w .
+ $rm conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files
+ $rm out/* && rmdir out
+ cd ..
+ rmdir conftest
+ $rm conftest*
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o" >&5
+echo "${ECHO_T}$lt_cv_prog_compiler_c_o" >&6
+
+
+hard_links="nottested"
+if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then
+ # do not overwrite the value of need_locks provided by the user
+ echo "$as_me:$LINENO: checking if we can lock with hard links" >&5
+echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6
+ hard_links=yes
+ $rm conftest*
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ touch conftest.a
+ ln conftest.a conftest.b 2>&5 || hard_links=no
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ echo "$as_me:$LINENO: result: $hard_links" >&5
+echo "${ECHO_T}$hard_links" >&6
+ if test "$hard_links" = no; then
+ { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
+echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
+ need_locks=warn
+ fi
+else
+ need_locks=no
+fi
+
+echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6
+
+ runpath_var=
+ allow_undefined_flag=
+ enable_shared_with_static_runtimes=no
+ archive_cmds=
+ archive_expsym_cmds=
+ old_archive_From_new_cmds=
+ old_archive_from_expsyms_cmds=
+ export_dynamic_flag_spec=
+ whole_archive_flag_spec=
+ thread_safe_flag_spec=
+ hardcode_libdir_flag_spec=
+ hardcode_libdir_flag_spec_ld=
+ hardcode_libdir_separator=
+ hardcode_direct=no
+ hardcode_minus_L=no
+ hardcode_shlibpath_var=unsupported
+ link_all_deplibs=unknown
+ hardcode_automatic=no
+ module_cmds=
+ module_expsym_cmds=
+ always_export_symbols=no
+ export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ # include_expsyms should be a list of space-separated symbols to be *always*
+ # included in the symbol list
+ include_expsyms=
+ # exclude_expsyms can be an extended regexp of symbols to exclude
+ # it will be wrapped by ` (' and `)$', so one must not match beginning or
+ # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+ # as well as any symbol that contains `d'.
+ exclude_expsyms="_GLOBAL_OFFSET_TABLE_"
+ # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+ # platforms (ab)use it in PIC code, but their linkers get confused if
+ # the symbol is explicitly referenced. Since portable code cannot
+ # rely on this symbol name, it's probably fine to never include it in
+ # preloaded symbol tables.
+ extract_expsyms_cmds=
+
+ case $host_os in
+ cygwin* | mingw* | pw32*)
+ # FIXME: the MSVC++ port hasn't been tested in a loooong time
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ if test "$GCC" != yes; then
+ with_gnu_ld=no
+ fi
+ ;;
+ openbsd*)
+ with_gnu_ld=no
+ ;;
+ esac
+
+ ld_shlibs=yes
+ if test "$with_gnu_ld" = yes; then
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ wlarc='${wl}'
+
+ # See if GNU ld supports shared libraries.
+ case $host_os in
+ aix3* | aix4* | aix5*)
+ # On AIX/PPC, the GNU linker is very broken
+ if test "$host_cpu" != ia64; then
+ ld_shlibs=no
+ cat <<EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.9.1, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support. If you
+*** really care for shared libraries, you may want to modify your PATH
+*** so that a non-GNU linker is found, and then restart.
+
+EOF
+ fi
+ ;;
+
+ amigaos*)
+ archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+
+ # Samuel A. Falvo II <kc5tja at dolphin.openprojects.net> reports
+ # that the semantics of dynamic libraries on AmigaOS, at least up
+ # to version 4, is to share data among multiple programs linked
+ # with the same dynamic library. Since this doesn't match the
+ # behavior of shared libraries on other platforms, we can't use
+ # them.
+ ld_shlibs=no
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ allow_undefined_flag=unsupported
+ # Joseph Beckenbach <jrb3 at best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ cygwin* | mingw* | pw32*)
+ # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless,
+ # as there is no search path for DLLs.
+ hardcode_libdir_flag_spec='-L$libdir'
+ allow_undefined_flag=unsupported
+ always_export_symbols=no
+ enable_shared_with_static_runtimes=yes
+ export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGS] /s/.* \([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW] /s/.* //'\'' | sort | uniq > $export_symbols'
+
+ if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+ # If the export-symbols file already is a .def file (1st line
+ # is EXPORTS), use it as is; otherwise, prepend...
+ archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+ archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+ wlarc=
+ else
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ fi
+ ;;
+
+ solaris* | sysv5*)
+ if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then
+ ld_shlibs=no
+ cat <<EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+EOF
+ elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ sunos4*)
+ archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ wlarc=
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ linux*)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ tmp_archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_cmds="$tmp_archive_cmds"
+ supports_anon_versioning=no
+ case `$LD -v 2>/dev/null` in
+ *\ 01.* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
+ *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+ *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+ *\ 2.11.*) ;; # other 2.11 versions
+ *) supports_anon_versioning=yes ;;
+ esac
+ if test $supports_anon_versioning = yes; then
+ archive_expsym_cmds='$echo "{ global:" > $output_objdir/$libname.ver~
+cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+$echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ else
+ archive_expsym_cmds="$tmp_archive_cmds"
+ fi
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ *)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ esac
+
+ if test "$ld_shlibs" = yes; then
+ runpath_var=LD_RUN_PATH
+ hardcode_libdir_flag_spec='${wl}--rpath ${wl}$libdir'
+ export_dynamic_flag_spec='${wl}--export-dynamic'
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then
+ whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ whole_archive_flag_spec=
+ fi
+ fi
+ else
+ # PORTME fill in a description of your system's linker (not GNU ld)
+ case $host_os in
+ aix3*)
+ allow_undefined_flag=unsupported
+ always_export_symbols=yes
+ archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+ # Note: this linker hardcodes the directories in LIBPATH if there
+ # are no directories specified by -L.
+ hardcode_minus_L=yes
+ if test "$GCC" = yes && test -z "$link_static_flag"; then
+ # Neither direct hardcoding nor static linking is supported with a
+ # broken collect2.
+ hardcode_direct=unsupported
+ fi
+ ;;
+
+ aix4* | aix5*)
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=""
+ else
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to AIX nm, but means don't demangle with GNU nm
+ if $NM -V 2>&1 | grep 'GNU' > /dev/null; then
+ export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols'
+ else
+ export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols'
+ fi
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # need to do runtime linking.
+ case $host_os in aix4.[23]|aix4.[23].*|aix5*)
+ for ld_flag in $LDFLAGS; do
+ if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+ aix_use_runtimelinking=yes
+ break
+ fi
+ done
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ archive_cmds=''
+ hardcode_direct=yes
+ hardcode_libdir_separator=':'
+ link_all_deplibs=yes
+
+ if test "$GCC" = yes; then
+ case $host_os in aix4.012|aix4.012.*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" && \
+ strings "$collect2name" | grep resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ hardcode_direct=yes
+ else
+ # We have old collect2
+ hardcode_direct=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ hardcode_minus_L=yes
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_libdir_separator=
+ fi
+ esac
+ shared_flag='-shared'
+ else
+ # not using gcc
+ if test "$host_cpu" = ia64; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag='${wl}-G'
+ else
+ shared_flag='${wl}-bM:SRE'
+ fi
+ fi
+ fi
+
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to export.
+ always_export_symbols=yes
+ if test "$aix_use_runtimelinking" = yes; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ allow_undefined_flag='-berok'
+ # Determine the default libpath from the value encoded in an empty executable.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
+}'`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
+}'`; fi
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+ hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+ archive_expsym_cmds="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ else
+ if test "$host_cpu" = ia64; then
+ hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
+ allow_undefined_flag="-z nodefs"
+ archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an empty executable.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
+}'`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
+}'`; fi
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+ hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ no_undefined_flag=' ${wl}-bernotok'
+ allow_undefined_flag=' ${wl}-berok'
+ # -bexpall does not export symbols beginning with underscore (_)
+ always_export_symbols=yes
+ # Exported symbols can be pulled into shared objects from archives
+ whole_archive_flag_spec=' '
+ archive_cmds_need_lc=yes
+ # This is similar to how AIX traditionally builds it's shared libraries.
+ archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ fi
+ fi
+ ;;
+
+ amigaos*)
+ archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ # see comment about different semantics on the GNU ld section
+ ld_shlibs=no
+ ;;
+
+ bsdi4*)
+ export_dynamic_flag_spec=-rdynamic
+ ;;
+
+ cygwin* | mingw* | pw32*)
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ hardcode_libdir_flag_spec=' '
+ allow_undefined_flag=unsupported
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=".dll"
+ # FIXME: Setting linknames here is a bad hack.
+ archive_cmds='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames='
+ # The linker will automatically build a .lib file if we build a DLL.
+ old_archive_From_new_cmds='true'
+ # FIXME: Should let the user specify the lib program.
+ old_archive_cmds='lib /OUT:$oldlib$oldobjs$old_deplibs'
+ fix_srcfile_path='`cygpath -w "$srcfile"`'
+ enable_shared_with_static_runtimes=yes
+ ;;
+
+ darwin* | rhapsody*)
+ if test "$GXX" = yes ; then
+ archive_cmds_need_lc=no
+ case "$host_os" in
+ rhapsody* | darwin1.[012])
+ allow_undefined_flag='-undefined suppress'
+ ;;
+ *) # Darwin 1.3 on
+ if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
+ allow_undefined_flag='-flat_namespace -undefined suppress'
+ else
+ case ${MACOSX_DEPLOYMENT_TARGET} in
+ 10.[012])
+ allow_undefined_flag='-flat_namespace -undefined suppress'
+ ;;
+ 10.*)
+ allow_undefined_flag='-undefined dynamic_lookup'
+ ;;
+ esac
+ fi
+ ;;
+ esac
+ lt_int_apple_cc_single_mod=no
+ output_verbose_link_cmd='echo'
+ if $CC -dumpspecs 2>&1 | grep 'single_module' >/dev/null ; then
+ lt_int_apple_cc_single_mod=yes
+ fi
+ if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
+ archive_cmds='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+ else
+ archive_cmds='$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+ fi
+ module_cmds='$CC ${wl}-bind_at_load $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+ # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's
+ if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
+ archive_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ else
+ archive_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ fi
+ module_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ hardcode_direct=no
+ hardcode_automatic=yes
+ hardcode_shlibpath_var=unsupported
+ whole_archive_flag_spec='-all_load $convenience'
+ link_all_deplibs=yes
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ dgux*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_shlibpath_var=no
+ ;;
+
+ freebsd1*)
+ ld_shlibs=no
+ ;;
+
+ # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+ # support. Future versions do this automatically, but an explicit c++rt0.o
+ # does not break anything, and helps significantly (at the cost of a little
+ # extra space).
+ freebsd2.2*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+ freebsd2*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=yes
+ hardcode_minus_L=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+ freebsd* | kfreebsd*-gnu)
+ archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ hpux9*)
+ if test "$GCC" = yes; then
+ archive_cmds='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ else
+ archive_cmds='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ fi
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator=:
+ hardcode_direct=yes
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ export_dynamic_flag_spec='${wl}-E'
+ ;;
+
+ hpux10* | hpux11*)
+ if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+ case "$host_cpu" in
+ hppa*64*|ia64*)
+ archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ else
+ case "$host_cpu" in
+ hppa*64*|ia64*)
+ archive_cmds='$LD -b +h $soname -o $lib $libobjs $deplibs $linker_flags'
+ ;;
+ *)
+ archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+ ;;
+ esac
+ fi
+ if test "$with_gnu_ld" = no; then
+ case "$host_cpu" in
+ hppa*64*)
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_flag_spec_ld='+b $libdir'
+ hardcode_libdir_separator=:
+ hardcode_direct=no
+ hardcode_shlibpath_var=no
+ ;;
+ ia64*)
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_direct=no
+ hardcode_shlibpath_var=no
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ ;;
+ *)
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator=:
+ hardcode_direct=yes
+ export_dynamic_flag_spec='${wl}-E'
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ ;;
+ esac
+ fi
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ if test "$GCC" = yes; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+ hardcode_libdir_flag_spec_ld='-rpath $libdir'
+ fi
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ link_all_deplibs=yes
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
+ else
+ archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF
+ fi
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ newsos6)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=yes
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ hardcode_shlibpath_var=no
+ ;;
+
+ openbsd*)
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ export_dynamic_flag_spec='${wl}-E'
+ else
+ case $host_os in
+ openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-R$libdir'
+ ;;
+ *)
+ archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ ;;
+ esac
+ fi
+ ;;
+
+ os2*)
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ allow_undefined_flag=unsupported
+ archive_cmds='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+ old_archive_From_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+ ;;
+
+ osf3*)
+ if test "$GCC" = yes; then
+ allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ allow_undefined_flag=' -expect_unresolved \*'
+ archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+ fi
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ ;;
+
+ osf4* | osf5*) # as osf3* with the addition of -msym flag
+ if test "$GCC" = yes; then
+ allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ else
+ allow_undefined_flag=' -expect_unresolved \*'
+ archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+ archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~
+ $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib~$rm $lib.exp'
+
+ # Both c and cxx compiler support -rpath directly
+ hardcode_libdir_flag_spec='-rpath $libdir'
+ fi
+ hardcode_libdir_separator=:
+ ;;
+
+ sco3.2v5*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var=no
+ export_dynamic_flag_spec='${wl}-Bexport'
+ runpath_var=LD_RUN_PATH
+ hardcode_runpath_var=yes
+ ;;
+
+ solaris*)
+ no_undefined_flag=' -z text'
+ if test "$GCC" = yes; then
+ archive_cmds='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp'
+ else
+ archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
+ fi
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_shlibpath_var=no
+ case $host_os in
+ solaris2.[0-5] | solaris2.[0-5].*) ;;
+ *) # Supported since Solaris 2.6 (maybe 2.5.1?)
+ whole_archive_flag_spec='-z allextract$convenience -z defaultextract' ;;
+ esac
+ link_all_deplibs=yes
+ ;;
+
+ sunos4*)
+ if test "x$host_vendor" = xsequent; then
+ # Use $CC to link under sequent, because it throws in some extra .o
+ # files that make .init and .fini sections work.
+ archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_direct=yes
+ hardcode_minus_L=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ sysv4)
+ case $host_vendor in
+ sni)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=yes # is this really true???
+ ;;
+ siemens)
+ ## LD is ld it makes a PLAMLIB
+ ## CC just makes a GrossModule.
+ archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+ reload_cmds='$CC -r -o $output$reload_objs'
+ hardcode_direct=no
+ ;;
+ motorola)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=no #Motorola manual says yes, but my tests say they lie
+ ;;
+ esac
+ runpath_var='LD_RUN_PATH'
+ hardcode_shlibpath_var=no
+ ;;
+
+ sysv4.3*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var=no
+ export_dynamic_flag_spec='-Bexport'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var=no
+ runpath_var=LD_RUN_PATH
+ hardcode_runpath_var=yes
+ ld_shlibs=yes
+ fi
+ ;;
+
+ sysv4.2uw2*)
+ archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=yes
+ hardcode_minus_L=no
+ hardcode_shlibpath_var=no
+ hardcode_runpath_var=yes
+ runpath_var=LD_RUN_PATH
+ ;;
+
+ sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[78]* | unixware7*)
+ no_undefined_flag='${wl}-z ${wl}text'
+ if test "$GCC" = yes; then
+ archive_cmds='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ runpath_var='LD_RUN_PATH'
+ hardcode_shlibpath_var=no
+ ;;
+
+ sysv5*)
+ no_undefined_flag=' -z text'
+ # $CC -shared without GNU ld will not create a library from C++
+ # object files and a static libstdc++, better avoid it by now
+ archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
+ hardcode_libdir_flag_spec=
+ hardcode_shlibpath_var=no
+ runpath_var='LD_RUN_PATH'
+ ;;
+
+ uts4*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_shlibpath_var=no
+ ;;
+
+ *)
+ ld_shlibs=no
+ ;;
+ esac
+ fi
+
+echo "$as_me:$LINENO: result: $ld_shlibs" >&5
+echo "${ECHO_T}$ld_shlibs" >&6
+test "$ld_shlibs" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+ variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$archive_cmds_need_lc" in
+x|xyes)
+ # Assume -lc should be added
+ archive_cmds_need_lc=yes
+
+ if test "$enable_shared" = yes && test "$GCC" = yes; then
+ case $archive_cmds in
+ *'~'*)
+ # FIXME: we may have to deal with multi-command sequences.
+ ;;
+ '$CC '*)
+ # Test whether the compiler implicitly links with -lc since on some
+ # systems, -lgcc has to come before -lc. If gcc already passes -lc
+ # to ld, don't add -lc before -lgcc.
+ echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5
+echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6
+ $rm conftest*
+ printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } 2>conftest.err; then
+ soname=conftest
+ lib=conftest
+ libobjs=conftest.$ac_objext
+ deplibs=
+ wl=$lt_prog_compiler_wl
+ compiler_flags=-v
+ linker_flags=-v
+ verstring=
+ output_objdir=.
+ libname=conftest
+ lt_save_allow_undefined_flag=$allow_undefined_flag
+ allow_undefined_flag=
+ if { (eval echo "$as_me:$LINENO: \"$archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5
+ (eval $archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+ then
+ archive_cmds_need_lc=no
+ else
+ archive_cmds_need_lc=yes
+ fi
+ allow_undefined_flag=$lt_save_allow_undefined_flag
+ else
+ cat conftest.err 1>&5
+ fi
+ $rm conftest*
+ echo "$as_me:$LINENO: result: $archive_cmds_need_lc" >&5
+echo "${ECHO_T}$archive_cmds_need_lc" >&6
+ ;;
+ esac
+ fi
+ ;;
+esac
+
+echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5
+echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+if test "$GCC" = yes; then
+ sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+ if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then
+ # if the path contains ";" then we assume it to be the separator
+ # otherwise default to the standard path separator (i.e. ":") - it is
+ # assumed that no part of a normal pathname contains ";" but that should
+ # okay in the real world where ";" in dirpaths is itself problematic.
+ sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+ else
+ sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ fi
+else
+ sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+ shlibpath_var=LIBPATH
+
+ # AIX 3 has no versioning support, so we append a major version to the name.
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+
+aix4* | aix5*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ hardcode_into_libs=yes
+ if test "$host_cpu" = ia64; then
+ # AIX 5 supports IA64
+ library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ else
+ # With GCC up to 2.95.x, collect2 would create an import file
+ # for dependence libraries. The import file would start with
+ # the line `#! .'. This would cause the generated library to
+ # depend on `.', always an invalid library. This was fixed in
+ # development snapshots of GCC prior to 3.0.
+ case $host_os in
+ aix4 | aix4.[01] | aix4.[01].*)
+ if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+ echo ' yes '
+ echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then
+ :
+ else
+ can_build_shared=no
+ fi
+ ;;
+ esac
+ # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+ # soname into executable. Probably we can add versioning support to
+ # collect2, so additional links can be useful in future.
+ if test "$aix_use_runtimelinking" = yes; then
+ # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+ # instead of lib<name>.a to let people know that these are not
+ # typical AIX shared libraries.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ else
+ # We preserve .a as extension for shared libraries through AIX4.2
+ # and later when we are not doing run time linking.
+ library_names_spec='${libname}${release}.a $libname.a'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ fi
+ shlibpath_var=LIBPATH
+ fi
+ ;;
+
+amigaos*)
+ library_names_spec='$libname.ixlibrary $libname.a'
+ # Create ${libname}_ixlibrary.a entries in /sys/libs.
+ finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+ ;;
+
+beos*)
+ library_names_spec='${libname}${shared_ext}'
+ dynamic_linker="$host_os ld.so"
+ shlibpath_var=LIBRARY_PATH
+ ;;
+
+bsdi4*)
+ version_type=linux
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+ # the default ld.so.conf also contains /usr/contrib/lib and
+ # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+ # libtool to hard-code these into programs
+ ;;
+
+cygwin* | mingw* | pw32*)
+ version_type=windows
+ shrext_cmds=".dll"
+ need_version=no
+ need_lib_prefix=no
+
+ case $GCC,$host_os in
+ yes,cygwin* | yes,mingw* | yes,pw32*)
+ library_names_spec='$libname.dll.a'
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \${file}`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $rm \$dlpath'
+ shlibpath_overrides_runpath=yes
+
+ case $host_os in
+ cygwin*)
+ # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+ soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib"
+ ;;
+ mingw*)
+ # MinGW DLLs use traditional 'lib' prefix
+ soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+ if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then
+ # It is most probably a Windows format PATH printed by
+ # mingw gcc, but we are running on Cygwin. Gcc prints its search
+ # path with ; separators, and with drive letters. We can handle the
+ # drive letters (cygwin fileutils understands them), so leave them,
+ # especially as we might pass files found there to a mingw objdump,
+ # which wouldn't understand a cygwinified path. Ahh.
+ sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+ else
+ sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ fi
+ ;;
+ pw32*)
+ # pw32 DLLs use 'pw' prefix rather than 'lib'
+ library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/./-/g'`${versuffix}${shared_ext}'
+ ;;
+ esac
+ ;;
+
+ *)
+ library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
+ ;;
+ esac
+ dynamic_linker='Win32 ld.exe'
+ # FIXME: first we should search . and the directory the executable is in
+ shlibpath_var=PATH
+ ;;
+
+darwin* | rhapsody*)
+ dynamic_linker="$host_os dyld"
+ version_type=darwin
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+ soname_spec='${libname}${release}${major}$shared_ext'
+ shlibpath_overrides_runpath=yes
+ shlibpath_var=DYLD_LIBRARY_PATH
+ shrext_cmds='$(test .$module = .yes && echo .so || echo .dylib)'
+ # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same.
+ if test "$GCC" = yes; then
+ sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"`
+ else
+ sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib'
+ fi
+ sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+ ;;
+
+dgux*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+freebsd1*)
+ dynamic_linker=no
+ ;;
+
+kfreebsd*-gnu)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='GNU ld.so'
+ ;;
+
+freebsd*)
+ objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout`
+ version_type=freebsd-$objformat
+ case $version_type in
+ freebsd-elf*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ need_version=no
+ need_lib_prefix=no
+ ;;
+ freebsd-*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+ need_version=yes
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_os in
+ freebsd2*)
+ shlibpath_overrides_runpath=yes
+ ;;
+ freebsd3.01* | freebsdelf3.01*)
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ *) # from 3.2 on
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+ esac
+ ;;
+
+gnu*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ hardcode_into_libs=yes
+ ;;
+
+hpux9* | hpux10* | hpux11*)
+ # Give a soname corresponding to the major version so that dld.sl refuses to
+ # link against other versions.
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ case "$host_cpu" in
+ ia64*)
+ shrext_cmds='.so'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ if test "X$HPUX_IA64_MODE" = X32; then
+ sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+ else
+ sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+ fi
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ hppa*64*)
+ shrext_cmds='.sl'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ *)
+ shrext_cmds='.sl'
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=SHLIB_PATH
+ shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+ esac
+ # HP-UX runs *really* slowly unless shared libraries are mode 555.
+ postinstall_cmds='chmod 555 $lib'
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $host_os in
+ nonstopux*) version_type=nonstopux ;;
+ *)
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ version_type=linux
+ else
+ version_type=irix
+ fi ;;
+ esac
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+ case $host_os in
+ irix5* | nonstopux*)
+ libsuff= shlibsuff=
+ ;;
+ *)
+ case $LD in # libtool.m4 will add one of these switches to LD
+ *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+ libsuff= shlibsuff= libmagic=32-bit;;
+ *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+ libsuff=32 shlibsuff=N32 libmagic=N32;;
+ *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+ libsuff=64 shlibsuff=64 libmagic=64-bit;;
+ *) libsuff= shlibsuff= libmagic=never-match;;
+ esac
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+ sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+ hardcode_into_libs=yes
+ ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+ dynamic_linker=no
+ ;;
+
+# This must be Linux ELF.
+linux*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ # This implies no fast_install, which is unacceptable.
+ # Some rework will be needed to allow for fast_install
+ # before this can be enabled.
+ hardcode_into_libs=yes
+
+ # find out which ABI we are using
+ libsuff=
+ case "$host_cpu" in
+ x86_64*|s390x*|powerpc64*)
+ echo '#line 9472 "configure"' > conftest.$ac_ext
+ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *64-bit*)
+ libsuff=64
+ sys_lib_search_path_spec="/lib${libsuff} /usr/lib${libsuff} /usr/local/lib${libsuff}"
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+ esac
+
+ # Append ld.so.conf contents to the search path
+ if test -f /etc/ld.so.conf; then
+ lt_ld_extra=`$SED -e 's/:,\t/ /g;s/=^=*$//;s/=^= * / /g' /etc/ld.so.conf | tr '\n' ' '`
+ sys_lib_dlsearch_path_spec="/lib${libsuff} /usr/lib${libsuff} $lt_ld_extra"
+ fi
+
+ # We used to test for /lib/ld.so.1 and disable shared libraries on
+ # powerpc, because MkLinux only supported shared libraries with the
+ # GNU dynamic linker. Since this was broken with cross compilers,
+ # most powerpc-linux boxes support dynamic linking these days and
+ # people can always --disable-shared, the test was removed, and we
+ # assume the GNU/Linux dynamic linker is in use.
+ dynamic_linker='GNU/Linux ld.so'
+ ;;
+
+knetbsd*-gnu)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='GNU ld.so'
+ ;;
+
+netbsd*)
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ dynamic_linker='NetBSD (a.out) ld.so'
+ else
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='NetBSD ld.elf_so'
+ fi
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+
+newsos6)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+nto-qnx*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+openbsd*)
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=yes
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ case $host_os in
+ openbsd2.[89] | openbsd2.[89].*)
+ shlibpath_overrides_runpath=no
+ ;;
+ *)
+ shlibpath_overrides_runpath=yes
+ ;;
+ esac
+ else
+ shlibpath_overrides_runpath=yes
+ fi
+ ;;
+
+os2*)
+ libname_spec='$name'
+ shrext_cmds=".dll"
+ need_lib_prefix=no
+ library_names_spec='$libname${shared_ext} $libname.a'
+ dynamic_linker='OS/2 ld.exe'
+ shlibpath_var=LIBPATH
+ ;;
+
+osf3* | osf4* | osf5*)
+ version_type=osf
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+ sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+ ;;
+
+sco3.2v5*)
+ version_type=osf
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+solaris*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ # ldd complains unless libraries are executable
+ postinstall_cmds='chmod +x $lib'
+ ;;
+
+sunos4*)
+ version_type=sunos
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ if test "$with_gnu_ld" = yes; then
+ need_lib_prefix=no
+ fi
+ need_version=yes
+ ;;
+
+sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_vendor in
+ sni)
+ shlibpath_overrides_runpath=no
+ need_lib_prefix=no
+ export_dynamic_flag_spec='${wl}-Blargedynsym'
+ runpath_var=LD_RUN_PATH
+ ;;
+ siemens)
+ need_lib_prefix=no
+ ;;
+ motorola)
+ need_lib_prefix=no
+ need_version=no
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+ ;;
+ esac
+ ;;
+
+sysv4*MP*)
+ if test -d /usr/nec ;then
+ version_type=linux
+ library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+ soname_spec='$libname${shared_ext}.$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ fi
+ ;;
+
+uts4*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+*)
+ dynamic_linker=no
+ ;;
+esac
+echo "$as_me:$LINENO: result: $dynamic_linker" >&5
+echo "${ECHO_T}$dynamic_linker" >&6
+test "$dynamic_linker" = no && can_build_shared=no
+
+echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5
+echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6
+hardcode_action=
+if test -n "$hardcode_libdir_flag_spec" || \
+ test -n "$runpath_var " || \
+ test "X$hardcode_automatic"="Xyes" ; then
+
+ # We can hardcode non-existant directories.
+ if test "$hardcode_direct" != no &&
+ # If the only mechanism to avoid hardcoding is shlibpath_var, we
+ # have to relink, otherwise we might link with an installed library
+ # when we should be linking with a yet-to-be-installed one
+ ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, )" != no &&
+ test "$hardcode_minus_L" != no; then
+ # Linking always hardcodes the temporary library directory.
+ hardcode_action=relink
+ else
+ # We can link without hardcoding, and we can hardcode nonexisting dirs.
+ hardcode_action=immediate
+ fi
+else
+ # We cannot hardcode anything, or else we can only hardcode existing
+ # directories.
+ hardcode_action=unsupported
+fi
+echo "$as_me:$LINENO: result: $hardcode_action" >&5
+echo "${ECHO_T}$hardcode_action" >&6
+
+if test "$hardcode_action" = relink; then
+ # Fast installation is not supported
+ enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+ test "$enable_shared" = no; then
+ # Fast installation is not necessary
+ enable_fast_install=needless
+fi
+
+striplib=
+old_striplib=
+echo "$as_me:$LINENO: checking whether stripping libraries is possible" >&5
+echo $ECHO_N "checking whether stripping libraries is possible... $ECHO_C" >&6
+if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then
+ test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+ test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+ case $host_os in
+ darwin*)
+ if test -n "$STRIP" ; then
+ striplib="$STRIP -x"
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+ ;;
+ *)
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ ;;
+ esac
+fi
+
+if test "x$enable_dlopen" != xyes; then
+ enable_dlopen=unknown
+ enable_dlopen_self=unknown
+ enable_dlopen_self_static=unknown
+else
+ lt_cv_dlopen=no
+ lt_cv_dlopen_libs=
+
+ case $host_os in
+ beos*)
+ lt_cv_dlopen="load_add_on"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+ ;;
+
+ mingw* | pw32*)
+ lt_cv_dlopen="LoadLibrary"
+ lt_cv_dlopen_libs=
+ ;;
+
+ cygwin*)
+ lt_cv_dlopen="dlopen"
+ lt_cv_dlopen_libs=
+ ;;
+
+ darwin*)
+ # if libdl is installed we need to link against it
+ echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5
+echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dlopen ();
+int
+main ()
+{
+dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_dl_dlopen=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dl_dlopen=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5
+echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6
+if test $ac_cv_lib_dl_dlopen = yes; then
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+
+ lt_cv_dlopen="dyld"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+
+fi
+
+ ;;
+
+ *)
+ echo "$as_me:$LINENO: checking for shl_load" >&5
+echo $ECHO_N "checking for shl_load... $ECHO_C" >&6
+if test "${ac_cv_func_shl_load+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define shl_load to an innocuous variant, in case <limits.h> declares shl_load.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define shl_load innocuous_shl_load
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char shl_load (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef shl_load
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char shl_load ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_shl_load) || defined (__stub___shl_load)
+choke me
+#else
+char (*f) () = shl_load;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != shl_load;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_shl_load=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_shl_load=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_shl_load" >&5
+echo "${ECHO_T}$ac_cv_func_shl_load" >&6
+if test $ac_cv_func_shl_load = yes; then
+ lt_cv_dlopen="shl_load"
+else
+ echo "$as_me:$LINENO: checking for shl_load in -ldld" >&5
+echo $ECHO_N "checking for shl_load in -ldld... $ECHO_C" >&6
+if test "${ac_cv_lib_dld_shl_load+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char shl_load ();
+int
+main ()
+{
+shl_load ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_dld_shl_load=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dld_shl_load=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dld_shl_load" >&5
+echo "${ECHO_T}$ac_cv_lib_dld_shl_load" >&6
+if test $ac_cv_lib_dld_shl_load = yes; then
+ lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"
+else
+ echo "$as_me:$LINENO: checking for dlopen" >&5
+echo $ECHO_N "checking for dlopen... $ECHO_C" >&6
+if test "${ac_cv_func_dlopen+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define dlopen to an innocuous variant, in case <limits.h> declares dlopen.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define dlopen innocuous_dlopen
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char dlopen (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef dlopen
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dlopen ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_dlopen) || defined (__stub___dlopen)
+choke me
+#else
+char (*f) () = dlopen;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != dlopen;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_dlopen=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_dlopen=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_dlopen" >&5
+echo "${ECHO_T}$ac_cv_func_dlopen" >&6
+if test $ac_cv_func_dlopen = yes; then
+ lt_cv_dlopen="dlopen"
+else
+ echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5
+echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dlopen ();
+int
+main ()
+{
+dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_dl_dlopen=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dl_dlopen=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5
+echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6
+if test $ac_cv_lib_dl_dlopen = yes; then
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+ echo "$as_me:$LINENO: checking for dlopen in -lsvld" >&5
+echo $ECHO_N "checking for dlopen in -lsvld... $ECHO_C" >&6
+if test "${ac_cv_lib_svld_dlopen+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsvld $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dlopen ();
+int
+main ()
+{
+dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_svld_dlopen=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_svld_dlopen=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_svld_dlopen" >&5
+echo "${ECHO_T}$ac_cv_lib_svld_dlopen" >&6
+if test $ac_cv_lib_svld_dlopen = yes; then
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"
+else
+ echo "$as_me:$LINENO: checking for dld_link in -ldld" >&5
+echo $ECHO_N "checking for dld_link in -ldld... $ECHO_C" >&6
+if test "${ac_cv_lib_dld_dld_link+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dld_link ();
+int
+main ()
+{
+dld_link ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_dld_dld_link=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dld_dld_link=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dld_dld_link" >&5
+echo "${ECHO_T}$ac_cv_lib_dld_dld_link" >&6
+if test $ac_cv_lib_dld_dld_link = yes; then
+ lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+ ;;
+ esac
+
+ if test "x$lt_cv_dlopen" != xno; then
+ enable_dlopen=yes
+ else
+ enable_dlopen=no
+ fi
+
+ case $lt_cv_dlopen in
+ dlopen)
+ save_CPPFLAGS="$CPPFLAGS"
+ test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+ save_LDFLAGS="$LDFLAGS"
+ eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+ save_LIBS="$LIBS"
+ LIBS="$lt_cv_dlopen_libs $LIBS"
+
+ echo "$as_me:$LINENO: checking whether a program can dlopen itself" >&5
+echo $ECHO_N "checking whether a program can dlopen itself... $ECHO_C" >&6
+if test "${lt_cv_dlopen_self+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$cross_compiling" = yes; then :
+ lt_cv_dlopen_self=cross
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<EOF
+#line 10343 "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+#ifdef __cplusplus
+extern "C" void exit (int);
+#endif
+
+void fnord() { int i=42;}
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ /* dlclose (self); */
+ }
+
+ exit (status);
+}
+EOF
+ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then
+ (./conftest; exit; ) 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;;
+ x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;;
+ x$lt_unknown|x*) lt_cv_dlopen_self=no ;;
+ esac
+ else :
+ # compilation failed
+ lt_cv_dlopen_self=no
+ fi
+fi
+rm -fr conftest*
+
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_dlopen_self" >&5
+echo "${ECHO_T}$lt_cv_dlopen_self" >&6
+
+ if test "x$lt_cv_dlopen_self" = xyes; then
+ LDFLAGS="$LDFLAGS $link_static_flag"
+ echo "$as_me:$LINENO: checking whether a statically linked program can dlopen itself" >&5
+echo $ECHO_N "checking whether a statically linked program can dlopen itself... $ECHO_C" >&6
+if test "${lt_cv_dlopen_self_static+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$cross_compiling" = yes; then :
+ lt_cv_dlopen_self_static=cross
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<EOF
+#line 10441 "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+#ifdef __cplusplus
+extern "C" void exit (int);
+#endif
+
+void fnord() { int i=42;}
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ /* dlclose (self); */
+ }
+
+ exit (status);
+}
+EOF
+ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then
+ (./conftest; exit; ) 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;;
+ x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;;
+ x$lt_unknown|x*) lt_cv_dlopen_self_static=no ;;
+ esac
+ else :
+ # compilation failed
+ lt_cv_dlopen_self_static=no
+ fi
+fi
+rm -fr conftest*
+
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_dlopen_self_static" >&5
+echo "${ECHO_T}$lt_cv_dlopen_self_static" >&6
+ fi
+
+ CPPFLAGS="$save_CPPFLAGS"
+ LDFLAGS="$save_LDFLAGS"
+ LIBS="$save_LIBS"
+ ;;
+ esac
+
+ case $lt_cv_dlopen_self in
+ yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+ *) enable_dlopen_self=unknown ;;
+ esac
+
+ case $lt_cv_dlopen_self_static in
+ yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+ *) enable_dlopen_self_static=unknown ;;
+ esac
+fi
+
+
+# Report which librarie types wil actually be built
+echo "$as_me:$LINENO: checking if libtool supports shared libraries" >&5
+echo $ECHO_N "checking if libtool supports shared libraries... $ECHO_C" >&6
+echo "$as_me:$LINENO: result: $can_build_shared" >&5
+echo "${ECHO_T}$can_build_shared" >&6
+
+echo "$as_me:$LINENO: checking whether to build shared libraries" >&5
+echo $ECHO_N "checking whether to build shared libraries... $ECHO_C" >&6
+test "$can_build_shared" = "no" && enable_shared=no
+
+# On AIX, shared libraries and static libraries use the same namespace, and
+# are all built from PIC.
+case "$host_os" in
+aix3*)
+ test "$enable_shared" = yes && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+
+aix4* | aix5*)
+ if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+ test "$enable_shared" = yes && enable_static=no
+ fi
+ ;;
+ darwin* | rhapsody*)
+ if test "$GCC" = yes; then
+ archive_cmds_need_lc=no
+ case "$host_os" in
+ rhapsody* | darwin1.[012])
+ allow_undefined_flag='-undefined suppress'
+ ;;
+ *) # Darwin 1.3 on
+ if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
+ allow_undefined_flag='-flat_namespace -undefined suppress'
+ else
+ case ${MACOSX_DEPLOYMENT_TARGET} in
+ 10.[012])
+ allow_undefined_flag='-flat_namespace -undefined suppress'
+ ;;
+ 10.*)
+ allow_undefined_flag='-undefined dynamic_lookup'
+ ;;
+ esac
+ fi
+ ;;
+ esac
+ output_verbose_link_cmd='echo'
+ archive_cmds='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs$compiler_flags -install_name $rpath/$soname $verstring'
+ module_cmds='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+ # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's
+ archive_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs$compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ module_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ hardcode_direct=no
+ hardcode_automatic=yes
+ hardcode_shlibpath_var=unsupported
+ whole_archive_flag_spec='-all_load $convenience'
+ link_all_deplibs=yes
+ else
+ ld_shlibs=no
+ fi
+ ;;
+esac
+echo "$as_me:$LINENO: result: $enable_shared" >&5
+echo "${ECHO_T}$enable_shared" >&6
+
+echo "$as_me:$LINENO: checking whether to build static libraries" >&5
+echo $ECHO_N "checking whether to build static libraries... $ECHO_C" >&6
+# Make sure either enable_shared or enable_static is yes.
+test "$enable_shared" = yes || enable_static=yes
+echo "$as_me:$LINENO: result: $enable_static" >&5
+echo "${ECHO_T}$enable_static" >&6
+
+# The else clause should only fire when bootstrapping the
+# libtool distribution, otherwise you forgot to ship ltmain.sh
+# with your package, and you will get complaints that there are
+# no rules to generate ltmain.sh.
+if test -f "$ltmain"; then
+ # See if we are running on zsh, and set the options which allow our commands through
+ # without removal of \ escapes.
+ if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+ fi
+ # Now quote all the things that may contain metacharacters while being
+ # careful not to overquote the AC_SUBSTed values. We take copies of the
+ # variables and quote the copies for generation of the libtool script.
+ for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC NM \
+ SED SHELL STRIP \
+ libname_spec library_names_spec soname_spec extract_expsyms_cmds \
+ old_striplib striplib file_magic_cmd finish_cmds finish_eval \
+ deplibs_check_method reload_flag reload_cmds need_locks \
+ lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \
+ lt_cv_sys_global_symbol_to_c_name_address \
+ sys_lib_search_path_spec sys_lib_dlsearch_path_spec \
+ old_postinstall_cmds old_postuninstall_cmds \
+ compiler \
+ CC \
+ LD \
+ lt_prog_compiler_wl \
+ lt_prog_compiler_pic \
+ lt_prog_compiler_static \
+ lt_prog_compiler_no_builtin_flag \
+ export_dynamic_flag_spec \
+ thread_safe_flag_spec \
+ whole_archive_flag_spec \
+ enable_shared_with_static_runtimes \
+ old_archive_cmds \
+ old_archive_from_new_cmds \
+ predep_objects \
+ postdep_objects \
+ predeps \
+ postdeps \
+ compiler_lib_search_path \
+ archive_cmds \
+ archive_expsym_cmds \
+ postinstall_cmds \
+ postuninstall_cmds \
+ old_archive_from_expsyms_cmds \
+ allow_undefined_flag \
+ no_undefined_flag \
+ export_symbols_cmds \
+ hardcode_libdir_flag_spec \
+ hardcode_libdir_flag_spec_ld \
+ hardcode_libdir_separator \
+ hardcode_automatic \
+ module_cmds \
+ module_expsym_cmds \
+ lt_cv_prog_compiler_c_o \
+ exclude_expsyms \
+ include_expsyms; do
+
+ case $var in
+ old_archive_cmds | \
+ old_archive_from_new_cmds | \
+ archive_cmds | \
+ archive_expsym_cmds | \
+ module_cmds | \
+ module_expsym_cmds | \
+ old_archive_from_expsyms_cmds | \
+ export_symbols_cmds | \
+ extract_expsyms_cmds | reload_cmds | finish_cmds | \
+ postinstall_cmds | postuninstall_cmds | \
+ old_postinstall_cmds | old_postuninstall_cmds | \
+ sys_lib_search_path_spec | sys_lib_dlsearch_path_spec)
+ # Double-quote double-evaled strings.
+ eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\""
+ ;;
+ *)
+ eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\""
+ ;;
+ esac
+ done
+
+ case $lt_echo in
+ *'\$0 --fallback-echo"')
+ lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'`
+ ;;
+ esac
+
+cfgfile="${ofile}T"
+ trap "$rm \"$cfgfile\"; exit 1" 1 2 15
+ $rm -f "$cfgfile"
+ { echo "$as_me:$LINENO: creating $ofile" >&5
+echo "$as_me: creating $ofile" >&6;}
+
+ cat <<__EOF__ >> "$cfgfile"
+#! $SHELL
+
+# `$echo "$cfgfile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP)
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+#
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001
+# Free Software Foundation, Inc.
+#
+# This file is part of GNU Libtool:
+# Originally by Gordon Matzigkeit <gord at gnu.ai.mit.edu>, 1996
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# A sed program that does not truncate output.
+SED=$lt_SED
+
+# Sed that helps us avoid accidentally triggering echo(1) options like -n.
+Xsed="$SED -e s/^X//"
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+if test "X\${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi
+
+# The names of the tagged configurations supported by this script.
+available_tags=
+
+# ### BEGIN LIBTOOL CONFIG
+
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+
+# Shell to use when invoking shell scripts.
+SHELL=$lt_SHELL
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc
+
+# Whether or not to disallow shared libs when runtime libs are static
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes
+
+# Whether or not to optimize for fast installation.
+fast_install=$enable_fast_install
+
+# The host system.
+host_alias=$host_alias
+host=$host
+
+# An echo program that does not interpret backslashes.
+echo=$lt_echo
+
+# The archiver.
+AR=$lt_AR
+AR_FLAGS=$lt_AR_FLAGS
+
+# A C compiler.
+LTCC=$lt_LTCC
+
+# A language-specific compiler.
+CC=$lt_compiler
+
+# Is the compiler the GNU C compiler?
+with_gcc=$GCC
+
+# An ERE matcher.
+EGREP=$lt_EGREP
+
+# The linker used to build libraries.
+LD=$lt_LD
+
+# Whether we need hard or soft links.
+LN_S=$lt_LN_S
+
+# A BSD-compatible nm program.
+NM=$lt_NM
+
+# A symbol stripping program
+STRIP=$lt_STRIP
+
+# Used to examine libraries when file_magic_cmd begins "file"
+MAGIC_CMD=$MAGIC_CMD
+
+# Used on cygwin: DLL creation program.
+DLLTOOL="$DLLTOOL"
+
+# Used on cygwin: object dumper.
+OBJDUMP="$OBJDUMP"
+
+# Used on cygwin: assembler.
+AS="$AS"
+
+# The name of the directory that contains temporary libtool files.
+objdir=$objdir
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag
+reload_cmds=$lt_reload_cmds
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl
+
+# Object file suffix (normally "o").
+objext="$ac_objext"
+
+# Old archive suffix (normally "a").
+libext="$libext"
+
+# Shared library suffix (normally ".so").
+shrext_cmds='$shrext_cmds'
+
+# Executable file suffix (normally "").
+exeext="$exeext"
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic
+pic_mode=$pic_mode
+
+# What is the maximum length of a command?
+max_cmd_len=$lt_cv_sys_max_cmd_len
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o
+
+# Must we lock files when doing compilation ?
+need_locks=$lt_need_locks
+
+# Do we need the lib prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Whether dlopen is supported.
+dlopen_support=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec
+
+# Compiler flag to generate thread-safe objects.
+thread_safe_flag_spec=$lt_thread_safe_flag_spec
+
+# Library versioning type.
+version_type=$version_type
+
+# Format of library name prefix.
+libname_spec=$lt_libname_spec
+
+# List of archive names. First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME.
+library_names_spec=$lt_library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$lt_soname_spec
+
+# Commands used to build and install an old-style archive.
+RANLIB=$lt_RANLIB
+old_archive_cmds=$lt_old_archive_cmds
+old_postinstall_cmds=$lt_old_postinstall_cmds
+old_postuninstall_cmds=$lt_old_postuninstall_cmds
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds
+
+# Commands used to build and install a shared archive.
+archive_cmds=$lt_archive_cmds
+archive_expsym_cmds=$lt_archive_expsym_cmds
+postinstall_cmds=$lt_postinstall_cmds
+postuninstall_cmds=$lt_postuninstall_cmds
+
+# Commands used to build a loadable module (assumed same as above if empty)
+module_cmds=$lt_module_cmds
+module_expsym_cmds=$lt_module_expsym_cmds
+
+# Commands to strip libraries.
+old_striplib=$lt_old_striplib
+striplib=$lt_striplib
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predep_objects=$lt_predep_objects
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdep_objects=$lt_postdep_objects
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predeps=$lt_predeps
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdeps=$lt_postdeps
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path=$lt_compiler_lib_search_path
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$lt_deplibs_check_method
+
+# Command to use when deplibs_check_method == file_magic.
+file_magic_cmd=$lt_file_magic_cmd
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag
+
+# Flag that forces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$lt_finish_cmds
+
+# Same as above, but a single script fragment to be evaled but not shown.
+finish_eval=$lt_finish_eval
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration
+global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
+
+# Transform the output of nm in a C name address pair
+global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
+
+# This is the shared library runtime path variable.
+runpath_var=$runpath_var
+
+# This is the shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=$hardcode_into_libs
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec
+
+# If ld is used when linking, flag to hardcode \$libdir into
+# a binary during linking. This must work even if \$libdir does
+# not exist.
+hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld
+
+# Whether we need a single -rpath flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator
+
+# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the
+# resulting binary.
+hardcode_direct=$hardcode_direct
+
+# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
+# resulting binary.
+hardcode_minus_L=$hardcode_minus_L
+
+# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into
+# the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var
+
+# Set to yes if building a shared library automatically hardcodes DIR into the library
+# and all subsequent libraries and executables linked against it.
+hardcode_automatic=$hardcode_automatic
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at relink time.
+variables_saved_for_relink="$variables_saved_for_relink"
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs
+
+# Compile-time system search path for libraries
+sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+
+# Run-time system search path for libraries
+sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
+
+# Fix the shell variable \$srcfile for the compiler.
+fix_srcfile_path="$fix_srcfile_path"
+
+# Set to yes if exported symbols are required.
+always_export_symbols=$always_export_symbols
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=$lt_extract_expsyms_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms
+
+# ### END LIBTOOL CONFIG
+
+__EOF__
+
+
+ case $host_os in
+ aix3*)
+ cat <<\EOF >> "$cfgfile"
+
+# AIX sometimes has problems with the GCC collect2 program. For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "X${COLLECT_NAMES+set}" != Xset; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+fi
+EOF
+ ;;
+ esac
+
+ # We use sed instead of cat because bash on DJGPP gets confused if
+ # if finds mixed CR/LF and LF-only lines. Since sed operates in
+ # text mode, it properly converts lines to CR/LF. This bash problem
+ # is reportedly fixed, but why not run on old versions too?
+ sed '$q' "$ltmain" >> "$cfgfile" || (rm -f "$cfgfile"; exit 1)
+
+ mv -f "$cfgfile" "$ofile" || \
+ (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+ chmod +x "$ofile"
+
+else
+ # If there is no Makefile yet, we rely on a make rule to execute
+ # `config.status --recheck' to rerun these tests and create the
+ # libtool script then.
+ ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'`
+ if test -f "$ltmain_in"; then
+ test -f Makefile && make "$ltmain"
+ fi
+fi
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+CC="$lt_save_CC"
+
+
+# Check whether --with-tags or --without-tags was given.
+if test "${with_tags+set}" = set; then
+ withval="$with_tags"
+ tagnames="$withval"
+fi;
+
+if test -f "$ltmain" && test -n "$tagnames"; then
+ if test ! -f "${ofile}"; then
+ { echo "$as_me:$LINENO: WARNING: output file \`$ofile' does not exist" >&5
+echo "$as_me: WARNING: output file \`$ofile' does not exist" >&2;}
+ fi
+
+ if test -z "$LTCC"; then
+ eval "`$SHELL ${ofile} --config | grep '^LTCC='`"
+ if test -z "$LTCC"; then
+ { echo "$as_me:$LINENO: WARNING: output file \`$ofile' does not look like a libtool script" >&5
+echo "$as_me: WARNING: output file \`$ofile' does not look like a libtool script" >&2;}
+ else
+ { echo "$as_me:$LINENO: WARNING: using \`LTCC=$LTCC', extracted from \`$ofile'" >&5
+echo "$as_me: WARNING: using \`LTCC=$LTCC', extracted from \`$ofile'" >&2;}
+ fi
+ fi
+
+ # Extract list of available tagged configurations in $ofile.
+ # Note that this assumes the entire list is on one line.
+ available_tags=`grep "^available_tags=" "${ofile}" | $SED -e 's/available_tags=\(.*$\)/\1/' -e 's/\"//g'`
+
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for tagname in $tagnames; do
+ IFS="$lt_save_ifs"
+ # Check whether tagname contains only valid characters
+ case `$echo "X$tagname" | $Xsed -e 's:[-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890,/]::g'` in
+ "") ;;
+ *) { { echo "$as_me:$LINENO: error: invalid tag name: $tagname" >&5
+echo "$as_me: error: invalid tag name: $tagname" >&2;}
+ { (exit 1); exit 1; }; }
+ ;;
+ esac
+
+ if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "${ofile}" > /dev/null
+ then
+ { { echo "$as_me:$LINENO: error: tag name \"$tagname\" already exists" >&5
+echo "$as_me: error: tag name \"$tagname\" already exists" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+
+ # Update the list of available tags.
+ if test -n "$tagname"; then
+ echo appending configuration tag \"$tagname\" to $ofile
+
+ case $tagname in
+ CXX)
+ if test -n "$CXX" && test "X$CXX" != "Xno"; then
+ ac_ext=cc
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+
+
+
+archive_cmds_need_lc_CXX=no
+allow_undefined_flag_CXX=
+always_export_symbols_CXX=no
+archive_expsym_cmds_CXX=
+export_dynamic_flag_spec_CXX=
+hardcode_direct_CXX=no
+hardcode_libdir_flag_spec_CXX=
+hardcode_libdir_flag_spec_ld_CXX=
+hardcode_libdir_separator_CXX=
+hardcode_minus_L_CXX=no
+hardcode_automatic_CXX=no
+module_cmds_CXX=
+module_expsym_cmds_CXX=
+link_all_deplibs_CXX=unknown
+old_archive_cmds_CXX=$old_archive_cmds
+no_undefined_flag_CXX=
+whole_archive_flag_spec_CXX=
+enable_shared_with_static_runtimes_CXX=no
+
+# Dependencies to place before and after the object being linked:
+predep_objects_CXX=
+postdep_objects_CXX=
+predeps_CXX=
+postdeps_CXX=
+compiler_lib_search_path_CXX=
+
+# Source file extension for C++ test sources.
+ac_ext=cc
+
+# Object file extension for compiled C++ test sources.
+objext=o
+objext_CXX=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;\n"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(int, char *) { return(0); }\n'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+# Allow CC to be a program name with arguments.
+lt_save_CC=$CC
+lt_save_LD=$LD
+lt_save_GCC=$GCC
+GCC=$GXX
+lt_save_with_gnu_ld=$with_gnu_ld
+lt_save_path_LD=$lt_cv_path_LD
+if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
+ lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
+else
+ unset lt_cv_prog_gnu_ld
+fi
+if test -n "${lt_cv_path_LDCXX+set}"; then
+ lt_cv_path_LD=$lt_cv_path_LDCXX
+else
+ unset lt_cv_path_LD
+fi
+test -z "${LDCXX+set}" || LD=$LDCXX
+CC=${CXX-"c++"}
+compiler=$CC
+compiler_CXX=$CC
+cc_basename=`$echo X"$compiler" | $Xsed -e 's%^.*/%%'`
+
+# We don't want -fno-exception wen compiling C++ code, so set the
+# no_builtin_flag separately
+if test "$GXX" = yes; then
+ lt_prog_compiler_no_builtin_flag_CXX=' -fno-builtin'
+else
+ lt_prog_compiler_no_builtin_flag_CXX=
+fi
+
+if test "$GXX" = yes; then
+ # Set up default GNU C++ configuration
+
+
+# Check whether --with-gnu-ld or --without-gnu-ld was given.
+if test "${with_gnu_ld+set}" = set; then
+ withval="$with_gnu_ld"
+ test "$withval" = no || with_gnu_ld=yes
+else
+ with_gnu_ld=no
+fi;
+ac_prog=ld
+if test "$GCC" = yes; then
+ # Check if gcc -print-prog-name=ld gives a path.
+ echo "$as_me:$LINENO: checking for ld used by $CC" >&5
+echo $ECHO_N "checking for ld used by $CC... $ECHO_C" >&6
+ case $host in
+ *-*-mingw*)
+ # gcc leaves a trailing carriage return which upsets mingw
+ ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+ *)
+ ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+ esac
+ case $ac_prog in
+ # Accept absolute paths.
+ [\\/]* | ?:[\\/]*)
+ re_direlt='/[^/][^/]*/\.\./'
+ # Canonicalize the pathname of ld
+ ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'`
+ while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do
+ ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"`
+ done
+ test -z "$LD" && LD="$ac_prog"
+ ;;
+ "")
+ # If it fails, then pretend we aren't using GCC.
+ ac_prog=ld
+ ;;
+ *)
+ # If it is relative, then search for the first ld in PATH.
+ with_gnu_ld=unknown
+ ;;
+ esac
+elif test "$with_gnu_ld" = yes; then
+ echo "$as_me:$LINENO: checking for GNU ld" >&5
+echo $ECHO_N "checking for GNU ld... $ECHO_C" >&6
+else
+ echo "$as_me:$LINENO: checking for non-GNU ld" >&5
+echo $ECHO_N "checking for non-GNU ld... $ECHO_C" >&6
+fi
+if test "${lt_cv_path_LD+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -z "$LD"; then
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+ lt_cv_path_LD="$ac_dir/$ac_prog"
+ # Check to see if the program is GNU ld. I'd rather use --version,
+ # but apparently some GNU ld's only accept -v.
+ # Break only if it was the GNU/non-GNU ld that we prefer.
+ case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+ *GNU* | *'with BFD'*)
+ test "$with_gnu_ld" != no && break
+ ;;
+ *)
+ test "$with_gnu_ld" != yes && break
+ ;;
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+else
+ lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi
+fi
+
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+ echo "$as_me:$LINENO: result: $LD" >&5
+echo "${ECHO_T}$LD" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+test -z "$LD" && { { echo "$as_me:$LINENO: error: no acceptable ld found in \$PATH" >&5
+echo "$as_me: error: no acceptable ld found in \$PATH" >&2;}
+ { (exit 1); exit 1; }; }
+echo "$as_me:$LINENO: checking if the linker ($LD) is GNU ld" >&5
+echo $ECHO_N "checking if the linker ($LD) is GNU ld... $ECHO_C" >&6
+if test "${lt_cv_prog_gnu_ld+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ # I'd rather use --version here, but apparently some GNU ld's only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+ lt_cv_prog_gnu_ld=yes
+ ;;
+*)
+ lt_cv_prog_gnu_ld=no
+ ;;
+esac
+fi
+echo "$as_me:$LINENO: result: $lt_cv_prog_gnu_ld" >&5
+echo "${ECHO_T}$lt_cv_prog_gnu_ld" >&6
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+
+
+ # Check if GNU C++ uses GNU ld as the underlying linker, since the
+ # archiving commands below assume that GNU ld is being used.
+ if test "$with_gnu_ld" = yes; then
+ archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+
+ hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir'
+ export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
+
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
+ # investigate it a little bit more. (MM)
+ wlarc='${wl}'
+
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if eval "`$CC -print-prog-name=ld` --help 2>&1" | \
+ grep 'no-whole-archive' > /dev/null; then
+ whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ whole_archive_flag_spec_CXX=
+ fi
+ else
+ with_gnu_ld=no
+ wlarc=
+
+ # A generic and very simple default shared library creation
+ # command for GNU C++ for the case where it uses the native
+ # linker, instead of GNU ld. If possible, this setting should
+ # overridden to take advantage of the native linker features on
+ # the platform it is being used on.
+ archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+ fi
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"'
+
+else
+ GXX=no
+ with_gnu_ld=no
+ wlarc=
+fi
+
+# PORTME: fill in a description of your system's C++ link characteristics
+echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6
+ld_shlibs_CXX=yes
+case $host_os in
+ aix3*)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ aix4* | aix5*)
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=""
+ else
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # need to do runtime linking.
+ case $host_os in aix4.[23]|aix4.[23].*|aix5*)
+ for ld_flag in $LDFLAGS; do
+ case $ld_flag in
+ *-brtl*)
+ aix_use_runtimelinking=yes
+ break
+ ;;
+ esac
+ done
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ archive_cmds_CXX=''
+ hardcode_direct_CXX=yes
+ hardcode_libdir_separator_CXX=':'
+ link_all_deplibs_CXX=yes
+
+ if test "$GXX" = yes; then
+ case $host_os in aix4.012|aix4.012.*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" && \
+ strings "$collect2name" | grep resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ hardcode_direct_CXX=yes
+ else
+ # We have old collect2
+ hardcode_direct_CXX=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ hardcode_minus_L_CXX=yes
+ hardcode_libdir_flag_spec_CXX='-L$libdir'
+ hardcode_libdir_separator_CXX=
+ fi
+ esac
+ shared_flag='-shared'
+ else
+ # not using gcc
+ if test "$host_cpu" = ia64; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag='${wl}-G'
+ else
+ shared_flag='${wl}-bM:SRE'
+ fi
+ fi
+ fi
+
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to export.
+ always_export_symbols_CXX=yes
+ if test "$aix_use_runtimelinking" = yes; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ allow_undefined_flag_CXX='-berok'
+ # Determine the default libpath from the value encoded in an empty executable.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_cxx_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
+}'`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
+}'`; fi
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+ hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath"
+
+ archive_expsym_cmds_CXX="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ else
+ if test "$host_cpu" = ia64; then
+ hardcode_libdir_flag_spec_CXX='${wl}-R $libdir:/usr/lib:/lib'
+ allow_undefined_flag_CXX="-z nodefs"
+ archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an empty executable.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_cxx_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
+}'`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
+}'`; fi
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+ hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ no_undefined_flag_CXX=' ${wl}-bernotok'
+ allow_undefined_flag_CXX=' ${wl}-berok'
+ # -bexpall does not export symbols beginning with underscore (_)
+ always_export_symbols_CXX=yes
+ # Exported symbols can be pulled into shared objects from archives
+ whole_archive_flag_spec_CXX=' '
+ archive_cmds_need_lc_CXX=yes
+ # This is similar to how AIX traditionally builds it's shared libraries.
+ archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ fi
+ fi
+ ;;
+ chorus*)
+ case $cc_basename in
+ *)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ esac
+ ;;
+
+ cygwin* | mingw* | pw32*)
+ # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, CXX) is actually meaningless,
+ # as there is no search path for DLLs.
+ hardcode_libdir_flag_spec_CXX='-L$libdir'
+ allow_undefined_flag_CXX=unsupported
+ always_export_symbols_CXX=no
+ enable_shared_with_static_runtimes_CXX=yes
+
+ if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
+ archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+ # If the export-symbols file already is a .def file (1st line
+ # is EXPORTS), use it as is; otherwise, prepend...
+ archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+ else
+ ld_shlibs_CXX=no
+ fi
+ ;;
+
+ darwin* | rhapsody*)
+ if test "$GXX" = yes; then
+ archive_cmds_need_lc_CXX=no
+ case "$host_os" in
+ rhapsody* | darwin1.[012])
+ allow_undefined_flag_CXX='-undefined suppress'
+ ;;
+ *) # Darwin 1.3 on
+ if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
+ allow_undefined_flag_CXX='-flat_namespace -undefined suppress'
+ else
+ case ${MACOSX_DEPLOYMENT_TARGET} in
+ 10.[012])
+ allow_undefined_flag_CXX='-flat_namespace -undefined suppress'
+ ;;
+ 10.*)
+ allow_undefined_flag_CXX='-undefined dynamic_lookup'
+ ;;
+ esac
+ fi
+ ;;
+ esac
+ lt_int_apple_cc_single_mod=no
+ output_verbose_link_cmd='echo'
+ if $CC -dumpspecs 2>&1 | grep 'single_module' >/dev/null ; then
+ lt_int_apple_cc_single_mod=yes
+ fi
+ if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
+ archive_cmds_CXX='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+ else
+ archive_cmds_CXX='$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+ fi
+ module_cmds_CXX='$CC ${wl}-bind_at_load $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+
+ # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's
+ if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
+ archive_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ else
+ archive_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ fi
+ module_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ hardcode_direct_CXX=no
+ hardcode_automatic_CXX=yes
+ hardcode_shlibpath_var_CXX=unsupported
+ whole_archive_flag_spec_CXX='-all_load $convenience'
+ link_all_deplibs_CXX=yes
+ else
+ ld_shlibs_CXX=no
+ fi
+ ;;
+
+ dgux*)
+ case $cc_basename in
+ ec++)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ ghcx)
+ # Green Hills C++ Compiler
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ esac
+ ;;
+ freebsd12*)
+ # C++ shared libraries reported to be fairly broken before switch to ELF
+ ld_shlibs_CXX=no
+ ;;
+ freebsd-elf*)
+ archive_cmds_need_lc_CXX=no
+ ;;
+ freebsd* | kfreebsd*-gnu)
+ # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
+ # conventions
+ ld_shlibs_CXX=yes
+ ;;
+ gnu*)
+ ;;
+ hpux9*)
+ hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator_CXX=:
+ export_dynamic_flag_spec_CXX='${wl}-E'
+ hardcode_direct_CXX=yes
+ hardcode_minus_L_CXX=yes # Not in the search PATH,
+ # but as the default
+ # location of the library.
+
+ case $cc_basename in
+ CC)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ aCC)
+ archive_cmds_CXX='$rm $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+ ;;
+ *)
+ if test "$GXX" = yes; then
+ archive_cmds_CXX='$rm $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ else
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ fi
+ ;;
+ esac
+ ;;
+ hpux10*|hpux11*)
+ if test $with_gnu_ld = no; then
+ case "$host_cpu" in
+ hppa*64*)
+ hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir'
+ hardcode_libdir_flag_spec_ld_CXX='+b $libdir'
+ hardcode_libdir_separator_CXX=:
+ ;;
+ ia64*)
+ hardcode_libdir_flag_spec_CXX='-L$libdir'
+ ;;
+ *)
+ hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator_CXX=:
+ export_dynamic_flag_spec_CXX='${wl}-E'
+ ;;
+ esac
+ fi
+ case "$host_cpu" in
+ hppa*64*)
+ hardcode_direct_CXX=no
+ hardcode_shlibpath_var_CXX=no
+ ;;
+ ia64*)
+ hardcode_direct_CXX=no
+ hardcode_shlibpath_var_CXX=no
+ hardcode_minus_L_CXX=yes # Not in the search PATH,
+ # but as the default
+ # location of the library.
+ ;;
+ *)
+ hardcode_direct_CXX=yes
+ hardcode_minus_L_CXX=yes # Not in the search PATH,
+ # but as the default
+ # location of the library.
+ ;;
+ esac
+
+ case $cc_basename in
+ CC)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ aCC)
+ case "$host_cpu" in
+ hppa*64*|ia64*)
+ archive_cmds_CXX='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs'
+ ;;
+ *)
+ archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ esac
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+ ;;
+ *)
+ if test "$GXX" = yes; then
+ if test $with_gnu_ld = no; then
+ case "$host_cpu" in
+ ia64*|hppa*64*)
+ archive_cmds_CXX='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs'
+ ;;
+ *)
+ archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ esac
+ fi
+ else
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ fi
+ ;;
+ esac
+ ;;
+ irix5* | irix6*)
+ case $cc_basename in
+ CC)
+ # SGI C++
+ archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib'
+
+ # Archives containing C++ object files must be created using
+ # "CC -ar", where "CC" is the IRIX C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ old_archive_cmds_CXX='$CC -ar -WR,-u -o $oldlib $oldobjs'
+ ;;
+ *)
+ if test "$GXX" = yes; then
+ if test "$with_gnu_ld" = no; then
+ archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib'
+ else
+ archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` -o $lib'
+ fi
+ fi
+ link_all_deplibs_CXX=yes
+ ;;
+ esac
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator_CXX=:
+ ;;
+ linux*)
+ case $cc_basename in
+ KCC)
+ # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+ # KCC will only create a shared library if the output file
+ # ends with ".so" (or ".sl" for HP-UX), so rename the library
+ # to its proper name (with version) after linking.
+ archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+ archive_expsym_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib'
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | grep "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+
+ hardcode_libdir_flag_spec_CXX='${wl}--rpath,$libdir'
+ export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
+
+ # Archives containing C++ object files must be created using
+ # "CC -Bstatic", where "CC" is the KAI C++ compiler.
+ old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs'
+ ;;
+ icpc)
+ # Intel C++
+ with_gnu_ld=yes
+ archive_cmds_need_lc_CXX=no
+ archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
+ export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
+ whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+ ;;
+ cxx)
+ # Compaq C++
+ archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
+
+ runpath_var=LD_RUN_PATH
+ hardcode_libdir_flag_spec_CXX='-rpath $libdir'
+ hardcode_libdir_separator_CXX=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+ ;;
+ esac
+ ;;
+ lynxos*)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ m88k*)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ mvs*)
+ case $cc_basename in
+ cxx)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ esac
+ ;;
+ netbsd*)
+ if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+ archive_cmds_CXX='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
+ wlarc=
+ hardcode_libdir_flag_spec_CXX='-R$libdir'
+ hardcode_direct_CXX=yes
+ hardcode_shlibpath_var_CXX=no
+ fi
+ # Workaround some broken pre-1.5 toolchains
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
+ ;;
+ osf3*)
+ case $cc_basename in
+ KCC)
+ # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+ # KCC will only create a shared library if the output file
+ # ends with ".so" (or ".sl" for HP-UX), so rename the library
+ # to its proper name (with version) after linking.
+ archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
+ hardcode_libdir_separator_CXX=:
+
+ # Archives containing C++ object files must be created using
+ # "CC -Bstatic", where "CC" is the KAI C++ compiler.
+ old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs'
+
+ ;;
+ RCC)
+ # Rational C++ 2.4.1
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ cxx)
+ allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && echo ${wl}-set_version $verstring` -update_registry ${objdir}/so_locations -o $lib'
+
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator_CXX=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+ ;;
+ *)
+ if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+ allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib'
+
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator_CXX=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"'
+
+ else
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ fi
+ ;;
+ esac
+ ;;
+ osf4* | osf5*)
+ case $cc_basename in
+ KCC)
+ # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+ # KCC will only create a shared library if the output file
+ # ends with ".so" (or ".sl" for HP-UX), so rename the library
+ # to its proper name (with version) after linking.
+ archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
+ hardcode_libdir_separator_CXX=:
+
+ # Archives containing C++ object files must be created using
+ # the KAI C++ compiler.
+ old_archive_cmds_CXX='$CC -o $oldlib $oldobjs'
+ ;;
+ RCC)
+ # Rational C++ 2.4.1
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ cxx)
+ allow_undefined_flag_CXX=' -expect_unresolved \*'
+ archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib'
+ archive_expsym_cmds_CXX='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
+ echo "-hidden">> $lib.exp~
+ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname -Wl,-input -Wl,$lib.exp `test -n "$verstring" && echo -set_version $verstring` -update_registry $objdir/so_locations -o $lib~
+ $rm $lib.exp'
+
+ hardcode_libdir_flag_spec_CXX='-rpath $libdir'
+ hardcode_libdir_separator_CXX=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+ ;;
+ *)
+ if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+ allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib'
+
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator_CXX=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"'
+
+ else
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ fi
+ ;;
+ esac
+ ;;
+ psos*)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ sco*)
+ archive_cmds_need_lc_CXX=no
+ case $cc_basename in
+ CC)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ esac
+ ;;
+ sunos4*)
+ case $cc_basename in
+ CC)
+ # Sun C++ 4.x
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ lcc)
+ # Lucid
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ esac
+ ;;
+ solaris*)
+ case $cc_basename in
+ CC)
+ # Sun C++ 4.2, 5.x and Centerline C++
+ no_undefined_flag_CXX=' -zdefs'
+ archive_cmds_CXX='$CC -G${allow_undefined_flag} -nolib -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ archive_expsym_cmds_CXX='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $CC -G${allow_undefined_flag} -nolib ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
+
+ hardcode_libdir_flag_spec_CXX='-R$libdir'
+ hardcode_shlibpath_var_CXX=no
+ case $host_os in
+ solaris2.0-5 | solaris2.0-5.*) ;;
+ *)
+ # The C++ compiler is used as linker so we must use $wl
+ # flag to pass the commands to the underlying system
+ # linker.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ whole_archive_flag_spec_CXX='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+ ;;
+ esac
+ link_all_deplibs_CXX=yes
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep "\-[LR]"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+
+ # Archives containing C++ object files must be created using
+ # "CC -xar", where "CC" is the Sun C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs'
+ ;;
+ gcx)
+ # Green Hills C++ Compiler
+ archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+
+ # The C++ compiler must be used to create the archive.
+ old_archive_cmds_CXX='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
+ ;;
+ *)
+ # GNU C++ compiler with Solaris linker
+ if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+ no_undefined_flag_CXX=' ${wl}-z ${wl}defs'
+ if $CC --version | grep -v '^2\.7' > /dev/null; then
+ archive_cmds_CXX='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+ archive_expsym_cmds_CXX='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd="$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\""
+ else
+ # g++ 2.7 appears to require `-G' NOT `-shared' on this
+ # platform.
+ archive_cmds_CXX='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+ archive_expsym_cmds_CXX='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd="$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\""
+ fi
+
+ hardcode_libdir_flag_spec_CXX='${wl}-R $wl$libdir'
+ fi
+ ;;
+ esac
+ ;;
+ sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[78]* | unixware7*)
+ archive_cmds_need_lc_CXX=no
+ ;;
+ tandem*)
+ case $cc_basename in
+ NCC)
+ # NonStop-UX NCC 3.20
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ esac
+ ;;
+ vxworks*)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+esac
+echo "$as_me:$LINENO: result: $ld_shlibs_CXX" >&5
+echo "${ECHO_T}$ld_shlibs_CXX" >&6
+test "$ld_shlibs_CXX" = no && can_build_shared=no
+
+GCC_CXX="$GXX"
+LD_CXX="$LD"
+
+
+cat > conftest.$ac_ext <<EOF
+class Foo
+{
+public:
+ Foo (void) { a = 0; }
+private:
+ int a;
+};
+EOF
+
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # Parse the compiler output and extract the necessary
+ # objects, libraries and library flags.
+
+ # Sentinel used to keep track of whether or not we are before
+ # the conftest object file.
+ pre_test_object_deps_done=no
+
+ # The `*' in the case matches for architectures that use `case' in
+ # $output_verbose_cmd can trigger glob expansion during the loop
+ # eval without this substitution.
+ output_verbose_link_cmd="`$echo \"X$output_verbose_link_cmd\" | $Xsed -e \"$no_glob_subst\"`"
+
+ for p in `eval $output_verbose_link_cmd`; do
+ case $p in
+
+ -L* | -R* | -l*)
+ # Some compilers place space between "-{L,R}" and the path.
+ # Remove the space.
+ if test $p = "-L" \
+ || test $p = "-R"; then
+ prev=$p
+ continue
+ else
+ prev=
+ fi
+
+ if test "$pre_test_object_deps_done" = no; then
+ case $p in
+ -L* | -R*)
+ # Internal compiler library paths should come after those
+ # provided the user. The postdeps already come after the
+ # user supplied libs so there is no need to process them.
+ if test -z "$compiler_lib_search_path_CXX"; then
+ compiler_lib_search_path_CXX="${prev}${p}"
+ else
+ compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} ${prev}${p}"
+ fi
+ ;;
+ # The "-l" case would never come before the object being
+ # linked, so don't bother handling this case.
+ esac
+ else
+ if test -z "$postdeps_CXX"; then
+ postdeps_CXX="${prev}${p}"
+ else
+ postdeps_CXX="${postdeps_CXX} ${prev}${p}"
+ fi
+ fi
+ ;;
+
+ *.$objext)
+ # This assumes that the test object file only shows up
+ # once in the compiler output.
+ if test "$p" = "conftest.$objext"; then
+ pre_test_object_deps_done=yes
+ continue
+ fi
+
+ if test "$pre_test_object_deps_done" = no; then
+ if test -z "$predep_objects_CXX"; then
+ predep_objects_CXX="$p"
+ else
+ predep_objects_CXX="$predep_objects_CXX $p"
+ fi
+ else
+ if test -z "$postdep_objects_CXX"; then
+ postdep_objects_CXX="$p"
+ else
+ postdep_objects_CXX="$postdep_objects_CXX $p"
+ fi
+ fi
+ ;;
+
+ *) ;; # Ignore the rest.
+
+ esac
+ done
+
+ # Clean up.
+ rm -f a.out a.exe
+else
+ echo "libtool.m4: error: problem compiling CXX test program"
+fi
+
+$rm -f confest.$objext
+
+case " $postdeps_CXX " in
+*" -lc "*) archive_cmds_need_lc_CXX=no ;;
+esac
+
+lt_prog_compiler_wl_CXX=
+lt_prog_compiler_pic_CXX=
+lt_prog_compiler_static_CXX=
+
+echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5
+echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
+
+ # C++ specific cases for pic, static, wl, etc.
+ if test "$GXX" = yes; then
+ lt_prog_compiler_wl_CXX='-Wl,'
+ lt_prog_compiler_static_CXX='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static_CXX='-Bstatic'
+ fi
+ ;;
+ amigaos*)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the `-m68020' flag to GCC prevents building anything better,
+ # like `-m68040'.
+ lt_prog_compiler_pic_CXX='-m68020 -resident32 -malways-restore-a4'
+ ;;
+ beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+ mingw* | os2* | pw32*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ lt_prog_compiler_pic_CXX='-DDLL_EXPORT'
+ ;;
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ lt_prog_compiler_pic_CXX='-fno-common'
+ ;;
+ *djgpp*)
+ # DJGPP does not support shared libraries at all
+ lt_prog_compiler_pic_CXX=
+ ;;
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ lt_prog_compiler_pic_CXX=-Kconform_pic
+ fi
+ ;;
+ hpux*)
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case "$host_cpu" in
+ hppa*64*|ia64*)
+ ;;
+ *)
+ lt_prog_compiler_pic_CXX='-fPIC'
+ ;;
+ esac
+ ;;
+ *)
+ lt_prog_compiler_pic_CXX='-fPIC'
+ ;;
+ esac
+ else
+ case $host_os in
+ aix4* | aix5*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static_CXX='-Bstatic'
+ else
+ lt_prog_compiler_static_CXX='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+ chorus*)
+ case $cc_basename in
+ cxch68)
+ # Green Hills C++ Compiler
+ # _LT_AC_TAGVAR(lt_prog_compiler_static, CXX)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
+ ;;
+ esac
+ ;;
+ dgux*)
+ case $cc_basename in
+ ec++)
+ lt_prog_compiler_pic_CXX='-KPIC'
+ ;;
+ ghcx)
+ # Green Hills C++ Compiler
+ lt_prog_compiler_pic_CXX='-pic'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ freebsd* | kfreebsd*-gnu)
+ # FreeBSD uses GNU C++
+ ;;
+ hpux9* | hpux10* | hpux11*)
+ case $cc_basename in
+ CC)
+ lt_prog_compiler_wl_CXX='-Wl,'
+ lt_prog_compiler_static_CXX="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive"
+ if test "$host_cpu" != ia64; then
+ lt_prog_compiler_pic_CXX='+Z'
+ fi
+ ;;
+ aCC)
+ lt_prog_compiler_wl_CXX='-Wl,'
+ lt_prog_compiler_static_CXX="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive"
+ case "$host_cpu" in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ lt_prog_compiler_pic_CXX='+Z'
+ ;;
+ esac
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ irix5* | irix6* | nonstopux*)
+ case $cc_basename in
+ CC)
+ lt_prog_compiler_wl_CXX='-Wl,'
+ lt_prog_compiler_static_CXX='-non_shared'
+ # CC pic flag -KPIC is the default.
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ linux*)
+ case $cc_basename in
+ KCC)
+ # KAI C++ Compiler
+ lt_prog_compiler_wl_CXX='--backend -Wl,'
+ lt_prog_compiler_pic_CXX='-fPIC'
+ ;;
+ icpc)
+ # Intel C++
+ lt_prog_compiler_wl_CXX='-Wl,'
+ lt_prog_compiler_pic_CXX='-KPIC'
+ lt_prog_compiler_static_CXX='-static'
+ ;;
+ cxx)
+ # Compaq C++
+ # Make sure the PIC flag is empty. It appears that all Alpha
+ # Linux and Compaq Tru64 Unix objects are PIC.
+ lt_prog_compiler_pic_CXX=
+ lt_prog_compiler_static_CXX='-non_shared'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ lynxos*)
+ ;;
+ m88k*)
+ ;;
+ mvs*)
+ case $cc_basename in
+ cxx)
+ lt_prog_compiler_pic_CXX='-W c,exportall'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ netbsd*)
+ ;;
+ osf3* | osf4* | osf5*)
+ case $cc_basename in
+ KCC)
+ lt_prog_compiler_wl_CXX='--backend -Wl,'
+ ;;
+ RCC)
+ # Rational C++ 2.4.1
+ lt_prog_compiler_pic_CXX='-pic'
+ ;;
+ cxx)
+ # Digital/Compaq C++
+ lt_prog_compiler_wl_CXX='-Wl,'
+ # Make sure the PIC flag is empty. It appears that all Alpha
+ # Linux and Compaq Tru64 Unix objects are PIC.
+ lt_prog_compiler_pic_CXX=
+ lt_prog_compiler_static_CXX='-non_shared'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ psos*)
+ ;;
+ sco*)
+ case $cc_basename in
+ CC)
+ lt_prog_compiler_pic_CXX='-fPIC'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ solaris*)
+ case $cc_basename in
+ CC)
+ # Sun C++ 4.2, 5.x and Centerline C++
+ lt_prog_compiler_pic_CXX='-KPIC'
+ lt_prog_compiler_static_CXX='-Bstatic'
+ lt_prog_compiler_wl_CXX='-Qoption ld '
+ ;;
+ gcx)
+ # Green Hills C++ Compiler
+ lt_prog_compiler_pic_CXX='-PIC'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ sunos4*)
+ case $cc_basename in
+ CC)
+ # Sun C++ 4.x
+ lt_prog_compiler_pic_CXX='-pic'
+ lt_prog_compiler_static_CXX='-Bstatic'
+ ;;
+ lcc)
+ # Lucid
+ lt_prog_compiler_pic_CXX='-pic'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ tandem*)
+ case $cc_basename in
+ NCC)
+ # NonStop-UX NCC 3.20
+ lt_prog_compiler_pic_CXX='-KPIC'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ unixware*)
+ ;;
+ vxworks*)
+ ;;
+ *)
+ lt_prog_compiler_can_build_shared_CXX=no
+ ;;
+ esac
+ fi
+
+echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_CXX" >&5
+echo "${ECHO_T}$lt_prog_compiler_pic_CXX" >&6
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$lt_prog_compiler_pic_CXX"; then
+
+echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5
+echo $ECHO_N "checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works... $ECHO_C" >&6
+if test "${lt_prog_compiler_pic_works_CXX+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_prog_compiler_pic_works_CXX=no
+ ac_outfile=conftest.$ac_objext
+ printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:12620: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&5
+ echo "$as_me:12624: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test ! -s conftest.err; then
+ lt_prog_compiler_pic_works_CXX=yes
+ fi
+ fi
+ $rm conftest*
+
+fi
+echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_works_CXX" >&5
+echo "${ECHO_T}$lt_prog_compiler_pic_works_CXX" >&6
+
+if test x"$lt_prog_compiler_pic_works_CXX" = xyes; then
+ case $lt_prog_compiler_pic_CXX in
+ "" | " "*) ;;
+ *) lt_prog_compiler_pic_CXX=" $lt_prog_compiler_pic_CXX" ;;
+ esac
+else
+ lt_prog_compiler_pic_CXX=
+ lt_prog_compiler_can_build_shared_CXX=no
+fi
+
+fi
+case "$host_os" in
+ # For platforms which do not support PIC, -DPIC is meaningless:
+ *djgpp*)
+ lt_prog_compiler_pic_CXX=
+ ;;
+ *)
+ lt_prog_compiler_pic_CXX="$lt_prog_compiler_pic_CXX -DPIC"
+ ;;
+esac
+
+echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5
+echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6
+if test "${lt_cv_prog_compiler_c_o_CXX+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_cv_prog_compiler_c_o_CXX=no
+ $rm -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:12680: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&5
+ echo "$as_me:12684: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test ! -s out/conftest.err; then
+ lt_cv_prog_compiler_c_o_CXX=yes
+ fi
+ fi
+ chmod u+w .
+ $rm conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files
+ $rm out/* && rmdir out
+ cd ..
+ rmdir conftest
+ $rm conftest*
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o_CXX" >&5
+echo "${ECHO_T}$lt_cv_prog_compiler_c_o_CXX" >&6
+
+
+hard_links="nottested"
+if test "$lt_cv_prog_compiler_c_o_CXX" = no && test "$need_locks" != no; then
+ # do not overwrite the value of need_locks provided by the user
+ echo "$as_me:$LINENO: checking if we can lock with hard links" >&5
+echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6
+ hard_links=yes
+ $rm conftest*
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ touch conftest.a
+ ln conftest.a conftest.b 2>&5 || hard_links=no
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ echo "$as_me:$LINENO: result: $hard_links" >&5
+echo "${ECHO_T}$hard_links" >&6
+ if test "$hard_links" = no; then
+ { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
+echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
+ need_locks=warn
+ fi
+else
+ need_locks=no
+fi
+
+echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6
+
+ export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ case $host_os in
+ aix4* | aix5*)
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to AIX nm, but means don't demangle with GNU nm
+ if $NM -V 2>&1 | grep 'GNU' > /dev/null; then
+ export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols'
+ else
+ export_symbols_cmds_CXX='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols'
+ fi
+ ;;
+ pw32*)
+ export_symbols_cmds_CXX="$ltdll_cmds"
+ ;;
+ cygwin* | mingw*)
+ export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGS] /s/.* \([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW] /s/.* //'\'' | sort | uniq > $export_symbols'
+ ;;
+ *)
+ export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ ;;
+ esac
+
+echo "$as_me:$LINENO: result: $ld_shlibs_CXX" >&5
+echo "${ECHO_T}$ld_shlibs_CXX" >&6
+test "$ld_shlibs_CXX" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+ variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$archive_cmds_need_lc_CXX" in
+x|xyes)
+ # Assume -lc should be added
+ archive_cmds_need_lc_CXX=yes
+
+ if test "$enable_shared" = yes && test "$GCC" = yes; then
+ case $archive_cmds_CXX in
+ *'~'*)
+ # FIXME: we may have to deal with multi-command sequences.
+ ;;
+ '$CC '*)
+ # Test whether the compiler implicitly links with -lc since on some
+ # systems, -lgcc has to come before -lc. If gcc already passes -lc
+ # to ld, don't add -lc before -lgcc.
+ echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5
+echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6
+ $rm conftest*
+ printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } 2>conftest.err; then
+ soname=conftest
+ lib=conftest
+ libobjs=conftest.$ac_objext
+ deplibs=
+ wl=$lt_prog_compiler_wl_CXX
+ compiler_flags=-v
+ linker_flags=-v
+ verstring=
+ output_objdir=.
+ libname=conftest
+ lt_save_allow_undefined_flag=$allow_undefined_flag_CXX
+ allow_undefined_flag_CXX=
+ if { (eval echo "$as_me:$LINENO: \"$archive_cmds_CXX 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5
+ (eval $archive_cmds_CXX 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+ then
+ archive_cmds_need_lc_CXX=no
+ else
+ archive_cmds_need_lc_CXX=yes
+ fi
+ allow_undefined_flag_CXX=$lt_save_allow_undefined_flag
+ else
+ cat conftest.err 1>&5
+ fi
+ $rm conftest*
+ echo "$as_me:$LINENO: result: $archive_cmds_need_lc_CXX" >&5
+echo "${ECHO_T}$archive_cmds_need_lc_CXX" >&6
+ ;;
+ esac
+ fi
+ ;;
+esac
+
+echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5
+echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+if test "$GCC" = yes; then
+ sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+ if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then
+ # if the path contains ";" then we assume it to be the separator
+ # otherwise default to the standard path separator (i.e. ":") - it is
+ # assumed that no part of a normal pathname contains ";" but that should
+ # okay in the real world where ";" in dirpaths is itself problematic.
+ sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+ else
+ sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ fi
+else
+ sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+ shlibpath_var=LIBPATH
+
+ # AIX 3 has no versioning support, so we append a major version to the name.
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+
+aix4* | aix5*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ hardcode_into_libs=yes
+ if test "$host_cpu" = ia64; then
+ # AIX 5 supports IA64
+ library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ else
+ # With GCC up to 2.95.x, collect2 would create an import file
+ # for dependence libraries. The import file would start with
+ # the line `#! .'. This would cause the generated library to
+ # depend on `.', always an invalid library. This was fixed in
+ # development snapshots of GCC prior to 3.0.
+ case $host_os in
+ aix4 | aix4.[01] | aix4.[01].*)
+ if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+ echo ' yes '
+ echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then
+ :
+ else
+ can_build_shared=no
+ fi
+ ;;
+ esac
+ # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+ # soname into executable. Probably we can add versioning support to
+ # collect2, so additional links can be useful in future.
+ if test "$aix_use_runtimelinking" = yes; then
+ # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+ # instead of lib<name>.a to let people know that these are not
+ # typical AIX shared libraries.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ else
+ # We preserve .a as extension for shared libraries through AIX4.2
+ # and later when we are not doing run time linking.
+ library_names_spec='${libname}${release}.a $libname.a'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ fi
+ shlibpath_var=LIBPATH
+ fi
+ ;;
+
+amigaos*)
+ library_names_spec='$libname.ixlibrary $libname.a'
+ # Create ${libname}_ixlibrary.a entries in /sys/libs.
+ finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+ ;;
+
+beos*)
+ library_names_spec='${libname}${shared_ext}'
+ dynamic_linker="$host_os ld.so"
+ shlibpath_var=LIBRARY_PATH
+ ;;
+
+bsdi4*)
+ version_type=linux
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+ # the default ld.so.conf also contains /usr/contrib/lib and
+ # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+ # libtool to hard-code these into programs
+ ;;
+
+cygwin* | mingw* | pw32*)
+ version_type=windows
+ shrext_cmds=".dll"
+ need_version=no
+ need_lib_prefix=no
+
+ case $GCC,$host_os in
+ yes,cygwin* | yes,mingw* | yes,pw32*)
+ library_names_spec='$libname.dll.a'
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \${file}`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $rm \$dlpath'
+ shlibpath_overrides_runpath=yes
+
+ case $host_os in
+ cygwin*)
+ # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+ soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib"
+ ;;
+ mingw*)
+ # MinGW DLLs use traditional 'lib' prefix
+ soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+ if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then
+ # It is most probably a Windows format PATH printed by
+ # mingw gcc, but we are running on Cygwin. Gcc prints its search
+ # path with ; separators, and with drive letters. We can handle the
+ # drive letters (cygwin fileutils understands them), so leave them,
+ # especially as we might pass files found there to a mingw objdump,
+ # which wouldn't understand a cygwinified path. Ahh.
+ sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+ else
+ sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ fi
+ ;;
+ pw32*)
+ # pw32 DLLs use 'pw' prefix rather than 'lib'
+ library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/./-/g'`${versuffix}${shared_ext}'
+ ;;
+ esac
+ ;;
+
+ *)
+ library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
+ ;;
+ esac
+ dynamic_linker='Win32 ld.exe'
+ # FIXME: first we should search . and the directory the executable is in
+ shlibpath_var=PATH
+ ;;
+
+darwin* | rhapsody*)
+ dynamic_linker="$host_os dyld"
+ version_type=darwin
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+ soname_spec='${libname}${release}${major}$shared_ext'
+ shlibpath_overrides_runpath=yes
+ shlibpath_var=DYLD_LIBRARY_PATH
+ shrext_cmds='$(test .$module = .yes && echo .so || echo .dylib)'
+ # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same.
+ if test "$GCC" = yes; then
+ sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"`
+ else
+ sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib'
+ fi
+ sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+ ;;
+
+dgux*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+freebsd1*)
+ dynamic_linker=no
+ ;;
+
+kfreebsd*-gnu)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='GNU ld.so'
+ ;;
+
+freebsd*)
+ objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout`
+ version_type=freebsd-$objformat
+ case $version_type in
+ freebsd-elf*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ need_version=no
+ need_lib_prefix=no
+ ;;
+ freebsd-*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+ need_version=yes
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_os in
+ freebsd2*)
+ shlibpath_overrides_runpath=yes
+ ;;
+ freebsd3.01* | freebsdelf3.01*)
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ *) # from 3.2 on
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+ esac
+ ;;
+
+gnu*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ hardcode_into_libs=yes
+ ;;
+
+hpux9* | hpux10* | hpux11*)
+ # Give a soname corresponding to the major version so that dld.sl refuses to
+ # link against other versions.
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ case "$host_cpu" in
+ ia64*)
+ shrext_cmds='.so'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ if test "X$HPUX_IA64_MODE" = X32; then
+ sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+ else
+ sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+ fi
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ hppa*64*)
+ shrext_cmds='.sl'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ *)
+ shrext_cmds='.sl'
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=SHLIB_PATH
+ shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+ esac
+ # HP-UX runs *really* slowly unless shared libraries are mode 555.
+ postinstall_cmds='chmod 555 $lib'
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $host_os in
+ nonstopux*) version_type=nonstopux ;;
+ *)
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ version_type=linux
+ else
+ version_type=irix
+ fi ;;
+ esac
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+ case $host_os in
+ irix5* | nonstopux*)
+ libsuff= shlibsuff=
+ ;;
+ *)
+ case $LD in # libtool.m4 will add one of these switches to LD
+ *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+ libsuff= shlibsuff= libmagic=32-bit;;
+ *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+ libsuff=32 shlibsuff=N32 libmagic=N32;;
+ *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+ libsuff=64 shlibsuff=64 libmagic=64-bit;;
+ *) libsuff= shlibsuff= libmagic=never-match;;
+ esac
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+ sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+ hardcode_into_libs=yes
+ ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+ dynamic_linker=no
+ ;;
+
+# This must be Linux ELF.
+linux*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ # This implies no fast_install, which is unacceptable.
+ # Some rework will be needed to allow for fast_install
+ # before this can be enabled.
+ hardcode_into_libs=yes
+
+ # find out which ABI we are using
+ libsuff=
+ case "$host_cpu" in
+ x86_64*|s390x*|powerpc64*)
+ echo '#line 13191 "configure"' > conftest.$ac_ext
+ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *64-bit*)
+ libsuff=64
+ sys_lib_search_path_spec="/lib${libsuff} /usr/lib${libsuff} /usr/local/lib${libsuff}"
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+ esac
+
+ # Append ld.so.conf contents to the search path
+ if test -f /etc/ld.so.conf; then
+ lt_ld_extra=`$SED -e 's/:,\t/ /g;s/=^=*$//;s/=^= * / /g' /etc/ld.so.conf | tr '\n' ' '`
+ sys_lib_dlsearch_path_spec="/lib${libsuff} /usr/lib${libsuff} $lt_ld_extra"
+ fi
+
+ # We used to test for /lib/ld.so.1 and disable shared libraries on
+ # powerpc, because MkLinux only supported shared libraries with the
+ # GNU dynamic linker. Since this was broken with cross compilers,
+ # most powerpc-linux boxes support dynamic linking these days and
+ # people can always --disable-shared, the test was removed, and we
+ # assume the GNU/Linux dynamic linker is in use.
+ dynamic_linker='GNU/Linux ld.so'
+ ;;
+
+knetbsd*-gnu)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='GNU ld.so'
+ ;;
+
+netbsd*)
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ dynamic_linker='NetBSD (a.out) ld.so'
+ else
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='NetBSD ld.elf_so'
+ fi
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+
+newsos6)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+nto-qnx*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+openbsd*)
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=yes
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ case $host_os in
+ openbsd2.[89] | openbsd2.[89].*)
+ shlibpath_overrides_runpath=no
+ ;;
+ *)
+ shlibpath_overrides_runpath=yes
+ ;;
+ esac
+ else
+ shlibpath_overrides_runpath=yes
+ fi
+ ;;
+
+os2*)
+ libname_spec='$name'
+ shrext_cmds=".dll"
+ need_lib_prefix=no
+ library_names_spec='$libname${shared_ext} $libname.a'
+ dynamic_linker='OS/2 ld.exe'
+ shlibpath_var=LIBPATH
+ ;;
+
+osf3* | osf4* | osf5*)
+ version_type=osf
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+ sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+ ;;
+
+sco3.2v5*)
+ version_type=osf
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+solaris*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ # ldd complains unless libraries are executable
+ postinstall_cmds='chmod +x $lib'
+ ;;
+
+sunos4*)
+ version_type=sunos
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ if test "$with_gnu_ld" = yes; then
+ need_lib_prefix=no
+ fi
+ need_version=yes
+ ;;
+
+sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_vendor in
+ sni)
+ shlibpath_overrides_runpath=no
+ need_lib_prefix=no
+ export_dynamic_flag_spec='${wl}-Blargedynsym'
+ runpath_var=LD_RUN_PATH
+ ;;
+ siemens)
+ need_lib_prefix=no
+ ;;
+ motorola)
+ need_lib_prefix=no
+ need_version=no
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+ ;;
+ esac
+ ;;
+
+sysv4*MP*)
+ if test -d /usr/nec ;then
+ version_type=linux
+ library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+ soname_spec='$libname${shared_ext}.$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ fi
+ ;;
+
+uts4*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+*)
+ dynamic_linker=no
+ ;;
+esac
+echo "$as_me:$LINENO: result: $dynamic_linker" >&5
+echo "${ECHO_T}$dynamic_linker" >&6
+test "$dynamic_linker" = no && can_build_shared=no
+
+echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5
+echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6
+hardcode_action_CXX=
+if test -n "$hardcode_libdir_flag_spec_CXX" || \
+ test -n "$runpath_var CXX" || \
+ test "X$hardcode_automatic_CXX"="Xyes" ; then
+
+ # We can hardcode non-existant directories.
+ if test "$hardcode_direct_CXX" != no &&
+ # If the only mechanism to avoid hardcoding is shlibpath_var, we
+ # have to relink, otherwise we might link with an installed library
+ # when we should be linking with a yet-to-be-installed one
+ ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, CXX)" != no &&
+ test "$hardcode_minus_L_CXX" != no; then
+ # Linking always hardcodes the temporary library directory.
+ hardcode_action_CXX=relink
+ else
+ # We can link without hardcoding, and we can hardcode nonexisting dirs.
+ hardcode_action_CXX=immediate
+ fi
+else
+ # We cannot hardcode anything, or else we can only hardcode existing
+ # directories.
+ hardcode_action_CXX=unsupported
+fi
+echo "$as_me:$LINENO: result: $hardcode_action_CXX" >&5
+echo "${ECHO_T}$hardcode_action_CXX" >&6
+
+if test "$hardcode_action_CXX" = relink; then
+ # Fast installation is not supported
+ enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+ test "$enable_shared" = no; then
+ # Fast installation is not necessary
+ enable_fast_install=needless
+fi
+
+striplib=
+old_striplib=
+echo "$as_me:$LINENO: checking whether stripping libraries is possible" >&5
+echo $ECHO_N "checking whether stripping libraries is possible... $ECHO_C" >&6
+if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then
+ test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+ test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+ case $host_os in
+ darwin*)
+ if test -n "$STRIP" ; then
+ striplib="$STRIP -x"
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+ ;;
+ *)
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ ;;
+ esac
+fi
+
+if test "x$enable_dlopen" != xyes; then
+ enable_dlopen=unknown
+ enable_dlopen_self=unknown
+ enable_dlopen_self_static=unknown
+else
+ lt_cv_dlopen=no
+ lt_cv_dlopen_libs=
+
+ case $host_os in
+ beos*)
+ lt_cv_dlopen="load_add_on"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+ ;;
+
+ mingw* | pw32*)
+ lt_cv_dlopen="LoadLibrary"
+ lt_cv_dlopen_libs=
+ ;;
+
+ cygwin*)
+ lt_cv_dlopen="dlopen"
+ lt_cv_dlopen_libs=
+ ;;
+
+ darwin*)
+ # if libdl is installed we need to link against it
+ echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5
+echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dlopen ();
+int
+main ()
+{
+dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_cxx_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_dl_dlopen=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dl_dlopen=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5
+echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6
+if test $ac_cv_lib_dl_dlopen = yes; then
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+
+ lt_cv_dlopen="dyld"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+
+fi
+
+ ;;
+
+ *)
+ echo "$as_me:$LINENO: checking for shl_load" >&5
+echo $ECHO_N "checking for shl_load... $ECHO_C" >&6
+if test "${ac_cv_func_shl_load+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define shl_load to an innocuous variant, in case <limits.h> declares shl_load.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define shl_load innocuous_shl_load
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char shl_load (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef shl_load
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char shl_load ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_shl_load) || defined (__stub___shl_load)
+choke me
+#else
+char (*f) () = shl_load;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != shl_load;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_cxx_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_shl_load=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_shl_load=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_shl_load" >&5
+echo "${ECHO_T}$ac_cv_func_shl_load" >&6
+if test $ac_cv_func_shl_load = yes; then
+ lt_cv_dlopen="shl_load"
+else
+ echo "$as_me:$LINENO: checking for shl_load in -ldld" >&5
+echo $ECHO_N "checking for shl_load in -ldld... $ECHO_C" >&6
+if test "${ac_cv_lib_dld_shl_load+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char shl_load ();
+int
+main ()
+{
+shl_load ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_cxx_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_dld_shl_load=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dld_shl_load=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dld_shl_load" >&5
+echo "${ECHO_T}$ac_cv_lib_dld_shl_load" >&6
+if test $ac_cv_lib_dld_shl_load = yes; then
+ lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"
+else
+ echo "$as_me:$LINENO: checking for dlopen" >&5
+echo $ECHO_N "checking for dlopen... $ECHO_C" >&6
+if test "${ac_cv_func_dlopen+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define dlopen to an innocuous variant, in case <limits.h> declares dlopen.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define dlopen innocuous_dlopen
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char dlopen (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef dlopen
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dlopen ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_dlopen) || defined (__stub___dlopen)
+choke me
+#else
+char (*f) () = dlopen;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != dlopen;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_cxx_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_dlopen=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_dlopen=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_dlopen" >&5
+echo "${ECHO_T}$ac_cv_func_dlopen" >&6
+if test $ac_cv_func_dlopen = yes; then
+ lt_cv_dlopen="dlopen"
+else
+ echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5
+echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dlopen ();
+int
+main ()
+{
+dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_cxx_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_dl_dlopen=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dl_dlopen=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5
+echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6
+if test $ac_cv_lib_dl_dlopen = yes; then
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+ echo "$as_me:$LINENO: checking for dlopen in -lsvld" >&5
+echo $ECHO_N "checking for dlopen in -lsvld... $ECHO_C" >&6
+if test "${ac_cv_lib_svld_dlopen+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsvld $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dlopen ();
+int
+main ()
+{
+dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_cxx_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_svld_dlopen=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_svld_dlopen=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_svld_dlopen" >&5
+echo "${ECHO_T}$ac_cv_lib_svld_dlopen" >&6
+if test $ac_cv_lib_svld_dlopen = yes; then
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"
+else
+ echo "$as_me:$LINENO: checking for dld_link in -ldld" >&5
+echo $ECHO_N "checking for dld_link in -ldld... $ECHO_C" >&6
+if test "${ac_cv_lib_dld_dld_link+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dld_link ();
+int
+main ()
+{
+dld_link ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_cxx_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_dld_dld_link=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dld_dld_link=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dld_dld_link" >&5
+echo "${ECHO_T}$ac_cv_lib_dld_dld_link" >&6
+if test $ac_cv_lib_dld_dld_link = yes; then
+ lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+ ;;
+ esac
+
+ if test "x$lt_cv_dlopen" != xno; then
+ enable_dlopen=yes
+ else
+ enable_dlopen=no
+ fi
+
+ case $lt_cv_dlopen in
+ dlopen)
+ save_CPPFLAGS="$CPPFLAGS"
+ test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+ save_LDFLAGS="$LDFLAGS"
+ eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+ save_LIBS="$LIBS"
+ LIBS="$lt_cv_dlopen_libs $LIBS"
+
+ echo "$as_me:$LINENO: checking whether a program can dlopen itself" >&5
+echo $ECHO_N "checking whether a program can dlopen itself... $ECHO_C" >&6
+if test "${lt_cv_dlopen_self+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$cross_compiling" = yes; then :
+ lt_cv_dlopen_self=cross
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<EOF
+#line 14062 "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+#ifdef __cplusplus
+extern "C" void exit (int);
+#endif
+
+void fnord() { int i=42;}
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ /* dlclose (self); */
+ }
+
+ exit (status);
+}
+EOF
+ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then
+ (./conftest; exit; ) 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;;
+ x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;;
+ x$lt_unknown|x*) lt_cv_dlopen_self=no ;;
+ esac
+ else :
+ # compilation failed
+ lt_cv_dlopen_self=no
+ fi
+fi
+rm -fr conftest*
+
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_dlopen_self" >&5
+echo "${ECHO_T}$lt_cv_dlopen_self" >&6
+
+ if test "x$lt_cv_dlopen_self" = xyes; then
+ LDFLAGS="$LDFLAGS $link_static_flag"
+ echo "$as_me:$LINENO: checking whether a statically linked program can dlopen itself" >&5
+echo $ECHO_N "checking whether a statically linked program can dlopen itself... $ECHO_C" >&6
+if test "${lt_cv_dlopen_self_static+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$cross_compiling" = yes; then :
+ lt_cv_dlopen_self_static=cross
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<EOF
+#line 14160 "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+#ifdef __cplusplus
+extern "C" void exit (int);
+#endif
+
+void fnord() { int i=42;}
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ /* dlclose (self); */
+ }
+
+ exit (status);
+}
+EOF
+ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then
+ (./conftest; exit; ) 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;;
+ x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;;
+ x$lt_unknown|x*) lt_cv_dlopen_self_static=no ;;
+ esac
+ else :
+ # compilation failed
+ lt_cv_dlopen_self_static=no
+ fi
+fi
+rm -fr conftest*
+
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_dlopen_self_static" >&5
+echo "${ECHO_T}$lt_cv_dlopen_self_static" >&6
+ fi
+
+ CPPFLAGS="$save_CPPFLAGS"
+ LDFLAGS="$save_LDFLAGS"
+ LIBS="$save_LIBS"
+ ;;
+ esac
+
+ case $lt_cv_dlopen_self in
+ yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+ *) enable_dlopen_self=unknown ;;
+ esac
+
+ case $lt_cv_dlopen_self_static in
+ yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+ *) enable_dlopen_self_static=unknown ;;
+ esac
+fi
+
+
+# The else clause should only fire when bootstrapping the
+# libtool distribution, otherwise you forgot to ship ltmain.sh
+# with your package, and you will get complaints that there are
+# no rules to generate ltmain.sh.
+if test -f "$ltmain"; then
+ # See if we are running on zsh, and set the options which allow our commands through
+ # without removal of \ escapes.
+ if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+ fi
+ # Now quote all the things that may contain metacharacters while being
+ # careful not to overquote the AC_SUBSTed values. We take copies of the
+ # variables and quote the copies for generation of the libtool script.
+ for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC NM \
+ SED SHELL STRIP \
+ libname_spec library_names_spec soname_spec extract_expsyms_cmds \
+ old_striplib striplib file_magic_cmd finish_cmds finish_eval \
+ deplibs_check_method reload_flag reload_cmds need_locks \
+ lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \
+ lt_cv_sys_global_symbol_to_c_name_address \
+ sys_lib_search_path_spec sys_lib_dlsearch_path_spec \
+ old_postinstall_cmds old_postuninstall_cmds \
+ compiler_CXX \
+ CC_CXX \
+ LD_CXX \
+ lt_prog_compiler_wl_CXX \
+ lt_prog_compiler_pic_CXX \
+ lt_prog_compiler_static_CXX \
+ lt_prog_compiler_no_builtin_flag_CXX \
+ export_dynamic_flag_spec_CXX \
+ thread_safe_flag_spec_CXX \
+ whole_archive_flag_spec_CXX \
+ enable_shared_with_static_runtimes_CXX \
+ old_archive_cmds_CXX \
+ old_archive_from_new_cmds_CXX \
+ predep_objects_CXX \
+ postdep_objects_CXX \
+ predeps_CXX \
+ postdeps_CXX \
+ compiler_lib_search_path_CXX \
+ archive_cmds_CXX \
+ archive_expsym_cmds_CXX \
+ postinstall_cmds_CXX \
+ postuninstall_cmds_CXX \
+ old_archive_from_expsyms_cmds_CXX \
+ allow_undefined_flag_CXX \
+ no_undefined_flag_CXX \
+ export_symbols_cmds_CXX \
+ hardcode_libdir_flag_spec_CXX \
+ hardcode_libdir_flag_spec_ld_CXX \
+ hardcode_libdir_separator_CXX \
+ hardcode_automatic_CXX \
+ module_cmds_CXX \
+ module_expsym_cmds_CXX \
+ lt_cv_prog_compiler_c_o_CXX \
+ exclude_expsyms_CXX \
+ include_expsyms_CXX; do
+
+ case $var in
+ old_archive_cmds_CXX | \
+ old_archive_from_new_cmds_CXX | \
+ archive_cmds_CXX | \
+ archive_expsym_cmds_CXX | \
+ module_cmds_CXX | \
+ module_expsym_cmds_CXX | \
+ old_archive_from_expsyms_cmds_CXX | \
+ export_symbols_cmds_CXX | \
+ extract_expsyms_cmds | reload_cmds | finish_cmds | \
+ postinstall_cmds | postuninstall_cmds | \
+ old_postinstall_cmds | old_postuninstall_cmds | \
+ sys_lib_search_path_spec | sys_lib_dlsearch_path_spec)
+ # Double-quote double-evaled strings.
+ eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\""
+ ;;
+ *)
+ eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\""
+ ;;
+ esac
+ done
+
+ case $lt_echo in
+ *'\$0 --fallback-echo"')
+ lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'`
+ ;;
+ esac
+
+cfgfile="$ofile"
+
+ cat <<__EOF__ >> "$cfgfile"
+# ### BEGIN LIBTOOL TAG CONFIG: $tagname
+
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+
+# Shell to use when invoking shell scripts.
+SHELL=$lt_SHELL
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc_CXX
+
+# Whether or not to disallow shared libs when runtime libs are static
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX
+
+# Whether or not to optimize for fast installation.
+fast_install=$enable_fast_install
+
+# The host system.
+host_alias=$host_alias
+host=$host
+
+# An echo program that does not interpret backslashes.
+echo=$lt_echo
+
+# The archiver.
+AR=$lt_AR
+AR_FLAGS=$lt_AR_FLAGS
+
+# A C compiler.
+LTCC=$lt_LTCC
+
+# A language-specific compiler.
+CC=$lt_compiler_CXX
+
+# Is the compiler the GNU C compiler?
+with_gcc=$GCC_CXX
+
+# An ERE matcher.
+EGREP=$lt_EGREP
+
+# The linker used to build libraries.
+LD=$lt_LD_CXX
+
+# Whether we need hard or soft links.
+LN_S=$lt_LN_S
+
+# A BSD-compatible nm program.
+NM=$lt_NM
+
+# A symbol stripping program
+STRIP=$lt_STRIP
+
+# Used to examine libraries when file_magic_cmd begins "file"
+MAGIC_CMD=$MAGIC_CMD
+
+# Used on cygwin: DLL creation program.
+DLLTOOL="$DLLTOOL"
+
+# Used on cygwin: object dumper.
+OBJDUMP="$OBJDUMP"
+
+# Used on cygwin: assembler.
+AS="$AS"
+
+# The name of the directory that contains temporary libtool files.
+objdir=$objdir
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag
+reload_cmds=$lt_reload_cmds
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl_CXX
+
+# Object file suffix (normally "o").
+objext="$ac_objext"
+
+# Old archive suffix (normally "a").
+libext="$libext"
+
+# Shared library suffix (normally ".so").
+shrext_cmds='$shrext_cmds'
+
+# Executable file suffix (normally "").
+exeext="$exeext"
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic_CXX
+pic_mode=$pic_mode
+
+# What is the maximum length of a command?
+max_cmd_len=$lt_cv_sys_max_cmd_len
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX
+
+# Must we lock files when doing compilation ?
+need_locks=$lt_need_locks
+
+# Do we need the lib prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Whether dlopen is supported.
+dlopen_support=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static_CXX
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX
+
+# Compiler flag to generate thread-safe objects.
+thread_safe_flag_spec=$lt_thread_safe_flag_spec_CXX
+
+# Library versioning type.
+version_type=$version_type
+
+# Format of library name prefix.
+libname_spec=$lt_libname_spec
+
+# List of archive names. First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME.
+library_names_spec=$lt_library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$lt_soname_spec
+
+# Commands used to build and install an old-style archive.
+RANLIB=$lt_RANLIB
+old_archive_cmds=$lt_old_archive_cmds_CXX
+old_postinstall_cmds=$lt_old_postinstall_cmds
+old_postuninstall_cmds=$lt_old_postuninstall_cmds
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX
+
+# Commands used to build and install a shared archive.
+archive_cmds=$lt_archive_cmds_CXX
+archive_expsym_cmds=$lt_archive_expsym_cmds_CXX
+postinstall_cmds=$lt_postinstall_cmds
+postuninstall_cmds=$lt_postuninstall_cmds
+
+# Commands used to build a loadable module (assumed same as above if empty)
+module_cmds=$lt_module_cmds_CXX
+module_expsym_cmds=$lt_module_expsym_cmds_CXX
+
+# Commands to strip libraries.
+old_striplib=$lt_old_striplib
+striplib=$lt_striplib
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predep_objects=$lt_predep_objects_CXX
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdep_objects=$lt_postdep_objects_CXX
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predeps=$lt_predeps_CXX
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdeps=$lt_postdeps_CXX
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path=$lt_compiler_lib_search_path_CXX
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$lt_deplibs_check_method
+
+# Command to use when deplibs_check_method == file_magic.
+file_magic_cmd=$lt_file_magic_cmd
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag_CXX
+
+# Flag that forces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag_CXX
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$lt_finish_cmds
+
+# Same as above, but a single script fragment to be evaled but not shown.
+finish_eval=$lt_finish_eval
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration
+global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
+
+# Transform the output of nm in a C name address pair
+global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
+
+# This is the shared library runtime path variable.
+runpath_var=$runpath_var
+
+# This is the shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action_CXX
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=$hardcode_into_libs
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX
+
+# If ld is used when linking, flag to hardcode \$libdir into
+# a binary during linking. This must work even if \$libdir does
+# not exist.
+hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_CXX
+
+# Whether we need a single -rpath flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX
+
+# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the
+# resulting binary.
+hardcode_direct=$hardcode_direct_CXX
+
+# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
+# resulting binary.
+hardcode_minus_L=$hardcode_minus_L_CXX
+
+# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into
+# the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX
+
+# Set to yes if building a shared library automatically hardcodes DIR into the library
+# and all subsequent libraries and executables linked against it.
+hardcode_automatic=$hardcode_automatic_CXX
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at relink time.
+variables_saved_for_relink="$variables_saved_for_relink"
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs_CXX
+
+# Compile-time system search path for libraries
+sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+
+# Run-time system search path for libraries
+sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
+
+# Fix the shell variable \$srcfile for the compiler.
+fix_srcfile_path="$fix_srcfile_path_CXX"
+
+# Set to yes if exported symbols are required.
+always_export_symbols=$always_export_symbols_CXX
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds_CXX
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=$lt_extract_expsyms_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms_CXX
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms_CXX
+
+# ### END LIBTOOL TAG CONFIG: $tagname
+
+__EOF__
+
+
+else
+ # If there is no Makefile yet, we rely on a make rule to execute
+ # `config.status --recheck' to rerun these tests and create the
+ # libtool script then.
+ ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'`
+ if test -f "$ltmain_in"; then
+ test -f Makefile && make "$ltmain"
+ fi
+fi
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+CC=$lt_save_CC
+LDCXX=$LD
+LD=$lt_save_LD
+GCC=$lt_save_GCC
+with_gnu_ldcxx=$with_gnu_ld
+with_gnu_ld=$lt_save_with_gnu_ld
+lt_cv_path_LDCXX=$lt_cv_path_LD
+lt_cv_path_LD=$lt_save_path_LD
+lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
+lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
+
+ else
+ tagname=""
+ fi
+ ;;
+
+ F77)
+ if test -n "$F77" && test "X$F77" != "Xno"; then
+
+ac_ext=f
+ac_compile='$F77 -c $FFLAGS conftest.$ac_ext >&5'
+ac_link='$F77 -o conftest$ac_exeext $FFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_f77_compiler_gnu
+
+
+archive_cmds_need_lc_F77=no
+allow_undefined_flag_F77=
+always_export_symbols_F77=no
+archive_expsym_cmds_F77=
+export_dynamic_flag_spec_F77=
+hardcode_direct_F77=no
+hardcode_libdir_flag_spec_F77=
+hardcode_libdir_flag_spec_ld_F77=
+hardcode_libdir_separator_F77=
+hardcode_minus_L_F77=no
+hardcode_automatic_F77=no
+module_cmds_F77=
+module_expsym_cmds_F77=
+link_all_deplibs_F77=unknown
+old_archive_cmds_F77=$old_archive_cmds
+no_undefined_flag_F77=
+whole_archive_flag_spec_F77=
+enable_shared_with_static_runtimes_F77=no
+
+# Source file extension for f77 test sources.
+ac_ext=f
+
+# Object file extension for compiled f77 test sources.
+objext=o
+objext_F77=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code=" subroutine t\n return\n end\n"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code=" program t\n end\n"
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+CC=${F77-"f77"}
+compiler=$CC
+compiler_F77=$CC
+cc_basename=`$echo X"$compiler" | $Xsed -e 's%^.*/%%'`
+
+echo "$as_me:$LINENO: checking if libtool supports shared libraries" >&5
+echo $ECHO_N "checking if libtool supports shared libraries... $ECHO_C" >&6
+echo "$as_me:$LINENO: result: $can_build_shared" >&5
+echo "${ECHO_T}$can_build_shared" >&6
+
+echo "$as_me:$LINENO: checking whether to build shared libraries" >&5
+echo $ECHO_N "checking whether to build shared libraries... $ECHO_C" >&6
+test "$can_build_shared" = "no" && enable_shared=no
+
+# On AIX, shared libraries and static libraries use the same namespace, and
+# are all built from PIC.
+case "$host_os" in
+aix3*)
+ test "$enable_shared" = yes && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+aix4* | aix5*)
+ test "$enable_shared" = yes && enable_static=no
+ ;;
+esac
+echo "$as_me:$LINENO: result: $enable_shared" >&5
+echo "${ECHO_T}$enable_shared" >&6
+
+echo "$as_me:$LINENO: checking whether to build static libraries" >&5
+echo $ECHO_N "checking whether to build static libraries... $ECHO_C" >&6
+# Make sure either enable_shared or enable_static is yes.
+test "$enable_shared" = yes || enable_static=yes
+echo "$as_me:$LINENO: result: $enable_static" >&5
+echo "${ECHO_T}$enable_static" >&6
+
+test "$ld_shlibs_F77" = no && can_build_shared=no
+
+GCC_F77="$G77"
+LD_F77="$LD"
+
+lt_prog_compiler_wl_F77=
+lt_prog_compiler_pic_F77=
+lt_prog_compiler_static_F77=
+
+echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5
+echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
+
+ if test "$GCC" = yes; then
+ lt_prog_compiler_wl_F77='-Wl,'
+ lt_prog_compiler_static_F77='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static_F77='-Bstatic'
+ fi
+ ;;
+
+ amigaos*)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the `-m68020' flag to GCC prevents building anything better,
+ # like `-m68040'.
+ lt_prog_compiler_pic_F77='-m68020 -resident32 -malways-restore-a4'
+ ;;
+
+ beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+
+ mingw* | pw32* | os2*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ lt_prog_compiler_pic_F77='-DDLL_EXPORT'
+ ;;
+
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ lt_prog_compiler_pic_F77='-fno-common'
+ ;;
+
+ msdosdjgpp*)
+ # Just because we use GCC doesn't mean we suddenly get shared libraries
+ # on systems that don't support them.
+ lt_prog_compiler_can_build_shared_F77=no
+ enable_shared=no
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ lt_prog_compiler_pic_F77=-Kconform_pic
+ fi
+ ;;
+
+ hpux*)
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case "$host_cpu" in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ lt_prog_compiler_pic_F77='-fPIC'
+ ;;
+ esac
+ ;;
+
+ *)
+ lt_prog_compiler_pic_F77='-fPIC'
+ ;;
+ esac
+ else
+ # PORTME Check for flag to pass linker flags through the system compiler.
+ case $host_os in
+ aix*)
+ lt_prog_compiler_wl_F77='-Wl,'
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static_F77='-Bstatic'
+ else
+ lt_prog_compiler_static_F77='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+
+ mingw* | pw32* | os2*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ lt_prog_compiler_pic_F77='-DDLL_EXPORT'
+ ;;
+
+ hpux9* | hpux10* | hpux11*)
+ lt_prog_compiler_wl_F77='-Wl,'
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case "$host_cpu" in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ lt_prog_compiler_pic_F77='+Z'
+ ;;
+ esac
+ # Is there a better lt_prog_compiler_static that works with the bundled CC?
+ lt_prog_compiler_static_F77='${wl}-a ${wl}archive'
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ lt_prog_compiler_wl_F77='-Wl,'
+ # PIC (with -KPIC) is the default.
+ lt_prog_compiler_static_F77='-non_shared'
+ ;;
+
+ newsos6)
+ lt_prog_compiler_pic_F77='-KPIC'
+ lt_prog_compiler_static_F77='-Bstatic'
+ ;;
+
+ linux*)
+ case $CC in
+ icc* | ecc*)
+ lt_prog_compiler_wl_F77='-Wl,'
+ lt_prog_compiler_pic_F77='-KPIC'
+ lt_prog_compiler_static_F77='-static'
+ ;;
+ ccc*)
+ lt_prog_compiler_wl_F77='-Wl,'
+ # All Alpha code is PIC.
+ lt_prog_compiler_static_F77='-non_shared'
+ ;;
+ esac
+ ;;
+
+ osf3* | osf4* | osf5*)
+ lt_prog_compiler_wl_F77='-Wl,'
+ # All OSF/1 code is PIC.
+ lt_prog_compiler_static_F77='-non_shared'
+ ;;
+
+ sco3.2v5*)
+ lt_prog_compiler_pic_F77='-Kpic'
+ lt_prog_compiler_static_F77='-dn'
+ ;;
+
+ solaris*)
+ lt_prog_compiler_wl_F77='-Wl,'
+ lt_prog_compiler_pic_F77='-KPIC'
+ lt_prog_compiler_static_F77='-Bstatic'
+ ;;
+
+ sunos4*)
+ lt_prog_compiler_wl_F77='-Qoption ld '
+ lt_prog_compiler_pic_F77='-PIC'
+ lt_prog_compiler_static_F77='-Bstatic'
+ ;;
+
+ sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ lt_prog_compiler_wl_F77='-Wl,'
+ lt_prog_compiler_pic_F77='-KPIC'
+ lt_prog_compiler_static_F77='-Bstatic'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec ;then
+ lt_prog_compiler_pic_F77='-Kconform_pic'
+ lt_prog_compiler_static_F77='-Bstatic'
+ fi
+ ;;
+
+ uts4*)
+ lt_prog_compiler_pic_F77='-pic'
+ lt_prog_compiler_static_F77='-Bstatic'
+ ;;
+
+ *)
+ lt_prog_compiler_can_build_shared_F77=no
+ ;;
+ esac
+ fi
+
+echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_F77" >&5
+echo "${ECHO_T}$lt_prog_compiler_pic_F77" >&6
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$lt_prog_compiler_pic_F77"; then
+
+echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic_F77 works" >&5
+echo $ECHO_N "checking if $compiler PIC flag $lt_prog_compiler_pic_F77 works... $ECHO_C" >&6
+if test "${lt_prog_compiler_pic_works_F77+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_prog_compiler_pic_works_F77=no
+ ac_outfile=conftest.$ac_objext
+ printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="$lt_prog_compiler_pic_F77"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:14987: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&5
+ echo "$as_me:14991: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test ! -s conftest.err; then
+ lt_prog_compiler_pic_works_F77=yes
+ fi
+ fi
+ $rm conftest*
+
+fi
+echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_works_F77" >&5
+echo "${ECHO_T}$lt_prog_compiler_pic_works_F77" >&6
+
+if test x"$lt_prog_compiler_pic_works_F77" = xyes; then
+ case $lt_prog_compiler_pic_F77 in
+ "" | " "*) ;;
+ *) lt_prog_compiler_pic_F77=" $lt_prog_compiler_pic_F77" ;;
+ esac
+else
+ lt_prog_compiler_pic_F77=
+ lt_prog_compiler_can_build_shared_F77=no
+fi
+
+fi
+case "$host_os" in
+ # For platforms which do not support PIC, -DPIC is meaningless:
+ *djgpp*)
+ lt_prog_compiler_pic_F77=
+ ;;
+ *)
+ lt_prog_compiler_pic_F77="$lt_prog_compiler_pic_F77"
+ ;;
+esac
+
+echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5
+echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6
+if test "${lt_cv_prog_compiler_c_o_F77+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_cv_prog_compiler_c_o_F77=no
+ $rm -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:15047: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&5
+ echo "$as_me:15051: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test ! -s out/conftest.err; then
+ lt_cv_prog_compiler_c_o_F77=yes
+ fi
+ fi
+ chmod u+w .
+ $rm conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files
+ $rm out/* && rmdir out
+ cd ..
+ rmdir conftest
+ $rm conftest*
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o_F77" >&5
+echo "${ECHO_T}$lt_cv_prog_compiler_c_o_F77" >&6
+
+
+hard_links="nottested"
+if test "$lt_cv_prog_compiler_c_o_F77" = no && test "$need_locks" != no; then
+ # do not overwrite the value of need_locks provided by the user
+ echo "$as_me:$LINENO: checking if we can lock with hard links" >&5
+echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6
+ hard_links=yes
+ $rm conftest*
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ touch conftest.a
+ ln conftest.a conftest.b 2>&5 || hard_links=no
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ echo "$as_me:$LINENO: result: $hard_links" >&5
+echo "${ECHO_T}$hard_links" >&6
+ if test "$hard_links" = no; then
+ { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
+echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
+ need_locks=warn
+ fi
+else
+ need_locks=no
+fi
+
+echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6
+
+ runpath_var=
+ allow_undefined_flag_F77=
+ enable_shared_with_static_runtimes_F77=no
+ archive_cmds_F77=
+ archive_expsym_cmds_F77=
+ old_archive_From_new_cmds_F77=
+ old_archive_from_expsyms_cmds_F77=
+ export_dynamic_flag_spec_F77=
+ whole_archive_flag_spec_F77=
+ thread_safe_flag_spec_F77=
+ hardcode_libdir_flag_spec_F77=
+ hardcode_libdir_flag_spec_ld_F77=
+ hardcode_libdir_separator_F77=
+ hardcode_direct_F77=no
+ hardcode_minus_L_F77=no
+ hardcode_shlibpath_var_F77=unsupported
+ link_all_deplibs_F77=unknown
+ hardcode_automatic_F77=no
+ module_cmds_F77=
+ module_expsym_cmds_F77=
+ always_export_symbols_F77=no
+ export_symbols_cmds_F77='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ # include_expsyms should be a list of space-separated symbols to be *always*
+ # included in the symbol list
+ include_expsyms_F77=
+ # exclude_expsyms can be an extended regexp of symbols to exclude
+ # it will be wrapped by ` (' and `)$', so one must not match beginning or
+ # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+ # as well as any symbol that contains `d'.
+ exclude_expsyms_F77="_GLOBAL_OFFSET_TABLE_"
+ # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+ # platforms (ab)use it in PIC code, but their linkers get confused if
+ # the symbol is explicitly referenced. Since portable code cannot
+ # rely on this symbol name, it's probably fine to never include it in
+ # preloaded symbol tables.
+ extract_expsyms_cmds=
+
+ case $host_os in
+ cygwin* | mingw* | pw32*)
+ # FIXME: the MSVC++ port hasn't been tested in a loooong time
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ if test "$GCC" != yes; then
+ with_gnu_ld=no
+ fi
+ ;;
+ openbsd*)
+ with_gnu_ld=no
+ ;;
+ esac
+
+ ld_shlibs_F77=yes
+ if test "$with_gnu_ld" = yes; then
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ wlarc='${wl}'
+
+ # See if GNU ld supports shared libraries.
+ case $host_os in
+ aix3* | aix4* | aix5*)
+ # On AIX/PPC, the GNU linker is very broken
+ if test "$host_cpu" != ia64; then
+ ld_shlibs_F77=no
+ cat <<EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.9.1, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support. If you
+*** really care for shared libraries, you may want to modify your PATH
+*** so that a non-GNU linker is found, and then restart.
+
+EOF
+ fi
+ ;;
+
+ amigaos*)
+ archive_cmds_F77='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ hardcode_libdir_flag_spec_F77='-L$libdir'
+ hardcode_minus_L_F77=yes
+
+ # Samuel A. Falvo II <kc5tja at dolphin.openprojects.net> reports
+ # that the semantics of dynamic libraries on AmigaOS, at least up
+ # to version 4, is to share data among multiple programs linked
+ # with the same dynamic library. Since this doesn't match the
+ # behavior of shared libraries on other platforms, we can't use
+ # them.
+ ld_shlibs_F77=no
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ allow_undefined_flag_F77=unsupported
+ # Joseph Beckenbach <jrb3 at best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ archive_cmds_F77='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ else
+ ld_shlibs_F77=no
+ fi
+ ;;
+
+ cygwin* | mingw* | pw32*)
+ # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, F77) is actually meaningless,
+ # as there is no search path for DLLs.
+ hardcode_libdir_flag_spec_F77='-L$libdir'
+ allow_undefined_flag_F77=unsupported
+ always_export_symbols_F77=no
+ enable_shared_with_static_runtimes_F77=yes
+ export_symbols_cmds_F77='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGS] /s/.* \([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW] /s/.* //'\'' | sort | uniq > $export_symbols'
+
+ if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
+ archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+ # If the export-symbols file already is a .def file (1st line
+ # is EXPORTS), use it as is; otherwise, prepend...
+ archive_expsym_cmds_F77='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+ archive_cmds_F77='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+ wlarc=
+ else
+ archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ fi
+ ;;
+
+ solaris* | sysv5*)
+ if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then
+ ld_shlibs_F77=no
+ cat <<EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+EOF
+ elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs_F77=no
+ fi
+ ;;
+
+ sunos4*)
+ archive_cmds_F77='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ wlarc=
+ hardcode_direct_F77=yes
+ hardcode_shlibpath_var_F77=no
+ ;;
+
+ linux*)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ tmp_archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_cmds_F77="$tmp_archive_cmds"
+ supports_anon_versioning=no
+ case `$LD -v 2>/dev/null` in
+ *\ 01.* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
+ *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+ *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+ *\ 2.11.*) ;; # other 2.11 versions
+ *) supports_anon_versioning=yes ;;
+ esac
+ if test $supports_anon_versioning = yes; then
+ archive_expsym_cmds_F77='$echo "{ global:" > $output_objdir/$libname.ver~
+cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+$echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ else
+ archive_expsym_cmds_F77="$tmp_archive_cmds"
+ fi
+ else
+ ld_shlibs_F77=no
+ fi
+ ;;
+
+ *)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs_F77=no
+ fi
+ ;;
+ esac
+
+ if test "$ld_shlibs_F77" = yes; then
+ runpath_var=LD_RUN_PATH
+ hardcode_libdir_flag_spec_F77='${wl}--rpath ${wl}$libdir'
+ export_dynamic_flag_spec_F77='${wl}--export-dynamic'
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then
+ whole_archive_flag_spec_F77="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ whole_archive_flag_spec_F77=
+ fi
+ fi
+ else
+ # PORTME fill in a description of your system's linker (not GNU ld)
+ case $host_os in
+ aix3*)
+ allow_undefined_flag_F77=unsupported
+ always_export_symbols_F77=yes
+ archive_expsym_cmds_F77='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+ # Note: this linker hardcodes the directories in LIBPATH if there
+ # are no directories specified by -L.
+ hardcode_minus_L_F77=yes
+ if test "$GCC" = yes && test -z "$link_static_flag"; then
+ # Neither direct hardcoding nor static linking is supported with a
+ # broken collect2.
+ hardcode_direct_F77=unsupported
+ fi
+ ;;
+
+ aix4* | aix5*)
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=""
+ else
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to AIX nm, but means don't demangle with GNU nm
+ if $NM -V 2>&1 | grep 'GNU' > /dev/null; then
+ export_symbols_cmds_F77='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols'
+ else
+ export_symbols_cmds_F77='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols'
+ fi
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # need to do runtime linking.
+ case $host_os in aix4.[23]|aix4.[23].*|aix5*)
+ for ld_flag in $LDFLAGS; do
+ if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+ aix_use_runtimelinking=yes
+ break
+ fi
+ done
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ archive_cmds_F77=''
+ hardcode_direct_F77=yes
+ hardcode_libdir_separator_F77=':'
+ link_all_deplibs_F77=yes
+
+ if test "$GCC" = yes; then
+ case $host_os in aix4.012|aix4.012.*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" && \
+ strings "$collect2name" | grep resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ hardcode_direct_F77=yes
+ else
+ # We have old collect2
+ hardcode_direct_F77=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ hardcode_minus_L_F77=yes
+ hardcode_libdir_flag_spec_F77='-L$libdir'
+ hardcode_libdir_separator_F77=
+ fi
+ esac
+ shared_flag='-shared'
+ else
+ # not using gcc
+ if test "$host_cpu" = ia64; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag='${wl}-G'
+ else
+ shared_flag='${wl}-bM:SRE'
+ fi
+ fi
+ fi
+
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to export.
+ always_export_symbols_F77=yes
+ if test "$aix_use_runtimelinking" = yes; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ allow_undefined_flag_F77='-berok'
+ # Determine the default libpath from the value encoded in an empty executable.
+ cat >conftest.$ac_ext <<_ACEOF
+ program main
+
+ end
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_f77_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
+}'`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
+}'`; fi
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+ hardcode_libdir_flag_spec_F77='${wl}-blibpath:$libdir:'"$aix_libpath"
+ archive_expsym_cmds_F77="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ else
+ if test "$host_cpu" = ia64; then
+ hardcode_libdir_flag_spec_F77='${wl}-R $libdir:/usr/lib:/lib'
+ allow_undefined_flag_F77="-z nodefs"
+ archive_expsym_cmds_F77="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an empty executable.
+ cat >conftest.$ac_ext <<_ACEOF
+ program main
+
+ end
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_f77_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
+}'`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
+}'`; fi
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+ hardcode_libdir_flag_spec_F77='${wl}-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ no_undefined_flag_F77=' ${wl}-bernotok'
+ allow_undefined_flag_F77=' ${wl}-berok'
+ # -bexpall does not export symbols beginning with underscore (_)
+ always_export_symbols_F77=yes
+ # Exported symbols can be pulled into shared objects from archives
+ whole_archive_flag_spec_F77=' '
+ archive_cmds_need_lc_F77=yes
+ # This is similar to how AIX traditionally builds it's shared libraries.
+ archive_expsym_cmds_F77="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ fi
+ fi
+ ;;
+
+ amigaos*)
+ archive_cmds_F77='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ hardcode_libdir_flag_spec_F77='-L$libdir'
+ hardcode_minus_L_F77=yes
+ # see comment about different semantics on the GNU ld section
+ ld_shlibs_F77=no
+ ;;
+
+ bsdi4*)
+ export_dynamic_flag_spec_F77=-rdynamic
+ ;;
+
+ cygwin* | mingw* | pw32*)
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ hardcode_libdir_flag_spec_F77=' '
+ allow_undefined_flag_F77=unsupported
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=".dll"
+ # FIXME: Setting linknames here is a bad hack.
+ archive_cmds_F77='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames='
+ # The linker will automatically build a .lib file if we build a DLL.
+ old_archive_From_new_cmds_F77='true'
+ # FIXME: Should let the user specify the lib program.
+ old_archive_cmds_F77='lib /OUT:$oldlib$oldobjs$old_deplibs'
+ fix_srcfile_path='`cygpath -w "$srcfile"`'
+ enable_shared_with_static_runtimes_F77=yes
+ ;;
+
+ darwin* | rhapsody*)
+ if test "$GXX" = yes ; then
+ archive_cmds_need_lc_F77=no
+ case "$host_os" in
+ rhapsody* | darwin1.[012])
+ allow_undefined_flag_F77='-undefined suppress'
+ ;;
+ *) # Darwin 1.3 on
+ if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
+ allow_undefined_flag_F77='-flat_namespace -undefined suppress'
+ else
+ case ${MACOSX_DEPLOYMENT_TARGET} in
+ 10.[012])
+ allow_undefined_flag_F77='-flat_namespace -undefined suppress'
+ ;;
+ 10.*)
+ allow_undefined_flag_F77='-undefined dynamic_lookup'
+ ;;
+ esac
+ fi
+ ;;
+ esac
+ lt_int_apple_cc_single_mod=no
+ output_verbose_link_cmd='echo'
+ if $CC -dumpspecs 2>&1 | grep 'single_module' >/dev/null ; then
+ lt_int_apple_cc_single_mod=yes
+ fi
+ if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
+ archive_cmds_F77='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+ else
+ archive_cmds_F77='$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+ fi
+ module_cmds_F77='$CC ${wl}-bind_at_load $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+ # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's
+ if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
+ archive_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ else
+ archive_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ fi
+ module_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ hardcode_direct_F77=no
+ hardcode_automatic_F77=yes
+ hardcode_shlibpath_var_F77=unsupported
+ whole_archive_flag_spec_F77='-all_load $convenience'
+ link_all_deplibs_F77=yes
+ else
+ ld_shlibs_F77=no
+ fi
+ ;;
+
+ dgux*)
+ archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec_F77='-L$libdir'
+ hardcode_shlibpath_var_F77=no
+ ;;
+
+ freebsd1*)
+ ld_shlibs_F77=no
+ ;;
+
+ # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+ # support. Future versions do this automatically, but an explicit c++rt0.o
+ # does not break anything, and helps significantly (at the cost of a little
+ # extra space).
+ freebsd2.2*)
+ archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+ hardcode_libdir_flag_spec_F77='-R$libdir'
+ hardcode_direct_F77=yes
+ hardcode_shlibpath_var_F77=no
+ ;;
+
+ # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+ freebsd2*)
+ archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct_F77=yes
+ hardcode_minus_L_F77=yes
+ hardcode_shlibpath_var_F77=no
+ ;;
+
+ # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+ freebsd* | kfreebsd*-gnu)
+ archive_cmds_F77='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
+ hardcode_libdir_flag_spec_F77='-R$libdir'
+ hardcode_direct_F77=yes
+ hardcode_shlibpath_var_F77=no
+ ;;
+
+ hpux9*)
+ if test "$GCC" = yes; then
+ archive_cmds_F77='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ else
+ archive_cmds_F77='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ fi
+ hardcode_libdir_flag_spec_F77='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator_F77=:
+ hardcode_direct_F77=yes
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L_F77=yes
+ export_dynamic_flag_spec_F77='${wl}-E'
+ ;;
+
+ hpux10* | hpux11*)
+ if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+ case "$host_cpu" in
+ hppa*64*|ia64*)
+ archive_cmds_F77='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ archive_cmds_F77='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ else
+ case "$host_cpu" in
+ hppa*64*|ia64*)
+ archive_cmds_F77='$LD -b +h $soname -o $lib $libobjs $deplibs $linker_flags'
+ ;;
+ *)
+ archive_cmds_F77='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+ ;;
+ esac
+ fi
+ if test "$with_gnu_ld" = no; then
+ case "$host_cpu" in
+ hppa*64*)
+ hardcode_libdir_flag_spec_F77='${wl}+b ${wl}$libdir'
+ hardcode_libdir_flag_spec_ld_F77='+b $libdir'
+ hardcode_libdir_separator_F77=:
+ hardcode_direct_F77=no
+ hardcode_shlibpath_var_F77=no
+ ;;
+ ia64*)
+ hardcode_libdir_flag_spec_F77='-L$libdir'
+ hardcode_direct_F77=no
+ hardcode_shlibpath_var_F77=no
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L_F77=yes
+ ;;
+ *)
+ hardcode_libdir_flag_spec_F77='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator_F77=:
+ hardcode_direct_F77=yes
+ export_dynamic_flag_spec_F77='${wl}-E'
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L_F77=yes
+ ;;
+ esac
+ fi
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ if test "$GCC" = yes; then
+ archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ archive_cmds_F77='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+ hardcode_libdir_flag_spec_ld_F77='-rpath $libdir'
+ fi
+ hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator_F77=:
+ link_all_deplibs_F77=yes
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+ archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
+ else
+ archive_cmds_F77='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF
+ fi
+ hardcode_libdir_flag_spec_F77='-R$libdir'
+ hardcode_direct_F77=yes
+ hardcode_shlibpath_var_F77=no
+ ;;
+
+ newsos6)
+ archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct_F77=yes
+ hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator_F77=:
+ hardcode_shlibpath_var_F77=no
+ ;;
+
+ openbsd*)
+ hardcode_direct_F77=yes
+ hardcode_shlibpath_var_F77=no
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ archive_cmds_F77='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ hardcode_libdir_flag_spec_F77='${wl}-rpath,$libdir'
+ export_dynamic_flag_spec_F77='${wl}-E'
+ else
+ case $host_os in
+ openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
+ archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec_F77='-R$libdir'
+ ;;
+ *)
+ archive_cmds_F77='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ hardcode_libdir_flag_spec_F77='${wl}-rpath,$libdir'
+ ;;
+ esac
+ fi
+ ;;
+
+ os2*)
+ hardcode_libdir_flag_spec_F77='-L$libdir'
+ hardcode_minus_L_F77=yes
+ allow_undefined_flag_F77=unsupported
+ archive_cmds_F77='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+ old_archive_From_new_cmds_F77='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+ ;;
+
+ osf3*)
+ if test "$GCC" = yes; then
+ allow_undefined_flag_F77=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds_F77='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ allow_undefined_flag_F77=' -expect_unresolved \*'
+ archive_cmds_F77='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+ fi
+ hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator_F77=:
+ ;;
+
+ osf4* | osf5*) # as osf3* with the addition of -msym flag
+ if test "$GCC" = yes; then
+ allow_undefined_flag_F77=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds_F77='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir'
+ else
+ allow_undefined_flag_F77=' -expect_unresolved \*'
+ archive_cmds_F77='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+ archive_expsym_cmds_F77='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~
+ $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib~$rm $lib.exp'
+
+ # Both c and cxx compiler support -rpath directly
+ hardcode_libdir_flag_spec_F77='-rpath $libdir'
+ fi
+ hardcode_libdir_separator_F77=:
+ ;;
+
+ sco3.2v5*)
+ archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var_F77=no
+ export_dynamic_flag_spec_F77='${wl}-Bexport'
+ runpath_var=LD_RUN_PATH
+ hardcode_runpath_var=yes
+ ;;
+
+ solaris*)
+ no_undefined_flag_F77=' -z text'
+ if test "$GCC" = yes; then
+ archive_cmds_F77='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_F77='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp'
+ else
+ archive_cmds_F77='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ archive_expsym_cmds_F77='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
+ fi
+ hardcode_libdir_flag_spec_F77='-R$libdir'
+ hardcode_shlibpath_var_F77=no
+ case $host_os in
+ solaris2.[0-5] | solaris2.[0-5].*) ;;
+ *) # Supported since Solaris 2.6 (maybe 2.5.1?)
+ whole_archive_flag_spec_F77='-z allextract$convenience -z defaultextract' ;;
+ esac
+ link_all_deplibs_F77=yes
+ ;;
+
+ sunos4*)
+ if test "x$host_vendor" = xsequent; then
+ # Use $CC to link under sequent, because it throws in some extra .o
+ # files that make .init and .fini sections work.
+ archive_cmds_F77='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds_F77='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ hardcode_libdir_flag_spec_F77='-L$libdir'
+ hardcode_direct_F77=yes
+ hardcode_minus_L_F77=yes
+ hardcode_shlibpath_var_F77=no
+ ;;
+
+ sysv4)
+ case $host_vendor in
+ sni)
+ archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct_F77=yes # is this really true???
+ ;;
+ siemens)
+ ## LD is ld it makes a PLAMLIB
+ ## CC just makes a GrossModule.
+ archive_cmds_F77='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+ reload_cmds_F77='$CC -r -o $output$reload_objs'
+ hardcode_direct_F77=no
+ ;;
+ motorola)
+ archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct_F77=no #Motorola manual says yes, but my tests say they lie
+ ;;
+ esac
+ runpath_var='LD_RUN_PATH'
+ hardcode_shlibpath_var_F77=no
+ ;;
+
+ sysv4.3*)
+ archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var_F77=no
+ export_dynamic_flag_spec_F77='-Bexport'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var_F77=no
+ runpath_var=LD_RUN_PATH
+ hardcode_runpath_var=yes
+ ld_shlibs_F77=yes
+ fi
+ ;;
+
+ sysv4.2uw2*)
+ archive_cmds_F77='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct_F77=yes
+ hardcode_minus_L_F77=no
+ hardcode_shlibpath_var_F77=no
+ hardcode_runpath_var=yes
+ runpath_var=LD_RUN_PATH
+ ;;
+
+ sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[78]* | unixware7*)
+ no_undefined_flag_F77='${wl}-z ${wl}text'
+ if test "$GCC" = yes; then
+ archive_cmds_F77='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds_F77='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ runpath_var='LD_RUN_PATH'
+ hardcode_shlibpath_var_F77=no
+ ;;
+
+ sysv5*)
+ no_undefined_flag_F77=' -z text'
+ # $CC -shared without GNU ld will not create a library from C++
+ # object files and a static libstdc++, better avoid it by now
+ archive_cmds_F77='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ archive_expsym_cmds_F77='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
+ hardcode_libdir_flag_spec_F77=
+ hardcode_shlibpath_var_F77=no
+ runpath_var='LD_RUN_PATH'
+ ;;
+
+ uts4*)
+ archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec_F77='-L$libdir'
+ hardcode_shlibpath_var_F77=no
+ ;;
+
+ *)
+ ld_shlibs_F77=no
+ ;;
+ esac
+ fi
+
+echo "$as_me:$LINENO: result: $ld_shlibs_F77" >&5
+echo "${ECHO_T}$ld_shlibs_F77" >&6
+test "$ld_shlibs_F77" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+ variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$archive_cmds_need_lc_F77" in
+x|xyes)
+ # Assume -lc should be added
+ archive_cmds_need_lc_F77=yes
+
+ if test "$enable_shared" = yes && test "$GCC" = yes; then
+ case $archive_cmds_F77 in
+ *'~'*)
+ # FIXME: we may have to deal with multi-command sequences.
+ ;;
+ '$CC '*)
+ # Test whether the compiler implicitly links with -lc since on some
+ # systems, -lgcc has to come before -lc. If gcc already passes -lc
+ # to ld, don't add -lc before -lgcc.
+ echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5
+echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6
+ $rm conftest*
+ printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } 2>conftest.err; then
+ soname=conftest
+ lib=conftest
+ libobjs=conftest.$ac_objext
+ deplibs=
+ wl=$lt_prog_compiler_wl_F77
+ compiler_flags=-v
+ linker_flags=-v
+ verstring=
+ output_objdir=.
+ libname=conftest
+ lt_save_allow_undefined_flag=$allow_undefined_flag_F77
+ allow_undefined_flag_F77=
+ if { (eval echo "$as_me:$LINENO: \"$archive_cmds_F77 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5
+ (eval $archive_cmds_F77 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+ then
+ archive_cmds_need_lc_F77=no
+ else
+ archive_cmds_need_lc_F77=yes
+ fi
+ allow_undefined_flag_F77=$lt_save_allow_undefined_flag
+ else
+ cat conftest.err 1>&5
+ fi
+ $rm conftest*
+ echo "$as_me:$LINENO: result: $archive_cmds_need_lc_F77" >&5
+echo "${ECHO_T}$archive_cmds_need_lc_F77" >&6
+ ;;
+ esac
+ fi
+ ;;
+esac
+
+echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5
+echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+if test "$GCC" = yes; then
+ sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+ if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then
+ # if the path contains ";" then we assume it to be the separator
+ # otherwise default to the standard path separator (i.e. ":") - it is
+ # assumed that no part of a normal pathname contains ";" but that should
+ # okay in the real world where ";" in dirpaths is itself problematic.
+ sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+ else
+ sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ fi
+else
+ sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+ shlibpath_var=LIBPATH
+
+ # AIX 3 has no versioning support, so we append a major version to the name.
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+
+aix4* | aix5*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ hardcode_into_libs=yes
+ if test "$host_cpu" = ia64; then
+ # AIX 5 supports IA64
+ library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ else
+ # With GCC up to 2.95.x, collect2 would create an import file
+ # for dependence libraries. The import file would start with
+ # the line `#! .'. This would cause the generated library to
+ # depend on `.', always an invalid library. This was fixed in
+ # development snapshots of GCC prior to 3.0.
+ case $host_os in
+ aix4 | aix4.[01] | aix4.[01].*)
+ if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+ echo ' yes '
+ echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then
+ :
+ else
+ can_build_shared=no
+ fi
+ ;;
+ esac
+ # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+ # soname into executable. Probably we can add versioning support to
+ # collect2, so additional links can be useful in future.
+ if test "$aix_use_runtimelinking" = yes; then
+ # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+ # instead of lib<name>.a to let people know that these are not
+ # typical AIX shared libraries.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ else
+ # We preserve .a as extension for shared libraries through AIX4.2
+ # and later when we are not doing run time linking.
+ library_names_spec='${libname}${release}.a $libname.a'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ fi
+ shlibpath_var=LIBPATH
+ fi
+ ;;
+
+amigaos*)
+ library_names_spec='$libname.ixlibrary $libname.a'
+ # Create ${libname}_ixlibrary.a entries in /sys/libs.
+ finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+ ;;
+
+beos*)
+ library_names_spec='${libname}${shared_ext}'
+ dynamic_linker="$host_os ld.so"
+ shlibpath_var=LIBRARY_PATH
+ ;;
+
+bsdi4*)
+ version_type=linux
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+ # the default ld.so.conf also contains /usr/contrib/lib and
+ # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+ # libtool to hard-code these into programs
+ ;;
+
+cygwin* | mingw* | pw32*)
+ version_type=windows
+ shrext_cmds=".dll"
+ need_version=no
+ need_lib_prefix=no
+
+ case $GCC,$host_os in
+ yes,cygwin* | yes,mingw* | yes,pw32*)
+ library_names_spec='$libname.dll.a'
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \${file}`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $rm \$dlpath'
+ shlibpath_overrides_runpath=yes
+
+ case $host_os in
+ cygwin*)
+ # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+ soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib"
+ ;;
+ mingw*)
+ # MinGW DLLs use traditional 'lib' prefix
+ soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+ if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then
+ # It is most probably a Windows format PATH printed by
+ # mingw gcc, but we are running on Cygwin. Gcc prints its search
+ # path with ; separators, and with drive letters. We can handle the
+ # drive letters (cygwin fileutils understands them), so leave them,
+ # especially as we might pass files found there to a mingw objdump,
+ # which wouldn't understand a cygwinified path. Ahh.
+ sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+ else
+ sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ fi
+ ;;
+ pw32*)
+ # pw32 DLLs use 'pw' prefix rather than 'lib'
+ library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/./-/g'`${versuffix}${shared_ext}'
+ ;;
+ esac
+ ;;
+
+ *)
+ library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
+ ;;
+ esac
+ dynamic_linker='Win32 ld.exe'
+ # FIXME: first we should search . and the directory the executable is in
+ shlibpath_var=PATH
+ ;;
+
+darwin* | rhapsody*)
+ dynamic_linker="$host_os dyld"
+ version_type=darwin
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+ soname_spec='${libname}${release}${major}$shared_ext'
+ shlibpath_overrides_runpath=yes
+ shlibpath_var=DYLD_LIBRARY_PATH
+ shrext_cmds='$(test .$module = .yes && echo .so || echo .dylib)'
+ # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same.
+ if test "$GCC" = yes; then
+ sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"`
+ else
+ sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib'
+ fi
+ sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+ ;;
+
+dgux*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+freebsd1*)
+ dynamic_linker=no
+ ;;
+
+kfreebsd*-gnu)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='GNU ld.so'
+ ;;
+
+freebsd*)
+ objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout`
+ version_type=freebsd-$objformat
+ case $version_type in
+ freebsd-elf*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ need_version=no
+ need_lib_prefix=no
+ ;;
+ freebsd-*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+ need_version=yes
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_os in
+ freebsd2*)
+ shlibpath_overrides_runpath=yes
+ ;;
+ freebsd3.01* | freebsdelf3.01*)
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ *) # from 3.2 on
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+ esac
+ ;;
+
+gnu*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ hardcode_into_libs=yes
+ ;;
+
+hpux9* | hpux10* | hpux11*)
+ # Give a soname corresponding to the major version so that dld.sl refuses to
+ # link against other versions.
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ case "$host_cpu" in
+ ia64*)
+ shrext_cmds='.so'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ if test "X$HPUX_IA64_MODE" = X32; then
+ sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+ else
+ sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+ fi
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ hppa*64*)
+ shrext_cmds='.sl'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ *)
+ shrext_cmds='.sl'
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=SHLIB_PATH
+ shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+ esac
+ # HP-UX runs *really* slowly unless shared libraries are mode 555.
+ postinstall_cmds='chmod 555 $lib'
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $host_os in
+ nonstopux*) version_type=nonstopux ;;
+ *)
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ version_type=linux
+ else
+ version_type=irix
+ fi ;;
+ esac
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+ case $host_os in
+ irix5* | nonstopux*)
+ libsuff= shlibsuff=
+ ;;
+ *)
+ case $LD in # libtool.m4 will add one of these switches to LD
+ *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+ libsuff= shlibsuff= libmagic=32-bit;;
+ *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+ libsuff=32 shlibsuff=N32 libmagic=N32;;
+ *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+ libsuff=64 shlibsuff=64 libmagic=64-bit;;
+ *) libsuff= shlibsuff= libmagic=never-match;;
+ esac
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+ sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+ hardcode_into_libs=yes
+ ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+ dynamic_linker=no
+ ;;
+
+# This must be Linux ELF.
+linux*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ # This implies no fast_install, which is unacceptable.
+ # Some rework will be needed to allow for fast_install
+ # before this can be enabled.
+ hardcode_into_libs=yes
+
+ # find out which ABI we are using
+ libsuff=
+ case "$host_cpu" in
+ x86_64*|s390x*|powerpc64*)
+ echo '#line 16361 "configure"' > conftest.$ac_ext
+ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *64-bit*)
+ libsuff=64
+ sys_lib_search_path_spec="/lib${libsuff} /usr/lib${libsuff} /usr/local/lib${libsuff}"
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+ esac
+
+ # Append ld.so.conf contents to the search path
+ if test -f /etc/ld.so.conf; then
+ lt_ld_extra=`$SED -e 's/:,\t/ /g;s/=^=*$//;s/=^= * / /g' /etc/ld.so.conf | tr '\n' ' '`
+ sys_lib_dlsearch_path_spec="/lib${libsuff} /usr/lib${libsuff} $lt_ld_extra"
+ fi
+
+ # We used to test for /lib/ld.so.1 and disable shared libraries on
+ # powerpc, because MkLinux only supported shared libraries with the
+ # GNU dynamic linker. Since this was broken with cross compilers,
+ # most powerpc-linux boxes support dynamic linking these days and
+ # people can always --disable-shared, the test was removed, and we
+ # assume the GNU/Linux dynamic linker is in use.
+ dynamic_linker='GNU/Linux ld.so'
+ ;;
+
+knetbsd*-gnu)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='GNU ld.so'
+ ;;
+
+netbsd*)
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ dynamic_linker='NetBSD (a.out) ld.so'
+ else
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='NetBSD ld.elf_so'
+ fi
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+
+newsos6)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+nto-qnx*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+openbsd*)
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=yes
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ case $host_os in
+ openbsd2.[89] | openbsd2.[89].*)
+ shlibpath_overrides_runpath=no
+ ;;
+ *)
+ shlibpath_overrides_runpath=yes
+ ;;
+ esac
+ else
+ shlibpath_overrides_runpath=yes
+ fi
+ ;;
+
+os2*)
+ libname_spec='$name'
+ shrext_cmds=".dll"
+ need_lib_prefix=no
+ library_names_spec='$libname${shared_ext} $libname.a'
+ dynamic_linker='OS/2 ld.exe'
+ shlibpath_var=LIBPATH
+ ;;
+
+osf3* | osf4* | osf5*)
+ version_type=osf
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+ sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+ ;;
+
+sco3.2v5*)
+ version_type=osf
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+solaris*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ # ldd complains unless libraries are executable
+ postinstall_cmds='chmod +x $lib'
+ ;;
+
+sunos4*)
+ version_type=sunos
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ if test "$with_gnu_ld" = yes; then
+ need_lib_prefix=no
+ fi
+ need_version=yes
+ ;;
+
+sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_vendor in
+ sni)
+ shlibpath_overrides_runpath=no
+ need_lib_prefix=no
+ export_dynamic_flag_spec='${wl}-Blargedynsym'
+ runpath_var=LD_RUN_PATH
+ ;;
+ siemens)
+ need_lib_prefix=no
+ ;;
+ motorola)
+ need_lib_prefix=no
+ need_version=no
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+ ;;
+ esac
+ ;;
+
+sysv4*MP*)
+ if test -d /usr/nec ;then
+ version_type=linux
+ library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+ soname_spec='$libname${shared_ext}.$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ fi
+ ;;
+
+uts4*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+*)
+ dynamic_linker=no
+ ;;
+esac
+echo "$as_me:$LINENO: result: $dynamic_linker" >&5
+echo "${ECHO_T}$dynamic_linker" >&6
+test "$dynamic_linker" = no && can_build_shared=no
+
+echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5
+echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6
+hardcode_action_F77=
+if test -n "$hardcode_libdir_flag_spec_F77" || \
+ test -n "$runpath_var F77" || \
+ test "X$hardcode_automatic_F77"="Xyes" ; then
+
+ # We can hardcode non-existant directories.
+ if test "$hardcode_direct_F77" != no &&
+ # If the only mechanism to avoid hardcoding is shlibpath_var, we
+ # have to relink, otherwise we might link with an installed library
+ # when we should be linking with a yet-to-be-installed one
+ ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, F77)" != no &&
+ test "$hardcode_minus_L_F77" != no; then
+ # Linking always hardcodes the temporary library directory.
+ hardcode_action_F77=relink
+ else
+ # We can link without hardcoding, and we can hardcode nonexisting dirs.
+ hardcode_action_F77=immediate
+ fi
+else
+ # We cannot hardcode anything, or else we can only hardcode existing
+ # directories.
+ hardcode_action_F77=unsupported
+fi
+echo "$as_me:$LINENO: result: $hardcode_action_F77" >&5
+echo "${ECHO_T}$hardcode_action_F77" >&6
+
+if test "$hardcode_action_F77" = relink; then
+ # Fast installation is not supported
+ enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+ test "$enable_shared" = no; then
+ # Fast installation is not necessary
+ enable_fast_install=needless
+fi
+
+striplib=
+old_striplib=
+echo "$as_me:$LINENO: checking whether stripping libraries is possible" >&5
+echo $ECHO_N "checking whether stripping libraries is possible... $ECHO_C" >&6
+if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then
+ test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+ test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+ case $host_os in
+ darwin*)
+ if test -n "$STRIP" ; then
+ striplib="$STRIP -x"
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+ ;;
+ *)
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ ;;
+ esac
+fi
+
+
+
+# The else clause should only fire when bootstrapping the
+# libtool distribution, otherwise you forgot to ship ltmain.sh
+# with your package, and you will get complaints that there are
+# no rules to generate ltmain.sh.
+if test -f "$ltmain"; then
+ # See if we are running on zsh, and set the options which allow our commands through
+ # without removal of \ escapes.
+ if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+ fi
+ # Now quote all the things that may contain metacharacters while being
+ # careful not to overquote the AC_SUBSTed values. We take copies of the
+ # variables and quote the copies for generation of the libtool script.
+ for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC NM \
+ SED SHELL STRIP \
+ libname_spec library_names_spec soname_spec extract_expsyms_cmds \
+ old_striplib striplib file_magic_cmd finish_cmds finish_eval \
+ deplibs_check_method reload_flag reload_cmds need_locks \
+ lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \
+ lt_cv_sys_global_symbol_to_c_name_address \
+ sys_lib_search_path_spec sys_lib_dlsearch_path_spec \
+ old_postinstall_cmds old_postuninstall_cmds \
+ compiler_F77 \
+ CC_F77 \
+ LD_F77 \
+ lt_prog_compiler_wl_F77 \
+ lt_prog_compiler_pic_F77 \
+ lt_prog_compiler_static_F77 \
+ lt_prog_compiler_no_builtin_flag_F77 \
+ export_dynamic_flag_spec_F77 \
+ thread_safe_flag_spec_F77 \
+ whole_archive_flag_spec_F77 \
+ enable_shared_with_static_runtimes_F77 \
+ old_archive_cmds_F77 \
+ old_archive_from_new_cmds_F77 \
+ predep_objects_F77 \
+ postdep_objects_F77 \
+ predeps_F77 \
+ postdeps_F77 \
+ compiler_lib_search_path_F77 \
+ archive_cmds_F77 \
+ archive_expsym_cmds_F77 \
+ postinstall_cmds_F77 \
+ postuninstall_cmds_F77 \
+ old_archive_from_expsyms_cmds_F77 \
+ allow_undefined_flag_F77 \
+ no_undefined_flag_F77 \
+ export_symbols_cmds_F77 \
+ hardcode_libdir_flag_spec_F77 \
+ hardcode_libdir_flag_spec_ld_F77 \
+ hardcode_libdir_separator_F77 \
+ hardcode_automatic_F77 \
+ module_cmds_F77 \
+ module_expsym_cmds_F77 \
+ lt_cv_prog_compiler_c_o_F77 \
+ exclude_expsyms_F77 \
+ include_expsyms_F77; do
+
+ case $var in
+ old_archive_cmds_F77 | \
+ old_archive_from_new_cmds_F77 | \
+ archive_cmds_F77 | \
+ archive_expsym_cmds_F77 | \
+ module_cmds_F77 | \
+ module_expsym_cmds_F77 | \
+ old_archive_from_expsyms_cmds_F77 | \
+ export_symbols_cmds_F77 | \
+ extract_expsyms_cmds | reload_cmds | finish_cmds | \
+ postinstall_cmds | postuninstall_cmds | \
+ old_postinstall_cmds | old_postuninstall_cmds | \
+ sys_lib_search_path_spec | sys_lib_dlsearch_path_spec)
+ # Double-quote double-evaled strings.
+ eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\""
+ ;;
+ *)
+ eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\""
+ ;;
+ esac
+ done
+
+ case $lt_echo in
+ *'\$0 --fallback-echo"')
+ lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'`
+ ;;
+ esac
+
+cfgfile="$ofile"
+
+ cat <<__EOF__ >> "$cfgfile"
+# ### BEGIN LIBTOOL TAG CONFIG: $tagname
+
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+
+# Shell to use when invoking shell scripts.
+SHELL=$lt_SHELL
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc_F77
+
+# Whether or not to disallow shared libs when runtime libs are static
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_F77
+
+# Whether or not to optimize for fast installation.
+fast_install=$enable_fast_install
+
+# The host system.
+host_alias=$host_alias
+host=$host
+
+# An echo program that does not interpret backslashes.
+echo=$lt_echo
+
+# The archiver.
+AR=$lt_AR
+AR_FLAGS=$lt_AR_FLAGS
+
+# A C compiler.
+LTCC=$lt_LTCC
+
+# A language-specific compiler.
+CC=$lt_compiler_F77
+
+# Is the compiler the GNU C compiler?
+with_gcc=$GCC_F77
+
+# An ERE matcher.
+EGREP=$lt_EGREP
+
+# The linker used to build libraries.
+LD=$lt_LD_F77
+
+# Whether we need hard or soft links.
+LN_S=$lt_LN_S
+
+# A BSD-compatible nm program.
+NM=$lt_NM
+
+# A symbol stripping program
+STRIP=$lt_STRIP
+
+# Used to examine libraries when file_magic_cmd begins "file"
+MAGIC_CMD=$MAGIC_CMD
+
+# Used on cygwin: DLL creation program.
+DLLTOOL="$DLLTOOL"
+
+# Used on cygwin: object dumper.
+OBJDUMP="$OBJDUMP"
+
+# Used on cygwin: assembler.
+AS="$AS"
+
+# The name of the directory that contains temporary libtool files.
+objdir=$objdir
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag
+reload_cmds=$lt_reload_cmds
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl_F77
+
+# Object file suffix (normally "o").
+objext="$ac_objext"
+
+# Old archive suffix (normally "a").
+libext="$libext"
+
+# Shared library suffix (normally ".so").
+shrext_cmds='$shrext_cmds'
+
+# Executable file suffix (normally "").
+exeext="$exeext"
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic_F77
+pic_mode=$pic_mode
+
+# What is the maximum length of a command?
+max_cmd_len=$lt_cv_sys_max_cmd_len
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o_F77
+
+# Must we lock files when doing compilation ?
+need_locks=$lt_need_locks
+
+# Do we need the lib prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Whether dlopen is supported.
+dlopen_support=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static_F77
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_F77
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_F77
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec_F77
+
+# Compiler flag to generate thread-safe objects.
+thread_safe_flag_spec=$lt_thread_safe_flag_spec_F77
+
+# Library versioning type.
+version_type=$version_type
+
+# Format of library name prefix.
+libname_spec=$lt_libname_spec
+
+# List of archive names. First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME.
+library_names_spec=$lt_library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$lt_soname_spec
+
+# Commands used to build and install an old-style archive.
+RANLIB=$lt_RANLIB
+old_archive_cmds=$lt_old_archive_cmds_F77
+old_postinstall_cmds=$lt_old_postinstall_cmds
+old_postuninstall_cmds=$lt_old_postuninstall_cmds
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_F77
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_F77
+
+# Commands used to build and install a shared archive.
+archive_cmds=$lt_archive_cmds_F77
+archive_expsym_cmds=$lt_archive_expsym_cmds_F77
+postinstall_cmds=$lt_postinstall_cmds
+postuninstall_cmds=$lt_postuninstall_cmds
+
+# Commands used to build a loadable module (assumed same as above if empty)
+module_cmds=$lt_module_cmds_F77
+module_expsym_cmds=$lt_module_expsym_cmds_F77
+
+# Commands to strip libraries.
+old_striplib=$lt_old_striplib
+striplib=$lt_striplib
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predep_objects=$lt_predep_objects_F77
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdep_objects=$lt_postdep_objects_F77
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predeps=$lt_predeps_F77
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdeps=$lt_postdeps_F77
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path=$lt_compiler_lib_search_path_F77
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$lt_deplibs_check_method
+
+# Command to use when deplibs_check_method == file_magic.
+file_magic_cmd=$lt_file_magic_cmd
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag_F77
+
+# Flag that forces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag_F77
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$lt_finish_cmds
+
+# Same as above, but a single script fragment to be evaled but not shown.
+finish_eval=$lt_finish_eval
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration
+global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
+
+# Transform the output of nm in a C name address pair
+global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
+
+# This is the shared library runtime path variable.
+runpath_var=$runpath_var
+
+# This is the shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action_F77
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=$hardcode_into_libs
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_F77
+
+# If ld is used when linking, flag to hardcode \$libdir into
+# a binary during linking. This must work even if \$libdir does
+# not exist.
+hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_F77
+
+# Whether we need a single -rpath flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator_F77
+
+# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the
+# resulting binary.
+hardcode_direct=$hardcode_direct_F77
+
+# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
+# resulting binary.
+hardcode_minus_L=$hardcode_minus_L_F77
+
+# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into
+# the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var_F77
+
+# Set to yes if building a shared library automatically hardcodes DIR into the library
+# and all subsequent libraries and executables linked against it.
+hardcode_automatic=$hardcode_automatic_F77
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at relink time.
+variables_saved_for_relink="$variables_saved_for_relink"
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs_F77
+
+# Compile-time system search path for libraries
+sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+
+# Run-time system search path for libraries
+sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
+
+# Fix the shell variable \$srcfile for the compiler.
+fix_srcfile_path="$fix_srcfile_path_F77"
+
+# Set to yes if exported symbols are required.
+always_export_symbols=$always_export_symbols_F77
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds_F77
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=$lt_extract_expsyms_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms_F77
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms_F77
+
+# ### END LIBTOOL TAG CONFIG: $tagname
+
+__EOF__
+
+
+else
+ # If there is no Makefile yet, we rely on a make rule to execute
+ # `config.status --recheck' to rerun these tests and create the
+ # libtool script then.
+ ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'`
+ if test -f "$ltmain_in"; then
+ test -f Makefile && make "$ltmain"
+ fi
+fi
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+CC="$lt_save_CC"
+
+ else
+ tagname=""
+ fi
+ ;;
+
+ GCJ)
+ if test -n "$GCJ" && test "X$GCJ" != "Xno"; then
+
+
+
+# Source file extension for Java test sources.
+ac_ext=java
+
+# Object file extension for compiled Java test sources.
+objext=o
+objext_GCJ=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="class foo {}\n"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='public class conftest { public static void main(String argv) {}; }\n'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+CC=${GCJ-"gcj"}
+compiler=$CC
+compiler_GCJ=$CC
+
+# GCJ did not exist at the time GCC didn't implicitly link libc in.
+archive_cmds_need_lc_GCJ=no
+
+
+lt_prog_compiler_no_builtin_flag_GCJ=
+
+if test "$GCC" = yes; then
+ lt_prog_compiler_no_builtin_flag_GCJ=' -fno-builtin'
+
+
+echo "$as_me:$LINENO: checking if $compiler supports -fno-rtti -fno-exceptions" >&5
+echo $ECHO_N "checking if $compiler supports -fno-rtti -fno-exceptions... $ECHO_C" >&6
+if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_cv_prog_compiler_rtti_exceptions=no
+ ac_outfile=conftest.$ac_objext
+ printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="-fno-rtti -fno-exceptions"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:17102: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&5
+ echo "$as_me:17106: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test ! -s conftest.err; then
+ lt_cv_prog_compiler_rtti_exceptions=yes
+ fi
+ fi
+ $rm conftest*
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_rtti_exceptions" >&5
+echo "${ECHO_T}$lt_cv_prog_compiler_rtti_exceptions" >&6
+
+if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then
+ lt_prog_compiler_no_builtin_flag_GCJ="$lt_prog_compiler_no_builtin_flag_GCJ -fno-rtti -fno-exceptions"
+else
+ :
+fi
+
+fi
+
+lt_prog_compiler_wl_GCJ=
+lt_prog_compiler_pic_GCJ=
+lt_prog_compiler_static_GCJ=
+
+echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5
+echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
+
+ if test "$GCC" = yes; then
+ lt_prog_compiler_wl_GCJ='-Wl,'
+ lt_prog_compiler_static_GCJ='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static_GCJ='-Bstatic'
+ fi
+ ;;
+
+ amigaos*)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the `-m68020' flag to GCC prevents building anything better,
+ # like `-m68040'.
+ lt_prog_compiler_pic_GCJ='-m68020 -resident32 -malways-restore-a4'
+ ;;
+
+ beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+
+ mingw* | pw32* | os2*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ lt_prog_compiler_pic_GCJ='-DDLL_EXPORT'
+ ;;
+
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ lt_prog_compiler_pic_GCJ='-fno-common'
+ ;;
+
+ msdosdjgpp*)
+ # Just because we use GCC doesn't mean we suddenly get shared libraries
+ # on systems that don't support them.
+ lt_prog_compiler_can_build_shared_GCJ=no
+ enable_shared=no
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ lt_prog_compiler_pic_GCJ=-Kconform_pic
+ fi
+ ;;
+
+ hpux*)
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case "$host_cpu" in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ lt_prog_compiler_pic_GCJ='-fPIC'
+ ;;
+ esac
+ ;;
+
+ *)
+ lt_prog_compiler_pic_GCJ='-fPIC'
+ ;;
+ esac
+ else
+ # PORTME Check for flag to pass linker flags through the system compiler.
+ case $host_os in
+ aix*)
+ lt_prog_compiler_wl_GCJ='-Wl,'
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static_GCJ='-Bstatic'
+ else
+ lt_prog_compiler_static_GCJ='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+
+ mingw* | pw32* | os2*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ lt_prog_compiler_pic_GCJ='-DDLL_EXPORT'
+ ;;
+
+ hpux9* | hpux10* | hpux11*)
+ lt_prog_compiler_wl_GCJ='-Wl,'
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case "$host_cpu" in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ lt_prog_compiler_pic_GCJ='+Z'
+ ;;
+ esac
+ # Is there a better lt_prog_compiler_static that works with the bundled CC?
+ lt_prog_compiler_static_GCJ='${wl}-a ${wl}archive'
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ lt_prog_compiler_wl_GCJ='-Wl,'
+ # PIC (with -KPIC) is the default.
+ lt_prog_compiler_static_GCJ='-non_shared'
+ ;;
+
+ newsos6)
+ lt_prog_compiler_pic_GCJ='-KPIC'
+ lt_prog_compiler_static_GCJ='-Bstatic'
+ ;;
+
+ linux*)
+ case $CC in
+ icc* | ecc*)
+ lt_prog_compiler_wl_GCJ='-Wl,'
+ lt_prog_compiler_pic_GCJ='-KPIC'
+ lt_prog_compiler_static_GCJ='-static'
+ ;;
+ ccc*)
+ lt_prog_compiler_wl_GCJ='-Wl,'
+ # All Alpha code is PIC.
+ lt_prog_compiler_static_GCJ='-non_shared'
+ ;;
+ esac
+ ;;
+
+ osf3* | osf4* | osf5*)
+ lt_prog_compiler_wl_GCJ='-Wl,'
+ # All OSF/1 code is PIC.
+ lt_prog_compiler_static_GCJ='-non_shared'
+ ;;
+
+ sco3.2v5*)
+ lt_prog_compiler_pic_GCJ='-Kpic'
+ lt_prog_compiler_static_GCJ='-dn'
+ ;;
+
+ solaris*)
+ lt_prog_compiler_wl_GCJ='-Wl,'
+ lt_prog_compiler_pic_GCJ='-KPIC'
+ lt_prog_compiler_static_GCJ='-Bstatic'
+ ;;
+
+ sunos4*)
+ lt_prog_compiler_wl_GCJ='-Qoption ld '
+ lt_prog_compiler_pic_GCJ='-PIC'
+ lt_prog_compiler_static_GCJ='-Bstatic'
+ ;;
+
+ sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ lt_prog_compiler_wl_GCJ='-Wl,'
+ lt_prog_compiler_pic_GCJ='-KPIC'
+ lt_prog_compiler_static_GCJ='-Bstatic'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec ;then
+ lt_prog_compiler_pic_GCJ='-Kconform_pic'
+ lt_prog_compiler_static_GCJ='-Bstatic'
+ fi
+ ;;
+
+ uts4*)
+ lt_prog_compiler_pic_GCJ='-pic'
+ lt_prog_compiler_static_GCJ='-Bstatic'
+ ;;
+
+ *)
+ lt_prog_compiler_can_build_shared_GCJ=no
+ ;;
+ esac
+ fi
+
+echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_GCJ" >&5
+echo "${ECHO_T}$lt_prog_compiler_pic_GCJ" >&6
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$lt_prog_compiler_pic_GCJ"; then
+
+echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic_GCJ works" >&5
+echo $ECHO_N "checking if $compiler PIC flag $lt_prog_compiler_pic_GCJ works... $ECHO_C" >&6
+if test "${lt_prog_compiler_pic_works_GCJ+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_prog_compiler_pic_works_GCJ=no
+ ac_outfile=conftest.$ac_objext
+ printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="$lt_prog_compiler_pic_GCJ"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:17335: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&5
+ echo "$as_me:17339: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test ! -s conftest.err; then
+ lt_prog_compiler_pic_works_GCJ=yes
+ fi
+ fi
+ $rm conftest*
+
+fi
+echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_works_GCJ" >&5
+echo "${ECHO_T}$lt_prog_compiler_pic_works_GCJ" >&6
+
+if test x"$lt_prog_compiler_pic_works_GCJ" = xyes; then
+ case $lt_prog_compiler_pic_GCJ in
+ "" | " "*) ;;
+ *) lt_prog_compiler_pic_GCJ=" $lt_prog_compiler_pic_GCJ" ;;
+ esac
+else
+ lt_prog_compiler_pic_GCJ=
+ lt_prog_compiler_can_build_shared_GCJ=no
+fi
+
+fi
+case "$host_os" in
+ # For platforms which do not support PIC, -DPIC is meaningless:
+ *djgpp*)
+ lt_prog_compiler_pic_GCJ=
+ ;;
+ *)
+ lt_prog_compiler_pic_GCJ="$lt_prog_compiler_pic_GCJ"
+ ;;
+esac
+
+echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5
+echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6
+if test "${lt_cv_prog_compiler_c_o_GCJ+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_cv_prog_compiler_c_o_GCJ=no
+ $rm -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:17395: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&5
+ echo "$as_me:17399: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test ! -s out/conftest.err; then
+ lt_cv_prog_compiler_c_o_GCJ=yes
+ fi
+ fi
+ chmod u+w .
+ $rm conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files
+ $rm out/* && rmdir out
+ cd ..
+ rmdir conftest
+ $rm conftest*
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o_GCJ" >&5
+echo "${ECHO_T}$lt_cv_prog_compiler_c_o_GCJ" >&6
+
+
+hard_links="nottested"
+if test "$lt_cv_prog_compiler_c_o_GCJ" = no && test "$need_locks" != no; then
+ # do not overwrite the value of need_locks provided by the user
+ echo "$as_me:$LINENO: checking if we can lock with hard links" >&5
+echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6
+ hard_links=yes
+ $rm conftest*
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ touch conftest.a
+ ln conftest.a conftest.b 2>&5 || hard_links=no
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ echo "$as_me:$LINENO: result: $hard_links" >&5
+echo "${ECHO_T}$hard_links" >&6
+ if test "$hard_links" = no; then
+ { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
+echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
+ need_locks=warn
+ fi
+else
+ need_locks=no
+fi
+
+echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6
+
+ runpath_var=
+ allow_undefined_flag_GCJ=
+ enable_shared_with_static_runtimes_GCJ=no
+ archive_cmds_GCJ=
+ archive_expsym_cmds_GCJ=
+ old_archive_From_new_cmds_GCJ=
+ old_archive_from_expsyms_cmds_GCJ=
+ export_dynamic_flag_spec_GCJ=
+ whole_archive_flag_spec_GCJ=
+ thread_safe_flag_spec_GCJ=
+ hardcode_libdir_flag_spec_GCJ=
+ hardcode_libdir_flag_spec_ld_GCJ=
+ hardcode_libdir_separator_GCJ=
+ hardcode_direct_GCJ=no
+ hardcode_minus_L_GCJ=no
+ hardcode_shlibpath_var_GCJ=unsupported
+ link_all_deplibs_GCJ=unknown
+ hardcode_automatic_GCJ=no
+ module_cmds_GCJ=
+ module_expsym_cmds_GCJ=
+ always_export_symbols_GCJ=no
+ export_symbols_cmds_GCJ='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ # include_expsyms should be a list of space-separated symbols to be *always*
+ # included in the symbol list
+ include_expsyms_GCJ=
+ # exclude_expsyms can be an extended regexp of symbols to exclude
+ # it will be wrapped by ` (' and `)$', so one must not match beginning or
+ # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+ # as well as any symbol that contains `d'.
+ exclude_expsyms_GCJ="_GLOBAL_OFFSET_TABLE_"
+ # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+ # platforms (ab)use it in PIC code, but their linkers get confused if
+ # the symbol is explicitly referenced. Since portable code cannot
+ # rely on this symbol name, it's probably fine to never include it in
+ # preloaded symbol tables.
+ extract_expsyms_cmds=
+
+ case $host_os in
+ cygwin* | mingw* | pw32*)
+ # FIXME: the MSVC++ port hasn't been tested in a loooong time
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ if test "$GCC" != yes; then
+ with_gnu_ld=no
+ fi
+ ;;
+ openbsd*)
+ with_gnu_ld=no
+ ;;
+ esac
+
+ ld_shlibs_GCJ=yes
+ if test "$with_gnu_ld" = yes; then
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ wlarc='${wl}'
+
+ # See if GNU ld supports shared libraries.
+ case $host_os in
+ aix3* | aix4* | aix5*)
+ # On AIX/PPC, the GNU linker is very broken
+ if test "$host_cpu" != ia64; then
+ ld_shlibs_GCJ=no
+ cat <<EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.9.1, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support. If you
+*** really care for shared libraries, you may want to modify your PATH
+*** so that a non-GNU linker is found, and then restart.
+
+EOF
+ fi
+ ;;
+
+ amigaos*)
+ archive_cmds_GCJ='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ hardcode_libdir_flag_spec_GCJ='-L$libdir'
+ hardcode_minus_L_GCJ=yes
+
+ # Samuel A. Falvo II <kc5tja at dolphin.openprojects.net> reports
+ # that the semantics of dynamic libraries on AmigaOS, at least up
+ # to version 4, is to share data among multiple programs linked
+ # with the same dynamic library. Since this doesn't match the
+ # behavior of shared libraries on other platforms, we can't use
+ # them.
+ ld_shlibs_GCJ=no
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ allow_undefined_flag_GCJ=unsupported
+ # Joseph Beckenbach <jrb3 at best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ archive_cmds_GCJ='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ else
+ ld_shlibs_GCJ=no
+ fi
+ ;;
+
+ cygwin* | mingw* | pw32*)
+ # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, GCJ) is actually meaningless,
+ # as there is no search path for DLLs.
+ hardcode_libdir_flag_spec_GCJ='-L$libdir'
+ allow_undefined_flag_GCJ=unsupported
+ always_export_symbols_GCJ=no
+ enable_shared_with_static_runtimes_GCJ=yes
+ export_symbols_cmds_GCJ='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGS] /s/.* \([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW] /s/.* //'\'' | sort | uniq > $export_symbols'
+
+ if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
+ archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+ # If the export-symbols file already is a .def file (1st line
+ # is EXPORTS), use it as is; otherwise, prepend...
+ archive_expsym_cmds_GCJ='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+ archive_cmds_GCJ='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+ wlarc=
+ else
+ archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ fi
+ ;;
+
+ solaris* | sysv5*)
+ if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then
+ ld_shlibs_GCJ=no
+ cat <<EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+EOF
+ elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs_GCJ=no
+ fi
+ ;;
+
+ sunos4*)
+ archive_cmds_GCJ='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ wlarc=
+ hardcode_direct_GCJ=yes
+ hardcode_shlibpath_var_GCJ=no
+ ;;
+
+ linux*)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ tmp_archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_cmds_GCJ="$tmp_archive_cmds"
+ supports_anon_versioning=no
+ case `$LD -v 2>/dev/null` in
+ *\ 01.* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
+ *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+ *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+ *\ 2.11.*) ;; # other 2.11 versions
+ *) supports_anon_versioning=yes ;;
+ esac
+ if test $supports_anon_versioning = yes; then
+ archive_expsym_cmds_GCJ='$echo "{ global:" > $output_objdir/$libname.ver~
+cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+$echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ else
+ archive_expsym_cmds_GCJ="$tmp_archive_cmds"
+ fi
+ else
+ ld_shlibs_GCJ=no
+ fi
+ ;;
+
+ *)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs_GCJ=no
+ fi
+ ;;
+ esac
+
+ if test "$ld_shlibs_GCJ" = yes; then
+ runpath_var=LD_RUN_PATH
+ hardcode_libdir_flag_spec_GCJ='${wl}--rpath ${wl}$libdir'
+ export_dynamic_flag_spec_GCJ='${wl}--export-dynamic'
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then
+ whole_archive_flag_spec_GCJ="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ whole_archive_flag_spec_GCJ=
+ fi
+ fi
+ else
+ # PORTME fill in a description of your system's linker (not GNU ld)
+ case $host_os in
+ aix3*)
+ allow_undefined_flag_GCJ=unsupported
+ always_export_symbols_GCJ=yes
+ archive_expsym_cmds_GCJ='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+ # Note: this linker hardcodes the directories in LIBPATH if there
+ # are no directories specified by -L.
+ hardcode_minus_L_GCJ=yes
+ if test "$GCC" = yes && test -z "$link_static_flag"; then
+ # Neither direct hardcoding nor static linking is supported with a
+ # broken collect2.
+ hardcode_direct_GCJ=unsupported
+ fi
+ ;;
+
+ aix4* | aix5*)
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=""
+ else
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to AIX nm, but means don't demangle with GNU nm
+ if $NM -V 2>&1 | grep 'GNU' > /dev/null; then
+ export_symbols_cmds_GCJ='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols'
+ else
+ export_symbols_cmds_GCJ='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols'
+ fi
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # need to do runtime linking.
+ case $host_os in aix4.[23]|aix4.[23].*|aix5*)
+ for ld_flag in $LDFLAGS; do
+ if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+ aix_use_runtimelinking=yes
+ break
+ fi
+ done
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ archive_cmds_GCJ=''
+ hardcode_direct_GCJ=yes
+ hardcode_libdir_separator_GCJ=':'
+ link_all_deplibs_GCJ=yes
+
+ if test "$GCC" = yes; then
+ case $host_os in aix4.012|aix4.012.*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" && \
+ strings "$collect2name" | grep resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ hardcode_direct_GCJ=yes
+ else
+ # We have old collect2
+ hardcode_direct_GCJ=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ hardcode_minus_L_GCJ=yes
+ hardcode_libdir_flag_spec_GCJ='-L$libdir'
+ hardcode_libdir_separator_GCJ=
+ fi
+ esac
+ shared_flag='-shared'
+ else
+ # not using gcc
+ if test "$host_cpu" = ia64; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag='${wl}-G'
+ else
+ shared_flag='${wl}-bM:SRE'
+ fi
+ fi
+ fi
+
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to export.
+ always_export_symbols_GCJ=yes
+ if test "$aix_use_runtimelinking" = yes; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ allow_undefined_flag_GCJ='-berok'
+ # Determine the default libpath from the value encoded in an empty executable.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
+}'`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
+}'`; fi
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+ hardcode_libdir_flag_spec_GCJ='${wl}-blibpath:$libdir:'"$aix_libpath"
+ archive_expsym_cmds_GCJ="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ else
+ if test "$host_cpu" = ia64; then
+ hardcode_libdir_flag_spec_GCJ='${wl}-R $libdir:/usr/lib:/lib'
+ allow_undefined_flag_GCJ="-z nodefs"
+ archive_expsym_cmds_GCJ="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an empty executable.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
+}'`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
+}'`; fi
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+ hardcode_libdir_flag_spec_GCJ='${wl}-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ no_undefined_flag_GCJ=' ${wl}-bernotok'
+ allow_undefined_flag_GCJ=' ${wl}-berok'
+ # -bexpall does not export symbols beginning with underscore (_)
+ always_export_symbols_GCJ=yes
+ # Exported symbols can be pulled into shared objects from archives
+ whole_archive_flag_spec_GCJ=' '
+ archive_cmds_need_lc_GCJ=yes
+ # This is similar to how AIX traditionally builds it's shared libraries.
+ archive_expsym_cmds_GCJ="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ fi
+ fi
+ ;;
+
+ amigaos*)
+ archive_cmds_GCJ='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ hardcode_libdir_flag_spec_GCJ='-L$libdir'
+ hardcode_minus_L_GCJ=yes
+ # see comment about different semantics on the GNU ld section
+ ld_shlibs_GCJ=no
+ ;;
+
+ bsdi4*)
+ export_dynamic_flag_spec_GCJ=-rdynamic
+ ;;
+
+ cygwin* | mingw* | pw32*)
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ hardcode_libdir_flag_spec_GCJ=' '
+ allow_undefined_flag_GCJ=unsupported
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=".dll"
+ # FIXME: Setting linknames here is a bad hack.
+ archive_cmds_GCJ='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames='
+ # The linker will automatically build a .lib file if we build a DLL.
+ old_archive_From_new_cmds_GCJ='true'
+ # FIXME: Should let the user specify the lib program.
+ old_archive_cmds_GCJ='lib /OUT:$oldlib$oldobjs$old_deplibs'
+ fix_srcfile_path='`cygpath -w "$srcfile"`'
+ enable_shared_with_static_runtimes_GCJ=yes
+ ;;
+
+ darwin* | rhapsody*)
+ if test "$GXX" = yes ; then
+ archive_cmds_need_lc_GCJ=no
+ case "$host_os" in
+ rhapsody* | darwin1.[012])
+ allow_undefined_flag_GCJ='-undefined suppress'
+ ;;
+ *) # Darwin 1.3 on
+ if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
+ allow_undefined_flag_GCJ='-flat_namespace -undefined suppress'
+ else
+ case ${MACOSX_DEPLOYMENT_TARGET} in
+ 10.[012])
+ allow_undefined_flag_GCJ='-flat_namespace -undefined suppress'
+ ;;
+ 10.*)
+ allow_undefined_flag_GCJ='-undefined dynamic_lookup'
+ ;;
+ esac
+ fi
+ ;;
+ esac
+ lt_int_apple_cc_single_mod=no
+ output_verbose_link_cmd='echo'
+ if $CC -dumpspecs 2>&1 | grep 'single_module' >/dev/null ; then
+ lt_int_apple_cc_single_mod=yes
+ fi
+ if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
+ archive_cmds_GCJ='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+ else
+ archive_cmds_GCJ='$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+ fi
+ module_cmds_GCJ='$CC ${wl}-bind_at_load $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+ # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's
+ if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
+ archive_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ else
+ archive_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ fi
+ module_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ hardcode_direct_GCJ=no
+ hardcode_automatic_GCJ=yes
+ hardcode_shlibpath_var_GCJ=unsupported
+ whole_archive_flag_spec_GCJ='-all_load $convenience'
+ link_all_deplibs_GCJ=yes
+ else
+ ld_shlibs_GCJ=no
+ fi
+ ;;
+
+ dgux*)
+ archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec_GCJ='-L$libdir'
+ hardcode_shlibpath_var_GCJ=no
+ ;;
+
+ freebsd1*)
+ ld_shlibs_GCJ=no
+ ;;
+
+ # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+ # support. Future versions do this automatically, but an explicit c++rt0.o
+ # does not break anything, and helps significantly (at the cost of a little
+ # extra space).
+ freebsd2.2*)
+ archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+ hardcode_libdir_flag_spec_GCJ='-R$libdir'
+ hardcode_direct_GCJ=yes
+ hardcode_shlibpath_var_GCJ=no
+ ;;
+
+ # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+ freebsd2*)
+ archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct_GCJ=yes
+ hardcode_minus_L_GCJ=yes
+ hardcode_shlibpath_var_GCJ=no
+ ;;
+
+ # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+ freebsd* | kfreebsd*-gnu)
+ archive_cmds_GCJ='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
+ hardcode_libdir_flag_spec_GCJ='-R$libdir'
+ hardcode_direct_GCJ=yes
+ hardcode_shlibpath_var_GCJ=no
+ ;;
+
+ hpux9*)
+ if test "$GCC" = yes; then
+ archive_cmds_GCJ='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ else
+ archive_cmds_GCJ='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ fi
+ hardcode_libdir_flag_spec_GCJ='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator_GCJ=:
+ hardcode_direct_GCJ=yes
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L_GCJ=yes
+ export_dynamic_flag_spec_GCJ='${wl}-E'
+ ;;
+
+ hpux10* | hpux11*)
+ if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+ case "$host_cpu" in
+ hppa*64*|ia64*)
+ archive_cmds_GCJ='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ archive_cmds_GCJ='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ else
+ case "$host_cpu" in
+ hppa*64*|ia64*)
+ archive_cmds_GCJ='$LD -b +h $soname -o $lib $libobjs $deplibs $linker_flags'
+ ;;
+ *)
+ archive_cmds_GCJ='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+ ;;
+ esac
+ fi
+ if test "$with_gnu_ld" = no; then
+ case "$host_cpu" in
+ hppa*64*)
+ hardcode_libdir_flag_spec_GCJ='${wl}+b ${wl}$libdir'
+ hardcode_libdir_flag_spec_ld_GCJ='+b $libdir'
+ hardcode_libdir_separator_GCJ=:
+ hardcode_direct_GCJ=no
+ hardcode_shlibpath_var_GCJ=no
+ ;;
+ ia64*)
+ hardcode_libdir_flag_spec_GCJ='-L$libdir'
+ hardcode_direct_GCJ=no
+ hardcode_shlibpath_var_GCJ=no
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L_GCJ=yes
+ ;;
+ *)
+ hardcode_libdir_flag_spec_GCJ='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator_GCJ=:
+ hardcode_direct_GCJ=yes
+ export_dynamic_flag_spec_GCJ='${wl}-E'
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L_GCJ=yes
+ ;;
+ esac
+ fi
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ if test "$GCC" = yes; then
+ archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ archive_cmds_GCJ='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+ hardcode_libdir_flag_spec_ld_GCJ='-rpath $libdir'
+ fi
+ hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator_GCJ=:
+ link_all_deplibs_GCJ=yes
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+ archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
+ else
+ archive_cmds_GCJ='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF
+ fi
+ hardcode_libdir_flag_spec_GCJ='-R$libdir'
+ hardcode_direct_GCJ=yes
+ hardcode_shlibpath_var_GCJ=no
+ ;;
+
+ newsos6)
+ archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct_GCJ=yes
+ hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator_GCJ=:
+ hardcode_shlibpath_var_GCJ=no
+ ;;
+
+ openbsd*)
+ hardcode_direct_GCJ=yes
+ hardcode_shlibpath_var_GCJ=no
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ archive_cmds_GCJ='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ hardcode_libdir_flag_spec_GCJ='${wl}-rpath,$libdir'
+ export_dynamic_flag_spec_GCJ='${wl}-E'
+ else
+ case $host_os in
+ openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
+ archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec_GCJ='-R$libdir'
+ ;;
+ *)
+ archive_cmds_GCJ='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ hardcode_libdir_flag_spec_GCJ='${wl}-rpath,$libdir'
+ ;;
+ esac
+ fi
+ ;;
+
+ os2*)
+ hardcode_libdir_flag_spec_GCJ='-L$libdir'
+ hardcode_minus_L_GCJ=yes
+ allow_undefined_flag_GCJ=unsupported
+ archive_cmds_GCJ='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+ old_archive_From_new_cmds_GCJ='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+ ;;
+
+ osf3*)
+ if test "$GCC" = yes; then
+ allow_undefined_flag_GCJ=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds_GCJ='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ allow_undefined_flag_GCJ=' -expect_unresolved \*'
+ archive_cmds_GCJ='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+ fi
+ hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator_GCJ=:
+ ;;
+
+ osf4* | osf5*) # as osf3* with the addition of -msym flag
+ if test "$GCC" = yes; then
+ allow_undefined_flag_GCJ=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds_GCJ='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir'
+ else
+ allow_undefined_flag_GCJ=' -expect_unresolved \*'
+ archive_cmds_GCJ='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+ archive_expsym_cmds_GCJ='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~
+ $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib~$rm $lib.exp'
+
+ # Both c and cxx compiler support -rpath directly
+ hardcode_libdir_flag_spec_GCJ='-rpath $libdir'
+ fi
+ hardcode_libdir_separator_GCJ=:
+ ;;
+
+ sco3.2v5*)
+ archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var_GCJ=no
+ export_dynamic_flag_spec_GCJ='${wl}-Bexport'
+ runpath_var=LD_RUN_PATH
+ hardcode_runpath_var=yes
+ ;;
+
+ solaris*)
+ no_undefined_flag_GCJ=' -z text'
+ if test "$GCC" = yes; then
+ archive_cmds_GCJ='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_GCJ='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp'
+ else
+ archive_cmds_GCJ='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ archive_expsym_cmds_GCJ='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
+ fi
+ hardcode_libdir_flag_spec_GCJ='-R$libdir'
+ hardcode_shlibpath_var_GCJ=no
+ case $host_os in
+ solaris2.[0-5] | solaris2.[0-5].*) ;;
+ *) # Supported since Solaris 2.6 (maybe 2.5.1?)
+ whole_archive_flag_spec_GCJ='-z allextract$convenience -z defaultextract' ;;
+ esac
+ link_all_deplibs_GCJ=yes
+ ;;
+
+ sunos4*)
+ if test "x$host_vendor" = xsequent; then
+ # Use $CC to link under sequent, because it throws in some extra .o
+ # files that make .init and .fini sections work.
+ archive_cmds_GCJ='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds_GCJ='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ hardcode_libdir_flag_spec_GCJ='-L$libdir'
+ hardcode_direct_GCJ=yes
+ hardcode_minus_L_GCJ=yes
+ hardcode_shlibpath_var_GCJ=no
+ ;;
+
+ sysv4)
+ case $host_vendor in
+ sni)
+ archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct_GCJ=yes # is this really true???
+ ;;
+ siemens)
+ ## LD is ld it makes a PLAMLIB
+ ## CC just makes a GrossModule.
+ archive_cmds_GCJ='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+ reload_cmds_GCJ='$CC -r -o $output$reload_objs'
+ hardcode_direct_GCJ=no
+ ;;
+ motorola)
+ archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct_GCJ=no #Motorola manual says yes, but my tests say they lie
+ ;;
+ esac
+ runpath_var='LD_RUN_PATH'
+ hardcode_shlibpath_var_GCJ=no
+ ;;
+
+ sysv4.3*)
+ archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var_GCJ=no
+ export_dynamic_flag_spec_GCJ='-Bexport'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var_GCJ=no
+ runpath_var=LD_RUN_PATH
+ hardcode_runpath_var=yes
+ ld_shlibs_GCJ=yes
+ fi
+ ;;
+
+ sysv4.2uw2*)
+ archive_cmds_GCJ='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct_GCJ=yes
+ hardcode_minus_L_GCJ=no
+ hardcode_shlibpath_var_GCJ=no
+ hardcode_runpath_var=yes
+ runpath_var=LD_RUN_PATH
+ ;;
+
+ sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[78]* | unixware7*)
+ no_undefined_flag_GCJ='${wl}-z ${wl}text'
+ if test "$GCC" = yes; then
+ archive_cmds_GCJ='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds_GCJ='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ runpath_var='LD_RUN_PATH'
+ hardcode_shlibpath_var_GCJ=no
+ ;;
+
+ sysv5*)
+ no_undefined_flag_GCJ=' -z text'
+ # $CC -shared without GNU ld will not create a library from C++
+ # object files and a static libstdc++, better avoid it by now
+ archive_cmds_GCJ='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ archive_expsym_cmds_GCJ='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
+ hardcode_libdir_flag_spec_GCJ=
+ hardcode_shlibpath_var_GCJ=no
+ runpath_var='LD_RUN_PATH'
+ ;;
+
+ uts4*)
+ archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec_GCJ='-L$libdir'
+ hardcode_shlibpath_var_GCJ=no
+ ;;
+
+ *)
+ ld_shlibs_GCJ=no
+ ;;
+ esac
+ fi
+
+echo "$as_me:$LINENO: result: $ld_shlibs_GCJ" >&5
+echo "${ECHO_T}$ld_shlibs_GCJ" >&6
+test "$ld_shlibs_GCJ" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+ variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$archive_cmds_need_lc_GCJ" in
+x|xyes)
+ # Assume -lc should be added
+ archive_cmds_need_lc_GCJ=yes
+
+ if test "$enable_shared" = yes && test "$GCC" = yes; then
+ case $archive_cmds_GCJ in
+ *'~'*)
+ # FIXME: we may have to deal with multi-command sequences.
+ ;;
+ '$CC '*)
+ # Test whether the compiler implicitly links with -lc since on some
+ # systems, -lgcc has to come before -lc. If gcc already passes -lc
+ # to ld, don't add -lc before -lgcc.
+ echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5
+echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6
+ $rm conftest*
+ printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } 2>conftest.err; then
+ soname=conftest
+ lib=conftest
+ libobjs=conftest.$ac_objext
+ deplibs=
+ wl=$lt_prog_compiler_wl_GCJ
+ compiler_flags=-v
+ linker_flags=-v
+ verstring=
+ output_objdir=.
+ libname=conftest
+ lt_save_allow_undefined_flag=$allow_undefined_flag_GCJ
+ allow_undefined_flag_GCJ=
+ if { (eval echo "$as_me:$LINENO: \"$archive_cmds_GCJ 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5
+ (eval $archive_cmds_GCJ 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+ then
+ archive_cmds_need_lc_GCJ=no
+ else
+ archive_cmds_need_lc_GCJ=yes
+ fi
+ allow_undefined_flag_GCJ=$lt_save_allow_undefined_flag
+ else
+ cat conftest.err 1>&5
+ fi
+ $rm conftest*
+ echo "$as_me:$LINENO: result: $archive_cmds_need_lc_GCJ" >&5
+echo "${ECHO_T}$archive_cmds_need_lc_GCJ" >&6
+ ;;
+ esac
+ fi
+ ;;
+esac
+
+echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5
+echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+if test "$GCC" = yes; then
+ sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+ if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then
+ # if the path contains ";" then we assume it to be the separator
+ # otherwise default to the standard path separator (i.e. ":") - it is
+ # assumed that no part of a normal pathname contains ";" but that should
+ # okay in the real world where ";" in dirpaths is itself problematic.
+ sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+ else
+ sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ fi
+else
+ sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+ shlibpath_var=LIBPATH
+
+ # AIX 3 has no versioning support, so we append a major version to the name.
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+
+aix4* | aix5*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ hardcode_into_libs=yes
+ if test "$host_cpu" = ia64; then
+ # AIX 5 supports IA64
+ library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ else
+ # With GCC up to 2.95.x, collect2 would create an import file
+ # for dependence libraries. The import file would start with
+ # the line `#! .'. This would cause the generated library to
+ # depend on `.', always an invalid library. This was fixed in
+ # development snapshots of GCC prior to 3.0.
+ case $host_os in
+ aix4 | aix4.[01] | aix4.[01].*)
+ if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+ echo ' yes '
+ echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then
+ :
+ else
+ can_build_shared=no
+ fi
+ ;;
+ esac
+ # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+ # soname into executable. Probably we can add versioning support to
+ # collect2, so additional links can be useful in future.
+ if test "$aix_use_runtimelinking" = yes; then
+ # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+ # instead of lib<name>.a to let people know that these are not
+ # typical AIX shared libraries.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ else
+ # We preserve .a as extension for shared libraries through AIX4.2
+ # and later when we are not doing run time linking.
+ library_names_spec='${libname}${release}.a $libname.a'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ fi
+ shlibpath_var=LIBPATH
+ fi
+ ;;
+
+amigaos*)
+ library_names_spec='$libname.ixlibrary $libname.a'
+ # Create ${libname}_ixlibrary.a entries in /sys/libs.
+ finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+ ;;
+
+beos*)
+ library_names_spec='${libname}${shared_ext}'
+ dynamic_linker="$host_os ld.so"
+ shlibpath_var=LIBRARY_PATH
+ ;;
+
+bsdi4*)
+ version_type=linux
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+ # the default ld.so.conf also contains /usr/contrib/lib and
+ # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+ # libtool to hard-code these into programs
+ ;;
+
+cygwin* | mingw* | pw32*)
+ version_type=windows
+ shrext_cmds=".dll"
+ need_version=no
+ need_lib_prefix=no
+
+ case $GCC,$host_os in
+ yes,cygwin* | yes,mingw* | yes,pw32*)
+ library_names_spec='$libname.dll.a'
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \${file}`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $rm \$dlpath'
+ shlibpath_overrides_runpath=yes
+
+ case $host_os in
+ cygwin*)
+ # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+ soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib"
+ ;;
+ mingw*)
+ # MinGW DLLs use traditional 'lib' prefix
+ soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+ if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then
+ # It is most probably a Windows format PATH printed by
+ # mingw gcc, but we are running on Cygwin. Gcc prints its search
+ # path with ; separators, and with drive letters. We can handle the
+ # drive letters (cygwin fileutils understands them), so leave them,
+ # especially as we might pass files found there to a mingw objdump,
+ # which wouldn't understand a cygwinified path. Ahh.
+ sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+ else
+ sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ fi
+ ;;
+ pw32*)
+ # pw32 DLLs use 'pw' prefix rather than 'lib'
+ library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/./-/g'`${versuffix}${shared_ext}'
+ ;;
+ esac
+ ;;
+
+ *)
+ library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
+ ;;
+ esac
+ dynamic_linker='Win32 ld.exe'
+ # FIXME: first we should search . and the directory the executable is in
+ shlibpath_var=PATH
+ ;;
+
+darwin* | rhapsody*)
+ dynamic_linker="$host_os dyld"
+ version_type=darwin
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+ soname_spec='${libname}${release}${major}$shared_ext'
+ shlibpath_overrides_runpath=yes
+ shlibpath_var=DYLD_LIBRARY_PATH
+ shrext_cmds='$(test .$module = .yes && echo .so || echo .dylib)'
+ # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same.
+ if test "$GCC" = yes; then
+ sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"`
+ else
+ sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib'
+ fi
+ sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+ ;;
+
+dgux*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+freebsd1*)
+ dynamic_linker=no
+ ;;
+
+kfreebsd*-gnu)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='GNU ld.so'
+ ;;
+
+freebsd*)
+ objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout`
+ version_type=freebsd-$objformat
+ case $version_type in
+ freebsd-elf*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ need_version=no
+ need_lib_prefix=no
+ ;;
+ freebsd-*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+ need_version=yes
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_os in
+ freebsd2*)
+ shlibpath_overrides_runpath=yes
+ ;;
+ freebsd3.01* | freebsdelf3.01*)
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ *) # from 3.2 on
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+ esac
+ ;;
+
+gnu*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ hardcode_into_libs=yes
+ ;;
+
+hpux9* | hpux10* | hpux11*)
+ # Give a soname corresponding to the major version so that dld.sl refuses to
+ # link against other versions.
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ case "$host_cpu" in
+ ia64*)
+ shrext_cmds='.so'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ if test "X$HPUX_IA64_MODE" = X32; then
+ sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+ else
+ sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+ fi
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ hppa*64*)
+ shrext_cmds='.sl'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ *)
+ shrext_cmds='.sl'
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=SHLIB_PATH
+ shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+ esac
+ # HP-UX runs *really* slowly unless shared libraries are mode 555.
+ postinstall_cmds='chmod 555 $lib'
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $host_os in
+ nonstopux*) version_type=nonstopux ;;
+ *)
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ version_type=linux
+ else
+ version_type=irix
+ fi ;;
+ esac
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+ case $host_os in
+ irix5* | nonstopux*)
+ libsuff= shlibsuff=
+ ;;
+ *)
+ case $LD in # libtool.m4 will add one of these switches to LD
+ *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+ libsuff= shlibsuff= libmagic=32-bit;;
+ *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+ libsuff=32 shlibsuff=N32 libmagic=N32;;
+ *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+ libsuff=64 shlibsuff=64 libmagic=64-bit;;
+ *) libsuff= shlibsuff= libmagic=never-match;;
+ esac
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+ sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+ hardcode_into_libs=yes
+ ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+ dynamic_linker=no
+ ;;
+
+# This must be Linux ELF.
+linux*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ # This implies no fast_install, which is unacceptable.
+ # Some rework will be needed to allow for fast_install
+ # before this can be enabled.
+ hardcode_into_libs=yes
+
+ # find out which ABI we are using
+ libsuff=
+ case "$host_cpu" in
+ x86_64*|s390x*|powerpc64*)
+ echo '#line 18729 "configure"' > conftest.$ac_ext
+ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *64-bit*)
+ libsuff=64
+ sys_lib_search_path_spec="/lib${libsuff} /usr/lib${libsuff} /usr/local/lib${libsuff}"
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+ esac
+
+ # Append ld.so.conf contents to the search path
+ if test -f /etc/ld.so.conf; then
+ lt_ld_extra=`$SED -e 's/:,\t/ /g;s/=^=*$//;s/=^= * / /g' /etc/ld.so.conf | tr '\n' ' '`
+ sys_lib_dlsearch_path_spec="/lib${libsuff} /usr/lib${libsuff} $lt_ld_extra"
+ fi
+
+ # We used to test for /lib/ld.so.1 and disable shared libraries on
+ # powerpc, because MkLinux only supported shared libraries with the
+ # GNU dynamic linker. Since this was broken with cross compilers,
+ # most powerpc-linux boxes support dynamic linking these days and
+ # people can always --disable-shared, the test was removed, and we
+ # assume the GNU/Linux dynamic linker is in use.
+ dynamic_linker='GNU/Linux ld.so'
+ ;;
+
+knetbsd*-gnu)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='GNU ld.so'
+ ;;
+
+netbsd*)
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ dynamic_linker='NetBSD (a.out) ld.so'
+ else
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='NetBSD ld.elf_so'
+ fi
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+
+newsos6)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+nto-qnx*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+openbsd*)
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=yes
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ case $host_os in
+ openbsd2.[89] | openbsd2.[89].*)
+ shlibpath_overrides_runpath=no
+ ;;
+ *)
+ shlibpath_overrides_runpath=yes
+ ;;
+ esac
+ else
+ shlibpath_overrides_runpath=yes
+ fi
+ ;;
+
+os2*)
+ libname_spec='$name'
+ shrext_cmds=".dll"
+ need_lib_prefix=no
+ library_names_spec='$libname${shared_ext} $libname.a'
+ dynamic_linker='OS/2 ld.exe'
+ shlibpath_var=LIBPATH
+ ;;
+
+osf3* | osf4* | osf5*)
+ version_type=osf
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+ sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+ ;;
+
+sco3.2v5*)
+ version_type=osf
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+solaris*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ # ldd complains unless libraries are executable
+ postinstall_cmds='chmod +x $lib'
+ ;;
+
+sunos4*)
+ version_type=sunos
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ if test "$with_gnu_ld" = yes; then
+ need_lib_prefix=no
+ fi
+ need_version=yes
+ ;;
+
+sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_vendor in
+ sni)
+ shlibpath_overrides_runpath=no
+ need_lib_prefix=no
+ export_dynamic_flag_spec='${wl}-Blargedynsym'
+ runpath_var=LD_RUN_PATH
+ ;;
+ siemens)
+ need_lib_prefix=no
+ ;;
+ motorola)
+ need_lib_prefix=no
+ need_version=no
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+ ;;
+ esac
+ ;;
+
+sysv4*MP*)
+ if test -d /usr/nec ;then
+ version_type=linux
+ library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+ soname_spec='$libname${shared_ext}.$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ fi
+ ;;
+
+uts4*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+*)
+ dynamic_linker=no
+ ;;
+esac
+echo "$as_me:$LINENO: result: $dynamic_linker" >&5
+echo "${ECHO_T}$dynamic_linker" >&6
+test "$dynamic_linker" = no && can_build_shared=no
+
+echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5
+echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6
+hardcode_action_GCJ=
+if test -n "$hardcode_libdir_flag_spec_GCJ" || \
+ test -n "$runpath_var GCJ" || \
+ test "X$hardcode_automatic_GCJ"="Xyes" ; then
+
+ # We can hardcode non-existant directories.
+ if test "$hardcode_direct_GCJ" != no &&
+ # If the only mechanism to avoid hardcoding is shlibpath_var, we
+ # have to relink, otherwise we might link with an installed library
+ # when we should be linking with a yet-to-be-installed one
+ ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, GCJ)" != no &&
+ test "$hardcode_minus_L_GCJ" != no; then
+ # Linking always hardcodes the temporary library directory.
+ hardcode_action_GCJ=relink
+ else
+ # We can link without hardcoding, and we can hardcode nonexisting dirs.
+ hardcode_action_GCJ=immediate
+ fi
+else
+ # We cannot hardcode anything, or else we can only hardcode existing
+ # directories.
+ hardcode_action_GCJ=unsupported
+fi
+echo "$as_me:$LINENO: result: $hardcode_action_GCJ" >&5
+echo "${ECHO_T}$hardcode_action_GCJ" >&6
+
+if test "$hardcode_action_GCJ" = relink; then
+ # Fast installation is not supported
+ enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+ test "$enable_shared" = no; then
+ # Fast installation is not necessary
+ enable_fast_install=needless
+fi
+
+striplib=
+old_striplib=
+echo "$as_me:$LINENO: checking whether stripping libraries is possible" >&5
+echo $ECHO_N "checking whether stripping libraries is possible... $ECHO_C" >&6
+if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then
+ test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+ test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+ case $host_os in
+ darwin*)
+ if test -n "$STRIP" ; then
+ striplib="$STRIP -x"
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+ ;;
+ *)
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ ;;
+ esac
+fi
+
+if test "x$enable_dlopen" != xyes; then
+ enable_dlopen=unknown
+ enable_dlopen_self=unknown
+ enable_dlopen_self_static=unknown
+else
+ lt_cv_dlopen=no
+ lt_cv_dlopen_libs=
+
+ case $host_os in
+ beos*)
+ lt_cv_dlopen="load_add_on"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+ ;;
+
+ mingw* | pw32*)
+ lt_cv_dlopen="LoadLibrary"
+ lt_cv_dlopen_libs=
+ ;;
+
+ cygwin*)
+ lt_cv_dlopen="dlopen"
+ lt_cv_dlopen_libs=
+ ;;
+
+ darwin*)
+ # if libdl is installed we need to link against it
+ echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5
+echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dlopen ();
+int
+main ()
+{
+dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_dl_dlopen=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dl_dlopen=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5
+echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6
+if test $ac_cv_lib_dl_dlopen = yes; then
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+
+ lt_cv_dlopen="dyld"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+
+fi
+
+ ;;
+
+ *)
+ echo "$as_me:$LINENO: checking for shl_load" >&5
+echo $ECHO_N "checking for shl_load... $ECHO_C" >&6
+if test "${ac_cv_func_shl_load+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define shl_load to an innocuous variant, in case <limits.h> declares shl_load.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define shl_load innocuous_shl_load
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char shl_load (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef shl_load
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char shl_load ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_shl_load) || defined (__stub___shl_load)
+choke me
+#else
+char (*f) () = shl_load;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != shl_load;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_shl_load=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_shl_load=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_shl_load" >&5
+echo "${ECHO_T}$ac_cv_func_shl_load" >&6
+if test $ac_cv_func_shl_load = yes; then
+ lt_cv_dlopen="shl_load"
+else
+ echo "$as_me:$LINENO: checking for shl_load in -ldld" >&5
+echo $ECHO_N "checking for shl_load in -ldld... $ECHO_C" >&6
+if test "${ac_cv_lib_dld_shl_load+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char shl_load ();
+int
+main ()
+{
+shl_load ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_dld_shl_load=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dld_shl_load=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dld_shl_load" >&5
+echo "${ECHO_T}$ac_cv_lib_dld_shl_load" >&6
+if test $ac_cv_lib_dld_shl_load = yes; then
+ lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"
+else
+ echo "$as_me:$LINENO: checking for dlopen" >&5
+echo $ECHO_N "checking for dlopen... $ECHO_C" >&6
+if test "${ac_cv_func_dlopen+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define dlopen to an innocuous variant, in case <limits.h> declares dlopen.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define dlopen innocuous_dlopen
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char dlopen (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef dlopen
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dlopen ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_dlopen) || defined (__stub___dlopen)
+choke me
+#else
+char (*f) () = dlopen;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != dlopen;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_dlopen=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_dlopen=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_dlopen" >&5
+echo "${ECHO_T}$ac_cv_func_dlopen" >&6
+if test $ac_cv_func_dlopen = yes; then
+ lt_cv_dlopen="dlopen"
+else
+ echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5
+echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dlopen ();
+int
+main ()
+{
+dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_dl_dlopen=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dl_dlopen=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5
+echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6
+if test $ac_cv_lib_dl_dlopen = yes; then
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+ echo "$as_me:$LINENO: checking for dlopen in -lsvld" >&5
+echo $ECHO_N "checking for dlopen in -lsvld... $ECHO_C" >&6
+if test "${ac_cv_lib_svld_dlopen+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsvld $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dlopen ();
+int
+main ()
+{
+dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_svld_dlopen=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_svld_dlopen=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_svld_dlopen" >&5
+echo "${ECHO_T}$ac_cv_lib_svld_dlopen" >&6
+if test $ac_cv_lib_svld_dlopen = yes; then
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"
+else
+ echo "$as_me:$LINENO: checking for dld_link in -ldld" >&5
+echo $ECHO_N "checking for dld_link in -ldld... $ECHO_C" >&6
+if test "${ac_cv_lib_dld_dld_link+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dld_link ();
+int
+main ()
+{
+dld_link ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_dld_dld_link=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dld_dld_link=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dld_dld_link" >&5
+echo "${ECHO_T}$ac_cv_lib_dld_dld_link" >&6
+if test $ac_cv_lib_dld_dld_link = yes; then
+ lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+ ;;
+ esac
+
+ if test "x$lt_cv_dlopen" != xno; then
+ enable_dlopen=yes
+ else
+ enable_dlopen=no
+ fi
+
+ case $lt_cv_dlopen in
+ dlopen)
+ save_CPPFLAGS="$CPPFLAGS"
+ test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+ save_LDFLAGS="$LDFLAGS"
+ eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+ save_LIBS="$LIBS"
+ LIBS="$lt_cv_dlopen_libs $LIBS"
+
+ echo "$as_me:$LINENO: checking whether a program can dlopen itself" >&5
+echo $ECHO_N "checking whether a program can dlopen itself... $ECHO_C" >&6
+if test "${lt_cv_dlopen_self+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$cross_compiling" = yes; then :
+ lt_cv_dlopen_self=cross
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<EOF
+#line 19600 "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+#ifdef __cplusplus
+extern "C" void exit (int);
+#endif
+
+void fnord() { int i=42;}
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ /* dlclose (self); */
+ }
+
+ exit (status);
+}
+EOF
+ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then
+ (./conftest; exit; ) 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;;
+ x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;;
+ x$lt_unknown|x*) lt_cv_dlopen_self=no ;;
+ esac
+ else :
+ # compilation failed
+ lt_cv_dlopen_self=no
+ fi
+fi
+rm -fr conftest*
+
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_dlopen_self" >&5
+echo "${ECHO_T}$lt_cv_dlopen_self" >&6
+
+ if test "x$lt_cv_dlopen_self" = xyes; then
+ LDFLAGS="$LDFLAGS $link_static_flag"
+ echo "$as_me:$LINENO: checking whether a statically linked program can dlopen itself" >&5
+echo $ECHO_N "checking whether a statically linked program can dlopen itself... $ECHO_C" >&6
+if test "${lt_cv_dlopen_self_static+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$cross_compiling" = yes; then :
+ lt_cv_dlopen_self_static=cross
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<EOF
+#line 19698 "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+#ifdef __cplusplus
+extern "C" void exit (int);
+#endif
+
+void fnord() { int i=42;}
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ /* dlclose (self); */
+ }
+
+ exit (status);
+}
+EOF
+ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then
+ (./conftest; exit; ) 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;;
+ x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;;
+ x$lt_unknown|x*) lt_cv_dlopen_self_static=no ;;
+ esac
+ else :
+ # compilation failed
+ lt_cv_dlopen_self_static=no
+ fi
+fi
+rm -fr conftest*
+
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_dlopen_self_static" >&5
+echo "${ECHO_T}$lt_cv_dlopen_self_static" >&6
+ fi
+
+ CPPFLAGS="$save_CPPFLAGS"
+ LDFLAGS="$save_LDFLAGS"
+ LIBS="$save_LIBS"
+ ;;
+ esac
+
+ case $lt_cv_dlopen_self in
+ yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+ *) enable_dlopen_self=unknown ;;
+ esac
+
+ case $lt_cv_dlopen_self_static in
+ yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+ *) enable_dlopen_self_static=unknown ;;
+ esac
+fi
+
+
+# The else clause should only fire when bootstrapping the
+# libtool distribution, otherwise you forgot to ship ltmain.sh
+# with your package, and you will get complaints that there are
+# no rules to generate ltmain.sh.
+if test -f "$ltmain"; then
+ # See if we are running on zsh, and set the options which allow our commands through
+ # without removal of \ escapes.
+ if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+ fi
+ # Now quote all the things that may contain metacharacters while being
+ # careful not to overquote the AC_SUBSTed values. We take copies of the
+ # variables and quote the copies for generation of the libtool script.
+ for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC NM \
+ SED SHELL STRIP \
+ libname_spec library_names_spec soname_spec extract_expsyms_cmds \
+ old_striplib striplib file_magic_cmd finish_cmds finish_eval \
+ deplibs_check_method reload_flag reload_cmds need_locks \
+ lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \
+ lt_cv_sys_global_symbol_to_c_name_address \
+ sys_lib_search_path_spec sys_lib_dlsearch_path_spec \
+ old_postinstall_cmds old_postuninstall_cmds \
+ compiler_GCJ \
+ CC_GCJ \
+ LD_GCJ \
+ lt_prog_compiler_wl_GCJ \
+ lt_prog_compiler_pic_GCJ \
+ lt_prog_compiler_static_GCJ \
+ lt_prog_compiler_no_builtin_flag_GCJ \
+ export_dynamic_flag_spec_GCJ \
+ thread_safe_flag_spec_GCJ \
+ whole_archive_flag_spec_GCJ \
+ enable_shared_with_static_runtimes_GCJ \
+ old_archive_cmds_GCJ \
+ old_archive_from_new_cmds_GCJ \
+ predep_objects_GCJ \
+ postdep_objects_GCJ \
+ predeps_GCJ \
+ postdeps_GCJ \
+ compiler_lib_search_path_GCJ \
+ archive_cmds_GCJ \
+ archive_expsym_cmds_GCJ \
+ postinstall_cmds_GCJ \
+ postuninstall_cmds_GCJ \
+ old_archive_from_expsyms_cmds_GCJ \
+ allow_undefined_flag_GCJ \
+ no_undefined_flag_GCJ \
+ export_symbols_cmds_GCJ \
+ hardcode_libdir_flag_spec_GCJ \
+ hardcode_libdir_flag_spec_ld_GCJ \
+ hardcode_libdir_separator_GCJ \
+ hardcode_automatic_GCJ \
+ module_cmds_GCJ \
+ module_expsym_cmds_GCJ \
+ lt_cv_prog_compiler_c_o_GCJ \
+ exclude_expsyms_GCJ \
+ include_expsyms_GCJ; do
+
+ case $var in
+ old_archive_cmds_GCJ | \
+ old_archive_from_new_cmds_GCJ | \
+ archive_cmds_GCJ | \
+ archive_expsym_cmds_GCJ | \
+ module_cmds_GCJ | \
+ module_expsym_cmds_GCJ | \
+ old_archive_from_expsyms_cmds_GCJ | \
+ export_symbols_cmds_GCJ | \
+ extract_expsyms_cmds | reload_cmds | finish_cmds | \
+ postinstall_cmds | postuninstall_cmds | \
+ old_postinstall_cmds | old_postuninstall_cmds | \
+ sys_lib_search_path_spec | sys_lib_dlsearch_path_spec)
+ # Double-quote double-evaled strings.
+ eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\""
+ ;;
+ *)
+ eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\""
+ ;;
+ esac
+ done
+
+ case $lt_echo in
+ *'\$0 --fallback-echo"')
+ lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'`
+ ;;
+ esac
+
+cfgfile="$ofile"
+
+ cat <<__EOF__ >> "$cfgfile"
+# ### BEGIN LIBTOOL TAG CONFIG: $tagname
+
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+
+# Shell to use when invoking shell scripts.
+SHELL=$lt_SHELL
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc_GCJ
+
+# Whether or not to disallow shared libs when runtime libs are static
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_GCJ
+
+# Whether or not to optimize for fast installation.
+fast_install=$enable_fast_install
+
+# The host system.
+host_alias=$host_alias
+host=$host
+
+# An echo program that does not interpret backslashes.
+echo=$lt_echo
+
+# The archiver.
+AR=$lt_AR
+AR_FLAGS=$lt_AR_FLAGS
+
+# A C compiler.
+LTCC=$lt_LTCC
+
+# A language-specific compiler.
+CC=$lt_compiler_GCJ
+
+# Is the compiler the GNU C compiler?
+with_gcc=$GCC_GCJ
+
+# An ERE matcher.
+EGREP=$lt_EGREP
+
+# The linker used to build libraries.
+LD=$lt_LD_GCJ
+
+# Whether we need hard or soft links.
+LN_S=$lt_LN_S
+
+# A BSD-compatible nm program.
+NM=$lt_NM
+
+# A symbol stripping program
+STRIP=$lt_STRIP
+
+# Used to examine libraries when file_magic_cmd begins "file"
+MAGIC_CMD=$MAGIC_CMD
+
+# Used on cygwin: DLL creation program.
+DLLTOOL="$DLLTOOL"
+
+# Used on cygwin: object dumper.
+OBJDUMP="$OBJDUMP"
+
+# Used on cygwin: assembler.
+AS="$AS"
+
+# The name of the directory that contains temporary libtool files.
+objdir=$objdir
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag
+reload_cmds=$lt_reload_cmds
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl_GCJ
+
+# Object file suffix (normally "o").
+objext="$ac_objext"
+
+# Old archive suffix (normally "a").
+libext="$libext"
+
+# Shared library suffix (normally ".so").
+shrext_cmds='$shrext_cmds'
+
+# Executable file suffix (normally "").
+exeext="$exeext"
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic_GCJ
+pic_mode=$pic_mode
+
+# What is the maximum length of a command?
+max_cmd_len=$lt_cv_sys_max_cmd_len
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o_GCJ
+
+# Must we lock files when doing compilation ?
+need_locks=$lt_need_locks
+
+# Do we need the lib prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Whether dlopen is supported.
+dlopen_support=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static_GCJ
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_GCJ
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_GCJ
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec_GCJ
+
+# Compiler flag to generate thread-safe objects.
+thread_safe_flag_spec=$lt_thread_safe_flag_spec_GCJ
+
+# Library versioning type.
+version_type=$version_type
+
+# Format of library name prefix.
+libname_spec=$lt_libname_spec
+
+# List of archive names. First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME.
+library_names_spec=$lt_library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$lt_soname_spec
+
+# Commands used to build and install an old-style archive.
+RANLIB=$lt_RANLIB
+old_archive_cmds=$lt_old_archive_cmds_GCJ
+old_postinstall_cmds=$lt_old_postinstall_cmds
+old_postuninstall_cmds=$lt_old_postuninstall_cmds
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_GCJ
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_GCJ
+
+# Commands used to build and install a shared archive.
+archive_cmds=$lt_archive_cmds_GCJ
+archive_expsym_cmds=$lt_archive_expsym_cmds_GCJ
+postinstall_cmds=$lt_postinstall_cmds
+postuninstall_cmds=$lt_postuninstall_cmds
+
+# Commands used to build a loadable module (assumed same as above if empty)
+module_cmds=$lt_module_cmds_GCJ
+module_expsym_cmds=$lt_module_expsym_cmds_GCJ
+
+# Commands to strip libraries.
+old_striplib=$lt_old_striplib
+striplib=$lt_striplib
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predep_objects=$lt_predep_objects_GCJ
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdep_objects=$lt_postdep_objects_GCJ
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predeps=$lt_predeps_GCJ
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdeps=$lt_postdeps_GCJ
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path=$lt_compiler_lib_search_path_GCJ
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$lt_deplibs_check_method
+
+# Command to use when deplibs_check_method == file_magic.
+file_magic_cmd=$lt_file_magic_cmd
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag_GCJ
+
+# Flag that forces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag_GCJ
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$lt_finish_cmds
+
+# Same as above, but a single script fragment to be evaled but not shown.
+finish_eval=$lt_finish_eval
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration
+global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
+
+# Transform the output of nm in a C name address pair
+global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
+
+# This is the shared library runtime path variable.
+runpath_var=$runpath_var
+
+# This is the shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action_GCJ
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=$hardcode_into_libs
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_GCJ
+
+# If ld is used when linking, flag to hardcode \$libdir into
+# a binary during linking. This must work even if \$libdir does
+# not exist.
+hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_GCJ
+
+# Whether we need a single -rpath flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator_GCJ
+
+# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the
+# resulting binary.
+hardcode_direct=$hardcode_direct_GCJ
+
+# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
+# resulting binary.
+hardcode_minus_L=$hardcode_minus_L_GCJ
+
+# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into
+# the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var_GCJ
+
+# Set to yes if building a shared library automatically hardcodes DIR into the library
+# and all subsequent libraries and executables linked against it.
+hardcode_automatic=$hardcode_automatic_GCJ
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at relink time.
+variables_saved_for_relink="$variables_saved_for_relink"
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs_GCJ
+
+# Compile-time system search path for libraries
+sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+
+# Run-time system search path for libraries
+sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
+
+# Fix the shell variable \$srcfile for the compiler.
+fix_srcfile_path="$fix_srcfile_path_GCJ"
+
+# Set to yes if exported symbols are required.
+always_export_symbols=$always_export_symbols_GCJ
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds_GCJ
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=$lt_extract_expsyms_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms_GCJ
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms_GCJ
+
+# ### END LIBTOOL TAG CONFIG: $tagname
+
+__EOF__
+
+
+else
+ # If there is no Makefile yet, we rely on a make rule to execute
+ # `config.status --recheck' to rerun these tests and create the
+ # libtool script then.
+ ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'`
+ if test -f "$ltmain_in"; then
+ test -f Makefile && make "$ltmain"
+ fi
+fi
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+CC="$lt_save_CC"
+
+ else
+ tagname=""
+ fi
+ ;;
+
+ RC)
+
+
+
+# Source file extension for RC test sources.
+ac_ext=rc
+
+# Object file extension for compiled RC test sources.
+objext=o
+objext_RC=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }\n'
+
+# Code to be used in simple link tests
+lt_simple_link_test_code="$lt_simple_compile_test_code"
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+CC=${RC-"windres"}
+compiler=$CC
+compiler_RC=$CC
+lt_cv_prog_compiler_c_o_RC=yes
+
+# The else clause should only fire when bootstrapping the
+# libtool distribution, otherwise you forgot to ship ltmain.sh
+# with your package, and you will get complaints that there are
+# no rules to generate ltmain.sh.
+if test -f "$ltmain"; then
+ # See if we are running on zsh, and set the options which allow our commands through
+ # without removal of \ escapes.
+ if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+ fi
+ # Now quote all the things that may contain metacharacters while being
+ # careful not to overquote the AC_SUBSTed values. We take copies of the
+ # variables and quote the copies for generation of the libtool script.
+ for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC NM \
+ SED SHELL STRIP \
+ libname_spec library_names_spec soname_spec extract_expsyms_cmds \
+ old_striplib striplib file_magic_cmd finish_cmds finish_eval \
+ deplibs_check_method reload_flag reload_cmds need_locks \
+ lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \
+ lt_cv_sys_global_symbol_to_c_name_address \
+ sys_lib_search_path_spec sys_lib_dlsearch_path_spec \
+ old_postinstall_cmds old_postuninstall_cmds \
+ compiler_RC \
+ CC_RC \
+ LD_RC \
+ lt_prog_compiler_wl_RC \
+ lt_prog_compiler_pic_RC \
+ lt_prog_compiler_static_RC \
+ lt_prog_compiler_no_builtin_flag_RC \
+ export_dynamic_flag_spec_RC \
+ thread_safe_flag_spec_RC \
+ whole_archive_flag_spec_RC \
+ enable_shared_with_static_runtimes_RC \
+ old_archive_cmds_RC \
+ old_archive_from_new_cmds_RC \
+ predep_objects_RC \
+ postdep_objects_RC \
+ predeps_RC \
+ postdeps_RC \
+ compiler_lib_search_path_RC \
+ archive_cmds_RC \
+ archive_expsym_cmds_RC \
+ postinstall_cmds_RC \
+ postuninstall_cmds_RC \
+ old_archive_from_expsyms_cmds_RC \
+ allow_undefined_flag_RC \
+ no_undefined_flag_RC \
+ export_symbols_cmds_RC \
+ hardcode_libdir_flag_spec_RC \
+ hardcode_libdir_flag_spec_ld_RC \
+ hardcode_libdir_separator_RC \
+ hardcode_automatic_RC \
+ module_cmds_RC \
+ module_expsym_cmds_RC \
+ lt_cv_prog_compiler_c_o_RC \
+ exclude_expsyms_RC \
+ include_expsyms_RC; do
+
+ case $var in
+ old_archive_cmds_RC | \
+ old_archive_from_new_cmds_RC | \
+ archive_cmds_RC | \
+ archive_expsym_cmds_RC | \
+ module_cmds_RC | \
+ module_expsym_cmds_RC | \
+ old_archive_from_expsyms_cmds_RC | \
+ export_symbols_cmds_RC | \
+ extract_expsyms_cmds | reload_cmds | finish_cmds | \
+ postinstall_cmds | postuninstall_cmds | \
+ old_postinstall_cmds | old_postuninstall_cmds | \
+ sys_lib_search_path_spec | sys_lib_dlsearch_path_spec)
+ # Double-quote double-evaled strings.
+ eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\""
+ ;;
+ *)
+ eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\""
+ ;;
+ esac
+ done
+
+ case $lt_echo in
+ *'\$0 --fallback-echo"')
+ lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'`
+ ;;
+ esac
+
+cfgfile="$ofile"
+
+ cat <<__EOF__ >> "$cfgfile"
+# ### BEGIN LIBTOOL TAG CONFIG: $tagname
+
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+
+# Shell to use when invoking shell scripts.
+SHELL=$lt_SHELL
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc_RC
+
+# Whether or not to disallow shared libs when runtime libs are static
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_RC
+
+# Whether or not to optimize for fast installation.
+fast_install=$enable_fast_install
+
+# The host system.
+host_alias=$host_alias
+host=$host
+
+# An echo program that does not interpret backslashes.
+echo=$lt_echo
+
+# The archiver.
+AR=$lt_AR
+AR_FLAGS=$lt_AR_FLAGS
+
+# A C compiler.
+LTCC=$lt_LTCC
+
+# A language-specific compiler.
+CC=$lt_compiler_RC
+
+# Is the compiler the GNU C compiler?
+with_gcc=$GCC_RC
+
+# An ERE matcher.
+EGREP=$lt_EGREP
+
+# The linker used to build libraries.
+LD=$lt_LD_RC
+
+# Whether we need hard or soft links.
+LN_S=$lt_LN_S
+
+# A BSD-compatible nm program.
+NM=$lt_NM
+
+# A symbol stripping program
+STRIP=$lt_STRIP
+
+# Used to examine libraries when file_magic_cmd begins "file"
+MAGIC_CMD=$MAGIC_CMD
+
+# Used on cygwin: DLL creation program.
+DLLTOOL="$DLLTOOL"
+
+# Used on cygwin: object dumper.
+OBJDUMP="$OBJDUMP"
+
+# Used on cygwin: assembler.
+AS="$AS"
+
+# The name of the directory that contains temporary libtool files.
+objdir=$objdir
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag
+reload_cmds=$lt_reload_cmds
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl_RC
+
+# Object file suffix (normally "o").
+objext="$ac_objext"
+
+# Old archive suffix (normally "a").
+libext="$libext"
+
+# Shared library suffix (normally ".so").
+shrext_cmds='$shrext_cmds'
+
+# Executable file suffix (normally "").
+exeext="$exeext"
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic_RC
+pic_mode=$pic_mode
+
+# What is the maximum length of a command?
+max_cmd_len=$lt_cv_sys_max_cmd_len
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o_RC
+
+# Must we lock files when doing compilation ?
+need_locks=$lt_need_locks
+
+# Do we need the lib prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Whether dlopen is supported.
+dlopen_support=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static_RC
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_RC
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_RC
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec_RC
+
+# Compiler flag to generate thread-safe objects.
+thread_safe_flag_spec=$lt_thread_safe_flag_spec_RC
+
+# Library versioning type.
+version_type=$version_type
+
+# Format of library name prefix.
+libname_spec=$lt_libname_spec
+
+# List of archive names. First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME.
+library_names_spec=$lt_library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$lt_soname_spec
+
+# Commands used to build and install an old-style archive.
+RANLIB=$lt_RANLIB
+old_archive_cmds=$lt_old_archive_cmds_RC
+old_postinstall_cmds=$lt_old_postinstall_cmds
+old_postuninstall_cmds=$lt_old_postuninstall_cmds
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_RC
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_RC
+
+# Commands used to build and install a shared archive.
+archive_cmds=$lt_archive_cmds_RC
+archive_expsym_cmds=$lt_archive_expsym_cmds_RC
+postinstall_cmds=$lt_postinstall_cmds
+postuninstall_cmds=$lt_postuninstall_cmds
+
+# Commands used to build a loadable module (assumed same as above if empty)
+module_cmds=$lt_module_cmds_RC
+module_expsym_cmds=$lt_module_expsym_cmds_RC
+
+# Commands to strip libraries.
+old_striplib=$lt_old_striplib
+striplib=$lt_striplib
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predep_objects=$lt_predep_objects_RC
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdep_objects=$lt_postdep_objects_RC
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predeps=$lt_predeps_RC
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdeps=$lt_postdeps_RC
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path=$lt_compiler_lib_search_path_RC
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$lt_deplibs_check_method
+
+# Command to use when deplibs_check_method == file_magic.
+file_magic_cmd=$lt_file_magic_cmd
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag_RC
+
+# Flag that forces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag_RC
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$lt_finish_cmds
+
+# Same as above, but a single script fragment to be evaled but not shown.
+finish_eval=$lt_finish_eval
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration
+global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
+
+# Transform the output of nm in a C name address pair
+global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
+
+# This is the shared library runtime path variable.
+runpath_var=$runpath_var
+
+# This is the shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action_RC
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=$hardcode_into_libs
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_RC
+
+# If ld is used when linking, flag to hardcode \$libdir into
+# a binary during linking. This must work even if \$libdir does
+# not exist.
+hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_RC
+
+# Whether we need a single -rpath flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator_RC
+
+# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the
+# resulting binary.
+hardcode_direct=$hardcode_direct_RC
+
+# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
+# resulting binary.
+hardcode_minus_L=$hardcode_minus_L_RC
+
+# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into
+# the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var_RC
+
+# Set to yes if building a shared library automatically hardcodes DIR into the library
+# and all subsequent libraries and executables linked against it.
+hardcode_automatic=$hardcode_automatic_RC
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at relink time.
+variables_saved_for_relink="$variables_saved_for_relink"
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs_RC
+
+# Compile-time system search path for libraries
+sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+
+# Run-time system search path for libraries
+sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
+
+# Fix the shell variable \$srcfile for the compiler.
+fix_srcfile_path="$fix_srcfile_path_RC"
+
+# Set to yes if exported symbols are required.
+always_export_symbols=$always_export_symbols_RC
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds_RC
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=$lt_extract_expsyms_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms_RC
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms_RC
+
+# ### END LIBTOOL TAG CONFIG: $tagname
+
+__EOF__
+
+
+else
+ # If there is no Makefile yet, we rely on a make rule to execute
+ # `config.status --recheck' to rerun these tests and create the
+ # libtool script then.
+ ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'`
+ if test -f "$ltmain_in"; then
+ test -f Makefile && make "$ltmain"
+ fi
+fi
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+CC="$lt_save_CC"
+
+ ;;
+
+ *)
+ { { echo "$as_me:$LINENO: error: Unsupported tag name: $tagname" >&5
+echo "$as_me: error: Unsupported tag name: $tagname" >&2;}
+ { (exit 1); exit 1; }; }
+ ;;
+ esac
+
+ # Append the new tag name to the list of available tags.
+ if test -n "$tagname" ; then
+ available_tags="$available_tags $tagname"
+ fi
+ fi
+ done
+ IFS="$lt_save_ifs"
+
+ # Now substitute the updated list of available tags.
+ if eval "sed -e 's/^available_tags=.*\$/available_tags=\"$available_tags\"/' \"$ofile\" > \"${ofile}T\""; then
+ mv "${ofile}T" "$ofile"
+ chmod +x "$ofile"
+ else
+ rm -f "${ofile}T"
+ { { echo "$as_me:$LINENO: error: unable to update list of available tagged configurations." >&5
+echo "$as_me: error: unable to update list of available tagged configurations." >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+fi
+
+
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh"
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+
+# Prevent multiple expansion
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# Check whether --enable-ndebug or --disable-ndebug was given.
+if test "${enable_ndebug+set}" = set; then
+ enableval="$enable_ndebug"
+
+else
+ enable_ndebug=no
+fi;
+
+
+if test x$enable_ndebug = yes; then
+ NDEBUG_TRUE=
+ NDEBUG_FALSE='#'
+else
+ NDEBUG_TRUE='#'
+ NDEBUG_FALSE=
+fi
+
+SOFIA_CFLAGS="$SOFIA_CFLAGS -DNDEBUG"
+
+
+# Check whether --enable-expensive-checks or --disable-expensive-checks was given.
+if test "${enable_expensive_checks+set}" = set; then
+ enableval="$enable_expensive_checks"
+
+else
+ enable_expensive_checks=no
+fi;
+if test $enable_expensive_checks != no; then
+TESTS_ENVIRONMENT=EXPENSIVE_CHECKS=1
+
+fi
+
+
+if test x$enable_expensive_checks != no; then
+ EXPENSIVE_CHECKS_TRUE=
+ EXPENSIVE_CHECKS_FALSE='#'
+else
+ EXPENSIVE_CHECKS_TRUE='#'
+ EXPENSIVE_CHECKS_FALSE=
+fi
+
+
+
+ACLOCAL_AMFLAGS="-I m4"
+
+
+# Extract the first word of "doxygen", so it can be a program name with args.
+set dummy doxygen; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_DOXYGEN+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$DOXYGEN"; then
+ ac_cv_prog_DOXYGEN="$DOXYGEN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_DOXYGEN="doxygen"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ test -z "$ac_cv_prog_DOXYGEN" && ac_cv_prog_DOXYGEN="echo"
+fi
+fi
+DOXYGEN=$ac_cv_prog_DOXYGEN
+if test -n "$DOXYGEN"; then
+ echo "$as_me:$LINENO: result: $DOXYGEN" >&5
+echo "${ECHO_T}$DOXYGEN" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+
+
+if test $DOXYGEN = doxygen; then
+ HAVE_DOXYGEN_TRUE=
+ HAVE_DOXYGEN_FALSE='#'
+else
+ HAVE_DOXYGEN_TRUE='#'
+ HAVE_DOXYGEN_FALSE=
+fi
+
+
+### checks for libraries
+### --------------------
+
+
+
+# Check whether --with-rt or --without-rt was given.
+if test "${with_rt+set}" = set; then
+ withval="$with_rt"
+
+fi;
+
+echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5
+echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6
+if test "${ac_cv_c_const+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+/* FIXME: Include the comments suggested by Paul. */
+#ifndef __cplusplus
+ /* Ultrix mips cc rejects this. */
+ typedef int charset[2];
+ const charset x;
+ /* SunOS 4.1.1 cc rejects this. */
+ char const *const *ccp;
+ char **p;
+ /* NEC SVR4.0.2 mips cc rejects this. */
+ struct point {int x, y;};
+ static struct point const zero = {0,0};
+ /* AIX XL C 1.02.0.0 rejects this.
+ It does not let you subtract one const X* pointer from another in
+ an arm of an if-expression whose if-part is not a constant
+ expression */
+ const char *g = "string";
+ ccp = &g + (g ? g-g : 0);
+ /* HPUX 7.0 cc rejects these. */
+ ++ccp;
+ p = (char**) ccp;
+ ccp = (char const *const *) p;
+ { /* SCO 3.2v4 cc rejects this. */
+ char *t;
+ char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+ *t++ = 0;
+ }
+ { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */
+ int x[] = {25, 17};
+ const int *foo = &x[0];
+ ++foo;
+ }
+ { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+ typedef const int *iptr;
+ iptr p = 0;
+ ++p;
+ }
+ { /* AIX XL C 1.02.0.0 rejects this saying
+ "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+ struct s { int j; const int *ap[3]; };
+ struct s *b; b->j = 5;
+ }
+ { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+ const int foo = 10;
+ }
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_c_const=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_c_const=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5
+echo "${ECHO_T}$ac_cv_c_const" >&6
+if test $ac_cv_c_const = no; then
+
+cat >>confdefs.h <<\_ACEOF
+#define const
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking whether time.h and sys/time.h may both be included" >&5
+echo $ECHO_N "checking whether time.h and sys/time.h may both be included... $ECHO_C" >&6
+if test "${ac_cv_header_time+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+
+int
+main ()
+{
+if ((struct tm *) 0)
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_header_time=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_header_time=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_time" >&5
+echo "${ECHO_T}$ac_cv_header_time" >&6
+if test $ac_cv_header_time = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define TIME_WITH_SYS_TIME 1
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for size_t" >&5
+echo $ECHO_N "checking for size_t... $ECHO_C" >&6
+if test "${ac_cv_type_size_t+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+if ((size_t *) 0)
+ return 0;
+if (sizeof (size_t))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_type_size_t=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_size_t=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_size_t" >&5
+echo "${ECHO_T}$ac_cv_type_size_t" >&6
+if test $ac_cv_type_size_t = yes; then
+ :
+else
+
+cat >>confdefs.h <<_ACEOF
+#define size_t unsigned
+_ACEOF
+
+fi
+
+
+echo "$as_me:$LINENO: checking whether $CC recognizes __func__" >&5
+echo $ECHO_N "checking whether $CC recognizes __func__... $ECHO_C" >&6
+if test "${ac_cv_c_var_func+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+char *s = __func__;
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_c_var_func=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_c_var_func=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_var_func" >&5
+echo "${ECHO_T}$ac_cv_c_var_func" >&6
+if test $ac_cv_c_var_func = "yes"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_FUNC 1
+_ACEOF
+
+fi
+
+
+echo "$as_me:$LINENO: checking whether $CC recognizes __FUNCTION__" >&5
+echo $ECHO_N "checking whether $CC recognizes __FUNCTION__... $ECHO_C" >&6
+if test "${ac_cv_c_macro_function+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+char *s = __FUNCTION__;
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_c_macro_function=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_c_macro_function=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_macro_function" >&5
+echo "${ECHO_T}$ac_cv_c_macro_function" >&6
+if test $ac_cv_c_macro_function = "yes"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_FUNCTION 1
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for inline" >&5
+echo $ECHO_N "checking for inline... $ECHO_C" >&6
+if test "${ac_cv_c_inline+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_c_inline=no
+for ac_kw in inline __inline__ __inline; do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifndef __cplusplus
+typedef int foo_t;
+static $ac_kw foo_t static_foo () {return 0; }
+$ac_kw foo_t foo () {return 0; }
+#endif
+
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_c_inline=$ac_kw; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_inline" >&5
+echo "${ECHO_T}$ac_cv_c_inline" >&6
+
+
+case $ac_cv_c_inline in
+ inline | yes) ;;
+ *)
+ case $ac_cv_c_inline in
+ no) ac_val=;;
+ *) ac_val=$ac_cv_c_inline;;
+ esac
+ cat >>confdefs.h <<_ACEOF
+#ifndef __cplusplus
+#define inline $ac_val
+#endif
+_ACEOF
+ ;;
+esac
+
+
+echo "$as_me:$LINENO: checking for sa_len" >&5
+echo $ECHO_N "checking for sa_len... $ECHO_C" >&6
+if test "${ac_cv_sa_len+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <sys/socket.h>
+int
+main ()
+{
+
+ struct sockaddr t;t.sa_len = 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_sa_len=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_sa_len=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_sa_len" >&5
+echo "${ECHO_T}$ac_cv_sa_len" >&6
+if test "$ac_cv_sa_len" = yes ;then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SA_LEN 1
+_ACEOF
+
+fi
+
+
+echo "$as_me:$LINENO: checking for sockaddr_in6" >&5
+echo $ECHO_N "checking for sockaddr_in6... $ECHO_C" >&6
+if test "${ac_cv_sin6+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <netinet/in.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "struct sockaddr_in6" >/dev/null 2>&1; then
+ ac_cv_sin6=yes
+else
+ ac_cv_sin6=no
+fi
+rm -f conftest*
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_sin6" >&5
+echo "${ECHO_T}$ac_cv_sin6" >&6
+if test $ac_cv_sin6 = yes ;then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SIN6 1
+_ACEOF
+
+fi
+
+
+# Beginning of SAC_SOFIA_SU
+
+
+
+# ======================================================================
+# Check for features used by su
+
+
+case "$target" in
+*-*-solaris?.* )
+
+cat >>confdefs.h <<\_AXEOF
+#define __EXTENSIONS__ 1
+_AXEOF
+
+;;
+esac
+
+# Check includes used by su includes
+if test "${ac_cv_header_sys_types_h+set}" = set; then
+ echo "$as_me:$LINENO: checking for sys/types.h" >&5
+echo $ECHO_N "checking for sys/types.h... $ECHO_C" >&6
+if test "${ac_cv_header_sys_types_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_sys_types_h" >&5
+echo "${ECHO_T}$ac_cv_header_sys_types_h" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking sys/types.h usability" >&5
+echo $ECHO_N "checking sys/types.h usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <sys/types.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking sys/types.h presence" >&5
+echo $ECHO_N "checking sys/types.h presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/types.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: sys/types.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: sys/types.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: sys/types.h: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: sys/types.h: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: sys/types.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: sys/types.h: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: sys/types.h: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: sys/types.h: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: sys/types.h: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: sys/types.h: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: sys/types.h: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: sys/types.h: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: sys/types.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: sys/types.h: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: sys/types.h: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: sys/types.h: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to the sofia-sip lists. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for sys/types.h" >&5
+echo $ECHO_N "checking for sys/types.h... $ECHO_C" >&6
+if test "${ac_cv_header_sys_types_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_header_sys_types_h=$ac_header_preproc
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_sys_types_h" >&5
+echo "${ECHO_T}$ac_cv_header_sys_types_h" >&6
+
+fi
+if test $ac_cv_header_sys_types_h = yes; then
+
+cat >>confdefs.h <<\_AXEOF
+#define SU_HAVE_SYS_TYPES 1
+_AXEOF
+
+fi
+
+
+
+ax_inttypes=false
+if test "${ac_cv_header_stdint_h+set}" = set; then
+ echo "$as_me:$LINENO: checking for stdint.h" >&5
+echo $ECHO_N "checking for stdint.h... $ECHO_C" >&6
+if test "${ac_cv_header_stdint_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_stdint_h" >&5
+echo "${ECHO_T}$ac_cv_header_stdint_h" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking stdint.h usability" >&5
+echo $ECHO_N "checking stdint.h usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <stdint.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking stdint.h presence" >&5
+echo $ECHO_N "checking stdint.h presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdint.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: stdint.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: stdint.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: stdint.h: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: stdint.h: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: stdint.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: stdint.h: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: stdint.h: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: stdint.h: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: stdint.h: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: stdint.h: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: stdint.h: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: stdint.h: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: stdint.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: stdint.h: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: stdint.h: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: stdint.h: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to the sofia-sip lists. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for stdint.h" >&5
+echo $ECHO_N "checking for stdint.h... $ECHO_C" >&6
+if test "${ac_cv_header_stdint_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_header_stdint_h=$ac_header_preproc
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_stdint_h" >&5
+echo "${ECHO_T}$ac_cv_header_stdint_h" >&6
+
+fi
+if test $ac_cv_header_stdint_h = yes; then
+
+ ax_inttypes=true
+
+cat >>confdefs.h <<\_AXEOF
+#define SU_HAVE_STDINT 1
+_AXEOF
+
+fi
+
+
+if test "${ac_cv_header_inttypes_h+set}" = set; then
+ echo "$as_me:$LINENO: checking for inttypes.h" >&5
+echo $ECHO_N "checking for inttypes.h... $ECHO_C" >&6
+if test "${ac_cv_header_inttypes_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_inttypes_h" >&5
+echo "${ECHO_T}$ac_cv_header_inttypes_h" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking inttypes.h usability" >&5
+echo $ECHO_N "checking inttypes.h usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <inttypes.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking inttypes.h presence" >&5
+echo $ECHO_N "checking inttypes.h presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <inttypes.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: inttypes.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: inttypes.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: inttypes.h: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: inttypes.h: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: inttypes.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: inttypes.h: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: inttypes.h: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: inttypes.h: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: inttypes.h: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: inttypes.h: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: inttypes.h: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: inttypes.h: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: inttypes.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: inttypes.h: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: inttypes.h: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: inttypes.h: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to the sofia-sip lists. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for inttypes.h" >&5
+echo $ECHO_N "checking for inttypes.h... $ECHO_C" >&6
+if test "${ac_cv_header_inttypes_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_header_inttypes_h=$ac_header_preproc
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_inttypes_h" >&5
+echo "${ECHO_T}$ac_cv_header_inttypes_h" >&6
+
+fi
+if test $ac_cv_header_inttypes_h = yes; then
+
+ ax_inttypes=true
+
+cat >>confdefs.h <<\_AXEOF
+#define SU_HAVE_INTTYPES 1
+_AXEOF
+
+fi
+
+
+
+if $ax_inttypes; then : ; else
+ { { echo "$as_me:$LINENO: error: \"No <stdint.h> or <inttypes.h> found.\"" >&5
+echo "$as_me: error: \"No <stdint.h> or <inttypes.h> found.\"" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+if test "x$MINGW_ENVIRONMENT" != x1 ; then
+ if test "${ac_cv_header_pthread_h+set}" = set; then
+ echo "$as_me:$LINENO: checking for pthread.h" >&5
+echo $ECHO_N "checking for pthread.h... $ECHO_C" >&6
+if test "${ac_cv_header_pthread_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_pthread_h" >&5
+echo "${ECHO_T}$ac_cv_header_pthread_h" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking pthread.h usability" >&5
+echo $ECHO_N "checking pthread.h usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <pthread.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking pthread.h presence" >&5
+echo $ECHO_N "checking pthread.h presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <pthread.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: pthread.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: pthread.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: pthread.h: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: pthread.h: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: pthread.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: pthread.h: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: pthread.h: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: pthread.h: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: pthread.h: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: pthread.h: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: pthread.h: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: pthread.h: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: pthread.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: pthread.h: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: pthread.h: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: pthread.h: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to the sofia-sip lists. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for pthread.h" >&5
+echo $ECHO_N "checking for pthread.h... $ECHO_C" >&6
+if test "${ac_cv_header_pthread_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_header_pthread_h=$ac_header_preproc
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_pthread_h" >&5
+echo "${ECHO_T}$ac_cv_header_pthread_h" >&6
+
+fi
+if test $ac_cv_header_pthread_h = yes; then
+ HAVE_PTHREADS=1;
+
+cat >>confdefs.h <<\_AXEOF
+#define SU_HAVE_PTHREADS 1
+_AXEOF
+
+fi
+
+
+else
+ HAVE_PTHREADS=1;
+
+cat >>confdefs.h <<\_AXEOF
+#define SU_HAVE_PTHREADS 1
+_AXEOF
+
+fi
+
+
+
+
+
+
+
+
+
+
+case "$ac_cv_c_inline" in
+ yes)
+cat >>confdefs.h <<\_AXEOF
+#define su_inline static inline
+_AXEOF
+
+cat >>confdefs.h <<\_AXEOF
+#define SU_INLINE inline
+_AXEOF
+
+cat >>confdefs.h <<\_AXEOF
+#define SU_HAVE_INLINE 1
+_AXEOF
+ ;;
+ no)
+cat >>confdefs.h <<\_AXEOF
+#define su_inline static
+_AXEOF
+
+cat >>confdefs.h <<\_AXEOF
+#define SU_INLINE 1
+_AXEOF
+
+cat >>confdefs.h <<\_AXEOF
+#define SU_HAVE_INLINE 1
+_AXEOF
+ ;;
+ *)
+cat >>confdefs.h <<_ACEOF
+#define su_inline static $ac_cv_c_inline
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define SU_INLINE $ac_cv_c_inline
+_ACEOF
+
+cat >>confdefs.h <<\_AXEOF
+#define SU_HAVE_INLINE 1
+_AXEOF
+ ;;
+esac
+
+# Check whether --enable-size-compat or --disable-size-compat was given.
+if test "${enable_size_compat+set}" = set; then
+ enableval="$enable_size_compat"
+
+else
+ enable_size_compat=yes
+fi;
+
+if test X$enable_size_compat != Xyes; then
+
+cat >>confdefs.h <<\_AXEOF
+#define SOFIA_ISIZE_T size_t
+_AXEOF
+
+cat >>confdefs.h <<\_AXEOF
+#define ISIZE_MAX SIZE_MAX
+_AXEOF
+
+cat >>confdefs.h <<\_AXEOF
+#define SOFIA_ISSIZE_T ssize_t
+_AXEOF
+
+cat >>confdefs.h <<\_AXEOF
+#define ISSIZE_MAX SSIZE_MAX
+_AXEOF
+
+cat >>confdefs.h <<\_AXEOF
+#define SOFIA_USIZE_T size_t
+_AXEOF
+
+cat >>confdefs.h <<\_AXEOF
+#define USIZE_MAX SIZE_MAX
+_AXEOF
+else
+
+cat >>confdefs.h <<\_AXEOF
+#define SOFIA_ISIZE_T int
+_AXEOF
+
+cat >>confdefs.h <<\_AXEOF
+#define ISIZE_MAX INT_MAX
+_AXEOF
+
+cat >>confdefs.h <<\_AXEOF
+#define SOFIA_ISSIZE_T int
+_AXEOF
+
+cat >>confdefs.h <<\_AXEOF
+#define ISSIZE_MAX INT_MAX
+_AXEOF
+
+cat >>confdefs.h <<\_AXEOF
+#define SOFIA_USIZE_T unsigned
+_AXEOF
+
+cat >>confdefs.h <<\_AXEOF
+#define USIZE_MAX UINT_MAX
+_AXEOF
+fi
+
+
+# Check whether --enable-corefoundation or --disable-corefoundation was given.
+if test "${enable_corefoundation+set}" = set; then
+ enableval="$enable_corefoundation"
+
+else
+ enable_corefoundation=no
+fi;
+
+
+if test $enable_corefoundation = yes; then
+ COREFOUNDATION_TRUE=
+ COREFOUNDATION_FALSE='#'
+else
+ COREFOUNDATION_TRUE='#'
+ COREFOUNDATION_FALSE=
+fi
+
+
+if test $enable_corefoundation = yes ; then
+
+cat >>confdefs.h <<\_AXEOF
+#define SU_HAVE_OSX_CF_API 1
+_AXEOF
+
+ LIBS="-framework CoreFoundation -framework SystemConfiguration $LIBS"
+fi
+
+
+### ======================================================================
+### Test if we have stack suitable for handling tags directly
+###
+
+test -z "$ac_cv_tagstack" &&
+case "$target" in
+i?86-*-* ) ac_cv_tagstack=yes ;;
+esac
+
+echo "$as_me:$LINENO: checking for stack suitable for tags" >&5
+echo $ECHO_N "checking for stack suitable for tags... $ECHO_C" >&6
+if test "${ac_cv_tagstack+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ac_cv_tagstack=no
+
+if test "$cross_compiling" = yes; then
+ ac_cv_tagstack=no
+else
+ cat >conftest.$ac_ext <<_ACEOF
+
+#if HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+#if HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#include <stdarg.h>
+
+typedef void *tp;
+typedef intptr_t tv;
+
+int test1(tv l, tv h, ...)
+{
+ va_list ap;
+ tv i, *p = &l;
+
+ va_start(ap, h);
+
+ if (*p++ != l || *p++ != h) return 1;
+
+ for (i = l; i <= h; i++) {
+ if (*p++ != i)
+ return 1;
+ }
+
+ for (i = l; i <= h; i++) {
+ if (va_arg(ap, tv) != i)
+ return 1;
+ }
+
+ va_end(ap);
+
+ return 0;
+}
+
+int main(int avc, char **av)
+{
+ return test1((tv)1, (tv)10,
+ (tv)1, (tv)2, (tv)3, (tv)4, (tv)5,
+ (tv)6, (tv)7, (tv)8, (tv)9, (tv)10);
+}
+
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_tagstack=yes
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_tagstack=no
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_tagstack" >&5
+echo "${ECHO_T}$ac_cv_tagstack" >&6
+
+if test $ac_cv_tagstack = yes ; then
+
+cat >>confdefs.h <<\_AXEOF
+#define SU_HAVE_TAGSTACK 1
+_AXEOF
+
+fi
+
+
+
+if test "$ac_cv_sa_len" = yes ;then
+
+cat >>confdefs.h <<\_AXEOF
+#define SU_HAVE_SOCKADDR_SA_LEN 1
+_AXEOF
+
+fi
+
+
+case $ac_cv_sin6 in
+yes)
+cat >>confdefs.h <<\_AXEOF
+#define SU_HAVE_IN6 1
+_AXEOF
+ ;;
+ no) ;;
+ *) { { echo "$as_me:$LINENO: error: Inconsistent struct sockaddr_sin6 test" >&5
+echo "$as_me: error: Inconsistent struct sockaddr_sin6 test" >&2;}
+ { (exit 1); exit 1; }; } ;;
+esac
+
+
+
+for ac_header in unistd.h sys/time.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to the sofia-sip lists. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+
+for ac_header in fcntl.h dirent.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to the sofia-sip lists. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+for ac_header in winsock2.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to the sofia-sip lists. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_WIN32 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_AXEOF
+#define SU_HAVE_WINSOCK 1
+_AXEOF
+
+
+cat >>confdefs.h <<\_AXEOF
+#define SU_HAVE_WINSOCK2 1
+_AXEOF
+
+
+cat >>confdefs.h <<\_AXEOF
+#define SU_HAVE_SOCKADDR_STORAGE 1
+_AXEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_ADDRINFO 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_GETADDRINFO 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_FREEADDRINFO 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_AXEOF
+#define SU_HAVE_ADDRINFO 1
+_AXEOF
+
+
+
+for ac_header in windef.h ws2tcpip.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to the sofia-sip lists. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in iphlpapi.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#if HAVE_WINDEF_H
+#include <windef.h>
+#include <winbase.h>
+#endif
+
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_Header=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_Header=no"
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_INTERFACE_INFO_EX 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SIO_ADDRESS_LIST_QUERY 1
+_ACEOF
+
+
+fi
+
+done
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_FILETIME 1
+_ACEOF
+
+
+else
+
+
+cat >>confdefs.h <<\_AXEOF
+#define SU_HAVE_BSDSOCK 1
+_AXEOF
+
+
+
+
+
+
+for ac_header in sys/socket.h sys/ioctl.h sys/filio.h sys/sockio.h \
+ sys/select.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to the sofia-sip lists. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+
+
+
+
+
+for ac_header in netinet/in.h arpa/inet.h netdb.h \
+ net/if.h net/if_types.h ifaddr.h netpacket/packet.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_Header=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_Header=no"
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+echo "$as_me:$LINENO: checking whether MSG_TRUNC is declared" >&5
+echo $ECHO_N "checking whether MSG_TRUNC is declared... $ECHO_C" >&6
+if test "${ac_cv_have_decl_MSG_TRUNC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+int
+main ()
+{
+#ifndef MSG_TRUNC
+ char *p = (char *) MSG_TRUNC;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_have_decl_MSG_TRUNC=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_have_decl_MSG_TRUNC=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_have_decl_MSG_TRUNC" >&5
+echo "${ECHO_T}$ac_cv_have_decl_MSG_TRUNC" >&6
+if test $ac_cv_have_decl_MSG_TRUNC = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_MSG_TRUNC 1
+_ACEOF
+
+fi
+
+
+echo "$as_me:$LINENO: checking for struct addrinfo" >&5
+echo $ECHO_N "checking for struct addrinfo... $ECHO_C" >&6
+if test "${ac_cv_struct_addrinfo+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ac_cv_struct_addrinfo=no
+if test "$ac_cv_header_sys_socket_h" = yes; then
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <netdb.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "struct.+addrinfo" >/dev/null 2>&1; then
+
+ ac_cv_struct_addrinfo=yes
+fi
+rm -f conftest*
+
+else
+ ac_cv_struct_addrinfo='sys/socket.h missing'
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_struct_addrinfo" >&5
+echo "${ECHO_T}$ac_cv_struct_addrinfo" >&6
+
+if test "$ac_cv_struct_addrinfo" = yes; then
+
+cat >>confdefs.h <<\_AXEOF
+#define SU_HAVE_ADDRINFO 1
+_AXEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for struct sockaddr_storage" >&5
+echo $ECHO_N "checking for struct sockaddr_storage... $ECHO_C" >&6
+if test "${ac_cv_struct_sockaddr_storage+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ac_cv_struct_sockaddr_storage=no
+if test "$ac_cv_header_sys_socket_h" = yes; then
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/socket.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "struct.+sockaddr_storage" >/dev/null 2>&1; then
+
+ ac_cv_struct_sockaddr_storage=yes
+fi
+rm -f conftest*
+
+else
+ ac_cv_struct_sockaddr_storage='sys/socket.h missing'
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_struct_sockaddr_storage" >&5
+echo "${ECHO_T}$ac_cv_struct_sockaddr_storage" >&6
+if test "$ac_cv_struct_sockaddr_storage" = yes; then
+
+cat >>confdefs.h <<\_AXEOF
+#define SU_HAVE_SOCKADDR_STORAGE 1
+_AXEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for field ifr_index in struct ifreq" >&5
+echo $ECHO_N "checking for field ifr_index in struct ifreq... $ECHO_C" >&6
+if test "${ac_cv_struct_ifreq_ifr_index+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ac_cv_struct_ifreq_ifr_index=no
+if test "1${ac_cv_header_arpa_inet_h}2${ac_cv_header_netdb_h}3${ac_cv_header_sys_socket_h}4${ac_cv_header_net_if_h}" = 1yes2yes3yes4yes; then
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <net/if.h>
+int
+main ()
+{
+
+struct ifreq ifreq; int index; index = ifreq.ifr_index;
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_struct_ifreq_ifr_index=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+ ac_cv_struct_ifreq_ifr_index='net/if.h missing'
+fi # arpa/inet.h && netdb.h && sys/socket.h && net/if.h
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_struct_ifreq_ifr_index" >&5
+echo "${ECHO_T}$ac_cv_struct_ifreq_ifr_index" >&6
+if test "$ac_cv_struct_ifreq_ifr_index" = yes ; then
+ :
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_IFR_INDEX 1
+_ACEOF
+
+else
+echo "$as_me:$LINENO: checking for field ifr_ifindex in struct ifreq" >&5
+echo $ECHO_N "checking for field ifr_ifindex in struct ifreq... $ECHO_C" >&6
+if test "${ac_cv_struct_ifreq_ifr_ifindex+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ac_cv_struct_ifreq_ifr_ifindex=no
+if test "1${ac_cv_header_arpa_inet_h}2${ac_cv_header_netdb_h}3${ac_cv_header_sys_socket_h}4${ac_cv_header_net_if_h}" = 1yes2yes3yes4yes; then
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <net/if.h>
+int
+main ()
+{
+
+struct ifreq ifreq; int index; index = ifreq.ifr_ifindex;
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_struct_ifreq_ifr_ifindex=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+ ac_cv_struct_ifreq_ifr_ifindex='net/if.h missing'
+fi # arpa/inet.h && netdb.h && sys/socket.h && net/if.h
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_struct_ifreq_ifr_ifindex" >&5
+echo "${ECHO_T}$ac_cv_struct_ifreq_ifr_ifindex" >&6
+if test "$ac_cv_struct_ifreq_ifr_ifindex" = yes; then
+ :
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_IFR_IFINDEX 1
+_ACEOF
+
+fi
+
+fi # ifr_index in struct ifreq
+
+echo "$as_me:$LINENO: checking for struct ifconf" >&5
+echo $ECHO_N "checking for struct ifconf... $ECHO_C" >&6
+if test "${ac_cv_struct_ifconf+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ac_cv_struct_ifconf=no
+if test "$ac_cv_header_net_if_h" = yes; then
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <net/if.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "struct.+ifconf" >/dev/null 2>&1; then
+ ac_cv_struct_ifconf=yes
+fi
+rm -f conftest*
+
+else
+ ac_cv_struct_ifconf='net/if.h missing'
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_struct_ifconf" >&5
+echo "${ECHO_T}$ac_cv_struct_ifconf" >&6
+if test "$ac_cv_struct_ifconf" = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_IFCONF 1
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for ioctl SIOCGIFNUM" >&5
+echo $ECHO_N "checking for ioctl SIOCGIFNUM... $ECHO_C" >&6
+if test "${ac_cv_ioctl_siocgifnum+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ac_cv_ioctl_siocgifnum=no
+if test "$ac_cv_header_sys_sockio_h" = yes; then
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <sys/sockio.h>
+#ifdef SIOCGIFNUM
+ yes
+#endif
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "yes" >/dev/null 2>&1; then
+ ac_cv_ioctl_siocgifnum=yes
+fi
+rm -f conftest*
+
+else
+ ac_cv_ioctl_siocgifnum='sys/sockio.h missing'
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_ioctl_siocgifnum" >&5
+echo "${ECHO_T}$ac_cv_ioctl_siocgifnum" >&6
+if test "$ac_cv_ioctl_siocgifnum" = yes; then
+ HAVE_IFNUM=1
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_IFNUM 1
+_ACEOF
+
+else
+ HAVE_IFNUM=0
+fi
+
+
+fi
+
+done
+
+
+# ===========================================================================
+# Checks for libraries
+# ===========================================================================
+
+
+
+
+echo "$as_me:$LINENO: checking for pthread_create in -lpthread" >&5
+echo $ECHO_N "checking for pthread_create in -lpthread... $ECHO_C" >&6
+if test "${ac_cv_lib_pthread_pthread_create+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpthread $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char pthread_create ();
+int
+main ()
+{
+pthread_create ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_pthread_pthread_create=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_pthread_pthread_create=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_pthread_pthread_create" >&5
+echo "${ECHO_T}$ac_cv_lib_pthread_pthread_create" >&6
+if test $ac_cv_lib_pthread_pthread_create = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBPTHREAD 1
+_ACEOF
+
+ LIBS="-lpthread $LIBS"
+
+fi
+
+
+echo "$as_me:$LINENO: checking for socketpair in -lsocket" >&5
+echo $ECHO_N "checking for socketpair in -lsocket... $ECHO_C" >&6
+if test "${ac_cv_lib_socket_socketpair+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsocket -lnsl $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char socketpair ();
+int
+main ()
+{
+socketpair ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_socket_socketpair=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_socket_socketpair=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_socket_socketpair" >&5
+echo "${ECHO_T}$ac_cv_lib_socket_socketpair" >&6
+if test $ac_cv_lib_socket_socketpair = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBSOCKET 1
+_ACEOF
+
+ LIBS="-lsocket $LIBS"
+
+fi
+
+if test "${with_rt}" != no; then
+ echo "$as_me:$LINENO: checking for library containing clock_gettime" >&5
+echo $ECHO_N "checking for library containing clock_gettime... $ECHO_C" >&6
+if test "${ac_cv_search_clock_gettime+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+ac_cv_search_clock_gettime=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char clock_gettime ();
+int
+main ()
+{
+clock_gettime ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_clock_gettime="none required"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_clock_gettime" = no; then
+ for ac_lib in rt; do
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char clock_gettime ();
+int
+main ()
+{
+clock_gettime ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_clock_gettime="-l$ac_lib"
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_clock_gettime" >&5
+echo "${ECHO_T}$ac_cv_search_clock_gettime" >&6
+if test "$ac_cv_search_clock_gettime" != no; then
+ test "$ac_cv_search_clock_gettime" = "none required" || LIBS="$ac_cv_search_clock_gettime $LIBS"
+
+fi
+
+fi
+
+
+# No GLib path explicitly defined, use pkg-config
+
+# Check whether --with-glib or --without-glib was given.
+if test "${with_glib+set}" = set; then
+ withval="$with_glib"
+
+case "$with_glib" in
+yes | "" ) with_glib=2.0 ;;
+esac
+
+else
+ with_glib=2.0
+fi;
+
+
+# Check whether --with-glib-dir or --without-glib-dir was given.
+if test "${with_glib_dir+set}" = set; then
+ withval="$with_glib_dir"
+
+else
+ with_glib_dir="pkg-config"
+fi;
+
+if test "$with_glib" = no || test "$with_glib_dir" = "no" ; then
+
+ : # No glib
+
+elif test "$with_glib_dir" = "pkg-config" ; then
+
+
+ succeeded=no
+
+ if test -z "$PKG_CONFIG"; then
+ # Extract the first word of "pkg-config", so it can be a program name with args.
+set dummy pkg-config; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_path_PKG_CONFIG+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $PKG_CONFIG in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ test -z "$ac_cv_path_PKG_CONFIG" && ac_cv_path_PKG_CONFIG="no"
+ ;;
+esac
+fi
+PKG_CONFIG=$ac_cv_path_PKG_CONFIG
+
+if test -n "$PKG_CONFIG"; then
+ echo "$as_me:$LINENO: result: $PKG_CONFIG" >&5
+echo "${ECHO_T}$PKG_CONFIG" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ fi
+
+ if test "$PKG_CONFIG" = "no" ; then
+ echo "*** The pkg-config script could not be found. Make sure it is"
+ echo "*** in your path, or set the PKG_CONFIG environment variable"
+ echo "*** to the full path to pkg-config."
+ echo "*** Or see http://www.freedesktop.org/software/pkgconfig to get pkg-config."
+ else
+ PKG_CONFIG_MIN_VERSION=0.9.0
+ if $PKG_CONFIG --atleast-pkgconfig-version $PKG_CONFIG_MIN_VERSION; then
+ echo "$as_me:$LINENO: checking for glib-$with_glib" >&5
+echo $ECHO_N "checking for glib-$with_glib... $ECHO_C" >&6
+
+ if $PKG_CONFIG --exists "glib-$with_glib" ; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ succeeded=yes
+
+ echo "$as_me:$LINENO: checking GLIB_CFLAGS" >&5
+echo $ECHO_N "checking GLIB_CFLAGS... $ECHO_C" >&6
+ GLIB_CFLAGS=`$PKG_CONFIG --cflags "glib-$with_glib"`
+ echo "$as_me:$LINENO: result: $GLIB_CFLAGS" >&5
+echo "${ECHO_T}$GLIB_CFLAGS" >&6
+
+ echo "$as_me:$LINENO: checking GLIB_LIBS" >&5
+echo $ECHO_N "checking GLIB_LIBS... $ECHO_C" >&6
+ GLIB_LIBS=`$PKG_CONFIG --libs "glib-$with_glib"`
+ echo "$as_me:$LINENO: result: $GLIB_LIBS" >&5
+echo "${ECHO_T}$GLIB_LIBS" >&6
+ else
+ GLIB_CFLAGS=""
+ GLIB_LIBS=""
+ ## If we have a custom action on failure, don't print errors, but
+ ## do set a variable so people can do so.
+ GLIB_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "glib-$with_glib"`
+
+ fi
+
+
+
+ else
+ echo "*** Your version of pkg-config is too old. You need version $PKG_CONFIG_MIN_VERSION or newer."
+ echo "*** See http://www.freedesktop.org/software/pkgconfig"
+ fi
+ fi
+
+ if test $succeeded = yes; then
+ HAVE_GLIB=yes
+ else
+ HAVE_GLIB=no
+ fi
+
+
+else # GLib path is explicitly defined
+
+ gprefix=$with_glib_dir
+ GLIB_VERSION="$with_glib"
+ GLIBXXX=glib-$with_glib
+
+ if test "$gprefix" = "yes" ; then
+ for gprefix in /usr /usr/local /opt/$GLIBXXX
+ do
+ test -d $gprefix/include/$GLIBXXX && break
+ done
+ fi
+
+ if ! test -d $gprefix/include/$GLIBXXX ; then
+ { { echo "$as_me:$LINENO: error: \"No $GLIBXXX in --with-glib=$with_glib_dir\"" >&5
+echo "$as_me: error: \"No $GLIBXXX in --with-glib=$with_glib_dir\"" >&2;}
+ { (exit 1); exit 1; }; }
+ else
+ exec_gprefix=${gprefix}
+ glibdir=${exec_gprefix}/lib
+ gincludedir=${gprefix}/include
+
+ # glib_genmarshal=glib-genmarshal
+ # glib_mkenums=glib-mkenums
+
+ HAVE_GLIB=yes
+
+ if test "x$MINGW_ENVIRONMENT" = x1 ; then
+ GLIB_LIBS="${glibdir}/lib$GLIBXXX.dll.a ${glibdir}/libintl.a ${glibdir}/libiconv.a"
+ else
+ GLIB_LIBS="-L${glibdir} -l$GLIBXXX -lintl -liconv"
+ fi
+ GLIB_CFLAGS="-I${gincludedir}/$GLIBXXX -I${glibdir}/$GLIBXXX/include"
+ fi
+
+fi # GLib path is explicitly defined
+
+if test "x$HAVE_GLIB" = xyes ; then
+ SOFIA_GLIB_PKG_REQUIRES="`test -n "$SOFIA_GLIB_PKG_REQUIRES" && echo "$SOFIA_GLIB_PKG_REQUIRES, "`glib-2.0"
+fi
+
+
+
+if test "x$HAVE_GLIB" = xyes; then
+ HAVE_GLIB_TRUE=
+ HAVE_GLIB_FALSE='#'
+else
+ HAVE_GLIB_TRUE='#'
+ HAVE_GLIB_FALSE=
+fi
+
+
+
+
+
+
+# ===========================================================================
+# Checks for library functions.
+# ===========================================================================
+
+echo "$as_me:$LINENO: checking for library containing socket" >&5
+echo $ECHO_N "checking for library containing socket... $ECHO_C" >&6
+if test "${ac_cv_search_socket+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+ac_cv_search_socket=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char socket ();
+int
+main ()
+{
+socket ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_socket="none required"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_socket" = no; then
+ for ac_lib in xnet socket; do
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char socket ();
+int
+main ()
+{
+socket ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_socket="-l$ac_lib"
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_socket" >&5
+echo "${ECHO_T}$ac_cv_search_socket" >&6
+if test "$ac_cv_search_socket" != no; then
+ test "$ac_cv_search_socket" = "none required" || LIBS="$ac_cv_search_socket $LIBS"
+
+fi
+
+echo "$as_me:$LINENO: checking for library containing inet_ntop" >&5
+echo $ECHO_N "checking for library containing inet_ntop... $ECHO_C" >&6
+if test "${ac_cv_search_inet_ntop+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+ac_cv_search_inet_ntop=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char inet_ntop ();
+int
+main ()
+{
+inet_ntop ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_inet_ntop="none required"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_inet_ntop" = no; then
+ for ac_lib in socket nsl; do
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char inet_ntop ();
+int
+main ()
+{
+inet_ntop ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_inet_ntop="-l$ac_lib"
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_inet_ntop" >&5
+echo "${ECHO_T}$ac_cv_search_inet_ntop" >&6
+if test "$ac_cv_search_inet_ntop" != no; then
+ test "$ac_cv_search_inet_ntop" = "none required" || LIBS="$ac_cv_search_inet_ntop $LIBS"
+
+fi
+
+echo "$as_me:$LINENO: checking for library containing getipnodebyname" >&5
+echo $ECHO_N "checking for library containing getipnodebyname... $ECHO_C" >&6
+if test "${ac_cv_search_getipnodebyname+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+ac_cv_search_getipnodebyname=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char getipnodebyname ();
+int
+main ()
+{
+getipnodebyname ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_getipnodebyname="none required"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_getipnodebyname" = no; then
+ for ac_lib in xnet socket nsl; do
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char getipnodebyname ();
+int
+main ()
+{
+getipnodebyname ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_getipnodebyname="-l$ac_lib"
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_getipnodebyname" >&5
+echo "${ECHO_T}$ac_cv_search_getipnodebyname" >&6
+if test "$ac_cv_search_getipnodebyname" != no; then
+ test "$ac_cv_search_getipnodebyname" = "none required" || LIBS="$ac_cv_search_getipnodebyname $LIBS"
+
+fi
+
+echo "$as_me:$LINENO: checking for library containing gethostbyname" >&5
+echo $ECHO_N "checking for library containing gethostbyname... $ECHO_C" >&6
+if test "${ac_cv_search_gethostbyname+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+ac_cv_search_gethostbyname=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char gethostbyname ();
+int
+main ()
+{
+gethostbyname ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_gethostbyname="none required"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_gethostbyname" = no; then
+ for ac_lib in xnet nsl; do
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char gethostbyname ();
+int
+main ()
+{
+gethostbyname ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_gethostbyname="-l$ac_lib"
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_gethostbyname" >&5
+echo "${ECHO_T}$ac_cv_search_gethostbyname" >&6
+if test "$ac_cv_search_gethostbyname" != no; then
+ test "$ac_cv_search_gethostbyname" = "none required" || LIBS="$ac_cv_search_gethostbyname $LIBS"
+
+fi
+
+echo "$as_me:$LINENO: checking for library containing getaddrinfo" >&5
+echo $ECHO_N "checking for library containing getaddrinfo... $ECHO_C" >&6
+if test "${ac_cv_search_getaddrinfo+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+ac_cv_search_getaddrinfo=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char getaddrinfo ();
+int
+main ()
+{
+getaddrinfo ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_getaddrinfo="none required"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_getaddrinfo" = no; then
+ for ac_lib in xnet socket nsl; do
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char getaddrinfo ();
+int
+main ()
+{
+getaddrinfo ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_getaddrinfo="-l$ac_lib"
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_getaddrinfo" >&5
+echo "${ECHO_T}$ac_cv_search_getaddrinfo" >&6
+if test "$ac_cv_search_getaddrinfo" != no; then
+ test "$ac_cv_search_getaddrinfo" = "none required" || LIBS="$ac_cv_search_getaddrinfo $LIBS"
+
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+for ac_func in gettimeofday strerror random initstate tcsetattr flock alarm \
+ socketpair gethostname gethostbyname getipnodebyname \
+ poll epoll_create select if_nameindex \
+ getaddrinfo getnameinfo freeaddrinfo gai_strerror getifaddrs \
+ getline getdelim getpass
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+# getline getdelim getpass are _GNU_SOURCE stuff
+
+if test $ac_cv_func_poll = yes ; then
+
+cat >>confdefs.h <<\_AXEOF
+#define SU_HAVE_POLL 1
+_AXEOF
+
+fi
+
+if test $ac_cv_func_epoll_create = yes ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_EPOLL 1
+_ACEOF
+
+fi
+
+if test $ac_cv_func_if_nameindex = yes ; then
+
+cat >>confdefs.h <<\_AXEOF
+#define SU_HAVE_IF_NAMEINDEX 1
+_AXEOF
+
+fi
+
+
+if test "${with_rt}" != no; then
+
+
+for ac_func in clock_gettime clock_getcpuclockid
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+fi
+
+
+
+
+
+
+
+
+
+for ac_func in memmem memccpy memspn memcspn strcasestr strtoull \
+ inet_ntop inet_pton
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+ :
+else
+ case "$REPLACE_LIBADD" in
+ "$ac_func.lo" | \
+ *" $ac_func.lo" | \
+ "$ac_func.lo "* | \
+ *" $ac_func.lo "* ) ;;
+ *) REPLACE_LIBADD="$REPLACE_LIBADD $ac_func.lo" ;;
+esac
+fi
+done
+
+
+:
+
+
+
+# ===========================================================================
+# Check pthread_rwlock_unlock()
+# ===========================================================================
+
+
+
+if test x$HAVE_PTHREADS = x1 ; then
+
+if test "$cross_compiling" = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_PTHREAD_RWLOCK 1
+_ACEOF
+
+else
+ cat >conftest.$ac_ext <<_ACEOF
+
+#define _XOPEN_SOURCE (500)
+
+#include <pthread.h>
+
+pthread_rwlock_t rw;
+
+int main()
+{
+ pthread_rwlock_init(&rw, NULL);
+ pthread_rwlock_rdlock(&rw);
+ pthread_rwlock_rdlock(&rw);
+ pthread_rwlock_unlock(&rw);
+ /* pthread_rwlock_trywrlock() should fail (not return 0) */
+ return pthread_rwlock_trywrlock(&rw) != 0 ? 0 : 1;
+}
+
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_PTHREAD_RWLOCK 1
+_ACEOF
+
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+
+{ echo "$as_me:$LINENO: WARNING: Recursive pthread_rwlock_rdlock() does not work!!! " >&5
+echo "$as_me: WARNING: Recursive pthread_rwlock_rdlock() does not work!!! " >&2;}
+
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+fi
+
+# ===========================================================================
+# Check IPv6 addresss configuration
+# ===========================================================================
+case "$target" in
+ *-*-linux*)
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_PROC_NET_IF_INET6 1
+_ACEOF
+ ;;
+esac
+
+ ac_config_headers="$ac_config_headers libsofia-sip-ua/su/sofia-sip/su_configure.h"
+
+
+# End of SAC_SOFIA_SU
+
+
+
+
+# Check whether --with-openssl or --without-openssl was given.
+if test "${with_openssl+set}" = set; then
+ withval="$with_openssl"
+
+else
+ with_openssl=yes
+fi;
+
+
+if test "$with_openssl" != no ;then
+
+for ac_header in openssl/tls1.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to the sofia-sip lists. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+
+ HAVE_OPENSSL=1 HAVE_TLS=1
+
+
+echo "$as_me:$LINENO: checking for BIO_new in -lcrypto" >&5
+echo $ECHO_N "checking for BIO_new in -lcrypto... $ECHO_C" >&6
+if test "${ac_cv_lib_crypto_BIO_new+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcrypto $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char BIO_new ();
+int
+main ()
+{
+BIO_new ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_crypto_BIO_new=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_crypto_BIO_new=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_crypto_BIO_new" >&5
+echo "${ECHO_T}$ac_cv_lib_crypto_BIO_new" >&6
+if test $ac_cv_lib_crypto_BIO_new = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBCRYPTO 1
+_ACEOF
+
+ LIBS="-lcrypto $LIBS"
+
+else
+ HAVE_OPENSSL=0
+ { echo "$as_me:$LINENO: WARNING: OpenSSL crypto library was not found" >&5
+echo "$as_me: WARNING: OpenSSL crypto library was not found" >&2;}
+fi
+
+
+
+echo "$as_me:$LINENO: checking for TLSv1_method in -lssl" >&5
+echo $ECHO_N "checking for TLSv1_method in -lssl... $ECHO_C" >&6
+if test "${ac_cv_lib_ssl_TLSv1_method+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lssl $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char TLSv1_method ();
+int
+main ()
+{
+TLSv1_method ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_ssl_TLSv1_method=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_ssl_TLSv1_method=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_ssl_TLSv1_method" >&5
+echo "${ECHO_T}$ac_cv_lib_ssl_TLSv1_method" >&6
+if test $ac_cv_lib_ssl_TLSv1_method = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBSSL 1
+_ACEOF
+
+ LIBS="-lssl $LIBS"
+
+else
+ HAVE_TLS=0
+ { echo "$as_me:$LINENO: WARNING: OpenSSL protocol library was not found" >&5
+echo "$as_me: WARNING: OpenSSL protocol library was not found" >&2;}
+fi
+
+
+ if test x$HAVE_OPENSSL = x1; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_OPENSSL 1
+_ACEOF
+
+ fi
+
+ if test x$HAVE_TLS = x1; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_TLS 1
+_ACEOF
+
+ fi
+
+else
+ { echo "$as_me:$LINENO: WARNING: OpenSSL include files were not found" >&5
+echo "$as_me: WARNING: OpenSSL include files were not found" >&2;}
+fi
+
+done
+
+fi
+
+
+
+if test x$HAVE_TLS = x1; then
+ HAVE_TLS_TRUE=
+ HAVE_TLS_FALSE='#'
+else
+ HAVE_TLS_TRUE='#'
+ HAVE_TLS_FALSE=
+fi
+
+
+
+
+
+# Check whether --with-sigcomp or --without-sigcomp was given.
+if test "${with_sigcomp+set}" = set; then
+ withval="$with_sigcomp"
+
+else
+ with_sigcomp=no
+fi;
+
+if test -n "${with_sigcomp}" && test "${with_sigcomp}" != no ; then
+ if test "${with_sigcomp}" != yes ; then
+ CPPFLAGS="-I${with_sigcomp}/include $CPPFLAGS"
+ LIBS="-L${with_sigcomp}/lib -lsigcomp $LIBS"
+ else
+ LIBS="-lsigcomp $LIBS"
+ fi
+
+
+for ac_header in sigcomp.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to the sofia-sip lists. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+else
+ { { echo "$as_me:$LINENO: error: cannot find Sofia SigComp includes" >&5
+echo "$as_me: error: cannot find Sofia SigComp includes" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+done
+
+
+ echo "$as_me:$LINENO: checking for sigcomp_library_2_5" >&5
+echo $ECHO_N "checking for sigcomp_library_2_5... $ECHO_C" >&6
+if test "${ac_cv_func_sigcomp_library_2_5+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define sigcomp_library_2_5 to an innocuous variant, in case <limits.h> declares sigcomp_library_2_5.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define sigcomp_library_2_5 innocuous_sigcomp_library_2_5
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char sigcomp_library_2_5 (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef sigcomp_library_2_5
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char sigcomp_library_2_5 ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_sigcomp_library_2_5) || defined (__stub___sigcomp_library_2_5)
+choke me
+#else
+char (*f) () = sigcomp_library_2_5;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != sigcomp_library_2_5;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_sigcomp_library_2_5=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_sigcomp_library_2_5=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_sigcomp_library_2_5" >&5
+echo "${ECHO_T}$ac_cv_func_sigcomp_library_2_5" >&6
+if test $ac_cv_func_sigcomp_library_2_5 = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SIGCOMP 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SOFIA_SIGCOMP 1
+_ACEOF
+
+else
+ { { echo "$as_me:$LINENO: error: Sofia SigComp API >= 2.5 was not found" >&5
+echo "$as_me: error: Sofia SigComp API >= 2.5 was not found" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+fi
+
+# Check for features used by tport.
+
+
+echo "$as_me:$LINENO: checking for IP_RECVERR" >&5
+echo $ECHO_N "checking for IP_RECVERR... $ECHO_C" >&6
+if test "${ac_cv_sys_ip_recverr+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+int
+main ()
+{
+
+ int one = 1;
+ int s = 0;
+ setsockopt(s, SOL_IP, IP_RECVERR, &one, sizeof(one));
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_sys_ip_recverr=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_sys_ip_recverr=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_sys_ip_recverr" >&5
+echo "${ECHO_T}$ac_cv_sys_ip_recverr" >&6
+if test "$ac_cv_sys_ip_recverr" = yes ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_IP_RECVERR 1
+_ACEOF
+
+fi
+
+
+
+echo "$as_me:$LINENO: checking for IPV6_RECVERR" >&5
+echo $ECHO_N "checking for IPV6_RECVERR... $ECHO_C" >&6
+if test "${ac_cv_sys_ipv6_recverr+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+int
+main ()
+{
+
+ int one = 1;
+ int s = 0;
+ setsockopt(s, SOL_IPV6, IPV6_RECVERR, &one, sizeof(one));
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_sys_ipv6_recverr=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_sys_ipv6_recverr=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_sys_ipv6_recverr" >&5
+echo "${ECHO_T}$ac_cv_sys_ipv6_recverr" >&6
+if test "$ac_cv_sys_ipv6_recverr" = yes ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_IPV6_RECVERR 1
+_ACEOF
+
+fi
+
+
+
+
+for ac_header in netinet/tcp.h netinet/sctp.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to the sofia-sip lists. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+# Check whether --with-sctp or --without-sctp was given.
+if test "${with_sctp+set}" = set; then
+ withval="$with_sctp"
+
+else
+ enable_sigcomp=no
+fi;
+
+if test x$enable_sctp = xyes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SCTP 1
+_ACEOF
+
+fi
+
+
+
+
+
+### internal modules
+### ----------------
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SOFIA_SIP 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SOFIA_SRESOLV 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SOFIA_SMIME 0
+_ACEOF
+
+
+# Check whether --enable-stun or --disable-stun was given.
+if test "${enable_stun+set}" = set; then
+ enableval="$enable_stun"
+
+else
+ enable_stun=yes
+fi;
+
+if test x$enable_stun = xno ; then
+ { echo "$as_me:$LINENO: WARNING: ** STUN support disabled **" >&5
+echo "$as_me: WARNING: ** STUN support disabled **" >&2;}
+elif test x${HAVE_OPENSSL} != x1 ; then
+ { echo "$as_me:$LINENO: WARNING: ** TLS support for STUN disabled as OpenSSL headers and/or libraries were not found **" >&5
+echo "$as_me: WARNING: ** TLS support for STUN disabled as OpenSSL headers and/or libraries were not found **" >&2;}
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SOFIA_STUN 1
+_ACEOF
+
+else
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SOFIA_STUN 1
+_ACEOF
+
+fi
+
+# Check whether --enable-ntlm or --disable-ntlm was given.
+if test "${enable_ntlm+set}" = set; then
+ enableval="$enable_ntlm"
+
+else
+ enable_ntlm=no
+fi;
+
+if test x$enable_ntlm = xyes ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SOFIA_NTLM 1
+_ACEOF
+
+fi
+
+
+if test "x$enable_ntlm" = xyes; then
+ HAVE_NTLM_TRUE=
+ HAVE_NTLM_FALSE='#'
+else
+ HAVE_NTLM_TRUE='#'
+ HAVE_NTLM_FALSE=
+fi
+
+
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SRTP 0
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_UPNP 0
+_ACEOF
+
+
+### checks for header files
+### -----------------------
+echo "$as_me:$LINENO: checking for ANSI C header files" >&5
+echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6
+if test "${ac_cv_header_stdc+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_header_stdc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_header_stdc=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "memchr" >/dev/null 2>&1; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "free" >/dev/null 2>&1; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+ if test "$cross_compiling" = yes; then
+ :
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ctype.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+ (('a' <= (c) && (c) <= 'i') \
+ || ('j' <= (c) && (c) <= 'r') \
+ || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ if (XOR (islower (i), ISLOWER (i))
+ || toupper (i) != TOUPPER (i))
+ exit(2);
+ exit (0);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_header_stdc=no
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5
+echo "${ECHO_T}$ac_cv_header_stdc" >&6
+if test $ac_cv_header_stdc = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define STDC_HEADERS 1
+_ACEOF
+
+fi
+
+
+### checks for declarations
+### -----------------------
+echo "$as_me:$LINENO: checking whether SIGPIPE is declared" >&5
+echo $ECHO_N "checking whether SIGPIPE is declared... $ECHO_C" >&6
+if test "${ac_cv_have_decl_SIGPIPE+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <signal.h>
+
+
+int
+main ()
+{
+#ifndef SIGPIPE
+ char *p = (char *) SIGPIPE;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_have_decl_SIGPIPE=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_have_decl_SIGPIPE=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_have_decl_SIGPIPE" >&5
+echo "${ECHO_T}$ac_cv_have_decl_SIGPIPE" >&6
+if test $ac_cv_have_decl_SIGPIPE = yes; then
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SIGPIPE 1
+_ACEOF
+
+fi
+
+
+### checks for types
+### ----------------
+
+echo "$as_me:$LINENO: checking return type of signal handlers" >&5
+echo $ECHO_N "checking return type of signal handlers... $ECHO_C" >&6
+if test "${ac_cv_type_signal+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <signal.h>
+#ifdef signal
+# undef signal
+#endif
+#ifdef __cplusplus
+extern "C" void (*signal (int, void (*)(int)))(int);
+#else
+void (*signal ()) ();
+#endif
+
+int
+main ()
+{
+int i;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_type_signal=void
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_signal=int
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_signal" >&5
+echo "${ECHO_T}$ac_cv_type_signal" >&6
+
+cat >>confdefs.h <<_ACEOF
+#define RETSIGTYPE $ac_cv_type_signal
+_ACEOF
+
+
+echo "$as_me:$LINENO: checking for long long" >&5
+echo $ECHO_N "checking for long long... $ECHO_C" >&6
+if test "${ac_cv_type_long_long+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+if ((long long *) 0)
+ return 0;
+if (sizeof (long long))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_type_long_long=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_long_long=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_long_long" >&5
+echo "${ECHO_T}$ac_cv_type_long_long" >&6
+if test $ac_cv_type_long_long = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define longlong long long
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define LLU "%llu"
+_ACEOF
+
+cat >>confdefs.h <<\_ACEOF
+#define LLI "%lli"
+_ACEOF
+
+cat >>confdefs.h <<\_ACEOF
+#define LLX "%llx"
+_ACEOF
+
+else
+ :
+fi
+
+
+cat >>confdefs.h <<\_ACEOF
+#define MOD_ZD "%zd"
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define MOD_ZU "%zu"
+_ACEOF
+
+
+### checks for structures
+### ---------------------
+
+### checks for typedefs, structures, and compiler characteristics.
+### --------------------------------------------------------------
+echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5
+echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6
+if test "${ac_cv_c_const+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+/* FIXME: Include the comments suggested by Paul. */
+#ifndef __cplusplus
+ /* Ultrix mips cc rejects this. */
+ typedef int charset[2];
+ const charset x;
+ /* SunOS 4.1.1 cc rejects this. */
+ char const *const *ccp;
+ char **p;
+ /* NEC SVR4.0.2 mips cc rejects this. */
+ struct point {int x, y;};
+ static struct point const zero = {0,0};
+ /* AIX XL C 1.02.0.0 rejects this.
+ It does not let you subtract one const X* pointer from another in
+ an arm of an if-expression whose if-part is not a constant
+ expression */
+ const char *g = "string";
+ ccp = &g + (g ? g-g : 0);
+ /* HPUX 7.0 cc rejects these. */
+ ++ccp;
+ p = (char**) ccp;
+ ccp = (char const *const *) p;
+ { /* SCO 3.2v4 cc rejects this. */
+ char *t;
+ char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+ *t++ = 0;
+ }
+ { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */
+ int x[] = {25, 17};
+ const int *foo = &x[0];
+ ++foo;
+ }
+ { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+ typedef const int *iptr;
+ iptr p = 0;
+ ++p;
+ }
+ { /* AIX XL C 1.02.0.0 rejects this saying
+ "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+ struct s { int j; const int *ap[3]; };
+ struct s *b; b->j = 5;
+ }
+ { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+ const int foo = 10;
+ }
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_c_const=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_c_const=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5
+echo "${ECHO_T}$ac_cv_c_const" >&6
+if test $ac_cv_c_const = no; then
+
+cat >>confdefs.h <<\_ACEOF
+#define const
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for inline" >&5
+echo $ECHO_N "checking for inline... $ECHO_C" >&6
+if test "${ac_cv_c_inline+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_c_inline=no
+for ac_kw in inline __inline__ __inline; do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifndef __cplusplus
+typedef int foo_t;
+static $ac_kw foo_t static_foo () {return 0; }
+$ac_kw foo_t foo () {return 0; }
+#endif
+
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_c_inline=$ac_kw; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_inline" >&5
+echo "${ECHO_T}$ac_cv_c_inline" >&6
+
+
+case $ac_cv_c_inline in
+ inline | yes) ;;
+ *)
+ case $ac_cv_c_inline in
+ no) ac_val=;;
+ *) ac_val=$ac_cv_c_inline;;
+ esac
+ cat >>confdefs.h <<_ACEOF
+#ifndef __cplusplus
+#define inline $ac_val
+#endif
+_ACEOF
+ ;;
+esac
+
+
+echo "$as_me:$LINENO: checking for inline" >&5
+echo $ECHO_N "checking for inline... $ECHO_C" >&6
+if test "${ac_cv_c_inline+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_c_inline=no
+for ac_kw in inline __inline__ __inline; do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifndef __cplusplus
+typedef int foo_t;
+static $ac_kw foo_t static_foo () {return 0; }
+$ac_kw foo_t foo () {return 0; }
+#endif
+
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_c_inline=$ac_kw; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_inline" >&5
+echo "${ECHO_T}$ac_cv_c_inline" >&6
+
+
+case $ac_cv_c_inline in
+ inline | yes) ;;
+ *)
+ case $ac_cv_c_inline in
+ no) ac_val=;;
+ *) ac_val=$ac_cv_c_inline;;
+ esac
+ cat >>confdefs.h <<_ACEOF
+#ifndef __cplusplus
+#define inline $ac_val
+#endif
+_ACEOF
+ ;;
+esac
+
+case "$ac_cv_c_inline" in *inline* | yes)
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_INLINE 1
+_ACEOF
+ ;;
+esac
+
+echo "$as_me:$LINENO: checking whether byte ordering is bigendian" >&5
+echo $ECHO_N "checking whether byte ordering is bigendian... $ECHO_C" >&6
+if test "${ac_cv_c_bigendian+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ # See if sys/param.h defines the BYTE_ORDER macro.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <sys/param.h>
+
+int
+main ()
+{
+#if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN
+ bogus endian macros
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ # It does; now see whether it defined to BIG_ENDIAN or not.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <sys/param.h>
+
+int
+main ()
+{
+#if BYTE_ORDER != BIG_ENDIAN
+ not big endian
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_c_bigendian=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_c_bigendian=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+# It does not; compile a test program.
+if test "$cross_compiling" = yes; then
+ # try to guess the endianness by grepping values into an object file
+ ac_cv_c_bigendian=unknown
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+short ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
+short ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
+void _ascii () { char *s = (char *) ascii_mm; s = (char *) ascii_ii; }
+short ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
+short ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 };
+void _ebcdic () { char *s = (char *) ebcdic_mm; s = (char *) ebcdic_ii; }
+int
+main ()
+{
+ _ascii (); _ebcdic ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ if grep BIGenDianSyS conftest.$ac_objext >/dev/null ; then
+ ac_cv_c_bigendian=yes
+fi
+if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then
+ if test "$ac_cv_c_bigendian" = unknown; then
+ ac_cv_c_bigendian=no
+ else
+ # finding both strings is unlikely to happen, but who knows?
+ ac_cv_c_bigendian=unknown
+ fi
+fi
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+int
+main ()
+{
+ /* Are we little or big endian? From Harbison&Steele. */
+ union
+ {
+ long l;
+ char c[sizeof (long)];
+ } u;
+ u.l = 1;
+ exit (u.c[sizeof (long) - 1] == 1);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_c_bigendian=no
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_c_bigendian=yes
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_bigendian" >&5
+echo "${ECHO_T}$ac_cv_c_bigendian" >&6
+case $ac_cv_c_bigendian in
+ yes)
+
+cat >>confdefs.h <<\_ACEOF
+#define WORDS_BIGENDIAN 1
+_ACEOF
+ ;;
+ no)
+ ;;
+ *)
+ { { echo "$as_me:$LINENO: error: unknown endianness
+presetting ac_cv_c_bigendian=no (or yes) will help" >&5
+echo "$as_me: error: unknown endianness
+presetting ac_cv_c_bigendian=no (or yes) will help" >&2;}
+ { (exit 1); exit 1; }; } ;;
+esac
+
+
+
+echo "$as_me:$LINENO: checking whether $CC recognizes __func__" >&5
+echo $ECHO_N "checking whether $CC recognizes __func__... $ECHO_C" >&6
+if test "${ac_cv_c_var_func+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+char *s = __func__;
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_c_var_func=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_c_var_func=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_var_func" >&5
+echo "${ECHO_T}$ac_cv_c_var_func" >&6
+if test $ac_cv_c_var_func = "yes"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_FUNC 1
+_ACEOF
+
+fi
+
+
+echo "$as_me:$LINENO: checking whether $CC recognizes __FUNCTION__" >&5
+echo $ECHO_N "checking whether $CC recognizes __FUNCTION__... $ECHO_C" >&6
+if test "${ac_cv_c_macro_function+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+char *s = __FUNCTION__;
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_c_macro_function=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_c_macro_function=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_macro_function" >&5
+echo "${ECHO_T}$ac_cv_c_macro_function" >&6
+if test $ac_cv_c_macro_function = "yes"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_FUNCTION 1
+_ACEOF
+
+fi
+
+
+
+echo "$as_me:$LINENO: checking whether $CC recognizes field names in struct initialization" >&5
+echo $ECHO_N "checking whether $CC recognizes field names in struct initialization... $ECHO_C" >&6
+if test "${ac_cv_c_keyword_struct+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ struct { int foo; char *bar; } test = { foo: 1, bar: "bar" };
+ return 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_c_keyword_struct=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_c_keyword_struct=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_keyword_struct" >&5
+echo "${ECHO_T}$ac_cv_c_keyword_struct" >&6
+if test $ac_cv_c_keyword_struct = "yes"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_STRUCT_KEYWORDS 1
+_ACEOF
+
+fi
+
+
+echo "$as_me:$LINENO: checking whether time.h and sys/time.h may both be included" >&5
+echo $ECHO_N "checking whether time.h and sys/time.h may both be included... $ECHO_C" >&6
+if test "${ac_cv_header_time+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+
+int
+main ()
+{
+if ((struct tm *) 0)
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_header_time=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_header_time=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_time" >&5
+echo "${ECHO_T}$ac_cv_header_time" >&6
+if test $ac_cv_header_time = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define TIME_WITH_SYS_TIME 1
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for size_t" >&5
+echo $ECHO_N "checking for size_t... $ECHO_C" >&6
+if test "${ac_cv_type_size_t+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+if ((size_t *) 0)
+ return 0;
+if (sizeof (size_t))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_type_size_t=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_size_t=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_size_t" >&5
+echo "${ECHO_T}$ac_cv_type_size_t" >&6
+if test $ac_cv_type_size_t = yes; then
+ :
+else
+
+cat >>confdefs.h <<_ACEOF
+#define size_t unsigned
+_ACEOF
+
+fi
+
+
+
+echo "$as_me:$LINENO: checking for sockaddr_in6" >&5
+echo $ECHO_N "checking for sockaddr_in6... $ECHO_C" >&6
+if test "${ac_cv_sin6+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <netinet/in.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "struct sockaddr_in6" >/dev/null 2>&1; then
+ ac_cv_sin6=yes
+else
+ ac_cv_sin6=no
+fi
+rm -f conftest*
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_sin6" >&5
+echo "${ECHO_T}$ac_cv_sin6" >&6
+if test $ac_cv_sin6 = yes ;then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SIN6 1
+_ACEOF
+
+fi
+
+
+echo "$as_me:$LINENO: checking for sa_len" >&5
+echo $ECHO_N "checking for sa_len... $ECHO_C" >&6
+if test "${ac_cv_sa_len+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <sys/socket.h>
+int
+main ()
+{
+
+ struct sockaddr t;t.sa_len = 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_sa_len=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_sa_len=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_sa_len" >&5
+echo "${ECHO_T}$ac_cv_sa_len" >&6
+if test "$ac_cv_sa_len" = yes ;then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SA_LEN 1
+_ACEOF
+
+fi
+
+
+### checks for library functions
+### ----------------------------
+
+### checks for system services
+### --------------------------
+
+
+echo "$as_me:$LINENO: checking /dev/urandom" >&5
+echo $ECHO_N "checking /dev/urandom... $ECHO_C" >&6
+if test "${ac_cv_dev_urandom+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_dev_urandom=no
+ if test -r /dev/urandom; then ac_cv_dev_urandom=yes; fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_dev_urandom" >&5
+echo "${ECHO_T}$ac_cv_dev_urandom" >&6
+if test $ac_cv_dev_urandom = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_DEV_URANDOM 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define DEV_URANDOM 1
+_ACEOF
+
+fi
+
+
+### output
+### ------
+
+ ac_config_files="$ac_config_files Makefile packages/Makefile packages/sofia-sip-ua.pc packages/sofia-sip-ua-glib.pc libsofia-sip-ua/Makefile libsofia-sip-ua/bnf/Makefile libsofia-sip-ua/docs/Makefile libsofia-sip-ua/docs/Doxyfile.version libsofia-sip-ua/docs/sofia-footer.html libsofia-sip-ua/features/Makefile libsofia-sip-ua/http/Makefile libsofia-sip-ua/ipt/Makefile libsofia-sip-ua/iptsec/Makefile libsofia-sip-ua/msg/Makefile libsofia-sip-ua/nea/Makefile libsofia-sip-ua/nta/Makefile libsofia-sip-ua/nth/Makefile libsofia-sip-ua/nua/Makefile libsofia-sip-ua/sdp/Makefile libsofia-sip-ua/sip/Makefile libsofia-sip-ua/soa/Makefile libsofia-sip-ua/sresolv/Makefile libsofia-sip-ua/stun/Makefile libsofia-sip-ua/su/Makefile libsofia-sip-ua/tport/Makefile libsofia-sip-ua/url/Makefile libsofia-sip-ua/features/sofia-sip/sofia_features.h libsofia-sip-ua-glib/Makefile libsofia-sip-ua-glib/su-glib/Makefile utils/Makefile utils/Doxyfile.build win32/Makefile win32/config.h"
+
+
+ ac_config_commands="$ac_config_commands version"
+
+ ac_config_files="$ac_config_files packages/sofia-sip-${PACKAGE_VERSION}.spec:packages/sofia-sip.spec.in"
+
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+{
+ (set) 2>&1 |
+ case `(ac_space=' '; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ # `set' does not quote correctly, so add quotes (double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \).
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;;
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n \
+ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+ ;;
+ esac;
+} |
+ sed '
+ t clear
+ : clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ : end' >>confcache
+if diff $cache_file confcache >/dev/null 2>&1; then :; else
+ if test -w $cache_file; then
+ test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file"
+ cat confcache >$cache_file
+ else
+ echo "not updating unwritable cache $cache_file"
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# VPATH may cause trouble with some makes, so we remove $(srcdir),
+# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=/{
+s/:*\$(srcdir):*/:/;
+s/:*\${srcdir}:*/:/;
+s/:*@srcdir@:*/:/;
+s/^\([^=]*=[ ]*\):*/\1/;
+s/:*$//;
+s/^[^=]*=[ ]*$//;
+}'
+fi
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_i=`echo "$ac_i" |
+ sed 's/\$U\././;s/\.o$//;s/\.obj$//'`
+ # 2. Add them.
+ ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext"
+ ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"MAINTAINER_MODE\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"MAINTAINER_MODE\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"AMDEP\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"AMDEP\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${HAVE_MINGW32_TRUE}" && test -z "${HAVE_MINGW32_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"HAVE_MINGW32\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"HAVE_MINGW32\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${ENABLE_COVERAGE_TRUE}" && test -z "${ENABLE_COVERAGE_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"ENABLE_COVERAGE\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"ENABLE_COVERAGE\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCXX\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"am__fastdepCXX\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${NDEBUG_TRUE}" && test -z "${NDEBUG_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"NDEBUG\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"NDEBUG\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${EXPENSIVE_CHECKS_TRUE}" && test -z "${EXPENSIVE_CHECKS_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"EXPENSIVE_CHECKS\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"EXPENSIVE_CHECKS\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${HAVE_DOXYGEN_TRUE}" && test -z "${HAVE_DOXYGEN_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"HAVE_DOXYGEN\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"HAVE_DOXYGEN\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${COREFOUNDATION_TRUE}" && test -z "${COREFOUNDATION_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"COREFOUNDATION\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"COREFOUNDATION\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${HAVE_GLIB_TRUE}" && test -z "${HAVE_GLIB_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"HAVE_GLIB\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"HAVE_GLIB\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${HAVE_TLS_TRUE}" && test -z "${HAVE_TLS_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"HAVE_TLS\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"HAVE_TLS\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${HAVE_NTLM_TRUE}" && test -z "${HAVE_NTLM_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"HAVE_NTLM\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"HAVE_NTLM\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+: ${CONFIG_STATUS=./config.status}
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5
+echo "$as_me: creating $CONFIG_STATUS" >&6;}
+cat >$CONFIG_STATUS <<_ACEOF
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+SHELL=\${CONFIG_SHELL-$SHELL}
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+## --------------------- ##
+## M4sh Initialization. ##
+## --------------------- ##
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+ set -o posix
+fi
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+fi
+
+
+# Work around bugs in pre-3.0 UWIN ksh.
+$as_unset ENV MAIL MAILPATH
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+ LC_TELEPHONE LC_TIME
+do
+ if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+ eval $as_var=C; export $as_var
+ else
+ $as_unset $as_var
+ fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)$' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
+ /^X\/\(\/\/\)$/{ s//\1/; q; }
+ /^X\/\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+
+
+# PATH needs CR, and LINENO needs CR and PATH.
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ echo "#! /bin/sh" >conf$$.sh
+ echo "exit 0" >>conf$$.sh
+ chmod +x conf$$.sh
+ if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conf$$.sh
+fi
+
+
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" || {
+ # Find who we are. Look in the path if we contain no path at all
+ # relative or not.
+ case $0 in
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+
+ ;;
+ esac
+ # We did not find ourselves, most probably we were run as `sh COMMAND'
+ # in which case we are not to be found in the path.
+ if test "x$as_myself" = x; then
+ as_myself=$0
+ fi
+ if test ! -f "$as_myself"; then
+ { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5
+echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ case $CONFIG_SHELL in
+ '')
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for as_base in sh bash ksh sh5; do
+ case $as_dir in
+ /*)
+ if ("$as_dir/$as_base" -c '
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then
+ $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; }
+ $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; }
+ CONFIG_SHELL=$as_dir/$as_base
+ export CONFIG_SHELL
+ exec "$CONFIG_SHELL" "$0" ${1+"$@"}
+ fi;;
+ esac
+ done
+done
+;;
+ esac
+
+ # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+ # uniformly replaced by the line number. The first 'sed' inserts a
+ # line-number line before each line; the second 'sed' does the real
+ # work. The second script uses 'N' to pair each line-number line
+ # with the numbered line, and appends trailing '-' during
+ # substitution so that $LINENO is not a special case at line end.
+ # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+ # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-)
+ sed '=' <$as_myself |
+ sed '
+ N
+ s,$,-,
+ : loop
+ s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
+ t loop
+ s,-$,,
+ s,^['$as_cr_digits']*\n,,
+ ' >$as_me.lineno &&
+ chmod +x $as_me.lineno ||
+ { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5
+echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;}
+ { (exit 1); exit 1; }; }
+
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensible to this).
+ . ./$as_me.lineno
+ # Exit status is that of the last command.
+ exit
+}
+
+
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+ *c*,-n*) ECHO_N= ECHO_C='
+' ECHO_T=' ' ;;
+ *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;;
+ *) ECHO_N= ECHO_C='\c' ECHO_T= ;;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+ # We could just check for DJGPP; but this test a) works b) is more generic
+ # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+ if test -f conf$$.exe; then
+ # Don't use ln at all; we don't have any links
+ as_ln_s='cp -p'
+ else
+ as_ln_s='ln -s'
+ fi
+elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.file
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p=:
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+as_executable_p="test -f"
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS=" $as_nl"
+
+# CDPATH.
+$as_unset CDPATH
+
+exec 6>&1
+
+# Open the log real soon, to keep \$[0] and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling. Logging --version etc. is OK.
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+} >&5
+cat >&5 <<_CSEOF
+
+This file was extended by sofia-sip $as_me 1.12.4work, which was
+generated by GNU Autoconf 2.59. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+_CSEOF
+echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5
+echo >&5
+_ACEOF
+
+# Files that config.status was made for.
+if test -n "$ac_config_files"; then
+ echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_headers"; then
+ echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_links"; then
+ echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_commands"; then
+ echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+ac_cs_usage="\
+\`$as_me' instantiates files from templates according to the
+current configuration.
+
+Usage: $0 [OPTIONS] [FILE]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number, then exit
+ -q, --quiet do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Configuration commands:
+$config_commands
+
+Report bugs to <bug-autoconf at gnu.org>."
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+ac_cs_version="\\
+sofia-sip config.status 1.12.4work
+configured by $0, generated by GNU Autoconf 2.59,
+ with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
+
+Copyright (C) 2003 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+srcdir=$srcdir
+INSTALL="$INSTALL"
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+# If no file are specified by the user, then we need to provide default
+# value. By we need to know if files were specified by the user.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=*)
+ ac_option=`expr "x$1" : 'x\([^=]*\)='`
+ ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ -*)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ *) # This is not an option, so the user has probably given explicit
+ # arguments.
+ ac_option=$1
+ ac_need_defaults=false;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --vers* | -V )
+ echo "$ac_cs_version"; exit 0 ;;
+ --he | --h)
+ # Conflict between --help and --header
+ { { echo "$as_me:$LINENO: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&5
+echo "$as_me: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&2;}
+ { (exit 1); exit 1; }; };;
+ --help | --hel | -h )
+ echo "$ac_cs_usage"; exit 0 ;;
+ --debug | --d* | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ CONFIG_FILES="$CONFIG_FILES $ac_optarg"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg"
+ ac_need_defaults=false;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&5
+echo "$as_me: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&2;}
+ { (exit 1); exit 1; }; } ;;
+
+ *) ac_config_targets="$ac_config_targets $1" ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+if \$ac_cs_recheck; then
+ echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6
+ exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+fi
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+#
+# INIT-COMMANDS section.
+#
+
+AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"
+PACKAGE_VERSION=${PACKAGE_VERSION}
+
+_ACEOF
+
+
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+for ac_config_target in $ac_config_targets
+do
+ case "$ac_config_target" in
+ # Handling of arguments.
+ "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+ "packages/Makefile" ) CONFIG_FILES="$CONFIG_FILES packages/Makefile" ;;
+ "packages/sofia-sip-ua.pc" ) CONFIG_FILES="$CONFIG_FILES packages/sofia-sip-ua.pc" ;;
+ "packages/sofia-sip-ua-glib.pc" ) CONFIG_FILES="$CONFIG_FILES packages/sofia-sip-ua-glib.pc" ;;
+ "libsofia-sip-ua/Makefile" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/Makefile" ;;
+ "libsofia-sip-ua/bnf/Makefile" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/bnf/Makefile" ;;
+ "libsofia-sip-ua/docs/Makefile" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/docs/Makefile" ;;
+ "libsofia-sip-ua/docs/Doxyfile.version" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/docs/Doxyfile.version" ;;
+ "libsofia-sip-ua/docs/sofia-footer.html" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/docs/sofia-footer.html" ;;
+ "libsofia-sip-ua/features/Makefile" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/features/Makefile" ;;
+ "libsofia-sip-ua/http/Makefile" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/http/Makefile" ;;
+ "libsofia-sip-ua/ipt/Makefile" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/ipt/Makefile" ;;
+ "libsofia-sip-ua/iptsec/Makefile" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/iptsec/Makefile" ;;
+ "libsofia-sip-ua/msg/Makefile" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/msg/Makefile" ;;
+ "libsofia-sip-ua/nea/Makefile" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/nea/Makefile" ;;
+ "libsofia-sip-ua/nta/Makefile" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/nta/Makefile" ;;
+ "libsofia-sip-ua/nth/Makefile" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/nth/Makefile" ;;
+ "libsofia-sip-ua/nua/Makefile" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/nua/Makefile" ;;
+ "libsofia-sip-ua/sdp/Makefile" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/sdp/Makefile" ;;
+ "libsofia-sip-ua/sip/Makefile" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/sip/Makefile" ;;
+ "libsofia-sip-ua/soa/Makefile" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/soa/Makefile" ;;
+ "libsofia-sip-ua/sresolv/Makefile" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/sresolv/Makefile" ;;
+ "libsofia-sip-ua/stun/Makefile" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/stun/Makefile" ;;
+ "libsofia-sip-ua/su/Makefile" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/su/Makefile" ;;
+ "libsofia-sip-ua/tport/Makefile" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/tport/Makefile" ;;
+ "libsofia-sip-ua/url/Makefile" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/url/Makefile" ;;
+ "libsofia-sip-ua/features/sofia-sip/sofia_features.h" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua/features/sofia-sip/sofia_features.h" ;;
+ "libsofia-sip-ua-glib/Makefile" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua-glib/Makefile" ;;
+ "libsofia-sip-ua-glib/su-glib/Makefile" ) CONFIG_FILES="$CONFIG_FILES libsofia-sip-ua-glib/su-glib/Makefile" ;;
+ "utils/Makefile" ) CONFIG_FILES="$CONFIG_FILES utils/Makefile" ;;
+ "utils/Doxyfile.build" ) CONFIG_FILES="$CONFIG_FILES utils/Doxyfile.build" ;;
+ "win32/Makefile" ) CONFIG_FILES="$CONFIG_FILES win32/Makefile" ;;
+ "win32/config.h" ) CONFIG_FILES="$CONFIG_FILES win32/config.h" ;;
+ "packages/sofia-sip-${PACKAGE_VERSION}.spec" ) CONFIG_FILES="$CONFIG_FILES packages/sofia-sip-${PACKAGE_VERSION}.spec:packages/sofia-sip.spec.in" ;;
+ "depfiles" ) CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
+ "version" ) CONFIG_COMMANDS="$CONFIG_COMMANDS version" ;;
+ "config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+ "libsofia-sip-ua/su/sofia-sip/su_configure.h" ) CONFIG_HEADERS="$CONFIG_HEADERS libsofia-sip-ua/su/sofia-sip/su_configure.h" ;;
+ *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
+echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+ test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason to put it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Create a temporary directory, and hook for its removal unless debugging.
+$debug ||
+{
+ trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0
+ trap '{ (exit 1); exit 1; }' 1 2 13 15
+}
+
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` &&
+ test -n "$tmp" && test -d "$tmp"
+} ||
+{
+ tmp=./confstat$$-$RANDOM
+ (umask 077 && mkdir $tmp)
+} ||
+{
+ echo "$me: cannot create a temporary directory in ." >&2
+ { (exit 1); exit 1; }
+}
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+
+#
+# CONFIG_FILES section.
+#
+
+# No need to generate the scripts if there are no CONFIG_FILES.
+# This happens for instance when ./config.status config.h
+if test -n "\$CONFIG_FILES"; then
+ # Protect against being on the right side of a sed subst in config.status.
+ sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g;
+ s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF
+s, at SHELL@,$SHELL,;t t
+s, at PATH_SEPARATOR@,$PATH_SEPARATOR,;t t
+s, at PACKAGE_NAME@,$PACKAGE_NAME,;t t
+s, at PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t
+s, at PACKAGE_VERSION@,$PACKAGE_VERSION,;t t
+s, at PACKAGE_STRING@,$PACKAGE_STRING,;t t
+s, at PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t
+s, at exec_prefix@,$exec_prefix,;t t
+s, at prefix@,$prefix,;t t
+s, at program_transform_name@,$program_transform_name,;t t
+s, at bindir@,$bindir,;t t
+s, at sbindir@,$sbindir,;t t
+s, at libexecdir@,$libexecdir,;t t
+s, at datadir@,$datadir,;t t
+s, at sysconfdir@,$sysconfdir,;t t
+s, at sharedstatedir@,$sharedstatedir,;t t
+s, at localstatedir@,$localstatedir,;t t
+s, at libdir@,$libdir,;t t
+s, at includedir@,$includedir,;t t
+s, at oldincludedir@,$oldincludedir,;t t
+s, at infodir@,$infodir,;t t
+s, at mandir@,$mandir,;t t
+s, at build_alias@,$build_alias,;t t
+s, at host_alias@,$host_alias,;t t
+s, at target_alias@,$target_alias,;t t
+s, at DEFS@,$DEFS,;t t
+s, at ECHO_C@,$ECHO_C,;t t
+s, at ECHO_N@,$ECHO_N,;t t
+s, at ECHO_T@,$ECHO_T,;t t
+s, at LIBS@,$LIBS,;t t
+s, at VER_LIBSOFIA_SIP_UA_MAJOR_MINOR@,$VER_LIBSOFIA_SIP_UA_MAJOR_MINOR,;t t
+s, at include_sofiadir@,$include_sofiadir,;t t
+s, at LIBVER_SOFIA_SIP_UA_CUR@,$LIBVER_SOFIA_SIP_UA_CUR,;t t
+s, at LIBVER_SOFIA_SIP_UA_REV@,$LIBVER_SOFIA_SIP_UA_REV,;t t
+s, at LIBVER_SOFIA_SIP_UA_AGE@,$LIBVER_SOFIA_SIP_UA_AGE,;t t
+s, at LIBVER_SOFIA_SIP_UA_SOVER@,$LIBVER_SOFIA_SIP_UA_SOVER,;t t
+s, at LIBVER_SOFIA_SIP_UA_GLIB_CUR@,$LIBVER_SOFIA_SIP_UA_GLIB_CUR,;t t
+s, at LIBVER_SOFIA_SIP_UA_GLIB_REV@,$LIBVER_SOFIA_SIP_UA_GLIB_REV,;t t
+s, at LIBVER_SOFIA_SIP_UA_GLIB_AGE@,$LIBVER_SOFIA_SIP_UA_GLIB_AGE,;t t
+s, at LIBVER_SOFIA_SIP_UA_GLIB_SOVER@,$LIBVER_SOFIA_SIP_UA_GLIB_SOVER,;t t
+s, at build@,$build,;t t
+s, at build_cpu@,$build_cpu,;t t
+s, at build_vendor@,$build_vendor,;t t
+s, at build_os@,$build_os,;t t
+s, at host@,$host,;t t
+s, at host_cpu@,$host_cpu,;t t
+s, at host_vendor@,$host_vendor,;t t
+s, at host_os@,$host_os,;t t
+s, at target@,$target,;t t
+s, at target_cpu@,$target_cpu,;t t
+s, at target_vendor@,$target_vendor,;t t
+s, at target_os@,$target_os,;t t
+s, at INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t
+s, at INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t
+s, at INSTALL_DATA@,$INSTALL_DATA,;t t
+s, at CYGPATH_W@,$CYGPATH_W,;t t
+s, at PACKAGE@,$PACKAGE,;t t
+s, at VERSION@,$VERSION,;t t
+s, at ACLOCAL@,$ACLOCAL,;t t
+s, at AUTOCONF@,$AUTOCONF,;t t
+s, at AUTOMAKE@,$AUTOMAKE,;t t
+s, at AUTOHEADER@,$AUTOHEADER,;t t
+s, at MAKEINFO@,$MAKEINFO,;t t
+s, at install_sh@,$install_sh,;t t
+s, at STRIP@,$STRIP,;t t
+s, at ac_ct_STRIP@,$ac_ct_STRIP,;t t
+s, at INSTALL_STRIP_PROGRAM@,$INSTALL_STRIP_PROGRAM,;t t
+s, at mkdir_p@,$mkdir_p,;t t
+s, at AWK@,$AWK,;t t
+s, at SET_MAKE@,$SET_MAKE,;t t
+s, at am__leading_dot@,$am__leading_dot,;t t
+s, at AMTAR@,$AMTAR,;t t
+s, at am__tar@,$am__tar,;t t
+s, at am__untar@,$am__untar,;t t
+s, at MAINTAINER_MODE_TRUE@,$MAINTAINER_MODE_TRUE,;t t
+s, at MAINTAINER_MODE_FALSE@,$MAINTAINER_MODE_FALSE,;t t
+s, at MAINT@,$MAINT,;t t
+s, at CC@,$CC,;t t
+s, at CFLAGS@,$CFLAGS,;t t
+s, at LDFLAGS@,$LDFLAGS,;t t
+s, at CPPFLAGS@,$CPPFLAGS,;t t
+s, at ac_ct_CC@,$ac_ct_CC,;t t
+s, at EXEEXT@,$EXEEXT,;t t
+s, at OBJEXT@,$OBJEXT,;t t
+s, at DEPDIR@,$DEPDIR,;t t
+s, at am__include@,$am__include,;t t
+s, at am__quote@,$am__quote,;t t
+s, at AMDEP_TRUE@,$AMDEP_TRUE,;t t
+s, at AMDEP_FALSE@,$AMDEP_FALSE,;t t
+s, at AMDEPBACKSLASH@,$AMDEPBACKSLASH,;t t
+s, at CCDEPMODE@,$CCDEPMODE,;t t
+s, at am__fastdepCC_TRUE@,$am__fastdepCC_TRUE,;t t
+s, at am__fastdepCC_FALSE@,$am__fastdepCC_FALSE,;t t
+s, at MINGW_ENVIRONMENT@,$MINGW_ENVIRONMENT,;t t
+s, at HAVE_MINGW32_TRUE@,$HAVE_MINGW32_TRUE,;t t
+s, at HAVE_MINGW32_FALSE@,$HAVE_MINGW32_FALSE,;t t
+s, at CWFLAG@,$CWFLAG,;t t
+s, at SOFIA_CFLAGS@,$SOFIA_CFLAGS,;t t
+s, at ENABLE_COVERAGE_TRUE@,$ENABLE_COVERAGE_TRUE,;t t
+s, at ENABLE_COVERAGE_FALSE@,$ENABLE_COVERAGE_FALSE,;t t
+s, at MOSTLYCLEANFILES@,$MOSTLYCLEANFILES,;t t
+s, at CPP@,$CPP,;t t
+s, at ETAGS@,$ETAGS,;t t
+s, at AR@,$AR,;t t
+s, at ac_ct_AR@,$ac_ct_AR,;t t
+s, at LD@,$LD,;t t
+s, at ac_ct_LD@,$ac_ct_LD,;t t
+s, at EGREP@,$EGREP,;t t
+s, at LN_S@,$LN_S,;t t
+s, at ECHO@,$ECHO,;t t
+s, at RANLIB@,$RANLIB,;t t
+s, at ac_ct_RANLIB@,$ac_ct_RANLIB,;t t
+s, at CXX@,$CXX,;t t
+s, at CXXFLAGS@,$CXXFLAGS,;t t
+s, at ac_ct_CXX@,$ac_ct_CXX,;t t
+s, at CXXDEPMODE@,$CXXDEPMODE,;t t
+s, at am__fastdepCXX_TRUE@,$am__fastdepCXX_TRUE,;t t
+s, at am__fastdepCXX_FALSE@,$am__fastdepCXX_FALSE,;t t
+s, at CXXCPP@,$CXXCPP,;t t
+s, at F77@,$F77,;t t
+s, at FFLAGS@,$FFLAGS,;t t
+s, at ac_ct_F77@,$ac_ct_F77,;t t
+s, at LIBTOOL@,$LIBTOOL,;t t
+s, at NDEBUG_TRUE@,$NDEBUG_TRUE,;t t
+s, at NDEBUG_FALSE@,$NDEBUG_FALSE,;t t
+s, at TESTS_ENVIRONMENT@,$TESTS_ENVIRONMENT,;t t
+s, at EXPENSIVE_CHECKS_TRUE@,$EXPENSIVE_CHECKS_TRUE,;t t
+s, at EXPENSIVE_CHECKS_FALSE@,$EXPENSIVE_CHECKS_FALSE,;t t
+s, at ACLOCAL_AMFLAGS@,$ACLOCAL_AMFLAGS,;t t
+s, at DOXYGEN@,$DOXYGEN,;t t
+s, at HAVE_DOXYGEN_TRUE@,$HAVE_DOXYGEN_TRUE,;t t
+s, at HAVE_DOXYGEN_FALSE@,$HAVE_DOXYGEN_FALSE,;t t
+s, at COREFOUNDATION_TRUE@,$COREFOUNDATION_TRUE,;t t
+s, at COREFOUNDATION_FALSE@,$COREFOUNDATION_FALSE,;t t
+s, at PKG_CONFIG@,$PKG_CONFIG,;t t
+s, at GLIB_CFLAGS@,$GLIB_CFLAGS,;t t
+s, at GLIB_LIBS@,$GLIB_LIBS,;t t
+s, at HAVE_GLIB_TRUE@,$HAVE_GLIB_TRUE,;t t
+s, at HAVE_GLIB_FALSE@,$HAVE_GLIB_FALSE,;t t
+s, at GLIB_VERSION@,$GLIB_VERSION,;t t
+s, at SOFIA_GLIB_PKG_REQUIRES@,$SOFIA_GLIB_PKG_REQUIRES,;t t
+s, at REPLACE_LIBADD@,$REPLACE_LIBADD,;t t
+s, at HAVE_TLS_TRUE@,$HAVE_TLS_TRUE,;t t
+s, at HAVE_TLS_FALSE@,$HAVE_TLS_FALSE,;t t
+s, at HAVE_NTLM_TRUE@,$HAVE_NTLM_TRUE,;t t
+s, at HAVE_NTLM_FALSE@,$HAVE_NTLM_FALSE,;t t
+s, at LIBOBJS@,$LIBOBJS,;t t
+s, at LTLIBOBJS@,$LTLIBOBJS,;t t
+CEOF
+
+_ACEOF
+
+ cat >>$CONFIG_STATUS <<\_ACEOF
+ # Split the substitutions into bite-sized pieces for seds with
+ # small command number limits, like on Digital OSF/1 and HP-UX.
+ ac_max_sed_lines=48
+ ac_sed_frag=1 # Number of current file.
+ ac_beg=1 # First line for current file.
+ ac_end=$ac_max_sed_lines # Line after last line for current file.
+ ac_more_lines=:
+ ac_sed_cmds=
+ while $ac_more_lines; do
+ if test $ac_beg -gt 1; then
+ sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
+ else
+ sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
+ fi
+ if test ! -s $tmp/subs.frag; then
+ ac_more_lines=false
+ else
+ # The purpose of the label and of the branching condition is to
+ # speed up the sed processing (if there are no `@' at all, there
+ # is no need to browse any of the substitutions).
+ # These are the two extra sed commands mentioned above.
+ (echo ':t
+ /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed"
+ else
+ ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed"
+ fi
+ ac_sed_frag=`expr $ac_sed_frag + 1`
+ ac_beg=$ac_end
+ ac_end=`expr $ac_end + $ac_max_sed_lines`
+ fi
+ done
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds=cat
+ fi
+fi # test -n "$CONFIG_FILES"
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case $ac_file in
+ - | *:- | *:-:* ) # input from stdin
+ cat >$tmp/stdin
+ ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ * ) ac_file_in=$ac_file.in ;;
+ esac
+
+ # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories.
+ ac_dir=`(dirname "$ac_file") 2>/dev/null ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ { if $as_mkdir_p; then
+ mkdir -p "$ac_dir"
+ else
+ as_dir="$ac_dir"
+ as_dirs=
+ while test ! -d "$as_dir"; do
+ as_dirs="$as_dir $as_dirs"
+ as_dir=`(dirname "$as_dir") 2>/dev/null ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ done
+ test ! -n "$as_dirs" || mkdir $as_dirs
+ fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5
+echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;}
+ { (exit 1); exit 1; }; }; }
+
+ ac_builddir=.
+
+if test "$ac_dir" != .; then
+ ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+ ac_dir_suffix= ac_top_builddir=
+fi
+
+case $srcdir in
+ .) # No --srcdir option. We are building in place.
+ ac_srcdir=.
+ if test -z "$ac_top_builddir"; then
+ ac_top_srcdir=.
+ else
+ ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+ fi ;;
+ [\\/]* | ?:[\\/]* ) # Absolute path.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir ;;
+ *) # Relative path.
+ ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+
+# Do not use `cd foo && pwd` to compute absolute paths, because
+# the directories may not exist.
+case `pwd` in
+.) ac_abs_builddir="$ac_dir";;
+*)
+ case "$ac_dir" in
+ .) ac_abs_builddir=`pwd`;;
+ [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";;
+ *) ac_abs_builddir=`pwd`/"$ac_dir";;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_builddir=${ac_top_builddir}.;;
+*)
+ case ${ac_top_builddir}. in
+ .) ac_abs_top_builddir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;;
+ *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_srcdir=$ac_srcdir;;
+*)
+ case $ac_srcdir in
+ .) ac_abs_srcdir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;;
+ *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_srcdir=$ac_top_srcdir;;
+*)
+ case $ac_top_srcdir in
+ .) ac_abs_top_srcdir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;;
+ *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;;
+ esac;;
+esac
+
+
+ case $INSTALL in
+ [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+ *) ac_INSTALL=$ac_top_builddir$INSTALL ;;
+ esac
+
+ if test x"$ac_file" != x-; then
+ { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+ rm -f "$ac_file"
+ fi
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ if test x"$ac_file" = x-; then
+ configure_input=
+ else
+ configure_input="$ac_file. "
+ fi
+ configure_input=$configure_input"Generated from `echo $ac_file_in |
+ sed 's,.*/,,'` by configure."
+
+ # First look for the input files in the build tree, otherwise in the
+ # src tree.
+ ac_file_inputs=`IFS=:
+ for f in $ac_file_in; do
+ case $f in
+ -) echo $tmp/stdin ;;
+ [\\/$]*)
+ # Absolute (can't be DOS-style, as IFS=:)
+ test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ echo "$f";;
+ *) # Relative
+ if test -f "$f"; then
+ # Build tree
+ echo "$f"
+ elif test -f "$srcdir/$f"; then
+ # Source tree
+ echo "$srcdir/$f"
+ else
+ # /dev/null tree
+ { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ fi;;
+ esac
+ done` || { (exit 1); exit 1; }
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+ sed "$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s, at configure_input@,$configure_input,;t t
+s, at srcdir@,$ac_srcdir,;t t
+s, at abs_srcdir@,$ac_abs_srcdir,;t t
+s, at top_srcdir@,$ac_top_srcdir,;t t
+s, at abs_top_srcdir@,$ac_abs_top_srcdir,;t t
+s, at builddir@,$ac_builddir,;t t
+s, at abs_builddir@,$ac_abs_builddir,;t t
+s, at top_builddir@,$ac_top_builddir,;t t
+s, at abs_top_builddir@,$ac_abs_top_builddir,;t t
+s, at INSTALL@,$ac_INSTALL,;t t
+" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out
+ rm -f $tmp/stdin
+ if test x"$ac_file" != x-; then
+ mv $tmp/out $ac_file
+ else
+ cat $tmp/out
+ rm -f $tmp/out
+ fi
+
+done
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+#
+# CONFIG_HEADER section.
+#
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s,^\([ ]*\)#\([ ]*define[ ][ ]*\)'
+ac_dB='[ ].*$,\1#\2'
+ac_dC=' '
+ac_dD=',;t'
+# ac_u turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_uA='s,^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_uB='$,\1#\2define\3'
+ac_uC=' '
+ac_uD=',;t'
+
+for ac_file in : $CONFIG_HEADERS; do test "x$ac_file" = x: && continue
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case $ac_file in
+ - | *:- | *:-:* ) # input from stdin
+ cat >$tmp/stdin
+ ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ * ) ac_file_in=$ac_file.in ;;
+ esac
+
+ test x"$ac_file" != x- && { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+
+ # First look for the input files in the build tree, otherwise in the
+ # src tree.
+ ac_file_inputs=`IFS=:
+ for f in $ac_file_in; do
+ case $f in
+ -) echo $tmp/stdin ;;
+ [\\/$]*)
+ # Absolute (can't be DOS-style, as IFS=:)
+ test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ # Do quote $f, to prevent DOS paths from being IFS'd.
+ echo "$f";;
+ *) # Relative
+ if test -f "$f"; then
+ # Build tree
+ echo "$f"
+ elif test -f "$srcdir/$f"; then
+ # Source tree
+ echo "$srcdir/$f"
+ else
+ # /dev/null tree
+ { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ fi;;
+ esac
+ done` || { (exit 1); exit 1; }
+ # Remove the trailing spaces.
+ sed 's/[ ]*$//' $ac_file_inputs >$tmp/in
+
+_ACEOF
+
+# Transform confdefs.h into two sed scripts, `conftest.defines' and
+# `conftest.undefs', that substitutes the proper values into
+# config.h.in to produce config.h. The first handles `#define'
+# templates, and the second `#undef' templates.
+# And first: Protect against being on the right side of a sed subst in
+# config.status. Protect against being in an unquoted here document
+# in config.status.
+rm -f conftest.defines conftest.undefs
+# Using a here document instead of a string reduces the quoting nightmare.
+# Putting comments in sed scripts is not portable.
+#
+# `end' is used to avoid that the second main sed command (meant for
+# 0-ary CPP macros) applies to n-ary macro definitions.
+# See the Autoconf documentation for `clear'.
+cat >confdef2sed.sed <<\_ACEOF
+s/[\\&,]/\\&/g
+s,[\\$`],\\&,g
+t clear
+: clear
+s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*\)\(([^)]*)\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1\2${ac_dC}\3${ac_dD},gp
+t end
+s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD},gp
+: end
+_ACEOF
+# If some macros were called several times there might be several times
+# the same #defines, which is useless. Nevertheless, we may not want to
+# sort them, since we want the *last* AC-DEFINE to be honored.
+uniq confdefs.h | sed -n -f confdef2sed.sed >conftest.defines
+sed 's/ac_d/ac_u/g' conftest.defines >conftest.undefs
+rm -f confdef2sed.sed
+
+# This sed command replaces #undef with comments. This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >>conftest.undefs <<\_ACEOF
+s,^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*,/* & */,
+_ACEOF
+
+# Break up conftest.defines because some shells have a limit on the size
+# of here documents, and old seds have small limits too (100 cmds).
+echo ' # Handle all the #define templates only if necessary.' >>$CONFIG_STATUS
+echo ' if grep "^[ ]*#[ ]*define" $tmp/in >/dev/null; then' >>$CONFIG_STATUS
+echo ' # If there are no defines, we may have an empty if/fi' >>$CONFIG_STATUS
+echo ' :' >>$CONFIG_STATUS
+rm -f conftest.tail
+while grep . conftest.defines >/dev/null
+do
+ # Write a limited-size here document to $tmp/defines.sed.
+ echo ' cat >$tmp/defines.sed <<CEOF' >>$CONFIG_STATUS
+ # Speed up: don't consider the non `#define' lines.
+ echo '/^[ ]*#[ ]*define/!b' >>$CONFIG_STATUS
+ # Work around the forget-to-reset-the-flag bug.
+ echo 't clr' >>$CONFIG_STATUS
+ echo ': clr' >>$CONFIG_STATUS
+ sed ${ac_max_here_lines}q conftest.defines >>$CONFIG_STATUS
+ echo 'CEOF
+ sed -f $tmp/defines.sed $tmp/in >$tmp/out
+ rm -f $tmp/in
+ mv $tmp/out $tmp/in
+' >>$CONFIG_STATUS
+ sed 1,${ac_max_here_lines}d conftest.defines >conftest.tail
+ rm -f conftest.defines
+ mv conftest.tail conftest.defines
+done
+rm -f conftest.defines
+echo ' fi # grep' >>$CONFIG_STATUS
+echo >>$CONFIG_STATUS
+
+# Break up conftest.undefs because some shells have a limit on the size
+# of here documents, and old seds have small limits too (100 cmds).
+echo ' # Handle all the #undef templates' >>$CONFIG_STATUS
+rm -f conftest.tail
+while grep . conftest.undefs >/dev/null
+do
+ # Write a limited-size here document to $tmp/undefs.sed.
+ echo ' cat >$tmp/undefs.sed <<CEOF' >>$CONFIG_STATUS
+ # Speed up: don't consider the non `#undef'
+ echo '/^[ ]*#[ ]*undef/!b' >>$CONFIG_STATUS
+ # Work around the forget-to-reset-the-flag bug.
+ echo 't clr' >>$CONFIG_STATUS
+ echo ': clr' >>$CONFIG_STATUS
+ sed ${ac_max_here_lines}q conftest.undefs >>$CONFIG_STATUS
+ echo 'CEOF
+ sed -f $tmp/undefs.sed $tmp/in >$tmp/out
+ rm -f $tmp/in
+ mv $tmp/out $tmp/in
+' >>$CONFIG_STATUS
+ sed 1,${ac_max_here_lines}d conftest.undefs >conftest.tail
+ rm -f conftest.undefs
+ mv conftest.tail conftest.undefs
+done
+rm -f conftest.undefs
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ if test x"$ac_file" = x-; then
+ echo "/* Generated by configure. */" >$tmp/config.h
+ else
+ echo "/* $ac_file. Generated by configure. */" >$tmp/config.h
+ fi
+ cat $tmp/in >>$tmp/config.h
+ rm -f $tmp/in
+ if test x"$ac_file" != x-; then
+ if diff $ac_file $tmp/config.h >/dev/null 2>&1; then
+ { echo "$as_me:$LINENO: $ac_file is unchanged" >&5
+echo "$as_me: $ac_file is unchanged" >&6;}
+ else
+ ac_dir=`(dirname "$ac_file") 2>/dev/null ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ { if $as_mkdir_p; then
+ mkdir -p "$ac_dir"
+ else
+ as_dir="$ac_dir"
+ as_dirs=
+ while test ! -d "$as_dir"; do
+ as_dirs="$as_dir $as_dirs"
+ as_dir=`(dirname "$as_dir") 2>/dev/null ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ done
+ test ! -n "$as_dirs" || mkdir $as_dirs
+ fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5
+echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;}
+ { (exit 1); exit 1; }; }; }
+
+ rm -f $ac_file
+ mv $tmp/config.h $ac_file
+ fi
+ else
+ cat $tmp/config.h
+ rm -f $tmp/config.h
+ fi
+# Compute $ac_file's index in $config_headers.
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+ case $_am_header in
+ $ac_file | $ac_file:* )
+ break ;;
+ * )
+ _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+ esac
+done
+echo "timestamp for $ac_file" >`(dirname $ac_file) 2>/dev/null ||
+$as_expr X$ac_file : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X$ac_file : 'X\(//\)[^/]' \| \
+ X$ac_file : 'X\(//\)$' \| \
+ X$ac_file : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X$ac_file |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`/stamp-h$_am_stamp_count
+done
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+#
+# CONFIG_COMMANDS section.
+#
+for ac_file in : $CONFIG_COMMANDS; do test "x$ac_file" = x: && continue
+ ac_dest=`echo "$ac_file" | sed 's,:.*,,'`
+ ac_source=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_dir=`(dirname "$ac_dest") 2>/dev/null ||
+$as_expr X"$ac_dest" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_dest" : 'X\(//\)[^/]' \| \
+ X"$ac_dest" : 'X\(//\)$' \| \
+ X"$ac_dest" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$ac_dest" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ { if $as_mkdir_p; then
+ mkdir -p "$ac_dir"
+ else
+ as_dir="$ac_dir"
+ as_dirs=
+ while test ! -d "$as_dir"; do
+ as_dirs="$as_dir $as_dirs"
+ as_dir=`(dirname "$as_dir") 2>/dev/null ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ done
+ test ! -n "$as_dirs" || mkdir $as_dirs
+ fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5
+echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;}
+ { (exit 1); exit 1; }; }; }
+
+ ac_builddir=.
+
+if test "$ac_dir" != .; then
+ ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+ ac_dir_suffix= ac_top_builddir=
+fi
+
+case $srcdir in
+ .) # No --srcdir option. We are building in place.
+ ac_srcdir=.
+ if test -z "$ac_top_builddir"; then
+ ac_top_srcdir=.
+ else
+ ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+ fi ;;
+ [\\/]* | ?:[\\/]* ) # Absolute path.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir ;;
+ *) # Relative path.
+ ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+
+# Do not use `cd foo && pwd` to compute absolute paths, because
+# the directories may not exist.
+case `pwd` in
+.) ac_abs_builddir="$ac_dir";;
+*)
+ case "$ac_dir" in
+ .) ac_abs_builddir=`pwd`;;
+ [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";;
+ *) ac_abs_builddir=`pwd`/"$ac_dir";;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_builddir=${ac_top_builddir}.;;
+*)
+ case ${ac_top_builddir}. in
+ .) ac_abs_top_builddir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;;
+ *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_srcdir=$ac_srcdir;;
+*)
+ case $ac_srcdir in
+ .) ac_abs_srcdir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;;
+ *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_srcdir=$ac_top_srcdir;;
+*)
+ case $ac_top_srcdir in
+ .) ac_abs_top_srcdir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;;
+ *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;;
+ esac;;
+esac
+
+
+ { echo "$as_me:$LINENO: executing $ac_dest commands" >&5
+echo "$as_me: executing $ac_dest commands" >&6;}
+ case $ac_dest in
+ depfiles ) test x"$AMDEP_TRUE" != x"" || for mf in $CONFIG_FILES; do
+ # Strip MF so we end up with the name of the file.
+ mf=`echo "$mf" | sed -e 's/:.*$//'`
+ # Check whether this is an Automake generated Makefile or not.
+ # We used to match only the files named `Makefile.in', but
+ # some people rename them; so instead we look at the file content.
+ # Grep'ing the first line is not enough: some people post-process
+ # each Makefile.in and add a new line on top of each file to say so.
+ # So let's grep whole file.
+ if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then
+ dirpart=`(dirname "$mf") 2>/dev/null ||
+$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$mf" : 'X\(//\)[^/]' \| \
+ X"$mf" : 'X\(//\)$' \| \
+ X"$mf" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$mf" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ else
+ continue
+ fi
+ # Extract the definition of DEPDIR, am__include, and am__quote
+ # from the Makefile without running `make'.
+ DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+ test -z "$DEPDIR" && continue
+ am__include=`sed -n 's/^am__include = //p' < "$mf"`
+ test -z "am__include" && continue
+ am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+ # When using ansi2knr, U may be empty or an underscore; expand it
+ U=`sed -n 's/^U = //p' < "$mf"`
+ # Find all dependency output files, they are included files with
+ # $(DEPDIR) in their names. We invoke sed twice because it is the
+ # simplest approach to changing $(DEPDIR) to its actual value in the
+ # expansion.
+ for file in `sed -n "
+ s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
+ # Make sure the directory exists.
+ test -f "$dirpart/$file" && continue
+ fdir=`(dirname "$file") 2>/dev/null ||
+$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$file" : 'X\(//\)[^/]' \| \
+ X"$file" : 'X\(//\)$' \| \
+ X"$file" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ { if $as_mkdir_p; then
+ mkdir -p $dirpart/$fdir
+ else
+ as_dir=$dirpart/$fdir
+ as_dirs=
+ while test ! -d "$as_dir"; do
+ as_dirs="$as_dir $as_dirs"
+ as_dir=`(dirname "$as_dir") 2>/dev/null ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ done
+ test ! -n "$as_dirs" || mkdir $as_dirs
+ fi || { { echo "$as_me:$LINENO: error: cannot create directory $dirpart/$fdir" >&5
+echo "$as_me: error: cannot create directory $dirpart/$fdir" >&2;}
+ { (exit 1); exit 1; }; }; }
+
+ # echo "creating $dirpart/$file"
+ echo '# dummy' > "$dirpart/$file"
+ done
+done
+ ;;
+ esac
+done
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+{ (exit 0); exit 0; }
+_ACEOF
+chmod +x $CONFIG_STATUS
+ac_clean_files=$ac_clean_files_save
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || { (exit 1); exit 1; }
+fi
+
Added: freeswitch/trunk/libs/sofia-sip/configure.ac
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/configure.ac Thu Dec 21 01:30:28 2006
@@ -0,0 +1,194 @@
+dnl Copyright (C) 2005-2006 Nokia Corporation
+dnl Contact: Pekka Pessi <pekka.pessi at nokia.com>
+dnl Licensed under LGPL. See file COPYING.
+
+dnl
+dnl ref: http://www.gnu.org/software/autoconf/manual/autoconf.info.gz
+dnl
+AC_PREREQ(2.57)
+
+dnl information on the package
+dnl ---------------------------
+
+dnl update both the version for AC_INIT and the LIBSOFIA_SIP_UA_MAJOR_MINOR
+AC_INIT([sofia-sip], [1.12.4work])
+AC_CONFIG_SRCDIR([libsofia-sip-ua/sip/sofia-sip/sip.h])
+AC_SUBST(VER_LIBSOFIA_SIP_UA_MAJOR_MINOR, [1.12])
+dnl Includedir specific to this sofia version
+AC_SUBST(include_sofiadir, '${includedir}/sofia-sip-1.12')
+AC_SUBST(LIBVER_SOFIA_SIP_UA_CUR, [3])
+AC_SUBST(LIBVER_SOFIA_SIP_UA_REV, [0])
+AC_SUBST(LIBVER_SOFIA_SIP_UA_AGE, [3])
+AC_SUBST(LIBVER_SOFIA_SIP_UA_SOVER, [0]) # CUR-AGE
+AC_SUBST(LIBVER_SOFIA_SIP_UA_GLIB_CUR, [3])
+AC_SUBST(LIBVER_SOFIA_SIP_UA_GLIB_REV, [0])
+AC_SUBST(LIBVER_SOFIA_SIP_UA_GLIB_AGE, [0])
+AC_SUBST(LIBVER_SOFIA_SIP_UA_GLIB_SOVER, [3]) # CUR-AGE
+
+# dnl calls AC_CANONICAL_ macros that are required by AM_INIT_AUTOMAKE
+SAC_CANONICAL_SYSTEM_CACHE_CHECK
+
+AM_INIT_AUTOMAKE
+AM_MAINTAINER_MODE
+AC_CONFIG_HEADERS([config.h])
+
+AC_GNU_SOURCE
+
+### checks for programs
+### -------------------
+AC_LANG([C])
+AC_CHECK_COMPILATION_ENVIRONMENT
+
+SAC_TOOL_CC
+AC_PROG_INSTALL
+AC_PROG_CPP
+AC_CHECK_PROG(ETAGS, etags, etags, echo)
+AC_CHECK_TOOL(AR, ar, ar)
+AC_CHECK_TOOL(LD, ld, ld)
+AC_PROG_LIBTOOL
+
+SAC_ENABLE_NDEBUG
+SAC_ENABLE_EXPENSIVE_CHECKS
+
+dnl Add parameters for aclocal
+AC_SUBST(ACLOCAL_AMFLAGS, "-I m4")
+
+AC_CHECK_PROG([DOXYGEN], [doxygen], [doxygen], [echo])
+AM_CONDITIONAL([HAVE_DOXYGEN], [test $DOXYGEN = doxygen])
+
+### checks for libraries
+### --------------------
+
+SAC_SOFIA_SU
+SAC_OPENSSL
+SAC_TPORT
+SAC_SU
+
+### internal modules
+### ----------------
+AC_DEFINE([HAVE_SOFIA_SIP], 1, [Define to 1 always])
+AC_DEFINE([HAVE_SOFIA_SRESOLV], 1, [Define to 1 if we use DNS library])
+AC_DEFINE([HAVE_SOFIA_SMIME], 0, [Define to 1 if we use S/MIME library])
+
+AC_ARG_ENABLE(stun,
+[ --disable-stun disable stun module (enabled)],
+ , enable_stun=yes)
+
+if test x$enable_stun = xno ; then
+ AC_MSG_WARN([** STUN support disabled **])
+elif test x${HAVE_OPENSSL} != x1 ; then
+ dnl compile STUN only if OPENSSL is available
+ AC_MSG_WARN([** TLS support for STUN disabled as OpenSSL headers and/or libraries were not found **])
+ AC_DEFINE([HAVE_SOFIA_STUN], 1, [Define to 1 if we use STUN library])
+else
+ AC_DEFINE([HAVE_SOFIA_STUN], 1, [Define to 1 if we use STUN library])
+fi
+
+dnl Disable NTLM support by default
+AC_ARG_ENABLE(ntlm,
+[ --enable-ntlm enable NTLM support (disabled)],
+ , enable_ntlm=no)
+
+if test x$enable_ntlm = xyes ; then
+ AC_DEFINE([HAVE_SOFIA_NTLM], 1, [Define to 1 if we use NTLM library])
+fi
+AM_CONDITIONAL([HAVE_NTLM], [test "x$enable_ntlm" = xyes])
+
+
+AC_DEFINE([HAVE_SRTP], 0, [Define to 1 if we use SRTP])
+AC_DEFINE([HAVE_UPNP], 0, [Define to 1 if we use UPnP])
+
+### checks for header files
+### -----------------------
+AC_HEADER_STDC
+
+### checks for declarations
+### -----------------------
+AC_CHECK_DECL([SIGPIPE], [
+AC_DEFINE([HAVE_SIGPIPE], 1, [Define to 1 if you have SIGPIPE])],,[
+#include <signal.h>
+])
+
+### checks for types
+### ----------------
+
+AC_TYPE_SIGNAL
+AC_TYPE_LONGLONG([
+AC_DEFINE([LLU], ["%llu"], [Define to format (%llu) for unsigned long long])dnl
+AC_DEFINE([LLI], ["%lli"], [Define to format (%lli) for long long])dnl
+AC_DEFINE([LLX], ["%llx"], [Define to format (%llx) for long long hex])dnl
+])
+AC_DEFINE([MOD_ZD], ["%zd"], [Define printf() modifier for ssize_t])
+AC_DEFINE([MOD_ZU], ["%zu"], [Define printf() modifier for size_t])
+
+### checks for structures
+### ---------------------
+
+### checks for typedefs, structures, and compiler characteristics.
+### --------------------------------------------------------------
+AC_C_CONST
+AC_C_INLINE
+AC_C_INLINE_DEFINE
+AC_C_BIGENDIAN
+
+AC_C_VAR_FUNC
+AC_C_MACRO_FUNCTION
+AC_C_KEYWORD_STRUCT
+
+AC_HEADER_TIME
+AC_TYPE_SIZE_T
+
+AC_STRUCT_SIN6
+AC_SYS_SA_LEN
+
+### checks for library functions
+### ----------------------------
+
+### checks for system services
+### --------------------------
+
+AC_DEV_URANDOM
+
+### output
+### ------
+
+AC_CONFIG_FILES([
+Makefile
+packages/Makefile
+packages/sofia-sip-ua.pc
+packages/sofia-sip-ua-glib.pc
+libsofia-sip-ua/Makefile
+libsofia-sip-ua/bnf/Makefile
+libsofia-sip-ua/docs/Makefile
+libsofia-sip-ua/docs/Doxyfile.version
+libsofia-sip-ua/docs/sofia-footer.html
+libsofia-sip-ua/features/Makefile
+libsofia-sip-ua/http/Makefile
+libsofia-sip-ua/ipt/Makefile
+libsofia-sip-ua/iptsec/Makefile
+libsofia-sip-ua/msg/Makefile
+libsofia-sip-ua/nea/Makefile
+libsofia-sip-ua/nta/Makefile
+libsofia-sip-ua/nth/Makefile
+libsofia-sip-ua/nua/Makefile
+libsofia-sip-ua/sdp/Makefile
+libsofia-sip-ua/sip/Makefile
+libsofia-sip-ua/soa/Makefile
+libsofia-sip-ua/sresolv/Makefile
+libsofia-sip-ua/stun/Makefile
+libsofia-sip-ua/su/Makefile
+libsofia-sip-ua/tport/Makefile
+libsofia-sip-ua/url/Makefile
+libsofia-sip-ua/features/sofia-sip/sofia_features.h
+libsofia-sip-ua-glib/Makefile
+libsofia-sip-ua-glib/su-glib/Makefile
+utils/Makefile
+utils/Doxyfile.build
+win32/Makefile
+win32/config.h
+])
+
+AC_CONFIG_COMMANDS([version],,[PACKAGE_VERSION=${PACKAGE_VERSION}])
+AC_CONFIG_FILES([packages/sofia-sip-${PACKAGE_VERSION}.spec:packages/sofia-sip.spec.in])
+
+AC_OUTPUT
Added: freeswitch/trunk/libs/sofia-sip/depcomp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/depcomp Thu Dec 21 01:30:28 2006
@@ -0,0 +1,522 @@
+#! /bin/sh
+# depcomp - compile a program generating dependencies as side-effects
+
+scriptversion=2004-05-31.23
+
+# Copyright (C) 1999, 2000, 2003, 2004 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program 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 General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Alexandre Oliva <oliva at dcc.unicamp.br>.
+
+case $1 in
+ '')
+ echo "$0: No command. Try \`$0 --help' for more information." 1>&2
+ exit 1;
+ ;;
+ -h | --h*)
+ cat <<\EOF
+Usage: depcomp [--help] [--version] PROGRAM [ARGS]
+
+Run PROGRAMS ARGS to compile a file, generating dependencies
+as side-effects.
+
+Environment variables:
+ depmode Dependency tracking mode.
+ source Source file read by `PROGRAMS ARGS'.
+ object Object file output by `PROGRAMS ARGS'.
+ DEPDIR directory where to store dependencies.
+ depfile Dependency file to output.
+ tmpdepfile Temporary file to use when outputing dependencies.
+ libtool Whether libtool is used (yes/no).
+
+Report bugs to <bug-automake at gnu.org>.
+EOF
+ exit 0
+ ;;
+ -v | --v*)
+ echo "depcomp $scriptversion"
+ exit 0
+ ;;
+esac
+
+if test -z "$depmode" || test -z "$source" || test -z "$object"; then
+ echo "depcomp: Variables source, object and depmode must be set" 1>&2
+ exit 1
+fi
+
+# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
+depfile=${depfile-`echo "$object" |
+ sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
+tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
+
+rm -f "$tmpdepfile"
+
+# Some modes work just like other modes, but use different flags. We
+# parameterize here, but still list the modes in the big case below,
+# to make depend.m4 easier to write. Note that we *cannot* use a case
+# here, because this file can only contain one case statement.
+if test "$depmode" = hp; then
+ # HP compiler uses -M and no extra arg.
+ gccflag=-M
+ depmode=gcc
+fi
+
+if test "$depmode" = dashXmstdout; then
+ # This is just like dashmstdout with a different argument.
+ dashmflag=-xM
+ depmode=dashmstdout
+fi
+
+case "$depmode" in
+gcc3)
+## gcc 3 implements dependency tracking that does exactly what
+## we want. Yay! Note: for some reason libtool 1.4 doesn't like
+## it if -MD -MP comes after the -MF stuff. Hmm.
+ "$@" -MT "$object" -MD -MP -MF "$tmpdepfile"
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ mv "$tmpdepfile" "$depfile"
+ ;;
+
+gcc)
+## There are various ways to get dependency output from gcc. Here's
+## why we pick this rather obscure method:
+## - Don't want to use -MD because we'd like the dependencies to end
+## up in a subdir. Having to rename by hand is ugly.
+## (We might end up doing this anyway to support other compilers.)
+## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
+## -MM, not -M (despite what the docs say).
+## - Using -M directly means running the compiler twice (even worse
+## than renaming).
+ if test -z "$gccflag"; then
+ gccflag=-MD,
+ fi
+ "$@" -Wp,"$gccflag$tmpdepfile"
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
+## The second -e expression handles DOS-style file names with drive letters.
+ sed -e 's/^[^:]*: / /' \
+ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
+## This next piece of magic avoids the `deleted header file' problem.
+## The problem is that when a header file which appears in a .P file
+## is deleted, the dependency causes make to die (because there is
+## typically no way to rebuild the header). We avoid this by adding
+## dummy dependencies for each header file. Too bad gcc doesn't do
+## this for us directly.
+ tr ' ' '
+' < "$tmpdepfile" |
+## Some versions of gcc put a space before the `:'. On the theory
+## that the space means something, we add a space to the output as
+## well.
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+hp)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+sgi)
+ if test "$libtool" = yes; then
+ "$@" "-Wp,-MDupdate,$tmpdepfile"
+ else
+ "$@" -MDupdate "$tmpdepfile"
+ fi
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+
+ if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
+ echo "$object : \\" > "$depfile"
+
+ # Clip off the initial element (the dependent). Don't try to be
+ # clever and replace this with sed code, as IRIX sed won't handle
+ # lines with more than a fixed number of characters (4096 in
+ # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
+ # the IRIX cc adds comments like `#:fec' to the end of the
+ # dependency line.
+ tr ' ' '
+' < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
+ tr '
+' ' ' >> $depfile
+ echo >> $depfile
+
+ # The second pass generates a dummy entry for each header file.
+ tr ' ' '
+' < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
+ >> $depfile
+ else
+ # The sourcefile does not contain any dependencies, so just
+ # store a dummy comment line, to avoid errors with the Makefile
+ # "include basename.Plo" scheme.
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+aix)
+ # The C for AIX Compiler uses -M and outputs the dependencies
+ # in a .u file. In older versions, this file always lives in the
+ # current directory. Also, the AIX compiler puts `$object:' at the
+ # start of each line; $object doesn't have directory information.
+ # Version 6 uses the directory in both cases.
+ stripped=`echo "$object" | sed 's/\(.*\)\..*$/\1/'`
+ tmpdepfile="$stripped.u"
+ if test "$libtool" = yes; then
+ "$@" -Wc,-M
+ else
+ "$@" -M
+ fi
+ stat=$?
+
+ if test -f "$tmpdepfile"; then :
+ else
+ stripped=`echo "$stripped" | sed 's,^.*/,,'`
+ tmpdepfile="$stripped.u"
+ fi
+
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+
+ if test -f "$tmpdepfile"; then
+ outname="$stripped.o"
+ # Each line is of the form `foo.o: dependent.h'.
+ # Do two passes, one to just change these to
+ # `$object: dependent.h' and one to simply `dependent.h:'.
+ sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile"
+ sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile"
+ else
+ # The sourcefile does not contain any dependencies, so just
+ # store a dummy comment line, to avoid errors with the Makefile
+ # "include basename.Plo" scheme.
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+icc)
+ # Intel's C compiler understands `-MD -MF file'. However on
+ # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c
+ # ICC 7.0 will fill foo.d with something like
+ # foo.o: sub/foo.c
+ # foo.o: sub/foo.h
+ # which is wrong. We want:
+ # sub/foo.o: sub/foo.c
+ # sub/foo.o: sub/foo.h
+ # sub/foo.c:
+ # sub/foo.h:
+ # ICC 7.1 will output
+ # foo.o: sub/foo.c sub/foo.h
+ # and will wrap long lines using \ :
+ # foo.o: sub/foo.c ... \
+ # sub/foo.h ... \
+ # ...
+
+ "$@" -MD -MF "$tmpdepfile"
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ # Each line is of the form `foo.o: dependent.h',
+ # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
+ # Do two passes, one to just change these to
+ # `$object: dependent.h' and one to simply `dependent.h:'.
+ sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
+ # Some versions of the HPUX 10.20 sed can't process this invocation
+ # correctly. Breaking it into two sed invocations is a workaround.
+ sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" |
+ sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+tru64)
+ # The Tru64 compiler uses -MD to generate dependencies as a side
+ # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'.
+ # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
+ # dependencies in `foo.d' instead, so we check for that too.
+ # Subdirectories are respected.
+ dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+ test "x$dir" = "x$object" && dir=
+ base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
+
+ if test "$libtool" = yes; then
+ # Dependencies are output in .lo.d with libtool 1.4.
+ # With libtool 1.5 they are output both in $dir.libs/$base.o.d
+ # and in $dir.libs/$base.o.d and $dir$base.o.d. We process the
+ # latter, because the former will be cleaned when $dir.libs is
+ # erased.
+ tmpdepfile1="$dir.libs/$base.lo.d"
+ tmpdepfile2="$dir$base.o.d"
+ tmpdepfile3="$dir.libs/$base.d"
+ "$@" -Wc,-MD
+ else
+ tmpdepfile1="$dir$base.o.d"
+ tmpdepfile2="$dir$base.d"
+ tmpdepfile3="$dir$base.d"
+ "$@" -MD
+ fi
+
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+ exit $stat
+ fi
+
+ if test -f "$tmpdepfile1"; then
+ tmpdepfile="$tmpdepfile1"
+ elif test -f "$tmpdepfile2"; then
+ tmpdepfile="$tmpdepfile2"
+ else
+ tmpdepfile="$tmpdepfile3"
+ fi
+ if test -f "$tmpdepfile"; then
+ sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
+ # That's a tab and a space in the [].
+ sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
+ else
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+#nosideeffect)
+ # This comment above is used by automake to tell side-effect
+ # dependency tracking mechanisms from slower ones.
+
+dashmstdout)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout, regardless of -o.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test $1 != '--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ # Remove `-o $object'.
+ IFS=" "
+ for arg
+ do
+ case $arg in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift # fnord
+ shift # $arg
+ ;;
+ esac
+ done
+
+ test -z "$dashmflag" && dashmflag=-M
+ # Require at least two characters before searching for `:'
+ # in the target name. This is to cope with DOS-style filenames:
+ # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise.
+ "$@" $dashmflag |
+ sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile"
+ rm -f "$depfile"
+ cat < "$tmpdepfile" > "$depfile"
+ tr ' ' '
+' < "$tmpdepfile" | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+dashXmstdout)
+ # This case only exists to satisfy depend.m4. It is never actually
+ # run, as this mode is specially recognized in the preamble.
+ exit 1
+ ;;
+
+makedepend)
+ "$@" || exit $?
+ # Remove any Libtool call
+ if test "$libtool" = yes; then
+ while test $1 != '--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+ # X makedepend
+ shift
+ cleared=no
+ for arg in "$@"; do
+ case $cleared in
+ no)
+ set ""; shift
+ cleared=yes ;;
+ esac
+ case "$arg" in
+ -D*|-I*)
+ set fnord "$@" "$arg"; shift ;;
+ # Strip any option that makedepend may not understand. Remove
+ # the object too, otherwise makedepend will parse it as a source file.
+ -*|$object)
+ ;;
+ *)
+ set fnord "$@" "$arg"; shift ;;
+ esac
+ done
+ obj_suffix="`echo $object | sed 's/^.*\././'`"
+ touch "$tmpdepfile"
+ ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
+ rm -f "$depfile"
+ cat < "$tmpdepfile" > "$depfile"
+ sed '1,2d' "$tmpdepfile" | tr ' ' '
+' | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile" "$tmpdepfile".bak
+ ;;
+
+cpp)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test $1 != '--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ # Remove `-o $object'.
+ IFS=" "
+ for arg
+ do
+ case $arg in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift # fnord
+ shift # $arg
+ ;;
+ esac
+ done
+
+ "$@" -E |
+ sed -n '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' |
+ sed '$ s: \\$::' > "$tmpdepfile"
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ cat < "$tmpdepfile" >> "$depfile"
+ sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+msvisualcpp)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout, regardless of -o,
+ # because we must use -o when running libtool.
+ "$@" || exit $?
+ IFS=" "
+ for arg
+ do
+ case "$arg" in
+ "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
+ set fnord "$@"
+ shift
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift
+ shift
+ ;;
+ esac
+ done
+ "$@" -E |
+ sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile"
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile"
+ echo " " >> "$depfile"
+ . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+none)
+ exec "$@"
+ ;;
+
+*)
+ echo "Unknown depmode $depmode" 1>&2
+ exit 1
+ ;;
+esac
+
+exit 0
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
Added: freeswitch/trunk/libs/sofia-sip/docs/build_system.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/docs/build_system.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,97 @@
+=============================
+Sofia-SIP build system README
+=============================
+
+:Author: Kai Vehmanen <kai -dot vehmanen -at- nokia -dot- com>
+:Author: Pekka Pessi <pekka -dot pessi -at- nokia -dot- com>
+:Version: 20051011-5
+:Formatting: reStructuredText, http://docutils.sourceforge.net/rst.html
+
+Introduction
+============
+
+The Sofia-SIP build system practices are documented in this
+file. The instructions are aimed at developers.
+
+Quick start
+===========
+
+To build Sofia-IP::
+
+ sh> ``./autogen.sh`` (if building from a fresh CVS checkout)
+ sh> ``./configure``
+ sh> ``make``
+
+Autotool notes
+==============
+
+Macros
+------
+
+Sofia-SIP specific macros are prefixed with "``SAC\_``" and are
+defined in files under the toplevel "m4/" directory.
+
+Makefile target notes
+---------------------
+
+- all optionally compiled source files should be listed
+ separately in ``DIST_SOURCES`` variable (otherwise ``make dist``
+ will fail)
+
+Maintainer mode
+---------------
+
+Sofia-SIP tree is by default configured with automake
+maintainer mode disable. In other words, Makefiles do not
+contain rules for recreating or updating configure, Makefiles
+or other autotool-generated files. To update these files,
+you need to run top-level autogen.sh script.
+
+Those developers who need to often modify configure.ac, Makefile.am
+and macro files, can enable maintainer mode with configure
+option '--enable-maintainer-mode'.
+
+Running tests
+=============
+
+Sofia-SIP has quite complete suite of test cases. It is prudent to
+run them while making changes and before committing them to revision
+control system. However, running certain tests takes quite a long
+time. Therefore, they are run only if the environment variable
+EXPENSIVE_CHECKS has been set. EXPENSIVE_CHECKS is also set by the build
+system if configure option '--enable-expensive-checks' has been used.
+
+Code-tree layout
+================
+
+Most of the code resides in the libsofia-sip-ua directory.
+The main library, libsofia-sip-ua.so, is created by
+collecting object files (for example bnf/bnf_objs.o) from
+individual modules.
+
+There are some portability issues with the way the
+shared library is currently built, and we are looking
+for ways to improve the situation.
+
+Making releases
+===============
+
+See sofia-sip/docs/release_management.txt
+
+Developer documentation
+=======================
+
+Generating reference documentation from source code
+---------------------------------------------------
+
+The libsofia-sip-ua library has a top-level make target
+"doxygen" for generating the HTML reference documentation.
+The pages will be created to libsofia-sip-ua/docs
+subdirectory.
+
+This special target is primarily meant for use by
+the Sofia-SIP website admins, but can be used by anyone
+with the proper set of tools:
+
+- Doxygen, http://www.stack.nl/~dimitri/doxygen/
+- Dot graph tool, http://www.research.att.com/sw/tools/graphviz/
Added: freeswitch/trunk/libs/sofia-sip/docs/devel_platform_notes.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/docs/devel_platform_notes.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,42 @@
+======================================================
+Notes on compiling Sofia-SIP in different environments
+======================================================
+
+Using GNU Autotools
+-------------------
+
+If you modify autoconf or automake files (configure.ac or Makefile.am) or if
+you compile Sofia SIP that you pulled from darcs or CVS repo, you need
+up-to-date autotools. Autoconf should be at least 2.57 and automake should
+be at least 1.7. You can avoid running autoreconf explicitly if you use
+./configure option --enable-maintainer-mode.
+
+Generic POSIX (GNU/Linux, BSD, ...)
+-----------------------------------
+
+Sofia-SIP should compile out-of-the-box on generic POSIX
+machines. Use the standard GNU autotool 'configure+make'
+procedure to build the software. See top-level INSTALL
+for more information.
+
+Mac OS X
+--------
+
+TBD
+
+Win32 / Mingw
+-------------
+
+TBD
+
+Win32 / Cygwin
+--------------
+
+TBD
+
+Visual-C on win32
+-----------------
+
+See sofia-sip/win32/README.txt
+
+ LocalWords: automake
Added: freeswitch/trunk/libs/sofia-sip/docs/release_management.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/docs/release_management.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,136 @@
+===================================
+Sofia-SIP release management README
+===================================
+
+:Author: Kai Vehmanen <kai -dot vehmanen -at- nokia -dot- com>
+:Version: 20060809-12
+:Formatting: reStructuredText, http://docutils.sourceforge.net/rst.html
+
+Introduction
+============
+
+This README contains instructions for making new Sofia-SIP releases.
+
+Links to other resources
+========================
+
+sofia-sip/README.developers
+
+The release notes
+=================
+
+The release notes should contain the following sections:
+
+- about Sofia-SIP
+ - copied verbatim from sofia-sip/README
+- list of changes since last release
+ - maintained in sofia-sip/RELEASE
+ - see diff between cvs/darcs between previous and
+ this version
+ - written in freshmeat.net "Changes:" style
+- notes on API/ABI interface changes
+ - maintained in sofia-sip/RELEASE
+ - all changes in public interfaces, plus other
+ notes that developers should be aware of
+- contributors to this release
+ - maintained in sofia-sip/RELEASE
+ - also sofia-sip/AUTHORS should be updated (file
+ should list all persons/companies who have code/scripts/etc
+ copyrighted to them in the sofia-sip tree)
+
+See the RELEASE.template file for a full list of release note
+sections.
+
+Making the release tarball
+==========================
+
+- basics: check system clock of the build host ;)
+- update the version number in sofia-sip/configure.ac
+- make sure the library versions are correct, and you've
+ frozen all library interfaces (with correct entries in
+ ChangeLog files), see README.developers for more information
+ on library versioning in general
+- make sure everything that is supposed to be in the
+ release is in the master darcs tree
+- run 'make distcheck' to verify everything is ready for
+ release (requires automake-1.7 or newer)
+- tag repos (darcs and any slave trees) with release tag
+ 'rel-sofia-sip-x_y_z', where x_y_z is the version number (see
+ README.developers):
+ sh> darcs tag -m"rel-sofia-sip-x_y_z"
+ sh> cvs tag rel-sofia-sip-x_y_z
+- take a fresh checkout of the release using the release tag
+ sh> darcs get http://sofia-sip.org/repos/sofia-sip --tag=rel-sofia-sip-1_yy_z
+- create the release tarball with "make distcheck"
+- calculate md5 and sha1 hashes using md5sum and sha1sum utilities,
+ and copy the values to the release-notes (see below)
+
+Creating the release notes and updating the website
+===================================================
+
+- combine the sofia-sip/RELEASE contents with
+ the template found from sfnet_www/templates/relnotes.txt
+- store the resulting release notes to
+ sfnet_www/relnotes/relnotes-sofia-sip-x.y.z.txt
+- add explicit link to the release notes to
+ sfnet_www/download.html (three most recent releases,
+ see guidelines in the html comments)
+- update sfnet_www/index.html to mention the latest
+ release
+- commit the change to sf.net website CVS, and run the
+ sfnet_www/put_online.sh script at the sourceforge.net
+ shell server
+
+Uploading the release to sourceforge.net
+========================================
+
+- use the the 'Admin' -> 'File releases' tool for
+ creating a new release
+- to upload the file, you can use for example ncftpput:
+ ncftpput -u anonymous -p USER at users.sourceforge.net upload.sourceforge.net /incoming/ sofia-sip-x.y.z.tar.gz
+- attach the release notes (relnotes-sofia-sip-x.y.z.txt)
+ to the file release
+
+Announcing releases
+===================
+
+- send an announcement mail, containing the
+ release notes, to sofia-sip-devel at lists.sourceforge.net
+- post a news item to freshmeat.net 'sofia-sip'
+ project (current project owner: Kai Vehmanen)
+
+After release
+=============
+
+- replace the RELEASE file with RELEASE.template, and
+ commit it to master source repository (see sofia-sip/README.developers)
+- change version in configure.ac from "X.Y.Z" to
+ "X.Y.Zwork" (as it is in many cases unknown what the
+ next version will be)
+- make a "tree open for development" commit
+
+Syncing CVS and darcs (or some other VCS)
+=========================================
+
+Some tips for synchronizing from/to different version controlled
+tree.
+
+- As CVS cannot trace file addition/move/removals, you need
+ to be extra careful with these. With darcs, you can use the
+ 'darcs changes -v' command to track down all fileops since
+ last synchronization.
+
+- Always tag the src-tree with "syncuser-fromvcs-to-tovcs-yearmmdd".
+
+- Add a top-level ChangeLog entry that documents all the
+ changes made outside the target tree (what, who and when -
+ for example produced with the "darcs changes --summary"
+ command).
+
+Checking API/ABI compatibility
+==============================
+
+- Use a unit test binary built against an old library,
+ to verify a new library version (forwards-compatibility).
+- Use the 'icheck' tool (in Debian) to make comparison
+ between two released versions.
Added: freeswitch/trunk/libs/sofia-sip/install-sh
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/install-sh Thu Dec 21 01:30:28 2006
@@ -0,0 +1,322 @@
+#!/bin/sh
+# install - install a program, script, or datafile
+
+scriptversion=2004-09-10.20
+
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
+#
+#
+# FSF changes to this file are in the public domain.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch. It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+chmodcmd="$chmodprog 0755"
+chowncmd=
+chgrpcmd=
+stripcmd=
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=
+dst=
+dir_arg=
+dstarg=
+no_target_directory=
+
+usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
+ or: $0 [OPTION]... SRCFILES... DIRECTORY
+ or: $0 [OPTION]... -t DIRECTORY SRCFILES...
+ or: $0 [OPTION]... -d DIRECTORIES...
+
+In the 1st form, copy SRCFILE to DSTFILE.
+In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
+In the 4th, create DIRECTORIES.
+
+Options:
+-c (ignored)
+-d create directories instead of installing files.
+-g GROUP $chgrpprog installed files to GROUP.
+-m MODE $chmodprog installed files to MODE.
+-o USER $chownprog installed files to USER.
+-s $stripprog installed files.
+-t DIRECTORY install into DIRECTORY.
+-T report an error if DSTFILE is a directory.
+--help display this help and exit.
+--version display version info and exit.
+
+Environment variables override the default commands:
+ CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG
+"
+
+while test -n "$1"; do
+ case $1 in
+ -c) shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ --help) echo "$usage"; exit 0;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd=$stripprog
+ shift
+ continue;;
+
+ -t) dstarg=$2
+ shift
+ shift
+ continue;;
+
+ -T) no_target_directory=true
+ shift
+ continue;;
+
+ --version) echo "$0 $scriptversion"; exit 0;;
+
+ *) # When -d is used, all remaining arguments are directories to create.
+ # When -t is used, the destination is already specified.
+ test -n "$dir_arg$dstarg" && break
+ # Otherwise, the last argument is the destination. Remove it from $@.
+ for arg
+ do
+ if test -n "$dstarg"; then
+ # $@ is not empty: it contains at least $arg.
+ set fnord "$@" "$dstarg"
+ shift # fnord
+ fi
+ shift # arg
+ dstarg=$arg
+ done
+ break;;
+ esac
+done
+
+if test -z "$1"; then
+ if test -z "$dir_arg"; then
+ echo "$0: no input file specified." >&2
+ exit 1
+ fi
+ # It's OK to call `install-sh -d' without argument.
+ # This can happen when creating conditional directories.
+ exit 0
+fi
+
+for src
+do
+ # Protect names starting with `-'.
+ case $src in
+ -*) src=./$src ;;
+ esac
+
+ if test -n "$dir_arg"; then
+ dst=$src
+ src=
+
+ if test -d "$dst"; then
+ mkdircmd=:
+ chmodcmd=
+ else
+ mkdircmd=$mkdirprog
+ fi
+ else
+ # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
+ # might cause directories to be created, which would be especially bad
+ # if $src (and thus $dsttmp) contains '*'.
+ if test ! -f "$src" && test ! -d "$src"; then
+ echo "$0: $src does not exist." >&2
+ exit 1
+ fi
+
+ if test -z "$dstarg"; then
+ echo "$0: no destination specified." >&2
+ exit 1
+ fi
+
+ dst=$dstarg
+ # Protect names starting with `-'.
+ case $dst in
+ -*) dst=./$dst ;;
+ esac
+
+ # If destination is a directory, append the input filename; won't work
+ # if double slashes aren't ignored.
+ if test -d "$dst"; then
+ if test -n "$no_target_directory"; then
+ echo "$0: $dstarg: Is a directory" >&2
+ exit 1
+ fi
+ dst=$dst/`basename "$src"`
+ fi
+ fi
+
+ # This sed command emulates the dirname command.
+ dstdir=`echo "$dst" | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+ # Make sure that the destination directory exists.
+
+ # Skip lots of stat calls in the usual case.
+ if test ! -d "$dstdir"; then
+ defaultIFS='
+ '
+ IFS="${IFS-$defaultIFS}"
+
+ oIFS=$IFS
+ # Some sh's can't handle IFS=/ for some reason.
+ IFS='%'
+ set - `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'`
+ IFS=$oIFS
+
+ pathcomp=
+
+ while test $# -ne 0 ; do
+ pathcomp=$pathcomp$1
+ shift
+ if test ! -d "$pathcomp"; then
+ $mkdirprog "$pathcomp"
+ # mkdir can fail with a `File exist' error in case several
+ # install-sh are creating the directory concurrently. This
+ # is OK.
+ test -d "$pathcomp" || exit
+ fi
+ pathcomp=$pathcomp/
+ done
+ fi
+
+ if test -n "$dir_arg"; then
+ $doit $mkdircmd "$dst" \
+ && { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \
+ && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \
+ && { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \
+ && { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; }
+
+ else
+ dstfile=`basename "$dst"`
+
+ # Make a couple of temp file names in the proper directory.
+ dsttmp=$dstdir/_inst.$$_
+ rmtmp=$dstdir/_rm.$$_
+
+ # Trap to clean up those temp files at exit.
+ trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
+ trap '(exit $?); exit' 1 2 13 15
+
+ # Copy the file name to the temp name.
+ $doit $cpprog "$src" "$dsttmp" &&
+
+ # and set any options; do chmod last to preserve setuid bits.
+ #
+ # If any of these fail, we abort the whole thing. If we want to
+ # ignore errors from any of these, just make sure not to ignore
+ # errors from the above "$doit $cpprog $src $dsttmp" command.
+ #
+ { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \
+ && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \
+ && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \
+ && { test -z "$chmodcmd" || $doit $chmodcmd "$dsttmp"; } &&
+
+ # Now rename the file to the real destination.
+ { $doit $mvcmd -f "$dsttmp" "$dstdir/$dstfile" 2>/dev/null \
+ || {
+ # The rename failed, perhaps because mv can't rename something else
+ # to itself, or perhaps because mv is so ancient that it does not
+ # support -f.
+
+ # Now remove or move aside any old file at destination location.
+ # We try this two ways since rm can't unlink itself on some
+ # systems and the destination file might be busy for other
+ # reasons. In this case, the final cleanup might fail but the new
+ # file should still install successfully.
+ {
+ if test -f "$dstdir/$dstfile"; then
+ $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \
+ || $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \
+ || {
+ echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2
+ (exit 1); exit
+ }
+ else
+ :
+ fi
+ } &&
+
+ # Now rename the file to the real destination.
+ $doit $mvcmd "$dsttmp" "$dstdir/$dstfile"
+ }
+ }
+ fi || { (exit 1); exit; }
+done
+
+# The final little trick to "correctly" pass the exit status to the exit trap.
+{
+ (exit 0); exit
+}
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/ChangeLog Thu Dec 21 01:30:28 2006
@@ -0,0 +1,25 @@
+2006-12-05 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * libsofia-sip-ua-glib interface v3 frozen, version to 3:0:0 (for 1.12.5 release).
+ * nua-glib submodule has been moved from libsofia-sip-ua-glib,
+ and sofia-sip, to a standalone sofia-nua-glib package.
+
+2006-11-22 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * libsofia-sip-ua-glib interface v2 frozen, version to 2:0:2 (for 1.12.4 release).
+
+2006-07-25 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * libsofia-sip-ua-glib interface v1 frozen, version to 1:0:1 (for 1.12.2 release).
+
+2006-06-16 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * libsofia-sip-ua-glib interface v0 frozen, version to 0:0:0.
+
+2006-04-12 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * Modified build system to require glib-2.4 or newer to compile libsofia-sip-ua-glib.
+
+2006-03-09 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * libsofia-sip-ua-glib created.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/Makefile.am Thu Dec 21 01:30:28 2006
@@ -0,0 +1,56 @@
+#
+# Makefile.am for sofia-sip/libsofia-sip-ua-glib
+#
+# Copyright (C) 2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+#
+
+AUTOMAKE_OPTIONS = foreign 1.7
+
+SUBDIRS=su-glib
+
+GLIB_TARGETS=su-glib/libsu-glib.la
+
+lib_LTLIBRARIES =
+if HAVE_GLIB
+lib_LTLIBRARIES += libsofia-sip-ua-glib.la
+endif
+
+libsofia_sip_ua_glib_la_SOURCES =
+libsofia_sip_ua_glib_la_LIBADD = $(GLIB_TARGETS) $(GLIB_LIBS)
+
+# set the libtool version info version:revision:age for libsofia-sip-ua-glib
+# - soname to 'libsofia-sip-ua-glib.so.(CUR-AGE)'
+libsofia_sip_ua_glib_la_LDFLAGS = \
+ -version-info $(LIBVER_SOFIA_SIP_UA_GLIB_CUR):$(LIBVER_SOFIA_SIP_UA_GLIB_REV):$(LIBVER_SOFIA_SIP_UA_GLIB_AGE)
+
+DOXYGEN = doxygen
+
+EXTRA_DIST = docs/Doxyfile.aliases \
+ docs/Doxyfile.conf \
+ docs/Doxyfile.version
+
+built-sources: built-sources-recursive
+clean-built-sources: clean-built-sources-recursive
+
+built-sources-recursive clean-built-sources-recursive:
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $@ in $$subdir"; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$target) \
+ done;
+
+doxygen: built-sources
+ @cd ${srcdir} ;\
+ mkdir -p docs docs/html &&\
+ for d in $(DIST_SUBDIRS) $(DIST_SUBDIRS); do \
+ test -r $$d/Doxyfile \
+ && pushd $$d > /dev/null \
+ && echo running ${DOXYGEN} in $$d \
+ && ${DOXYGEN} \
+ && popd > /dev/null ; \
+ done
+ cd ${srcdir}/docs/html && ../../${top_srcdir}/libsofia-sip-ua/docs/hide_emails.sh
+
+.PHONY: built-sources built-sources-am doxygen
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/Makefile.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1,630 @@
+# 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.
+
+ at SET_MAKE@
+
+#
+# Makefile.am for sofia-sip/libsofia-sip-ua-glib
+#
+# Copyright (C) 2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+#
+
+SOURCES = $(libsofia_sip_ua_glib_la_SOURCES)
+
+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@
+ at HAVE_GLIB_TRUE@am__append_1 = libsofia-sip-ua-glib.la
+subdir = libsofia-sip-ua-glib
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ChangeLog
+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 =
+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|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(libdir)"
+libLTLIBRARIES_INSTALL = $(INSTALL)
+LTLIBRARIES = $(lib_LTLIBRARIES)
+am__DEPENDENCIES_1 = su-glib/libsu-glib.la
+am__DEPENDENCIES_2 =
+libsofia_sip_ua_glib_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_2)
+am_libsofia_sip_ua_glib_la_OBJECTS =
+libsofia_sip_ua_glib_la_OBJECTS = \
+ $(am_libsofia_sip_ua_glib_la_OBJECTS)
+ at HAVE_GLIB_TRUE@am_libsofia_sip_ua_glib_la_rpath = -rpath $(libdir)
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) -I$(top_builddir)/libsofia-sip-ua/su/sofia-sip
+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 = $(libsofia_sip_ua_glib_la_SOURCES)
+DIST_SOURCES = $(libsofia_sip_ua_glib_la_SOURCES)
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+ html-recursive info-recursive install-data-recursive \
+ install-exec-recursive install-info-recursive \
+ install-recursive installcheck-recursive installdirs-recursive \
+ pdf-recursive ps-recursive uninstall-info-recursive \
+ uninstall-recursive
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+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@
+AUTOMAKE_OPTIONS = foreign 1.7
+SUBDIRS = su-glib
+GLIB_TARGETS = su-glib/libsu-glib.la
+lib_LTLIBRARIES = $(am__append_1)
+libsofia_sip_ua_glib_la_SOURCES =
+libsofia_sip_ua_glib_la_LIBADD = $(GLIB_TARGETS) $(GLIB_LIBS)
+
+# set the libtool version info version:revision:age for libsofia-sip-ua-glib
+# - soname to 'libsofia-sip-ua-glib.so.(CUR-AGE)'
+libsofia_sip_ua_glib_la_LDFLAGS = \
+ -version-info $(LIBVER_SOFIA_SIP_UA_GLIB_CUR):$(LIBVER_SOFIA_SIP_UA_GLIB_REV):$(LIBVER_SOFIA_SIP_UA_GLIB_AGE)
+
+EXTRA_DIST = docs/Doxyfile.aliases \
+ docs/Doxyfile.conf \
+ docs/Doxyfile.version
+
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.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) --foreign libsofia-sip-ua-glib/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --foreign libsofia-sip-ua-glib/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
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(libdir)" || $(mkdir_p) "$(DESTDIR)$(libdir)"
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ if test -f $$p; then \
+ f=$(am__strip_dir) \
+ echo " $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \
+ else :; fi; \
+ done
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @set -x; list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ p=$(am__strip_dir) \
+ echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \
+ $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_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
+libsofia-sip-ua-glib.la: $(libsofia_sip_ua_glib_la_OBJECTS) $(libsofia_sip_ua_glib_la_DEPENDENCIES)
+ $(LINK) $(am_libsofia_sip_ua_glib_la_rpath) $(libsofia_sip_ua_glib_la_LDFLAGS) $(libsofia_sip_ua_glib_la_OBJECTS) $(libsofia_sip_ua_glib_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+uninstall-info-am:
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+# (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+ @set fnord $$MAKEFLAGS; amf=$$2; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+mostlyclean-recursive clean-recursive distclean-recursive \
+maintainer-clean-recursive:
+ @set fnord $$MAKEFLAGS; amf=$$2; \
+ dot_seen=no; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ rev=''; for subdir in $$list; do \
+ if test "$$subdir" = "."; then :; else \
+ rev="$$subdir $$rev"; \
+ fi; \
+ done; \
+ rev="$$rev ."; \
+ target=`echo $@ | sed s/-recursive//`; \
+ for subdir in $$rev; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+ done && test -z "$$fail"
+tags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+ done
+ctags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+ 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: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ 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: ctags-recursive $(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
+
+distdir: $(DISTFILES)
+ $(mkdir_p) $(distdir)/docs
+ @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
+ list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test -d "$(distdir)/$$subdir" \
+ || $(mkdir_p) "$(distdir)/$$subdir" \
+ || exit 1; \
+ distdir=`$(am__cd) $(distdir) && pwd`; \
+ top_distdir=`$(am__cd) $(top_distdir) && pwd`; \
+ (cd $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$top_distdir" \
+ distdir="$$distdir/$$subdir" \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(LTLIBRARIES)
+installdirs: installdirs-recursive
+installdirs-am:
+ for dir in "$(DESTDIR)$(libdir)"; do \
+ test -z "$$dir" || $(mkdir_p) "$$dir"; \
+ done
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+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)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-libtool distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-exec-am: install-libLTLIBRARIES
+
+install-info: install-info-recursive
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-libLTLIBRARIES
+
+uninstall-info: uninstall-info-recursive
+
+.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am check check-am \
+ clean clean-generic clean-libLTLIBRARIES clean-libtool \
+ clean-recursive ctags ctags-recursive distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-recursive distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-exec install-exec-am install-info \
+ install-info-am install-libLTLIBRARIES install-man \
+ install-strip installcheck installcheck-am installdirs \
+ installdirs-am maintainer-clean maintainer-clean-generic \
+ maintainer-clean-recursive mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool mostlyclean-recursive \
+ pdf pdf-am ps ps-am tags tags-recursive uninstall uninstall-am \
+ uninstall-info-am uninstall-libLTLIBRARIES
+
+
+built-sources: built-sources-recursive
+clean-built-sources: clean-built-sources-recursive
+
+built-sources-recursive clean-built-sources-recursive:
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $@ in $$subdir"; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$target) \
+ done;
+
+doxygen: built-sources
+ @cd ${srcdir} ;\
+ mkdir -p docs docs/html &&\
+ for d in $(DIST_SUBDIRS) $(DIST_SUBDIRS); do \
+ test -r $$d/Doxyfile \
+ && pushd $$d > /dev/null \
+ && echo running ${DOXYGEN} in $$d \
+ && ${DOXYGEN} \
+ && popd > /dev/null ; \
+ done
+ cd ${srcdir}/docs/html && ../../${top_srcdir}/libsofia-sip-ua/docs/hide_emails.sh
+
+.PHONY: built-sources built-sources-am doxygen
+# 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:
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/docs/Doxyfile.aliases
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/docs/Doxyfile.aliases Thu Dec 21 01:30:28 2006
@@ -0,0 +1 @@
+ at INCLUDE = ../../libsofia-sip-ua/docs/Doxyfile.aliases
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/docs/Doxyfile.conf
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/docs/Doxyfile.conf Thu Dec 21 01:30:28 2006
@@ -0,0 +1,18 @@
+ at INCLUDE = ../../libsofia-sip-ua/docs/Doxyfile.conf
+ at INCLUDE = ../../libsofia-sip-ua/docs/Doxyfile.rfc
+
+HTML_FOOTER = ../../libsofia-sip-ua/docs/sofia-footer.html
+
+TAGFILES += ../../libsofia-sip-ua/docs/docs.doxytags=../docs
+TAGFILES += ../../libsofia-sip-ua/docs/su.doxytags=../su
+TAGFILES += ../../libsofia-sip-ua/docs/ipt.doxytags=../ipt
+TAGFILES += ../../libsofia-sip-ua/docs/bnf.doxytags=../bnf
+TAGFILES += ../../libsofia-sip-ua/docs/url.doxytags=../url
+TAGFILES += ../../libsofia-sip-ua/docs/msg.doxytags=../msg
+TAGFILES += ../../libsofia-sip-ua/docs/sip.doxytags=../sip
+TAGFILES += ../../libsofia-sip-ua/docs/sresolv.doxytags=../sresolv
+TAGFILES += ../../libsofia-sip-ua/docs/tport.doxytags=../tport
+TAGFILES += ../../libsofia-sip-ua/docs/nta.doxytags=../nta
+TAGFILES += ../../libsofia-sip-ua/docs/sdp.doxytags=../sdp
+TAGFILES += ../../libsofia-sip-ua/docs/nua.doxytags=../nua
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/docs/Doxyfile.version
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/docs/Doxyfile.version Thu Dec 21 01:30:28 2006
@@ -0,0 +1,2 @@
+ at INCLUDE = ../../libsofia-sip-ua/docs/Doxyfile.version
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/Doxyfile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/Doxyfile Thu Dec 21 01:30:28 2006
@@ -0,0 +1,11 @@
+PROJECT_NAME = "sofia-sip/su-glib"
+
+OUTPUT_DIRECTORY = ../docs/html/su-glib
+
+INPUT = su_glib.docs . sofia-sip
+
+ at INCLUDE = ../docs/Doxyfile.conf
+
+GENERATE_TAGFILE = ../docs/su_glib.doxytags
+
+ALIASES +=
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/Makefile.am Thu Dec 21 01:30:28 2006
@@ -0,0 +1,61 @@
+#
+# Makefile.am for su-glib module
+#
+# Copyright (C) 2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+#
+
+# ----------------------------------------------------------------------
+# Headers
+
+S_BASE = $(top_srcdir)/libsofia-sip-ua
+B_BASE = $(top_builddir)/libsofia-sip-ua
+
+INCLUDES = -I$(S_BASE)/su -I$(B_BASE)/su $(GLIB_CFLAGS)
+
+# ----------------------------------------------------------------------
+# Build targets
+
+noinst_LTLIBRARIES = libsu-glib.la
+
+check_PROGRAMS = su_source_test
+
+# ----------------------------------------------------------------------
+# Tests
+
+TESTS = su_source_test
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+
+nobase_include_sofia_HEADERS =
+if HAVE_GLIB
+nobase_include_sofia_HEADERS += \
+ sofia-sip/su_source.h \
+ sofia-sip/su_glib.h
+endif
+
+libsu_glib_la_SOURCES = su_source.c
+
+libsu_glib_la_DEPENDENCIES = \
+ ../../libsofia-sip-ua/libsofia-sip-ua.la
+
+LDADD = libsu-glib.la \
+ ../../libsofia-sip-ua/libsofia-sip-ua.la \
+ $(GLIB_LIBS)
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+
+EXTRA_DIST = Doxyfile su_glib.docs
+
+# ----------------------------------------------------------------------
+# Automake options
+
+AUTOMAKE_OPTIONS = foreign
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+
+include ../../libsofia-sip-ua/sofia.am
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/Makefile.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1,705 @@
+# 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.
+
+ at SET_MAKE@
+
+#
+# Makefile.am for su-glib module
+#
+# Copyright (C) 2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+#
+
+# ----------------------------------------------------------------------
+# Headers
+
+# common Makefile targets for libsofia-sip-ua modules
+# ---------------------------------------------------
+
+
+SOURCES = $(libsu_glib_la_SOURCES) su_source_test.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 = su_source_test$(EXEEXT)
+ at HAVE_GLIB_TRUE@am__append_1 = \
+ at HAVE_GLIB_TRUE@ sofia-sip/su_source.h \
+ at HAVE_GLIB_TRUE@ sofia-sip/su_glib.h
+
+DIST_COMMON = $(am__nobase_include_sofia_HEADERS_DIST) \
+ $(srcdir)/../../libsofia-sip-ua/sofia.am $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in
+subdir = libsofia-sip-ua-glib/su-glib
+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 =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libsu_glib_la_LIBADD =
+am_libsu_glib_la_OBJECTS = su_source.lo
+libsu_glib_la_OBJECTS = $(am_libsu_glib_la_OBJECTS)
+su_source_test_SOURCES = su_source_test.c
+su_source_test_OBJECTS = su_source_test.$(OBJEXT)
+su_source_test_LDADD = $(LDADD)
+am__DEPENDENCIES_1 =
+su_source_test_DEPENDENCIES = libsu-glib.la \
+ ../../libsofia-sip-ua/libsofia-sip-ua.la $(am__DEPENDENCIES_1)
+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 = $(libsu_glib_la_SOURCES) su_source_test.c
+DIST_SOURCES = $(libsu_glib_la_SOURCES) su_source_test.c
+am__nobase_include_sofia_HEADERS_DIST = sofia-sip/su_source.h \
+ sofia-sip/su_glib.h
+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|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(include_sofiadir)"
+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@
+S_BASE = $(top_srcdir)/libsofia-sip-ua
+B_BASE = $(top_builddir)/libsofia-sip-ua
+INCLUDES = -I$(S_BASE)/su -I$(B_BASE)/su $(GLIB_CFLAGS)
+
+# ----------------------------------------------------------------------
+# Build targets
+noinst_LTLIBRARIES = libsu-glib.la
+
+# ----------------------------------------------------------------------
+# Tests
+TESTS = su_source_test
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+nobase_include_sofia_HEADERS = $(am__append_1)
+libsu_glib_la_SOURCES = su_source.c
+libsu_glib_la_DEPENDENCIES = \
+ ../../libsofia-sip-ua/libsofia-sip-ua.la
+
+LDADD = libsu-glib.la \
+ ../../libsofia-sip-ua/libsofia-sip-ua.la \
+ $(GLIB_LIBS)
+
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+EXTRA_DIST = Doxyfile su_glib.docs
+
+# ----------------------------------------------------------------------
+# Automake options
+AUTOMAKE_OPTIONS = foreign
+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
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/../../libsofia-sip-ua/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) --foreign libsofia-sip-ua-glib/su-glib/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --foreign libsofia-sip-ua-glib/su-glib/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-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
+libsu-glib.la: $(libsu_glib_la_OBJECTS) $(libsu_glib_la_DEPENDENCIES)
+ $(LINK) $(libsu_glib_la_LDFLAGS) $(libsu_glib_la_OBJECTS) $(libsu_glib_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
+su_source_test$(EXEEXT): $(su_source_test_OBJECTS) $(su_source_test_DEPENDENCIES)
+ @rm -f su_source_test$(EXEEXT)
+ $(LINK) $(su_source_test_LDFLAGS) $(su_source_test_OBJECTS) $(su_source_test_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_source.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_source_test.Po at am__quote@
+
+.c.o:
+ at am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+ at am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ at am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at 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)/../../libsofia-sip-ua $(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: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(include_sofiadir)"; do \
+ test -z "$$dir" || $(mkdir_p) "$$dir"; \
+ done
+install: 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."
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+ 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-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-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-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-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-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) $<
+
+ at ENABLE_COVERAGE_TRUE@coverage:
+ at 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)
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+# 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:
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/sofia-sip/su_glib.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/sofia-sip/su_glib.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,49 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_GLIB_SOURCE_H
+#define SU_GLIB_SOURCE_H
+
+/**
+ * @file su_glib.h
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Kai Vehmanen <first.surname at nokia.com>
+ */
+
+#ifndef SU_WAIT_H
+#include <sofia-sip/su_wait.h>
+#endif
+#ifndef __GLIB_H__
+#include <glib.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+SOFIAPUBFUN su_root_t *su_glib_root_create(su_root_magic_t *) __attribute__((__malloc__));
+SOFIAPUBFUN GSource *su_glib_root_gsource(su_root_t *);
+
+SOFIA_END_DECLS
+
+#endif /* !defined SU_GLIB_SOURCE_H */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/sofia-sip/su_source.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/sofia-sip/su_source.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,56 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_SOURCE_H /** Defined when su_source.h has been included. */
+#define SU_SOURCE_H
+
+/**
+ * @file su_source.h
+ * @brief
+ *
+ * NOTE: This file (su_source.h) is DEPRECATED as of 1.12.2 release.
+ * Please use su_glib.h instead.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Kai Vehmanen <first.surname at nokia.com>
+ *
+ * @date Created: Thu Mar 4 19:58:50 2004 ppessi
+ *
+ */
+
+#ifndef SU_WAIT_H
+#include <sofia-sip/su_wait.h>
+#endif
+#ifndef __GLIB_H__
+#include <glib.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+SOFIAPUBFUN su_root_t *su_root_source_create(su_root_magic_t *) __attribute__((__malloc__));
+SOFIAPUBFUN GSource *su_root_source(su_root_t *);
+
+SOFIA_END_DECLS
+
+#endif /* !defined SU_SOURCE_H */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/su_glib.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/su_glib.docs Thu Dec 21 01:30:28 2006
@@ -0,0 +1,59 @@
+/**
+
+ at mainpage Sofia-SIP su-glib Module
+
+ at section su_glib_meta Module Meta Information
+
+The su-glib module provides an interface to connect Sofia-SIP event loop
+to an existing glib main loop. Without this interface, a glib based
+application would have to create a separate thread for running
+the Sofia-SIP event loop.
+
+ at CONTACT Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ at STATUS Core library
+
+ at LICENSE LGPL
+
+ at section su_glib_contents Contents of su-glib Module
+
+The su-glib module contains the public header files as follows:
+- <su_glib.h> the public API of the module
+- <su_source.h> deprecated API (1.12.1 and earlier)
+
+ at section su_glib_examples Examples of use
+
+Below is a simple example of how to use su-glib:
+ at code
+ #include <glib.h>
+ #include <sofia-sip/su_glib.h>
+
+ /* ... */
+
+ GMainLoop *ptr = g_main_loop_new(NULL, FALSE);
+ GSource *gsource;
+ su_root_t *sofia_event_loop;
+ su_timer_t *timer;
+
+ /* create a sofia event loop using su-glib function su_glib_root_source_create() */
+ sofia_event_loop = su_glib_root_create(NULL);
+
+ /* attach the created GSource to glib event loop */
+ gsource = su_glib_root_gsource(sofia_event_loop);
+ g_source_attach(gsource, g_main_loop_get_context(ptr));
+
+ /* use the sofia event loop with libsofia-sip-ua modules */
+ timer = su_timer_create(su_root_task(sofia_event_loop), 200L);
+
+ /* ... initialize other Sofia-SIP modules/functrions */
+
+ /* run the glib mainloop */
+ g_main_loop_run(ptr);
+ at endcode
+
+ at section su_glib_todo Todo
+
+- see sourceforge.net issue tracker for sofia-sip
+ (-> http://sofia-sip.sourceforge.net/development.html )
+
+*/
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/su_source.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/su_source.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1118 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**
+ * @file su_source.c
+ * @brief Wrapper for glib GSource.
+ * *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Thu Mar 4 15:15:15 2004 ppessi
+ *
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+
+#include <glib.h>
+
+#define SU_PORT_IMPLEMENTATION 1
+
+#define SU_MSG_ARG_T union { char anoymous[4]; }
+
+#define su_port_s su_source_s
+
+#include "sofia-sip/su_source.h"
+#include "sofia-sip/su_glib.h"
+
+#include "sofia-sip/su.h"
+#include "su_port.h"
+#include "sofia-sip/su_alloc.h"
+
+static su_port_t *su_source_create(void) __attribute__((__malloc__));
+static gboolean su_source_prepare(GSource *gs, gint *return_tout);
+static gboolean su_source_check(GSource *gs);
+static gboolean su_source_dispatch(GSource *gs,
+ GSourceFunc callback,
+ gpointer user_data);
+static void su_source_finalize(GSource *source);
+
+static int su_source_getmsgs(su_port_t *self);
+
+static
+GSourceFuncs su_source_funcs[1] = {{
+ su_source_prepare,
+ su_source_check,
+ su_source_dispatch,
+ su_source_finalize,
+ NULL,
+ NULL
+ }};
+
+static void su_source_lock(su_port_t *self, char const *who);
+static void su_source_unlock(su_port_t *self, char const *who);
+static void su_source_incref(su_port_t *self, char const *who);
+static void su_source_decref(su_port_t *self, int blocking, char const *who);
+static struct _GSource *su_source_gsource(su_port_t *port);
+
+static int su_source_send(su_port_t *self, su_msg_r rmsg);
+
+static int su_source_register(su_port_t *self,
+ su_root_t *root,
+ su_wait_t *wait,
+ su_wakeup_f callback,
+ su_wakeup_arg_t *arg,
+ int priority);
+static int su_source_unregister(su_port_t *port,
+ su_root_t *root,
+ su_wait_t *wait,
+ su_wakeup_f callback,
+ su_wakeup_arg_t *arg);
+static int su_source_deregister(su_port_t *self, int i);
+static int su_source_unregister_all(su_port_t *self,
+ su_root_t *root);
+static int su_source_eventmask(su_port_t *self,
+ int index, int socket, int events);
+static void su_source_run(su_port_t *self);
+static void su_source_break(su_port_t *self);
+static su_duration_t su_source_step(su_port_t *self, su_duration_t tout);
+static int su_source_own_thread(su_port_t const *port);
+static int su_source_add_prepoll(su_port_t *port,
+ su_root_t *root,
+ su_prepoll_f *,
+ su_prepoll_magic_t *);
+static int su_source_remove_prepoll(su_port_t *port,
+ su_root_t *root);
+static su_timer_t **su_source_timers(su_port_t *port);
+static int su_source_multishot(su_port_t *self, int multishot);
+static int su_source_threadsafe(su_port_t *port);
+
+static
+su_port_vtable_t const su_source_vtable[1] =
+ {{
+ /* su_vtable_size: */ sizeof su_source_vtable,
+ su_source_lock,
+ su_source_unlock,
+ su_source_incref,
+ su_source_decref,
+
+ su_source_gsource,
+
+ su_source_send,
+ su_source_register,
+ su_source_unregister,
+ su_source_deregister,
+ su_source_unregister_all,
+ su_source_eventmask,
+ su_source_run,
+ su_source_break,
+ su_source_step,
+ su_source_own_thread,
+ su_source_add_prepoll,
+ su_source_remove_prepoll,
+ su_source_timers,
+ su_source_multishot,
+ su_source_threadsafe
+
+ }};
+
+/**
+ * Port is a per-thread reactor.
+ *
+ * Multiple root objects executed by single thread share a su_port_t object.
+ */
+struct su_source_s {
+ su_home_t sup_home[1];
+ su_port_vtable_t const *sup_vtable;
+
+ GThread *sup_tid;
+ GStaticMutex sup_mutex[1];
+ GStaticRWLock sup_ref[1];
+
+ GSource *sup_source;
+ GMainLoop *sup_main_loop;
+
+ /* Message list - this is protected by lock */
+ su_msg_t *sup_head;
+ su_msg_t **sup_tail;
+
+ /* Waits */
+ unsigned sup_registers; /** Counter incremented by
+ su_port_register() or
+ su_port_unregister()
+ */
+ unsigned sup_n_waits;
+ unsigned sup_size_waits;
+ unsigned sup_max_index;
+ unsigned *sup_indices;
+ su_wait_t *sup_waits;
+ su_wakeup_f *sup_wait_cbs;
+ su_wakeup_arg_t**sup_wait_args;
+ su_root_t **sup_wait_roots;
+
+ /* Timer list */
+ su_timer_t *sup_timers;
+};
+
+typedef struct _SuSource
+{
+ GSource ss_source[1];
+ su_port_t ss_port[1];
+} SuSource;
+
+#define SU_SOURCE_OWN_THREAD(p) ((p)->sup_tid == g_thread_self())
+
+#if 1
+#define SU_SOURCE_INCREF(p, f) (g_source_ref(p->sup_source))
+#define SU_SOURCE_DECREF(p, f) (g_source_unref(p->sup_source))
+
+#define SU_SOURCE_INITLOCK(p) (g_static_mutex_init((p)->sup_mutex))
+#define SU_SOURCE_LOCK(p, f) (g_static_mutex_lock((p)->sup_mutex))
+#define SU_SOURCE_UNLOCK(p, f) (g_static_mutex_unlock((p)->sup_mutex))
+
+#else
+
+/* Debugging versions */
+#define SU_SOURCE_INCREF(p, f) (g_source_ref(p->sup_source), printf("incref(%p) by %s\n", (p), f))
+#define SU_SOURCE_DECREF(p, f) do { printf("decref(%p) by %s\n", (p), f), \
+ g_source_unref(p->sup_source); } while(0)
+
+#define SU_SOURCE_INITLOCK(p) \
+ (g_static_mutex_init((p)->sup_mutex), printf("init_lock(%p)\n", p))
+
+#define SU_SOURCE_LOCK(p, f) \
+ (printf("%ld at %s locking(%p)...", g_thread_self(), f, p), g_static_mutex_lock((p)->sup_mutex), printf(" ...%ld at %s locked(%p)...", g_thread_self(), f, p))
+
+#define SU_SOURCE_UNLOCK(p, f) \
+ (g_static_mutex_unlock((p)->sup_mutex), printf(" ...%ld at %s unlocked(%p)\n", g_thread_self(), f, p))
+
+#endif
+
+#if HAVE_FUNC
+#define enter (void)SU_DEBUG_9(("%s: entering\n", __func__))
+#elif HAVE_FUNCTION
+#define enter (void)SU_DEBUG_9(("%s: entering\n", __FUNCTION__))
+#else
+#define enter (void)0
+#endif
+
+/*=============== Public function definitions ===============*/
+
+/** Create a root that uses GSource as reactor */
+su_root_t *su_glib_root_create(su_root_magic_t *magic)
+{
+ return su_root_create_with_port(magic, su_source_create());
+}
+
+/** Deprecated */
+su_root_t *su_root_source_create(su_root_magic_t *magic)
+{
+ return su_glib_root_create(magic);
+}
+
+GSource *su_glib_root_gsource(su_root_t *root)
+{
+ g_assert(root);
+ return su_root_gsource(root);
+}
+
+/*=============== Private function definitions ===============*/
+
+/**@internal
+ *
+ * Allocates and initializes a reactor and message port object.
+ *
+ * @return
+ * If successful a pointer to the new message port is returned, otherwise
+ * NULL is returned.
+ */
+su_port_t *su_source_create(void)
+{
+ SuSource *ss;
+
+ SU_DEBUG_9(("su_source_create() called\n"));
+
+ ss = (SuSource *)g_source_new(su_source_funcs, (sizeof *ss));
+
+ if (ss) {
+ su_port_t *self = ss->ss_port;
+
+ self->sup_vtable = su_source_vtable;
+ self->sup_source = ss->ss_source;
+
+ SU_SOURCE_INITLOCK(self);
+
+ self->sup_tail = &self->sup_head;
+ self->sup_tid = g_thread_self();
+
+ SU_DEBUG_9(("su_source_with_main_context() returns %p\n", self));
+
+ return self;
+ } else {
+ su_perror("su_source_with_main_context(): su_home_clone");
+ SU_DEBUG_9(("su_source_with_main_context() fails\n"));
+ return NULL;
+ }
+}
+
+/** @internal Destroy a port. */
+static
+void su_source_finalize(GSource *gs)
+{
+ SuSource *ss = (SuSource *)gs;
+ su_port_t *self = ss->ss_port;
+
+ assert(gs);
+
+ SU_DEBUG_9(("su_source_finalize() called\n"));
+
+ if (self->sup_waits)
+ free(self->sup_waits), self->sup_waits = NULL;
+ if (self->sup_wait_cbs)
+ free(self->sup_wait_cbs), self->sup_wait_cbs = NULL;
+ if (self->sup_wait_args)
+ free(self->sup_wait_args), self->sup_wait_args = NULL;
+ if (self->sup_wait_roots)
+ free(self->sup_wait_roots), self->sup_wait_roots = NULL;
+ if (self->sup_indices)
+ free(self->sup_indices), self->sup_indices = NULL;
+
+ su_home_deinit(self->sup_home);
+}
+
+/* Seconds from 1.1.1900 to 1.1.1970 */
+#define NTP_EPOCH 2208988800UL
+
+static
+gboolean su_source_prepare(GSource *gs, gint *return_tout)
+{
+ SuSource *ss = (SuSource *)gs;
+ su_port_t *self = ss->ss_port;
+
+ enter;
+
+ if (self->sup_head)
+ return TRUE;
+
+ *return_tout = -1;
+
+ if (self->sup_timers) {
+ su_time_t now;
+ GTimeVal gtimeval;
+ su_duration_t tout;
+
+ tout = SU_DURATION_MAX;
+
+ g_source_get_current_time(gs, >imeval);
+
+ now.tv_sec = gtimeval.tv_sec + 2208988800UL;
+ now.tv_usec = gtimeval.tv_usec;
+
+ tout = su_timer_next_expires(self->sup_timers, now);
+
+ if (tout == 0)
+ return TRUE;
+
+ if ((gint)tout < 0 || tout > (su_duration_t)G_MAXINT)
+ tout = -1;
+
+ *return_tout = (gint)tout;
+ }
+
+ return FALSE;
+}
+
+static
+gboolean su_source_check(GSource *gs)
+{
+ SuSource *ss = (SuSource *)gs;
+ su_port_t *self = ss->ss_port;
+ gint tout;
+ unsigned i, I;
+
+ enter;
+
+ I = self->sup_n_waits;
+
+#if SU_HAVE_POLL
+ for (i = 0; i < I; i++) {
+ if (self->sup_waits[i].revents)
+ return TRUE;
+ }
+#endif
+
+ return su_source_prepare(gs, &tout);
+}
+
+static
+gboolean su_source_dispatch(GSource *gs,
+ GSourceFunc callback,
+ gpointer user_data)
+{
+ SuSource *ss = (SuSource *)gs;
+ su_port_t *self = ss->ss_port;
+
+ enter;
+
+ if (self->sup_head)
+ su_source_getmsgs(self);
+
+ if (self->sup_timers) {
+ su_time_t now;
+ GTimeVal gtimeval;
+ su_duration_t tout;
+ int timers = 0;
+
+ tout = SU_DURATION_MAX;
+
+ g_source_get_current_time(gs, >imeval);
+
+ now.tv_sec = gtimeval.tv_sec + 2208988800UL;
+ now.tv_usec = gtimeval.tv_usec;
+
+ timers = su_timer_expire(&self->sup_timers, &tout, now);
+ }
+
+#if SU_HAVE_POLL
+ {
+ su_root_t *root;
+ su_wait_t *waits = self->sup_waits;
+ unsigned i, n = self->sup_n_waits;
+ unsigned version = self->sup_registers;
+
+ for (i = 0; i < n; i++) {
+ if (waits[i].revents) {
+ root = self->sup_wait_roots[i];
+ self->sup_wait_cbs[i](root ? su_root_magic(root) : NULL,
+ &waits[i],
+ self->sup_wait_args[i]);
+ /* Callback used su_register()/su_unregister() */
+ if (version != self->sup_registers)
+ break;
+ }
+ }
+ }
+#endif
+
+ if (!callback)
+ return TRUE;
+
+ return callback(user_data);
+}
+
+static void su_source_lock(su_port_t *self, char const *who)
+{
+ SU_SOURCE_LOCK(self, who);
+}
+
+static void su_source_unlock(su_port_t *self, char const *who)
+{
+ SU_SOURCE_UNLOCK(self, who);
+}
+
+static void su_source_incref(su_port_t *self, char const *who)
+{
+ SU_SOURCE_INCREF(self, who);
+}
+
+static void su_source_decref(su_port_t *self, int blocking, char const *who)
+{
+ /* XXX - blocking? */
+ SU_SOURCE_DECREF(self, who);
+}
+
+GSource *su_source_gsource(su_port_t *self)
+{
+ return self->sup_source;
+}
+
+/** @internal Send a message to the port. */
+int su_source_send(su_port_t *self, su_msg_r rmsg)
+{
+ enter;
+
+ if (self) {
+ su_msg_t *msg;
+ GMainContext *gmc;
+
+ SU_SOURCE_LOCK(self, "su_source_send");
+
+ msg = rmsg[0]; rmsg[0] = NULL;
+ *self->sup_tail = msg;
+ self->sup_tail = &msg->sum_next;
+
+ SU_SOURCE_UNLOCK(self, "su_source_send");
+
+ gmc = g_source_get_context(self->sup_source);
+
+ if (gmc)
+ g_main_context_wakeup(gmc);
+
+ return 0;
+ }
+ else {
+ su_msg_destroy(rmsg);
+ return -1;
+ }
+}
+
+/** @internal
+ * Execute the messages in the incoming queue until the queue is empty..
+ *
+ * @param self - pointer to a port object
+ *
+ * @retval 0 if there was a signal to handle,
+ * @retval -1 otherwise.
+ */
+static
+int su_source_getmsgs(su_port_t *self)
+{
+ enter;
+
+ if (self && self->sup_head) {
+ su_root_t *root;
+ su_msg_f f;
+
+ SU_SOURCE_INCREF(self, "su_source_getmsgs");
+ SU_SOURCE_LOCK(self, "su_source_getmsgs");
+
+ while (self->sup_head) {
+ su_msg_t *msg = self->sup_head;
+ self->sup_head = msg->sum_next;
+ if (!self->sup_head) {
+ assert(self->sup_tail == &msg->sum_next);
+ self->sup_tail = &self->sup_head;
+ }
+ root = msg->sum_to->sut_root;
+ f = msg->sum_func;
+ SU_SOURCE_UNLOCK(self, "su_source_getmsgs");
+ if (f)
+ f(su_root_magic(root), &msg, msg->sum_data);
+ su_msg_delivery_report(&msg);
+ SU_SOURCE_LOCK(self, "su_source_getmsgs");
+ }
+
+ SU_SOURCE_UNLOCK(self, "su_source_getmsgs");
+ SU_SOURCE_DECREF(self, "su_source_getmsgs");
+
+ return 0;
+ }
+ else
+ return -1;
+}
+
+/** @internal
+ *
+ * Register a @c su_wait_t object. The wait object, a callback function and
+ * a argument pointer is stored in the port object. The callback function
+ * will be called when the wait object is signaled.
+ *
+ * Please note if identical wait objects are inserted, only first one is
+ * ever signalled.
+ *
+ * @param self pointer to port
+ * @param root pointer to root object
+ * @param waits pointer to wait object
+ * @param callback callback function pointer
+ * @param arg argument given to callback function when it is invoked
+ * @param priority relative priority of the wait object
+ * (0 is normal, 1 important, 2 realtime)
+ *
+ * @return
+ * The function @su_source_register returns nonzero index of the wait object,
+ * or -1 upon an error. */
+int su_source_register(su_port_t *self,
+ su_root_t *root,
+ su_wait_t *wait,
+ su_wakeup_f callback,
+ su_wakeup_arg_t *arg,
+ int priority)
+{
+ unsigned i, j, I;
+ unsigned n;
+
+ enter;
+
+ assert(SU_SOURCE_OWN_THREAD(self));
+
+ n = self->sup_n_waits;
+
+ if (n >= self->sup_size_waits) {
+ /* Reallocate size arrays */
+ unsigned size;
+ unsigned *indices;
+ su_wait_t *waits;
+ su_wakeup_f *wait_cbs;
+ su_wakeup_arg_t **wait_args;
+ su_root_t **wait_tasks;
+
+ if (self->sup_size_waits == 0)
+ size = SU_WAIT_MIN;
+ else
+ size = 2 * self->sup_size_waits;
+
+ indices = realloc(self->sup_indices, size * sizeof(*indices));
+ if (indices) {
+ self->sup_indices = indices;
+
+ for (i = self->sup_size_waits; i < size; i++)
+ indices[i] = UINT_MAX;
+ }
+
+ for (i = 0; i < self->sup_n_waits; i++)
+ g_source_remove_poll(self->sup_source, (GPollFD*)&self->sup_waits[i]);
+
+ waits = realloc(self->sup_waits, size * sizeof(*waits));
+ if (waits)
+ self->sup_waits = waits;
+
+ for (i = 0; i < self->sup_n_waits; i++)
+ g_source_add_poll(self->sup_source, (GPollFD*)&waits[i]);
+
+ wait_cbs = realloc(self->sup_wait_cbs, size * sizeof(*wait_cbs));
+ if (wait_cbs)
+ self->sup_wait_cbs = wait_cbs;
+
+ wait_args = realloc(self->sup_wait_args, size * sizeof(*wait_args));
+ if (wait_args)
+ self->sup_wait_args = wait_args;
+
+ /* Add sup_wait_roots array, if needed */
+ wait_tasks = realloc(self->sup_wait_roots, size * sizeof(*wait_tasks));
+ if (wait_tasks)
+ self->sup_wait_roots = wait_tasks;
+
+ if (!(indices && waits && wait_cbs && wait_args && wait_tasks)) {
+ return -1;
+ }
+
+ self->sup_size_waits = size;
+ }
+
+ self->sup_n_waits++;
+
+ if (priority > 0) {
+ /* Insert */
+ for (; n > 0; n--) {
+ g_source_remove_poll(self->sup_source, (GPollFD*)&self->sup_waits[n-1]);
+ self->sup_waits[n] = self->sup_waits[n-1];
+ g_source_add_poll(self->sup_source, (GPollFD*)&self->sup_waits[n]);
+ self->sup_wait_cbs[n] = self->sup_wait_cbs[n-1];
+ self->sup_wait_args[n] = self->sup_wait_args[n-1];
+ self->sup_wait_roots[n] = self->sup_wait_roots[n-1];
+ }
+ }
+ else {
+ /* Append - no need to move anything */
+ }
+
+ self->sup_waits[n] = *wait;
+ g_source_add_poll(self->sup_source, (GPollFD*)&self->sup_waits[n]);
+ self->sup_wait_cbs[n] = callback;
+ self->sup_wait_args[n] = arg;
+ self->sup_wait_roots[n] = root;
+
+ I = self->sup_max_index;
+
+ for (i = 0; i < I; i++)
+ if (self->sup_indices[i] == UINT_MAX)
+ break;
+ else if (self->sup_indices[i] >= n)
+ self->sup_indices[i]++;
+
+ if (i == I)
+ self->sup_max_index++;
+
+ if (n + 1 < self->sup_n_waits)
+ for (j = i; j < I; j++)
+ if (self->sup_indices[j] != UINT_MAX &&
+ self->sup_indices[j] >= n)
+ self->sup_indices[j]++;
+
+ self->sup_indices[i] = n;
+
+ self->sup_registers++;
+
+ return i + 1; /* 0 is failure */
+}
+
+/** Unregister a su_wait_t object.
+ *
+ * The function su_source_unregister() unregisters a su_wait_t object. The
+ * wait object, a callback function and a argument are removed from the
+ * port object.
+ *
+ * @param self - pointer to port object
+ * @param root - pointer to root object
+ * @param wait - pointer to wait object
+ * @param callback - callback function pointer (may be NULL)
+ * @param arg - argument given to callback function when it is invoked
+ * (may be NULL)
+ *
+ * @return Nonzero index of the wait object, or -1 upon an error.
+ */
+int su_source_unregister(su_port_t *self,
+ su_root_t *root,
+ su_wait_t *wait,
+ su_wakeup_f callback, /* XXX - ignored */
+ su_wakeup_arg_t *arg)
+{
+ unsigned n, N;
+ unsigned i, I, j, *indices;
+
+ enter;
+
+ assert(self);
+ assert(SU_SOURCE_OWN_THREAD(self));
+
+ i = (unsigned)-1;
+ N = self->sup_n_waits;
+ I = self->sup_max_index;
+ indices = self->sup_indices;
+
+ for (n = 0; n < N; n++) {
+ if (SU_WAIT_CMP(wait[0], self->sup_waits[n]) != 0)
+ continue;
+
+ /* Found - delete it */
+ if (indices[n] == n)
+ i = n;
+ else for (i = 0; i < I; i++)
+ if (indices[i] == n)
+ break;
+
+ assert(i < I);
+
+ indices[i] = UINT_MAX;
+
+ g_source_remove_poll(self->sup_source, (GPollFD*)&self->sup_waits[n]);
+
+ self->sup_n_waits = N = N - 1;
+
+ if (n < N)
+ for (j = 0; j < I; j++)
+ if (self->sup_indices[j] != UINT_MAX &&
+ self->sup_indices[j] > n)
+ self->sup_indices[j]--;
+
+ for (; n < N; n++) {
+ g_source_remove_poll(self->sup_source, (GPollFD*)&self->sup_waits[n+1]);
+ self->sup_waits[n] = self->sup_waits[n+1];
+ g_source_add_poll(self->sup_source, (GPollFD*)&self->sup_waits[n]);
+ self->sup_wait_cbs[n] = self->sup_wait_cbs[n+1];
+ self->sup_wait_args[n] = self->sup_wait_args[n+1];
+ self->sup_wait_roots[n] = self->sup_wait_roots[n+1];
+ }
+
+ i += 1; /* 0 is failure */
+
+ if (i == I)
+ self->sup_max_index--;
+
+ break;
+ }
+
+ self->sup_registers++;
+
+ return (int)i;
+}
+
+/** Deregister a su_wait_t object.
+ *
+ * The function su_source_deregister() deregisters a su_wait_t registrattion.
+ * The wait object, a callback function and a argument are removed from the
+ * port object.
+ *
+ * @param self - pointer to port object
+ * @param i - registration index
+ *
+ * @return Index of the wait object, or -1 upon an error.
+ */
+int su_source_deregister(su_port_t *self, int i)
+{
+ unsigned j, n, N;
+ unsigned I, *indices;
+ su_wait_t wait[1];
+
+ enter;
+
+ assert(self);
+ assert(SU_SOURCE_OWN_THREAD(self));
+
+ if (i <= 0)
+ return -1;
+
+ N = self->sup_n_waits;
+ I = self->sup_max_index;
+ indices = self->sup_indices;
+
+ assert((unsigned)i < I + 1);
+
+ n = indices[i - 1];
+
+ if (n == UINT_MAX)
+ return -1;
+
+ self->sup_n_waits = N = N - 1;
+
+ wait[0] = self->sup_waits[n];
+
+ g_source_remove_poll(self->sup_source, (GPollFD*)&self->sup_waits[n]);
+
+ if (n < N)
+ for (j = 0; j < I; j++)
+ if (self->sup_indices[j] != UINT_MAX &&
+ self->sup_indices[j] > n)
+ self->sup_indices[j]--;
+
+ for (; n < N; n++) {
+ g_source_remove_poll(self->sup_source, (GPollFD*)&self->sup_waits[n + 1]);
+ self->sup_waits[n] = self->sup_waits[n+1];
+ g_source_add_poll(self->sup_source, (GPollFD*)&self->sup_waits[n]);
+ self->sup_wait_cbs[n] = self->sup_wait_cbs[n+1];
+ self->sup_wait_args[n] = self->sup_wait_args[n+1];
+ self->sup_wait_roots[n] = self->sup_wait_roots[n+1];
+ }
+
+ indices[i - 1] = UINT_MAX;
+
+ if ((unsigned)i == I)
+ self->sup_max_index--;
+
+ su_wait_destroy(wait);
+
+ self->sup_registers++;
+
+ return (int)i;
+}
+
+/** @internal
+ * Unregister all su_wait_t objects.
+ *
+ * The function su_source_unregister_all() unregisters all su_wait_t objects
+ * associated with given root object destroys all queued timers.
+ *
+ * @param self - pointer to port object
+ * @param root - pointer to root object
+ *
+ * @return Number of wait objects removed.
+ */
+int su_source_unregister_all(su_port_t *self,
+ su_root_t *root)
+{
+ unsigned i, j;
+ unsigned n_waits;
+ su_wait_t *waits;
+ su_wakeup_f *wait_cbs;
+ su_wakeup_arg_t**wait_args;
+ su_root_t **wait_roots;
+
+ enter;
+
+ assert(SU_SOURCE_OWN_THREAD(self));
+
+ n_waits = self->sup_n_waits;
+ waits = self->sup_waits;
+ wait_cbs = self->sup_wait_cbs;
+ wait_args = self->sup_wait_args;
+ wait_roots = self->sup_wait_roots;
+
+ for (i = j = 0; (unsigned)i < n_waits; i++) {
+ if (wait_roots[i] == root) {
+ /* XXX - we should free all resources associated with this */
+ g_source_remove_poll(self->sup_source, (GPollFD*)&waits[i]);
+ continue;
+ }
+ if (i != j) {
+ g_source_remove_poll(self->sup_source, (GPollFD*)&waits[i]);
+ waits[j] = waits[i];
+ wait_cbs[j] = wait_cbs[i];
+ wait_args[j] = wait_args[i];
+ wait_roots[j] = wait_roots[i];
+ g_source_add_poll(self->sup_source, (GPollFD*)&waits[i]);
+ }
+ j++;
+ }
+
+ self->sup_n_waits = j;
+ self->sup_registers++;
+
+ return n_waits - j;
+}
+
+/**Set mask for a registered event. @internal
+ *
+ * The function su_source_eventmask() sets the mask describing events that can
+ * signal the registered callback.
+ *
+ * @param port pointer to port object
+ * @param index registration index
+ * @param socket socket
+ * @param events new event mask
+ *
+ * @retval 0 when successful,
+ * @retval -1 upon an error.
+ */
+int su_source_eventmask(su_port_t *self, int index, int socket, int events)
+{
+ unsigned n;
+ int retval;
+
+ enter;
+
+ assert(self);
+ assert(SU_SOURCE_OWN_THREAD(self));
+ assert(0 < index && (unsigned)index <= self->sup_max_index);
+
+ if (index <= 0 || (unsigned)index > self->sup_max_index)
+ return -1;
+
+ n = self->sup_indices[index - 1];
+
+ if (n == UINT_MAX)
+ return -1;
+
+ g_source_remove_poll(self->sup_source, (GPollFD*)&self->sup_waits[n]);
+
+ retval = su_wait_mask(&self->sup_waits[n], socket, events);
+
+ g_source_add_poll(self->sup_source, (GPollFD*)&self->sup_waits[n]);
+
+ return retval;
+}
+
+static
+int su_source_multishot(su_port_t *self, int multishot)
+{
+ if (multishot == -1)
+ return 1;
+ else if (multishot == 0 || multishot == 1)
+ return 1; /* Always enabled */
+ else
+ return (errno = EINVAL), -1;
+}
+
+/** @internal Enable threadsafe operation. */
+static
+int su_source_threadsafe(su_port_t *port)
+{
+ return su_home_threadsafe(port->sup_home);
+}
+
+
+/** @internal Main loop.
+ *
+ * The function @c su_source_run() runs the main loop
+ *
+ * The function @c su_source_run() runs until @c su_source_break() is called
+ * from a callback.
+ *
+ * @param self pointer to root object
+ * */
+void su_source_run(su_port_t *self)
+{
+ GMainContext *gmc;
+ GMainLoop *gml;
+
+ enter;
+
+ gmc = g_source_get_context(self->sup_source);
+ if (gmc && g_main_context_acquire(gmc)) {
+ gml = g_main_loop_new(gmc, TRUE);
+ self->sup_main_loop = gml;
+ g_main_loop_run(gml);
+ g_main_loop_unref(gml);
+ self->sup_main_loop = NULL;
+ g_main_context_release(gmc);
+ }
+}
+
+/** @internal
+ * The function @c su_source_break() is used to terminate execution of @c
+ * su_source_run(). It can be called from a callback function.
+ *
+ * @param self pointer to port
+ *
+ */
+void su_source_break(su_port_t *self)
+{
+ enter;
+
+ if (self->sup_main_loop)
+ g_main_loop_quit(self->sup_main_loop);
+}
+
+/** @internal Block until wait object is signaled or timeout.
+ *
+ * This function waits for wait objects and the timers associated with
+ * the root object. When any wait object is signaled or timer is
+ * expired, it invokes the callbacks.
+ *
+ * This function returns when a callback has been invoked or @c tout
+ * milliseconds is elapsed.
+ *
+ * @param self pointer to port
+ * @param tout timeout in milliseconds
+ *
+ * @Return
+ * Milliseconds to the next invocation of timer, or @c SU_WAIT_FOREVER if
+ * there are no active timers.
+ */
+su_duration_t su_source_step(su_port_t *self, su_duration_t tout)
+{
+ GMainContext *gmc;
+
+ enter;
+
+ gmc = g_source_get_context(self->sup_source);
+
+ if (gmc && g_main_context_acquire(gmc)) {
+ gint priority = G_MAXINT;
+ if (g_main_context_prepare(gmc, &priority)) {
+ g_main_context_dispatch(gmc);
+ } else {
+ gint timeout = tout > G_MAXINT ? G_MAXINT : tout;
+ gint i, n = 0;
+ GPollFD *fds = NULL;
+
+ priority = G_MAXINT;
+
+ n = g_main_context_query(gmc, priority, &timeout, fds, n);
+ if (n > 0) {
+ fds = g_alloca(n * (sizeof *fds));
+ n = g_main_context_query(gmc, priority, &timeout, fds, n);
+ }
+
+ if (tout < timeout)
+ timeout = tout;
+
+ i = su_wait((su_wait_t *)fds, n, timeout);
+
+ if (g_main_context_check(gmc, priority, fds, n))
+ g_main_context_dispatch(gmc);
+ }
+ g_main_context_release(gmc);
+ }
+
+ return 0;
+}
+
+
+/** @internal
+ * Checks if the calling thread owns the port object.
+ *
+ * @param self pointer to a port object
+ *
+ * @retval true (nonzero) if the calling thread owns the port,
+ * @retval false (zero) otherwise.
+ */
+int su_source_own_thread(su_port_t const *self)
+{
+ return self == NULL || SU_SOURCE_OWN_THREAD(self);
+}
+
+#if 0
+/** @internal
+ * Prints out the contents of the port.
+ *
+ * @param self pointer to a port
+ * @param f pointer to a file (if @c NULL, uses @c stdout).
+ */
+void su_source_dump(su_port_t const *self, FILE *f)
+{
+ int i;
+#define IS_WAIT_IN(x) (((x)->events & SU_WAIT_IN) ? "IN" : "")
+#define IS_WAIT_OUT(x) (((x)->events & SU_WAIT_OUT) ? "OUT" : "")
+#define IS_WAIT_ACCEPT(x) (((x)->events & SU_WAIT_ACCEPT) ? "ACCEPT" : "")
+
+ if (f == NULL)
+ f = stdout;
+
+ fprintf(f, "su_port_t at %p:\n", self);
+ fprintf(f, "\tport is%s running\n", self->sup_running ? "" : "not ");
+ fprintf(f, "\tport tid %p\n", (void *)self->sup_tid);
+ fprintf(f, "\t%d wait objects\n", self->sup_n_waits);
+ for (i = 0; i < self->sup_n_waits; i++) {
+
+ }
+}
+
+#endif
+
+/* =========================================================================
+ * Pre-poll() callback
+ */
+
+int su_source_add_prepoll(su_port_t *port,
+ su_root_t *root,
+ su_prepoll_f *callback,
+ su_prepoll_magic_t *magic)
+{
+#if 0
+ if (port->sup_prepoll)
+ return -1;
+
+ port->sup_prepoll = callback;
+ port->sup_pp_magic = magic;
+ port->sup_pp_root = root;
+
+ return 0;
+#else
+ return -1;
+#endif
+}
+
+int su_source_remove_prepoll(su_port_t *port,
+ su_root_t *root)
+{
+#if 0
+ if (port->sup_pp_root != root)
+ return -1;
+
+ port->sup_prepoll = NULL;
+ port->sup_pp_magic = NULL;
+ port->sup_pp_root = NULL;
+
+ return 0;
+#else
+ return -1;
+#endif
+}
+
+/* =========================================================================
+ * Timers
+ */
+
+static
+su_timer_t **su_source_timers(su_port_t *self)
+{
+ return &self->sup_timers;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/su_source_test.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/su_source_test.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,517 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005-2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_root_ex
+ * @CFILE su_source_test.c
+ *
+ * @brief Test program for glib and su root event loop integration.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Mar 18 19:40:51 1999 pessi
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <signal.h>
+
+#include <assert.h>
+
+struct pinger;
+#define SU_ROOT_MAGIC_T struct pinger
+#define SU_INTERNAL_P su_root_t *
+#define SU_MSG_ARG_T su_sockaddr_t
+
+#include "sofia-sip/su.h"
+#include "sofia-sip/su_wait.h"
+#include "sofia-sip/su_log.h"
+
+#include "sofia-sip/su_glib.h"
+
+struct pinger {
+ enum { PINGER = 1, PONGER = 2 } const sort;
+ char const * name;
+ unsigned running : 1;
+ unsigned : 0;
+ su_root_t *root;
+ su_socket_t s;
+ su_timer_t *t;
+ int id;
+ int rindex;
+ su_time_t when;
+ su_sockaddr_t addr;
+ double rtt_total;
+ int rtt_n;
+};
+
+short opt_family = AF_INET;
+short opt_verbatim = 0;
+short opt_singlethread = 0;
+GMainLoop *global_gmainloop = NULL;
+
+static su_socket_t udpsocket(void)
+{
+ su_socket_t s;
+ su_sockaddr_t su = { 0 };
+ socklen_t sulen = sizeof(su);
+ char nbuf[64];
+
+ su.su_family = opt_family;
+
+ su_getlocalip(&su);
+
+ s = su_socket(su.su_family, SOCK_DGRAM, 0);
+ if (s == INVALID_SOCKET) {
+ su_perror("udpsocket: socket");
+ exit(1);
+ }
+
+ if (bind(s, &su.su_sa, su_sockaddr_size(&su)) == SOCKET_ERROR) {
+ su_perror("udpsocket: bind");
+ exit(1);
+ }
+
+ if (getsockname(s, &su.su_sa, &sulen) == SOCKET_ERROR) {
+ su_perror("udpsocket: getsockname");
+ exit(1);
+ }
+
+ if (opt_verbatim)
+ printf("udpsocket: using address [%s]:%u\n",
+ inet_ntop(su.su_family, SU_ADDR(&su), nbuf, sizeof(nbuf)),
+ ntohs(su.su_sin.sin_port));
+
+ return s;
+}
+
+static char *snow(su_time_t now)
+{
+ static char buf[24];
+
+ su_time_print(buf, sizeof(buf), &now);
+
+ return buf;
+}
+
+void
+do_ping(struct pinger *p, su_timer_t *t, void *p0)
+{
+ char buf[1024];
+
+ assert(p == su_root_magic(su_timer_root(t)));
+ assert(p->sort == PINGER);
+
+ p->when = su_now();
+
+ snprintf(buf, sizeof(buf), "Ping %d at %s", p->id++, snow(p->when));
+ if (sendto(p->s, buf, strlen(buf), 0,
+ &p->addr.su_sa, su_sockaddr_size(&p->addr)) == -1) {
+ su_perror("do_ping: send");
+ }
+
+ if (opt_verbatim) {
+ puts(buf);
+ fflush(stdout);
+ }
+}
+
+int
+do_rtt(struct pinger *p, su_wait_t *w, void *p0)
+{
+ su_sockaddr_t su;
+ struct sockaddr * const susa = &su.su_sa;
+ socklen_t susize[] = { sizeof(su)};
+ char buf[1024];
+ char nbuf[1024];
+ int n;
+ su_time_t now = su_now();
+ double rtt;
+
+ assert(p0 == p);
+ assert(p->sort == PINGER);
+
+ rtt = su_time_diff(now, p->when);
+
+ p->rtt_total += rtt, p->rtt_n++;
+
+ su_wait_events(w, p->s);
+
+ n = recvfrom(p->s, buf, sizeof(buf) - 1, 0, susa, susize);
+ if (n < 0) {
+ su_perror("do_rtt: recvfrom");
+ return 0;
+ }
+ buf[n] = 0;
+
+ if (opt_verbatim)
+ printf("do_rtt: %d bytes from [%s]:%u: \"%s\", rtt = %lg ms\n",
+ n, inet_ntop(su.su_family, SU_ADDR(&su), nbuf, sizeof(nbuf)),
+ ntohs(su.su_sin.sin_port), buf, rtt / 1000);
+
+ do_ping(p, p->t, NULL);
+
+ return 0;
+}
+
+void
+do_pong(struct pinger *p, su_timer_t *t, void *p0)
+{
+ char buf[1024];
+
+ assert(p == su_root_magic(su_timer_root(t)));
+ assert(p->sort == PONGER);
+
+ p->id = 0;
+
+ snprintf(buf, sizeof(buf), "Pong at %s", snow(su_now()));
+ if (sendto(p->s, buf, strlen(buf), 0,
+ &p->addr.su_sa, su_sockaddr_size(&p->addr)) == -1) {
+ su_perror("do_pong: send");
+ }
+
+ if (opt_verbatim) {
+ puts(buf);
+ fflush(stdout);
+ }
+}
+
+int
+do_recv(struct pinger *p, su_wait_t *w, void *p0)
+{
+ su_sockaddr_t su;
+ socklen_t susize[] = { sizeof(su)};
+ char buf[1024];
+ char nbuf[1024];
+ int n;
+ su_time_t now = su_now();
+
+ assert(p0 == p);
+ assert(p->sort == PONGER);
+
+ su_wait_events(w, p->s);
+
+ n = recvfrom(p->s, buf, sizeof(buf) - 1, 0, &su.su_sa, susize);
+ if (n < 0) {
+ su_perror("do_recv: recvfrom");
+ return 0;
+ }
+ buf[n] = 0;
+
+ if (opt_verbatim)
+ printf("do_recv: %d bytes from [%s]:%u: \"%s\" at %s\n",
+ n, inet_ntop(su.su_family, SU_ADDR(&su), nbuf, sizeof(nbuf)),
+ ntohs(su.su_sin.sin_port), buf, snow(now));
+
+ fflush(stdout);
+
+#if 0
+ if (p->id)
+ puts("do_recv: already a pending reply");
+
+ if (su_timer_set(p->t, do_pong, p) < 0) {
+ fprintf(stderr, "do_recv: su_timer_set() error\n");
+ return 0;
+ }
+
+ p->id = 1;
+#else
+ do_pong(p, p->t, NULL);
+#endif
+
+ return 0;
+}
+
+void
+do_exit(struct pinger *x, su_timer_t *t, void *x0)
+{
+ g_assert(global_gmainloop);
+ if (opt_verbatim)
+ printf("do_exit at %s\n", snow(su_now()));
+ g_main_loop_quit(global_gmainloop);
+}
+
+int
+do_init(su_root_t *root, struct pinger *p)
+{
+ su_wait_t w;
+ su_socket_t s;
+ long interval;
+ su_timer_t *t;
+ su_wakeup_f f;
+ int index, index0;
+
+ switch (p->sort) {
+ case PINGER: f = do_rtt; interval = 200; break;
+ case PONGER: f = do_recv; interval = 40; break;
+ default:
+ return SU_FAILURE;
+ }
+
+ /* Create a sockets, */
+ s = udpsocket();
+ if (su_wait_create(&w, s, SU_WAIT_IN) == SOCKET_ERROR)
+ su_perror("su_wait_create"), exit(1);
+
+ p->s = s;
+ p->t = t = su_timer_create(su_root_task(root), interval);
+ if (t == NULL) {
+ su_perror("su_timer_create");
+ return SU_FAILURE;
+ }
+
+ index0 = su_root_register(root, &w, f, p, 0);
+ if (index0 == SOCKET_ERROR) {
+ su_perror("su_root_register");
+ return SU_FAILURE;
+ }
+
+ index = su_root_register(root, &w, f, p, 0);
+ if (index == SOCKET_ERROR) {
+ su_perror("su_root_register");
+ return SU_FAILURE;
+ }
+
+ su_root_deregister(root, index0);
+
+ p->rindex = index;
+
+ return 0;
+}
+
+void
+do_destroy(su_root_t *root, struct pinger *p)
+{
+ if (opt_verbatim)
+ printf("do_destroy %s at %s\n", p->name, snow(su_now()));
+ su_root_deregister(root, p->rindex);
+ su_timer_destroy(p->t), p->t = NULL;
+ p->running = 0;
+}
+
+void
+start_ping(struct pinger *p, su_msg_r msg, su_sockaddr_t *arg)
+{
+ if (!p->running)
+ return;
+
+ if (opt_verbatim)
+ printf("start_ping: %s\n", p->name);
+
+ p->addr = *arg;
+ p->id = 1;
+ su_timer_set_at(p->t, do_ping, p, su_now());
+}
+
+void
+start_pong(struct pinger *p, su_msg_r msg, su_sockaddr_t *arg)
+{
+ su_msg_r reply;
+
+ if (!p->running)
+ return;
+
+ if (opt_verbatim)
+ printf("start_pong: %s\n", p->name);
+
+ p->addr = *arg;
+
+ if (su_msg_reply(reply, msg, start_ping, sizeof(p->addr)) == 0) {
+ socklen_t sinsize[1] = { sizeof(p->addr) };
+ if (getsockname(p->s, (struct sockaddr*)su_msg_data(reply), sinsize)
+ == SOCKET_ERROR)
+ su_perror("start_pong: getsockname()"), exit(1);
+ su_msg_send(reply);
+ }
+ else {
+ fprintf(stderr, "su_msg_create failed!\n");
+ }
+}
+
+void
+init_ping(struct pinger *p, su_msg_r msg, su_sockaddr_t *arg)
+{
+ su_msg_r reply;
+
+ if (opt_verbatim)
+ printf("init_ping: %s\n", p->name);
+
+ if (su_msg_reply(reply, msg, start_pong, sizeof(p->addr)) == 0) {
+ socklen_t sinsize[1] = { sizeof(p->addr) };
+ if (getsockname(p->s, (struct sockaddr*)su_msg_data(reply), sinsize)
+ == SOCKET_ERROR)
+ su_perror("start_pong: getsockname()"), exit(1);
+ su_msg_send(reply);
+ }
+ else {
+ fprintf(stderr, "su_msg_reply failed!\n");
+ }
+}
+
+static
+RETSIGTYPE term(int n)
+{
+ exit(1);
+}
+
+void
+time_test(void)
+{
+ su_time_t now = su_now(), then = now;
+ su_duration_t t1, t2;
+ su_duration_t us;
+
+ for (us = 0; us < 1000000; us += 300) {
+ then.tv_sec = now.tv_sec;
+ if ((then.tv_usec = now.tv_usec + us) >= 1000000)
+ then.tv_usec -= 1000000, then.tv_sec++;
+ t1 = su_duration(now, then);
+ t2 = su_duration(then, now);
+ assert(t1 == -t2);
+ }
+
+ if (opt_verbatim)
+ printf("time_test: passed\n");
+}
+
+char const name[] = "su_test";
+
+void
+usage(int exitcode)
+{
+ fprintf(stderr, "usage: %s [-6vs] [pid]\n", name);
+ exit(exitcode);
+}
+
+/*
+ * test su_wait functionality:
+ *
+ * Create a ponger, waking up do_recv() when data arrives,
+ * then scheduling do_pong() by timer
+ *
+ * Create a pinger, executed from timer, scheduling do_ping(),
+ * waking up do_rtt() when data arrives
+ *
+ * Create a timer, executing do_exit() after 10 seconds
+ */
+int main(int argc, char *argv[])
+{
+ su_root_t *root;
+ su_clone_r ping = SU_CLONE_R_INIT, pong = SU_CLONE_R_INIT;
+ su_msg_r start_msg = SU_MSG_R_INIT;
+ su_timer_t *t;
+ unsigned long sleeppid = 0;
+
+ struct pinger
+ pinger = { PINGER, "ping", 1 },
+ ponger = { PONGER, "pong", 1 };
+
+ char *argv0 = argv[0];
+
+ while (argv[1]) {
+ if (strcmp(argv[1], "-v") == 0) {
+ opt_verbatim = 1;
+ argv++;
+ }
+#if SU_HAVE_IN6
+ else if (strcmp(argv[1], "-6") == 0) {
+ opt_family = AF_INET6;
+ argv++;
+ }
+#endif
+ else if (strcmp(argv[1], "-s") == 0) {
+ opt_singlethread = 1;
+ argv++;
+ }
+ else if (strlen(argv[1]) == strspn(argv[1], "0123456789")) {
+ sleeppid = strtoul(argv[1], NULL, 10);
+ argv++;
+ }
+ else {
+ usage(1);
+ }
+ }
+
+ signal(SIGTERM, term);
+
+ su_init(); atexit(su_deinit);
+
+ time_test();
+
+ global_gmainloop = g_main_loop_new(NULL, FALSE);
+ g_assert(global_gmainloop);
+
+ root = su_glib_root_create(NULL);
+
+ if (!root) perror("su_root_glib_create"), exit(1);
+
+ if (!g_source_attach(su_glib_root_gsource(root), g_main_loop_get_context(global_gmainloop)))
+ perror("g_source_attach"), exit(1);
+
+ su_root_threading(root, 0 && !opt_singlethread);
+
+ if (su_clone_start(root, ping, &pinger, do_init, do_destroy) != 0)
+ perror("su_clone_start"), exit(1);
+ if (su_clone_start(root, pong, &ponger, do_init, do_destroy) != 0)
+ perror("su_clone_start"), exit(1);
+
+ /* Test timer, exiting after 200 milliseconds */
+ t = su_timer_create(su_root_task(root), 200L);
+ if (t == NULL)
+ su_perror("su_timer_create"), exit(1);
+ su_timer_set(t, (su_timer_f)do_exit, NULL);
+
+ su_msg_create(start_msg, su_clone_task(ping), su_clone_task(pong),
+ init_ping, 0);
+ su_msg_send(start_msg);
+
+ g_main_loop_run(global_gmainloop);
+
+ su_clone_wait(root, ping);
+ su_clone_wait(root, pong);
+
+ su_timer_destroy(t);
+
+ if (pinger.rtt_n) {
+ printf("%s executed %u pings in %g, mean rtt=%g sec\n", name,
+ pinger.rtt_n, pinger.rtt_total, pinger.rtt_total / pinger.rtt_n);
+ }
+ su_root_destroy(root);
+
+ g_main_loop_unref(global_gmainloop), global_gmainloop = NULL;
+
+ if (opt_verbatim)
+ printf("%s exiting\n", argv0);
+
+#ifndef HAVE_WIN32
+ if (sleeppid)
+ kill(sleeppid, SIGTERM);
+#endif
+
+ return 0;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ChangeLog Thu Dec 21 01:30:28 2006
@@ -0,0 +1,415 @@
+2006-09-26 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * libsofia-sip-ua interface v2 frozen (2:0:2) for the 1.12.2 release
+
+2006-08-30 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * nua: added tag nutag_refer_with_id.
+
+2006-08-28 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * libsofia-sip-ua interface v2 opened to development, version to 2:0:2.
+
+2006-08-25 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Added urltag_scan().
+
+2006-08-23 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * nta.c, nta.h: added nta_leg_make_replaces(), nta_leg_by_replaces().
+
+ * nua: event watcher (nua_subscribe, nua_watcher) now tries to re-establish
+ subscription if the subscription was terminated with reason "deactivated" or
+ "probation". Likewise, if SUBSCRIBE was returned a suitable error response
+ with Retry-After header, nua tries to re-establish subscription after
+ given interval.
+
+2006-07-27 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * libsofia-sip-ua interface v1 frozen (1.12.1), version to 1:0:1.
+
+2006-06-16 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * libsofia-sip-ua interface v0 frozen (1.12.0), version to 0:0:0.
+
+2005-11-28 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * <SUBDIRS>/Doxyfile: Fixed the use of doxytags. Now
+ a separate 'doxytags_MODNAME' file is created for each
+ module.
+
+2005-11-15 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * <SUBDIRS>/Makefile.am: Changed to use the 'include_sofia_HEADERS'
+ variable for listing public library headers. The variable
+ is defined in the top-level configure.ac.
+
+2005-10-27 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Always including stun library.
+
+ M ./libsofia-sip-ua/Makefile.am -6 +3
+
+ * Added rule to make missing module libraries in libsofia-sip-ua/sofia.am
+
+ M ./libsofia-sip-ua/sofia.am -1 +6
+
+ * Added LDFLAG -static to all test programs in their Makefile.am
+
+ M ./libsofia-sip-ua/bnf/Makefile.am -1 +1
+ M ./libsofia-sip-ua/http/Makefile.am -2 +2
+ M ./libsofia-sip-ua/ipt/Makefile.am -1 +2
+ M ./libsofia-sip-ua/iptsec/Makefile.am +2
+ M ./libsofia-sip-ua/msg/Makefile.am -2 +2
+ M ./libsofia-sip-ua/nta/Makefile.am -1 +1
+ M ./libsofia-sip-ua/nth/Makefile.am +2
+ M ./libsofia-sip-ua/nua/Makefile.am +2
+ M ./libsofia-sip-ua/sdp/Makefile.am +3
+ M ./libsofia-sip-ua/sip/Makefile.am +4
+ M ./libsofia-sip-ua/soa/Makefile.am +2
+ M ./libsofia-sip-ua/sresolv/Makefile.am -2 +2
+ M ./libsofia-sip-ua/stun/Makefile.am -6 +1
+
+2005-10-14 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Shell syntax exercise.
+
+ M ./autogen.sh -4 +4
+
+2005-10-13 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * <SUBDIRS>/Makefile.am: fixed COVERAGE_INPUT.
+
+2005-10-13 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * <SUBDIRS>/Makefile.am: Build all submodules as proper shared
+ libraries (noinst_LTLIBRARIES). Fixes sf.net:#1264030.
+
+2005-09-09 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * darcs changes --from-tag pessi-darcs-1:
+
+ Thu Sep 8 21:50:24 EEST 2005 Pekka.Pessi at nokia.com
+ * There is no separate TLS test anymore.
+
+ M ./tport/Makefile.am -1 +1
+
+ Thu Sep 8 21:36:46 EEST 2005 Pekka.Pessi at nokia.com
+ * Logging.
+
+ M ./nua/nua_stack.c -4 +2
+
+ Thu Sep 8 21:36:39 EEST 2005 Pekka.Pessi at nokia.com
+ * Added tests for tport_convert_addr.
+
+ M ./tport/tport_test.c +22
+
+ Thu Sep 8 21:36:27 EEST 2005 Pekka.Pessi at nokia.com
+ * Fixed receiving empty SigComp message.
+
+ M ./tport/tport.c +7
+
+ Thu Sep 8 21:32:48 EEST 2005 Pekka.Pessi at nokia.com
+ * Updated ChangeLogs.
+
+ M ./nta/ChangeLog -2 +10
+
+ Thu Sep 8 21:32:37 EEST 2005 Pekka.Pessi at nokia.com
+ * Updated ChangeLog.
+
+ M ./iptsec/ChangeLog +11
+
+ Thu Sep 8 21:31:16 EEST 2005 Pekka.Pessi at nokia.com
+ * Added more tests.
+
+ M ./nta/nta.c -2 +2
+ M ./nta/nta_test.c -2 +44
+
+ Thu Sep 8 21:30:19 EEST 2005 Pekka.Pessi at nokia.com
+ * Handling changes in alias list.
+
+ M ./nta/nta.c -9 +22
+ M ./nta/nta_test.c +1
+
+ Thu Sep 8 21:18:47 EEST 2005 Pekka.Pessi at nokia.com
+ * Gcc4 fixes.
+
+ M ./ipt/base64.c -1 +1
+ M ./iptsec/auth_module.c -1 +1
+ M ./iptsec/auth_plugin_delayed.c +4
+ M ./nua/nua_stack.c -1 +1
+ M ./nua/nua_tag.c -1 +1
+ M ./nua/nua_tag.h -5 +5
+ M ./su/htable2.h -1 +1
+ M ./su/su.c -1 +1
+ M ./tport/tport.c -7 +7
+
+ Thu Sep 8 21:16:39 EEST 2005 Pekka.Pessi at nokia.com
+ * Added tests for tport_shutdown(). Do not assert() on invalid
+ input.
+
+ M ./tport/tport.c -2
+ M ./tport/tport_test.c +5
+
+ Thu Sep 8 21:13:18 EEST 2005 Pekka.Pessi at nokia.com
+ * Log when password file is read.
+
+ M ./iptsec/auth_module.c +3
+
+ Thu Sep 8 21:12:49 EEST 2005 Pekka.Pessi at nokia.com
+ * Allow empty allow list.
+
+ M ./iptsec/auth_module.c -1 +1
+
+ Thu Sep 8 21:12:26 EEST 2005 Pekka.Pessi at nokia.com
+ * Use unsigned as auth_htable_t hash type.
+
+ M ./iptsec/auth_module.c -5 +5
+
+ Thu Sep 8 21:10:23 EEST 2005 Pekka.Pessi at nokia.com
+ * Added auth_digest_credentials().
+ Use opaque to match Authorization header.
+
+ M ./iptsec/auth_digest_test.c -2 +3
+ M ./iptsec/auth_module.c -1 +78
+ M ./iptsec/auth_plugin.h +4
+
+ Thu Sep 8 21:07:57 EEST 2005 Pekka.Pessi at nokia.com
+ * Fixed gcc4 problems with tag classes.
+
+ M ./http/http_tag.h.in +3
+ M ./msg/msg_mime_protos.h.in +3
+ M ./sdp/sdp_tag.h +3
+ M ./su/su_tag_class.h +12
+ M ./su/su_tag_inline.h -1 +1
+ M ./url/url_tag_class.h +3
+
+ Thu Sep 8 21:06:22 EEST 2005 Pekka.Pessi at nokia.com
+ * Added sip_security_client_select().
+
+ M ./sip/sip_util.c -37 +14
+ M ./sip/sip_util.h +4
+
+ Thu Sep 8 19:32:19 EEST 2005 Pekka.Pessi at nokia.com
+ * Not using su_home_deinit() to destroy homes that are not
+ initialized.
+
+ M ./nth/nth_server.c -3 +2
+ M ./nua/nua.c -2 +1
+ M ./su/su_vector.c -2 +1
+
+ Thu Sep 8 19:06:31 EEST 2005 Pekka.Pessi at nokia.com
+ * Moved function types to msg_types.h.
+
+ M ./msg/msg_header.h -7
+ M ./msg/msg_types.h +9
+
+ Thu Sep 8 18:35:12 EEST 2005 Pekka.Pessi at nokia.com
+ * Fixed su_clone_start() return value.
+
+ M ./su/su_root.c -1 +1
+
+ Thu Sep 8 18:34:26 EEST 2005 Pekka.Pessi at nokia.com
+ * Removed SIP_DLL_VAR.
+
+ M ./sip/sip_dll.h -7
+
+ Thu Sep 8 18:29:27 EEST 2005 Pekka.Pessi at nokia.com
+ * Avoid __func__.
+
+ M ./sresolv/sresolv.c -3 +4
+
+ Thu Sep 8 18:29:09 EEST 2005 Pekka.Pessi at nokia.com
+ * Fix includes.
+
+ M ./nta/nta.c -2 +1
+ M ./sresolv/sresolv.c -4 +7
+ M ./sresolv/sresolv.h -1 +1
+
+ Thu Sep 8 18:26:35 EEST 2005 Pekka.Pessi at nokia.com
+ * Using autoconf to figure out 64-bit types. Avoid off_t and
+ 64-bit constants.
+
+ M ../configure.ac +6
+ M ./nta/sl_read_payload.c -1 +1
+ M ./nua/nua_stack.c -6 +5
+ M ./sdp/sdp_parse.c -3 +2
+ M ./sdp/sdp_print.c -5 +5
+ M ./sip/validator.c -18 +18
+ M ./soa/soa.c -3 +4
+ M ./su/su_time.c -1 +1
+ M ./su/tstdef.h -3 +3
+
+ Thu Sep 8 18:17:58 EEST 2005 Pekka.Pessi at nokia.com
+ * Using RETSIGTYPE.
+
+ M ../configure.ac -3 +4
+ M ./nth/http-server.c -2 +2
+ M ./soa/test_soa.c -1 +3
+ M ./su/su_test.c -1 +1
+ M ./su/su_timer_test.c -1 +1
+
+ Thu Sep 8 18:13:35 EEST 2005 Pekka.Pessi at nokia.com
+ * Fixed macro expansion problem with VC6
+
+ M ./nta/nta_test.c -2 +2
+
+ Thu Sep 8 18:12:45 EEST 2005 Pekka.Pessi at nokia.com
+ * Compile without sresolv, too.
+
+ M ./nta/nta.c -3 +5
+
+ Thu Sep 8 18:12:16 EEST 2005 Pekka.Pessi at nokia.com
+ * Fixed const/non-const problems with gcc4/vc6.
+
+ M ./msg/msg_mime.c -6 +6
+ M ./msg/msg_parser.c -1 +1
+ M ./nta/nta.c -4 +4
+ M ./sip/sip_basic.c -1 +1
+ M ./sip/sip_security.c -1 +1
+ M ./sip/sip_util.c -2 +2
+ M ./su/htable.h -10 +10
+
+ Thu Sep 8 18:06:04 EEST 2005 Pekka.Pessi at nokia.com
+ * Moved msg_hclass_t definition into msg_types.h
+
+ M ./msg/msg_header.h -37
+ M ./msg/msg_types.h +40
+
+ Thu Sep 8 18:05:32 EEST 2005 Pekka.Pessi at nokia.com
+ * Silenced vc6 warning.
+
+ M ./iptsec/auth_module.c -1 +1
+
+ Thu Sep 8 18:05:07 EEST 2005 Pekka.Pessi at nokia.com
+ * Not using __func__.
+
+ M ./iptsec/auth_digest.c -2 +2
+
+ Thu Sep 8 18:04:38 EEST 2005 Pekka.Pessi at nokia.com
+ * Silenced gcc4 warning.
+
+ M ./tport/tport.c -1 +1
+
+ Thu Sep 8 18:04:16 EEST 2005 Pekka.Pessi at nokia.com
+ * Better following autoconf macros
+
+ M ./tport/tport.c +9
+
+ Thu Sep 8 18:02:53 EEST 2005 Pekka.Pessi at nokia.com
+ * Using TPORT_DLL.
+
+ M ./tport/tport.h -10 +19
+
+ Thu Sep 8 18:01:58 EEST 2005 Pekka.Pessi at nokia.com
+ * Not using IS_EXCLUDED_MASK.
+
+ M ./url/url.c -1 +6
+
+ Thu Sep 8 18:01:17 EEST 2005 Pekka.Pessi at nokia.com
+ * Explicitly using <errno.h>
+
+ M ./msg/msg.c +2
+ M ./msg/msg_mclass.c +1
+ M ./msg/msg_mime.c +1
+ M ./msg/msg_parser.c +1
+ M ./nta/nta.c +3
+ M ./nth/nth_client.c +2
+ M ./nth/nth_server.c +2
+ M ./su/su_port.c +1
+ M ./su/su_proxy.c +1
+ M ./su/su_root.c +1
+
+ Thu Sep 8 17:54:28 EEST 2005 Pekka.Pessi at nokia.com
+ * Using http_off_t instead of off_t.
+
+ M ./http/http_basic.c -5 +5
+
+ Thu Sep 8 18:56:58 EEST 2005 Pekka.Pessi at nokia.com
+ * Not using su_home_deinit().
+
+ M ./nua/nua.c -3 +2
+
+ Thu Sep 8 16:40:30 EEST 2005 Pekka.Pessi at nokia.com
+ * Adding soa_asynch.c
+
+ A ./soa/soa_asynch.c
+
+ Thu Sep 8 03:23:00 EEST 2005 Pekka.Pessi at nokia.com
+ * stab 2 at soa
+ Added more functionality to soa. Stab at asynchronous API, too.
+
+ M ./soa/Makefile.am -1 +2
+ M ./soa/soa.c -146 +564
+ M ./soa/soa.h -5 +24
+ M ./soa/soa_add.h -2 +5
+ M ./soa/soa_session.h -21 +48
+ M ./soa/soa_static.c -30 +89
+ M ./soa/soa_tag.c +64
+ M ./soa/test_soa.c -7 +224
+ M ./m4/sac-su2.m4 -1 +1
+
+ Thu Sep 8 03:12:28 EEST 2005 Pekka.Pessi at nokia.com
+ * really run sdp tests
+ Now really running SDP tests.
+
+ M ./sdp/run-tests -1 +1
+
+ Thu Sep 8 03:11:35 EEST 2005 Pekka.Pessi at nokia.com
+ * su_home_new and su_home_unref
+ Added su_home_new() and su_home_unref().
+
+ Fixed su_home_mutex_lock() and su_home_mutex_unlock().
+
+ Slightly changed semantics of su_home_clone() versus
+ su_home_threadsafe().
+
+ M ./http/http_test.c -6 +6
+ M ./msg/msg_test.c -2 +2
+ M ./su/htable_test.c +3
+ M ./su/su_alloc.c -173 +337
+ M ./su/su_alloc.h -10 +18
+ M ./su/su_alloc_lock.c -8 +31
+ M ./su/su_alloc_test.c -5 +12
+
+ Thu Sep 8 03:07:17 EEST 2005 Pekka.Pessi at nokia.com
+ * More liberal sdp parsing for config files.
+ Be more liberal when parsing config files
+ (do not require v=, accept -1 as len argument).
+
+ M ./sdp/sdp_parse.c -9 +25
+
+ Thu Sep 8 01:05:02 EEST 2005 Pekka.Pessi at nokia.com
+ * su_msg_is_non_null
+ Added su_msg_is_non_null().
+
+ M ./su/su_wait.h +11
+
+ Thu Sep 8 01:03:31 EEST 2005 Pekka.Pessi at nokia.com
+ * sdp_parser_home
+ Added sdp_parser_home()
+
+ M ./sdp/sdp.h +2
+ M ./sdp/sdp_parse.c +10
+
+2005-09-08 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * Makefile.am: Workaround for automake bug related to adding
+ custom targets to RECURSIVE_TARGETS.
+
+2005-08-25 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * Makefile.am: soa depends on ipt and sip, so has to
+ be after them in SUBDIRS.
+
+2005-08-17 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Fixed BEGIN()/END() pairs in test programs.
+
+2005-08-04 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Added soa module.
+
+2005-07-18 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * libsofia-sip-ua created.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/Makefile.am Thu Dec 21 01:30:28 2006
@@ -0,0 +1,104 @@
+#
+# Makefile.am for sofia-sip/libsofia-sip-ua
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+#
+# ref: http://www.gnu.org/software/automake/manual/automake.html
+
+AUTOMAKE_OPTIONS = foreign
+
+# note: order does matter in the subdir list
+SUBDIRS = su features bnf sresolv sdp url msg sip stun ipt soa \
+ tport http nta nea iptsec nth nua
+DIST_SUBDIRS = $(SUBDIRS) docs
+
+EXTRA_DIST = sofia.am
+DOXYGEN = doxygen
+
+lib_LTLIBRARIES = libsofia-sip-ua.la
+
+libsofia_sip_ua_la_SOURCES =
+libsofia_sip_ua_la_LIBADD = bnf/libbnf.la \
+ features/libfeatures.la \
+ ipt/libipt.la \
+ iptsec/libiptsec.la \
+ msg/libmsg.la \
+ nea/libnea.la \
+ nta/libnta.la \
+ nth/libnth.la \
+ nua/libnua.la \
+ http/libhttp.la \
+ sdp/libsdp.la \
+ sip/libsip.la \
+ soa/libsoa.la \
+ sresolv/libsresolv.la \
+ su/libsu.la \
+ stun/libstun.la \
+ tport/libtport.la \
+ url/liburl.la
+# set the libtool version info version:revision:age for libsofia-sip-ua
+# - soname to 'libsofia-sip-ua.so.(CUR-AGE)'
+libsofia_sip_ua_la_LDFLAGS = \
+ -version-info $(LIBVER_SOFIA_SIP_UA_CUR):$(LIBVER_SOFIA_SIP_UA_REV):$(LIBVER_SOFIA_SIP_UA_AGE)
+
+if ENABLE_COVERAGE
+COVERAGE_RECURSIVE = coverage-recursive
+coverage: $(COVERAGE_RECURSIVE)
+endif
+
+all-recursive: built-sources-recursive
+built-sources: built-sources-recursive
+clean-built-sources: clean-built-sources-recursive
+
+built-sources-recursive clean-built-sources-recursive $(COVERAGE_RECURSIVE):
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $@ in $$subdir"; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$target) \
+ done;
+
+doxygen: built-sources
+ @echo Generating empty doxytags
+ cd ${srcdir}; \
+ mkdir -p docs/html ; \
+ for d in $(DIST_SUBDIRS); do \
+ test -r $$d/Doxyfile || continue ; \
+ if ! test -r docs/$$d.doxytags ; then \
+ echo '<?xml version="1.0"?><tagfile/>' > docs/$$d.doxytags ; \
+ else \
+ sed '2,10s!<name>index</name>!<name>'$$d'_index</name>!' \
+ docs/$$d.doxytags > docs/$$d.doxytags.tmp && \
+ mv -f docs/$$d.doxytags.tmp docs/$$d.doxytags ; \
+ fi ; \
+ done
+ @cd ${srcdir} ;\
+ for d in $(DIST_SUBDIRS); do \
+ test -r $$d/Doxyfile \
+ && pushd $$d > /dev/null \
+ && echo running ${DOXYGEN} first time in $$d \
+ && ${DOXYGEN} 2>&1 \
+ | egrep -v -i -e 'Warning: (unsupported (xml/)?html tag|unable to resolve reference|could not be resolved)' \
+ ; popd > /dev/null ; \
+ test -r docs/$$d.doxytags && \
+ sed '2,10s!<name>index</name>!<name>'$$d'_index</name>!' \
+ docs/$$d.doxytags > docs/$$d.doxytags.tmp && \
+ mv -f docs/$$d.doxytags.tmp docs/$$d.doxytags ; \
+ done
+ @cd ${srcdir} ;\
+ for d in $(DIST_SUBDIRS); do \
+ test -r $$d/Doxyfile \
+ && pushd $$d > /dev/null \
+ && echo running ${DOXYGEN} in second time in $$d \
+ && ${DOXYGEN} 2>&1 \
+ | egrep -v -i -e 'Warning: Unsupported (xml/)?html tag' \
+ ; popd > /dev/null ; \
+ test -r docs/$$d.doxytags && \
+ sed '2,10s!<name>index</name>!<name>'$$d'_index</name>!' \
+ docs/$$d.doxytags > docs/$$d.doxytags.tmp && \
+ mv -f docs/$$d.doxytags.tmp docs/$$d.doxytags ; \
+ done
+ cd ${srcdir}/docs/html && ../hide_emails.sh
+
+.PHONY: built-sources built-sources-am empty-doxytags doxygen
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/Makefile.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1,679 @@
+# 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.
+
+ at SET_MAKE@
+
+#
+# Makefile.am for sofia-sip/libsofia-sip-ua
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+#
+# ref: http://www.gnu.org/software/automake/manual/automake.html
+
+SOURCES = $(libsofia_sip_ua_la_SOURCES)
+
+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@
+subdir = libsofia-sip-ua
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ChangeLog
+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 =
+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|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(libdir)"
+libLTLIBRARIES_INSTALL = $(INSTALL)
+LTLIBRARIES = $(lib_LTLIBRARIES)
+libsofia_sip_ua_la_DEPENDENCIES = bnf/libbnf.la \
+ features/libfeatures.la ipt/libipt.la iptsec/libiptsec.la \
+ msg/libmsg.la nea/libnea.la nta/libnta.la nth/libnth.la \
+ nua/libnua.la http/libhttp.la sdp/libsdp.la sip/libsip.la \
+ soa/libsoa.la sresolv/libsresolv.la su/libsu.la \
+ stun/libstun.la tport/libtport.la url/liburl.la
+am_libsofia_sip_ua_la_OBJECTS =
+libsofia_sip_ua_la_OBJECTS = $(am_libsofia_sip_ua_la_OBJECTS)
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) -I$(top_builddir)/libsofia-sip-ua/su/sofia-sip
+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 = $(libsofia_sip_ua_la_SOURCES)
+DIST_SOURCES = $(libsofia_sip_ua_la_SOURCES)
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+ html-recursive info-recursive install-data-recursive \
+ install-exec-recursive install-info-recursive \
+ install-recursive installcheck-recursive installdirs-recursive \
+ pdf-recursive ps-recursive uninstall-info-recursive \
+ uninstall-recursive
+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@
+AUTOMAKE_OPTIONS = foreign
+
+# note: order does matter in the subdir list
+SUBDIRS = su features bnf sresolv sdp url msg sip stun ipt soa \
+ tport http nta nea iptsec nth nua
+
+DIST_SUBDIRS = $(SUBDIRS) docs
+EXTRA_DIST = sofia.am
+lib_LTLIBRARIES = libsofia-sip-ua.la
+libsofia_sip_ua_la_SOURCES =
+libsofia_sip_ua_la_LIBADD = bnf/libbnf.la \
+ features/libfeatures.la \
+ ipt/libipt.la \
+ iptsec/libiptsec.la \
+ msg/libmsg.la \
+ nea/libnea.la \
+ nta/libnta.la \
+ nth/libnth.la \
+ nua/libnua.la \
+ http/libhttp.la \
+ sdp/libsdp.la \
+ sip/libsip.la \
+ soa/libsoa.la \
+ sresolv/libsresolv.la \
+ su/libsu.la \
+ stun/libstun.la \
+ tport/libtport.la \
+ url/liburl.la
+
+# set the libtool version info version:revision:age for libsofia-sip-ua
+# - soname to 'libsofia-sip-ua.so.(CUR-AGE)'
+libsofia_sip_ua_la_LDFLAGS = \
+ -version-info $(LIBVER_SOFIA_SIP_UA_CUR):$(LIBVER_SOFIA_SIP_UA_REV):$(LIBVER_SOFIA_SIP_UA_AGE)
+
+ at ENABLE_COVERAGE_TRUE@COVERAGE_RECURSIVE = coverage-recursive
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.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) --foreign libsofia-sip-ua/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --foreign libsofia-sip-ua/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
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(libdir)" || $(mkdir_p) "$(DESTDIR)$(libdir)"
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ if test -f $$p; then \
+ f=$(am__strip_dir) \
+ echo " $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \
+ else :; fi; \
+ done
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @set -x; list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ p=$(am__strip_dir) \
+ echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \
+ $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_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
+libsofia-sip-ua.la: $(libsofia_sip_ua_la_OBJECTS) $(libsofia_sip_ua_la_DEPENDENCIES)
+ $(LINK) -rpath $(libdir) $(libsofia_sip_ua_la_LDFLAGS) $(libsofia_sip_ua_la_OBJECTS) $(libsofia_sip_ua_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+uninstall-info-am:
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+# (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+ @set fnord $$MAKEFLAGS; amf=$$2; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+mostlyclean-recursive clean-recursive distclean-recursive \
+maintainer-clean-recursive:
+ @set fnord $$MAKEFLAGS; amf=$$2; \
+ dot_seen=no; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ rev=''; for subdir in $$list; do \
+ if test "$$subdir" = "."; then :; else \
+ rev="$$subdir $$rev"; \
+ fi; \
+ done; \
+ rev="$$rev ."; \
+ target=`echo $@ | sed s/-recursive//`; \
+ for subdir in $$rev; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+ done && test -z "$$fail"
+tags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+ done
+ctags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+ 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: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ 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: ctags-recursive $(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
+
+distdir: $(DISTFILES)
+ @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
+ list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test -d "$(distdir)/$$subdir" \
+ || $(mkdir_p) "$(distdir)/$$subdir" \
+ || exit 1; \
+ distdir=`$(am__cd) $(distdir) && pwd`; \
+ top_distdir=`$(am__cd) $(top_distdir) && pwd`; \
+ (cd $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$top_distdir" \
+ distdir="$$distdir/$$subdir" \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(LTLIBRARIES)
+installdirs: installdirs-recursive
+installdirs-am:
+ for dir in "$(DESTDIR)$(libdir)"; do \
+ test -z "$$dir" || $(mkdir_p) "$$dir"; \
+ done
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+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)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-libtool distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-exec-am: install-libLTLIBRARIES
+
+install-info: install-info-recursive
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-libLTLIBRARIES
+
+uninstall-info: uninstall-info-recursive
+
+.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am check check-am \
+ clean clean-generic clean-libLTLIBRARIES clean-libtool \
+ clean-recursive ctags ctags-recursive distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-recursive distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-exec install-exec-am install-info \
+ install-info-am install-libLTLIBRARIES install-man \
+ install-strip installcheck installcheck-am installdirs \
+ installdirs-am maintainer-clean maintainer-clean-generic \
+ maintainer-clean-recursive mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool mostlyclean-recursive \
+ pdf pdf-am ps ps-am tags tags-recursive uninstall uninstall-am \
+ uninstall-info-am uninstall-libLTLIBRARIES
+
+ at ENABLE_COVERAGE_TRUE@coverage: $(COVERAGE_RECURSIVE)
+
+all-recursive: built-sources-recursive
+built-sources: built-sources-recursive
+clean-built-sources: clean-built-sources-recursive
+
+built-sources-recursive clean-built-sources-recursive $(COVERAGE_RECURSIVE):
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $@ in $$subdir"; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$target) \
+ done;
+
+doxygen: built-sources
+ @echo Generating empty doxytags
+ cd ${srcdir}; \
+ mkdir -p docs/html ; \
+ for d in $(DIST_SUBDIRS); do \
+ test -r $$d/Doxyfile || continue ; \
+ if ! test -r docs/$$d.doxytags ; then \
+ echo '<?xml version="1.0"?><tagfile/>' > docs/$$d.doxytags ; \
+ else \
+ sed '2,10s!<name>index</name>!<name>'$$d'_index</name>!' \
+ docs/$$d.doxytags > docs/$$d.doxytags.tmp && \
+ mv -f docs/$$d.doxytags.tmp docs/$$d.doxytags ; \
+ fi ; \
+ done
+ @cd ${srcdir} ;\
+ for d in $(DIST_SUBDIRS); do \
+ test -r $$d/Doxyfile \
+ && pushd $$d > /dev/null \
+ && echo running ${DOXYGEN} first time in $$d \
+ && ${DOXYGEN} 2>&1 \
+ | egrep -v -i -e 'Warning: (unsupported (xml/)?html tag|unable to resolve reference|could not be resolved)' \
+ ; popd > /dev/null ; \
+ test -r docs/$$d.doxytags && \
+ sed '2,10s!<name>index</name>!<name>'$$d'_index</name>!' \
+ docs/$$d.doxytags > docs/$$d.doxytags.tmp && \
+ mv -f docs/$$d.doxytags.tmp docs/$$d.doxytags ; \
+ done
+ @cd ${srcdir} ;\
+ for d in $(DIST_SUBDIRS); do \
+ test -r $$d/Doxyfile \
+ && pushd $$d > /dev/null \
+ && echo running ${DOXYGEN} in second time in $$d \
+ && ${DOXYGEN} 2>&1 \
+ | egrep -v -i -e 'Warning: Unsupported (xml/)?html tag' \
+ ; popd > /dev/null ; \
+ test -r docs/$$d.doxytags && \
+ sed '2,10s!<name>index</name>!<name>'$$d'_index</name>!' \
+ docs/$$d.doxytags > docs/$$d.doxytags.tmp && \
+ mv -f docs/$$d.doxytags.tmp docs/$$d.doxytags ; \
+ done
+ cd ${srcdir}/docs/html && ../hide_emails.sh
+
+.PHONY: built-sources built-sources-am empty-doxytags doxygen
+# 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:
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/ChangeLog Thu Dec 21 01:30:28 2006
@@ -0,0 +1,7 @@
+2006-06-15 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * sofia-sip/hostdomain.h (host_is_local): Function added.
+
+2005-07-18 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * Initial import of the module to Sofia-SIP tree.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/Doxyfile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/Doxyfile Thu Dec 21 01:30:28 2006
@@ -0,0 +1,14 @@
+PROJECT_NAME = "bnf"
+OUTPUT_DIRECTORY = ../docs/html/bnf
+
+INPUT = bnf.docs sofia-sip .
+
+ at INCLUDE = ../docs/Doxyfile.conf
+
+TAGFILES += ../docs/su.doxytags=../su
+
+GENERATE_TAGFILE = ../docs/bnf.doxytags
+
+PREDEFINED += "static="
+
+MAX_INITIALIZER_LINES = 2
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/Makefile.am Thu Dec 21 01:30:28 2006
@@ -0,0 +1,46 @@
+#
+# Makefile.am for bnf module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+INCLUDES = -I$(srcdir)/../su -I../su
+
+# ----------------------------------------------------------------------
+# Build targets
+
+noinst_LTLIBRARIES = libbnf.la
+
+check_PROGRAMS = torture_bnf
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+
+nobase_include_sofia_HEADERS = sofia-sip/bnf.h sofia-sip/hostdomain.h
+
+libbnf_la_SOURCES = bnf.c
+
+COVERAGE_INPUT = $(libbnf_la_SOURCES) $(include_sofia_HEADERS)
+
+LDADD = libbnf.la
+
+torture_bnf_LDFLAGS = -static
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+
+EXTRA_DIST = Doxyfile bnf.docs
+
+# ----------------------------------------------------------------------
+# Tests
+
+TESTS = torture_bnf
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+
+include ../sofia.am
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/Makefile.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1,685 @@
+# 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.
+
+ at SET_MAKE@
+
+#
+# Makefile.am for bnf module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+# common Makefile targets for libsofia-sip-ua modules
+# ---------------------------------------------------
+
+
+SOURCES = $(libbnf_la_SOURCES) torture_bnf.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 = torture_bnf$(EXEEXT)
+DIST_COMMON = $(nobase_include_sofia_HEADERS) $(srcdir)/../sofia.am \
+ $(srcdir)/Makefile.am $(srcdir)/Makefile.in ChangeLog
+subdir = libsofia-sip-ua/bnf
+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 =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libbnf_la_LIBADD =
+am_libbnf_la_OBJECTS = bnf.lo
+libbnf_la_OBJECTS = $(am_libbnf_la_OBJECTS)
+torture_bnf_SOURCES = torture_bnf.c
+torture_bnf_OBJECTS = torture_bnf.$(OBJEXT)
+torture_bnf_LDADD = $(LDADD)
+torture_bnf_DEPENDENCIES = libbnf.la
+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 = $(libbnf_la_SOURCES) torture_bnf.c
+DIST_SOURCES = $(libbnf_la_SOURCES) torture_bnf.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|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(include_sofiadir)"
+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)/../su -I../su
+
+# ----------------------------------------------------------------------
+# Build targets
+noinst_LTLIBRARIES = libbnf.la
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+nobase_include_sofia_HEADERS = sofia-sip/bnf.h sofia-sip/hostdomain.h
+libbnf_la_SOURCES = bnf.c
+COVERAGE_INPUT = $(libbnf_la_SOURCES) $(include_sofia_HEADERS)
+LDADD = libbnf.la
+torture_bnf_LDFLAGS = -static
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+EXTRA_DIST = Doxyfile bnf.docs
+
+# ----------------------------------------------------------------------
+# Tests
+TESTS = torture_bnf
+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
+
+all: 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/bnf/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu libsofia-sip-ua/bnf/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-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
+libbnf.la: $(libbnf_la_OBJECTS) $(libbnf_la_DEPENDENCIES)
+ $(LINK) $(libbnf_la_LDFLAGS) $(libbnf_la_OBJECTS) $(libbnf_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
+torture_bnf$(EXEEXT): $(torture_bnf_OBJECTS) $(torture_bnf_DEPENDENCIES)
+ @rm -f torture_bnf$(EXEEXT)
+ $(LINK) $(torture_bnf_LDFLAGS) $(torture_bnf_OBJECTS) $(torture_bnf_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/bnf.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/torture_bnf.Po at am__quote@
+
+.c.o:
+ at am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+ at am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ at am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at 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: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(include_sofiadir)"; do \
+ test -z "$$dir" || $(mkdir_p) "$$dir"; \
+ done
+install: 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."
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+ 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-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-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-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-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-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) $<
+
+ at ENABLE_COVERAGE_TRUE@coverage:
+ at 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)
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+# 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:
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/bnf.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/bnf.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,913 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005,2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE bnf.c
+ * @brief Character syntax table for HTTP-like protocols.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Kai Vehmanen <Kai.Vehmanen at nokia.com>
+ *
+ * @date Created: Thu Jun 8 19:28:55 2000 ppessi
+ */
+
+#include "config.h"
+
+#include "sofia-sip/bnf.h"
+
+#include <assert.h>
+
+#define ws bnf_ws
+#define crlf bnf_crlf
+#define alpha bnf_alpha
+#define digit bnf_mark|bnf_token0|bnf_safe
+#define sep bnf_separator
+#define msep bnf_mark|bnf_separator
+#define psep bnf_param0|bnf_separator
+#define tok bnf_token0
+#define mtok bnf_mark|bnf_token0
+#define smtok bnf_mark|bnf_token0|bnf_safe
+#define safe bnf_safe
+
+/** Table for determining class of a character */
+unsigned char const _bnf_table[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, ws, crlf, 0, 0, crlf, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ ws, mtok, sep, 0, safe, mtok, 0, mtok, /* !"#$%&' */
+ msep, msep, mtok, tok, sep, smtok, smtok, psep, /* ()*+,-./ */
+ digit, digit, digit, digit, digit, digit, digit, digit, /* 01234567 */
+ digit, digit, psep, sep, sep, sep, sep, sep, /* 89:;<=>? */
+ sep, alpha, alpha, alpha, alpha, alpha, alpha, alpha, /* @ABCDEFG */
+ alpha, alpha, alpha, alpha, alpha, alpha, alpha, alpha, /* HIJKLMNO */
+ alpha, alpha, alpha, alpha, alpha, alpha, alpha, alpha, /* PQRSTUVW */
+ alpha, alpha, alpha, psep, sep, psep, 0, smtok, /* XYZ[\]^_ */
+ tok, alpha, alpha, alpha, alpha, alpha, alpha, alpha, /* `abcdefg */
+ alpha, alpha, alpha, alpha, alpha, alpha, alpha, alpha, /* hijklmno */
+ alpha, alpha, alpha, alpha, alpha, alpha, alpha, alpha, /* pqrstuvw */
+ alpha, alpha, alpha, sep, 0, sep, mtok, 0, /* xyz{|}~ */
+};
+
+
+#define BM(c, m00, m32, m64, m96) \
+ ((c < 64) \
+ ? ((c < 32) \
+ ? (m00 & (1 << (31 - c))) \
+ : (m32 & (1 << (63 - c)))) \
+ : ((c < 96) \
+ ? (m64 & (1 << (95 - c))) \
+ : (m96 & (1 << (127 - c)))))
+
+/** Span of a token */
+size_t bnf_span_token(char const *s)
+{
+ char const *e = s;
+ unsigned const m32 = 0x4536FFC0U, m64 = 0x7FFFFFE1U, m96 = 0xFFFFFFE2U;
+
+ while (BM(*e, 0, m32, m64, m96))
+ e++;
+
+ return e - s;
+}
+
+/** Span of a token */
+size_t bnf_span_token4(char const *s)
+{
+ char const *e = s;
+ while (_bnf_table[(unsigned char)(*e)] & bnf_token)
+ e++;
+ return e - s;
+}
+
+char * bnf_span_token_end(char const *s)
+{
+ return (char *)s;
+}
+
+/** Return length of decimal-octet */
+static inline int span_ip4_octet(char const *host)
+{
+ /*
+ decimal-octet = DIGIT
+ / DIGIT DIGIT
+ / (("0"/"1") 2*(DIGIT))
+ / ("2" ("0"/"1"/"2"/"3"/"4") DIGIT)
+ / ("2" "5" ("0"/"1"/"2"/"3"/"4"/"5"))
+ */
+
+ if (!IS_DIGIT(host[0]))
+ return 0;
+
+ /* DIGIT */
+ if (!IS_DIGIT(host[1]))
+ return 1;
+
+ if (host[0] == '2') {
+ /* ("2" "5" ("0"/"1"/"2"/"3"/"4"/"5")) */
+ if (host[1] == '5' && host[2] >= '0' && host[2] <= '5')
+ return 3;
+
+ /* ("2" ("0"/"1"/"2"/"3"/"4") DIGIT) */
+ if (host[1] >= '0' && host[1] <= '4' &&
+ host[2] >= '0' && host[2] <= '9')
+ return 3;
+ }
+ else if (host[0] == '0' || host[0] == '1') {
+ if (IS_DIGIT(host[2]))
+ /* ("1" 2*(DIGIT)) ... or "0" 2*(DIGIT) */
+ return 3;
+ }
+
+ /* POS-DIGIT DIGIT */
+ return 2;
+}
+
+/** Return length of valid IP4 address */
+static
+int span_canonic_ip4_address(char const *host, int *return_canonize)
+{
+ int n, len, canonize = 0;
+
+ if (host == NULL)
+ return 0;
+
+ /* IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet */
+ len = span_ip4_octet(host);
+ if (len == 0 || host[len] != '.')
+ return 0;
+ if (len > 1 && host[0] == '0')
+ canonize = 1;
+ n = len + 1;
+
+ len = span_ip4_octet(host + n);
+ if (len == 0 || host[n + len] != '.')
+ return 0;
+ if (len > 1 && host[n] == '0')
+ canonize = 1;
+ n += len + 1;
+
+ len = span_ip4_octet(host + n);
+ if (len == 0 || host[n + len] != '.')
+ return 0;
+ if (len > 1 && host[n] == '0')
+ canonize = 1;
+ n += len + 1;
+
+ len = span_ip4_octet(host + n);
+ if (len == 0 || IS_DIGIT(host[n + len]) || host[n + len] == '.')
+ return 0;
+ if (len > 1 && host[n] == '0')
+ canonize = 1;
+ n += len;
+
+ if (canonize && return_canonize)
+ *return_canonize = 1;
+
+ return n;
+}
+
+/** Return length of valid IP4 address.
+ *
+ * Note that we accept here up to two leading zeroes
+ * which makes "dotted decimal" notation ambiguous:
+ * 127.000.000.001 is interpreted same as 127.0.0.1
+ *
+ * Note that traditionally IP address octets starting
+ * with zero have been interpreted as octal:
+ * 172.055.055.001 has been same as 172.45.45.1
+ *
+ * @b However, we interpret them as @b decimal,
+ * 172.055.055.001 is same as 172.55.55.1.
+ */
+int span_ip4_address(char const *host)
+{
+ return span_canonic_ip4_address(host, NULL);
+}
+
+/** Scan and canonize a valid IP4 address. */
+int scan_ip4_address(char **inout_host)
+{
+ char *src = *inout_host, *dst = src;
+ issize_t n;
+ int canonize = 0;
+
+ n = span_canonic_ip4_address(src, &canonize);
+ if (n == 0)
+ return -1;
+
+ *inout_host += n;
+
+ if (!canonize)
+ return n;
+
+ for (;;) {
+ char c = *dst++ = *src++;
+
+ if (IS_DIGIT(*src)) {
+ if (canonize && c == '0')
+ dst--;
+ else if (c == '.')
+ canonize = 1;
+ else
+ canonize = 0;
+ }
+ else if (*src != '.') {
+ break;
+ }
+ }
+ *dst = '\0';
+
+ return n;
+}
+
+/** Return length of hex4 */
+static inline int span_hex4(char const *host)
+{
+ if (!IS_HEX(host[0]))
+ return 0;
+ if (!IS_HEX(host[1]))
+ return 1;
+ if (!IS_HEX(host[2]))
+ return 2;
+ if (!IS_HEX(host[3]))
+ return 3;
+ return 4;
+}
+
+/** Return length of valid IP6 address */
+static inline
+int span_canonic_ip6_address(char const *host,
+ int *return_canonize,
+ char *hexparts[9])
+{
+ int n = 0, len, hex4, doublecolon = 0, canonize = 0;
+
+ /*
+ IPv6address = hexpart [ ":" IPv4address ]
+ hexpart = hexseq / hexseq "::" [ hexseq ] / "::" [ hexseq ]
+ hexseq = hex4 *( ":" hex4)
+ hex4 = 1*4HEXDIG
+
+ There is at most 8 hex4, 6 hex4 if IPv4address is included.
+ */
+
+ if (host == NULL)
+ return 0;
+
+ for (hex4 = 0; hex4 < 8; ) {
+ len = span_hex4(host + n);
+
+ if (return_canonize) {
+ if ((len > 1 && host[n + 1] == '0') || host[n] == '0')
+ canonize = 1;
+ if (hexparts)
+ hexparts[hex4 + doublecolon] = (char *)(host + n);
+ }
+
+ if (host[n + len] == ':') {
+ if (len != 0) {
+ hex4++;
+ n += len + 1;
+ if (!doublecolon && host[n] == ':') {
+ if (return_canonize && hexparts) {
+ hexparts[hex4] = (char *)(host + n - 1);
+ }
+ doublecolon++, n++;
+ }
+ }
+ else if (n == 0 && host[1] == ':') {
+ doublecolon++, n = 2;
+ }
+ else
+ break;
+ }
+ else if (host[n + len] == '.') {
+ len = span_canonic_ip4_address(host + n, return_canonize);
+
+ if (len == 0 || hex4 > 6 || !(doublecolon || hex4 == 6))
+ return 0;
+
+ if (canonize && return_canonize)
+ *return_canonize = 1;
+
+ return n + len;
+ }
+ else {
+ if (len != 0)
+ hex4++;
+ n += len;
+ break;
+ }
+ }
+
+ if (hex4 != 8 && !doublecolon)
+ return 0;
+
+ if (IS_HEX(host[n]) || host[n] == ':')
+ return 0;
+
+ if (canonize && return_canonize)
+ *return_canonize = canonize;
+
+ return n;
+}
+
+/** Canonize scanned IP6 address.
+ *
+ * @retval Length of canonized IP6 address.
+ */
+static inline
+int canonize_ip6_address(char *host, char *hexparts[9])
+{
+ char *dst, *hex, *ip4 = NULL;
+ int i, doublecolon, j, maxparts, maxspan, span, len;
+
+ char buf[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
+
+ /*
+ Canonic representation has fewest chars
+ - except for mapped/compatible IP4 addresses, like
+ ::15.21.117.42 or ::ffff:15.21.117.42 which have non-canonic forms of
+ ::f15:752a or ::ffff:f15:752a
+ => we just canonize hexparts and ip4part separately
+ and select optimal place for doublecolon
+ (with expection of ::1 and ::, which are canonized)
+ */
+ for (i = 0, doublecolon = -1; i < 9; i++) {
+ hex = hexparts[i];
+ if (!hex)
+ break;
+ if (hex[0] == ':')
+ doublecolon = i;
+ while (hex[0] == '0' && IS_HEX(hex[1]))
+ hex++;
+ hexparts[i] = hex;
+ }
+ assert(i > 0);
+
+ if (hexparts[i - 1][span_hex4(hexparts[i - 1])] == '.')
+ ip4 = hexparts[--i];
+
+ maxparts = ip4 ? 6 : 8;
+
+ if (doublecolon >= 0) {
+ /* Order at most 8 (or 6) hexparts */
+ assert(i <= maxparts + 1);
+
+ if (i == maxparts + 1) {
+ /* There is an extra doublecolon */
+ for (j = doublecolon; j <= i; j++)
+ hexparts[j] = hexparts[j + 1];
+ i--;
+ }
+ else {
+ for (j = maxparts; i > doublecolon + 1; )
+ hexparts[--j] = hexparts[--i];
+ for (;j > doublecolon;)
+ hexparts[--j] = "0:";
+ i = maxparts;
+ }
+ }
+ assert(i == maxparts);
+
+ /* Scan for optimal place for "::" */
+ for (i = 0, maxspan = 0, span = 0, doublecolon = 0; i < maxparts; i++) {
+ if (hexparts[i][0] == '0')
+ span++;
+ else if (span > maxspan)
+ doublecolon = i - span, maxspan = span, span = 0;
+ else
+ span = 0;
+ }
+
+ if (span > maxspan)
+ doublecolon = i - span, maxspan = span;
+
+ dst = buf;
+
+ for (i = 0; i < maxparts; i++) {
+ if (i == doublecolon)
+ hex = i == 0 ? "::" : ":", len = 1;
+ else if (i > doublecolon && i < doublecolon + maxspan)
+ continue;
+ else
+ hex = hexparts[i], len = span_hex4(hex);
+ if (hex[len] == ':')
+ len++;
+ memcpy(dst, hex, len);
+ dst += len;
+ }
+
+ if (ip4) {
+ hex = ip4;
+ len = scan_ip4_address(&hex); assert(len > 0);
+
+ /* Canonize :: and ::1 */
+ if (doublecolon == 0 && maxspan == 6) {
+ if (len == 7 && strncmp(ip4, "0.0.0.0", len) == 0)
+ ip4 = "", len = 0;
+ else if (len == 7 && strncmp(ip4, "0.0.0.1", len) == 0)
+ ip4 = "1", len = 1;
+ }
+
+ memcpy(dst, ip4, len);
+ dst += len;
+ }
+
+ len = dst - buf;
+
+ memcpy(host, buf, len);
+
+ return len;
+}
+
+/** Return length of valid IP6 address */
+int span_ip6_address(char const *host)
+{
+ return span_canonic_ip6_address(host, NULL, NULL);
+}
+
+/** Scan and canonize valid IP6 address.
+ *
+ * @param inout_host input pointer to string to scan
+ * output pointer to first character after valid IP6 address
+ *
+ * @retval Length of valid IP6 address or -1 upon an error.
+ *
+ * @note Scanned IP6 is not always NUL-terminated.
+ */
+int scan_ip6_address(char **inout_host)
+{
+ int n, canonize = 0;
+ char *host = *inout_host;
+ char *hexparts[9] = { NULL };
+
+ n = span_canonic_ip6_address(host, &canonize, hexparts);
+
+ if (n == 0)
+ return -1;
+
+ *inout_host += n;
+
+ if (canonize) {
+ int len = canonize_ip6_address(host, hexparts);
+ assert(len <= n);
+ if (len < n)
+ host[len] = '\0';
+ }
+
+ return n;
+}
+
+/** Return length of valid IP6 reference. */
+int span_ip6_reference(char const *host)
+{
+ /* IPv6reference = "[" IPv6address "]" */
+
+ if (host && host[0] == '[') {
+ int n = span_ip6_address(host + 1);
+ if (n > 0 && host[n + 1] == ']')
+ return n + 2;
+ }
+
+ return 0;
+}
+
+/** Scan valid IP6 reference. */
+int scan_ip6_reference(char **inout_host)
+{
+ int n, canonize = 0;
+ char *host = *inout_host;
+ char *hexparts[9] = { NULL };
+
+ /* IPv6reference = "[" IPv6address "]" */
+
+ if (host == NULL ||
+ host[0] != '[' ||
+ (n = span_canonic_ip6_address(host + 1, &canonize, hexparts)) == 0 ||
+ host[n + 1] != ']')
+ return -1;
+
+ *inout_host += n + 2;
+
+ if (canonize) {
+ int len = canonize_ip6_address(host + 1, hexparts);
+
+ assert(len <= n);
+
+ host[len + 1] = ']';
+ if (len + 2 < n + 2)
+ host[len + 2] = '\0';
+ }
+
+ return n + 2;
+}
+
+/** Return length of valid IP4 or IP6 address. */
+int span_ip_address(char const *host)
+{
+ if (!host || !host[0])
+ return 0;
+
+ /* IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet */
+ if (IS_DIGIT(host[0])) {
+ int n = span_ip4_address(host);
+ if (n)
+ return n;
+ }
+
+ if (host[0] == '[')
+ return span_ip6_reference(host);
+ else
+ return span_ip6_address(host);
+}
+
+/** Scan valid IP4/IP6 address. */
+int scan_ip_address(char **inout_host)
+{
+ char *host = *inout_host;
+
+ if (host == NULL)
+ return -1;
+
+ /* IPv6reference = "[" IPv6address "]" */
+ if (host[0] == '[')
+ return scan_ip6_reference(inout_host);
+
+ if (IS_DIGIT(host[0])) {
+ int n = scan_ip4_address(inout_host);
+ if (n > 0)
+ return n;
+ }
+
+ return scan_ip6_address(inout_host);
+}
+
+/** Return length of a valid domain label */
+static inline
+size_t span_domain_label(char const *label)
+{
+ /* domainlabel = alphanum / alphanum *( alphanum / "-" ) alphanum */
+ if (IS_ALPHANUM(*label)) {
+ size_t n;
+ for (n = 1; IS_ALPHANUM(label[n]) || label[n] == '-'; n++)
+ ;
+ if (IS_ALPHANUM(label[n - 1]))
+ return n;
+ }
+
+ return 0;
+}
+
+/** Scan valid domain name and count number of labels in it. */
+static inline
+size_t span_domain_labels(char const *host, size_t *return_labels)
+{
+ size_t len, n, labels;
+ int c;
+
+ if (!host || !host[0])
+ return 0;
+
+ for (n = 0, labels = 0; ; n += len) {
+ len = span_domain_label(host + n);
+ if (len == 0)
+ return 0;
+
+ labels++;
+
+ if (host[n + len] != '.')
+ break;
+ len++;
+ if (!IS_ALPHANUM(host[n + len]))
+ break;
+ }
+
+ /* Check that last label does not start with number */
+ if (!IS_ALPHA(host[n]))
+ return 0;
+
+ c = host[n + len];
+ if (IS_ALPHANUM(c) || c == '-' || c == '.')
+ return 0;
+
+ if (return_labels)
+ *return_labels = labels;
+
+ return n + len;
+}
+
+/** Return length of a valid domain name.
+ *
+ * @code
+ * hostname = *( domainlabel "." ) toplabel [ "." ]
+ * domainlabel = alphanum
+ * / alphanum *( alphanum / "-" ) alphanum
+ * toplabel = ALPHA / ALPHA *( alphanum / "-" ) alphanum
+ * @endcode
+ */
+isize_t span_domain(char const *host)
+{
+ return span_domain_labels(host, NULL);
+}
+
+/** Scan valid domain name. */
+issize_t scan_domain(char **inout_host)
+{
+ char *host;
+ size_t n, labels;
+
+ n = span_domain_labels(host = *inout_host, &labels);
+ if (n == 0)
+ return -1;
+
+ /* Remove extra dot at the end of hostname */
+ if (labels > 1 && host[n - 1] == '.')
+ host[n - 1] = '\0';
+
+ *inout_host += n;
+
+ return n;
+}
+
+/** Return length of a valid domain name or IP address. */
+isize_t span_host(char const *host)
+{
+ if (!host || !host[0])
+ return 0;
+
+ if (host[0] == '[')
+ return span_ip6_reference(host);
+
+ if (IS_DIGIT(host[0])) {
+ int n = span_ip4_address(host);
+ if (n)
+ return (isize_t)n;
+ }
+
+ return span_domain(host);
+}
+
+/** Scan valid domain name or IP address. */
+issize_t scan_host(char **inout_host)
+{
+ char *host = *inout_host;
+
+ if (host == NULL)
+ return -1;
+
+ /* IPv6reference = "[" IPv6address "]" */
+ if (host[0] == '[')
+ return scan_ip6_reference(inout_host);
+
+ if (IS_DIGIT(host[0])) {
+ int n = scan_ip4_address(inout_host);
+ if (n > 0)
+ return (issize_t)n;
+ }
+
+ return scan_domain(inout_host);
+}
+
+#include <sofia-sip/hostdomain.h>
+
+/** Return true if @a string is valid IP4 address in dot-notation.
+ *
+ * @note Only 4-octet form is accepted, e.g., @c 127.1 is not considered
+ * valid IP4 address.
+ */
+int host_is_ip4_address(char const *string)
+{
+ int n = span_ip4_address(string);
+ return n > 0 && string[n] == '\0';
+}
+
+/** Return true if @a string is valid IP6 address in hex notation.
+ *
+ * E.g., fe80::1 is a valid IP6 address.
+ */
+int host_is_ip6_address(char const *string)
+{
+ int n = span_ip6_address(string);
+ return n > 0 && string[n] == '\0';
+}
+
+int host_ip6_reference(char const *string)
+{
+ return host_is_ip6_reference(string);
+}
+
+/** Return true if @a string is valid IP6 reference,
+ * i.e. hex notation in square brackets.
+ *
+ * E.g., [::1] is a valid IP6 reference.
+ */
+int host_is_ip6_reference(char const *string)
+{
+ int n = span_ip6_reference(string);
+ return n > 0 && string[n] == '\0';
+}
+
+/** Return true if @a string is valid IP address.
+ *
+ * Valid IP address is either a IP4 adddress in quad-octet notation,
+ * IP6 hex address or IP6 reference in square brackets ([]).
+ */
+int host_is_ip_address(char const *string)
+{
+ int n = span_ip_address(string);
+ return n > 0 && string[n] == '\0';
+}
+
+/** Return true if @a string is valid a domain name.
+ *
+ * Valid domain name consists of alphanumeric labels separated with
+ * dot ("."). There can be a "-" in the middle of label.
+ * The last label must start with a letter.
+ *
+ * @code
+ * hostname = *( domainlabel "." ) toplabel [ "." ]
+ * domainlabel = alphanum
+ * / alphanum *( alphanum / "-" ) alphanum
+ * toplabel = ALPHA / ALPHA *( alphanum / "-" ) alphanum
+ * @endcode
+ */
+int host_is_domain(char const *string)
+{
+ size_t n = string ? span_domain(string) : 0;
+ return string && n > 0 && string[n] == '\0';
+}
+
+/** Return true if @a string is valid a host name.
+ *
+ * Check if the @a string is a domain name, IP address or IP6 reference.
+ */
+int host_is_valid(char const *string)
+{
+ size_t n = span_host(string);
+ return n > 0 && string[n] == '\0';
+}
+
+/** Returns true if @a string is describing a local address.
+ *
+ * Uses the definitions of local addresses found in RFC1700 and
+ * RFC4291.
+ */
+int host_is_local(char const *host)
+{
+ size_t n;
+
+ if (host_is_ip6_reference(host))
+ return (strcmp(host, "[::1]") == 0);
+ else if (host_is_ip6_address(host))
+ return (strcmp(host, "::1") == 0);
+ else if (host_is_ip4_address(host))
+ return (strncmp(host, "127.", 4) == 0);
+
+ n = span_domain(host);
+
+ return
+ n >= 9 /* strlen("localhost") */ &&
+ strncasecmp(host, "localhost", 9) == 0 &&
+ (n == 9 ||
+ ((n == 10 || /* localhost. */
+ n == 21 || /* strlen("localhost.localdomain") */
+ n == 22) && /* strlen("localhost.localdomain.") */
+ strncasecmp(host + 9, ".localdomain.", n - 9) == 0));
+}
+
+/** Return true if @a string has domain name in "invalid." domain.
+ *
+ */
+int host_has_domain_invalid(char const *string)
+{
+ size_t n = span_domain(string);
+
+ if (n >= 7 && string[n] == '\0') {
+ static char const invalid[] = ".invalid";
+ if (string[n - 1] == '.') /* .invalid. perhaps? */
+ n--;
+ if (n == 7 /* strlen("invalid") */)
+ return strncasecmp(string, invalid + 1, 7) == 0;
+ else
+ return strncasecmp(string + n - 8, invalid, 8) == 0;
+ }
+
+ return 0;
+}
+
+#include <sofia-sip/su.h>
+
+static size_t convert_ip_address(char const *s,
+ uint8_t addr[16],
+ size_t *return_addrlen)
+{
+ size_t len;
+ int canonize = 0;
+
+#if SU_HAVE_IN6
+ char buf[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
+
+ len = span_ip6_reference(s);
+ if (len) {
+ assert(len - 2 < sizeof buf); assert(len > 2);
+
+ if (s[len])
+ return 0;
+
+ len = len - 2;
+ s = memcpy(buf, s + 1, len), buf[len] = '\0';
+ }
+ else
+ len = span_ip6_address(s);
+
+ if (len) {
+ if (s[len] == '\0' && inet_pton(AF_INET6, s, addr) == 1) {
+ if (SU_IN6_IS_ADDR_V4MAPPED(addr) ||
+ SU_IN6_IS_ADDR_V4COMPAT(addr)) {
+ memcpy(addr, addr + 12, 4);
+ return (void)(*return_addrlen = 4), len;
+ }
+ return (void)(*return_addrlen = 16), len;
+ }
+ else
+ return 0;
+ }
+#endif
+
+ len = span_canonic_ip4_address(s, &canonize);
+ if (len) {
+ if (canonize) {
+ char *tmp = buf;
+ s = memcpy(tmp, s, len + 1);
+ scan_ip4_address(&tmp);
+ }
+ if (s[len] == '\0' && inet_pton(AF_INET, s, addr) == 1)
+ return (void)(*return_addrlen = 4), len;
+ else
+ return 0;
+ }
+
+ return 0;
+}
+
+/** Compare two host names or IP addresses
+ *
+ * Converts valid IP addresses to the binary format before comparing them.
+ * Note that IP6-mapped IP4 addresses and IP6-compatible IP4 addresses are
+ * compared as IP4 addresses; that is, ::ffff:127.0.0.1, ::127.0.0.1 and
+ * 127.0.0.1 all are all equal.
+ *
+ * @param a IP address or domain name
+ * @param b IP address or domain name
+ *
+ * @retval -1 if a < b
+ * @retval 0 if a == b
+ * @retval 1 if a > b
+ *
+ * @since New in @VERSION_1_12_4.
+ */
+int host_cmp(char const *a, char const *b)
+{
+ uint8_t a6[16], b6[16];
+ size_t alen, blen, asize = 0, bsize = 0;
+
+ if (a == NULL || b == NULL)
+ return (a != NULL) - (b != NULL);
+
+ alen = convert_ip_address(a, a6, &asize);
+ blen = convert_ip_address(b, b6, &bsize);
+
+ if (alen > 0 && blen > 0) {
+ if (asize < bsize)
+ return -1;
+ else if (asize > bsize)
+ return 1;
+ else
+ return memcmp(a6, b6, asize);
+ }
+ else {
+ return strcasecmp(a, b);
+ }
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/bnf.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/bnf.docs Thu Dec 21 01:30:28 2006
@@ -0,0 +1,17 @@
+/* -*- C -*- */
+
+/**@MODULEPAGE "bnf" - String Parser Module
+ *
+ * @section bnf_meta Module Meta Information
+ *
+ * The Sofia @b bnf module contains macros and functions for parsing
+ * text-based formats, for example, for SIP. The interface is described in
+ * <bnf.h>, the <bnf.c> contains a #_bnf_table table used to classify
+ * characters.
+ *
+ * @CONTACT Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @STATUS @SofiaSIP Core library
+ *
+ * @LICENSE LGPL
+ */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/sofia-sip/bnf.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/sofia-sip/bnf.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,330 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef BNF_H /** Defined when <sofia-sip/bnf.h> has been included. */
+#define BNF_H
+
+/**@file sofia-sip/bnf.h
+ *
+ * Parsing macros and prototypes for HTTP-like protocols.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Jun 06 10:59:34 2000 ppessi
+ *
+ */
+
+#include <sofia-sip/su_types.h>
+
+#include <string.h>
+
+SOFIA_BEGIN_DECLS
+
+/* Parsing tokens */
+/** Control characters. */
+#define CTL "\001\002\003\004\005\006\007" \
+ "\010\011\012\013\014\015\016\017" \
+ "\020\021\022\023\024\025\026\027" \
+ "\030\031\032\033\034\035\036\037" "\177" "\0"
+/** Space */
+#define SP " "
+/** Horizontal tab */
+#define HT "\t"
+/** Carriage return */
+#define CR "\r"
+/** Line feed */
+#define LF "\n"
+/** Line-ending characters */
+#define CRLF CR LF
+/** Whitespace */
+#define WS SP HT
+/** Linear whitespace */
+#define LWS SP HT CR LF
+/** Lower-case alphabetic characters */
+#define LOALPHA "abcdefghijklmnopqrstuvwxyz"
+/** Upper-case alphabetic characters */
+#define UPALPHA "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+/** Alphabetic characters */
+#define ALPHA LOALPHA UPALPHA
+/** Digits */
+#define DIGIT "0123456789"
+/** RTSP safe characters */
+#define SAFE "$-_." /* RTSP stuff */
+#define ALPHANUM DIGIT ALPHA
+#define HEX DIGIT "ABCDEF" "abcdef"
+
+/** SIP token characters.
+ * @note $|&^# were token chars in RFC 2543, but no more in RFC 3261.
+ */
+#define SIP_TOKEN ALPHANUM "-.!%*_+`'~"
+/** SIP separator characters */
+#define SIP_SEPARATOR "()<>@,;:\\\"/[]?={}" SP HT
+
+/** SIP Word characters (that are not token characters) */
+#define SIP_WORD "()<>:\\\"/[]?{}"
+
+/** Skip whitespace (SP HT) */
+#define skip_ws(ss) (*(ss) += span_ws(*(ss)))
+
+/** Skip linear whitespace (SP HT CR LF) */
+#define skip_lws(ss) (*(ss) += span_lws(*(ss)))
+
+/** Skip [a-zA-Z] */
+#define skip_alpha(ss) (*(ss) += span_alpha(*(ss)))
+
+/** Skip digits */
+#define skip_digit(ss) (*(ss) += span_digit(*(ss)))
+
+/** Skip characters belonging to an RTSP token. */
+#define skip_alpha_digit_safe(ss) (*(ss) += span_alpha_digit_safe(*(ss)))
+
+/** Skip characters belonging to a SIP token. */
+#define skip_token(ss) (*(ss) += span_token(*(ss)))
+
+/** Skip characters belonging to a SIP parameter value. */
+#define skip_param(ss) (*(ss) += span_param(*(ss)))
+
+/** Skip characters belonging to a SIP word. */
+#define skip_word(ss) (*(ss) += span_word(*(ss)))
+
+/** Test if @c is CR or LF */
+#define IS_CRLF(c) ((c) == '\r' || (c) == '\n')
+/** Test if @c is linear whitespace */
+#define IS_LWS(c) ((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == '\n')
+/*#define IS_LWS(c) ((_bnf_table[(unsigned char)(c)] & bnf_lws))*/
+/** Test if @c is normal whitespace */
+#define IS_WS(c) ((c) == ' ' || (c) == '\t')
+/** Test if @c is not whitespace (and not NUL). */
+#define IS_NON_WS(c) (c && !IS_WS(c))
+/*#define IS_NON_WS(c) (c && !(_bnf_table[(unsigned char)c] & bnf_ws))*/
+/** Test if @c is not linear whitespace (and not NUL). */
+#define IS_NON_LWS(c) (c && !IS_LWS(c))
+/*#define IS_NON_LWS(c) (c && !(_bnf_table[(unsigned char)c] & bnf_lws))*/
+/** Test if @c is a digit. */
+#define IS_DIGIT(c) ((c) >= '0' && (c) <= '9')
+/** Test if @c is alphabetic. */
+#define IS_ALPHA(c) (c && ((_bnf_table[(unsigned char)c] & bnf_alpha)))
+/** Test if @c is alphanumeric. */
+#define IS_ALPHANUM(c) (c && (IS_DIGIT(c) || IS_ALPHA(c)))
+/** Test if @c is URL-unreserved. */
+#define IS_UNRESERVED(c) ((_bnf_table[(unsigned char)c] & bnf_unreserved))
+/** Test if @c is URL-reserved. */
+#define IS_RESERVED(c) (c && !(_bnf_table[(unsigned char)c] & bnf_unreserved))
+/** Test if @c is valid in tokens. */
+#define IS_TOKEN(c) ((_bnf_table[(unsigned char)c] & bnf_token))
+/** Test if @c is valid for SIP parameter value. */
+#define IS_PARAM(c) ((_bnf_table[(unsigned char)c] & (bnf_token|bnf_param)))
+/** Test if @c is a hex digit. */
+#define IS_HEX(c) (((c) >= '0' && (c) <= '9') || ((c) >= 'A' && (c) <= 'F') || ((c) >= 'a' && (c) <= 'f'))
+/** Test if @c is a linear whitespace or valid in tokens. */
+#define IS_TOKENLWS(c) ((_bnf_table[(unsigned char)c] & (bnf_token|bn_lws)))
+
+enum {
+ bnf_ws = 1, /**< Whitespace character */
+ bnf_crlf = 2, /**< Line end character */
+ bnf_lws = 3, /**< Linear whitespace */
+ bnf_alpha = 4, /**< Alphabetic */
+ bnf_safe = 8, /**< RTSP safe */
+ bnf_mark = 16, /**< URL mark */
+ bnf_unreserved = bnf_alpha | bnf_mark, /**< URL unreserved */
+ bnf_separator = 32, /**< SIP separator */
+ /** SIP token, not alphabetic (0123456789-.!%*_+`'~) */
+ bnf_token0 = 64 | bnf_safe,
+ bnf_token = bnf_token0 | bnf_alpha, /**< SIP token */
+ bnf_param0 = 128, /**< SIP parameter, not token */
+ bnf_param = bnf_token | bnf_param0 /**< SIP/HTTP parameter */
+};
+
+/** Table for determining class of a character. */
+SOFIAPUBVAR unsigned char const _bnf_table[256];
+
+/** Get number of characters before CRLF */
+#define span_non_crlf(s) strcspn(s, CR LF)
+
+/** Get number of characters before whitespace */
+#define span_non_ws(s) strcspn(s, WS)
+
+/** Get number of whitespace characters */
+#define span_ws(s) strspn(s, WS)
+
+/** Get number of characters before linear whitespace */
+#define span_non_lws(s) strcspn(s, LWS)
+
+/** Calculate span of a linear whitespace.
+ * LWS = [*WSP CRLF] 1*WSP
+ */
+static inline isize_t span_lws(char const *s)
+{
+ char const *e = s;
+ int i = 0;
+ e += strspn(s, WS);
+ if (e[i] == '\r') i++;
+ if (e[i] == '\n') i++;
+ if (IS_WS(e[i]))
+ e += i + strspn(e + i, WS);
+ return e - s;
+}
+
+/** Calculate span of a token or linear whitespace characters. */
+static inline isize_t span_token_lws(char const *s)
+{
+ char const *e = s;
+ while (_bnf_table[(unsigned char)(*e)] & (bnf_token | bnf_lws))
+ e++;
+ return e - s;
+}
+
+#if 1
+/** Calculate span of a token characters. */
+static inline isize_t span_token(char const *s)
+{
+ char const *e = s;
+ while (_bnf_table[(unsigned char)(*e)] & bnf_token)
+ e++;
+ return e - s;
+}
+#else
+size_t bnf_span_token(char const *s);
+#define span_token(s) bnf_span_token((s))
+#endif
+
+
+/** Calculate span of a alphabetic characters. */
+static inline isize_t span_alpha(char const *s)
+{
+ char const *e = s;
+ while (_bnf_table[(unsigned char)(*e)] & bnf_alpha)
+ e++;
+ return e - s;
+}
+
+/** Calculate span of a digits. */
+static inline isize_t span_digit(char const *s)
+{
+ char const *e = s;
+ while (*e >= '0' && *e <= '9')
+ e++;
+ return e - s;
+}
+
+/** Calculate span of a hex. */
+static inline isize_t span_hexdigit(char const *s)
+{
+ char const *e = s;
+ while (IS_HEX(*e))
+ e++;
+ return e - s;
+}
+
+/** Calculate span of characters belonging to an RTSP token */
+static inline isize_t span_alpha_digit_safe(char const *s)
+{
+ char const *e = s;
+ while (_bnf_table[(unsigned char)(*e)] & (bnf_alpha | bnf_safe))
+ e++;
+ return e - s;
+}
+
+/** Calculate span of a characters valid in parameters. */
+static inline isize_t span_param(char const *s)
+{
+ char const *e = s;
+ while (IS_PARAM(*e))
+ e++;
+ return e - s;
+}
+
+/** Calculate span of a SIP word. */
+static inline isize_t span_word(char const *s)
+{
+ char const *e = s;
+ while (*e && (IS_TOKEN(*e) || strchr(SIP_WORD, *e)))
+ e++;
+ return e - s;
+}
+
+/** Calculate span of a unreserved characters. */
+static inline isize_t span_unreserved(char const *s)
+{
+ char const *e = s;
+ while (IS_UNRESERVED(*e))
+ e++;
+ return e - s;
+}
+
+/** Calculate span of a double quoted string (with escaped chars inside) */
+static inline isize_t span_quoted(char const *s)
+{
+ char const *b = s;
+
+ if (*s++ != '"')
+ return 0;
+
+ for (;;) {
+ s += strcspn(s, "\\\"");
+ if (!*s)
+ return 0;
+ if (*s++ == '"')
+ return s - b;
+ if (!*s++)
+ return 0;
+ }
+}
+
+/* RFC 2396 defines URL chars */
+/** Reserved in URLs */
+#define URL_RESERVED ";/?:=+$,"
+
+/** Non-alphanumeric characters without syntactical meaning. */
+#define URL_MARK "-_.!~*'()"
+
+/** Unreserved characters. */
+#define URL_UNRESERVED ALPHANUM URL_MARK
+
+/** URL hex escape. */
+#define URL_ESCAPED "%"
+#define URL_DELIMS "<>#%\""
+#define URL_UNWISE "{}|\\^[]`"
+#define URL_SCHEME ALPHANUM "+-."
+
+/** Get number of characters belonging to url scheme */
+#define span_url_scheme(s) strspn(s, URL_SCHEME)
+
+SOFIAPUBFUN int span_ip4_address(char const *host);
+SOFIAPUBFUN int span_ip6_address(char const *host);
+SOFIAPUBFUN int span_ip6_reference(char const *host);
+SOFIAPUBFUN int span_ip_address(char const *host);
+SOFIAPUBFUN isize_t span_domain(char const *host);
+SOFIAPUBFUN isize_t span_host(char const *host);
+
+SOFIAPUBFUN int scan_ip4_address(char **inout_host);
+SOFIAPUBFUN int scan_ip6_address(char **inout_host);
+SOFIAPUBFUN int scan_ip6_reference(char **inout_host);
+SOFIAPUBFUN int scan_ip_address(char **inout_host);
+SOFIAPUBFUN issize_t scan_domain(char **inout_host);
+SOFIAPUBFUN issize_t scan_host(char **inout_host);
+
+SOFIA_END_DECLS
+
+#endif /* !defined BNF_H */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/sofia-sip/hostdomain.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/sofia-sip/hostdomain.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,60 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SOFIA_SIP_HOSTDOMAIN_H
+/** Defined when <sofia-sip/hostdomain.h> has been included. */
+#define SOFIA_SIP_HOSTDOMAIN_H
+
+/**@file sofia-sip/hostdomain.h
+ *
+ * Predicates for handling host names: IP addresses or domain names.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Mar 9 16:15:22 EET 2006 ppessi
+ */
+
+#ifndef SU_CONFIG_H
+#include <sofia-sip/su_config.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+SOFIAPUBFUN int host_is_ip4_address(char const *string);
+SOFIAPUBFUN int host_is_ip6_address(char const *string);
+SOFIAPUBFUN int host_is_ip6_reference(char const *string);
+SOFIAPUBFUN int host_is_ip_address(char const *string);
+SOFIAPUBFUN int host_is_domain(char const *string);
+SOFIAPUBFUN int host_is_valid(char const *string);
+SOFIAPUBFUN int host_is_local(char const *string);
+SOFIAPUBFUN int host_has_domain_invalid(char const *string);
+SOFIAPUBFUN int host_cmp(char const *a, char const *b);
+
+/** This is typo. @deprecated Use host_is_ip6_reference() instead. */
+SOFIAPUBFUN int host_ip6_reference(char const *string);
+
+
+SOFIA_END_DECLS
+
+#endif /* !defined(SOFIA_SIP_HOSTDOMAIN_H) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/torture_bnf.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/bnf/torture_bnf.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,366 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE torture_bnf.c
+ *
+ * Torture tests for BNF functions.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Aug 21 15:18:26 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include "sofia-sip/bnf.h"
+
+static int test_flags = 0;
+#define TSTFLAGS test_flags
+
+#include <sofia-sip/tstdef.h>
+
+char const name[] = "torture_bnf";
+
+int count_bnf(int bnf_flags)
+{
+ int i, n;
+
+ for (i = 0, n = 0; i < 128; i++)
+ if (_bnf_table[i] & bnf_flags)
+ n++;
+
+ return n;
+}
+
+int bnf_test(void)
+{
+ BEGIN();
+ TEST_1(IS_TOKEN('a'));
+ TEST_1(IS_TOKEN('b'));
+ /* Fixed for 1.12.2: lws = [*wsp crlf] 1*wsp */
+ TEST_SIZE(span_lws(" \r\n \r\nLoppuu"), 5);
+ TEST_SIZE(span_lws(" \r\r \nLoppuu"), 2);
+ TEST_SIZE(span_lws(" \n\r \nLoppuu"), 2);
+ TEST_SIZE(span_lws(" \r \nLoppuu"), 4);
+ TEST_SIZE(span_lws(" \n\t \nLoppuu"), 5);
+ TEST_SIZE(span_lws(" \r\n\t \nLoppuu"), 6);
+ TEST_SIZE(span_token(SIP_TOKEN), strlen(SIP_TOKEN));
+ TEST_SIZE(count_bnf(bnf_token), strlen(SIP_TOKEN "$"));
+ #define SIP_PARAM SIP_TOKEN "[:]/"
+ TEST_SIZE(span_param(SIP_PARAM), strlen(SIP_PARAM));
+ TEST_SIZE(count_bnf(bnf_param), strlen(SIP_PARAM "$"));
+
+ TEST_SIZE(span_unreserved(URL_UNRESERVED URL_ESCAPED),
+ strlen(URL_UNRESERVED URL_ESCAPED));
+
+ TEST_SIZE(count_bnf(bnf_unreserved),
+ strlen(URL_UNRESERVED URL_ESCAPED));
+
+ {
+ char word[] = ALPHA DIGIT "-.!%*_+`'~()<>:\\\"/[]?{}";
+ TEST_SIZE(span_word(word), strlen(word));
+ }
+
+ END();
+}
+
+int ip_test(void)
+{
+ BEGIN();
+ char *s;
+
+ TEST(span_ip4_address("127.255.249.000,"), 15);
+ TEST(span_ip4_address("0.00.000.000:,"), 12);
+
+ /* Test error detection */
+ TEST(span_ip4_address("256.00.000.000:,"), 0);
+ TEST(span_ip4_address("255.00.000.0000,"), 0);
+ TEST(span_ip4_address("255.00.000.199."), 0);
+
+ {
+ char ip0[] = "010.250.020.000,";
+ char ip1[] = "0.00.000.000:,";
+ char ip2[] = "256.00.000.000:,";
+ char ip3[] = "255.00.000.0000,";
+ char ip4[] = "255.00.000.199.";
+
+ s = ip0;
+ TEST(scan_ip4_address(&s), 15); TEST_S(s, ","); TEST_S(ip0, "10.250.20.0");
+
+ s = ip1;
+ TEST(scan_ip4_address(&s), 12); TEST_S(s, ":,"); TEST_S(ip1, "0.0.0.0");
+
+ /* Test error detection */
+ s = ip2; TEST(scan_ip4_address(&s), -1);
+ s = ip3; TEST(scan_ip4_address(&s), -1);
+ s = ip4; TEST(scan_ip4_address(&s), -1);
+ }
+
+ TEST(span_ip6_address("dead:beef:feed:ded:0:1:2:3"), 26);
+ TEST(span_ip6_address("::beef:feed:ded:0:1:2:3"), 23);
+ TEST(span_ip6_address("::255.0.0.0,"), 11);
+ TEST(span_ip6_address("::,"), 2);
+
+ TEST(span_ip_address("[dead:beef:feed:ded:0:1:2:3]"), 28);
+ TEST(span_ip_address("::255.0.0.0,"), 11);
+ TEST(span_ip_address("[::255.0.0.0]:"), 13);
+
+ TEST(span_ip6_address("dead:beef:feed::0ded:0:1:2:3"), 28);
+ TEST(span_ip6_address("dead:beef:feed::0ded:0000:0001:0002:0003"), 40);
+
+ TEST(span_ip6_address("dead:beef:feed::0ded::0000:0001:0002:0003"), 0);
+ TEST(span_ip6_address("::dead:beef:feed::0ded:0000:0001:0002:0003"), 0);
+ TEST(span_ip6_address("dead:beef:feed:ded:0:1:2:3:4"), 0);
+ TEST(span_ip6_address("dead:beef:feed:00ded:0:1:2:3"), 0);
+ TEST(span_ip6_address("dead:beef:feed:ded:0:1:2:127.0.0.1"), 0);
+ TEST(span_ip6_address(":255.0.0.0,"), 0);
+ TEST(span_ip6_address("255.0.0.0,"), 0);
+
+ /* Accept colon after IP4-quad */
+ TEST(span_ip_address("::255.0.0.0:5060"), 11);
+
+ /* This is a reference */
+ TEST(span_ip6_address("[dead:beef:feed:ded:0:1:2:3]"), 0);
+ TEST(span_ip6_reference("[dead:beef:feed:ded:0:1:2:3]:1"), 28);
+ TEST(span_ip_address("[dead:beef:feed:ded:0:1:2:3]:1"), 28);
+ TEST(span_ip_address("[127.0.0.1]:1"), 0);
+
+ {
+ char ip0[] = "dead:beef:feed:ded:0:1:2:3,";
+ char ip1[] = "::beef:feed:ded:0:1:2:3;";
+ char ip1b[] = "::beef:feed:ded:0:0:2:3;";
+ char ip2[] = "::255.00.0.0,";
+ char ip3[] = "::,";
+ char ip4[] = "0:0:0:0:0:0:0:0,";
+ char ip4b[] = "0:0:0:0:0:0:0.0.0.0,";
+ char ip4c[] = "0:0:0:0:0:0:0.0.0.1,";
+ char ip5[] = "dead:beef:feed::0ded:0:1:2:3";
+ char ip6[] = "dead:beef:feed::0ded:0000:0001:0002:0003+";
+ char ip7[] = "1:0:0:2:0:0:0:3,";
+ char ip8[] = "1:0:0:2:0:0:3:4,";
+ char ip9[] = "1::2:0:0:0:3,";
+
+ s = ip0; TEST(scan_ip6_address(&s), 26); TEST_S(s, ",");
+ TEST_S(ip0, "dead:beef:feed:ded::1:2:3");
+ s = ip1; TEST(scan_ip6_address(&s), 23); TEST_S(s, ";");
+ TEST_S(ip1, "::beef:feed:ded:0:1:2:3;");
+ s = ip1b; TEST(scan_ip6_address(&s), 23); TEST_S(s, ";");
+ TEST_S(ip1b, "0:beef:feed:ded::2:3");
+ s = ip2; TEST(scan_ip6_address(&s), 12); TEST_S(s, ",");
+ TEST_S(ip2, "::255.0.0.0");
+ s = ip3; TEST(scan_ip6_address(&s), 2); TEST_S(s, ",");
+ TEST_S(ip3, "::,");
+ s = ip4; TEST(scan_ip6_address(&s), 15); TEST_S(s, ",");
+ TEST_S(ip4, "::");
+ s = ip4b; TEST(scan_ip6_address(&s), 19); TEST_S(s, ",");
+ TEST_S(ip4b, "::");
+ s = ip4c; TEST(scan_ip6_address(&s), 19); TEST_S(s, ",");
+ TEST_S(ip4c, "::1");
+ TEST_S(ip5, "dead:beef:feed::0ded:0:1:2:3");
+ s = ip5; TEST(scan_ip6_address(&s), 28); TEST_S(s, "");
+ TEST_S(ip5, "dead:beef:feed:ded::1:2:3");
+ s = ip6; TEST(scan_ip6_address(&s), 40); TEST_S(s, "+");
+ TEST_S(ip6, "dead:beef:feed:ded::1:2:3");
+ s = ip7; TEST(scan_ip6_address(&s), 15); TEST_S(s, ",");
+ TEST_S(ip7, "1:0:0:2::3");
+ s = ip8; TEST(scan_ip6_address(&s), 15); TEST_S(s, ",");
+ TEST_S(ip8, "1::2:0:0:3:4");
+ s = ip9; TEST(scan_ip6_address(&s), 12); TEST_S(s, ",");
+ TEST_S(ip9, "1:0:0:2::3");
+ }
+
+ {
+ char err0[] = "dead:beef:feed::0ded::0000:0001:0002:0003";
+ char err1[] = "::dead:beef:feed::0ded:0000:0001:0002:0003";
+ char err2[] = "dead:beef:feed:ded:0:1:2:3:4";
+ char err3[] = "dead:beef:feed:00ded:0:1:2:3";
+ char err4[] = "dead:beef:feed:ded:0:1:2:127.0.0.1";
+ char err5[] = ":255.0.0.0,";
+ char err6[] = "255.0.0.0,";
+ char err7[] = "dead:beef:feed:ded:0:1:2:3:4:5,";
+
+ TEST(scan_ip6_address((s = err0, &s)), -1);
+ TEST(scan_ip6_address((s = err1, &s)), -1);
+ TEST(scan_ip6_address((s = err2, &s)), -1);
+ TEST(scan_ip6_address((s = err3, &s)), -1);
+ TEST(scan_ip6_address((s = err4, &s)), -1);
+ TEST(scan_ip6_address((s = err5, &s)), -1);
+ TEST(scan_ip6_address((s = err6, &s)), -1);
+ TEST(scan_ip6_address((s = err7, &s)), -1);
+ }
+
+ {
+ char err0[] = "[dead:beef:feed::0ded::0000:0001:0002:0003]:";
+ char err1[] = "[::dead:beef:feed::0ded:0000:0001:0002:0003]+";
+ char err2[] = "[dead:beef:feed:ded:0:1:2:3:4]+";
+ char err3[] = "[dead:beef:feed:00ded:0:1:2:3]+";
+ char err4[] = "[dead:beef:feed:ded:0:1:2:127.0.0.1]";
+ char err5[] = "[:255.0.0.0],";
+ char err6[] = "[255.0.0.0],";
+ char err7[] = "[dead:beef:feed:ded:0:1:2:]";
+
+ TEST(scan_ip6_reference((s = err0, &s)), -1);
+ TEST(scan_ip6_reference((s = err1, &s)), -1);
+ TEST(scan_ip6_reference((s = err2, &s)), -1);
+ TEST(scan_ip6_reference((s = err3, &s)), -1);
+ TEST(scan_ip6_reference((s = err4, &s)), -1);
+ TEST(scan_ip6_reference((s = err5, &s)), -1);
+ TEST(scan_ip6_reference((s = err6, &s)), -1);
+ TEST(scan_ip6_reference((s = err7, &s)), -1);
+ }
+
+ END();
+}
+
+#define TEST_SCAN(scanner, input, canonic, output) \
+ do { char s0[] = input; char *s = s0; \
+ size_t n = sizeof(input) - sizeof(output); \
+ TEST_SIZE(scanner(&s), n); \
+ TEST_S(s, output); \
+ TEST_S(s0, canonic); } while(0)
+
+#include <sofia-sip/hostdomain.h>
+
+int host_test(void)
+{
+ BEGIN();
+
+ TEST(host_is_ip4_address(NULL), 0);
+ TEST(host_is_ip6_address(NULL), 0);
+ TEST(host_ip6_reference(NULL), 0);
+ TEST(host_is_ip_address(NULL), 0);
+ TEST(host_is_domain(NULL), 0);
+ TEST(host_is_valid(NULL), 0);
+ TEST(host_has_domain_invalid(NULL), 0);
+
+ TEST_SIZE(span_host("rama"), 4);
+ TEST_SIZE(span_host("ra-ma.1-2.3-4.a4-9."), 19);
+ TEST_SIZE(span_host("a.1.b"), 5);
+ TEST_SIZE(span_host("127.255.249.000.a,"), 17);
+ TEST_SIZE(span_host("127.255.249.000,"), 15);
+ TEST_SIZE(span_host("0.00.000.000:,"), 12);
+ TEST_SIZE(span_host("127.255.249.000,"), 15);
+ TEST_SIZE(span_host("[dead:beef:feed:ded:0:1:2:3]:1"), 28);
+ TEST_SIZE(span_host("[dead:beef:feed:ded::1:2:3]:1"), 27);
+ TEST_SIZE(span_host("[::127.0.0.1]:1"), 13);
+
+ TEST_SCAN(scan_host, "rama", "rama", "");
+ TEST_SCAN(scan_host, "rama.", "rama.", "");
+ TEST_SCAN(scan_ip4_address, "127.255.249.000,", "127.255.249.0", ",");
+ TEST_SCAN(scan_host, "127.255.249.000,", "127.255.249.0", ",");
+ TEST_SCAN(scan_host, "a.1.b.", "a.1.b", "");
+ TEST_SCAN(scan_host, "ra-ma.1-2.3-4.a4-9.", "ra-ma.1-2.3-4.a4-9", "");
+ TEST_SCAN(scan_host, "127.255.249.000.a,", "127.255.249.000.a,", ",");
+ TEST_SCAN(scan_host, "0.00.000.000:,", "0.0.0.0", ":,");
+ TEST_SCAN(scan_host, "127.255.249.000,", "127.255.249.0", ",");
+ TEST_SCAN(scan_host, "[dead:beef:feed:ded:0:1:2:3]:1",
+ "[dead:beef:feed:ded::1:2:3]", ":1");
+ TEST_SCAN(scan_host, "[::127.0.0.1]:1", "[::127.0.0.1]:1", ":1");
+
+ /* Test error detection */
+ TEST_SIZE(span_host("256.00.000.000:,"), 0);
+ TEST_SIZE(span_host("255.00.000.0000,"), 0);
+ TEST_SIZE(span_host("255.00.000.199."), 0);
+ TEST_SIZE(span_host("[127.0.0.1]:1"), 0);
+ TEST_SIZE(span_domain("rama.1"), 0);
+ TEST_SIZE(span_domain("-ma.1-2.3-4.a4-9."), 0);
+ TEST_SIZE(span_domain("a..b"), 0);
+ TEST_SIZE(span_domain("a.b.-"), 0);
+ TEST_SIZE(span_domain("a.b-"), 0);
+
+ TEST(host_is_local("126.0.0.0"), 0);
+ TEST(host_is_local("127.0.0.0"), 1);
+ TEST(host_is_local("127.0.0.2"), 1);
+ TEST(host_is_local("0.0.0.0"), 0);
+ TEST(host_is_local("::1"), 1);
+ TEST(host_is_local("::1"), 1);
+ TEST(host_is_local("::1:3fff"), 0);
+ TEST(host_is_local("[::1]"), 1);
+ TEST(host_is_local("localdomain.domain.org"), 0);
+ TEST(host_is_local("localhost.domain.org"), 0);
+ TEST(host_is_local("localhost"), 1);
+ TEST(host_is_local("localhost.localdomain"), 1);
+ TEST(host_is_local("localhost."), 1);
+ TEST(host_is_local("localhost.localdomain."), 1);
+ TEST(host_is_local("localhost.localdomain.org"), 0);
+
+ TEST(host_has_domain_invalid("invalid"), 1);
+ TEST(host_has_domain_invalid("invalid."), 1);
+ TEST(host_has_domain_invalid("1.invalid"), 1);
+ TEST(host_has_domain_invalid("1.invalid."), 1);
+ TEST(host_has_domain_invalid("1invalid"), 0);
+ TEST(host_has_domain_invalid("valid."), 0);
+ TEST(host_has_domain_invalid("1-.invalid."), 0);
+
+ /* Invalid IP4 addresses (extra leading zeros) */
+ TEST_1(!host_cmp("127.0.0.1", "127.0.0.01"));
+ TEST_1(!host_cmp("[ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255]",
+ "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"));
+ /* Invalid reference (extra leading zeros) */
+ TEST_1(host_cmp("[0ffff:0ffff:0ffff:0ffff:0ffff:0ffff:255.255.255.255]",
+ "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"));
+ TEST_1(!host_cmp("::1", "::001"));
+ TEST_1(!host_cmp("[::1]", "::1"));
+ TEST_1(!host_cmp("[::1]", "::0.0.0.1"));
+ TEST_1(!host_cmp("::ffff:127.0.0.1", "127.0.0.1"));
+ TEST_1(!host_cmp("::ffff:127.0.0.1", "::ffff:7f00:1"));
+ TEST_1(!host_cmp("::ffff:127.0.0.1", "::ffff:7f00:1"));
+ TEST_1(!host_cmp("[::ffff:127.0.0.1]", "[::7f00:1]"));
+ TEST_1(host_cmp("::", "0.0.0.0"));
+ TEST_1(host_cmp("::1", "0.0.0.1"));
+
+ END();
+}
+
+void usage(void)
+{
+ fprintf(stderr, "usage: %s [-v]\n", name);
+}
+
+int main(int argc, char *argv[])
+{
+ int retval = 0;
+ int i;
+
+ for (i = 1; argv[i]; i++) {
+ if (strcmp(argv[i], "-v") == 0)
+ test_flags |= tst_verbatim;
+ else
+ usage();
+ }
+
+ retval |= bnf_test(); fflush(stdout);
+ retval |= ip_test(); fflush(stdout);
+ retval |= host_test(); fflush(stdout);
+
+ return retval;
+}
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/ChangeLog Thu Dec 21 01:30:28 2006
@@ -0,0 +1,20 @@
+2005-10-27 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Added aliases for RFC links in libsofia-sip-ua/docs/Doxyfile.aliases.
+
+ M ./libsofia-sip-ua/docs/Doxyfile.aliases -7 +2208
+
+2005-10-12 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Fixed aliases for Doxygen 1.4.
+
+ M ./libsofia-sip-ua/docs/Doxyfile.aliases -6 +6
+
+2005-09-08 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * hide_emails.sh: Fixed bug in hiding addresses of
+ form foo.bar-bar at something.org. Fixed sf.net
+ bug #1277167.
+
+
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/Doxyfile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/Doxyfile Thu Dec 21 01:30:28 2006
@@ -0,0 +1,30 @@
+PROJECT_NAME = "libsofia-sip-ua"
+OUTPUT_DIRECTORY = ../docs/html
+
+INPUT = mainpage.docs docguide.docs conformance.docs
+
+# release.docs
+
+ at INCLUDE = ../docs/Doxyfile.conf
+
+GENERATE_TAGFILE = docs.doxytags
+
+TAGFILES =
+TAGFILES += su.doxytags=su
+TAGFILES += ipt.doxytags=ipt
+TAGFILES += bnf.doxytags=bnf
+TAGFILES += url.doxytags=url
+TAGFILES += msg.doxytags=msg
+TAGFILES += sip.doxytags=sip
+TAGFILES += sresolv.doxytags=sresolv
+TAGFILES += stun.doxytags=stun
+TAGFILES += tport.doxytags=tport
+TAGFILES += nta.doxytags=nta
+TAGFILES += iptsec.doxytags=iptsec
+TAGFILES += sdp.doxytags=sdp
+TAGFILES += soa.doxytags=soa
+TAGFILES += nea.doxytags=nea
+TAGFILES += nua.doxytags=nua
+TAGFILES += features.doxytags=features
+
+EXAMPLE_PATH = ../sip
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/Doxyfile.aliases
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/Doxyfile.aliases Thu Dec 21 01:30:28 2006
@@ -0,0 +1,48 @@
+# Doxyfile 1.0.0 format
+#
+
+PREDEFINED = DOX \
+ DOXYGEN_ONLY=1 \
+ DOCUMENTATION_ONLY=1 \
+ SU_HAVE_INLINE=1 su_inline=inline \
+ SOFIA_BEGIN_DECLS SOFIA_END_DECLS SOFIAPUBFUN SOFIACALL \
+ SOFIAPUBVAR=extern \
+ SU_DLL SIP_DLL RTSP_DLL SU_DLL NTA_DLL NUA_DLL MSG_DLL AUTH_DLL \
+ NTH_DLL HTTP_DLL \
+ __attribute__()=
+
+ALIASES = \
+ "MODULEPAGE=\mainpage Sofia SIP User Agent Library - " \
+ "CONTACT=\par Contact:\n" \
+ "STATUS=\par Status:\n" \
+ "LICENSE=\par License:\n" \
+ "SofiaSIP=<a href=\"../index.html\">Sofia SIP</a>" \
+ "SU=@ref su_index \"SU\"" "su=@ref su_index \"su\"" \
+ "msg=@ref msg_index \"msg\"" \
+ "sip=@ref sip_index \"sip\"" \
+ "nua=@ref nua_index \"nua\"" \
+ "nta=@ref nta_index \"nta\"" \
+ "soa=@ref soa_index \"soa\"" \
+ "DEF=\def" \
+ "TAGS=\par Related Tags:" \
+ "TAG=\par \n" \
+ "EVENTS=\par Events:\n" \
+ "RESPONSES=\par Related Response Codes:\n" \
+ "CFILE=\file" \
+ "IFILE=\file" \
+ "HI=\hideinitializer " \
+ "HIDE=\hideinitializer " \
+ "SHOW=\showinitializer " \
+ "LGPL2=\par Lesser GNU Public License Version 2:\n \ref lgpl2\n \if 0\n" \
+ "ENDLGPL2=\endif \n" \
+ "GPL2=\par GNU Public License Version 2:\n \ref gpl2\n \if 0\n" \
+ "ENDGPL2=\endif \n" \
+ "ERRORS=\par Errors: " \
+ "ERROR=\par \n \b " \
+ "NEW_1_12_2=@since New in <a href=\"http://sofia-sip.sf.net/relnotes/relnotes-sofia-sip-1.12.2.txt\">1.12.2</a>" \
+ "VERSION_1_12_2=<a href=\"http://sofia-sip.sf.net/relnotes/relnotes-sofia-sip-1.12.2.txt\">1.12.2</a>" \
+ "NEW_1_12_4=@since New in <a href=\"http://sofia-sip.sf.net/relnotes/relnotes-sofia-sip-1.12.4.txt\">1.12.4</a>" \
+ "VERSION_1_12_4=<a href=\"http://sofia-sip.sf.net/relnotes/relnotes-sofia-sip-1.12.4.txt\">1.12.4</a>" \
+ "VERSION_1_12_5=<a href=\"http://sofia-sip.sf.net/relnotes/relnotes-sofia-sip-1.12.5.txt\">1.12.5</a>" \
+ "NEW_1_12_5=@since New in <a href=\"http://sofia-sip.sf.net/relnotes/relnotes-sofia-sip-1.12.5.txt\">1.12.5</a>" \
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/Doxyfile.conf
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/Doxyfile.conf Thu Dec 21 01:30:28 2006
@@ -0,0 +1,66 @@
+# Doxyfile 1.0.0 format
+#
+
+ at INCLUDE = "../../libsofia-sip-ua/docs/Doxyfile.version"
+ at INCLUDE = "../../libsofia-sip-ua/docs/Doxyfile.aliases"
+ at INCLUDE = "../../libsofia-sip-ua/docs/Doxyfile.rfc"
+
+OUTPUT_LANGUAGE = English
+
+DETAILS_AT_TOP = YES
+OPTIMIZE_OUTPUT_FOR_C = YES
+SHOW_USED_FILES = NO
+
+QUIET = YES
+WARNINGS = YES
+DISABLE_INDEX = NO
+
+HAVE_DOT = YES
+CLASS_GRAPH = NO
+INCLUDE_GRAPH = YES
+INCLUDED_BY_GRAPH = NO
+COLLABORATION_GRAPH = YES
+GROUP_GRAPHS = NO
+EXTRACT_ALL = NO
+EXTRACT_PRIVATE = NO
+HIDE_UNDOC_RELATIONS = YES
+HIDE_UNDOC_MEMBERS = YES
+HIDE_UNDOC_CLASSES = YES
+HIDE_SCOPE_NAMES = YES
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+JAVADOC_AUTOBRIEF = YES
+MAX_INITIALIZER_LINES = 0
+ENUM_VALUES_PER_LINE = 1
+
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION = YES
+EXPAND_ONLY_PREDEF = YES
+
+# HTML
+GENERATE_HTML = YES
+HTML_OUTPUT = .
+HTML_ALIGN_MEMBERS = YES
+HTML_FOOTER = ../../libsofia-sip-ua/docs/sofia-footer.html
+
+ALLEXTERNALS = NO
+EXTERNAL_GROUPS = NO
+
+# LATEX
+GENERATE_LATEX = NO
+LATEX_OUTPUT = latex
+LATEX_CMD_NAME = pdflatex
+USE_PDFLATEX = YES
+PDF_HYPERLINKS = YES
+COMPACT_LATEX = YES
+PAPER_TYPE = a4wide
+EXTRA_PACKAGES =
+LATEX_BATCHMODE = YES
+
+FILE_PATTERNS = *.h *.c
+
+EXCLUDE_PATTERNS = acconfig.h config.h confdefs.h \
+ test*.h test*.c torture*.c *test.c *torture.c \
+ *_tag_dll.c *_tag_ref.c
+
+IMAGE_PATH = ../../libsofia-sip-ua/docs/pictures
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/Doxyfile.version.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/Doxyfile.version.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1 @@
+PROJECT_NUMBER = @VERSION@
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/Makefile.am Thu Dec 21 01:30:28 2006
@@ -0,0 +1,50 @@
+EXTRA_DIST = Doxyfile Doxyfile.aliases Doxyfile.conf \
+ docguide.docs \
+ mainpage.docs \
+ conformance.docs \
+ Doxyfile.version.in \
+ sofia-footer.html.in \
+ hide_emails.sh \
+ ChangeLog \
+ pictures/SIP_basic_incoming_operation.eps \
+ pictures/SIP_basic_incoming_operation.gif \
+ pictures/SIP_basic_incoming_operation.vsd \
+ pictures/SIP_basic_outgoing_operation.eps \
+ pictures/SIP_basic_outgoing_operation.gif \
+ pictures/SIP_basic_outgoing_operation.vsd \
+ pictures/SIP_incoming_call.eps \
+ pictures/SIP_incoming_call.gif \
+ pictures/SIP_incoming_call.vsd \
+ pictures/SIP_outgoing_call.eps \
+ pictures/SIP_outgoing_call.gif \
+ pictures/SIP_outgoing_call.vsd \
+ pictures/SIP_outgoing_operation_with_auth.eps \
+ pictures/SIP_outgoing_operation_with_auth.gif \
+ pictures/SIP_outgoing_operation_with_auth.vsd \
+ pictures/autotools.eps \
+ pictures/autotools.gif \
+ pictures/autotools.vsd \
+ pictures/nta-receiving-message.eps \
+ pictures/nta-receiving-message.gif
+
+BUILT_SOURCES = Doxyfile.rfc
+
+# Including Doxyfile.rfc in dist breaks make manpages
+
+Doxyfile.rfc:
+ $(AWK) 'END { b="\\"; q="\\\""; \
+ print "# Autogenerated aliases for RFCs "from" .. "to ; \
+ print "ALIASES += " b; \
+ for (i=from; i < to; i++) { \
+ print "RFC"i"=\"<a href="q site i type q">RFC "i"</a>\" "b; \
+ }}' \
+ site=http://www.faqs.org/rfcs/rfc type=.html \
+ from=700 to=4800 \
+ /dev/null > $@
+
+CLEANFILES = Doxyfile.rfc
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+
+include ../sofia.am
\ No newline at end of file
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/Makefile.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1,474 @@
+# 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.
+
+ at SET_MAKE@
+
+# common Makefile targets for libsofia-sip-ua modules
+# ---------------------------------------------------
+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@
+DIST_COMMON = $(srcdir)/../sofia.am $(srcdir)/Doxyfile.version.in \
+ $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+ $(srcdir)/sofia-footer.html.in ChangeLog
+subdir = libsofia-sip-ua/docs
+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 = Doxyfile.version sofia-footer.html
+SOURCES =
+DIST_SOURCES =
+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@
+EXTRA_DIST = Doxyfile Doxyfile.aliases Doxyfile.conf \
+ docguide.docs \
+ mainpage.docs \
+ conformance.docs \
+ Doxyfile.version.in \
+ sofia-footer.html.in \
+ hide_emails.sh \
+ ChangeLog \
+ pictures/SIP_basic_incoming_operation.eps \
+ pictures/SIP_basic_incoming_operation.gif \
+ pictures/SIP_basic_incoming_operation.vsd \
+ pictures/SIP_basic_outgoing_operation.eps \
+ pictures/SIP_basic_outgoing_operation.gif \
+ pictures/SIP_basic_outgoing_operation.vsd \
+ pictures/SIP_incoming_call.eps \
+ pictures/SIP_incoming_call.gif \
+ pictures/SIP_incoming_call.vsd \
+ pictures/SIP_outgoing_call.eps \
+ pictures/SIP_outgoing_call.gif \
+ pictures/SIP_outgoing_call.vsd \
+ pictures/SIP_outgoing_operation_with_auth.eps \
+ pictures/SIP_outgoing_operation_with_auth.gif \
+ pictures/SIP_outgoing_operation_with_auth.vsd \
+ pictures/autotools.eps \
+ pictures/autotools.gif \
+ pictures/autotools.vsd \
+ pictures/nta-receiving-message.eps \
+ pictures/nta-receiving-message.gif
+
+BUILT_SOURCES = Doxyfile.rfc
+CLEANFILES = Doxyfile.rfc
+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
+
+all: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+$(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/docs/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu libsofia-sip-ua/docs/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
+Doxyfile.version: $(top_builddir)/config.status $(srcdir)/Doxyfile.version.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+sofia-footer.html: $(top_builddir)/config.status $(srcdir)/sofia-footer.html.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+uninstall-info-am:
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+distdir: $(DISTFILES)
+ $(mkdir_p) $(distdir)/.. $(distdir)/pictures
+ @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
+check: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile
+installdirs:
+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:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+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-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-libtool
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ distclean distclean-generic distclean-libtool distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-exec install-exec-am \
+ install-info install-info-am install-man install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am uninstall uninstall-am \
+ uninstall-info-am
+
+
+# Including Doxyfile.rfc in dist breaks make manpages
+
+Doxyfile.rfc:
+ $(AWK) 'END { b="\\"; q="\\\""; \
+ print "# Autogenerated aliases for RFCs "from" .. "to ; \
+ print "ALIASES += " b; \
+ for (i=from; i < to; i++) { \
+ print "RFC"i"=\"<a href="q site i type q">RFC "i"</a>\" "b; \
+ }}' \
+ site=http://www.faqs.org/rfcs/rfc type=.html \
+ from=700 to=4800 \
+ /dev/null > $@
+
+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) $<
+
+ at ENABLE_COVERAGE_TRUE@coverage:
+ at 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)
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+# 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:
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/conformance.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/conformance.docs Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1158 @@
+/* -*- html -*- */
+/**
+
+ at page sofia_sip_conformance SIP and SDP Protocol Features in Sofia-SIP
+
+This document describes how Sofia-SIP stack supports specifications listed
+below.
+
+<table border=0>
+<tr valign="top">
+<td>
+<a href="#3261">RFC 3261</a> <br>
+<a href="#2617">RFC 2617</a> <br>
+<a href="#3262">RFC 3262</a> <br>
+<a href="#3263">RFC 3263</a> <br>
+<a href="#3265">RFC 3265</a> <br>
+<a href="#2806">RFC 2806</a> <br>
+<a href="#2976">RFC 2976</a> <br>
+<a href="#3311">RFC 3311</a> <br>
+<a href="#3313">RFC 3313</a> <br>
+<a href="#3323">RFC 3323</a> <br>
+<a href="#3326">RFC 3326</a> <br>
+</td><td>
+<a href="#3325">RFC 3325</a> <br>
+<a href="#3327">RFC 3327</a> <br>
+<a href="#3329">RFC 3329</a> <br>
+<a href="#3361">RFC 3361</a> <br>
+<a href="#3420">RFC 3420</a> <br>
+<a href="#3428">RFC 3428</a> <br>
+<a href="#3486">RFC 3486</a> <br>
+<a href="#3515">RFC 3515</a> <br>
+<a href="#3608">RFC 3608</a> <br>
+<a href="#3680">RFC 3680</a> <br>
+<a href="#3824">RFC 3824</a> <br>
+</td><td>
+<a href="#3840">RFC 3840</a> <br>
+<a href="#3841">RFC 3841</a> <br>
+<a href="#3842">RFC 3842</a> <br>
+<a href="#3856">RFC 3856</a> <br>
+<a href="#3857">RFC 3857</a> <br>
+<a href="#3858">RFC 3858</a> <br>
+<a href="#3891">RFC 3891</a> <br>
+<a href="#3892">RFC 3892</a> <br>
+<a href="#3903">RFC 3903</a> <br>
+<a href="#4028">RFC 4028</a> <br>
+<a href="#4566">RFC 4566</a> <br>
+</td><td>
+<a href="#2327">RFC 2327</a> <br>
+<a href="#3264">RFC 3264</a> <br>
+<a href="#3266">RFC 3266</a> <br>
+<a href="#3312">RFC 3312</a> <br>
+<a href="#3388">RFC 3388</a> <br>
+<a href="#3407">RFC 3407</a> <br>
+<a href="#3524">RFC 3524</a> <br>
+<a href="#3556">RFC 3556</a> <br>
+<a href="#3605">RFC 3605</a> <br>
+<a href="#3890">RFC 3890</a> <br>
+</td></tr>
+</table>
+
+<table border=1 cellpadding=4 cellspacing=0>
+<tr>
+ <th>Feature</th>
+ <th>Supported</td>
+ <th>Notes</td>
+</tr>
+
+<tr valign=top>
+ <th align="left">
+ <a name="3261"></a>
+ @RFC3261: Basic SIP Protocol
+ </th>
+ <td>
+ The SIP registration and dialog level implementation enables the
+ application to operate as a SIP UA, SIP proxy or a redirect server
+ according to the @RFC3261.
+
+ The @RFC3261 functionality is divided into five layers:
+ -# <a href="sip/index.html">message syntax and encoding</a>
+ -# <a href="tport/index.html">transport</a>
+ -# <a href="nta/index.html">transaction</a>
+ -# transaction user (UAS and UAC cores, proxy core)
+ -# SIP elements: <a href="nua/index.html">user agent</a>
+ client and server, proxies,
+ registrars
+ </td>
+ <td>
+
+ </td>
+</tr>
+
+<tr valign=top>
+ <th align="left">
+ <a name="3261.19"></a> <a name="3261.20"></a>
+ @RFC3261 Sections 19 and 20:<br>
+ Syntax and encoding
+ </td>
+ <td>
+ The supported @RFC3261 methods are: @b REGISTER, @b OPTIONS, @b
+ INVITE, @b ACK, @b CANCEL, @b BYE, as well as methods
+ <a href="#2976"><b>INFO</b></a>,
+ <a href="#3262"><b>PRACK</b></a>,
+ <a href="#3265"><b>SUBSCRIBE</b></a>,
+ <a href="#3265"><b>NOTIFY</b></a>,
+ <a href="#3311"><b>UPDATE</b></a>,
+ <a href="#3428"><b>MESSAGE</b></a>,
+ <a href="#3515"><b>REFER</b></a>,
+ and
+ <a href="#3903"><b>PUBLISH</b></a>.
+
+ Sofia-SIP supports the following SIP headers as specified in
+ @RFC3261 or its extensions (generating, parsing and syntax
+ checking):
+
+ @ref sip_accept "Accept",
+ @ref sip_accept_encoding "Accept-Encoding",
+ @ref sip_accept_language "Accept-Language",
+ @ref sip_allow "Allow",
+ @ref sip_authentication_info "Authentication-Info",
+ @ref sip_authorization "Authorization",
+ @ref sip_call_id "Call-ID" ("i"),
+ @ref sip_call_info "Call-Info",
+ @ref sip_contact "Contact" ("m"),
+ @ref sip_content_disposition "Content-Disposition",
+ @ref sip_content_encoding "Content-Encoding" ("e"),
+ @ref sip_content_language "Content-Language",
+ @ref sip_content_length "Content-Length" ("l"),
+ @ref sip_content_type "Content-Type" ("c"),
+ @ref sip_cseq "CSeq",
+ @ref sip_date "Date",
+ @ref sip_error_info "Error-Info",
+ @ref sip_expires "Expires",
+ @ref sip_from "From" ("f"),
+ @ref sip_in_reply_to "In-Reply-To",
+ @ref sip_max_forwards "Max-Forwards",
+ @ref sip_min_expires "Min-Expires",
+ @ref sip_mime_version "MIME-Version",
+ @ref sip_organization "Organization",
+ @ref sip_priority "Priority",
+ @ref sip_proxy_authenticate "Proxy-Authenticate",
+ @ref sip_proxy_authorization "Proxy-Authorization",
+ @ref sip_proxy_require "Proxy-Require",
+ @ref sip_record_route "Record-Route",
+ @ref sip_require "Require",
+ @ref sip_retry_after "Retry-After",
+ @ref sip_route "Route",
+ @ref sip_server "Server",
+ @ref sip_subject "Subject" ("s"),
+ @ref sip_supported "Supported" ("k"),
+ @ref sip_timestamp "Timestamp",
+ @ref sip_to "To" ("t"),
+ @ref sip_unsupported "Unsupported",
+ @ref sip_user_agent "User-Agent",
+ @ref sip_via "Via" ("v"),
+ @ref sip_warning "Warning", and
+ @ref sip_www_authenticate "WWW-Authenticate".
+
+ Unknown headers (extension headers) are supported and can be passed
+ to/received from application as name-value pairs.
+
+ It is possible to extend SIP parser in run-time with header-specific
+ parsers.
+ </td>
+ <td>
+ - Unsupported headers:
+ Alert-Info,
+ Reply-To
+ - Automatic escaping of reserved characters has not been
+ implemented.
+ - Using NUL (zero byte) in doublequoted strings has not been implemented
+ </td>
+</tr>
+
+<tr valign=top>
+ <th align="left">
+ <a name="3261.18"></a>
+ @RFC3261 Section 18:<br>
+ UDP and TCP transports
+ </th>
+ <td>
+ UDP and TCP on both IP4 and IP6 are supported.
+
+ The UDP size limit of 1300 bytes is enforced by default. If limit is
+ exceeded, TCP is tried instead. If TCP connection is refused, UDP is
+ tried if message size is less than 64 kilobytes. Limit is adjustable
+ via parameter NTATAG_UDP_MTU().
+
+ TCP connections are reused by client. However, server closes
+ connections after idle time of 30 minutes (by default). The idle
+ time limit is adjustable with TPTAG_IDLE() (given as argument to
+ nta_agent_add_tport() or nta_agent_create()).
+
+ Server tries to use same TCP connection to return response as the
+ request was received.
+
+ Only one SIP message is accepted per UDP message, as per @RFC3261.
+ </td>
+ <td>
+ There is experimental support for SCTP, too.
+ </td>
+</tr>
+
+<tr valign=top>
+ <th align="left">
+ <a name="3261.17"></a>
+ @RFC3261 Section 17:<br> Transactions
+ </th>
+ <td>
+ Transaction state engines function as specified in @RFC3261 section
+ 17. There is special handling of methods @b INVITE, @b ACK, and @b
+ CANCEL. There are two modes for transaction state engines,
+ User-Agent and Proxy modes.
+
+ Default values for SIP timers are those specified by @RFC3261. The
+ defaults for T1, T1x64, T2 and T4 can be changed via
+ configuration tags defined in <nta_tag.h>.
+ </td>
+ <td>
+
+ </td>
+</tr>
+
+
+<tr valign=top>
+ <th align="left">
+ <a name="3261.26"></a>
+ @RFC3261 Section 26:<br> Security
+ </th>
+ <td>
+ TLS and SIPS URIs has been implemented. Currently, TLS does not
+ require certificate from client nor it does check it if one is
+ provided.
+ </td>
+ <td>
+ Missing:
+ - TLS certificate checking
+ - S/MIME
+ </td>
+</tr>
+
+<tr valign=top>
+ <th align="left">
+ <a name="2617"></a>
+ @RFC2617: HTTP Digest Authentication
+ </th>
+ <td>
+ Sofia-SIP an authentication client and server modules implementing
+ HTTP Digest authentication.
+
+ HTTP Digest is a simple challenge-response authentication
+ scheme defined in @RFC2617 based on the UA sending a checksum
+ calculated over specific values in response to a challenge sent by
+ the server (proxy or UA).
+
+ Checksum calculation supports MD5 (@RFC1321). The algorithm for
+ calculating MD5 digest hash can be MD5, MD5sess or be
+ @RFC2069-compatible algorithm. The quality-of-protection (qop)
+ parameters "auth", "auth-int" and none (missing) are supported. The
+ "opaque" parameter is supported.
+
+ The SIP authentication headers supported (generating, parsing and
+ syntax checking) are:
+ @ref sip_authorization "Authorization",
+ @ref sip_authentication_info "Authentication-Info",
+ @ref sip_proxy_authenticate "Proxy-Authenticate",
+ @ref sip_proxy_authentication_info "Proxy-Authentication-Info",
+ @ref sip_proxy_authorization "Proxy-Authorization", and
+ @ref sip_www_authenticate "WWW-Authenticate".
+
+ SIP interface to the modules is implemented as defined in @RFC3261
+ (sections 8.1.3.5, 22.2, 22.3, 22.4).
+
+ An @RFC2617 header
+ @ref sip_proxy_authentication_info "Proxy-Authentication-Info"
+ is not listed in @RFC3261 but it is nevertheless supported by
+ Sofia-SIP.
+ </td>
+ <td>
+ Missing:
+ - Using nextnonce
+ - Mutual authentication
+ </td>
+</tr>
+
+<tr valign=top>
+ <th align="left">
+ <a name="3262"></a>
+ @RFC3262: PRACK and 100rel
+ </th>
+ <td>
+ PRACK method is supported within dialog as defined in RFC3262.
+ Semantics of reliable provisional responses are supported:
+ - including 100rel Required header in provisional responses if
+ request had 100rel
+ - generation of PRACK based on 100rel option tag in Require header of
+ a provisional response, and
+ - automatic re-transmission of provisional responses.
+
+ The SIP headers supported (generating, parsing and syntax checking)
+ are @ref sip_rseq "RSeq" and @ref sip_rack "RAck".
+ </td>
+ <td>
+
+ </td>
+</tr>
+
+<tr valign=top>
+ <th align="left">
+ <a name="3263"></a>
+ @RFC3263: Locating SIP Servers
+ </th>
+ <td>
+ Support for SIP server address resolution from SIP or SIPS URI using
+ NAPTR, SRV, A or AAAA records in DNS as defined in @RFC3263.
+ </td>
+ <td>
+ - Resolving any other types of URIs than SIP or SIPS URIs, e.g., IM:
+ or PRES: URIs.
+ </td>
+</tr>
+
+<tr valign=top>
+ <th align="left">
+ <a name="3265"></a>
+ @RFC3265: SIP Event Notifications
+ </th>
+ <td>
+ SIP extensions for subscribing and processing asynchronous event
+ notifications as defined in @RFC3265.
+
+ Includes dialog level support for sending and refreshing SUBSCRIBE
+ and receiving NOTIFY messages.
+
+ The SIP headers explicitly supported (generating, parsing and
+ syntax checking) are
+ @ref sip_event "Event" ("o"),
+ @ref sip_allow_events "Allow-Events", and
+ @ref sip_subscription_state "Subscription-State"
+
+ Note: currently there is no support for forked SUBSCRIBE requests.
+ </td>
+ <td>
+ Application must take care of:
+ - Subscribing, generating or processing specific event types
+ and interpreting the content of event data is up to application
+ </td>
+</tr>
+
+<tr valign=top>
+ <th align="left">
+ <a name="2806"></a>
+ @RFC2806: tel URI
+ </th>
+ <td>
+ Sofia-SIP supports handling of any URI type. Sofia-SIP parses tel:
+ URIs.
+ </td>
+ <td>
+ Missing:
+ - Resolving the tel: URIs
+ </td>
+</tr>
+
+<tr valign=top>
+ <th align="left">
+ <a name="2976"></a>
+ @RFC2976: INFO
+ </th>
+ <td>
+ INFO method is supported within a dialog natively.
+ </td>
+ <td>
+ Not implemented:
+ - Generating or processing contents of INFO requests
+ </td>
+</tr>
+
+
+<tr valign=top>
+ <th align="left">
+ <a name="3311"></a>
+ @RFC3311: UPDATE
+ </th>
+ <td>
+ UPDATE method as defined in RFC3311. UPDATE allows a client to
+ update parameters of a session (such as the set of media streams and
+ their codecs) even within early dialogs.
+
+ Offer-Answer negotiation with UPDATE is implemented in nua.
+ </td>
+ <td>
+ Application must take care of:
+ - Initiating UPDATE requests
+ </td>
+</tr>
+
+
+<tr valign=top>
+ <th align="left">
+ <a name="3313"></a>
+ @RFC3313: Media Authentication
+ </th>
+ <td>
+ Sofia-SIP provides <a href="#3261.19">generic support</a> for
+ extension headers and parameters. P-Media-Authorization header is
+ supported as an @ref sip_unknown "extension header".
+ </td>
+ <td>
+ Application must take care of:
+ - Passing the authorization token to QoS reservation request
+ </td>
+</tr>
+
+
+<tr valign=top>
+ <th align="left">
+ <a name="3323"></a>
+ @RFC3323: Privacy
+ </th>
+ <td>
+ @ref sip_privacy "Privacy" header is supported (generating, parsing
+ and syntax checking).
+
+ Call-Id header is generated from cryptographically random id without
+ host name or IP address. By default, @ref sip_contact "Contact" and
+ @ref sip_via "Via" headers contain only IP address that can be
+ dynamically allocated.
+
+ Application can enter any SIP URI and display name to From header,
+ e.g., @code Anonymous <sip:anonymous at example.org> @endcode.
+ </td>
+ <td>
+ Application must take care of:
+ - Properly populating the URIs and display names within SIP headers
+ - Not including any optional headers that could reveal identity
+ - Generating of Privacy header with appropriate values
+ - Generating of Proxy-Require: privacy
+ - Using anonymous callback URIs etc.
+ </td>
+</tr>
+
+
+<tr valign=top>
+ <th align="left">
+ <a name="3326"></a>
+ @RFC3326: Reason
+ </th>
+ <td>
+ Sofia-SIP supports @ref sip_reason "Reason" header (generating,
+ parsing and syntax checking).
+ </td>
+ <td>
+ Application must take care of:
+ - Generating or processing Reason headers
+ </td>
+</tr>
+
+
+<tr valign=top>
+ <th align="left">
+ <a name="3325"></a>
+ @RFC3325: Asserted Identity
+ </th>
+ <td>
+ Sofia-SIP provides <a href="#3261.19">generic support</a> for
+ extension headers and parameters. P-Asserted-Identity and
+ P-Preferred-Identity are supported as supported as @ref
+ sip_unknown "extension headers".
+ </td>
+ <td>
+ Not implemented:
+ - <a href="#3323">id privacy</a>
+ - Recognizing trust domains and enforcing handling of headers
+ based on those
+ </td>
+</tr>
+
+<tr valign=top>
+ <th align="left">
+ <a name="3327"></a>
+ @RFC3327: Path
+ </th>
+ <td>
+ User-agent engine can add "path" option tag to Supported header of
+ REGISTER requests.
+
+ Sofia-SIP explicitly supports @ref sip_path "Path" header
+ (generating, parsing and syntax checking).
+ </td>
+ <td>
+
+ </td>
+</tr>
+
+<tr valign=top>
+ <th align="left">
+ <a name="3329"></a>
+ @RFC3329:
+ Security Agreement
+ </th>
+ <td>
+ Some support of the SIP Security Mechanism Agreement procedures. The
+ client is able to insert Security-Client and Security-Verify header
+ with fake @e d-ver value.
+
+ Sofia-SIP explicitly supports (generating, parsing
+ and syntax checking)
+ @ref sip_security_client "Security-Client",
+ @ref sip_security_server "Security-Server", and
+ @ref sip_security_verify "Security-Verify" headers.
+
+ Security-mechanism supported is "digest".
+ </td>
+ <td>
+ Correct @e d-ver value is not calculated.
+ </td>
+</tr>
+
+<tr valign=top>
+ <th align="left">
+ <a name="3361"></a>
+ @RFC3361: DHCPv4 option for locating SIP servers.
+ </th>
+ <td>
+ Sofia-SIP supports outbound proxy.
+ </td>
+ <td>
+ Application must take care of:
+ - passing outbound proxy name or address from DHCP client
+ to Sofia-SIP stack.
+ </td>
+</tr>
+
+<tr valign=top>
+ <th align="left">
+ <a name="3420"></a>
+ @RFC3420: message/sipfrag
+ </th>
+ <td>
+ Sofia-SIP passes the received SIP message headers to application
+ which can create a message/sipfrag payload.
+ </td>
+ <td>
+ Application must take care of:
+ - processing the SIP message fragments
+ </td>
+</tr>
+
+<tr valign=top>
+ <th align="left">
+ <a name="3428"></a>
+ @RFC3428: MESSAGE
+ </th>
+ <td>
+ MESSAGE method is supported natively.
+ </td>
+ <td>
+
+ </td>
+</tr>
+
+<tr valign=top>
+ <th align="left">
+ <a name="3486"></a>
+ @RFC3486: Compressing SIP
+ </th>
+ <td>
+ Sofia-SIP provides support for using comp=sigcomp parameters in @ref
+ sip_via "Via" header and @ref url_t "SIP URIs", indicating
+ support for compression.
+ </td>
+ <td>
+ SigComp itself is not supported.
+ </td>
+</tr>
+
+<tr valign=top>
+ <th align="left">
+ <a name="3515"></a>
+ @RFC3515: REFER
+ </th>
+ <td>
+ REFER method is supported natively. Sofia-SIP processes incoming
+ REFER requests and generates NOTIFY with correct
+ @ref sip_event "Event" header automatically.
+
+ Further notifications can be automatically generated actions when
+ nua_invite() is given referrer's nua handle in NUTAG_NOTIFY_REFER().
+
+ Sofia-SIP explicitly supports (generating, parsing and syntax
+ checking) @ref sip_refer_to "Refer-To" ("r") SIP header.
+
+ See also support for
+ <a href="#3891">RFC 3891</a> and
+ <a href="#3892">RFC 3892</a>.
+ </td>
+ <td>
+
+ </td>
+</tr>
+
+<tr valign=top>
+ <th align="left">
+ <a name="3608"></a>
+ @RFC3608: Service-Route
+ </th>
+ <td>
+ Sofia-SIP supports @ref sip_service_route "Service-Route" that can
+ be used to provide a mechanism by which a registrar may inform a
+ registering UA of a service route. User-Agent will optionally use
+ the route provided in @ref sip_service_route "Service-Route" header.
+
+ The SIP header explicitly supported (generating, parsing and
+ syntax checking) is @ref sip_service_route "Service-Route".
+ </td>
+ <td>
+
+ </td>
+</tr>
+
+<tr valign=top>
+ <th align="left">
+ <a name="3680"></a>
+ @RFC3680: "reg" event
+ </th>
+ <td>
+ Sofia-SIP supports <a href="#3265">generic SIP event support</a> for
+ subscribing SIP event packages and receiving notifications for them.
+ Subscriptions are refreshed before expiration when needed and
+ subscriptions are terminated on request. Sofia-SIP takes care of
+ notified subscription states.
+
+ UA can SUBSCRIBE to a registration state event package after sending
+ initial REGISTER to, e.g., 3GPP network and use it to follow its
+ registration status.
+ </td>
+ <td>
+ Application must take care of:
+ - Generating subscriptions for "reg" event
+ - Processing notifications for "reg" event
+ - Handling of XML document in notifications
+ </td>
+</tr>
+
+<tr valign=top>
+ <th align="left">
+ <a name="3824"></a>
+ @RFC3824: ENUM
+ </th>
+ <td>
+ Tel URIs are supported in any headers including URI parameters,
+ e.g., To, From, Contact headers, and Request-URI of the outgoing SIP
+ request provided that the next hop is given as SIP or SIPS URI.
+ </td>
+ <td>
+ Stack can not resolve E.164 number to address of next
+ hop. A proxy in the network must resolve E.164 numbers with ENUM.
+ </td>
+</tr>
+
+<tr valign=top>
+ <th align="left">
+ <a name="3840"></a>
+ @RFC3840: Callee Capabilities
+ </th>
+ <td>
+ Feature parameters can be added to SIP profiles and sent within
+ Contact header of REGISTER request as header parameters.
+
+ UAC can optionally generate media tags for Contact header using
+ local media profile.
+
+ Feature parameters can also be sent within any other SIP request as
+ extension parameters of Contact header.
+ </td>
+ <td>
+ Application must take care of:
+ - Processing the feature parameters received in the Contact header
+ </td>
+</tr>
+
+
+<tr valign=top>
+ <th align="left">
+ <a name="3841"></a>
+ @RFC3841: Caller Preferences
+ </th>
+ <td>
+ Built-in support for user-agent behavior.
+
+ UAC can optionally generate Accept-Contact header using local media
+ profile.
+
+ SIP parser parses the Accept-Contact and Reject-Contact headers.
+
+ ACK and CANCEL request messages sent have same values
+ for Accept-Contact/Reject-Contact or Request-Disposition
+ headers as the original request had.
+
+ There are functions for calculating score for contacts.
+
+ The SIP headers explicitly supported (generating,
+ parsing and syntax checking) are:
+ @ref sip_request_disposition "Request-Disposition" ("d"),
+ @ref sip_accept_contact "Accept-Contact" ("a"),
+ @ref sip_reject_contact "Reject-Contact" ("j"),
+ </td>
+ <td>
+ Application must take care of:
+ - UAS processing incoming Accept-Contact or Reject-Contact headers
+ </td>
+</tr>
+
+<tr valign=top>
+ <th align="left">
+ <a name="3842"></a>
+ @RFC3842: Message waiting event
+ </th>
+ <td>
+ Sofia-SIP supports <a href="#3265">generic SIP event support</a> for
+ subscribing SIP event packages and receiving notifications for them.
+ Subscriptions are refreshed before expiration when needed and
+ subscriptions are terminated on request. Sofia-SIP takes care of
+ notified subscription states.
+ </td>
+ <td>
+ Application must take care of:
+ - Generating subscriptions for "message-summary" event
+ - Including correct @ref sip_event "Event" and
+ @ref sip_accept "Accept" headers in the request (if needed)
+ - Processing notifications for "message-summary" event
+ - Handling of summary information in notifications
+ </td>
+</tr>
+
+<tr valign=top>
+ <th align="left">
+ <a name="3856"></a>
+ @RFC3856: Presence
+ </th>
+ <td>
+ Sofia-SIP supports <a href="#3265">generic SIP event support</a> for
+ subscribing SIP event packages and receiving notifications for them.
+ Subscriptions are refreshed before expiration when needed and
+ subscriptions are terminated on request. Sofia-SIP takes care of
+ notified subscription states.
+
+ Note: Usage of pres: URI is supported only if the next hop URI to
+ where to send SUBSCRIBE is a SIP URI (e.g. of outbound proxy).
+ Resolving of pres: URIs by DNS is not supported.
+ </td>
+ <td>
+ Application must take care of:
+ - Generating subscriptions for "presence" event
+ - Including correct @ref sip_event "Event" and
+ @ref sip_accept "Accept" headers in the request (if needed)
+ - Processing notifications for "presence" event
+ - Handling of presence information in notifications
+ </td>
+</tr>
+
+<tr valign=top>
+ <th align="left">
+ <a name="3857"></a> <a name="3858"></a>
+ @RFC3857: "winfo" event template package<br>
+ @RFC3858: winfo format
+ </th>
+ <td>
+ Sofia-SIP supports <a href="#3265">generic SIP event support</a> for
+ subscribing SIP event packages and receiving notifications for them.
+ Subscriptions are refreshed before expiration when needed and
+ subscriptions are terminated on request. Sofia-SIP takes care of
+ notified subscription states.
+ </td>
+ <td>
+ Application must take care of:
+ - Generating subscriptions for winfo events
+ - Including correct @ref sip_event "Event" and
+ @ref sip_accept "Accept" headers in the request (if needed)
+ - Processing notifications for winfo events:
+ - Processing watcherxinfo XML documents
+ </td>
+</tr>
+
+<tr valign=top>
+ <th align="left">
+ <a name="3891"></a>
+ @RFC3891: Replaces
+ </th>
+ <td>
+ @ref sip_replaces "Replaces" header is explicitly supported
+ (generating, parsing and syntax checking).
+ </td>
+ <td>
+ Application must take care of:
+ - generating @ref sip_replaces "Replaces" header from a dialog and
+ matching a dialog with a Replaces header received
+ </td>
+</tr>
+
+<tr valign=top>
+ <th align="left">
+ <a name="3892"></a>
+ @RFC3892: Referred-By
+ </th>
+ <td>
+ @ref sip_referred_by "Referred-By" header is explicitly supported
+ (generating, parsing and syntax checking).
+
+ Referred-by token can be sent and received in
+ text-based SIP message body.
+ </td>
+ <td>
+ Application must take care of:
+ - Generating or processing @ref sip_referred_by "Referred-By" headers
+ - Generating (and encrypting) or verifying (and decrypting) of
+ Referred-by tokens
+ </td>
+</tr>
+
+<tr valign=top>
+ <th align="left">
+ <a name="3903"></a>
+ @RFC3903: PUBLISH
+ </th>
+ <td>
+ PUBLISH method is supported natively. The SIP headers
+ explicitly supported (generating, parsing and syntax checking) are
+ @ref sip_etag "SIP-ETag" and @ref sip_if_match "SIP-If-Match".
+
+ The <a href="nua/index.html">user-agent engine</a> keep published
+ data refreshed until nua_unpublish() is called.
+ </td>
+ <td>
+ Application must take care of:
+ - Including correct @ref sip_event "Event" in the request
+ - Permanently storing SIP-ETag
+ </td>
+</tr>
+
+<tr valign=top>
+ <th align="left">
+ <a name="4028"></a>
+ @RFC4028: Session Timers
+ </th>
+ <td>
+ The SIP session-timer ("timer") extension is supported.
+
+ The session-expires value and refreshing party is negotiated in
+ <a href="nua/index.html">user-agent engine</a>. When user-agent
+ engine is responsible for refreshes, it will initiate re-INVITE or
+ UPDATE transaction at regular intervals. If there has been no SIP
+ activity in session during the refresh period, it will try to
+ automatically terminate the call by sending a @b BYE request.
+
+ The SIP headers explicitly supported (generating, parsing and
+ syntax checking) are @ref sip_session_expires "Session-Expires" ("x") and
+ @ref sip_min_se "Min-SE".
+ </td>
+ <td>
+
+ </td>
+</tr>
+</table>
+
+<table border=1 cellpadding=4 cellspacing=0>
+<tr>
+ <th>Feature</th>
+ <th>Supported</td>
+ <th>Notes</td>
+</tr>
+
+<tr valign=top>
+ <th align="left" align="left">
+ <a name="2327"></a>
+ @RFC2327: SDP (Session Description Protocol)
+ </th>
+ <td>
+ Generic support (generating, parsing and syntax checking) for SDP.
+ The SDP
+ @ref sdp_version_t "v=",
+ @ref sdp_origin_t "o=",
+ @ref sdp_connection_t "c=",
+ @ref sdp_bandwidth_t "b=",
+ @ref sdp_time_t "t=",
+ @ref sdp_repeat_t "r=",
+ @ref sdp_zone_t "z=",
+ @ref sdp_key_t "k=",
+ @ref sdp_attribute_t "a=", and
+ @ref sdp_media_t "m="
+ lines are separated and parsed. The "e=", "p=", "s=", and "i=" lines
+ are separated.
+
+ The attributes "a=sendrecv", "a=sendonly", "a=recvonly",
+ "a=inactive", @ref sdp_rtpmap_s "a=rtpmap", and "a=fmtp" are parsed.
+
+ The implementation tries to follow draft-ietf-mmusic-sdp-new-25,
+ draft Internet Standard for SDP in progress.
+ </td>
+ <td>
+ - see also <a href="#4566">RFC 4566</a>
+ </td>
+</tr>
+
+<tr valign=top>
+ <th align="left">
+ <a name="3264"></a>
+ @RFC3264: SDP Offer/Answer Negotiation
+ </th>
+ <td>
+ Generating and processing offers or answers.
+ </td>
+ <td>
+ - "a=fmtp" parameters are not taken into account
+ when generating or processing answer
+ </td>
+</tr>
+
+<tr valign=top>
+ <th align="left">
+ <a name="3266"></a>
+ @RFC3266: IP6 in SDP
+ </th>
+ <td>
+ Representation of IP6 addresses within SDP message.
+ </td>
+ <td>
+ - see also <a href="#4566">RFC 4566</a>
+ </td>
+</tr>
+
+<tr valign=top>
+ <th align="left">
+ <a name="3312"></a>
+ @RFC3312: Preconditions
+ </th>
+ <td>
+ Sofia-SIP provides <a href="#2616">generic support</a> for attribute
+ lines that conform to SDP syntax.
+
+ Sofia-SIP supports handling SIP feature tags in
+ @ref sip_proxy_require "Proxy-Require",
+ @ref sip_require "Require",
+ @ref sip_supported "Supported" ("k"),
+ and
+ @ref sip_unsupported "Unsupported" header.
+ </td>
+ <td>
+ Application must take care of:
+ - Semantics and handling of preconditions
+ - Reservation of resources
+ </td>
+</tr>
+
+<tr valign=top>
+ <th align="left">
+ <a name="3388"></a>
+ @RFC3388: Grouping of Media Lines
+ </th>
+ <td>
+ Sofia-SIP provides <a href="#2616">generic support</a> for attribute
+ lines that conform to SDP syntax.
+
+ @RFC3388 defines mid, group, LS and FID are predefined strings to be
+ used within attribute line
+ </td>
+ <td>
+ Application must take care of:
+ - Generating or processing the attribute lines
+ - Grouping the media for transport accordingly
+ </td>
+</tr>
+
+
+<tr valign=top>
+ <th align="left">
+ <a name="3407"></a>
+ @RFC3407: Capability Declaration
+ </th>
+ <td>
+ Sofia-SIP provides <a href="#2616">generic support</a> for attribute
+ lines that conform to SDP syntax.
+ </td>
+ <td>
+ Application must take care of:
+ - Defining sqn, cdsc, cpar etc. strings needed in a= line
+ - Generating or processing the attribute lines
+ - Capability negotiation itself
+ </td>
+</tr>
+
+
+<tr valign=top>
+ <th align="left">
+ <a name="3524"></a>
+ @RFC3524: SRF
+ </th>
+ <td>
+ Sofia-SIP provides <a href="#2616">generic support</a> for attribute
+ lines that conform to SDP syntax.
+ </td>
+ <td>
+ Application must take care of:
+ - Defining SRF string needed in a= line
+ - Generating or processing the attribute lines
+ </td>
+</tr>
+
+<tr valign=top>
+ <th align="left">
+ <a name="3556"></a>
+ @RFC3556: Bandwidth
+ </th>
+ <td>
+ Sofia-SIP provides <a href="#2616">generic support</a> for attribute
+ lines that conform to SDP syntax.
+ </td>
+ <td>
+ Application must take care of:
+ - Generating or processing RS and RR bandwidth modifiers
+ - Semantics of bandwidth allocation
+ </td>
+</tr>
+
+<tr valign=top>
+ <th align="left">
+ <a name="3605"></a>
+ @RFC3605: RTCP attribute
+ </th>
+ <td>
+ Sofia-SIP provides <a href="#2616">generic support</a> for attribute
+ lines that conform to SDP syntax.
+ </td>
+ <td>
+ Application must take care of:
+ - Discovering port numbers
+ - Generating or processing the RTCP attribute lines
+ </td>
+</tr>
+
+<tr valign=top>
+ <th align="left">
+ <a name="3890"></a>
+ @RFC3890: TIAS
+ </th>
+ <td>
+ Sofia-SIP provides <a href="#2616">generic support</a> for attribute
+ lines that conform to SDP syntax.
+ </td>
+ <td>
+ Application must take care of:
+ - Generating or processing TIAS bandwidth modifiers
+ - Generating or processing the maxprate attribute lines
+ </td>
+</tr>
+
+<tr valign=top>
+ <th align="left">
+ <a name="4566"></a>
+ @RFC4566: SDP: Session Description Protocol
+ </th>
+ <td>
+ Obsoletes RFC2327 and RFC3266.
+ </td>
+ <td>
+
+ </td>
+</tr>
+
+</table>
+
+*/
+
+/* Overflow:
+
+<tr valign=top>
+ <th align="left">
+ <a name="3320"></a>
+ @RFC3320: SigComp
+ </th>
+ <td>
+ Support for using SigComp for compression and
+ decompression of SIP/SDP messages. By default, dynamic
+ compression is used.
+
+ Decompression using UDVM
+ </td>
+ <td>
+
+ </td>
+</tr>
+
+<tr valign=top>
+ <th align="left">
+ <a name="3321"></a>
+ @RFC3321: SigComp Extended operations
+ </th>
+ <td>
+ Support for SigComp extended operations.
+ </td>
+ <td>
+ - Explicit Acknowledgment Scheme
+ - Shared Compression
+ - Checkpoint State
+ - Implicit Deletion for Dictionary Update
+ </td>
+</tr>
+
+<tr valign=top>
+ <th align="left">
+ <a name="3325"></a>
+ @RFC3325: Asserted Identity
+ </th>
+ <td>
+ Explicit support (generating, parsing and syntax checking) for the
+ following SIP headers: P-Asserted-Identity, P-Preferred-Identity
+ </td>
+ <td>
+ - Recognizing trust domains and enforcing handling of headers
+ based on those
+ </td>
+</tr>
+
+<tr valign=top>
+ <th align="left">
+ <a name="3485"></a>
+ @RFC3485: SIP/SDP Dictionary
+ </th>
+ <td>
+ Support for SigComp static compression using SIP/SDP
+ dictionary.
+ </td>
+ <td>
+
+ </td>
+</tr>
+
+
+
+
+ - Implicitly registered user identities
+
+<tr valign=top>
+ <th align="left">
+ <a name="3959"></a>
+ @RFC3959: early-session
+ </th>
+ <td>
+ Early-session value can be used within Content-Disposition,
+ Supported and Require headers.
+ </td>
+ <td>
+ - Generating of Content-Disposition, Supported and Require
+ - Handling of multipart bodies with early and session SDP
+ </td>
+</tr>
+
+*/
\ No newline at end of file
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/docguide.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/docguide.docs Thu Dec 21 01:30:28 2006
@@ -0,0 +1,249 @@
+/*!
+
+ at page docguide Documentation Guidelines
+
+ at section doxygen Using Doxygen
+
+Doxygen is a document generation program, used by many C/C++ projects. Its
+home page is at <a href="http://www.doxygen.org">http://www.doxygen.org</a>.
+The Sofia documentation is written using Doxygen.
+
+Doxygen works by extracting the documentation data both from the actual
+C/C++ source code and from the specially formatted comments.
+The comments can contain some Javadoc-like
+ at ref doxycommands "special commands".
+
+In general the the style of the comments and documentation should follow the
+<a href="http://java.sun.com/j2se/javadoc/writingdoccomments/">
+javadoc style guide</a>.
+
+A Doxygen comment must either contain reference about the entity
+it is describing, e.g., command
+\@file when describing files:
+ at verbatim
+/**
+ * @file foo.c
+ *
+ * Implementation of foo. The foo takes care of grokking xyzzy.
+ *
+ * @author Jaska Jokunen <jaska.jokunen at company.com> \n
+ *
+ * @date Created: Wed Oct 20 15:06:51 EEST 2004 jasjoku
+ */
+ at endverbatim
+
+Usually the entity that is documented comes straight after the documentation
+comment. For example, documenting a function happens like this:
+ at anchor orch
+ at verbatim
+
+/**
+ * Orches a candometer. If orching candometer is not possible, it
+ * tries to schadule hearping.
+ *
+ * @param[in] k pointer to a candometer
+ * @param[in] level orching level
+ * @param[out] return_hearping return value for schaduled hearping
+ *
+ * @return
+ * The function orch() returns the candometer value, or #ERROR upon an error.
+ * If the returned value is 0, the newly schaduled hearping is returned in
+ * @a return_hearping.
+ */
+int orch(cando_t *k, int level, hearping_t *return_hearping)
+{
+ ...
+}
+ at endverbatim
+
+ at subsection doxyfile Doxyfile and Doxyfile.conf
+
+The doxygen options are specified through a configuration file,
+<i>Doxyfile</i>. As a convention, a module-specific Doxyfile includes
+a common file libsofia-sip-ua/docs/Doxyfile.conf. This makes it possible
+to keep the module-specific Doxyfiles as clean as possible:
+
+ at code
+PROJECT_NAME = "ipt"
+OUTPUT_DIRECTORY = ../docs/ipt
+
+INPUT = ipt.docs .
+
+ at INCLUDE = ../Doxyfile.conf
+
+TAGFILES += ../docs/docs/doxytags=../docs
+TAGFILES += ../docs/su/doxytags=../su
+GENERATE_TAGFILE = ../docs/ipt/doxytags
+ at endcode
+
+From the file above, you can observe some conventions. The
+Doxygen-generated HTML documentation is collected in @b docs
+subdirectory at top level. A separate output directory is created for
+each submodule under it. Doxytags for the module are generated in the @e
+doxytags file in the output directory.
+
+ at subsection module_docs Module documentation in \<module\>.docs
+
+Each module contains a documentation file containing at least the module
+mainpage called @e \<module\>.docs. There should be the module
+boilerplate information, for instance the following example is excerpt
+contents of file @e ipt.docs:
+
+ at verbatim
+/**
+ at MODULEPAGE "ipt" - Utility Module
+
+ at section ipt_meta Module Meta Information
+
+Utility library for IP Telephony applications.
+
+ at CONTACT Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ at STATUS @SofiaSIP Core library
+
+ at LICENSE LGPL
+
+ at section ipt_overview Overview
+
+This module contain some routines useful for IPT applications, like
+- ...
+- ...
+*/
+ at endverbatim
+
+ at section doxycommands Common Doxygen Commands
+
+In this section we go through the most common Doxygen commands. All
+the commands are explained in the manual.
+The commands include
+- @ref doxystyle "style commands (@@a, @@b, @@c, @@e, @@em, @@p)"
+- @ref doxyfuncs "function parameters and return values (@@param, @@return, @@retval)"
+
+ at subsection doxystyle Style Commands - @a, @b, @c, @e
+
+The text style can be changed with @@b @b (bold), @@c @c (code), or
+@@e @e (italic) commands. Function argument names use style command
+@@a.
+
+For example, a sentence "The @b Content-Type header @a ct specifies the @e
+media-type of the message body, e.g., @c audio/amr would be AMR-encoded
+audio." is produced with commands like
+ at code
+The @b Content-Type header @a ct specifies the @e media-type of
+the message body, e.g., @c audio/amr would be AMR-encoded audio.
+ at endcode
+
+The style commands have synonyms, e.g., @@em and @@e mean same, as
+well as @@c and @@p.
+
+ at subsection doxyfuncs Function Parameters and Return Values - @param, @return, @retval
+
+Parameters to a function are documented with @@param commands. (See
+the @ref orch "orch()" function above.) As a convention, the data flow
+direction [in], [out] or [in,out] is indicated in the brackets after the
+@@param command keyword.
+
+Return values can be documented in two alternative manners, either
+using @@return command (see @ref orch "orch()") or @@retval command. The
+latter is used if the function returns a small number of possible
+values, e.g., enumeration or success/failure indication.
+
+ at verbatim
+/**Schadule hearping.
+ *
+ * The function schadule() schadules a hearping.
+ *
+ * @param[in] h pointer to hearping
+ *
+ * @retval 0 hearping was successful
+ * @retval -1 an error occurred
+ */
+int schadule(hearping_t *h)
+{
+ ...
+}
+ at endverbatim
+
+ at subsection doxyexamples Example Blocks - @code, @endcode
+
+An example code fragment can be included using @@code and @@endcode
+commands.
+ at verbatim
+/**Destroy a hearping.
+ *
+ * The function hearping_destroy() deinitializes a hearping and
+ * reclaims the memory allocated for it.
+ *
+ * @param[in,out] h pointer to pointer to hearping
+ *
+ * The function clears the pointer to hearping, so it must be called
+ * with a pointer to pointer:
+ * @code
+ * hearping_destroy(&x->hearping);
+ * @endcode
+ */
+void hearping_destroy(hearping_t **h)
+{
+ at endverbatim
+
+ at subsection docpar Paragraphs
+
+The command @@par can be used to divide text into paragraphs. The text on
+the same line with @@par is used as a subtitle for the paragraph. The
+commands @@date, @@note, @@bug, @@todo, @@sa (See Also) and
+@@deprecated can be used to add common paragraphs to documentation entries.
+
+ at subsection docfiles Documenting Files
+
+In most files there is documentation entry for the file itself. It is
+usually at top after the LGPL reference, containing @@file command or alias
+@@CFILE/@@IFILE. There are Emacs macros for creating the boilerplate entry.
+
+ at subsection docgrouping Grouping Entries
+
+When the structure of the documentation does not follow directory or file
+structure, it is possible to use grouping commands @@defgroup and @@ingroup.
+The command @@defgroup creates a group, and @@ingroup adds an entry to an
+group.
+
+ at subsection doclinking Creating Links
+
+Normally, Doxygen creates links to classes (and C structs) when it
+encounters the struct/class name. It is also possible to add links to
+functions, type names and variables. If the function name is followed by
+pair of parenthesis (), Doxygen creates a link to it. If a type name or
+variable is prefixed with hash @#, Doxygen creates a link to it.
+
+It is also possible to create links with freely selected link to
+documentation entries with @@link and @@endlink commands.
+
+When the link target is a named page, section, or subsection, it is possible
+to use the @@ref command.
+
+ at subsection doctext Writing Body Text
+
+The main body of the documentation is specified with @@mainpage command. The
+contents of the @@mainpage entry become the HTML home page of the
+documentation set. In each documentation set generated with Doxygen there
+can be only one @@mainpage command. Commands @@section, @@subsection, and
+@@subsubsection can be used to structure the body text.
+
+It is also possible to add individual HTML pages to the documentation. It
+happens with @@page command. These individual pages are like the home page
+added with @@mainpage, they can be accessed with the Related Pages link from
+the navigation bar.
+
+ at subsection docimages Adding Images
+
+Images are added with @@image command. As the different documentation
+formats support different image formats, the @@image has list the image file
+name for each supported documentation format. The following example uses
+bitmap image for HTML documentation and Encapsulate PostScript for
+print documents:
+ at code
+ at image html sip-parser.gif
+
+ at image latex sip-parser.eps
+ at endcode
+
+*/
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/hide_emails.sh
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/hide_emails.sh Thu Dec 21 01:30:28 2006
@@ -0,0 +1,37 @@
+#!/bin/sh
+#
+# description: Mangle email addresses in the HTML documentation
+# author: Kai Vehmanen <kai.vehmanen at nokia.com>
+# version: 20050908-3
+#
+# --------------------------------------------------------------------
+#
+# This file is part of the Sofia-SIP package
+#
+# Copyright (C) 2005 Nokia Corporation.
+#
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+#
+# --------------------------------------------------------------------
+
+find . -name '*.html' -print | while read i ; do
+ (
+ echo "Hiding email addresses in ${i}."
+ sed -r -i 's/([:>;][a-z][-a-z.]*)(@[a-z][a-z]*)\.[a-z][a-z]*(["<\&])/\1\2-email.address.hidden\3/gi' $i
+ )
+done
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/mainpage.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/mainpage.docs Thu Dec 21 01:30:28 2006
@@ -0,0 +1,740 @@
+/* -*- text -*- */
+
+/**@mainpage Sofia SIP User Agent Library - sofia-sip-ua
+
+ at section Introduction
+
+This document contains automatically generated reference documentation
+for Sofia-SIP components. Some introductory material and
+pointers to the example code are also included.
+
+For a list of module specific pages, see @ref subdirs
+"source tree structure" or direct links to submodules:<br>
+<a href="nua/index.html">nua</a>
+<a href="su/index.html">su</a>
+<a href="features/index.html">features</a>
+<a href="soa/index.html">soa</a>
+<a href="sdp/index.html">sdp</a>
+<a href="nta/index.html">nta</a>
+<a href="tport/index.html">tport</a>
+<a href="sresolv/index.html">sresolv</a>
+<a href="sip/index.html">sip</a>
+<a href="msg/index.html">msg</a>
+<a href="url/index.html">url</a>
+<a href="stun/index.html">stun</a>
+<a href="iptsec/index.html">iptsec</a>
+<a href="nea/index.html">nea</a>
+<a href="nth/index.html">nth</a>
+<a href="http/index.html">http</a>
+<a href="bnf/index.html">bnf</a>
+<a href="ipt/index.html">ipt</a>
+
+ at section who Contact Information
+
+You can download latest Sofia SIP from the project
+<a href="http://sofia-sip.sf.net">home page</a> at
+<a href="sf.net">Sourceforge.net</a>.
+
+Please contact us if you have questions regarding this software:
+
+<ul>
+<li>Pekka Pessi <Pekka.Pessi at nokia.com></li>
+<li>Kai Vehmanen <Kai.Vehmanen at nokia.com></li>
+</ul>
+
+Or post to the Sofia-SIP mailing list:
+
+<ul>
+<li>mailto:sofia-sip-devel at lists.sourceforge.net</li>
+<li>http://lists.sourceforge.net/lists/listinfo/sofia-sip-devel</li>
+</ul>
+
+*/
+
+/**@page building Source Tree Structure
+
+ at section subdirs Directory Structure
+
+In libsofia-sip-ua, there are subdirectories
+
+Terminal and high-level libraries utilizing for both signaling and media:
+
+Common runtime library:
+ - <a href="su/index.html">"su" - sockets, memory management, threads</a>
+ - <a href="sresolv/index.html">"sresolv" - Asynchronous DNS resolver</a>
+ - <a href="ipt/index.html">"ipt" - IPT utility library</a>
+
+SIP Signaling:
+ - <a href="nua/index.html">"nua" - SIP User Agent library</a>
+ - <a href="nea/index.html">"nea" - SIP Event API</a>
+ - <a href="iptsec/index.html">"iptsec" -
+ Digest authentication for HTTP and SIP</a>
+ - <a href="nta/index.html">"nta" - SIP transaction engine</a>
+ - <a href="tport/index.html">"tport" - Message transport</a>
+ - <a href="sip/index.html">"sip" - SIP messages and headers</a>
+ - <a href="msg/index.html">"msg" - Message handling </a>
+ - <a href="url/index.html">"url" - URL handling</a>
+ - <a href="bnf/index.html">"url" - low level parsing</a>
+
+HTTP subsystem:
+ - <a href="nth/index.html">"nth" - HTTP protocol engine</a>
+ - <a href="http/index.html">"http" - HTTP messages and headers</a>
+
+SDP processing:
+ - <a href="soa/index.html">"soa" - SDP Offer/Answer engine for SIP</a>
+ - <a href="sdp/index.html">"sdp" - SDP parser</a>
+
+Other:
+ - <a href="stun/index.html">"stun" - STUN library</a>
+
+Features provided by Sofia-SIP library:
+ - <a href="features/index.html">"features" - Features provided by Sofia SIP</a>
+
+Documentation:
+ - "docs" - Doxygen reference documentation
+
+*/
+
+/**
+ at page styleguide C Style Guide
+
+This document gives general guidelines on generic C style and code
+formatting within Sofia-SIP. The guidelines include identifier naming
+conventions, indenting convention, and tool usage directions.
+
+Please note that C style is always a matter of taste.
+
+ at section naming Naming Conventions
+
+Generally, identifiers within each module are prefixed with the name of
+that module. For instance, the functions within http parser module @b http
+have prefix @c http_. Identifiers composed of multiple words have an
+underscore "_" between the words, the words themselves are in lower
+case. For instance, http_request_create().
+
+Macros should be in upper case. File names should be in lower case using
+underscore as delimiter if needed.
+
+Normal typedefs have suffix @c _t, however, function types have suffix @c
+_f. The enum names also sometimes have @c _e, struct names have @c _s and
+union names @c _u.
+
+It is recommended that type itself is typedef'ed, not a pointer to the
+type. It should be clear from variable declaration if the variable is a
+pointer or not.
+
+ at code
+typedef struct foo_s foo_t;
+typedef int f_fun(foo_t *f, char const *s);
+ at endcode
+
+Struct and union members should have common prefix. For instance,
+ at code
+struct foo_s {
+ int f_len;
+ char *f_name;
+ fun_f *f_fun;
+};
+ at endcode
+
+This prefix makes it easier to find where members are used.
+
+ at section formatting Indenting and Formatting code
+
+Indentation in Sofia-SIP C code generally follows the @e K&R style with indent
+of 2 characters (so you can use the default "GNU" c-style in Emacs). The
+maximum line length should be 80 characters.
+
+For example,
+
+ at code
+void kluge(int foo)
+{
+ if (foo) {
+ bar();
+ }
+ else {
+ switch (baz()) {
+ case a:
+ eeny();
+ break;
+ case b:
+ meeny();
+ break;
+ default:
+ moe();
+ break;
+ }
+ }
+}
+ at endcode
+
+The default indentation can be achieved with GNU indent with options
+ at code
+-nbad -bap -bbo -nbc -br -brs -c33 -cd33 -ncdb -ce -ci2 -cli0 -cp33 -cs
+-d0 -di1 -nfc1 -nfca -hnl -i2 -ip0 -l79 -lp -npcs -nprs -npsl -saf -sai
+-saw -nsc -nsob -nss
+ at endcode
+
+Loops without condition use @c for @c (;;) instead of @c while @c (1).
+
+ at code
+ for (;;) {
+ foo();
+ if (bar())
+ break;
+ baz();
+ }
+ at endcode
+
+There should be whitespace on both sides of infix operators, except
+<code>.</code> or <code>-></code>, which require no space, or
+<code>,</code> (comma) which requires space only after). There should be
+whitespace between a keyword and parenthesis following it, but no
+whitespace between an identifier and parenthesis following it. E.g.,
+
+ at code
+ while (i++ < n)
+ baz();
+ for (;;) {
+ x->x_foo();
+ if (bar())
+ break;
+ z.z_baz++;
+ }
+ return (13 * i);
+ at endcode
+
+ */
+
+/**
+ at page programming Programming Guide
+
+ at section porting Writing Portable Code
+
+Most of Sofia-SIP software is written as portable. All core modules are
+(or at least should be) written in ANSI C 89 with some ANSI C 99
+features. If there are platform specific parts, they are collected to
+separate C files and isolated from the rest of the software with a
+wrapper interface.
+
+SU module handles abstraction to OS specific functionality such as
+memory management, sockets, threads and time functions.
+
+ at subsection ansi_99 ANSI C 99 features
+
+The following ANSI C 99 features are to be used in Sofia-SIP software:
+- Integer types
+- functions va_copy() and snprintf()
+
+The following ANSI C 99 features shall not be used in Sofia-SIP software:
+- definition of a variable in the middle of function code.
+ (so always define your variables in the beginning of the block)
+
+ at subsection port_ints Integer Types
+
+As you should know, the length of native storage size depends on hardware,
+OS and compiler. This means in practice that the length of int or long is
+not necessarily 32 bits. As a consequence, you need to make sure that the
+value you intend to store in the int, can actually fit in int on different
+platforms. As a rule of thumb, if the integer value can exceed 8 bits, you
+should use types that have a defined length.
+
+Nevertheless its OK to use native integer types if you bear in mind
+what was said above. The original reason for having only native
+data type was performance. The int type is always stored in the
+fastest (and usually biggest size) possible.
+
+Never assume anything on the length of the type. Alway use sizeof()
+operator to find out the length.
+
+C 99 standard defines the following fixed length data types:
+
+- int64_t
+- uint64_t
+- int32_t
+- uint32_t
+- int16_t
+- uint16_t
+- int8_t
+- uint8_t
+
+To use these data types you must include the <su_types.h> header, which
+takes care of including correct file. If @b su includes are not available,
+you must include the following code segment to each file where you plan to
+use them:
+
+ at code
+#if HAVE_STDINT_H
+#include <stdint.h>
+#elif HAVE_INTTYPES_H
+#include <inttypes.h>
+#else
+#error Define HAVE_STDINT_H as 1 if you have <stdint.h>, \
+ or HAVE_INTTYPES_H if you have <inttypes.h>
+#endif
+ at endcode
+
+ at subsection port_byte_sex Byte order
+
+The host byte order on different platforms vary. When you do only
+local processing, need not to worry about the byte order. But as
+soon as you start writing code that send or receives anything to
+the network, you need to start worrying.
+
+If you wish to convert the byte order, it is simply done by calling
+one the following functions:
+
+The htonl() function converts the unsigned integer hostlong from
+host byte order to network byte order.
+
+The htons() function converts the unsigned short integer hostshort
+from host byte order to network byte order.
+
+The ntohl() function converts the unsigned integer netlong from
+network byte order to host byte order.
+
+The ntohs() function converts the unsigned short integer netshort
+from network byte order to host byte order.
+
+You need to include <netinet/in.h> or <su.h> to use these functions.
+
+ at subsection port_struct Packing structures
+
+By default, compilers usually arrange structures so that they are
+quick to access. This means that most fields in the structure start
+at the 32 bit boundary. If you need to conserve memory, you may use
+structure packing.
+
+To tell the compiler that you only need certain amount of bits to
+store a variable, you can use bit-fields. Compiler may or may not
+pack the bit-fields.
+
+ at code
+struct foo {
+ unsigned bar:5;
+ unsigned foo:2;
+ unsigned :0;
+ int something;
+}
+ at endcode
+
+If compiler decides to pack this structure, this code generates a
+structure that has @a bar and @a foo in the first seven bits, and then
+ at a something beginning from the next 32 bit boundary.
+
+One problem arises when using packed bit-fields: on ARM it is
+generally not possible to access a 32 bit field that does not start from
+the 32-bit boundary. Hence the example has the :0 padding member in the
+structure. Seems handy but beware: initialization of this structure fails
+on some ARM gcc compilers. (Ask Kai Vehmanen for details).
+
+A way to force packing of a structure is to use preprocessor
+directive @c @#pragma(pack). This directive is compiler specific, so if
+you plan to write truly portable code, you cannot use it. We have
+used it in some parts of the Sofia-SIP though. Only alternative is to
+write functions that fetch the desired bits from a 32 bit field
+with bit operations; not very handy and error prone.
+
+The same aligment problem also arises if you cast for example char
+buffer to a int32_t. You can only read int32_t from the 32bit boundary
+on ARM platform. So be careful.
+
+As a conclusion, when using bit-fields and stucture packing, beware
+of the pitfalls. If you don't really need to use them (as in parsing
+binary protocols), don't use them.
+
+ at section file_organization File and Directory Structure
+
+A Sofia-SIP library module can be defined as a subdirectory under the
+libsofia-sip-ua directory hierarchy that contains a file \<modulename\>.docs
+(where the \<modulename\> of course referes to the actual name of
+the module).
+
+In case you like to start developing a new module, please
+contact Sofia-SIP development team so that they can help you to set up
+the basic module for you.
+
+An overview of the contents of a module directory:
+ - file \<modulename\>.docs \n
+ Main documentation file for the module. See @ref module_docs
+ for more information
+ - subdirectory pictures \n
+ Contains any pictures/images
+ that are needed by the module documentation. The
+ file formats to use are GIF (for html pages) and
+ EPS (for latex). If some program (e.g. MS Visio) is
+ used to create the pictures, also the original
+ files must be stored here.\n
+ (Note that old modules may have "images" subdirectory instead of
+ "pictures")
+ - files Makefile.am \n
+ See section @ref build "dealing with GNU Autotools" below.
+ - (optionally) source code file(s) of the module and module tests.
+ The source code file(s) can also be located in subdirectories if necesary.
+
+
+ at section oo_with_c Writing Object-Oriented Code
+
+While C does not provide any special object-oriented features on its own, it
+is possible to program in object-oriented way using C, too. Sofia code make
+use of many object-oriented features while being written entirely in C.
+
+ at subsection oo_hiding Data Hiding
+
+Data hiding is a practice that makes separation between two modules very
+clear. Outside code cannot directly access the data within a module, but it
+has to use functions provided for that purpose. Data hiding also makes it
+easier to define a protocol between two objects - all communication happens
+using function calls.
+
+How to implement data hiding in C? Easiest answer is to only declare data
+structures in the header files, not to define them. We have a typedef #msg_t
+for @link msg_s struct msg_s @endlink in <sofia-sip/msg.h>, but the actual
+structure is defined in "msg_internal.h". Programs outside @b msg module
+does not have access to the @link msg_s struct msg_s @endlink, but they have
+to to access the #msg_t object through method functions provided in
+<sofia-sip/msg.h>. The @b msg implementation is also free to change the
+internal layout of the structure, only keeping the function interface
+unmodified.
+
+ at subsection oo_interface Interfaces
+
+Abstract interface is another object-oriented practice used in Sofia. Parser
+headers, defined in <sofia-sip/msg_types.h>, is a good example of abstract
+interface. The type for message headers, #msg_header_t, is defined using two
+C structures @link msg_common_s struct msg_common_s @endlink
+(#msg_common_t), and @link msg_hclass_s struct msg_hclass_s @endlink
+(#msg_hclass_t).
+
+Abstract interface is achieved using virtual function table in #msg_hclass_t
+structure, bit like C++ typically implements abstract classes and virtual
+functions. For implemenation of each header, the function table is
+initialized with functions responsible for decoding, encoding and
+manipulating the header structure. Unlike C++, the class of the object
+(#msg_hclass_t) is represented by a real data structure which also contains
+header-specific data, like header name.
+
+ at dontinclude sip_basic.c
+ at skipline msg_hclass_t sip_contact_class
+ at skip {{
+ at until }};
+
+ at subsection oo_derived Inheritance and Derived Objects
+
+Inheritance is a object-oriented practice that has limited use in Sofia.
+Most common example of inheritance is use of #su_home_t. Many objects are
+derived from #su_home_t, which means that they can use the various
+home-based memory management functions from <su_alloc.h>.
+
+In this sence, inheritance means that a pointer to a derived object can be
+casted as a pointer to a base object. In other words, the derived object
+must have the base object at the beginning of its memory area:
+
+ at code
+struct derived
+{
+ struct base base[1];
+ int extra;
+ char *data;
+};
+ at endcode
+
+There are three alternatives to cast a pointer to derived to a pointer to
+base:
+ at code
+struct base *base1 = (struct base *)derived;
+struct base *base2 = &derived->base;
+struct base *base3 = derived->base;
+ at endcode
+The third alternative works because base was used as a 1-element array.
+
+ at subsection oo_templates Templates
+
+There are a few template types implemented as macros in Sofia libraries.
+They include hash table, defined in <sofia-sip/htable.h>, which can be used
+to define hash tables types and accessor functions for different object, and
+red-black tree, defined in <sofia-sip/rbtree.h>.
+
+ at section memory Memory Management
+
+The home-based memory management is useful when a lot of memory blocks are
+allocated for given task. The allocations are done via the memory home,
+which keeps a reference to each allocated memory block. When the memory
+home is then freed, it will free all memory blocks to which it has
+reference. This simplifies application logic because application code does
+not need to keep track of the allocated memory and free every allocated block
+separately.
+
+See documentation of <su_alloc.h> and @ref su_alloc "memory managment tutorial"
+for more information of memory management services.
+
+ at subsection contextdata Memory management of context data
+
+A typical example of use of a memory home is to have a memory home structure
+(#su_home_t) as part of operation context information structure.
+
+ at code
+ /* context info structure */
+ struct context {
+ su_home_t ctx_home[1]; /* memory home */
+ other_t *ctx_other_stuff; /* example of memory areas */
+ ...
+ };
+
+ /* context pointer */
+ struct context *ctx;
+
+ /* Allocate memory for context structure and initialize memory home */
+ ctx = su_home_clone(NULL, sizeof (struct context));
+
+ /* Allocate memory and register it with memory home */
+ ctx->ctx_other_stuff = su_zalloc(ctx->ctx_home, sizeof(other_t));
+
+ ... processing and allocating more memory ...
+
+ /* Release registered memory areas, home, and context structure */
+ su_home_zap(ctx->ctx_home);
+
+ at endcode
+
+ at subsection combining Combining allocations
+
+Another place where home-based memory management makes programmers
+life easier is case where a sub-procedure makes multiple memory allocations
+and, in case the sub-procedure fails, all the allocations must be released
+and, in case the sub-procedure is succesfull, all allocations must be
+controlled by upper level memory management.
+
+ at code
+ /* example sub-procedure. top_home is upper-level memory home */
+ int sub_procedure( su_home_t *top_home, ... )
+ {
+ su_home_t temphome[1] = { SU_HOME_INIT(temphome) };
+
+ ... allocations and other processing ...
+
+ /* was processing successfull ? */
+ if (success) {
+ /* ok -> move registered allocated memory to upper level memory home */
+ su_home_move( top_home, temphome );
+ }
+ /* destroy temporary memory home (and registered allocations) */
+ /* Note than in case processing was succesfull the memory */
+ /* registrations were already moved to upper level home. */
+ su_home_deinit(temphome);
+
+ /* return ok/not-ok */
+ return success;
+ }
+ at endcode
+
+ at section testing Testing Your Code
+
+See <tstdef.h> for example of how to write module tests with macros provided
+by Sofia.
+
+Here are some ideas of what you should test:
+- "Smoke test" \n
+ See that the module compiles, links and executes.
+- Module API functions should be tested with\n
+ - valid args
+ - not valid args
+- Aim for 100% line coverage\n
+ (If there is a line of code that you have not tested, you don't know
+ if its working.) \n
+ For selected part of code you should also aim for
+ 100% branch/path coverage.\n
+ But be anyway reasonable with these because in practise complete
+ coverage is next to impossible to achive (so 80% is ok in practise).
+- Create test to check assumptions and/or tricks used in code.\n
+ For example if you rely on some compiler feature, create a test that
+ will fail with a compiler that does not have that feature.
+
+ at subsection check Running Module Tests
+
+Automake, which is used to build Sofia SIP, has builtin
+support for unit tests. To add an automatically run test to your module,
+you just have to add the following few lines to your module's Makefile.am
+(of course, you have to write the test programs, too):
+
+ at code
+TESTS = test_foo test_bar
+
+check_PROGRAMS = test_foo test_bar
+
+test_foo_SOURCES = foo.c foo.h
+test_foo_LDADD = -L. -lmy
+
+test_bar_SOURCES = bar.c bar.h
+test_foo_LDADD = -L. -lmy
+ at endcode
+
+Each test program should either return zero for success or a non-zero
+error code in its main function. Now when you run "make check",
+ at b my_test_foo and @b my_test_bar will be built and then run.
+Make will print a
+summary of how the tests went. As these tests are run from the build
+system, the tests must be non-interactive (no questions asked) and not
+rely on any files that are not in version control system.
+
+Sofia SIP's top-level makefile contains a recursive check target, so
+you can use "cd sofia-sip ; make check" to run all the existing tests
+with a single command.
+
+ at section build Dealing with GNU Autotools
+
+Sofia-SIP build system is based on the GNU tools automake, autoconf and
+libtool. This toolset has become the de-facto way of building Linux
+software. Because of this there is a lot of publicly available documentation
+about these tools, and of course, lots and lots of examples.
+
+A good introduction to these tools is available at
+<a href="http://developer.gnome.org/doc/books/WGA/generating-makefiles.html">
+developer.gnome.org</a>. <a href="http://sources.redhat.com/autobook">Autobook</a>
+provides more detailed documentation for autoconf and automake.
+The <a href="http://www.gnu.org/manual/make/">GNU make manual</a>
+is also a good source of information.
+
+ at subsection autogen_sh autogen.sh
+
+At top-level there is a shell script called @b autogen.sh. It calls a
+convenient tool called @b autoreconf which will generate configure script
+for you. It also fixes the mode bits: the mode bits are not stored in
+<a href="http://darcs.net">darcs</a> version control system.
+
+ at code
+$ sh autogen.sh
+$ ./configure ... with your configure options ...
+ at endcode
+
+ at subsection configure_ac configure.ac
+
+The @b configure.ac file (older autoconf versions used also @b configure.in)
+contains the primary configuration for autoconf. configure.ac contains
+checks for all external libraries, non-standard language and compiler
+features that are needed to build the target module.
+
+This file is created by the developer of the module.
+
+ at subsection sofia_m4 m4 files
+
+Sofia-SIP's own autoconf macros are stored in the top-level direcry called @b
+m4. These macros, along with all other macros used by @b configure.ac, are
+copied into the module-specific @b aclocal.m4 file by an utility called
+aclocal.
+
+Contact Sofia-SIP development team, if you need changes to these files.
+
+ at subsection aclocal_m4 aclocal.m4
+
+The aclocal.m4 contains the definitions of the autoconf macros used in
+ at b configure.ac.
+
+This file is generated by aclocal command.
+
+ at subsection Makefile_am Makefile.am
+
+Makefile.am is where you define what programs and libraries should
+be built, and also what source files are needed to create them.
+When you run automake, it creates the file Makefile.in.
+
+This file is created by the developer of the module.
+
+ at subsection configure configure
+
+When you run configure script, it performs all the checks defined in
+ at b configure.ac and then replaces all @b xxx.in files with equivalent
+ at b xxx files. All @c @@FOO@@ variables in the source @b *.in files are
+replaced with values found during the configuration process. For instance
+the variable @c @@srcdir@@ in @b Makefile.in is replaced in @b Makefile
+with the source directory path (useful when compiling outside the main
+source tree).
+
+This file is generated by autoconf command.
+
+ at subsection config_status config.status
+
+This script stores the last parameters given to configre command.
+If necessary you can rerun the last given configure script (with given
+parameters) by using command "./config.status -r" or
+"./config.status --recheck".
+
+This file is generated by configure script.
+
+ at subsection config_cache config.cache
+
+This file contains results of the various checks that configure script
+performed. In case the configure script failed, you might try to
+delete this file and run the configure script again.
+
+This file is generated by configure script.
+
+ at subsection Makefile Makefile
+
+The @b Makefile contains the actual rules how to build the target
+libraries and program. It is used by the @c make program. @b Makefile
+is generated from @b Makefile.in when you run @c autoconf command.
+Ensure that "make dist" and "make install" targets work.
+
+This file is generated by config.status and configure scripts.
+
+ at subsection config_h config.h
+
+This file contains C language defines of various confurable issues.
+
+This file is generated by config.status and configure script.
+
+ at subsection sofia_sip_configure_h sofia-sip/su_configure.h
+
+This file contains C language defines describing how the Sofia SIP UA
+library is configured.
+
+This file is generated by config.status and configure script.
+
+*/
+
+/**
+ at page debug_logs Debugging Logs
+
+The Sofia-SIP components can output various debugging information. The
+detail of the debugging output is determined by the debugging level. The
+level is usually module-specific and it can be modified by module-specific
+environment variable. There is also a default level for all modules,
+controlled by environment variable #SOFIA_DEBUG.
+
+The environment variables controlling the logging and other debug output are
+as follows:
+- #SOFIA_DEBUG Default debug level (0..9)
+- #NUA_DEBUG User Agent engine (<a href="nua/index.html">nua</a>) debug level (0..9)
+- #SOA_DEBUG SDP Offer/Answer engine (<a href="soa/index.html">soa</a>) debug level (0..9)
+- #NEA_DEBUG Event engine (<a href="nea/index.html">nea</a>) debug level (0..9)
+- #IPTSEC_DEBUG HTTP/SIP autentication module debug level (0..9)
+- #NTA_DEBUG Transaction engine debug level (0..9)
+- #TPORT_DEBUG Transport event debug level (0..9)
+ - #TPORT_LOG If set, print out all parsed SIP messages on transport layer
+ - #TPORT_DUMP Filename for dumping unparsed messages from transport
+- #SU_DEBUG <a href="nea/index.html">su</a> module debug level (0..9)
+
+The defined debug output levels are:
+- 0 SU_DEBUG_0() - fatal errors, panic
+- 1 SU_DEBUG_1() - critical errors, minimal progress at subsystem level
+- 2 SU_DEBUG_2() - non-critical errors
+- 3 SU_DEBUG_3() - warnings, progress messages
+- 5 SU_DEBUG_5() - signaling protocol actions (incoming packets, ...)
+- 7 SU_DEBUG_7() - media protocol actions (incoming packets, ...)
+- 9 SU_DEBUG_9() - entering/exiting functions, very verbatim progress
+
+In addition to the macros mentioned above, there is also functions for
+printing logging messages:
+- su_llog(), su_vllog()
+- su_perror(), su_perror2()
+
+The log level can be set (to a level defined in a configuration file, for
+instance) with following functions
+- su_log_set_level(), su_log_soft_set_level()
+
+The log output can be redirected to, e.g., system log or loggin server, with
+su_log_redirect().
+
+*/
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_basic_incoming_operation.eps
==============================================================================
Binary file. No diff available.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_basic_incoming_operation.gif
==============================================================================
Binary file. No diff available.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_basic_incoming_operation.vsd
==============================================================================
Binary file. No diff available.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_basic_outgoing_operation.eps
==============================================================================
Binary file. No diff available.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_basic_outgoing_operation.gif
==============================================================================
Binary file. No diff available.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_basic_outgoing_operation.vsd
==============================================================================
Binary file. No diff available.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_incoming_call.eps
==============================================================================
Binary file. No diff available.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_incoming_call.gif
==============================================================================
Binary file. No diff available.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_incoming_call.vsd
==============================================================================
Binary file. No diff available.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_outgoing_call.eps
==============================================================================
Binary file. No diff available.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_outgoing_call.gif
==============================================================================
Binary file. No diff available.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_outgoing_call.vsd
==============================================================================
Binary file. No diff available.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_outgoing_operation_with_auth.eps
==============================================================================
Binary file. No diff available.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_outgoing_operation_with_auth.gif
==============================================================================
Binary file. No diff available.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_outgoing_operation_with_auth.vsd
==============================================================================
Binary file. No diff available.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/autotools.eps
==============================================================================
Binary file. No diff available.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/autotools.gif
==============================================================================
Binary file. No diff available.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/autotools.vsd
==============================================================================
Binary file. No diff available.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/nta-receiving-message.eps
==============================================================================
Binary file. No diff available.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/pictures/nta-receiving-message.gif
==============================================================================
Binary file. No diff available.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/sofia-footer.html.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/sofia-footer.html.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1,4 @@
+<hr />
+Sofia-SIP @VERSION@ -
+Copyright (C) 2006 Nokia Corporation. All rights reserved.
+Licensed under the terms of the GNU Lesser General Public License.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/ChangeLog Thu Dec 21 01:30:28 2006
@@ -0,0 +1,32 @@
+2005-10-27 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Fixed features.
+ Added libfeatures.la into .so. Renamed sofia_has_* as sofia_sip_has_*. Using
+ features in nua_cli.c
+
+ M ./libsofia-sip-ua/Makefile.am +1
+ M ./libsofia-sip-ua/features/Makefile.am -2 +2
+ M ./libsofia-sip-ua/features/sofia_sip_features.c -14 +14
+ M ./libsofia-sip-ua/features/sofia_sip_features.docs -10 +10
+ M ./libsofia-sip-ua/features/sofia_sip_features.h.in -10 +10
+ M ./libsofia-sip-ua/stun/stun.c -2 +2
+ M ./utils/Makefile.am -1 +2
+ M ./utils/nua_cli.c -2 +29
+
+ * Added "features" module.
+
+ ./libsofia-sip-ua/nua/sofia_config.c -> ./libsofia-sip-ua/sofia/sofia_sip_features.c
+ ./libsofia-sip-ua/nua/sofia_config.h.in -> ./libsofia-sip-ua/sofia/sofia_sip_features.h.in
+ ./libsofia-sip-ua/sofia -> ./libsofia-sip-ua/features
+ M ./configure.ac -2 +3
+ M ./libsofia-sip-ua/Makefile.am -1 +1
+ A ./libsofia-sip-ua/features/Doxyfile
+ A ./libsofia-sip-ua/features/Makefile.am
+ M ./libsofia-sip-ua/features/sofia_sip_features.c -21 +78
+ A ./libsofia-sip-ua/features/sofia_sip_features.docs
+ M ./libsofia-sip-ua/features/sofia_sip_features.h.in -15 +20
+ M ./libsofia-sip-ua/nua/Makefile.am -4 +3
+ A ./libsofia-sip-ua/sofia/
+ M ./libsofia-sip-ua/stun/stun.c -1 +6
+ M ./libsofia-sip-ua/stun/stun.h +2
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/Doxyfile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/Doxyfile Thu Dec 21 01:30:28 2006
@@ -0,0 +1,22 @@
+PROJECT_NAME = "features"
+OUTPUT_DIRECTORY = ../docs/html/features
+
+INPUT = features.docs sofia-sip .
+
+ at INCLUDE = ../docs/Doxyfile.conf
+
+TAGFILES += ../docs/docs.doxytags=..
+TAGFILES += ../docs/su.doxytags=../su
+TAGFILES += ../docs/ipt.doxytags=../ipt
+TAGFILES += ../docs/bnf.doxytags=../bnf
+TAGFILES += ../docs/url.doxytags=../url
+TAGFILES += ../docs/msg.doxytags=../msg
+TAGFILES += ../docs/sip.doxytags=../sip
+TAGFILES += ../docs/sresolv.doxytags=../sresolv
+TAGFILES += ../docs/tport.doxytags=../tport
+TAGFILES += ../docs/nta.doxytags=../nta
+TAGFILES += ../docs/sdp.doxytags=../sdp
+
+GENERATE_TAGFILE = ../docs/features.doxytags
+
+ALIASES +=
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/Makefile.am Thu Dec 21 01:30:28 2006
@@ -0,0 +1,34 @@
+#
+# Makefile.am for sofia features module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+INCLUDES = $(INTERNAL_INCLUDES)
+
+# ----------------------------------------------------------------------
+# Build targets
+
+noinst_LTLIBRARIES = libfeatures.la
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+
+# This is used by platforms not supporting autoconf
+nobase_include_sofia_HEADERS = sofia-sip/sofia_features.h
+
+libfeatures_la_SOURCES = features.c
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+
+EXTRA_DIST = Doxyfile features.docs
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+
+include ../sofia.am
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/Makefile.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1,588 @@
+# 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.
+
+ at SET_MAKE@
+
+#
+# Makefile.am for sofia features module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+# common Makefile targets for libsofia-sip-ua modules
+# ---------------------------------------------------
+
+
+SOURCES = $(libfeatures_la_SOURCES)
+
+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@
+DIST_COMMON = $(nobase_include_sofia_HEADERS) $(srcdir)/../sofia.am \
+ $(srcdir)/Makefile.am $(srcdir)/Makefile.in ChangeLog
+subdir = libsofia-sip-ua/features
+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 =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libfeatures_la_LIBADD =
+am_libfeatures_la_OBJECTS = features.lo
+libfeatures_la_OBJECTS = $(am_libfeatures_la_OBJECTS)
+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 = $(libfeatures_la_SOURCES)
+DIST_SOURCES = $(libfeatures_la_SOURCES)
+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|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(include_sofiadir)"
+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 = $(INTERNAL_INCLUDES)
+
+# ----------------------------------------------------------------------
+# Build targets
+noinst_LTLIBRARIES = libfeatures.la
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+
+# This is used by platforms not supporting autoconf
+nobase_include_sofia_HEADERS = sofia-sip/sofia_features.h
+libfeatures_la_SOURCES = features.c
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+EXTRA_DIST = Doxyfile features.docs
+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
+
+all: 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/features/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu libsofia-sip-ua/features/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-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
+libfeatures.la: $(libfeatures_la_OBJECTS) $(libfeatures_la_DEPENDENCIES)
+ $(LINK) $(libfeatures_la_LDFLAGS) $(libfeatures_la_OBJECTS) $(libfeatures_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/features.Plo at am__quote@
+
+.c.o:
+ at am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+ at am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ at am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at 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
+
+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
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(include_sofiadir)"; do \
+ test -z "$$dir" || $(mkdir_p) "$$dir"; \
+ done
+install: 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."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool 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-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-info-am uninstall-nobase_include_sofiaHEADERS
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool 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-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-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) $<
+
+ at ENABLE_COVERAGE_TRUE@coverage:
+ at 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)
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+# 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:
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/features.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/features.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,138 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE features.c
+ * Provide features available through the sofia-sip library.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Mon Oct 24 14:51:32 2005 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+
+#include <sofia-sip/su_configure.h>
+#include <tport_tls.h>
+#include "sofia-sip/sofia_features.h"
+
+/** The name and version of software package providing Sofia-SIP-UA library.
+ * @showinitializer
+ */
+char const * const sofia_sip_name_version = SOFIA_SIP_NAME_VERSION;
+
+/** The name and version of software package providing S/MIME functionality,
+ * NULL if none.
+ */
+char const * sofia_sip_has_smime;
+
+
+/** The name and version of software package providing TLS functionality,
+ * NULL if none.
+ *
+ * TLS over TCP is used as transport for SIP messages when using SIPS
+ * scheme. Using TLS over TCP with SIP is described in @RFC3261.
+ */
+#if HAVE_OPENSSL
+char const * sofia_sip_has_tls = tls_version;
+#else
+char const * sofia_sip_has_tls;
+#endif
+
+/** The name and version of software package providing DTLS functionality,
+ * NULL if none.
+ *
+ * DTLS or TLS over datagram transport (UDP) can be used as transport for
+ * SIP messages.
+ */
+char const * sofia_sip_has_dtls;
+
+/** The name and version of software package providing TLS over SCTP functionality,
+ * NULL if none.
+ *
+ * TLS over SCTP can be used as transport for SIP messages.
+ */
+char const * sofia_sip_has_tls_sctp;
+
+#if HAVE_SOFIA_SIGCOMP
+#include <sigcomp.h>
+#endif
+
+/** The name and version of software package providing SigComp functionality,
+ * NULL if none.
+ *
+ * SigComp can be used to compress SIP messages.
+ */
+#if HAVE_SOFIA_SIGCOMP
+char const * sofia_sip_has_sigcomp = sigcomp_package_version;
+#else
+char const * sofia_sip_has_sigcomp;
+#endif
+
+/** The name and version of software package providing STUN functionality,
+ * NULL if none.
+ *
+ * STUN is a protocol used to traverse NATs with UDP.
+ */
+#if HAVE_SOFIA_STUN
+extern char const stun_version[];
+char const * sofia_sip_has_stun = stun_version;
+#else
+char const * sofia_sip_has_stun;
+#endif
+
+/** The name and version of software package providing TURN functionality,
+ * NULL if none.
+ *
+ * TURN is a protocol used to traverse NATs or firewalls with TCP or UDP.
+ */
+char const * sofia_sip_has_turn;
+
+/** The name and version of software package providing UPnP functionality,
+ * NULL if none.
+ *
+ * UPnP (Universal Plug and Play) can be used to traverse NATs or firewalls.
+ */
+char const * sofia_sip_has_upnp;
+
+/** The name and version of software package providing SCTP functionality,
+ * NULL if none.
+ *
+ * SCTP can be used as transport for SIP messages. The software providing it
+ * can be, for example, LKSCTP (Linux kernel SCTP) for Linux.
+ */
+char const * sofia_sip_has_sctp;
+/* We don't have viable SCTP transport interface */
+
+/** The name and version of software package providing IPv6 functionality,
+ * NULL if none.
+ *
+ * IPv6 can be used to send SIP messages.
+ */
+#if SU_HAVE_IN6
+char const * sofia_sip_has_ipv6 = "IPv6";
+#else
+char const * sofia_sip_has_ipv6;
+#endif
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/features.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/features.docs Thu Dec 21 01:30:28 2006
@@ -0,0 +1,41 @@
+/* -*- text -*- */
+
+/**@MODULEPAGE "features" Module
+
+ at section features_meta Module Meta Information
+
+The @b features module provides application information about the various
+features possibly available through the @ref subdirs "sofia-sip-ua" binary API.
+
+ at CONTACT Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ at STATUS @SofiaSIP Core library
+
+ at LICENSE LGPL
+
+ at par Contributor(s):
+- Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ at section features_overview Overview
+
+The #sofia_sip_name_version contains the name and release of currently
+installed @a libsofia-sip-ua.so library. The macro #SOFIA_SIP_NAME_VERSION
+contains the name and release of currently available include files.
+
+The Sofia SIP binary API hides some protocols used under the SIP stack.
+While the binary API stays the same, the features are not necessarily there.
+These features are mainly related to encryption, compression and underlying
+transports.
+
+- #sofia_sip_has_smime
+- #sofia_sip_has_tls
+- #sofia_sip_has_dtls
+- #sofia_sip_has_tls_sctp
+- #sofia_sip_has_sigcomp
+- #sofia_sip_has_stun
+- #sofia_sip_has_turn
+- #sofia_sip_has_upnp
+- #sofia_sip_has_sctp
+- #sofia_sip_has_ipv6
+
+*/
\ No newline at end of file
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/sofia-sip/sofia_features.h.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/features/sofia-sip/sofia_features.h.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1,67 @@
+/* This -*- C -*- file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/* @configure_input@ */
+
+/**@file sofia-sip/sofia_features.h
+ * @brief Sofia-SIP Library Features
+ *
+ * Macros and string constants listing features supported or not supported
+ * by sofia-sip-ua library.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Feb 14 17:09:44 2001 ppessi
+ */
+
+#ifndef SOFIA_SIP_FEATURES_H
+/** Defined when <sofia-sip/sofia_features.h> has been included. */
+#define SOFIA_SIP_FEATURES_H
+
+/** Current Sofia version. @showinitializer */
+#define SOFIA_SIP_VERSION "@PACKAGE_VERSION@"
+/** Current Sofia package name and version. @showinitializer */
+#define SOFIA_SIP_NAME_VERSION "@PACKAGE_NAME at -@PACKAGE_VERSION@"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+SOFIAPUBVAR char const * const sofia_sip_name_version;
+SOFIAPUBVAR char const * sofia_sip_has_smime;
+SOFIAPUBVAR char const * sofia_sip_has_tls;
+SOFIAPUBVAR char const * sofia_sip_has_dtls;
+SOFIAPUBVAR char const * sofia_sip_has_tls_sctp;
+SOFIAPUBVAR char const * sofia_sip_has_sigcomp;
+SOFIAPUBVAR char const * sofia_sip_has_stun;
+SOFIAPUBVAR char const * sofia_sip_has_turn;
+SOFIAPUBVAR char const * sofia_sip_has_upnp;
+
+SOFIAPUBVAR char const * sofia_sip_has_sctp;
+SOFIAPUBVAR char const * sofia_sip_has_ipv6;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/ChangeLog Thu Dec 21 01:30:28 2006
@@ -0,0 +1,7 @@
+2005-11-08 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Renamed http_test.c as test_http.c
+
+2005-07-18 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * Initial import of the module to Sofia-SIP tree.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/Doxyfile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/Doxyfile Thu Dec 21 01:30:28 2006
@@ -0,0 +1,18 @@
+PROJECT_NAME = "http"
+OUTPUT_DIRECTORY = ../docs/html/http
+
+INPUT = http.docs sofia-sip .
+
+ at INCLUDE = ../docs/Doxyfile.conf
+
+TAGFILES += \
+ ../docs/su.doxytags=../su \
+ ../docs/ipt.doxytags=../ipt \
+ ../docs/bnf.doxytags=../bnf \
+ ../docs/url.doxytags=../url \
+ ../docs/msg.doxytags=../msg
+
+GENERATE_TAGFILE = ../docs/http.doxytags
+
+ALIASES += \
+ "HTTP_HEADER=@ingroup http_headers\n at defgroup" \
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/Makefile.am Thu Dec 21 01:30:28 2006
@@ -0,0 +1,93 @@
+#
+# Makefile.am for http module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+INCLUDES = -I$(srcdir)/../bnf -I../bnf \
+ -I$(srcdir)/../msg -I../msg \
+ -I$(srcdir)/../url -I../url \
+ -I$(srcdir)/../su -I../su -I../su
+
+# ----------------------------------------------------------------------
+# Build targets
+
+noinst_LTLIBRARIES = libhttp.la
+
+check_PROGRAMS = test_http
+
+TESTS = test_http
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+
+PUBLIC_H = sofia-sip/http.h sofia-sip/http_header.h \
+ sofia-sip/http_parser.h sofia-sip/http_tag_class.h \
+ sofia-sip/http_status.h sofia-sip/http_hclasses.h
+
+BUILT_H = sofia-sip/http_protos.h sofia-sip/http_tag.h
+BUILT_C = http_tag.c http_tag_ref.c http_parser_table.c
+
+BUILT_SOURCES = $(BUILT_H) $(BUILT_C)
+
+nobase_include_sofia_HEADERS = $(BUILT_H) $(PUBLIC_H)
+
+libhttp_la_SOURCES = $(INTERNAL_H) \
+ http_parser.c http_header.c \
+ http_basic.c http_extra.c \
+ http_status.c http_tag_class.c \
+ $(BUILT_C)
+
+COVERAGE_INPUT = $(libhttp_la_SOURCES) $(include_sofia_HEADERS)
+
+LDADD = libhttp.la \
+ ../bnf/libbnf.la \
+ ../msg/libmsg.la \
+ ../url/liburl.la \
+ ../su/libsu.la
+
+test_http_LDFLAGS = -static
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+
+EXTRA_DIST = Doxyfile http.docs \
+ sofia-sip/http_protos.h.in \
+ sofia-sip/http_tag.h.in \
+ http_parser_table.c.in \
+ http_tag.c.in
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+
+include ../sofia.am
+
+TAG_DLL_FLAGS = DLLREF=1
+
+MSG_PARSER_AWK = $(srcdir)/../msg/msg_parser.awk
+
+AWK_HTTP_AWK = $(AWK) -f $(MSG_PARSER_AWK) module=http
+
+sofia-sip/http_tag.h: sofia-sip/http_tag.h.in $(MSG_PARSER_AWK)
+sofia-sip/http_protos.h: sofia-sip/http_protos.h.in $(MSG_PARSER_AWK)
+http_tag.c: http_tag.c.in $(MSG_PARSER_AWK)
+http_parser_table.c: http_parser_table.c.in $(MSG_PARSER_AWK)
+
+sofia-sip/http_protos.h: sofia-sip/http.h
+ @-mkdir sofia-sip 2>/dev/null || true
+ $(AWK_HTTP_AWK) PR=$@ TEMPLATE=$(srcdir)/sofia-sip/http_protos.h.in $<
+
+sofia-sip/http_tag.h: sofia-sip/http.h
+ @-mkdir sofia-sip 2>/dev/null || true
+ $(AWK_HTTP_AWK) PR=$@ TEMPLATE=$(srcdir)/sofia-sip/http_tag.h.in $<
+
+http_tag.c: sofia-sip/http.h
+ $(AWK_HTTP_AWK) PR=$@ TEMPLATE=$(srcdir)/http_tag.c.in $<
+
+http_parser_table.c: sofia-sip/http.h
+ $(AWK_HTTP_AWK) PT=$@ TEMPLATE=$(srcdir)/http_parser_table.c.in \
+ MC_HASH_SIZE=127 $<
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/Makefile.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1,747 @@
+# 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.
+
+ at SET_MAKE@
+
+#
+# Makefile.am for http module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+# common Makefile targets for libsofia-sip-ua modules
+# ---------------------------------------------------
+
+
+SOURCES = $(libhttp_la_SOURCES) test_http.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 = test_http$(EXEEXT)
+DIST_COMMON = $(nobase_include_sofia_HEADERS) $(srcdir)/../sofia.am \
+ $(srcdir)/Makefile.am $(srcdir)/Makefile.in ChangeLog
+subdir = libsofia-sip-ua/http
+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 =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libhttp_la_LIBADD =
+am__objects_1 = http_tag.lo http_tag_ref.lo http_parser_table.lo
+am_libhttp_la_OBJECTS = http_parser.lo http_header.lo http_basic.lo \
+ http_extra.lo http_status.lo http_tag_class.lo \
+ $(am__objects_1)
+libhttp_la_OBJECTS = $(am_libhttp_la_OBJECTS)
+test_http_SOURCES = test_http.c
+test_http_OBJECTS = test_http.$(OBJEXT)
+test_http_LDADD = $(LDADD)
+test_http_DEPENDENCIES = libhttp.la ../bnf/libbnf.la ../msg/libmsg.la \
+ ../url/liburl.la ../su/libsu.la
+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 = $(libhttp_la_SOURCES) test_http.c
+DIST_SOURCES = $(libhttp_la_SOURCES) test_http.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|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(include_sofiadir)"
+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)/../bnf -I../bnf \
+ -I$(srcdir)/../msg -I../msg \
+ -I$(srcdir)/../url -I../url \
+ -I$(srcdir)/../su -I../su -I../su
+
+
+# ----------------------------------------------------------------------
+# Build targets
+noinst_LTLIBRARIES = libhttp.la
+TESTS = test_http
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+PUBLIC_H = sofia-sip/http.h sofia-sip/http_header.h \
+ sofia-sip/http_parser.h sofia-sip/http_tag_class.h \
+ sofia-sip/http_status.h sofia-sip/http_hclasses.h
+
+BUILT_H = sofia-sip/http_protos.h sofia-sip/http_tag.h
+BUILT_C = http_tag.c http_tag_ref.c http_parser_table.c
+BUILT_SOURCES = $(BUILT_H) $(BUILT_C)
+nobase_include_sofia_HEADERS = $(BUILT_H) $(PUBLIC_H)
+libhttp_la_SOURCES = $(INTERNAL_H) \
+ http_parser.c http_header.c \
+ http_basic.c http_extra.c \
+ http_status.c http_tag_class.c \
+ $(BUILT_C)
+
+COVERAGE_INPUT = $(libhttp_la_SOURCES) $(include_sofia_HEADERS)
+LDADD = libhttp.la \
+ ../bnf/libbnf.la \
+ ../msg/libmsg.la \
+ ../url/liburl.la \
+ ../su/libsu.la
+
+test_http_LDFLAGS = -static
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+EXTRA_DIST = Doxyfile http.docs \
+ sofia-sip/http_protos.h.in \
+ sofia-sip/http_tag.h.in \
+ http_parser_table.c.in \
+ http_tag.c.in
+
+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
+TAG_DLL_FLAGS = DLLREF=1
+MSG_PARSER_AWK = $(srcdir)/../msg/msg_parser.awk
+AWK_HTTP_AWK = $(AWK) -f $(MSG_PARSER_AWK) module=http
+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/http/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu libsofia-sip-ua/http/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-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
+libhttp.la: $(libhttp_la_OBJECTS) $(libhttp_la_DEPENDENCIES)
+ $(LINK) $(libhttp_la_LDFLAGS) $(libhttp_la_OBJECTS) $(libhttp_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
+test_http$(EXEEXT): $(test_http_OBJECTS) $(test_http_DEPENDENCIES)
+ @rm -f test_http$(EXEEXT)
+ $(LINK) $(test_http_LDFLAGS) $(test_http_OBJECTS) $(test_http_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/http_basic.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/http_extra.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/http_header.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/http_parser.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/http_parser_table.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/http_status.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/http_tag.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/http_tag_class.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/http_tag_ref.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_http.Po at am__quote@
+
+.c.o:
+ at am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+ at am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ at am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at 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 $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(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-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-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-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-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-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-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) $<
+
+ at ENABLE_COVERAGE_TRUE@coverage:
+ at 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)
+
+sofia-sip/http_tag.h: sofia-sip/http_tag.h.in $(MSG_PARSER_AWK)
+sofia-sip/http_protos.h: sofia-sip/http_protos.h.in $(MSG_PARSER_AWK)
+http_tag.c: http_tag.c.in $(MSG_PARSER_AWK)
+http_parser_table.c: http_parser_table.c.in $(MSG_PARSER_AWK)
+
+sofia-sip/http_protos.h: sofia-sip/http.h
+ @-mkdir sofia-sip 2>/dev/null || true
+ $(AWK_HTTP_AWK) PR=$@ TEMPLATE=$(srcdir)/sofia-sip/http_protos.h.in $<
+
+sofia-sip/http_tag.h: sofia-sip/http.h
+ @-mkdir sofia-sip 2>/dev/null || true
+ $(AWK_HTTP_AWK) PR=$@ TEMPLATE=$(srcdir)/sofia-sip/http_tag.h.in $<
+
+http_tag.c: sofia-sip/http.h
+ $(AWK_HTTP_AWK) PR=$@ TEMPLATE=$(srcdir)/http_tag.c.in $<
+
+http_parser_table.c: sofia-sip/http.h
+ $(AWK_HTTP_AWK) PT=$@ TEMPLATE=$(srcdir)/http_parser_table.c.in \
+ MC_HASH_SIZE=127 $<
+# 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:
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/headers
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/headers Thu Dec 21 01:30:28 2006
@@ -0,0 +1,48 @@
+accept Accept
+accept_charset Accept-Charset
+accept_encoding Accept-Encoding
+accept_language Accept-Language
+accept_ranges Accept-Ranges
+age Age
+allow Allow
+authorization Authorization
+cache_control Cache-Control
+connection Connection
+content_encoding Content-Encoding
+content_language Content-Language
+content_length Content-Length
+content_location Content-Location
+content_md5 Content-MD5
+content_range Content-Range
+content_type Content-Type
+date Date
+etag ETag
+expect Expect
+expires Expires
+from From
+host Host
+if_match If-Match
+if_modified_since If-Modified-Since
+if_none_match If-None-Match
+if_range If-Range
+if_unmodified_since If-Unmodified-Since
+last_modified Last-Modified
+location Location
+max_forwards Max-Forwards
+mime_version MIME-Version
+pragma Pragma
+pr_authenticate Proxy-Authenticate
+pr_authorization Proxy-Authorization
+range Range
+referer Referer
+retry_after Retry-After
+server Server
+te TE
+trailer Trailer
+transfer_encoding Transfer-Encoding
+upgrade Upgrade
+user_agent User-Agent
+vary Vary
+via Via
+warning Warning
+www_authenticate WWW-Authenticate
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http.def.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http.def.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1,17 @@
+; Template for http.def
+
+LIBRARY "http"
+
+DESCRIPTION 'HTTP Win32 Dynamic Link Library'
+
+EXPORTS
+ ; Explicit exports can go here
+
+ http_default_mclass
+
+ sip_#xxxxxx#_class
+ sip_#xxxxxx#_p
+ sip_#xxxxxx#_dup
+ sip_#xxxxxx#_copy
+ sip_#xxxxxx#_make
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http.docs Thu Dec 21 01:30:28 2006
@@ -0,0 +1,40 @@
+/* -*- c -*- */
+
+/**@MODULEPAGE "http" - HTTP Parser Module
+ *
+ * @section http_meta Module Meta Information
+ *
+ * The @b http module contains interface to the HTTP parser and the header
+ * and message objects.
+ *
+ * @CONTACT Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @STATUS @SofiaSIP Core library
+ *
+ * @LICENSE LGPL
+ *
+ * @section http_overview Overview
+ *
+ * Each HTTP header has a structure defined for it in <http.h>. All the
+ * variables, objects and functions related to a particular HTTP header are
+ * documented in a <a href="modules.html">submodule</a> for the header. In
+ * addition to the header structure, there is defined a @em header @em class
+ * structure and some standard functions for each header in the
+ * <http_header.h> include file. For header @c X, there are types,
+ * functions, macros and header class as follows:
+ *
+ * - @c http_X_t is the structure used to store parsed header,
+ * - @c HTTP_X_INIT() initializes a static instance of http_X_t,
+ * - @c http_X_p() tests if header object is instance of header X,
+ * - @c http_X_make() is a macro that creates a header X object by
+ decoding given string,
+ * - @c http_X_dup() duplicates (deeply copies) the header X (macro),
+ * - @c http_X_copy() is a macro that copies the header X (macro),
+ * - @c #msg_hclass_t http_X_class[] contains the @em header @em class
+ * for header X.
+ *
+ * In addition to this interface, the parser provider interface is
+ * documented in the <a href="../sip/group__sip__parser.html">SIP Parser module</a>.
+ * The parser provider interface makes it possible to extend HTTP parser with
+ * new headers or extend existing ones.
+ */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_basic.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_basic.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1634 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE http_basic.c
+ * @brief HTTP basic header
+ *
+ * The file @b http_basic.c contains implementation of header classes for
+ * basic HTTP headers, like request and status lines, payload, @b Call-ID, @b
+ * CSeq, @b Contact, @b Content-Length, @b Date, @b Expires, @b From, @b
+ * Route, @b Record-Route, @b To, and @b Via.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Jun 13 02:57:51 2000 ppessi
+ */
+
+#include "config.h"
+
+/* Avoid casting http_t to msg_pub_t and http_header_t to msg_header_t */
+#define MSG_PUB_T struct http_s
+#define MSG_HDR_T union http_header_u
+
+#include <sofia-sip/su_alloc.h>
+
+#include <sofia-sip/http_parser.h>
+#include <sofia-sip/http_header.h>
+#include <sofia-sip/http_status.h>
+
+#include <sofia-sip/msg_mime_protos.h>
+#include <sofia-sip/msg_date.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <stdio.h>
+
+/* ====================================================================== */
+
+/**@HTTP_HEADER http_request HTTP request line.
+ *
+ * The HTTP request line contains the method, URL, and an optional HTTP
+ * protocol version. The missing version indicates version 0.9 without any
+ * request headers.
+ */
+
+/**
+ * Parse request line of a HTTP message.
+ *
+ * The function @c http_request_d() parses the request line from a a HTTP
+ * message.
+ */
+issize_t http_request_d(su_home_t *home, http_header_t *h, char *s, isize_t slen)
+{
+ http_request_t *rq = h->sh_request;
+ char *uri, *version;
+
+ if (msg_firstline_d(s, &uri, &version) < 0 ||
+ (rq->rq_method = http_method_d(&s, &rq->rq_method_name)) < 0 || *s ||
+ url_d(rq->rq_url, uri) < 0 ||
+ (http_version_d(&version, &rq->rq_version) < 0 || version[0]))
+ return -1;
+
+ return 0;
+}
+
+/**
+ * Encode a HTTP request line.
+ *
+ * The function @c http_request_e() prints a HTTP request line.
+ */
+issize_t http_request_e(char b[], isize_t bsiz, http_header_t const *h, int flags)
+{
+ http_request_t const *rq = h->sh_request;
+
+ return snprintf(b, bsiz, "%s " URL_FORMAT_STRING "%s%s" CRLF,
+ rq->rq_method_name,
+ URL_PRINT_ARGS(rq->rq_url),
+ rq->rq_version ? " " : "",
+ rq->rq_version ? rq->rq_version : "");
+}
+
+isize_t http_request_dup_xtra(http_header_t const *h, isize_t offset)
+{
+ http_request_t const *rq = h->sh_request;
+
+ offset += url_xtra(rq->rq_url);
+ if (!rq->rq_method)
+ offset += MSG_STRING_SIZE(rq->rq_method_name);
+ if (rq->rq_version)
+ offset += http_version_xtra(rq->rq_version);
+
+ return offset;
+}
+
+/** Duplicate one request header. */
+char *http_request_dup_one(http_header_t *dst, http_header_t const *src,
+ char *b, isize_t xtra)
+{
+ http_request_t *rq = dst->sh_request;
+ http_request_t const *o = src->sh_request;
+ char *end = b + xtra;
+
+ URL_DUP(b, end, rq->rq_url, o->rq_url);
+
+ if (!(rq->rq_method = o->rq_method))
+ MSG_STRING_DUP(b, rq->rq_method_name, o->rq_method_name);
+ else
+ rq->rq_method_name = o->rq_method_name;
+ http_version_dup(&b, &rq->rq_version, o->rq_version);
+
+ assert(b <= end);
+
+ return b;
+}
+
+/** Create a request line object.
+ *
+ * Note that version string is not copied; it @b MUST remain constant during
+ * lifetime of the @c http_request_t object. You can use constants
+ * http_version_1_1 or http_version_1_0 declared in <http_header.h>.
+ */
+http_request_t *http_request_create(su_home_t *home,
+ http_method_t method, char const *name,
+ url_string_t const *url,
+ char const *version)
+{
+ size_t xtra;
+ http_request_t *rq;
+
+ if (method)
+ name = http_method_name(method, name);
+
+ if (!name)
+ return NULL;
+
+ xtra = url_xtra(url->us_url) + (method ? 0 : strlen(name) + 1);
+
+ rq = msg_header_alloc(home, http_request_class, (isize_t)xtra)->sh_request;
+
+ if (rq) {
+ char *b = (char *)(rq + 1), *end = b + xtra;
+
+ rq->rq_method = method;
+ rq->rq_method_name = name;
+ if (!method)
+ MSG_STRING_DUP(b, rq->rq_method_name, name);
+
+ URL_DUP(b, end, rq->rq_url, url->us_url);
+
+ rq->rq_version = version ? version : HTTP_VERSION_CURRENT;
+ assert(b == end);
+ }
+
+ return rq;
+}
+
+msg_hclass_t http_request_class[] =
+HTTP_HEADER_CLASS(request, NULL, rq_common, single_critical, request);
+
+/* ====================================================================== */
+
+/**@HTTP_HEADER http_status HTTP status line.
+ *
+ * The HTTP status line contains the HTTP protocol version, a reason code
+ * (100..599) and reason phrase.
+ */
+
+/** Parse status line */
+issize_t http_status_d(su_home_t *home, http_header_t *h, char *s, isize_t slen)
+{
+ http_status_t *st = h->sh_status;
+ char *status, *phrase;
+ uint32_t code;
+
+ if (msg_firstline_d(s, &status, &phrase) < 0 ||
+ http_version_d(&s, &st->st_version) < 0 || *s ||
+ msg_uint32_d(&status, &code) == -1 ||
+ status[0])
+ return -1;
+
+ st->st_status = code;
+ st->st_phrase = phrase;
+
+ return 0;
+}
+
+issize_t http_status_e(char b[], isize_t bsiz, http_header_t const *h, int flags)
+{
+ http_status_t const *st = h->sh_status;
+ char const *phrase = st->st_phrase;
+
+ if (phrase == NULL)
+ phrase = "";
+
+ if (st->st_version)
+ return snprintf(b, bsiz, "%s %03u %s" CRLF,
+ st->st_version,
+ st->st_status,
+ phrase);
+ else
+ return snprintf(b, bsiz, "%03u %s" CRLF,
+ st->st_status,
+ phrase);
+}
+
+/** Extra size of a http_status_t object. */
+isize_t http_status_dup_xtra(http_header_t const *h, isize_t offset)
+{
+ if (h->sh_status->st_version)
+ offset += http_version_xtra(h->sh_status->st_version);
+ offset += MSG_STRING_SIZE(h->sh_status->st_phrase);
+ return offset;
+}
+
+/** Duplicate one status header. */
+char *http_status_dup_one(http_header_t *dst, http_header_t const *src,
+ char *b, isize_t xtra)
+{
+ http_status_t *st = dst->sh_status;
+ http_status_t const *o = src->sh_status;
+ char *end = b + xtra;
+
+ if (o->st_version)
+ http_version_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;
+}
+
+/** Create a status line object.
+ *
+ * Note that version is not copied; it @b MUST remain constant during
+ * lifetime of the @c http_status_t object.
+ */
+http_status_t *http_status_create(su_home_t *home,
+ unsigned status,
+ char const *phrase,
+ char const *version)
+{
+ http_status_t *st;
+
+ if (phrase == NULL && (phrase = http_status_phrase(status)) == NULL)
+ return NULL;
+
+ if ((st = msg_header_alloc(home, http_status_class, 0)->sh_status)) {
+ st->st_status = status;
+ st->st_phrase = phrase;
+ st->st_version = version ? version : HTTP_VERSION_CURRENT;
+ }
+
+ return st;
+}
+
+msg_hclass_t http_status_class[] =
+HTTP_HEADER_CLASS(status, NULL, st_common, single_critical, status);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_accept Accept header.
+ *
+ * We use MIME Accept header.
+ */
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_accept_charset Accept-Charset header.
+ *
+ * We use MIME Accept-Charset header.
+ */
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_accept_encoding Accept-Encoding header.
+ *
+ * We use MIME Accept-Encoding header.
+ */
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_accept_language Accept-Language header.
+ *
+ * We use MIME Accept-Language header.
+ */
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_accept_ranges Accept-Ranges header. */
+
+#define http_accept_ranges_d msg_list_d
+#define http_accept_ranges_e msg_list_e
+msg_hclass_t http_accept_ranges_class[] =
+HTTP_HEADER_CLASS_LIST(accept_ranges, "Accept-Ranges", list);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_age Age header. */
+
+#define http_age_d msg_numeric_d
+#define http_age_e msg_numeric_e
+#define http_age_dup_xtra msg_default_dup_xtra
+#define http_age_dup_one msg_default_dup_one
+msg_hclass_t http_age_class[] =
+HTTP_HEADER_CLASS(age, "Age", x_common, single, age);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_allow Allow header. */
+
+#define http_allow_d msg_list_d
+#define http_allow_e msg_list_e
+msg_hclass_t http_allow_class[] =
+HTTP_HEADER_CLASS_LIST(allow, "Allow", list);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_authentication_info Authentication-Info header.
+ * @sa RFC 2617
+ */
+
+#define http_authentication_info_d msg_list_d
+#define http_authentication_info_e msg_list_e
+#define http_authentication_info_dup_xtra msg_list_dup_xtra
+#define http_authentication_info_dup_one msg_list_dup_one
+
+msg_hclass_t http_authentication_info_class[] =
+HTTP_HEADER_CLASS(authentication_info, "Authentication-Info",
+ ai_params, list, authentication_info);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_authorization Authorization header.
+ *
+ * We use MIME Authorization header.
+ */
+
+#define http_authorization_d msg_auth_d
+#define http_authorization_e msg_auth_e
+
+msg_hclass_t http_authorization_class[] =
+HTTP_HEADER_CLASS_AUTH(authorization, "Authorization", single);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_cache_control Cache-Control header. */
+
+#define http_cache_control_d msg_list_d
+#define http_cache_control_e msg_list_e
+
+msg_hclass_t http_cache_control_class[] =
+ HTTP_HEADER_CLASS_LIST(cache_control, "Cache-Control", list);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_connection Connection header. */
+
+#define http_connection_d msg_list_d
+#define http_connection_e msg_list_e
+msg_hclass_t http_connection_class[] =
+HTTP_HEADER_CLASS_LIST(connection, "Connection", list_critical);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_content_encoding Content-Encoding header.
+ *
+ * We use MIME Content-Encoding header.
+ */
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_content_language Content-Language header.
+ *
+ * We use MIME Content-Language header.
+ */
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_content_length Content-Length header.
+ *
+ * We use MIME Content-Length header.
+ */
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_content_location Content-Location header.
+ *
+ * We use MIME Content-Location header.
+ */
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_content_md5 Content-MD5 header.
+ *
+ * We use MIME Content-MD5 header.
+ */
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_content_range Content-Range header.
+ *
+ * The Content-Range entity-header is sent with a partial entity-body to
+ * specify where in the full entity-body the partial body should be
+ * applied. Its syntax is defined in [H14.16] as follows:
+ *
+ * @code
+ * Content-Range = "Content-Range" ":" content-range-spec
+ * content-range-spec = byte-content-range-spec
+ * byte-content-range-spec = bytes-unit SP
+ * byte-range-resp-spec "/"
+ * ( instance-length | "*" )
+ *
+ * byte-range-resp-spec = (first-byte-pos "-" last-byte-pos)
+ * | "*"
+ * instance-length = 1*DIGIT
+ * @endcode
+ *
+ */
+
+/**@ingroup http_content_range
+ * @typedef typedef struct http_content_range_s http_content_range_t;
+ *
+ * The structure #http_content_range_t contains representation of
+ * @b Content-Range header.
+ *
+ * The #http_content_range_t is defined as follows:
+ * @code
+ * typedef struct {
+ * msg_common_t cr_common[1];
+ * msg_error_t *cr_next;
+ * off_t cr_first; // First-byte-pos
+ * off_t cr_last; // Last-byte-pos
+ * off_t cr_length; // Instance-length
+ * } http_content_range_t;
+ * @endcode
+ */
+
+issize_t http_content_range_d(su_home_t *home, http_header_t *h, char *s, isize_t slen)
+{
+ http_content_range_t *cr = h->sh_content_range;
+
+ if (strncasecmp(s, "bytes", 5))
+ return -1;
+ s += 5; skip_lws(&s);
+ if (s[0] == '*') {
+ cr->cr_first = cr->cr_last = (http_off_t)-1;
+ s++; skip_lws(&s);
+ } else {
+ if (msg_delta_d((char const **)&s, &cr->cr_first) < 0)
+ return -1;
+ if (s[0] != '-')
+ return -1;
+ s++; skip_lws(&s);
+ if (msg_delta_d((char const **)&s, &cr->cr_last) < 0)
+ return -1;
+ }
+
+ if (s[0] != '/')
+ return -1;
+ s++; skip_lws(&s);
+
+ if (s[0] == '*') {
+ cr->cr_length = (http_off_t)-1;
+ s++; skip_lws(&s);
+ } else {
+ if (msg_delta_d((char const **)&s, &cr->cr_length) < 0)
+ return -1;
+ }
+
+ return s[0] ? -1 : 0;
+}
+
+issize_t http_content_range_e(char b[], isize_t bsiz, http_header_t const *h, int f)
+{
+ http_content_range_t const *cr = h->sh_content_range;
+
+ if (cr->cr_first == (http_off_t)-1) {
+ if (cr->cr_length == (http_off_t)-1)
+ return snprintf(b, bsiz, "bytes */*");
+ else
+ return snprintf(b, bsiz, "bytes */%lu", cr->cr_length);
+ }
+ else {
+ if (cr->cr_length == (http_off_t)-1)
+ return snprintf(b, bsiz, "bytes %lu-%lu/*", cr->cr_first, cr->cr_last);
+ else
+ return snprintf(b, bsiz, "bytes %lu-%lu/%lu",
+ cr->cr_first, cr->cr_last, cr->cr_length);
+ }
+}
+
+msg_hclass_t http_content_range_class[] =
+HTTP_HEADER_CLASS(content_range, "Content-Range", cr_common, single, default);
+
+
+/* ====================================================================== */
+
+/**@HTTP_HEADER http_content_type Content-Type header.
+ *
+ * We use MIME Content-Type header.
+ */
+
+/* ====================================================================== */
+
+/**@HTTP_HEADER http_date Date header.
+ *
+ * The Date header field reflects the time when the request or response was
+ * first sent. Its syntax is defined in [H14.18] as
+ * follows:
+ *
+ * @code
+ * Date = "Date" HCOLON HTTP-date
+ * HTTP-date = rfc1123-date
+ * rfc1123-date = wkday "," SP date1 SP time SP "GMT"
+ * date1 = 2DIGIT SP month SP 4DIGIT
+ * ; day month year (e.g., 02 Jun 1982)
+ * time = 2DIGIT ":" 2DIGIT ":" 2DIGIT
+ * ; 00:00:00 - 23:59:59
+ * wkday = "Mon" / "Tue" / "Wed"
+ * / "Thu" / "Fri" / "Sat" / "Sun"
+ * month = "Jan" / "Feb" / "Mar" / "Apr"
+ * / "May" / "Jun" / "Jul" / "Aug"
+ * / "Sep" / "Oct" / "Nov" / "Dec"
+ * @endcode
+ *
+ */
+
+/**@ingroup http_date
+ * @typedef typedef struct http_date_s http_date_t;
+ *
+ * The structure #http_date_t contains representation of @b Date header.
+ *
+ * The #http_date_t is defined as follows:
+ * @code
+ * typedef struct {
+ * msg_common_t d_common[1]; // Common fragment info
+ * msg_error_t *d_next; // Link to next (dummy)
+ * http_time_t d_time; // Seconds since Jan 1, 1900
+ * } http_date_t;
+ * @endcode
+ */
+
+issize_t http_date_d(su_home_t *home, http_header_t *h, char *s, isize_t slen)
+{
+ http_date_t *date = h->sh_date;
+
+ if (msg_date_d((char const **)&s, &date->d_time) < 0 || *s)
+ return -1;
+ else
+ return 0;
+}
+
+
+issize_t http_date_e(char b[], isize_t bsiz, http_header_t const *h, int f)
+{
+ http_date_t const *date = h->sh_date;
+
+ return msg_date_e(b, bsiz, date->d_time);
+}
+
+/**@ingroup http_date
+ * @brief Create an @b Date header object.
+ *
+ * The function http_date_create() creates a Date header object with the
+ * date @a date. If @date is 0, current time (as returned by msg_now()) is
+ * used.
+ *
+ * @param home memory home
+ * @param date date expressed as seconds since Mon, 01 Jan 1900 00:00:00
+ *
+ * @return
+ * The function http_date_create() returns a pointer to newly created
+ * @b Date header object when successful, or NULL upon an error.
+ */
+http_date_t *http_date_create(su_home_t *home, http_time_t date)
+{
+ http_header_t *h = msg_header_alloc(home, http_date_class, 0);
+
+ if (h) {
+ if (date == 0)
+ date = msg_now();
+ h->sh_date->d_time = date;
+ }
+
+ return h->sh_date;
+}
+
+
+msg_hclass_t http_date_class[] =
+HTTP_HEADER_CLASS(date, "Date", d_common, single, default);
+
+
+/* ====================================================================== */
+
+/**@HTTP_HEADER http_etag ETag header. */
+
+#define http_etag_d msg_generic_d
+#define http_etag_e msg_generic_e
+msg_hclass_t http_etag_class[] =
+HTTP_HEADER_CLASS_G(etag, "ETag", single);
+
+/* ====================================================================== */
+
+/**@HTTP_HEADER http_expect Expect header. */
+
+#define http_expect_d msg_generic_d
+#define http_expect_e msg_generic_e
+msg_hclass_t http_expect_class[] =
+HTTP_HEADER_CLASS_G(expect, "Expect", single);
+
+/* ====================================================================== */
+
+/**@HTTP_HEADER http_expires Expires header.
+ *
+ * The Expires header field gives the date and time after which the message
+ * content expires. Its syntax is defined in RFC 1428 section 14.21 as
+ * follows:
+ *
+ * @code
+ * Expires = "Expires:" HTTP-date
+ * @endcode
+ *
+ */
+
+/**@ingroup http_expires
+ * @typedef typedef struct http_expires_s http_expires_t;
+ *
+ * The structure #http_expires_t contains representation of @b Expires
+ * header.
+ *
+ * The #http_expires_t is defined as follows:
+ * @code
+ * typedef struct {
+ * msg_common_t d_common[1]; // Common fragment info
+ * msg_error_t *d_next; // Link to next (dummy)
+ * http_time_t d_time; // Seconds since Jan 1, 1900
+ * } http_expires_t;
+ * @endcode
+ */
+
+#define http_expires_d http_date_d
+#define http_expires_e http_date_e
+
+msg_hclass_t http_expires_class[] =
+HTTP_HEADER_CLASS(expires, "Expires", d_common, single, default);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_from From header.
+ *
+ * @code
+ * From = "From" ":" mailbox
+ * @endcode
+ */
+
+
+#define http_from_d msg_generic_d
+#define http_from_e msg_generic_e
+msg_hclass_t http_from_class[] =
+HTTP_HEADER_CLASS_G(from, "From", single);
+
+/* ====================================================================== */
+
+/**@HTTP_HEADER http_host Host header.
+ *
+ * @code
+ * Host = "Host" ":" host [ ":" port ]
+ * @endcode
+ */
+
+/** Parse Host header */
+issize_t http_host_d(su_home_t *home, http_header_t *h, char *s, isize_t slen)
+{
+ http_host_t *host = h->sh_host;
+
+ if (msg_hostport_d(&s, &host->h_host, &host->h_port) < 0 || *s)
+ return -1;
+
+ return 0;
+}
+
+/** Print Host header */
+issize_t http_host_e(char b[], isize_t bsiz, http_header_t const *h, int flags)
+{
+ char *b0 = b, *end = b + bsiz;
+
+ MSG_STRING_E(b, end, h->sh_host->h_host);
+ if (h->sh_host->h_port) {
+ MSG_CHAR_E(b, end, ':');
+ MSG_STRING_E(b, end, h->sh_host->h_port);
+ }
+
+ return b - b0;
+}
+
+/** Extra size of a http_host_t object. */
+static
+isize_t http_host_dup_xtra(http_header_t const *h, isize_t offset)
+{
+ offset += MSG_STRING_SIZE(h->sh_host->h_host);
+ offset += MSG_STRING_SIZE(h->sh_host->h_port);
+ return offset;
+}
+
+/** Duplicate one Host header. */
+static
+char *http_host_dup_one(http_header_t *dst, http_header_t const *src,
+ char *b, isize_t xtra)
+{
+ http_host_t *h = dst->sh_host;
+ http_host_t const *o = src->sh_host;
+ char *end = b + xtra;
+
+ MSG_STRING_DUP(b, h->h_host, o->h_host);
+ MSG_STRING_DUP(b, h->h_port, o->h_port);
+
+ assert(b <= end); (void)end;
+
+ return b;
+}
+
+/**Create a Host object. */
+http_host_t *http_host_create(su_home_t *home,
+ char const *host,
+ char const *port)
+{
+ http_host_t h[1];
+
+ http_host_init(h);
+
+ h->h_host = host, h->h_port = port;
+
+ if (host) {
+ return http_host_dup(home, h);
+ }
+ else
+ return NULL;
+}
+
+msg_hclass_t http_host_class[] =
+HTTP_HEADER_CLASS(host, "Host", h_common, single, host);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_if_match If-Match header. */
+
+#define http_if_match_d msg_list_d
+#define http_if_match_e msg_list_e
+msg_hclass_t http_if_match_class[] =
+HTTP_HEADER_CLASS_LIST(if_match, "If-Match", list);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_if_modified_since If-Modified-Since header.
+ *
+ * The If-Modified-Since header field The If-Modified-Since request-header
+ * field is used with a method to make it conditional: if the requested
+ * variant has not been modified since the time specified in this field, an
+ * entity will not be returned from the server; instead, a 304 (not
+ * modified) response will be returned without any message-body. Its syntax
+ * is defined in RFC 2616 secion 14.25 as follows:
+ *
+ * @code
+ * If-Modified-Since = "If-Modified-Since" ":" HTTP-date
+ * @endcode
+ *
+ */
+
+/**@ingroup http_if_modified_since
+ * @typedef typedef struct http_if_modified_since_s http_if_modified_since_t;
+ *
+ * The structure #http_if_modified_since_t contains representation of
+ * @b If-Modified-Since header.
+ *
+ * The #http_if_modified_since_t is defined as follows:
+ * @code
+ * typedef struct {
+ * msg_common_t d_common[1]; // Common fragment info
+ * msg_error_t *d_next; // Link to next (dummy)
+ * http_time_t d_time; // Seconds since Jan 1, 1900
+ * } http_if_modified_since_t;
+ * @endcode
+ */
+
+#define http_if_modified_since_d http_date_d
+#define http_if_modified_since_e http_date_e
+
+msg_hclass_t http_if_modified_since_class[] =
+HTTP_HEADER_CLASS(if_modified_since, "If-Modified-Since",
+ d_common, single, default);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_if_none_match If-None-Match header. */
+
+#define http_if_none_match_d msg_list_d
+#define http_if_none_match_e msg_list_e
+msg_hclass_t http_if_none_match_class[] =
+HTTP_HEADER_CLASS_LIST(if_none_match, "If-None-Match", list);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_if_range If-Range header.
+ *
+ * The @b If-Range header is used when a client has a partial copy of an
+ * entity in its cache, and wishes to have an up-to-date copy of the entire
+ * entity. Informally, its meaning is `if the entity is unchanged, send
+ * me the part(s) that I am missing; otherwise, send me the entire new
+ * entity'. Its syntax is defined in RFC 2616 as follows:
+ *
+ * @code
+ * If-Range = "If-Range" ":" ( entity-tag / HTTP-date )
+ * @endcode
+ */
+
+/** Parse If-Range header */
+issize_t http_if_range_d(su_home_t *home, http_header_t *h, char *s, isize_t slen)
+{
+ http_if_range_t *ifr = (http_if_range_t *)h;
+
+ if (s[0] == '"' || strncasecmp(s, "W/\"", 3) == 0) {
+ ifr->ifr_tag = s;
+ return 0;
+ } else {
+ return msg_date_d((char const **)&s, &ifr->ifr_time);
+ }
+}
+
+/** Print If-Range header */
+issize_t http_if_range_e(char b[], isize_t bsiz, http_header_t const *h, int flags)
+{
+ http_if_range_t const *ifr = (http_if_range_t const *)h;
+ char *b0 = b, *end = b + bsiz;
+
+ if (ifr->ifr_tag) {
+ MSG_STRING_E(b, end, ifr->ifr_tag);
+ return b - b0;
+ } else {
+ return msg_date_e(b, bsiz, ifr->ifr_time);
+ }
+}
+
+/** Extra size of a http_if_range_t object. */
+static
+isize_t http_if_range_dup_xtra(http_header_t const *h, isize_t offset)
+{
+ http_if_range_t const *ifr = (http_if_range_t const *)h;
+ offset += MSG_STRING_SIZE(ifr->ifr_tag);
+ return offset;
+}
+
+/** Duplicate one If-Range header. */
+static
+char *http_if_range_dup_one(http_header_t *dst, http_header_t const *src,
+ char *b, isize_t xtra)
+{
+ http_if_range_t *ifr = dst->sh_if_range;
+ http_if_range_t const *o = src->sh_if_range;
+ char *end = b + xtra;
+
+ MSG_STRING_DUP(b, ifr->ifr_tag, o->ifr_tag);
+
+ ifr->ifr_time = o->ifr_time;
+
+ assert(b <= end); (void)end;
+
+ return b;
+}
+
+msg_hclass_t http_if_range_class[] =
+HTTP_HEADER_CLASS(if_range, "If-Range", ifr_common, single, if_range);
+
+
+/* ====================================================================== */
+
+/**@HTTP_HEADER http_if_unmodified_since If-Unmodified-Since header.
+ *
+ * The @b If-Unmodified-Since header is used with a method to make it
+ * conditional. If the requested resource has not been modified since the
+ * time specified in this field, the server SHOULD perform the requested
+ * operation as if the If-Unmodified-Since header were not present. Its
+ * syntax is defined in RFC 2616 14.28 as follows:
+ *
+ * @code
+ * If-Unmodified-Since = "If-Unmodified-Since:" HTTP-date
+ * @endcode
+ *
+ */
+
+/**@ingroup http_if_unmodified_since
+ * @typedef typedef http_date_t http_if_unmodified_since_t;
+ *
+ * The structure #http_if_unmodified_since_t contains representation of
+ * @b If-Unmodified-Since header.
+ *
+ * The #http_if_unmodified_since_t is defined as follows:
+ * @code
+ * typedef struct {
+ * msg_common_t d_common[1]; // Common fragment info
+ * msg_error_t *d_next; // Link to next (dummy)
+ * http_time_t d_time; // Seconds since Jan 1, 1900
+ * } http_if_unmodified_since_t;
+ * @endcode
+ */
+
+#define http_if_unmodified_since_d http_date_d
+#define http_if_unmodified_since_e http_date_e
+
+msg_hclass_t http_if_unmodified_since_class[] =
+HTTP_HEADER_CLASS(if_unmodified_since, "If-Unmodified-Since",
+ d_common, single, default);
+
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_last_modified Last-Modified header.
+ *
+ * The Last-Modified header field gives the date and time after which the
+ * message content last_modified. Its syntax is defined in [] as follows:
+ *
+ * @code
+ * Last-Modified = "Last-Modified:" HTTP-date
+ * @endcode
+ *
+ */
+
+/**@ingroup http_last_modified
+ * @typedef typedef struct http_last_modified_s http_last_modified_t;
+ *
+ * The structure #http_last_modified_t contains representation of @b
+ * Last-Modified header.
+ *
+ * The #http_last_modified_t is defined as follows:
+ * @code
+ * typedef struct {
+ * msg_common_t d_common[1]; // Common fragment info
+ * msg_error_t *d_next; // Link to next (dummy)
+ * http_time_t d_time; // Seconds since Jan 1, 1900
+ * } http_last_modified_t;
+ * @endcode
+ */
+
+#define http_last_modified_d http_date_d
+#define http_last_modified_e http_date_e
+
+msg_hclass_t http_last_modified_class[] =
+HTTP_HEADER_CLASS(last_modified, "Last-Modified", d_common, single, default);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_location Location Header
+ *
+ * The Location header is used to redirect the recipient to a location other
+ * than the Request-URI for completion of the request or identification of a
+ * new resource. Its syntax is defined in RFC 2616 section 14.30 as follows:
+ *
+ * @code
+ * Location = "Location" ":" absoluteURI
+ * @endcode
+ *
+ */
+
+/**@ingroup http_location
+ *
+ * @typedef typedef struct http_location_s http_location_t;
+ *
+ * The structure http_location_t contains representation of @b Location
+ * header.
+ *
+ * The http_location_t is defined as follows:
+ * @code
+ * typedef struct http_location_s
+ * {
+ * msg_common_t loc_common[1];
+ * msg_error_t *loc_next;
+ * url_t loc_url[1];
+ * } http_location_t;
+ * @endcode
+ */
+
+/** Decode (parse) a Location header */
+issize_t http_location_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
+{
+ http_location_t *loc = (http_location_t *)h;
+
+ return url_d(loc->loc_url, s);
+}
+
+/** Encode (print) a Location header */
+issize_t http_location_e(char b[], isize_t bsiz, msg_header_t const *h, int flags)
+{
+ http_location_t const *loc = (http_location_t *)h;
+
+ return url_e(b, bsiz, loc->loc_url);
+}
+
+/** Calculate extra storage used by Location header field */
+isize_t http_location_dup_xtra(msg_header_t const *h, isize_t offset)
+{
+ http_location_t const *loc = (http_location_t *)h;
+
+ offset += url_xtra(loc->loc_url);
+
+ return offset;
+}
+
+/** Duplicate a Location header field */
+char *http_location_dup_one(msg_header_t *dst, msg_header_t const *src,
+ char *b, isize_t xtra)
+{
+ http_location_t *loc = (http_location_t *)dst;
+ http_location_t const *o = (http_location_t const *)src;
+ char *end = b + xtra;
+
+ URL_DUP(b, end, loc->loc_url, o->loc_url);
+
+ assert(b <= end);
+
+ return b;
+}
+
+msg_hclass_t http_location_class[] =
+HTTP_HEADER_CLASS(location, "Location", loc_common, single, location);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_max_forwards Max-Forwards header. */
+
+#define http_max_forwards_d msg_numeric_d
+#define http_max_forwards_e msg_numeric_e
+msg_hclass_t http_max_forwards_class[] =
+HTTP_HEADER_CLASS(max_forwards, "Max-Forwards", mf_common, single, numeric);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_pragma Pragma header. */
+
+#define http_pragma_d msg_list_d
+#define http_pragma_e msg_list_e
+msg_hclass_t http_pragma_class[] =
+HTTP_HEADER_CLASS_LIST(pragma, "Pragma", list);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_proxy_authenticate Proxy-Authenticate header. */
+
+#define http_proxy_authenticate_d msg_auth_d
+#define http_proxy_authenticate_e msg_auth_e
+
+msg_hclass_t http_proxy_authenticate_class[] =
+HTTP_HEADER_CLASS_AUTH(proxy_authenticate, "Proxy-Authenticate", append);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_proxy_authorization Proxy-Authorization header. */
+
+#define http_proxy_authorization_d msg_auth_d
+#define http_proxy_authorization_e msg_auth_e
+
+msg_hclass_t http_proxy_authorization_class[] =
+HTTP_HEADER_CLASS_AUTH(proxy_authorization, "Proxy-Authorization", append);
+
+/* ====================================================================== */
+
+/**@HTTP_HEADER http_range Range header.
+ *
+ * The Range header is used to GET one or more sub-ranges of an entity
+ * instead of the entire entity. Its syntax is defined in RFC 2616 section
+ * 14.35 as follows:
+ *
+ * @code
+ * Range = "Range" ":" ranges-specifier
+ * ranges-specifier = byte-ranges-specifier
+ * byte-ranges-specifier = bytes-unit "=" byte-range-set
+ * byte-range-set = 1#( byte-range-spec | suffix-byte-range-spec )
+ * byte-range-spec = first-byte-pos "-" [last-byte-pos]
+ * first-byte-pos = 1*DIGIT
+ * last-byte-pos = 1*DIGIT
+ * @endcode
+ *
+ */
+
+/**@ingroup http_range
+ *
+ * @typedef typedef struct http_range_s http_range_t;
+ *
+ * The structure http_range_t contains representation of @b Range header.
+ *
+ * The http_range_t is defined as follows:
+ * @code
+ * typedef struct http_range_s
+ * {
+ * msg_common_t rng_common[1];
+ * msg_error_t *rng_next;
+ * char const *rng_unit;
+ * char const * const *rng_specs;
+ * } http_range_t;
+ * @endcode
+ */
+
+static issize_t range_spec_scan(char *start);
+
+/** Decode (parse) a Range header */
+issize_t http_range_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
+{
+ http_range_t *rng = (http_range_t *)h;
+
+ rng->rng_unit = s;
+ skip_token(&s);
+ if (s == rng->rng_unit)
+ return -1;
+ if (IS_LWS(*s)) {
+ *s++ = '\0';
+ skip_lws(&s);
+ }
+ if (*s != '=')
+ return -1;
+ *s++ = '\0';
+ skip_lws(&s);
+
+ /* XXX - use range-scanner */
+ return msg_commalist_d(home, &s, &rng->rng_specs, range_spec_scan);
+}
+
+/** Scan and compact a range spec. */
+static
+issize_t range_spec_scan(char *start)
+{
+ size_t tlen;
+ char *s, *p;
+
+ s = p = start;
+
+ if (s[0] == ',')
+ return 0;
+
+ /* Three forms: 1*DIGIT "-" 1*DIGIT | 1*DIGIT "-" | "-" 1*DIGIT */
+
+ if (*s != '-') {
+ tlen = span_digit(s);
+ if (tlen == 0)
+ return -1;
+ p += tlen; s += tlen;
+ skip_lws(&s);
+ }
+
+ if (*s != '-')
+ return -1;
+
+ if (p != s)
+ *p = *s;
+ p++, s++; skip_lws(&s);
+
+ if (IS_DIGIT(*s)) {
+ tlen = span_digit(s);
+ if (tlen == 0)
+ return -1;
+ if (p != s)
+ memmove(p, s, tlen);
+ p += tlen; s += tlen;
+ skip_lws(&s);
+ }
+
+ if (p != s)
+ *p = '\0';
+
+ return s - start;
+}
+
+
+/** Encode (print) a Range header */
+issize_t http_range_e(char b[], isize_t bsiz, msg_header_t const *h, int flags)
+{
+ http_range_t const *rng = (http_range_t *)h;
+ char *b0 = b, *end = b + bsiz;
+
+ MSG_STRING_E(b, end, rng->rng_unit);
+ MSG_CHAR_E(b, end, '=');
+ MSG_COMMALIST_E(b, end, rng->rng_specs, MSG_IS_COMPACT(flags));
+ MSG_TERM_E(b, end);
+
+ return b - b0;
+}
+
+/** Calculate extra storage used by Range header field */
+isize_t http_range_dup_xtra(msg_header_t const *h, isize_t offset)
+{
+ http_range_t const *rng = (http_range_t *)h;
+
+ MSG_PARAMS_SIZE(offset, rng->rng_specs);
+ offset += MSG_STRING_SIZE(rng->rng_unit);
+
+ return offset;
+}
+
+/** Duplicate a Range header field */
+char *http_range_dup_one(msg_header_t *dst, msg_header_t const *src,
+ char *b, isize_t xtra)
+{
+ http_range_t *rng = (http_range_t *)dst;
+ http_range_t const *o = (http_range_t const *)src;
+ char *end = b + xtra;
+
+ b = msg_params_dup((char const * const **)&rng->rng_specs,
+ o->rng_specs, b, xtra);
+ MSG_STRING_DUP(b, rng->rng_unit, o->rng_unit);
+
+ assert(b <= end); (void)end;
+
+ return b;
+}
+
+msg_hclass_t http_range_class[] =
+HTTP_HEADER_CLASS(range, "Range", rng_specs, single, range);
+
+/* ====================================================================== */
+
+/**@HTTP_HEADER http_referer Referer header.
+ *
+ * The Referer header is used to redirect the recipient to a referer other
+ * than the Request-URI for completion of the request or identification of a
+ * new resource. Its syntax is defined in RFC 2616 section 14.30 as follows:
+ *
+ * @code
+ * Referer = "Referer" ":" absoluteURI
+ * @endcode
+ *
+ */
+
+/**@ingroup http_referer
+ *
+ * @typedef typedef struct http_referer_s http_referer_t;
+ *
+ * The structure http_referer_t contains representation of @b Referer
+ * header.
+ *
+ * The http_referer_t is defined as follows:
+ * @code
+ * typedef struct http_referer_s
+ * {
+ * msg_common_t loc_common[1];
+ * msg_error_t *loc_next;
+ * url_t loc_url[1];
+ * } http_referer_t;
+ * @endcode
+ */
+
+#define http_referer_d http_location_d
+#define http_referer_e http_location_e
+
+msg_hclass_t http_referer_class[] =
+HTTP_HEADER_CLASS(referer, "Referer", loc_common, single, location);
+
+/* ====================================================================== */
+
+/**@HTTP_HEADER http_mime_version MIME-Version header.
+ *
+ * We use MIME MIME-Version header.
+ */
+
+/* ====================================================================== */
+
+/**@HTTP_HEADER http_retry_after Retry-After header.
+ *
+ * The Retry-After response-header field can be used with a 503 (Service
+ * Unavailable) response to indicate how long the service is expected to be
+ * unavailable to the requesting client. This field MAY also be used with
+ * any 3xx (Redirection) response to indicate the minimum time the
+ * user-agent is asked wait before issuing the redirected request. Its
+ * syntax is defined in RFC 2616 section 14.37 as follows:
+ *
+ * @code
+ * Retry-After = "Retry-After" ":" ( HTTP-date / delta-seconds )
+ * @endcode
+ *
+ */
+
+/**@ingroup http_retry_after
+ * @typedef typedef struct http_retry_after_s http_retry_after_t;
+ *
+ * The structure #http_retry_after_t contains representation of @b
+ * Retry-After header.
+ *
+ * The #http_retry_after_t is defined as follows:
+ * @code
+ * typedef struct {
+ * msg_common_t ra_common[1]; // Common fragment info
+ * msg_error_t *ra_next; // Link to next (dummy)
+ * http_time_t ra_date; // When to retry
+ * http_time_t ra_delta; // Seconds to before retry
+ * } http_retry_after_t;
+ * @endcode
+ */
+
+issize_t http_retry_after_d(su_home_t *home, http_header_t *h, char *s, isize_t slen)
+{
+ http_retry_after_t *ra = h->sh_retry_after;
+
+ if (msg_date_delta_d((char const **)&s,
+ &ra->ra_date,
+ &ra->ra_delta) < 0 || *s)
+ return -1;
+ else
+ return 0;
+}
+
+issize_t http_retry_after_e(char b[], isize_t bsiz, http_header_t const *h, int f)
+{
+ http_retry_after_t const *ra = h->sh_retry_after;
+
+ if (ra->ra_date)
+ return msg_date_e(b, bsiz, ra->ra_date + ra->ra_delta);
+ else
+ return msg_delta_e(b, bsiz, ra->ra_delta);
+}
+
+msg_hclass_t http_retry_after_class[] =
+HTTP_HEADER_CLASS(retry_after, "Retry-After", ra_common, single, default);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_server Server header. */
+
+#define http_server_d msg_generic_d
+#define http_server_e msg_generic_e
+msg_hclass_t http_server_class[] =
+HTTP_HEADER_CLASS_G(server, "Server", single);
+
+/* ====================================================================== */
+
+/**@HTTP_HEADER http_te TE header.
+ *
+ * The TE request-header field indicates what extension transfer-codings it
+ * is willing to accept in the response and whether or not it is willing to
+ * accept trailer fields in a chunked transfer-coding. Its value may consist
+ * of the keyword "trailers" and/or a comma-separated list of extension
+ * transfer-coding names with optional accept parameters. Its syntax is
+ * defined in [H14.39] as follows:
+ *
+ * @code
+ * TE = "TE" ":" #( t-codings )
+ * t-codings = "trailers" | ( transfer-extension [ accept-params ] )
+ * @endcode
+ *
+ */
+
+/**@ingroup http_te
+ * @typedef typedef strucy http_te_s http_te_t;
+ *
+ * The structure http_te_t contains representation of @b TE header.
+ *
+ * The http_te_t is defined as follows:
+ * @code
+ * typedef struct http_te_s {
+ * } http_te_t;
+ * @endcode
+ */
+
+static inline
+void http_te_update(http_te_t *te)
+{
+ te->te_q = msg_header_find_param(te->te_common, "q");
+}
+
+issize_t http_te_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
+{
+ msg_header_t **hh = &h->sh_succ, *h0 = h;
+ http_te_t *te = (http_te_t *)h;
+
+ assert(h); assert(sizeof(*h));
+
+ for (;*s;) {
+ /* Ignore empty entries (comma-whitespace) */
+ if (*s == ',') { *s++ = '\0'; skip_lws(&s); continue; }
+
+ if (!h) { /* Allocate next header structure */
+ if (!(h = msg_header_alloc(home, h0->sh_class, 0)))
+ break;
+ *hh = h; h->sh_prev = hh; hh = &h->sh_succ;
+ te = te->te_next = (http_te_t *)h;
+ }
+
+ /* "TE:" #(transfer-extension ; *(parameters))) */
+ if (msg_token_d(&s, &te->te_extension) == -1)
+ return -1;
+
+ if (*s == ';' && msg_params_d(home, &s, &te->te_params) == -1)
+ return -1;
+
+ if (*s != '\0' && *s != ',')
+ return -1;
+
+ if (te->te_params)
+ http_te_update(te);
+
+ h = NULL;
+ }
+
+ return 0;
+}
+
+issize_t http_te_e(char b[], isize_t bsiz, msg_header_t const *h, int flags)
+{
+ char *b0 = b, *end = b + bsiz;
+ http_te_t const *te = (http_te_t *)h;
+
+ assert(http_is_te(h));
+
+ MSG_STRING_E(b, end, te->te_extension);
+ MSG_PARAMS_E(b, end, te->te_params, flags);
+
+ MSG_TERM_E(b, end);
+
+ return b - b0;
+}
+
+isize_t http_te_dup_xtra(msg_header_t const *h, isize_t offset)
+{
+ http_te_t const *te = (http_te_t const *)h;
+
+ MSG_PARAMS_SIZE(offset, te->te_params);
+ offset += MSG_STRING_SIZE(te->te_extension);
+
+ return offset;
+}
+
+/** Duplicate one http_te_t object */
+char *http_te_dup_one(msg_header_t *dst, msg_header_t const *src,
+ char *b, isize_t xtra)
+{
+ http_te_t *te = (http_te_t *)dst;
+ http_te_t const *o = (http_te_t const *)src;
+ char *end = b + xtra;
+
+ b = msg_params_dup(&te->te_params, o->te_params, b, xtra);
+ MSG_STRING_DUP(b, te->te_extension, o->te_extension);
+ if (te->te_params) http_te_update(te);
+
+ assert(b <= end); (void)end;
+
+ return b;
+}
+
+msg_hclass_t http_te_class[] =
+HTTP_HEADER_CLASS(te, "TE", te_params, append, te);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_trailer Trailer header. */
+
+#define http_trailer_d msg_list_d
+#define http_trailer_e msg_list_e
+msg_hclass_t http_trailer_class[] =
+HTTP_HEADER_CLASS_LIST(trailer, "Trailer", list_critical);
+
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_transfer_encoding Transfer-Encoding header. */
+
+#define http_transfer_encoding_d msg_list_d
+#define http_transfer_encoding_e msg_list_e
+msg_hclass_t http_transfer_encoding_class[] =
+HTTP_HEADER_CLASS_LIST(transfer_encoding, "Transfer-Encoding", list_critical);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_upgrade Upgrade header. */
+
+#define http_upgrade_d msg_list_d
+#define http_upgrade_e msg_list_e
+msg_hclass_t http_upgrade_class[] =
+HTTP_HEADER_CLASS_LIST(upgrade, "Upgrade", list_critical);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_user_agent User-Agent header. */
+
+#define http_user_agent_d msg_generic_d
+#define http_user_agent_e msg_generic_e
+msg_hclass_t http_user_agent_class[] =
+HTTP_HEADER_CLASS_G(user_agent, "User-Agent", single);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_vary Vary header. */
+
+#define http_vary_d msg_list_d
+#define http_vary_e msg_list_e
+msg_hclass_t http_vary_class[] =
+HTTP_HEADER_CLASS_LIST(vary, "Vary", list);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_via Via header.
+ *
+ * @code
+ * Via = "Via" ":" 1#( received-protocol received-by [ comment ] )
+ * received-protocol = [ protocol-name "/" ] protocol-version
+ * protocol-name = token
+ * protocol-version = token
+ * received-by = ( host [ ":" port ] ) | pseudonym
+ * pseudonym = token
+ * @endcode
+ */
+
+issize_t http_via_d(su_home_t *home, http_header_t *h, char *s, isize_t slen)
+{
+ http_header_t **hh = &h->sh_succ, *h0 = h;
+ http_via_t *v = h->sh_via;
+
+ assert(h && h->sh_class);
+
+ for (;*s;) {
+ /* Ignore empty entries (comma-whitespace) */
+ if (*s == ',') { *s++ = '\0'; skip_lws(&s); continue; }
+
+ if (!h) { /* Allocate next header structure */
+ if (!(h = msg_header_alloc(home, h0->sh_class, 0)))
+ return -1;
+ *hh = h; h->sh_prev = hh; hh = &h->sh_succ;
+ v = v->v_next = h->sh_via;
+ }
+
+ if (http_version_d(&s, &v->v_version) == -1) /* Parse protocol version */
+ return -1;
+ if (msg_hostport_d(&s, &v->v_host, &v->v_port) == -1) /* Host (and port) */
+ return -1;
+ if (*s == '(' && msg_comment_d(&s, &v->v_comment) == -1) /* Comment */
+ return -1;
+ if (*s != '\0' && *s != ',') /* Extra before next header field? */
+ return -1;
+
+ h = NULL;
+ }
+
+ if (h) /* List without valid header via */
+ return -1;
+
+ return 0;
+}
+
+issize_t http_via_e(char b[], isize_t bsiz, http_header_t const *h, int flags)
+{
+ int const compact = MSG_IS_COMPACT(flags);
+ char *b0 = b, *end = b + bsiz;
+ http_via_t const *v = h->sh_via;
+
+ MSG_STRING_E(b, end, v->v_version);
+ MSG_CHAR_E(b, end, ' ');
+ MSG_STRING_E(b, end, v->v_host);
+ if (v->v_port) {
+ MSG_CHAR_E(b, end, ':');
+ MSG_STRING_E(b, end, v->v_port);
+ }
+ if (v->v_comment) {
+ if (!compact) MSG_CHAR_E(b, end, ' ');
+ MSG_CHAR_E(b, end, '(');
+ MSG_STRING_E(b, end, v->v_comment);
+ MSG_CHAR_E(b, end, ')');
+ }
+
+ MSG_TERM_E(b, end);
+
+ return b - b0;
+}
+
+static isize_t http_via_dup_xtra(http_header_t const *h, isize_t offset)
+{
+ http_via_t const *v = h->sh_via;
+
+ offset += MSG_STRING_SIZE(v->v_version);
+ offset += MSG_STRING_SIZE(v->v_host);
+ offset += MSG_STRING_SIZE(v->v_port);
+ offset += MSG_STRING_SIZE(v->v_comment);
+
+ return offset;
+}
+
+/** Duplicate one http_via_t object */
+static char *http_via_dup_one(http_header_t *dst, http_header_t const *src,
+ char *b, isize_t xtra)
+{
+ http_via_t *v = dst->sh_via;
+ http_via_t const *o = src->sh_via;
+ char *end = b + xtra;
+
+ MSG_STRING_DUP(b, v->v_version, o->v_version);
+ MSG_STRING_DUP(b, v->v_host, o->v_host);
+ MSG_STRING_DUP(b, v->v_port, o->v_port);
+ MSG_STRING_DUP(b, v->v_comment, o->v_comment);
+
+ assert(b <= end); (void)end;
+
+ return b;
+}
+
+msg_hclass_t http_via_class[] =
+HTTP_HEADER_CLASS(via, "Via", v_common, prepend, via);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_warning Warning header. */
+
+#define http_warning_d msg_warning_d
+#define http_warning_e msg_warning_e
+#define http_warning_dup_xtra msg_warning_dup_xtra
+#define http_warning_dup_one msg_warning_dup_one
+
+msg_hclass_t http_warning_class[] =
+ HTTP_HEADER_CLASS(warning, "Warning", w_common, append, warning);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_www_authenticate WWW-Authenticate header. */
+
+#define http_www_authenticate_d msg_auth_d
+#define http_www_authenticate_e msg_auth_e
+
+msg_hclass_t http_www_authenticate_class[] =
+HTTP_HEADER_CLASS_AUTH(www_authenticate, "WWW-Authenticate", single);
+
+/* ====================================================================== */
+
+/**@HTTP_HEADER http_error Erroneous headers.
+ *
+ * We use erroneous header object from @b msg module.
+ */
+
+/* ====================================================================== */
+
+/**@HTTP_HEADER http_unknown Unknown headers.
+ *
+ * We use unknown header object from @b msg module.
+ */
+/* ====================================================================== */
+
+/**@HTTP_HEADER http_separator Header separator.
+ *
+ * We use header separator object from @b msg module.
+ */
+/* ====================================================================== */
+
+/**@HTTP_HEADER http_payload Message payload.
+ *
+ * We use message body object from @b msg module.
+ */
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_extra.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_extra.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,469 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE http_extra.c
+ *
+ * Extra HTTP headers
+ *
+ * @author Pekka Pessi <Pekka.Pessi at 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>
+
+/* Avoid casting http_t to msg_pub_t and http_header_t to msg_header_t */
+#define MSG_PUB_T struct http_s
+#define MSG_HDR_T union http_header_u
+
+#include "sofia-sip/http_parser.h"
+
+/* ========================================================================== */
+
+/**@HTTP_HEADER http_proxy_connection Proxy-Connection extension header. */
+
+#define http_proxy_connection_d msg_list_d
+#define http_proxy_connection_e msg_list_e
+msg_hclass_t http_proxy_connection_class[] =
+HTTP_HEADER_CLASS_LIST(proxy_connection, "Proxy-Connection", list);
+
+/* ====================================================================== */
+/**@HTTP_HEADER http_cookie Cookie extension header.
+ *
+ * The Cookie header is used to transmit state information from server
+ * back to the http client. Its syntax is defined in RFC 2109 section 4.3.4
+ * as follows:
+ *
+ * @code
+ * cookie = "Cookie:" cookie-version
+ * 1*((";" | ",") cookie-value)
+ * cookie-value = NAME "=" VALUE [";" path] [";" domain]
+ * cookie-version = "$Version" "=" value
+ * NAME = attr
+ * VALUE = value
+ * path = "$Path" "=" value
+ * domain = "$Domain" "=" value
+ * @endcode
+ *
+ */
+
+/**@ingroup http_cookie
+ *
+ * @typedef typedef struct http_cookie_s http_cookie_t;
+ *
+ * The structure http_cookie_t contains representation of @b Cookie
+ * header. Please note that a single http_cookie_t can contain many
+ * cookies.
+ *
+ * The http_cookie_t is defined as follows:
+ * @code
+ * typedef struct http_cookie_s
+ * {
+ * } http_cookie_t;
+ * @endcode
+ */
+
+/**Update Cookie parameters.
+ *
+ * The function http_cookie_update() updates a @b Cookie parameter
+ * shortcuts.
+ *
+ * @param sc pointer to a @c http_cookie_t object
+ */
+static inline
+void http_cookie_update(http_cookie_t *c)
+{
+ size_t i;
+
+ c->c_name = NULL;
+ c->c_version = NULL, c->c_domain = NULL, c->c_path = NULL;
+
+ if (!c->c_params)
+ return;
+
+ if (!(MSG_PARAM_MATCH(c->c_version, c->c_params[0], "$Version")))
+ return;
+ if (!c->c_params[1] || c->c_params[1][0] == '$')
+ return;
+
+ c->c_name = c->c_params[1];
+
+ for (i = 2; ; i++) {
+ msg_param_t p = c->c_params[i];
+ if (!p || *p++ != '$')
+ break;
+ switch (p[0]) {
+ case 'd': case 'D':
+ MSG_PARAM_MATCH(c->c_domain, p, "Domain");
+ break;
+ case 'p': case 'P':
+ MSG_PARAM_MATCH(c->c_path, p, "Path");
+ break;
+ }
+ }
+}
+
+/* Scan a cookie parameter */
+static issize_t cookie_scanner(char *s)
+{
+ char *p = s;
+ size_t tlen;
+
+ skip_token(&s);
+
+ if (s == p) /* invalid parameter name */
+ return -1;
+
+ tlen = s - p;
+
+ if (IS_LWS(*s)) { *s++ = '\0'; skip_lws(&s); }
+
+ if (*s == '=') {
+ char *v;
+ s++;
+ skip_lws(&s);
+
+ v = s;
+
+ /* get value */
+ if (*s == '"') {
+ size_t qlen = span_quoted(s);
+ if (!qlen)
+ return -1;
+ s += qlen;
+ }
+ else {
+ s += strcspn(s, ",;" LWS);
+ if (s == v)
+ return -1;
+ }
+
+ if (p + tlen + 1 != v) {
+ memmove(p + tlen + 1, v, s - v);
+ p[tlen] = '=';
+ p[tlen + 1 + (s - v)] = '\0';
+ }
+ }
+
+ if (IS_LWS(*s)) { *s++ = '\0'; skip_lws(&s); }
+
+ return s - p;
+}
+
+/** Decode (parse) a Cookie header */
+issize_t http_cookie_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
+{
+ http_cookie_t *c = (http_cookie_t *)h;
+
+ assert(h); assert(sizeof(*h));
+
+ for (;*s;) {
+ /* Ignore empty entries (comma-whitespace) */
+ if (*s == ',') { *s++ = '\0'; skip_lws(&s); continue; }
+
+ if (msg_any_list_d(home, &s, (msg_param_t **)&c->c_params,
+ cookie_scanner, ';') == -1)
+ return -1;
+
+ if (*s != '\0' && *s != ',')
+ return -1;
+
+ if (!c->c_params)
+ return -1;
+ }
+
+ http_cookie_update(c);
+
+ return 0;
+}
+
+/** Encode (print) a Cookie header */
+issize_t http_cookie_e(char b[], isize_t bsiz, msg_header_t const *h, int flags)
+{
+ char *b0 = b, *end = b + bsiz;
+ http_cookie_t const *c = (http_cookie_t *)h;
+ size_t i;
+
+ if (c->c_params) {
+ for (i = 0; c->c_params[i]; i++) {
+ if (i > 0) MSG_CHAR_E(b, end, ';');
+ MSG_STRING_E(b, end, c->c_params[i]);
+ }
+ }
+
+ MSG_TERM_E(b, end);
+
+ return b - b0;
+}
+
+/** Calculate extra storage used by Cookie header field */
+isize_t http_cookie_dup_xtra(msg_header_t const *h, isize_t offset)
+{
+ http_cookie_t const *c = (http_cookie_t *)h;
+
+ MSG_PARAMS_SIZE(offset, c->c_params);
+
+ return offset;
+}
+
+/** Duplicate a Cookie header field */
+char *http_cookie_dup_one(msg_header_t *dst, msg_header_t const *src,
+ char *b, isize_t xtra)
+{
+ http_cookie_t *c = (http_cookie_t *)dst;
+ http_cookie_t const *o = (http_cookie_t const *)src;
+ char *end = b + xtra;
+
+ b = msg_params_dup(&c->c_params, o->c_params, b, xtra);
+ http_cookie_update(c);
+
+ assert(b <= end); (void)end;
+
+ return b;
+}
+
+msg_hclass_t http_cookie_class[] =
+HTTP_HEADER_CLASS(cookie, "Cookie", c_params, append, cookie);
+
+/* ====================================================================== */
+
+/**@HTTP_HEADER http_set_cookie Set-Cookie extension header.
+ *
+ * The Set-Cookie header is used to transmit state information from server
+ * back to the http client. Its syntax is defined in RFC 2109 section 4.2.2
+ * as follows:
+ *
+ * @code
+ * set-cookie = "Set-Cookie:" cookies
+ * cookies = 1#cookie
+ * cookie = NAME "=" VALUE *(";" cookie-av)
+ * NAME = attr
+ * VALUE = value
+ * cookie-av = "Comment" "=" value
+ * | "Domain" "=" value
+ * | "Max-Age" "=" value
+ * | "Path" "=" value
+ * | "Secure"
+ * | "Version" "=" 1*DIGIT
+ *
+ * @endcode
+ *
+ */
+
+/**@ingroup http_set_cookie
+ *
+ * @typedef typedef struct http_set_cookie_s http_set_cookie_t;
+ *
+ * The structure http_set_cookie_t contains representation of @b Set-Cookie
+ * header.
+ *
+ * The http_set_cookie_t is defined as follows:
+ * @code
+ * typedef struct http_set_cookie_s
+ * {
+ * } http_set_cookie_t;
+ * @endcode
+ */
+
+/**Update Set-Cookie parameters.
+ *
+ * The function http_set_cookie_update() updates a @b Set-Cookie parameter
+ * shortcuts.
+ *
+ * @param sc pointer to a @c http_set_cookie_t object
+ */
+static inline
+void http_set_cookie_update(http_set_cookie_t *sc)
+{
+ size_t i;
+
+ sc->sc_name = NULL;
+ sc->sc_version = NULL, sc->sc_domain = NULL, sc->sc_path = NULL;
+ sc->sc_comment = NULL, sc->sc_max_age = NULL, sc->sc_secure = 0;
+
+ if (!sc->sc_params)
+ return;
+
+ sc->sc_name = sc->sc_params[0];
+
+ for (i = 1; sc->sc_params[i]; i++) {
+ msg_param_t p = sc->sc_params[i];
+ switch (p[0]) {
+ case 'c': case 'C':
+ MSG_PARAM_MATCH(sc->sc_comment, p, "Comment");
+ break;
+ case 'd': case 'D':
+ MSG_PARAM_MATCH(sc->sc_domain, p, "Domain");
+ break;
+ case 'm': case 'M':
+ MSG_PARAM_MATCH(sc->sc_max_age, p, "Max-Age");
+ break;
+ case 'p': case 'P':
+ MSG_PARAM_MATCH(sc->sc_path, p, "Path");
+ break;
+ case 's': case 'S':
+ MSG_PARAM_MATCH_P(sc->sc_secure, p, "Secure");
+ break;
+ case 'v': case 'V':
+ MSG_PARAM_MATCH(sc->sc_version, p, "Version");
+ break;
+ }
+ }
+
+}
+
+#include <sofia-sip/msg_date.h>
+
+/* Scan a cookie parameter */
+static issize_t set_cookie_scanner(char *s)
+{
+ char *rest;
+
+#define LOOKING_AT(s, what) \
+ (strncasecmp((s), what, strlen(what)) == 0 && (rest = s + strlen(what)))
+
+ /* Special cases from Netscape spec */
+ if (LOOKING_AT(s, "expires=")) {
+ msg_time_t value;
+ msg_date_d((char const **)&rest, &value);
+ } else if (LOOKING_AT(s, "path=/")) {
+ for (;;) {
+ rest += span_unreserved(rest);
+ if (*rest != '/')
+ break;
+ rest++;
+ }
+ } else {
+ return msg_attribute_value_scanner(s);
+ }
+#undef LOOKING_AT
+
+ if (IS_LWS(*rest)) {
+ *rest++ = '\0'; skip_lws(&rest);
+ }
+
+ return rest - s;
+}
+
+/** Decode (parse) Set-Cookie header */
+issize_t http_set_cookie_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
+{
+ msg_header_t **hh = &h->sh_succ, *h0 = h;
+ http_set_cookie_t *sc = (http_set_cookie_t *)h;
+ msg_param_t *params;
+
+ assert(h); assert(sizeof(*h));
+
+ for (;*s;) {
+ /* Ignore empty entries (comma-whitespace) */
+ if (*s == ',') { *s++ = '\0'; skip_lws(&s); continue; }
+
+ if (!h) { /* Allocate next header structure */
+ if (!(h = msg_header_alloc(home, h0->sh_class, 0)))
+ return -1;
+ *hh = h; h->sh_prev = hh; hh = &h->sh_succ;
+ sc = sc->sc_next = (http_set_cookie_t *)h;
+ }
+
+ /* "Set-Cookie:" 1#(NAME "=" VALUE *(";" cookie-av))) */
+ params = su_zalloc(home, MSG_PARAMS_NUM(1) * sizeof(msg_param_t));
+ if (!params)
+ return -1;
+
+ params[0] = s, sc->sc_params = params;
+ s += strcspn(s, ",;" LWS);
+
+ if (*s) {
+ *s++ = '\0';
+ skip_lws(&s);
+ if (*s && msg_any_list_d(home, &s, (msg_param_t **)&sc->sc_params,
+ set_cookie_scanner, ';') == -1)
+ return -1;
+ }
+
+ if (*s != '\0' && *s != ',')
+ return -1;
+
+ if (sc->sc_params)
+ http_set_cookie_update(sc);
+
+ h = NULL;
+ }
+
+ return 0;
+}
+
+/** Encode (print) Set-Cookie header */
+issize_t http_set_cookie_e(char b[], isize_t bsiz, msg_header_t const *h, int flags)
+{
+ char *b0 = b, *end = b + bsiz;
+ http_set_cookie_t const *sc = (http_set_cookie_t *)h;
+ size_t i;
+
+ if (sc->sc_params) {
+ for (i = 0; sc->sc_params[i]; i++) {
+ if (i > 0) MSG_CHAR_E(b, end, ';');
+ MSG_STRING_E(b, end, sc->sc_params[i]);
+ }
+ }
+
+ MSG_TERM_E(b, end);
+
+ return b - b0;
+}
+
+/** Calculate extra storage used by Set-Cookie header field */
+isize_t http_set_cookie_dup_xtra(msg_header_t const *h, isize_t offset)
+{
+ http_set_cookie_t const *sc = (http_set_cookie_t *)h;
+
+ MSG_PARAMS_SIZE(offset, sc->sc_params);
+
+ return offset;
+}
+
+/** Duplicate a Set-Cookie header field */
+char *http_set_cookie_dup_one(msg_header_t *dst, msg_header_t const *src,
+ char *b, isize_t xtra)
+{
+ http_set_cookie_t *sc = (http_set_cookie_t *)dst;
+ http_set_cookie_t const *o = (http_set_cookie_t const *)src;
+ char *end = b + xtra;
+
+ b = msg_params_dup(&sc->sc_params, o->sc_params, b, xtra);
+ http_set_cookie_update(sc);
+
+ assert(b <= end); (void)end;
+
+ return b;
+}
+
+msg_hclass_t http_set_cookie_class[] =
+HTTP_HEADER_CLASS(set_cookie, "Set-Cookie", sc_params, append, set_cookie);
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_header.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_header.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,307 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE http_header.c
+ *
+ * HTTP header handling.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at 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 <stdio.h>
+#include <limits.h>
+#include <stdarg.h>
+
+#include <assert.h>
+
+#include <sofia-sip/su_alloc.h>
+
+/* Avoid casting http_t to msg_pub_t and http_header_t to msg_header_t */
+#define MSG_PUB_T struct http_s
+#define MSG_HDR_T union http_header_u
+#define HTTP_STATIC_INLINE
+
+#include "sofia-sip/http_parser.h"
+
+#include <sofia-sip/http_header.h>
+#include <sofia-sip/http_status.h>
+
+#ifndef UINT32_MAX
+#define UINT32_MAX (0xffffffffU)
+#endif
+
+/** Complete a HTTP request. */
+int http_request_complete(msg_t *msg)
+{
+ size_t len = 0;
+ http_t *http = http_object(msg);
+ http_payload_t const *pl;
+ su_home_t *home = msg_home(msg);
+
+ if (!http)
+ return -1;
+ if (!http->http_request)
+ return -1;
+ if (!http->http_host)
+ return -1;
+
+ for (pl = http->http_payload; pl; pl = pl->pl_next)
+ len += pl->pl_len;
+
+ if (len > UINT32_MAX)
+ return -1;
+
+ if (!http->http_content_length) {
+ http->http_content_length = http_content_length_create(home, (uint32_t)len);
+ }
+ else {
+ if (http->http_content_length->l_length != len) {
+ http->http_content_length->l_length = (uint32_t)len;
+ msg_fragment_clear(http->http_content_length->l_common);
+ }
+ }
+
+ if (!http->http_separator)
+ http->http_separator = http_separator_create(home);
+
+ return 0;
+}
+
+/** Remove schema, host, port, and fragment from HTTP/HTTPS URL */
+int http_strip_hostport(url_t *url)
+{
+ if (url->url_type == url_http || url->url_type == url_https) {
+ url->url_type = url_unknown;
+ url->url_scheme = NULL;
+ url->url_user = NULL;
+ url->url_password = NULL;
+ url->url_host = NULL;
+ url->url_port = NULL;
+ if (url->url_path == NULL) {
+ url->url_root = '/';
+ url->url_path = "";
+ }
+ }
+
+ url->url_fragment = NULL;
+
+ return 0;
+}
+
+/** Add a Content-Length and separator to a message */
+int http_message_complete(msg_t *msg, http_t *http)
+{
+#if 1
+ if (!http->http_content_length) {
+ http_content_length_t *l;
+ http_payload_t *pl;
+ size_t len = 0;
+
+ for (pl = http->http_payload; pl; pl = pl->pl_next)
+ len += pl->pl_len;
+
+ if (len > UINT32_MAX)
+ return -1;
+
+ l = http_content_length_create(msg_home(msg), (uint32_t)len);
+
+ if (msg_header_insert(msg, http, (http_header_t *)l) < 0)
+ return -1;
+ }
+#endif
+
+ if (!http->http_separator) {
+ http_separator_t *sep = http_separator_create(msg_home(msg));
+ if (msg_header_insert(msg, http, (http_header_t *)sep) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+/** Add headers from the request to the response message. */
+int http_complete_response(msg_t *msg,
+ int status, char const *phrase,
+ http_t const *request)
+{
+ su_home_t *home = msg_home(msg);
+ http_t *http = msg_object(msg);
+
+ if (!http || !request || !request->http_request)
+ return -1;
+
+ if (!http->http_status)
+ http->http_status = http_status_create(home, status, phrase, NULL);
+
+ if (!http->http_status)
+ return -1;
+
+ if (!http->http_separator) {
+ http_separator_t *sep = http_separator_create(msg_home(msg));
+ if (msg_header_insert(msg, http, (http_header_t *)sep) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+/** Copy a HTTP header. */
+http_header_t *http_header_copy(su_home_t *home, http_header_t const *h)
+{
+ if (h == NULL || h == HTTP_NONE)
+ return NULL;
+ return msg_header_copy_as(home, h->sh_class, h);
+}
+
+/** Duplicate a HTTP header. */
+http_header_t *http_header_dup(su_home_t *home, http_header_t const *h)
+{
+ if (h == NULL || h == HTTP_NONE)
+ return NULL;
+ return msg_header_dup_as(home, h->sh_class, h);
+
+}
+
+/** Decode a HTTP header. */
+http_header_t *http_header_d(su_home_t *home, msg_t const *msg, char const *b)
+{
+ return msg_header_d(home, msg, b);
+}
+
+/** Encode a HTTP header. */
+int http_header_e(char b[], int bsiz, http_header_t const *h, int flags)
+{
+ return msg_header_e(b, bsiz, h, flags);
+}
+
+/** Encode HTTP header contents. */
+int http_header_field_e(char b[], int bsiz, http_header_t const *h, int flags)
+{
+ assert(h); assert(h->sh_class);
+
+ return h->sh_class->hc_print(b, bsiz, h, flags);
+}
+
+http_header_t *http_header_format(su_home_t *home,
+ msg_hclass_t *hc,
+ char const *fmt,
+ ...)
+{
+ http_header_t *h;
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ h = http_header_vformat(home, hc, fmt, ap);
+
+ va_end(ap);
+
+ return h;
+}
+
+/** Add a duplicate of header object to a HTTP message. */
+int http_add_dup(msg_t *msg,
+ http_t *http,
+ http_header_t const *o)
+{
+ if (o == HTTP_NONE)
+ return 0;
+
+ if (msg == NULL || o == NULL)
+ return -1;
+
+ return msg_header_insert(msg, http, msg_header_dup(msg_home(msg), o));
+}
+
+int http_add_make(msg_t *msg,
+ http_t *http,
+ msg_hclass_t *hc,
+ char const *s)
+{
+ if (s == NULL)
+ return 0;
+
+ if (msg == NULL)
+ return -1;
+
+ return msg_header_insert(msg, http, msg_header_make(msg_home(msg), hc, s));
+}
+
+int http_add_format(msg_t *msg,
+ http_t *http,
+ msg_hclass_t *hc,
+ char const *fmt,
+ ...)
+{
+ http_header_t *h;
+ va_list ap;
+
+ if (fmt == NULL)
+ return 0;
+
+ if (msg == NULL)
+ return -1;
+
+ va_start(ap, fmt);
+ h = http_header_vformat(msg_home(msg), hc, fmt, ap);
+ va_end(ap);
+
+ return msg_header_insert(msg, http, h);
+}
+
+/** Compare two HTTP URLs. */
+int http_url_cmp(url_t const *a, url_t const *b)
+{
+ int rv;
+
+ if ((rv = url_cmp(a, b)))
+ return rv;
+
+ if (a->url_path != b->url_path) {
+ if (a->url_path == NULL) return -1;
+ if (b->url_path == NULL) return +1;
+ if ((rv = strcmp(a->url_path, b->url_path)))
+ return rv;
+ }
+
+ /* Params? */
+
+ /* Query */
+ if (a->url_headers != b->url_headers) {
+ if (a->url_headers == NULL) return -1;
+ if (b->url_headers == NULL) return +1;
+ if ((rv = strcmp(a->url_headers, b->url_headers)))
+ return rv;
+ }
+
+ return 0;
+}
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_parser.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_parser.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,573 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE http_parser.c
+ *
+ * HTTP parser.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Oct 5 14:01:24 2000 ppessi
+ */
+
+#include "config.h"
+
+/* Avoid casting http_t to msg_pub_t and http_header_t to msg_header_t */
+#define MSG_PUB_T struct http_s
+#define MSG_HDR_T union http_header_u
+
+#include <sofia-sip/su_alloc.h>
+#include "sofia-sip/http_parser.h"
+#include <sofia-sip/msg_parser.h>
+#include <sofia-sip/http_header.h>
+#include <sofia-sip/http_status.h>
+#include <sofia-sip/msg_mclass.h>
+
+#include <sofia-sip/su_tagarg.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <limits.h>
+#include <stdarg.h>
+
+/** HTTP version 1.1. */
+char const http_version_1_1[] = "HTTP/1.1";
+/** HTTP version 1.0. */
+char const http_version_1_0[] = "HTTP/1.0";
+/** HTTP version 0.9 is an empty string. */
+char const http_version_0_9[] = "";
+
+msg_mclass_t *http_default_mclass(void)
+{
+ extern msg_mclass_t http_mclass[];
+
+ return http_mclass;
+}
+
+static
+issize_t http_extract_chunk(msg_t *, http_t *, char b[], isize_t bsiz, int eos);
+
+/** Calculate length of line ending (0, 1 or 2) */
+#define CRLF_TEST(s) \
+ (((s)[0]) == '\r' ? (((s)[1]) == '\n') + 1 : ((s)[0])=='\n')
+
+/** Extract the HTTP message body, including separator line.
+ *
+ * @retval -1 error
+ * @retval 0 cannot proceed
+ * @retval other number of bytes extracted
+ */
+issize_t http_extract_body(msg_t *msg, http_t *http, char b[], isize_t bsiz, int eos)
+{
+ issize_t m = 0;
+ size_t body_len;
+
+ int flags = http->http_flags;
+
+ if (eos && bsiz == 0) {
+ msg_mark_as_complete(msg, MSG_FLG_COMPLETE);
+ return 0;
+ }
+
+ if (flags & MSG_FLG_TRAILERS) {
+ /* The empty line after trailers */
+ if (!eos && (bsiz == 0 || (bsiz == 1 && b[0] == '\r')))
+ return 0;
+
+ m = CRLF_TEST(b);
+
+ assert(m > 0 || eos); /* We should be looking at an empty line */
+
+ /* We have completed trailers */
+ msg_mark_as_complete(msg, MSG_FLG_COMPLETE);
+
+ return m;
+ }
+
+ if (flags & MSG_FLG_CHUNKS)
+ return http_extract_chunk(msg, http, b, bsiz, eos);
+
+ if (!(flags & MSG_FLG_BODY)) {
+ /* We are looking at a potential empty line */
+ m = msg_extract_separator(msg, http, b, bsiz, eos);
+
+ if (m == 0) /* Not yet */
+ return 0;
+
+ http->http_flags |= MSG_FLG_BODY;
+ b += m, bsiz -= m;
+ }
+
+ /* body_len is determined by rules in RFC2616 sections 4.3 and 4.4 */
+
+ /* 1XX, 204, 304 do not have message-body, ever */
+ if (http->http_status) {
+ int status = http->http_status->st_status;
+
+ if (status < 200 || status == 204 || status == 304)
+ flags |= HTTP_FLG_NO_BODY;
+ }
+
+ if (flags & HTTP_FLG_NO_BODY) {
+ msg_mark_as_complete(msg, MSG_FLG_COMPLETE);
+ return m;
+ }
+
+ if (http->http_transfer_encoding) {
+ if (/* NOTE - there is really no Transfer-Encoding: identity in RFC 2616
+ * but it was used in drafts...
+ */
+ http->http_transfer_encoding->k_items &&
+ http->http_transfer_encoding->k_items[0] &&
+ strcasecmp(http->http_transfer_encoding->k_items[0],
+ "identity") != 0) {
+ http->http_flags |= MSG_FLG_CHUNKS;
+
+ if (http->http_flags & MSG_FLG_STREAMING)
+ msg_set_streaming(msg, msg_start_streaming);
+
+ if (m)
+ return m;
+
+ return http_extract_chunk(msg, http, b, bsiz, eos);
+ }
+ }
+
+
+ if (http->http_content_length)
+ body_len = http->http_content_length->l_length;
+ /* We cannot parse multipart/byteranges ... */
+ else if (http->http_content_type && http->http_content_type->c_type &&
+ strcasecmp(http->http_content_type->c_type, "multipart/byteranges")
+ == 0)
+ return -1;
+ else if (MSG_IS_MAILBOX(flags)) /* message fragments */
+ body_len = 0;
+ else if (http->http_request)
+ body_len = 0;
+ else if (eos)
+ body_len = bsiz;
+ else
+ return 0; /* XXX */
+
+ if (body_len == 0) {
+ msg_mark_as_complete(msg, MSG_FLG_COMPLETE);
+ return m;
+ }
+
+ if (http->http_flags & MSG_FLG_STREAMING)
+ msg_set_streaming(msg, msg_start_streaming);
+
+ if (m)
+ return m;
+
+ m = msg_extract_payload(msg, http, NULL, body_len, b, bsiz, eos);
+ if (m == -1)
+ return -1;
+
+ /* We have now all message fragments in place */
+ http->http_flags |= MSG_FLG_FRAGS;
+ if (bsiz >= body_len) {
+ msg_mark_as_complete(msg, MSG_FLG_COMPLETE);
+ }
+
+ return m;
+}
+
+/** Extract a chunk.
+ *
+ * @retval -1 error
+ * @retval 0 cannot proceed
+ * @retval other number of bytes extracted
+ */
+issize_t http_extract_chunk(msg_t *msg, http_t *http, char b[], isize_t bsiz, int eos)
+{
+ size_t n;
+ unsigned crlf, chunk_len;
+ char *b0 = b, *s;
+ union {
+ msg_header_t *header;
+ msg_payload_t *chunk;
+ } h = { NULL };
+ size_t bsiz0 = bsiz;
+
+ if (bsiz == 0)
+ return 0;
+
+ /* We should be looking at an empty line followed by the chunk header */
+ while ((crlf = CRLF_TEST(b))) {
+ if (bsiz == 1 && crlf == 1 && b[0] == '\r' && !eos)
+ return 0;
+
+ if (crlf == bsiz) {
+ if (eos) {
+ msg_mark_as_complete(msg, MSG_FLG_COMPLETE | MSG_FLG_FRAGS);
+ return (b - b0) + crlf;
+ }
+ else
+ return 0;
+ }
+ assert(crlf < bsiz);
+
+ /* Skip crlf */
+ b += crlf; bsiz -= crlf;
+ }
+
+ /* Now, looking at the chunk header */
+ n = strcspn(b, CRLF);
+ if (!eos && n == bsiz)
+ return 0;
+ crlf = CRLF_TEST(b + n);
+
+ if (n == 0) {
+ if (crlf == bsiz && eos) {
+ msg_mark_as_complete(msg, MSG_FLG_COMPLETE | MSG_FLG_FRAGS);
+ return crlf;
+ }
+ else
+ return -1; /* XXX - should we be more liberal? */
+ }
+
+ if (!eos && n + crlf == bsiz && (crlf == 0 || (crlf == 1 && b[n] == '\r')))
+ return 0;
+
+ chunk_len = strtoul(b, &s, 16);
+ if (s == b)
+ return -1;
+ skip_ws(&s);
+ if (s != b + n && s[0] != ';') /* Extra stuff that is not parameter */
+ return -1;
+
+ if (chunk_len == 0) { /* We found last-chunk */
+ b += n + crlf, bsiz -= n + crlf;
+
+ crlf = bsiz > 0 ? CRLF_TEST(b) : 0;
+
+ if ((eos && bsiz == 0) || crlf == 2 ||
+ (crlf == 1 && (bsiz > 1 || b[0] == '\n'))) {
+ /* Shortcut - We got empty trailers */
+ b += crlf;
+ msg_mark_as_complete(msg, MSG_FLG_COMPLETE | MSG_FLG_FRAGS);
+ } else {
+ /* We have to parse trailers */
+ http->http_flags |= MSG_FLG_TRAILERS;
+ }
+
+ return b - b0;
+ }
+ else {
+ issize_t chunk;
+
+ b += n + crlf, bsiz -= n + crlf;
+
+ /* Extract chunk */
+ chunk = msg_extract_payload(msg, http,
+ &h.header, chunk_len + (b - b0),
+ b0, bsiz0, eos);
+
+ if (chunk != -1 && h.header) {
+ assert(h.chunk->pl_data);
+ h.chunk->pl_data += (b - b0);
+ h.chunk->pl_len -= (b - b0);
+ }
+
+ return chunk;
+ }
+}
+
+/** Parse HTTP version.
+ *
+ * The function http_version_d() parses a HTTP method.
+ *
+ * @retval 0 when successful,
+ * @retval -1 upon an error.
+ */
+int http_version_d(char **ss, char const **ver)
+{
+ char *s = *ss;
+ char const *result;
+ int const version_size = sizeof(http_version_1_1) - 1;
+
+ if (strncasecmp(s, http_version_1_1, version_size) == 0 &&
+ !IS_TOKEN(s[version_size])) {
+ result = http_version_1_1;
+ s += version_size;
+ }
+ else if (strncasecmp(s, http_version_1_0, version_size) == 0 &&
+ !IS_TOKEN(s[version_size])) {
+ result = http_version_1_0;
+ s += version_size;
+ }
+ else if (s[0] == '\0') {
+ result = http_version_0_9;
+ } else {
+ /* Version consists of one or two tokens, separated by / */
+ size_t l1 = 0, l2 = 0, n;
+
+ result = s;
+
+ l1 = span_token(s);
+ for (n = l1; IS_LWS(s[n]); n++)
+ s[n] = '\0';
+ if (s[n] == '/') {
+ for (n = n + 1; IS_LWS(s[n]); n++);
+ l2 = span_token(s + n);
+ n += l2;
+ }
+
+ if (l1 == 0)
+ return -1;
+
+ /* If there is extra ws between tokens, compact version */
+ if (l2 > 0 && n > l1 + 1 + l2) {
+ s[l1] = '/';
+ memmove(s + l1 + 1, s + n - l2, l2);
+ s[l1 + 1 + l2] = 0;
+
+ /* Compare again with compacted version */
+ if (strcasecmp(s, http_version_1_1) == 0)
+ result = http_version_1_1;
+ else if (strcasecmp(s, http_version_1_0) == 0)
+ result = http_version_1_0;
+ }
+
+ s += n;
+ }
+
+ while (IS_LWS(*s)) *s++ = '\0';
+
+ *ss = s;
+
+ if (ver)
+ *ver = result;
+
+ return 0;
+}
+
+/** Calculate extra space required by version string */
+isize_t http_version_xtra(char const *version)
+{
+ if (version == http_version_1_1)
+ return 0;
+ else if (version == http_version_1_0)
+ return 0;
+ else
+ return MSG_STRING_SIZE(version);
+}
+
+/** Duplicate a transport string */
+void http_version_dup(char **pp, char const **dd, char const *s)
+{
+ if (s == http_version_1_1)
+ *dd = s;
+ else if (s == http_version_1_0)
+ *dd = s;
+ else
+ MSG_STRING_DUP(*pp, *dd, s);
+}
+
+/** Well-known HTTP method names. */
+static char const * const methods[] = {
+ "<UNKNOWN>",
+ http_method_name_get,
+ http_method_name_post,
+ http_method_name_head,
+ http_method_name_options,
+ http_method_name_put,
+ http_method_name_delete,
+ http_method_name_trace,
+ http_method_name_connect,
+ NULL,
+ /* If you add something here, add also them to http_method_d! */
+};
+
+char const http_method_name_get[] = "GET";
+char const http_method_name_post[] = "POST";
+char const http_method_name_head[] = "HEAD";
+char const http_method_name_options[] = "OPTIONS";
+char const http_method_name_put[] = "PUT";
+char const http_method_name_delete[] = "DELETE";
+char const http_method_name_trace[] = "TRACE";
+char const http_method_name_connect[] = "CONNECT";
+
+char const *http_method_name(http_method_t method, char const *name)
+{
+ if (method > 0 && (size_t)method < sizeof(methods)/sizeof(methods[0]))
+ return methods[method];
+ else if (method == 0)
+ return name;
+ else
+ return NULL;
+}
+
+/**Parse a HTTP method name.
+ *
+ * The function @c http_method_d() parses a HTTP method, and returns a code
+ * corresponding to the method. It stores the address of the first non-LWS
+ * character after method name in @c *ss.
+ *
+ * @param ss pointer to pointer to string to be parsed
+ * @param nname pointer to value-result parameter formethod name
+ *
+ * @note
+ * If there is no whitespace after method name, the value in @a *nname
+ * may not be NUL-terminated. The calling function @b must NUL terminate
+ * the value by setting the @a **ss to NUL after first examining its value.
+ *
+ * @return The function @c http_method_d returns the method code if method
+ * was identified, 0 (@c http_method_unknown) if method is not known, or @c -1
+ * (@c http_method_invalid) if an error occurred.
+ *
+ * If the value-result argument @a nname is not @c NULL, http_method_d()
+ * stores a pointer to the method name to it.
+ */
+http_method_t http_method_d(char **ss, char const **nname)
+{
+ char *s = *ss, c = *s;
+ char const *name;
+ int code = http_method_unknown;
+ size_t n = 0;
+
+#define MATCH(s, m) (strncasecmp(s, m, n = sizeof(m) - 1) == 0)
+
+ if (c >= 'a' && c <= 'z')
+ c += 'A' - 'a';
+
+ switch (c) {
+ case 'C': if (MATCH(s, "CONNECT")) code = http_method_connect; break;
+ case 'D': if (MATCH(s, "DELETE")) code = http_method_delete; break;
+ case 'G': if (MATCH(s, "GET")) code = http_method_get; break;
+ case 'H': if (MATCH(s, "HEAD")) code = http_method_head; break;
+ case 'O': if (MATCH(s, "OPTIONS")) code = http_method_options; break;
+ case 'P': if (MATCH(s, "POST")) code = http_method_post;
+ else
+ if (MATCH(s, "PUT")) code = http_method_put; break;
+ case 'T': if (MATCH(s, "TRACE")) code = http_method_trace; break;
+ }
+
+#undef MATCH
+
+ if (!code || IS_NON_WS(s[n])) {
+ /* Unknown method */
+ code = http_method_unknown;
+ name = s;
+ for (n = 0; IS_UNRESERVED(s[n]); n++)
+ ;
+ if (s[n]) {
+ if (!IS_LWS(s[n]))
+ return http_method_invalid;
+ if (nname)
+ s[n++] = '\0';
+ }
+ }
+ else {
+ name = methods[code];
+ }
+
+ while (IS_LWS(s[n]))
+ n++;
+
+ *ss = (s + n);
+ if (nname) *nname = name;
+
+ return code;
+}
+
+/** Get method enum corresponding to method name */
+http_method_t http_method_code(char const *name)
+{
+ /* Note that http_method_d() does not change string if nname is NULL */
+ return http_method_d((char **)&name, NULL);
+}
+
+/**Parse HTTP query string.
+ *
+ * The function http_query_parse() searches for the given keys in HTTP @a
+ * query. For each key, a query element (in the form name=value) is searched
+ * from the query string. If a query element has a beginning matching with
+ * the key, a copy of the rest of the element is returned in corresponding
+ * return_value argument.
+ *
+ * @note The @a query string will be modified.
+ *
+ * @return
+ * The function http_query_parse() returns number keys that matched within
+ * the @a query string.
+ */
+issize_t http_query_parse(char *query,
+ /* char const *key, char **return_value, */
+ ...)
+{
+ va_list ap;
+ char *q, *q_next;
+ char *name, *value, **return_value;
+ char const *key;
+ size_t namelen, valuelen, keylen;
+ isize_t N;
+ int has_value;
+
+ if (!query)
+ return -1;
+
+ for (q = query, N = 0; *q; q = q_next) {
+ namelen = strcspn(q, "=&");
+ valuelen = namelen + strcspn(q + namelen, "&");
+
+ q_next = q + valuelen;
+ if (*q_next)
+ *q_next++ = '\0';
+
+ value = q + namelen;
+ has_value = (*value) != '\0'; /* is the part in form of name=value? */
+ if (has_value)
+ *value++ = '\0';
+
+ name = url_unescape(q, q);
+
+ if (has_value) {
+ namelen = strlen(name);
+ name[namelen] = '=';
+ url_unescape(name + namelen + 1, value);
+ }
+
+ va_start(ap, query);
+
+ while ((key = va_arg(ap, char const *))) {
+ return_value = va_arg(ap, char **);
+ keylen = strlen(key);
+
+ if (strncmp(key, name, keylen) == 0) {
+ *return_value = name + keylen;
+ N++;
+ }
+ }
+
+ va_end(ap);
+ }
+
+ return N;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_parser_table.c.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_parser_table.c.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1,59 @@
+/** -*- C -*-
+ * @IFILE http_parser_table.c.in
+ *
+ * Template for <http_parser_table.c>.
+ *
+ * @date Created: Tue Oct 1 20:37:52 2002 ppessi
+ */
+
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@internal
+ * @CFILE http_parser_table.c
+ * @brief HTTP parser table
+ *
+ * #AUTO#
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Oct 1 20:37:52 2002 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <string.h>
+
+/* Avoid casting http_t to msg_pub_t and http_header_t to msg_header_t */
+#define MSG_PUB_T struct http_s
+#define MSG_HDR_T union http_header_u
+
+#include <sofia-sip/http_parser.h>
+#include <sofia-sip/msg_mclass.h>
+
+#define HTTP_PARSER_FLAGS (MSG_FLG_CHUNKING)
+
+
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_status.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_status.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,130 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE http_status.c HTTP status codes.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Sep 18 18:58:21 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <sofia-sip/http_status.h>
+
+char const
+ http_100_continue[] = "Continue",
+ http_101_switching[] = "Switching Protocols",
+ http_200_ok[] = "OK",
+ http_201_created[] = "Created",
+ http_202_accepted[] = "Accepted",
+ http_203_non_auth_info[] = "Non-Authoritative Information",
+ http_204_no_content[] = "No Content",
+ http_205_reset_content[] = "Reset Content",
+ http_206_partial_content[] = "Partial Content",
+ http_300_multiple_choices[] = "Multiple Choices",
+ http_301_moved_permanently[] = "Moved Permanently",
+ http_302_found[] = "Found",
+ http_303_see_other[] = "See Other",
+ http_304_not_modified[] = "Not Modified",
+ http_305_use_proxy[] = "Use Proxy",
+ http_307_temporary_redirect[] = "Temporary Redirect",
+ http_400_bad_request[] = "Bad Request",
+ http_401_unauthorized[] = "Unauthorized",
+ http_402_payment_required[] = "Payment Required",
+ http_403_forbidden[] = "Forbidden",
+ http_404_not_found[] = "Not Found",
+ http_405_not_allowed[] = "Method Not Allowed",
+ http_406_not_acceptable[] = "Not Acceptable",
+ http_407_proxy_auth[] = "Proxy Authentication Required",
+ http_408_timeout[] = "Request Timeout",
+ http_409_conflict[] = "Conflict",
+ http_410_gone[] = "Gone",
+ http_411_no_length[] = "Length Required",
+ http_412_precondition[] = "Precondition Failed",
+ http_413_entity_too_large[] = "Request Entity Too Large",
+ http_414_uri_too_long[] = "Request-URI Too Long",
+ http_415_media_type[] = "Unsupported Media Type",
+ http_416_requested_range[] = "Requested Range Not Satisfiable",
+ http_417_expectation[] = "Expectation Failed",
+ http_426_upgrade[] = "Upgrade Required",
+ http_500_internal_server[] = "Internal Server Error",
+ http_501_not_implemented[] = "Not Implemented",
+ http_502_bad_gateway[] = "Bad Gateway",
+ http_503_no_service[] = "Service Unavailable",
+ http_504_gateway_timeout[] = "Gateway Timeout",
+ http_505_http_version[] = "HTTP Version Not Supported";
+
+char const *http_status_phrase(int status)
+{
+ if (status < 100 || status > 699)
+ return NULL;
+
+ switch (status) {
+ case 100: return http_100_continue;
+ case 101: return http_101_switching;
+ case 200: return http_200_ok;
+ case 201: return http_201_created;
+ case 202: return http_202_accepted;
+ case 203: return http_203_non_auth_info;
+ case 204: return http_204_no_content;
+ case 205: return http_205_reset_content;
+ case 206: return http_206_partial_content;
+ case 300: return http_300_multiple_choices;
+ case 301: return http_301_moved_permanently;
+ case 302: return http_302_found;
+ case 303: return http_303_see_other;
+ case 304: return http_304_not_modified;
+ case 305: return http_305_use_proxy;
+ case 307: return http_307_temporary_redirect;
+ case 400: return http_400_bad_request;
+ case 401: return http_401_unauthorized;
+ case 402: return http_402_payment_required;
+ case 403: return http_403_forbidden;
+ case 404: return http_404_not_found;
+ case 405: return http_405_not_allowed;
+ case 406: return http_406_not_acceptable;
+ case 407: return http_407_proxy_auth;
+ case 408: return http_408_timeout;
+ case 409: return http_409_conflict;
+ case 410: return http_410_gone;
+ case 411: return http_411_no_length;
+ case 412: return http_412_precondition;
+ case 413: return http_413_entity_too_large;
+ case 414: return http_414_uri_too_long;
+ case 415: return http_415_media_type;
+ case 416: return http_416_requested_range;
+ case 417: return http_417_expectation;
+ case 426: return http_426_upgrade;
+ case 500: return http_500_internal_server;
+ case 501: return http_501_not_implemented;
+ case 502: return http_502_bad_gateway;
+ case 503: return http_503_no_service;
+ case 504: return http_504_gateway_timeout;
+ case 505: return http_505_http_version;
+ }
+
+ return " ";
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_tag.c.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_tag.c.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1,68 @@
+/**@HTTP
+ * @IFILE http_tag.c.in
+ *
+ * Template for <http_tag.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 at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@file http_tag.c HTTP Tag classes
+ *
+ * This file is autogenerated from <http_tag.c.in>.
+ *
+ * #AUTO#
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ */
+
+#include "config.h"
+
+#define TAG_NAMESPACE "http"
+
+#include <assert.h>
+#include <stddef.h>
+#include <string.h>
+
+#include <sofia-sip/su.h>
+
+#include <sofia-sip/http.h>
+#include <sofia-sip/http_protos.h>
+#include <sofia-sip/http_tag.h>
+#include <sofia-sip/http_tag_class.h>
+
+tag_typedef_t httptag_any = NSTAG_TYPEDEF(*);
+
+tag_typedef_t httptag_http = HTTPMSGTAG_TYPEDEF(http);
+tag_typedef_t httptag_version = STRTAG_TYPEDEF(version);
+tag_typedef_t httptag_header =
+ {{ TAG_NAMESPACE, "header", httphdrtag_class, 0 }};
+tag_typedef_t httptag_header_str = STRTAG_TYPEDEF(header_str);
+
+
+tag_typedef_t httptag_#xxxxxx# = HTTPHDRTAG_TYPEDEF(#xxxxxx#);
+tag_typedef_t httptag_#xxxxxx#_str = HTTPSTRTAG_TYPEDEF(#xxxxxx#);
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_tag_class.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/http_tag_class.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,222 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE http_tag_class.c HTTP tag classes
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Fri Feb 23 12:46:42 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <assert.h>
+#include <stddef.h>
+#include <string.h>
+
+#include <sofia-sip/su.h>
+
+/* Avoid casting http_t to msg_pub_t and http_header_t to msg_header_t */
+#define MSG_PUB_T struct http_s
+#define MSG_HDR_T union http_header_u
+
+#include <sofia-sip/http_parser.h>
+
+#include <sofia-sip/http_tag.h>
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/su_tag_inline.h>
+#include <sofia-sip/http_tag_class.h>
+#include <sofia-sip/su_tagarg.h>
+
+tag_class_t httphdrtag_class[1] =
+ {{
+ sizeof(httphdrtag_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 */ httptag_filter,
+ /* tc_ref_set */ t_ptr_ref_set,
+ /* tc_scan */ msghdrtag_scan,
+ }};
+
+tag_class_t httpstrtag_class[1] =
+ {{
+ sizeof(httpstrtag_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 */ msghdrtag_scan,
+ }};
+
+tag_class_t httpmsgtag_class[1] =
+ {{
+ sizeof(httpmsgtag_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 /* httptag_http_filter */,
+ /* tc_ref_set */ t_ptr_ref_set,
+ /* tc_scan */ t_str_scan
+ }};
+
+/** Filter a HTTP header structure. */
+tagi_t *httptag_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 == httpmsgtag_class) {
+ http_t const *http;
+ msg_mclass_t const *mc;
+ http_header_t const *h, **hh;
+
+ http = (http_t const *)src->t_value;
+ mc = (void *)http->http_common->h_class;
+ hh = (void *)msg_hclass_offset(mc, http, hc);
+
+ if (http == NULL ||
+ (char *)hh >= ((char *)http + http->http_size) ||
+ (char *)hh < (char *)&http->http_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;
+ }
+}
+
+/** Duplicate headers from taglist and add them to the HTTP message.
+ *
+ * Return the number of headers added to the HTTP message.
+ */
+int http_add_tl(msg_t *msg, http_t *http,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ tagi_t const *t;
+ ta_list ta;
+ int retval = 0;
+
+ if (msg == NULL)
+ return -1;
+ if (http == NULL)
+ http = msg_object(msg);
+
+ 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 (HTTPTAG_P(tag)) {
+ msg_hclass_t *hc = (msg_hclass_t *)tag->tt_magic;
+ http_header_t *h = (http_header_t *)value, **hh;
+
+ if (h == HTTP_NONE) { /* Remove header(s) */
+ if (hc == NULL)
+ break;
+
+ hh = msg_hclass_offset(msg_mclass(msg), http, hc);
+ if (!hh)
+ break;
+
+ while (*hh) {
+ msg_header_remove(msg, http, *hh);
+ }
+ }
+ else if (h == NULL) {
+ continue;
+ } else {
+ if (tag == httptag_header)
+ hc = h->sh_class;
+
+ if (msg_header_add_dup_as(msg, http, hc, h) < 0)
+ break;
+ }
+ }
+ else if (HTTPTAG_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, http, hc, s) < 0)
+ break;
+ }
+ else if (tag == httptag_header_str) {
+ if (msg_header_add_str(msg, http, (char const *)value) < 0)
+ break;
+ }
+ else
+ continue;
+
+ retval++;
+ }
+
+ ta_end(ta);
+
+ if (t)
+ return -1;
+
+ return retval;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,482 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef HTTP_H
+/** Defined when <sofia-sip/http.h> has been included. */
+#define HTTP_H
+
+/**@file sofia-sip/http.h
+ *
+ * HTTP message, methods, headers.
+ *
+ * @sa <a href="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616</a>
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created : Thu Jun 8 19:28:55 2000 ppessi
+ */
+
+#ifndef MSG_H
+#include <sofia-sip/msg.h>
+#endif
+#ifndef URL_H
+#include <sofia-sip/url.h>
+#endif
+#ifndef MSG_MIME_H
+#include <sofia-sip/msg_mime.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/* ----------------------------------------------------------------------
+ * 1) Constants
+ */
+
+#define HTTP_NONE ((http_header_t *)MSG_HEADER_NONE)
+#define HTTP_DEFAULT_PORT (80)
+#define HTTP_DEFAULT_SERV "80"
+
+/** HTTP protocol identifier */
+#define HTTP_PROTOCOL_TAG ((void *)0x48545450) /* 'HTTP' */
+
+/** HTTP parser flags */
+enum {
+ HTTP_FLG_NO_BODY = (1 << 15)
+};
+
+/** IDs for well-known HTTP methods. */
+typedef enum {
+ http_method_invalid = -1, /**< Invalid method name */
+ http_method_unknown = 0, /**< Unknown method, use @c method_name */
+ http_method_get, /**< GET */
+ http_method_post, /**< POST */
+ http_method_head, /**< HEAD */
+ http_method_options, /**< OPTIONS */
+ http_method_put, /**< PUT */
+ http_method_delete, /**< DELETE */
+ http_method_trace, /**< TRACE */
+ http_method_connect, /**< CONNECT */
+} http_method_t;
+
+#define HTTP_METHOD(s) http_method_unknown, #s
+#define HTTP_NO_METHOD http_method_unknown, NULL
+#define HTTP_METHOD_GET http_method_get, "GET"
+#define HTTP_METHOD_POST http_method_post, "POST"
+#define HTTP_METHOD_HEAD http_method_head, "HEAD"
+#define HTTP_METHOD_OPTIONS http_method_options, "OPTIONS"
+#define HTTP_METHOD_PUT http_method_put, "PUT"
+#define HTTP_METHOD_DELETE http_method_delete, "DELETE"
+#define HTTP_METHOD_TRACE http_method_trace, "TRACE"
+#define HTTP_METHOD_CONNECT http_method_connect, "CONNECT"
+
+/* ----------------------------------------------------------------------
+ * 2) Type declarations
+ */
+
+/** HTTP message object. */
+typedef struct http_s http_t;
+
+/** Any HTTP header - union of all possible HTTP headers. */
+typedef union http_header_u http_header_t;
+
+typedef struct http_request_s http_request_t;
+typedef struct http_status_s http_status_t;
+typedef msg_accept_t http_accept_t;
+typedef msg_accept_charset_t http_accept_charset_t;
+typedef msg_accept_encoding_t http_accept_encoding_t;
+typedef msg_accept_language_t http_accept_language_t;
+typedef msg_list_t http_accept_ranges_t;
+typedef msg_numeric_t http_age_t;
+typedef msg_list_t http_allow_t;
+typedef msg_auth_info_t http_authentication_info_t;
+typedef msg_auth_t http_authorization_t;
+typedef msg_list_t http_cache_control_t;
+typedef msg_list_t http_connection_t;
+typedef msg_content_encoding_t http_content_encoding_t;
+typedef msg_content_language_t http_content_language_t;
+typedef msg_content_length_t http_content_length_t;
+typedef msg_content_location_t http_content_location_t;
+typedef msg_generic_t http_content_md5_t;
+typedef struct http_content_range_s http_content_range_t;
+typedef msg_content_type_t http_content_type_t;
+typedef struct http_date_s http_date_t;
+typedef msg_generic_t http_etag_t;
+typedef msg_generic_t http_expect_t;
+typedef http_date_t http_expires_t;
+typedef msg_generic_t http_from_t;
+typedef struct http_host_s http_host_t;
+typedef msg_list_t http_if_match_t;
+typedef http_date_t http_if_modified_since_t;
+typedef msg_list_t http_if_none_match_t;
+typedef struct http_if_range_s http_if_range_t;
+typedef http_date_t http_if_unmodified_since_t;
+typedef http_date_t http_last_modified_t;
+typedef struct http_location_s http_location_t;
+typedef struct http_max_forwards_s http_max_forwards_t;
+typedef msg_generic_t http_mime_version_t;
+typedef msg_list_t http_pragma_t;
+typedef msg_auth_t http_proxy_authenticate_t;
+typedef msg_auth_t http_proxy_authorization_t;
+typedef struct http_range_s http_range_t;
+typedef struct http_location_s http_referer_t;
+typedef struct http_retry_after_s http_retry_after_t;
+typedef msg_generic_t http_server_t;
+typedef struct http_te_s http_te_t;
+typedef msg_list_t http_trailer_t;
+typedef msg_list_t http_transfer_encoding_t;
+typedef msg_list_t http_upgrade_t;
+typedef msg_generic_t http_user_agent_t;
+typedef msg_list_t http_vary_t;
+typedef struct http_via_s http_via_t;
+typedef msg_warning_t http_warning_t;
+typedef msg_auth_t http_www_authenticate_t;
+
+typedef msg_list_t http_proxy_connection_t;
+
+typedef struct http_set_cookie_s http_set_cookie_t;
+typedef struct http_cookie_s http_cookie_t;
+
+/** Erroneous header. */
+typedef msg_error_t http_error_t;
+/** Unknown header. */
+typedef msg_generic_t http_unknown_t;
+/** Separator line between headers and message contents */
+typedef msg_separator_t http_separator_t;
+/** Entity-body */
+typedef msg_payload_t http_payload_t;
+/** Time in seconds since 01-Jan-1900. */
+typedef unsigned long http_time_t;
+/** Range offset. */
+typedef unsigned long http_off_t;
+
+
+/* ----------------------------------------------------------------------
+ * 3) Structure definitions
+ */
+
+/** HTTP request line */
+struct http_request_s {
+ msg_common_t rq_common[1];
+ http_error_t *rq_next;
+ http_method_t rq_method; /** Method enum. */
+ char const *rq_method_name; /** Method name. */
+ url_t rq_url[1]; /** URL. */
+ char const *rq_version; /** Protocol version. */
+};
+
+/** HTTP status line */
+struct http_status_s {
+ msg_common_t st_common[1];
+ http_error_t *st_next;
+ char const *st_version;
+ int st_status;
+ char const *st_phrase;
+};
+
+/**@ingroup http_authentication_info
+ * @brief Structure for @b Authentication-Info header.
+ *
+ * @deprecated Use struct msg_auth_info_s instead.
+ */
+struct http_authentication_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 authentication info */
+};
+
+/** Content-Range */
+struct http_content_range_s {
+ msg_common_t cr_common[1];
+ http_error_t *cr_next;
+ http_off_t cr_first; /**< First-byte-pos */
+ http_off_t cr_last; /**< Last-byte-pos */
+ http_off_t cr_length; /**< Instance-length */
+};
+
+/** Date, Expires, If-Modified-Since, If-Unmodified-Since, Last-Modified */
+struct http_date_s {
+ msg_common_t d_common[1];
+ http_error_t *d_next;
+ http_time_t d_time; /**< Seconds since Jan 1, 1900 */
+};
+
+/** Host */
+struct http_host_s {
+ msg_common_t h_common[1];
+ http_error_t *h_next;
+ char const *h_host;
+ char const *h_port;
+};
+
+/** If-Range */
+struct http_if_range_s {
+ msg_common_t ifr_common[1];
+ http_error_t *ifr_next;
+ char const *ifr_tag; /**< Tag */
+ http_time_t ifr_time; /**< Timestamp */
+};
+
+/** Location, Referer */
+struct http_location_s {
+ msg_common_t loc_common[1];
+ http_error_t *loc_next;
+ url_t loc_url[1];
+};
+
+/** Max-Forwards */
+struct http_max_forwards_s {
+ msg_common_t mf_common[1];
+ http_error_t *mf_next;
+ unsigned long mf_count;
+};
+
+/** Range */
+struct http_range_s
+{
+ msg_common_t rng_common[1];
+ http_error_t *rng_next;
+ char const *rng_unit;
+ char const **rng_specs;
+};
+
+/** Retry-After. */
+struct http_retry_after_s {
+ msg_common_t ra_common[1]; /**< Common fragment info */
+ http_error_t *ra_next; /**< Link to next (dummy) */
+ http_time_t ra_date; /**< When to retry */
+ http_time_t ra_delta; /**< Seconds to before retry */
+};
+
+/** TE */
+struct http_te_s {
+ msg_common_t te_common[1]; /**< Common fragment info */
+ http_te_t *te_next; /**< Link to next t-coding */
+ char const *te_extension; /**< Transfer-Extension */
+ msg_param_t const *te_params; /**< List of parameters */
+ char const *te_q; /**< Q-value */
+};
+
+/** Via */
+struct http_via_s {
+ msg_common_t v_common[1];
+ http_via_t *v_next;
+ char const *v_version;
+ char const *v_host;
+ char const *v_port;
+ char const *v_comment;
+};
+
+/** Cookie */
+struct http_cookie_s {
+ msg_common_t c_common[1];
+ http_cookie_t *c_next;
+ msg_param_t const *c_params;
+ char const *c_version;
+ char const *c_name;
+ char const *c_domain;
+ char const *c_path;
+};
+
+/** Set-Cookie */
+struct http_set_cookie_s {
+ msg_common_t sc_common[1];
+ http_set_cookie_t *sc_next;
+ msg_param_t const *sc_params;
+ char const *sc_name;
+ char const *sc_version;
+ char const *sc_domain;
+ char const *sc_path;
+ char const *sc_comment;
+ char const *sc_max_age;
+ unsigned sc_secure;
+};
+
+/**HTTP message object.
+ *
+ * This structure contains a HTTP message object. It is used to access the
+ * headers and payload within the message. The generic transport aspects of
+ * the message, like network address, is accessed using a @b msg_t object
+ * directly.
+ */
+struct http_s {
+ msg_common_t http_common[1]; /**< For recursive inclusion */
+ msg_pub_t *http_next; /**< Dummy pointer to next part */
+ void *http_user; /**< Application data */
+ unsigned http_size; /**< Size of this structure */
+ int http_flags; /**< Flags */
+ http_error_t *http_error; /**< Erroneous headers */
+
+ http_request_t *http_request; /**< Request line */
+ http_status_t *http_status; /**< Status line */
+
+ /* === Headers start here */
+ http_accept_t *http_accept; /**< Accept */
+ http_accept_charset_t *http_accept_charset; /**< Accept-Charset */
+ http_accept_encoding_t *http_accept_encoding; /**< Accept-Encoding */
+ http_accept_language_t *http_accept_language; /**< Accept-Language */
+ http_accept_ranges_t *http_accept_ranges; /**< Accept-Ranges */
+ http_allow_t *http_allow; /**< Allow */
+ http_authentication_info_t*http_authentication_info;/**<Authentication-Info*/
+ http_authorization_t *http_authorization; /**< Authorization */
+ http_age_t *http_age; /**< Age */
+ http_cache_control_t *http_cache_control; /**< Cache-Control */
+ http_connection_t *http_connection; /**< Connection */
+ http_date_t *http_date; /**< Date */
+ http_etag_t *http_etag; /**< ETag */
+ http_expect_t *http_expect; /**< Expect */
+ http_expires_t *http_expires; /**< Expires */
+ http_from_t *http_from; /**< From */
+ http_host_t *http_host; /**< Host */
+ http_if_match_t *http_if_match; /**< If-Match */
+ http_if_modified_since_t *http_if_modified_since; /**< If-Modified-Since */
+ http_if_none_match_t *http_if_none_match; /**< If-None-Match */
+ http_if_range_t *http_if_range; /**< If-Range */
+ http_if_unmodified_since_t*http_if_unmodified_since;/**<If-Unmodified-Since*/
+ http_last_modified_t *http_last_modified; /**< Last-Modified */
+ http_location_t *http_location; /**< Location */
+ http_max_forwards_t *http_max_forwards; /**< Max-Forwards */
+ http_pragma_t *http_pragma; /**< Pragma */
+ http_proxy_authenticate_t *http_proxy_authenticate;/**< Proxy-Authenticate */
+ http_proxy_authorization_t*http_proxy_authorization;/**<Proxy-Authorization*/
+ http_range_t *http_range; /**< Range */
+ http_referer_t *http_referer; /**< Referer */
+ http_retry_after_t *http_retry_after; /**< Retry-After */
+ http_server_t *http_server; /**< Server */
+ http_te_t *http_te; /**< TE */
+ http_trailer_t *http_trailer; /**< Trailer */
+ http_transfer_encoding_t *http_transfer_encoding; /**< Transfer-Encoding */
+ http_upgrade_t *http_upgrade; /**< Upgrade */
+ http_user_agent_t *http_user_agent; /**< User-Agent */
+ http_vary_t *http_vary; /**< Vary */
+ http_via_t *http_via; /**< Via */
+ http_warning_t *http_warning; /**< Warning */
+ http_www_authenticate_t *http_www_authenticate; /**< WWW-Authenticate */
+
+ http_proxy_connection_t *http_proxy_connection; /**< Proxy-Connection */
+ http_set_cookie_t *http_set_cookie; /**< Set-Cookie */
+ http_cookie_t *http_cookie; /**< Cookie */
+
+ http_mime_version_t *http_mime_version; /**< MIME-Version */
+ http_content_encoding_t *http_content_encoding; /**< Content-Encoding */
+ http_content_language_t *http_content_language; /**< Content-Language */
+ http_content_length_t *http_content_length; /**< Content-Length */
+ http_content_location_t *http_content_location; /**< Content-Location */
+ http_content_md5_t *http_content_md5; /**< Content-MD5 */
+ http_content_range_t *http_content_range; /**< Content-Range */
+ http_content_type_t *http_content_type; /**< Content-Type */
+
+ /* === Headers end here */
+ http_header_t *http_unknown; /**< Unknown headers. */
+ http_separator_t *http_separator;
+ /**< Separator between message and payload */
+ http_payload_t *http_payload; /**< Message entity-body */
+};
+
+/**Union representing any HTTP header.
+ *
+ * Each different header is an array of size 1.
+ *
+ * @deprecated
+ */
+union http_header_u {
+ msg_common_t sh_common[1];
+ struct {
+ msg_common_t shn_common;
+ http_header_t *shn_next;
+ } sh_header_next[1];
+
+ msg_auth_t sh_auth[1];
+ msg_generic_t sh_generic[1];
+ msg_numeric_t sh_numeric[1];
+
+ http_request_t sh_request[1];
+ http_status_t sh_status[1];
+ http_error_t sh_error[1];
+ http_unknown_t sh_unknown[1];
+ http_separator_t sh_separator[1];
+ http_payload_t sh_payload[1];
+
+ /* Proper headers */
+ http_via_t sh_via[1];
+ http_host_t sh_host[1];
+ http_from_t sh_from[1];
+ http_referer_t sh_referer[1];
+ http_connection_t sh_connection[1];
+
+ http_accept_t sh_accept[1];
+ http_accept_charset_t sh_accept_charset[1];
+ http_accept_encoding_t sh_accept_encoding[1];
+ http_accept_language_t sh_accept_language[1];
+ http_accept_ranges_t sh_accept_ranges[1];
+ http_allow_t sh_allow[1];
+ http_te_t sh_te[1];
+
+ http_authentication_info_t sh_authentication_info[1];
+ http_authorization_t sh_authorization[1];
+ http_www_authenticate_t sh_www_authenticate[1];
+ http_proxy_authenticate_t sh_proxy_authenticate[1];
+ http_proxy_authorization_t sh_proxy_authorization[1];
+
+ http_age_t sh_age[1];
+ http_cache_control_t sh_cache_control[1];
+ http_date_t sh_date[1];
+ http_expires_t sh_expires[1];
+ http_if_match_t sh_if_match[1];
+ http_if_modified_since_t sh_if_modified_since[1];
+ http_if_none_match_t sh_if_none_match[1];
+ http_if_range_t sh_if_range[1];
+ http_if_unmodified_since_t sh_if_unmodified_since[1];
+
+ http_etag_t sh_etag[1];
+ http_expect_t sh_expect[1];
+ http_last_modified_t sh_last_modified[1];
+ http_location_t sh_location[1];
+ http_max_forwards_t sh_max_forwards[1];
+ http_pragma_t sh_pragma[1];
+ http_range_t sh_range[1];
+ http_retry_after_t sh_retry_after[1];
+ http_trailer_t sh_trailer[1];
+ http_upgrade_t sh_upgrade[1];
+ http_vary_t sh_vary[1];
+ http_warning_t sh_warning[1];
+
+ http_user_agent_t sh_user_agent[1];
+ http_server_t sh_server[1];
+
+ http_mime_version_t sh_mime_version[1];
+ http_content_language_t sh_content_language[1];
+ http_content_location_t sh_content_location[1];
+ http_content_md5_t sh_content_md5[1];
+ http_content_range_t sh_content_range[1];
+ http_content_encoding_t sh_content_encoding[1];
+ http_transfer_encoding_t sh_transfer_encoding[1];
+ http_content_type_t sh_content_type[1];
+ http_content_length_t sh_content_length[1];
+
+};
+
+SOFIA_END_DECLS
+
+#endif /* !defined(HTTP_H) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_hclasses.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_hclasses.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,70 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef HTTP_HCLASSES_H
+/** Defined when <sofia-sip/http_hclasses.h> has been included. */
+#define HTTP_HCLASSES_H
+
+/**@file sofia-sip/http_hclasses.h
+ * @brief HTTP header classes.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ */
+
+#ifndef MSG_TYPES_H
+#include <sofia-sip/msg_types.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/* Use directly these header classes */
+
+#define http_accept_class msg_accept_class
+#define http_accept_charset_class msg_accept_charset_class
+#define http_accept_encoding_class msg_accept_encoding_class
+#define http_accept_language_class msg_accept_language_class
+#define http_content_encoding_class msg_content_encoding_class
+#define http_content_length_class msg_content_length_class
+#define http_content_md5_class msg_content_md5_class
+#define http_content_type_class msg_content_type_class
+#define http_content_id_class msg_content_id_class
+#define http_content_location_class msg_content_location_class
+#define http_content_language_class msg_content_language_class
+#define http_mime_version_class msg_mime_version_class
+
+#define http_error_class msg_error_class
+#define http_unknown_class msg_unknown_class
+#define http_separator_class msg_separator_class
+#define http_payload_class msg_payload_class
+
+SOFIA_END_DECLS
+
+#ifndef HTTP_PROTOS_H
+#define HTTP_HCLASSES_ONLY
+#include <sofia-sip/http_protos.h>
+#undef HTTP_HCLASSES_ONLY
+#endif
+
+#endif /* !defined HTTP_HCLASSES_H */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_header.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_header.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,271 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef HTTP_HEADER_H
+/** Defined when <sofia-sip/http_header.h> has been included.*/
+#define HTTP_HEADER_H
+
+/**@file sofia-sip/http_header.h
+ *
+ * HTTP library prototypes.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Jun 13 02:58:26 2000 ppessi
+ */
+
+#ifndef SU_ALLOC_H
+#include <sofia-sip/su_alloc.h>
+#endif
+
+#ifndef SU_TAG_H
+#include <sofia-sip/su_tag.h>
+#endif
+
+#ifndef HTTP_H
+#include <sofia-sip/http.h>
+#endif
+
+#ifndef MSG_HEADER_H
+#include <sofia-sip/msg_header.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/* ----------------------------------------------------------------------
+ * 1) Macros
+ */
+
+/** Initialize a HTTP header structure. */
+#define HTTP_HEADER_INIT(h, http_class, size) \
+ ((void)memset((h), 0, (size)), \
+ (void)(((msg_common_t *)(h))->h_class = (http_class)), \
+ (h))
+
+#define HTTP_METHOD_NAME(method, name) \
+ ((method) == http_method_unknown ? (name) : http_method_name(method, name))
+
+/* ----------------------------------------------------------------------
+ * 2) Variables
+ */
+
+SOFIAPUBVAR char const http_method_name_get[];
+SOFIAPUBVAR char const http_method_name_post[];
+SOFIAPUBVAR char const http_method_name_head[];
+SOFIAPUBVAR char const http_method_name_options[];
+SOFIAPUBVAR char const http_method_name_put[];
+SOFIAPUBVAR char const http_method_name_delete[];
+SOFIAPUBVAR char const http_method_name_trace[];
+SOFIAPUBVAR char const http_method_name_connect[];
+
+/** HTTP 0.9 */
+SOFIAPUBVAR char const http_version_0_9[];
+
+/** HTTP 1.0 */
+SOFIAPUBVAR char const http_version_1_0[];
+
+/** HTTP 1.1 version. */
+SOFIAPUBVAR char const http_version_1_1[];
+
+#define HTTP_VERSION_CURRENT http_version_1_1
+
+/* ----------------------------------------------------------------------
+ * 3) Prototypes
+ */
+
+/** HTTP parser description. */
+SOFIAPUBFUN msg_mclass_t *http_default_mclass(void);
+
+/** Complete a HTTP request. */
+SOFIAPUBFUN int http_request_complete(msg_t *msg);
+
+/** Complete a HTTP message. */
+SOFIAPUBFUN int http_message_complete(msg_t *msg, http_t *http);
+
+/** Add a duplicate of header object to a HTTP message. */
+SOFIAPUBFUN int http_add_dup(msg_t *, http_t *, http_header_t const *);
+
+/** Add a header to the HTTP message. */
+SOFIAPUBFUN int http_add_make(msg_t *msg, http_t *http,
+ msg_hclass_t *hc, char const *s);
+
+/** Add a header to the HTTP message. */
+SOFIAPUBFUN int http_add_format(msg_t *msg, http_t *http, msg_hclass_t *hc,
+ char const *fmt, ...);
+
+/** Add tagged headers to the HTTP message */
+SOFIAPUBFUN int http_add_tl(msg_t *msg, http_t *http,
+ tag_type_t tag, tag_value_t value, ...);
+
+/** Remove schema, host, and port from URL */
+SOFIAPUBFUN int http_strip_hostport(url_t *url);
+
+/** Add required headers to the response message */
+SOFIAPUBFUN int http_complete_response(msg_t *msg,
+ int status, char const *phrase,
+ http_t const *request);
+
+/** Return string corresponding to the method. */
+SOFIAPUBFUN char const *http_method_name(http_method_t method,
+ char const *name);
+
+/** Return enum corresponding to the method name */
+SOFIAPUBFUN http_method_t http_method_code(char const *name);
+
+#if !SU_HAVE_INLINE
+SOFIAPUBFUN http_t *http_object(msg_t *msg);
+SOFIAPUBFUN int http_header_insert(msg_t *msg, http_t *http, http_header_t *h);
+SOFIAPUBFUN int http_header_remove(msg_t *msg, http_t *http, http_header_t *h);
+SOFIAPUBFUN char const *http_header_name(http_header_t const *h, int compact);
+SOFIAPUBFUN void *http_header_data(http_header_t *h);
+SOFIAPUBFUN http_content_length_t *http_content_length_create(su_home_t *home,
+ uint32_t n);
+SOFIAPUBFUN http_payload_t *http_payload_create(su_home_t *home,
+ void const *data, usize_t len);
+SOFIAPUBFUN http_separator_t *http_separator_create(su_home_t *home);
+#endif
+
+SOFIAPUBFUN http_header_t *http_header_format(su_home_t *home, msg_hclass_t *,
+ char const *fmt, ...);
+
+
+/** Create a request line object. */
+SOFIAPUBFUN http_request_t *http_request_create(su_home_t *home,
+ http_method_t method,
+ const char *name,
+ url_string_t const *url,
+ char const *version);
+
+/** Create a status line object. */
+SOFIAPUBFUN http_status_t *http_status_create(su_home_t *home,
+ unsigned status,
+ char const *phrase,
+ char const *version);
+
+/** Create an @b Host header object. */
+SOFIAPUBFUN http_host_t *http_host_create(su_home_t *home,
+ char const *host,
+ char const *port);
+
+/** Create an @b Date header object. */
+SOFIAPUBFUN http_date_t *http_date_create(su_home_t *home, http_time_t t);
+
+/** Create an @b Expires header object. */
+SOFIAPUBFUN http_expires_t *http_expires_create(su_home_t *home,
+ http_time_t delta);
+
+/** Compare two HTTP URLs. */
+SOFIAPUBFUN int http_url_cmp(url_t const *a, url_t const *b);
+
+/** Parse query part in HTTP URL. */
+SOFIAPUBFUN issize_t http_query_parse(char *query,
+ /* char const *key, char **return_value, */
+ ...);
+
+/* ----------------------------------------------------------------------
+ * 4) Inlined functions
+ */
+
+#if SU_HAVE_INLINE
+/** Get HTTP structure from msg. */
+su_inline
+http_t *http_object(msg_t *msg)
+{
+ return (http_t *)msg_public(msg, HTTP_PROTOCOL_TAG);
+}
+
+/** Insert a (list of) header(s) to the header structure and fragment chain.
+ *
+ * The function @c http_header_insert() inserts header or list of headers
+ * into a HTTP message. It also inserts them into the the message fragment
+ * chain, if it exists.
+ *
+ * When inserting headers into the fragment chain, a request (or status) is
+ * inserted first and replaces the existing request (or status). The Via
+ * headers are inserted after the request or status, and rest of the headers
+ * after request, status, or Via headers.
+ *
+ * If the header is a singleton, existing headers with the same class are
+ * removed.
+ *
+ * @param msg message owning the fragment chain
+ * @param http HTTP message structure to which header is added
+ * @param h list of header(s) to be added
+ */
+su_inline
+int http_header_insert(msg_t *msg, http_t *http, http_header_t *h)
+{
+ return msg_header_insert(msg, (msg_pub_t *)http, (msg_header_t *)h);
+}
+
+/** Remove a header from a HTTP message. */
+su_inline
+int http_header_remove(msg_t *msg, http_t *http, http_header_t *h)
+{
+ return msg_header_remove(msg, (msg_pub_t *)http, (msg_header_t *)h);
+}
+
+/** Return name of the header. */
+su_inline
+char const *http_header_name(http_header_t const *h, int compact)
+{
+ if (compact && h->sh_class->hc_short[0])
+ return h->sh_class->hc_short;
+ else
+ return h->sh_class->hc_name;
+}
+
+/** Return data after header structure. */
+su_inline
+void *http_header_data(http_header_t *h)
+{
+ return h && h != HTTP_NONE ? h->sh_class->hc_size + (char *)h : NULL;
+}
+
+su_inline
+http_content_length_t *http_content_length_create(su_home_t *home, uint32_t n)
+{
+ return msg_content_length_create(home, n);
+}
+
+su_inline
+http_payload_t *http_payload_create(su_home_t *home, void const *data, isize_t len)
+{
+ return msg_payload_create(home, data, len);
+}
+
+su_inline
+http_separator_t *http_separator_create(su_home_t *home)
+{
+ return msg_separator_create(home);
+}
+#endif
+
+SOFIA_END_DECLS
+
+#ifndef HTTP_PROTOS_H
+#include <sofia-sip/http_protos.h>
+#endif
+
+#endif /* !defined(HTTP_HEADER_H) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_parser.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_parser.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,110 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef HTTP_PARSER_H
+/**Defined when <sofia-sip/http_parser.h> has been included.*/
+#define HTTP_PARSER_H
+/**@file sofia-sip/http_parser.h
+ * @brief Typedefs and prototypes used by HTTP parser.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Jun 13 02:58:26 2000 ppessi
+ */
+
+#ifndef SU_ALLOC_H
+#include <sofia-sip/su_alloc.h>
+#endif
+
+#ifndef MSG_H
+#include <sofia-sip/msg.h>
+#endif
+
+#ifndef MSG_PARSER_H
+#include <sofia-sip/msg_parser.h>
+#endif
+
+#ifndef HTTP_H
+#include <sofia-sip/http.h>
+#endif
+
+#ifndef HTTP_HEADER_H
+#include <sofia-sip/http_header.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/* ---------------------------------------------------------------------------
+ * 1) Macros for defining boilerplate functions and structures for each header
+ */
+
+#define HTTP_HCLASS_TAG HTTP_PROTOCOL_TAG
+#define HTTP_HCLASS_TEST(x) ((x) && (x)->hc_tag == HTTP_PROTOCOL_TAG)
+#define HTTP_HDR_TEST(x) ((x)->sh_class && HTTP_HCLASS_TEST((x)->sh_class))
+
+/** Define a header class for a HTTP header. */
+#define HTTP_HEADER_CLASS(c, l, params, kind, dup) \
+ MSG_HEADER_CLASS(http_, c, l, "", params, kind, http_ ## dup, http_no)
+
+/** This is used by headers with no extra data in copy */
+#define HTTP_HEADER_CLASS_G(c, l, kind) \
+ MSG_HEADER_CLASS(http_, c, l, "", g_common, kind, msg_generic, http_no)
+
+/** Define a header class for a msg_list_t kind of header */
+#define HTTP_HEADER_CLASS_LIST(c, l, kind) \
+ MSG_HEADER_CLASS(http_, c, l, "", k_items, kind, msg_list, http_no)
+
+/** Define a authorization header class */
+#define HTTP_HEADER_CLASS_AUTH(c, l, kind) \
+ MSG_HEADER_CLASS(http_, c, l, "", au_params, kind, msg_auth, http_no)
+
+#define http_numeric_dup_xtra msg_default_dup_xtra
+#define http_numeric_dup_one msg_default_dup_one
+
+#define http_default_dup_xtra msg_default_dup_xtra
+#define http_default_dup_one msg_default_dup_one
+
+#define http_no_update NULL
+
+/* ---------------------------------------------------------------------------
+ * 2) Prototypes for HTTP-specific decoding/encoding functions
+ */
+
+/* Version strings */
+SOFIAPUBFUN int http_version_d(char **ss, char const **ver);
+SOFIAPUBFUN isize_t http_version_xtra(char const *version);
+SOFIAPUBFUN void http_version_dup(char **pp, char const **dd, char const *s);
+
+/* Method */
+SOFIAPUBFUN http_method_t http_method_d(char **ss, char const **nname);
+SOFIAPUBFUN char const *http_method_name(http_method_t method,
+ char const *name);
+
+/** Extract HTTP message body */
+SOFIAPUBFUN issize_t http_extract_body(msg_t *, http_t *,
+ char b[], isize_t bsiz, int eos);
+
+SOFIA_END_DECLS
+
+#endif /* !defined(HTTP_PARSER_H) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_protos.h.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_protos.h.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1,311 @@
+/** -*- C -*-
+ * @file sofia-sip/http_protos.h.in
+ *
+ * Template for <http_protos.h>.
+ */
+
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef HTTP_PROTOS_H
+/** Defined when <sofia-sip/http_protos.h> has been included. */
+#define HTTP_PROTOS_H
+
+/**@file sofia-sip/http_protos.h
+ *
+ * Macros for each HTTP header.
+ *
+ * #AUTO#
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ */
+
+#include <sofia-sip/su_config.h>
+
+#ifndef HTTP_HEADER_H
+#include <sofia-sip/http_header.h>
+#endif
+#ifndef HTTP_HCLASSES_H
+#include <sofia-sip/http_hclasses.h>
+#endif
+
+#define http_header_make(h, c, s) \
+ ((http_header_t *)msg_header_make((h), (c), (s)))
+#define http_header_vformat(h, c, f, a) \
+ ((http_header_t *)msg_header_vformat((h), (c), (f), (a)))
+
+SOFIA_BEGIN_DECLS
+
+/* Declare internal prototypes for #xxxxxxx_xxxxxxx# */
+
+/**@addtogroup http_#xxxxxx#*/ /** @{ */
+
+enum {
+ /** Hash of #xxxxxxx_xxxxxxx#. @internal*/
+ http_#xxxxxx#_hash = #hash#
+};
+
+/**Header class for HTTP #xxxxxxx_xxxxxxx#.
+ *
+ * The header class http_#xxxxxx#_class defines how a HTTP
+ * #xxxxxxx_xxxxxxx# is parsed and printed. It also
+ * contains methods used by HTTP parser and other functions
+ * to manipulate the http_#xxxxxx#_t header structure.
+ *
+ */
+SOFIAPUBVAR msg_hclass_t http_#xxxxxx#_class[];
+
+#ifndef HTTP_HCLASSES_ONLY
+
+/** Decode (parse) a #xxxxxxx_xxxxxxx#. @internal */
+SOFIAPUBFUN msg_parse_f http_#xxxxxx#_d;
+
+/** Encode (print) a #xxxxxxx_xxxxxxx#. @internal */
+SOFIAPUBFUN msg_print_f http_#xxxxxx#_e;
+
+/**Initializer for structure http_#xxxxxx#_t.
+ *
+ * A static http_#xxxxxx#_t structure must be initialized
+ * with the HTTP_#XXXXXX#_INIT() macro. For instance,
+ * @code
+ *
+ * http_#xxxxxx#_t http_#xxxxxx# = HTTP_#XXXXXX#_INIT;
+ *
+ * @endcode
+ * @HI
+ */
+#define HTTP_#XXXXXX#_INIT() HTTP_HDR_INIT(#xxxxxx#)
+
+/**Initialize a structure http_#xxxxxx#_t.
+ *
+ * An http_#xxxxxx#_t structure can be initialized with the
+ * http_#xxxxxx#_init() function/macro. For instance,
+ * @code
+ *
+ * http_#xxxxxx#_t http_#xxxxxx#;
+ *
+ * http_#xxxxxx#_init(&http_#xxxxxx#);
+ *
+ * @endcode
+ * @HI
+ */
+#if SU_HAVE_INLINE
+su_inline http_#xxxxxx#_t *http_#xxxxxx#_init(http_#xxxxxx#_t x[1])
+{
+ return HTTP_HEADER_INIT(x, http_#xxxxxx#_class, sizeof(http_#xxxxxx#_t));
+}
+#else
+#define http_#xxxxxx#_init(x) \
+ HTTP_HEADER_INIT(x, http_#xxxxxx#_class, sizeof(http_#xxxxxx#_t))
+#endif
+
+/**Test if header object is instance of http_#xxxxxx#_t.
+ *
+ * The function http_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 http_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 http_is_#xxxxxx#(http_header_t const *header)
+{
+ return header && header->sh_class->hc_hash == http_#xxxxxx#_hash;
+}
+#else
+#define http_is_#xxxxxx#(h) \
+ ((h) && ((msg_common_t *)(h))->h_class->hc_hash == http_#xxxxxx#_hash)
+#endif
+
+/**Duplicate (deep copy) @c http_#xxxxxx#_t.
+ *
+ * The function http_#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# = http_#xxxxxx#_dup(home, http->http_#xxxxxx#);
+ *
+ * @endcode
+ *
+ * @return
+ * The function http_#xxxxxx#_dup() returns a pointer to the
+ * newly duplicated http_#xxxxxx#_t header structure, or NULL
+ * upon an error.
+ */
+#if SU_HAVE_INLINE
+su_inline
+#endif
+http_#xxxxxx#_t *http_#xxxxxx#_dup(su_home_t *home,
+ http_#xxxxxx#_t const *hdr)
+ __attribute__((__malloc__));
+
+/**Copy a http_#xxxxxx#_t header structure.
+ *
+ * The function http_#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# = http_#xxxxxx#_copy(home, http->http_#xxxxxx#);
+ *
+ * @endcode
+ *
+ * @return
+ * The function http_#xxxxxx#_copy() returns a pointer to
+ * newly copied header structure, or NULL upon an error.
+ */
+#if SU_HAVE_INLINE
+su_inline
+#endif
+http_#xxxxxx#_t *http_#xxxxxx#_copy(su_home_t *home,
+ http_#xxxxxx#_t const *hdr)
+ __attribute__((__malloc__));
+
+/**Make a header structure http_#xxxxxx#_t.
+ *
+ * The function http_#xxxxxx#_make() makes a new
+ * http_#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
+ * http_header_make().
+ *
+ * @return
+ * The function http_#xxxxxx#_make() returns a pointer to
+ * newly maked http_#xxxxxx#_t header structure, or NULL upon
+ * an error.
+ */
+#if SU_HAVE_INLINE
+su_inline
+#endif
+http_#xxxxxx#_t *http_#xxxxxx#_make(su_home_t *home, char const *s)
+ __attribute__((__malloc__));
+
+/**Make a #xxxxxxx_xxxxxxx# from formatting result.
+ *
+ * The function http_#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 http_#xxxxxx#_format() returns a pointer to newly
+ * makes header structure, or NULL upon an error.
+ *
+ * @HIDE
+ */
+#if SU_HAVE_INLINE
+su_inline
+#endif
+http_#xxxxxx#_t *http_#xxxxxx#_format(su_home_t *home, char const *fmt, ...)
+ __attribute__((__malloc__, __format__ (printf, 2, 3)));
+
+
+/* Inlined functions */
+#if SU_HAVE_INLINE
+su_inline
+http_#xxxxxx#_t *http_#xxxxxx#_format(su_home_t *home, char const *fmt, ...)
+{
+ http_header_t *h;
+ va_list ap;
+
+ va_start(ap, fmt);
+ h = http_header_vformat(home, http_#xxxxxx#_class, fmt, ap);
+ va_end(ap);
+
+ return (http_#xxxxxx#_t *)h;
+}
+
+su_inline
+http_#xxxxxx#_t *http_#xxxxxx#_dup(su_home_t *home, http_#xxxxxx#_t const *o)
+{
+ return (http_#xxxxxx#_t *)
+ msg_header_dup_as(home, http_#xxxxxx#_class, (msg_header_t const *)o);
+}
+
+su_inline
+http_#xxxxxx#_t *http_#xxxxxx#_copy(su_home_t *home, http_#xxxxxx#_t const *o)
+{
+ return (http_#xxxxxx#_t *)
+ msg_header_copy_as(home, http_#xxxxxx#_class, (msg_header_t const *)o);
+}
+
+su_inline
+http_#xxxxxx#_t *http_#xxxxxx#_make(su_home_t *home, char const *s)
+{
+ return (http_#xxxxxx#_t *)http_header_make(home, http_#xxxxxx#_class, s);
+}
+#endif
+
+#endif /* !define HTTP_HCLASSES_ONLY */
+
+/** @} */
+
+
+SOFIA_END_DECLS
+#endif /* !defined(HTTP_PROTOS_H) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_status.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_status.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,129 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef HTTP_STATUS_H
+#define HTTP_STATUS_H
+
+/**@file sofia-sip/http_status.h
+ *
+ * HTTP status codes.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Sep 18 18:55:09 2001 ppessi
+ */
+
+#include <sofia-sip/su_config.h>
+
+SOFIA_BEGIN_DECLS
+
+SOFIAPUBFUN char const *http_status_phrase(int status);
+
+#define HTTP_100_CONTINUE 100, http_100_continue
+#define HTTP_101_SWITCHING 101, http_101_switching
+#define HTTP_200_OK 200, http_200_ok
+#define HTTP_201_CREATED 201, http_201_created
+#define HTTP_202_ACCEPTED 202, http_202_accepted
+#define HTTP_203_NON_AUTH_INFO 203, http_203_non_auth_info
+#define HTTP_204_NO_CONTENT 204, http_204_no_content
+#define HTTP_205_RESET_CONTENT 205, http_205_reset_content
+#define HTTP_206_PARTIAL_CONTENT 206, http_206_partial_content
+#define HTTP_300_MULTIPLE_CHOICES 300, http_300_multiple_choices
+#define HTTP_301_MOVED_PERMANENTLY 301, http_301_moved_permanently
+#define HTTP_302_FOUND 302, http_302_found
+#define HTTP_303_SEE_OTHER 303, http_303_see_other
+#define HTTP_304_NOT_MODIFIED 304, http_304_not_modified
+#define HTTP_305_USE_PROXY 305, http_305_use_proxy
+#define HTTP_307_TEMPORARY_REDIRECT 307, http_307_temporary_redirect
+#define HTTP_400_BAD_REQUEST 400, http_400_bad_request
+#define HTTP_401_UNAUTHORIZED 401, http_401_unauthorized
+#define HTTP_402_PAYMENT_REQUIRED 402, http_402_payment_required
+#define HTTP_403_FORBIDDEN 403, http_403_forbidden
+#define HTTP_404_NOT_FOUND 404, http_404_not_found
+#define HTTP_405_NOT_ALLOWED 405, http_405_not_allowed
+#define HTTP_406_NOT_ACCEPTABLE 406, http_406_not_acceptable
+#define HTTP_407_PROXY_AUTH 407, http_407_proxy_auth
+#define HTTP_408_TIMEOUT 408, http_408_timeout
+#define HTTP_409_CONFLICT 409, http_409_conflict
+#define HTTP_410_GONE 410, http_410_gone
+#define HTTP_411_NO_LENGTH 411, http_411_no_length
+#define HTTP_412_PRECONDITION 412, http_412_precondition
+#define HTTP_413_ENTITY_TOO_LARGE 413, http_413_entity_too_large
+#define HTTP_414_URI_TOO_LONG 414, http_414_uri_too_long
+#define HTTP_415_MEDIA_TYPE 415, http_415_media_type
+#define HTTP_416_REQUESTED_RANGE 416, http_416_requested_range
+#define HTTP_417_EXPECTATION 417, http_417_expectation
+#define HTTP_426_UPGRADE 426, http_426_upgrade
+#define HTTP_500_INTERNAL_SERVER 500, http_500_internal_server
+#define HTTP_501_NOT_IMPLEMENTED 501, http_501_not_implemented
+#define HTTP_502_BAD_GATEWAY 502, http_502_bad_gateway
+#define HTTP_503_NO_SERVICE 503, http_503_no_service
+#define HTTP_504_GATEWAY_TIMEOUT 504, http_504_gateway_timeout
+#define HTTP_505_HTTP_VERSION 505, http_505_http_version
+
+SOFIAPUBVAR char const http_100_continue[];
+SOFIAPUBVAR char const http_101_switching[];
+SOFIAPUBVAR char const http_200_ok[];
+SOFIAPUBVAR char const http_201_created[];
+SOFIAPUBVAR char const http_202_accepted[];
+SOFIAPUBVAR char const http_203_non_auth_info[];
+SOFIAPUBVAR char const http_204_no_content[];
+SOFIAPUBVAR char const http_205_reset_content[];
+SOFIAPUBVAR char const http_206_partial_content[];
+SOFIAPUBVAR char const http_300_multiple_choices[];
+SOFIAPUBVAR char const http_301_moved_permanently[];
+SOFIAPUBVAR char const http_302_found[];
+SOFIAPUBVAR char const http_303_see_other[];
+SOFIAPUBVAR char const http_304_not_modified[];
+SOFIAPUBVAR char const http_305_use_proxy[];
+SOFIAPUBVAR char const http_307_temporary_redirect[];
+SOFIAPUBVAR char const http_400_bad_request[];
+SOFIAPUBVAR char const http_401_unauthorized[];
+SOFIAPUBVAR char const http_402_payment_required[];
+SOFIAPUBVAR char const http_403_forbidden[];
+SOFIAPUBVAR char const http_404_not_found[];
+SOFIAPUBVAR char const http_405_not_allowed[];
+SOFIAPUBVAR char const http_406_not_acceptable[];
+SOFIAPUBVAR char const http_407_proxy_auth[];
+SOFIAPUBVAR char const http_408_timeout[];
+SOFIAPUBVAR char const http_409_conflict[];
+SOFIAPUBVAR char const http_410_gone[];
+SOFIAPUBVAR char const http_411_no_length[];
+SOFIAPUBVAR char const http_412_precondition[];
+SOFIAPUBVAR char const http_413_entity_too_large[];
+SOFIAPUBVAR char const http_414_uri_too_long[];
+SOFIAPUBVAR char const http_415_media_type[];
+SOFIAPUBVAR char const http_416_requested_range[];
+SOFIAPUBVAR char const http_417_expectation[];
+SOFIAPUBVAR char const http_426_upgrade[];
+SOFIAPUBVAR char const http_500_internal_server[];
+SOFIAPUBVAR char const http_501_not_implemented[];
+SOFIAPUBVAR char const http_502_bad_gateway[];
+SOFIAPUBVAR char const http_503_no_service[];
+SOFIAPUBVAR char const http_504_gateway_timeout[];
+SOFIAPUBVAR char const http_505_http_version[];
+
+SOFIA_END_DECLS
+
+#endif /* HTTP_STATUS_H */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_tag.h.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_tag.h.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1,236 @@
+/**@file sofia-sip/http_tag.h.in
+ *
+ * Template for <http_tag.h>.
+ *
+ * @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 at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef HTTP_TAG_H
+/** Defined when <sofia-sip/http_tag.h> has been included. */
+#define HTTP_TAG_H
+
+/**@file sofia-sip/http_tag.h
+ * @brief Tag class for HTTP headers
+ *
+ * #AUTO#
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ */
+
+#ifndef SU_TAG_H
+#include <sofia-sip/su_tag.h>
+#endif
+#ifndef SU_TAG_CLASS_H
+#include <sofia-sip/su_tag_class.h>
+#endif
+#ifndef SU_TAG_CLASS_H
+#include <sofia-sip/su_tag_class.h>
+#endif
+
+#ifndef HTTP_H
+#include <sofia-sip/http.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+#define HTTPTAG(c, x) httptag_##c, httptag_##c##_v(x)
+#define HTTPTAG_REF(c, x) httptag_##c##_ref, httptag_##c##_vr(&(x))
+#define HTTPTAG_STR(c, s) httptag_##c##_str, tag_str_v(s)
+#define HTTPTAG_STR_REF(c, s) httptag_##c##_str_ref, tag_str_vr(&(s))
+
+/** Test if tag type marks a http_t structure. @HIDE */
+#define HTTPTAG_P(tt) ((tt)->tt_class == httphdrtag_class)
+/** Test if tag type marks a HTTP header string. @HIDE */
+#define HTTPTAG_STR_P(tt) ((tt)->tt_class == httpstrtag_class)
+/** Test if tag type marks a HTTP header structure. @HIDE */
+#define HTTPTAG_HTTP_P(tt) ((tt)->tt_class == httpmsgtag_class)
+
+/** Test if tag item contains http_t structure. @HIDE */
+#define HTTPTAGI_P(t) (HTTPTAG_P((t)->t_tag))
+/** Test if tag item contains a HTTP header string. @HIDE */
+#define HTTPTAGI_STR_P(t) (HTTPTAG_STR_P((t)->t_tag))
+/** Test if tag item contains a HTTP header structure. @HIDE */
+#define HTTPTAGI_HTTP_P(t) (HTTPTAG_HTTP_P((t)->t_tag))
+
+SOFIAPUBVAR tag_class_t httphdrtag_class[1];
+SOFIAPUBVAR tag_class_t httpstrtag_class[1];
+SOFIAPUBVAR tag_class_t httpmsgtag_class[1];
+
+/** Filter tag matching any http tag. */
+#define HTTPTAG_ANY() httptag_any, ((tag_value_t)0)
+SOFIAPUBVAR tag_typedef_t httptag_any;
+
+/**Tag list item for @c http_t object.
+ *
+ * The HTTPTAG_HTTP() macro is used to include a tag item for a http_t object
+ * in the tag list.
+ *
+ * @param x pointer to a http_t message object, or NULL.
+ *
+ * @HIDE
+ */
+#define HTTPTAG_HTTP(x) httptag_http, httptag_http_v((x))
+
+/** Tag for @c http_t */
+SOFIAPUBVAR tag_typedef_t httptag_http;
+
+#define HTTPTAG_HTTP_REF(x) httptag_http_ref, httptag_http_vr(&(x))
+SOFIAPUBVAR tag_typedef_t httptag_http_ref;
+
+#if SU_HAVE_INLINE
+static inline
+tag_value_t httptag_http_v(http_t const *v) { return (tag_value_t)v; }
+static inline
+tag_value_t httptag_http_vr(http_t const **vp) { return (tag_value_t)vp; }
+#else
+#define httptag_http_v(v) (tag_value_t)(v)
+#define httptag_http_vr(vp) (tag_value_t)(vp)
+#endif
+
+/**Tag list item for http protocol version.
+ *
+ * The HTTPTAG_VERSION() macro is used to include a tag item for a HTTP
+ * protocol version in the tag list.
+ *
+ * @param x pointer to a http_t message object, or NULL.
+ */
+#define HTTPTAG_VERSION(x) httptag_http, (tag_value_t)x
+
+extern tag_typedef_t httptag_version;
+
+/** Reference to HTTPTAG_VERSION */
+#define HTTPTAG_VERSION_REF(x) httptag_http_ref, (tag_value_t)&(x)
+
+extern tag_typedef_t httptag_version_ref;
+
+/**Tag list item for header string.
+ *
+ * The HTTPTAG_HEADER() macro is used to include a tag item containing an
+ * unknown HTTP header in the tag list, e.g.,
+ * @code
+ * http_header_t *hdr;
+ *
+ * HTTPTAG_HEADER(hdr).
+ * @endcode
+ *
+ * @param x pointer to a header structure, or NULL.
+ *
+ * @HIDE
+ */
+#define HTTPTAG_HEADER(x) httptag_header, httptag_header_v((x))
+
+/** Tag for header string */
+SOFIAPUBVAR tag_typedef_t httptag_header;
+
+#define HTTPTAG_HEADER_REF(x) httptag_header_ref, httptag_header_vr(&(x))
+SOFIAPUBVAR tag_typedef_t httptag_header_ref;
+
+#if SU_HAVE_INLINE
+static inline tag_value_t
+httptag_header_v(http_header_t const *v)
+{ return (tag_value_t)v; }
+static inline tag_value_t
+httptag_header_vr(http_header_t const **vp)
+{ return (tag_value_t)vp; }
+#else
+#define httptag_header_v(v) (tag_value_t)(v)
+#define httptag_header_vr(vp) (tag_value_t)(vp)
+#endif
+
+/**Tag list item for header string.
+ *
+ * The HTTPTAG_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 HTTPTAG_HEADER_STR(x) httptag_header_str, tag_str_v((x))
+
+/** Tag for header string */
+SOFIAPUBVAR tag_typedef_t httptag_header_str;
+
+#define HTTPTAG_HEADER_STR_REF(x) httptag_header_str_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t httptag_header_str_ref;
+
+
+/**@ingroup http_#xxxxxx#
+ *
+ * Tag list item for pointer to a #xxxxxxx_xxxxxxx# object.
+ *
+ * The HTTPTAG_#XXXXXX#() macro is used to include a tag item with a
+ * pointer to a http_#xxxxxx#_t object in a tag list.
+ *
+ * @param x pointer to a http_#xxxxxx#_t header structure, or NULL.
+ *
+ * @HIDE
+ */
+#define HTTPTAG_#XXXXXX#(x) HTTPTAG(#xxxxxx#, x)
+
+SOFIAPUBVAR tag_typedef_t httptag_#xxxxxx#;
+
+/**@ingroup http_#xxxxxx#
+ *
+ * Tag list item for string with #xxxxxxx_xxxxxxx# value.
+ *
+ * The HTTPTAG_#XXXXXX#_STR() macro is used to include a tag item with a
+ * string containing value of a http_#xxxxxx#_t header in a tag list.
+ *
+ * @param s pointer to a string containing http_#xxxxxx#_t value, or NULL.
+ *
+ * The HTTPTAG_#XXXXXX#_STR string can be converted to a
+ * http_#xxxxxx#_t header structure by giving the string @a s has
+ * second argument to function http_#xxxxxx#_make().
+ *
+ * @HIDE
+ */
+#define HTTPTAG_#XXXXXX#_STR(s) HTTPTAG_STR(#xxxxxx#, s)
+
+SOFIAPUBVAR tag_typedef_t httptag_#xxxxxx#_str;
+
+#define HTTPTAG_#XXXXXX#_REF(x) HTTPTAG_REF(#xxxxxx#, x)
+SOFIAPUBVAR tag_typedef_t httptag_#xxxxxx#_ref;
+
+#define HTTPTAG_#XXXXXX#_STR_REF(x) HTTPTAG_STR_REF(#xxxxxx#, x)
+SOFIAPUBVAR tag_typedef_t httptag_#xxxxxx#_str_ref;
+
+#if SU_HAVE_INLINE
+static inline tag_value_t
+httptag_#xxxxxx#_v(http_#xxxxxx#_t const *v)
+{ return (tag_value_t)v; }
+static inline tag_value_t
+httptag_#xxxxxx#_vr(http_#xxxxxx#_t const **vp)
+{ return (tag_value_t)vp; }
+#else
+#define httptag_#xxxxxx#_v(v) (tag_value_t)(v)
+#define httptag_#xxxxxx#_vr(vp) (tag_value_t)(vp)
+#endif
+
+SOFIA_END_DECLS
+#endif /* !defined(HTTP_TAG_H) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_tag_class.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_tag_class.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,72 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef HTTP_TAG_CLASS_H
+/**Defined when http_tag_class.h have been included*/
+#define HTTP_TAG_CLASS_H
+
+/**@file sofia-sip/http_tag_class.h
+ * @brief Tag classes for HTTP headers.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Feb 21 11:01:45 2001 ppessi
+ */
+
+#ifndef SU_TAG_CLASS_H
+#include <sofia-sip/su_tag_class.h>
+#endif
+
+#ifndef MSG_TAG_CLASS_H
+#include <sofia-sip/msg_tag_class.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** Define a named tag type for HTTP header @a t. */
+#define HTTPHDRTAG_NAMED_TYPEDEF(n, t) \
+{{ TAG_NAMESPACE, #n, httphdrtag_class, \
+ (tag_value_t)http_##t##_class }}
+
+/** Define a tag type for HTTP header @a t. */
+#define HTTPHDRTAG_TYPEDEF(t) HTTPHDRTAG_NAMED_TYPEDEF(t, t)
+
+/** Define a string tag type for HTTP header @a t. */
+#define HTTPSTRTAG_TYPEDEF(t) \
+{{ TAG_NAMESPACE, #t "_str", httpstrtag_class, \
+ (tag_value_t)http_##t##_class }}
+
+/** Define a tag type for HTTP message @a t. */
+#define HTTPMSGTAG_TYPEDEF(t) \
+ {{ TAG_NAMESPACE, #t, httpmsgtag_class, \
+ (tag_value_t)HTTP_PROTOCOL_TAG }}
+
+/**@internal Filter HTTP header tag items. */
+SOFIAPUBFUN tagi_t *httptag_filter(tagi_t *dst, tagi_t const f[],
+ tagi_t const *src,
+ void **bb);
+
+SOFIA_END_DECLS
+
+#endif /* !defined(HTTP_TAG_CLASS_H) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/test_http.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/test_http.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1513 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_http.c
+ *
+ * Testing functions for HTTP parser.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Mar 6 18:33:42 2001 ppessi
+ */
+
+#include "config.h"
+
+/* Avoid casting http_t to msg_pub_t and http_header_t to msg_header_t */
+#define MSG_PUB_T struct http_s
+#define MSG_HDR_T union http_header_u
+
+#include <sofia-sip/su.h>
+
+#include <sofia-sip/su_types.h>
+
+#include <sofia-sip/su_tag.h>
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/su_tag_io.h>
+
+#include <sofia-sip/http_parser.h>
+
+#include <sofia-sip/http_tag.h>
+#include <sofia-sip/url_tag.h>
+
+#include <sofia-sip/http_header.h>
+#include <sofia-sip/msg_addr.h>
+
+#define TSTFLAGS tstflags
+
+#include <sofia-sip/tstdef.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <assert.h>
+
+char const *name = "test_http";
+
+static int tag_test(void);
+static int tag_test2(void);
+static int http_header_handling_test(void);
+static int http_header_test(void);
+static int http_parser_test(void);
+static int test_http_encoding(void);
+static int http_chunk_test(void);
+static int http_tag_test(void);
+static int test_query_parser(void);
+
+static msg_t *read_message(char const string[]);
+msg_mclass_t *test_mclass = NULL;
+
+void usage(void)
+{
+ fprintf(stderr,
+ "usage: %s [-v]\n",
+ name);
+}
+
+char *lastpart(char *path)
+{
+ if (strchr(path, '/'))
+ return strrchr(path, '/') + 1;
+ else
+ return path;
+}
+
+int tstflags;
+
+int main(int argc, char *argv[])
+{
+ int retval = 0;
+ int i;
+
+ name = lastpart(argv[0]); /* Set our name */
+
+ for (i = 1; argv[i]; i++) {
+ if (strcmp(argv[i], "-v") == 0)
+ tstflags |= tst_verbatim;
+ else
+ usage();
+ }
+
+ if (!test_mclass)
+ test_mclass = http_default_mclass();
+
+ retval |= tag_test(); fflush(stdout);
+ retval |= tag_test2(); fflush(stdout);
+ retval |= http_header_handling_test(); fflush(stdout);
+ retval |= http_header_test(); fflush(stdout);
+ retval |= http_tag_test(); fflush(stdout);
+ retval |= http_parser_test(); fflush(stdout);
+ retval |= test_http_encoding(); fflush(stdout);
+ retval |= http_chunk_test(); fflush(stdout);
+ retval |= test_query_parser(); fflush(stdout);
+
+ return retval;
+}
+
+msg_t *read_message(char const buffer[])
+{
+ int i, n, m;
+ msg_t *msg;
+ msg_iovec_t iovec[2];
+
+ n = strlen(buffer);
+ if (n == 0)
+ return NULL;
+
+ msg = msg_create(test_mclass, MSG_DO_EXTRACT_COPY);
+
+ for (i = 0; i < n;) {
+ if (msg_recv_iovec(msg, iovec, 2, 10, 0) < 0) {
+ perror("msg_recv_iovec");
+ return NULL;
+ }
+ *(char *)(iovec->mv_base) = buffer[i++];
+ msg_recv_commit(msg, 1, i == n);
+
+ m = msg_extract(msg);
+ if (m < 0) {
+ fprintf(stderr, "test_http: parsing error\n");
+ return NULL;
+ }
+ if (m > 0)
+ break;
+ }
+
+ if (i != n) {
+ fprintf(stderr, "test_http: parser error (len=%u, read=%u)\n", n, i);
+ msg_destroy(msg), msg = NULL;
+ }
+
+ return msg;
+}
+
+/* Read message byte-by-byte */
+msg_t *read_message_byte_by_byte(char const buffer[])
+{
+ int i, n, m;
+ msg_t *msg;
+ msg_iovec_t iovec[msg_n_fragments];
+
+ n = strlen(buffer);
+ if (n == 0)
+ return NULL;
+
+ msg = msg_create(test_mclass, MSG_DO_EXTRACT_COPY);
+
+ for (i = 0; i < n;) {
+ /* This prevent msg_recv_iovec() from allocating extra slack */
+ int msg_buf_exact(msg_t *, int);
+ msg_buf_exact(msg, 10 + 1);
+
+ if (msg_recv_iovec(msg, iovec, msg_n_fragments, 10, 0) < 0) {
+ perror("msg_recv_iovec");
+ return NULL;
+ }
+ assert(iovec->mv_len > 0);
+ *(char *)(iovec->mv_base) = buffer[i++];
+ msg_recv_commit(msg, 1, i == n);
+
+ m = msg_extract(msg);
+ if (m < 0) {
+ fprintf(stderr, "test_http: parsing error\n");
+ return NULL;
+ }
+ if (m > 0)
+ break;
+ }
+
+ if (i != n) {
+ fprintf(stderr, "test_http: parser error (len=%u, read=%u)\n", n, i);
+ msg_destroy(msg), msg = NULL;
+ }
+
+ return msg;
+}
+
+static
+int header_size(http_header_t *h)
+{
+ int offset = 0;
+
+ for (; h; h = h->sh_next) {
+ offset += SU_ALIGN(offset) + h->sh_class->hc_size;
+ offset = h->sh_class->hc_dxtra(h, offset);
+ }
+
+ return offset;
+}
+
+#define XTRA(xtra, h) SU_ALIGN(xtra) + header_size((http_header_t*)h)
+
+/** Test header filtering and duplicating */
+static int tag_test(void)
+{
+ su_home_t *home = su_home_new(sizeof *home);
+ http_request_t *request =
+ http_request_make(home, "GET /test/path HTTP/1.1");
+ http_via_t *via = http_via_make(home, "1.1 http.example.com, 1.0 fred");
+ http_host_t *host = http_host_make(home, "http.example.com:8080");
+ http_max_forwards_t *mf = http_max_forwards_make(home, "16");
+ url_t *url = url_hdup(home, (url_t *)"http://host:80/test/path");
+
+ tagi_t *lst, *dup;
+ int xtra;
+
+ BEGIN();
+
+ su_home_check(home);
+
+ TEST_1(home); TEST_1(request); TEST_1(host);
+ TEST_1(via); TEST_1(via->v_next);
+
+ lst = tl_list(HTTPTAG_REQUEST(request),
+ HTTPTAG_HOST(host),
+ HTTPTAG_VIA(via),
+ HTTPTAG_MAX_FORWARDS(mf),
+ URLTAG_URL(url),
+ TAG_NULL());
+
+ xtra = 0;
+ xtra += XTRA(xtra, request);
+ xtra += XTRA(xtra, host);
+ xtra += XTRA(xtra, via);
+ xtra += XTRA(xtra, mf);
+ xtra += SU_ALIGN(xtra) + sizeof(*url) + url_xtra(url);
+
+ TEST_SIZE(tl_xtra(lst, 0), xtra);
+ TEST_SIZE(tl_len(lst), 6 * sizeof(tagi_t));
+
+ dup = tl_adup(NULL, lst);
+
+ TEST_1(dup != NULL);
+ TEST_SIZE(tl_len(dup), 6 * sizeof(tagi_t));
+ TEST_SIZE(tl_xtra(dup, 0), xtra);
+
+ if (tstflags & tst_verbatim)
+ tl_print(stdout, "dup:\n", dup);
+
+ su_free(NULL, dup);
+ tl_vfree(lst);
+
+ su_home_unref(home);
+
+ END();
+}
+
+/** Test advanced tag features */
+static int tag_test2(void)
+{
+ BEGIN();
+
+#if 0
+ tagi_t
+ *lst, *dup, *filter1, *filter2, *filter3, *filter4,
+ *b1, *b2, *b3, *b4;
+
+ msg_t *msg;
+ http_t *http;
+ su_home_t *home;
+ int xtra;
+
+ home = su_home_new(sizeof *home);
+
+ msg = read_message("HTTP/2.0 401 Unauthorized\r\n"
+ "Content-Length: 0\r\n"
+ "\r\n");
+
+ http = msg_object(msg);
+
+ TEST_1(home && msg && http);
+
+ TEST_1(http_status_p((http_header_t *)http->http_status));
+ TEST_1(http_content_length_p((http_header_t *)http->http_content_length));
+
+ lst = tl_list(HTTPTAG_VIA(http->http_via),
+ HTTPTAG_RECORD_ROUTE(http->http_record_route),
+ TAG_SKIP(2),
+ HTTPTAG_CSEQ(http->http_cseq),
+ HTTPTAG_PAYLOAD(http->http_payload),
+ TAG_NULL());
+ filter1 = tl_list(HTTPTAG_VIA(0),
+ TAG_NULL());
+ filter2 = tl_list(HTTPTAG_CALL_ID(0),
+ HTTPTAG_FROM(0),
+ HTTPTAG_ROUTE(0),
+ HTTPTAG_CSEQ(0),
+ TAG_NULL());
+ filter3 = tl_list(HTTPTAG_CSEQ(0),
+ HTTPTAG_CONTENT_LENGTH(0),
+ TAG_NULL());
+ filter4 = tl_list(HTTPTAG_STATUS(0),
+ HTTPTAG_VIA(0),
+ HTTPTAG_RECORD_ROUTE(0),
+ HTTPTAG_FROM(0),
+ HTTPTAG_TO(0),
+ HTTPTAG_CALL_ID(0),
+ HTTPTAG_CSEQ(0),
+ HTTPTAG_WWW_AUTHENTICATE(0),
+ HTTPTAG_PROXY_AUTHENTICATE(0),
+ HTTPTAG_CONTENT_LENGTH(0),
+ TAG_NULL());
+
+ TEST_1(lst && filter1 && filter2 && filter3 && filter4);
+
+ b1 = tl_afilter(home, filter1, lst);
+ TEST(tl_len(b1), 2 * sizeof(tagi_t));
+ TEST_1(((http_via_t *)b1->t_value)->v_next);
+ xtra = http_header_size((http_header_t *)http->http_via);
+ xtra += SU_ALIGN(xtra);
+ xtra += http_header_size((http_header_t *)http->http_via->v_next);
+ TEST(tl_xtra(b1, 0), xtra);
+
+ dup = tl_adup(home, lst);
+
+ TEST(tl_len(dup), tl_len(lst));
+ TEST(tl_xtra(dup, 0), tl_xtra(lst, 0));
+
+ tl_vfree(lst);
+
+ lst = tl_list(HTTPTAG_HTTP(http), TAG_NULL());
+
+ b2 = tl_afilter(home, filter2, lst);
+ TEST(tl_len(b2), 4 * sizeof(tagi_t));
+ xtra = 0;
+ xtra += XTRA(xtra, http->http_call_id);
+ xtra += XTRA(xtra, http->http_from);
+ xtra += XTRA(xtra, http->http_cseq);
+ TEST(tl_xtra(b2, 0), xtra);
+
+ b3 = tl_afilter(home, filter3, lst);
+
+ TEST(tl_len(b3), 3 * sizeof(tagi_t));
+ TEST(tl_xtra(b3, 0),
+ sizeof(http_content_length_t) + sizeof(http_cseq_t));
+
+
+ b4 = tl_afilter(home, filter4, lst);
+ TEST(tl_len(b4), 11 * sizeof(tagi_t));
+ xtra = 0;
+ xtra += XTRA(xtra, http->http_status);
+ xtra += XTRA(xtra, http->http_via);
+ xtra += XTRA(xtra, http->http_via->v_next);
+ xtra += XTRA(xtra, http->http_record_route);
+ xtra += XTRA(xtra, http->http_from);
+ xtra += XTRA(xtra, http->http_to);
+ xtra += XTRA(xtra, http->http_call_id);
+ xtra += XTRA(xtra, http->http_cseq);
+ xtra += XTRA(xtra, http->http_www_authenticate);
+ xtra += XTRA(xtra, http->http_proxy_authenticate);
+ xtra += XTRA(xtra, http->http_content_length);
+ TEST(tl_xtra(b4, 0), xtra);
+
+ tl_vfree(filter1); tl_vfree(filter2); tl_vfree(filter3); tl_vfree(filter4);
+ tl_vfree(lst);
+
+ su_home_check(home);
+
+ su_free(home, b4);
+ su_free(home, b3);
+ su_free(home, b2);
+ su_free(home, dup);
+ su_free(home, b1);
+
+ su_home_check(home);
+
+ su_home_unref(home);
+#endif
+
+ END();
+}
+
+/** Test parser and header manipulation */
+static int http_header_handling_test(void)
+{
+ msg_t *msg;
+ http_t *http;
+ su_home_t *home;
+
+ http_request_t http_request[1];
+ http_status_t http_status[1];
+ http_unknown_t http_unknown[1];
+ http_separator_t http_separator[1];
+ http_payload_t http_payload[1];
+ http_via_t http_via[1];
+ http_host_t http_host[1];
+ http_from_t http_from[1];
+ http_referer_t http_referer[1];
+ http_connection_t http_connection[1];
+ http_accept_t http_accept[1];
+ http_accept_charset_t http_accept_charset[1];
+ http_accept_encoding_t http_accept_encoding[1];
+ http_accept_language_t http_accept_language[1];
+ http_accept_ranges_t http_accept_ranges[1];
+ http_allow_t http_allow[1];
+ http_te_t http_te[1];
+ http_authorization_t http_authorization[1];
+ http_www_authenticate_t http_www_authenticate[1];
+ http_proxy_authenticate_t http_proxy_authenticate[1];
+ http_proxy_authorization_t http_proxy_authorization[1];
+ http_age_t http_age[1];
+ http_cache_control_t http_cache_control[1];
+ http_date_t http_date[1];
+ http_expires_t http_expires[1];
+ http_if_match_t http_if_match[1];
+ http_if_modified_since_t http_if_modified_since[1];
+ http_if_none_match_t http_if_none_match[1];
+ http_if_range_t http_if_range[1];
+ http_if_unmodified_since_t http_if_unmodified_since[1];
+ http_etag_t http_etag[1];
+ http_expect_t http_expect[1];
+ http_last_modified_t http_last_modified[1];
+ http_location_t http_location[1];
+ http_max_forwards_t http_max_forwards[1];
+ http_pragma_t http_pragma[1];
+ http_range_t http_range[1];
+ http_retry_after_t http_retry_after[1];
+ http_trailer_t http_trailer[1];
+ http_upgrade_t http_upgrade[1];
+ http_vary_t http_vary[1];
+ http_warning_t http_warning[1];
+ http_user_agent_t http_user_agent[1];
+ http_server_t http_server[1];
+ http_mime_version_t http_mime_version[1];
+ http_content_language_t http_content_language[1];
+ http_content_location_t http_content_location[1];
+ http_content_md5_t http_content_md5[1];
+ http_content_range_t http_content_range[1];
+ http_content_encoding_t http_content_encoding[1];
+ http_transfer_encoding_t http_transfer_encoding[1];
+ http_content_type_t http_content_type[1];
+ http_content_length_t http_content_length[1];
+
+ BEGIN();
+
+ http_request_init(http_request);
+ http_status_init(http_status);
+ http_unknown_init(http_unknown);
+ http_separator_init(http_separator);
+ http_payload_init(http_payload);
+ http_via_init(http_via);
+ http_host_init(http_host);
+ http_from_init(http_from);
+ http_referer_init(http_referer);
+ http_connection_init(http_connection);
+
+ http_accept_init(http_accept);
+ http_accept_charset_init(http_accept_charset);
+ http_accept_encoding_init(http_accept_encoding);
+ http_accept_language_init(http_accept_language);
+ http_accept_ranges_init(http_accept_ranges);
+ http_allow_init(http_allow);
+ http_te_init(http_te);
+
+ http_authorization_init(http_authorization);
+ http_www_authenticate_init(http_www_authenticate);
+ http_proxy_authenticate_init(http_proxy_authenticate);
+ http_proxy_authorization_init(http_proxy_authorization);
+
+ http_age_init(http_age);
+ http_cache_control_init(http_cache_control);
+ http_date_init(http_date);
+ http_expires_init(http_expires);
+ http_if_match_init(http_if_match);
+ http_if_modified_since_init(http_if_modified_since);
+ http_if_none_match_init(http_if_none_match);
+ http_if_range_init(http_if_range);
+ http_if_unmodified_since_init(http_if_unmodified_since);
+
+ http_etag_init(http_etag);
+ http_expect_init(http_expect);
+ http_last_modified_init(http_last_modified);
+ http_location_init(http_location);
+ http_max_forwards_init(http_max_forwards);
+ http_pragma_init(http_pragma);
+ http_range_init(http_range);
+ http_retry_after_init(http_retry_after);
+ http_trailer_init(http_trailer);
+ http_upgrade_init(http_upgrade);
+ http_vary_init(http_vary);
+ http_warning_init(http_warning);
+
+ http_user_agent_init(http_user_agent);
+ http_server_init(http_server);
+
+ http_mime_version_init(http_mime_version);
+ http_content_language_init(http_content_language);
+ http_content_location_init(http_content_location);
+ http_content_md5_init(http_content_md5);
+ http_content_range_init(http_content_range);
+
+ http_content_encoding_init(http_content_encoding);
+ http_transfer_encoding_init(http_transfer_encoding);
+
+ http_content_type_init(http_content_type);
+ http_content_length_init(http_content_length);
+
+ home = su_home_new(sizeof *home);
+
+ {
+ int i;
+
+ struct { http_method_t number; char const *name; } methods[] = {
+ { http_method_get, "GET" },
+ { http_method_post, "POST" },
+ { http_method_head, "HEAD" },
+ { http_method_options, "OPTIONS" },
+ { http_method_put, "PUT" },
+ { http_method_delete, "DELETE" },
+ { http_method_trace, "TRACE" },
+ { http_method_connect, "CONNECT" },
+ { 0, NULL }
+ };
+
+ for (i = 0; methods[i].name; i++) {
+ TEST_1(strcmp(methods[i].name,
+ http_method_name(methods[i].number, "")) == 0);
+ }
+ }
+
+ msg = read_message(
+ "PUT /Foo HTTP/1.1\r\n"
+ "Host: [::1]:8080\r\n"
+ "From: webmaster at w3.org\r\n"
+ "Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1)\r\n"
+ "Referer: http://www.w3.org/hypertext/DataSources/Overview.html\r\n"
+ "Connection: close\r\n"
+ "Accept: audio/*; q=0.2, audio/basic\r\n"
+ "Accept-Charset: iso-8859-5, unicode-1-1;q=0.8\r\n"
+ "Accept-Encoding: gzip;q=1.0, identity; q=0.5, *;q=0\r\n"
+ "Accept-Language: da, en-gb;q=0.8, en;q=0.7\r\n"
+ "Accept-Ranges: bytes\r\n"
+ "Age: 212\r\n"
+ "Allow: GET, HEAD, PUT\r\n"
+ "Cache-Control: private, community=\"UCI\"\r\n"
+ "Content-Encoding: identity\r\n"
+ "Content-Language: da\r\n"
+ "Content-Type: text/html\r\n"
+ "Content-Location: http://localhost/Foo\r\n"
+ "Content-Length: 28\r\n"
+ "Content-MD5: f48BLMCjkX5M5PgWoelogA==\r\n"
+ "Content-Range: bytes 0-27/*\r\n"
+ "\r\n"
+ "<html><body></body></html>\r\n");
+
+ http = msg_object(msg);
+
+ TEST_1(home && msg && http);
+
+ TEST_1(http_is_request((http_header_t *)http->http_request));
+ TEST_1(http->http_via); TEST_1(http->http_via->v_next);
+ TEST_1(http->http_via->v_next->v_next == NULL);
+
+ TEST_1(http->http_host);
+ TEST_1(http->http_from);
+ TEST_1(http->http_referer);
+ TEST_1(http->http_connection);
+ TEST_1(http->http_accept);
+ TEST_1(http->http_accept_charset);
+ TEST_1(http->http_accept_encoding);
+ TEST_1(http->http_accept_language);
+ TEST_1(http->http_accept_ranges);
+ TEST_1(http->http_age);
+ TEST_1(http->http_allow);
+ TEST_1(http->http_cache_control);
+ TEST_1(http->http_content_encoding);
+ TEST_1(http->http_content_language);
+ TEST_1(http->http_content_type);
+ TEST_1(http->http_content_location);
+ TEST_1(http->http_content_length);
+ TEST_1(http->http_content_md5);
+ TEST_1(http->http_content_range);
+
+ /* Quiet lots of warnings */
+#define _msg_header_offset msg_header_offset
+#define msg_header_offset(msg, http, h) \
+ _msg_header_offset(msg, http, (http_header_t *)h)
+
+ TEST_P(msg_header_offset(msg, http, http_request), &http->http_request);
+ TEST_P(msg_header_offset(msg, http, http_status), &http->http_status);
+ TEST_P(msg_header_offset(msg, http, http_unknown), &http->http_unknown);
+ TEST_P(msg_header_offset(msg, http, http_separator), &http->http_separator);
+ TEST_P(msg_header_offset(msg, http, http_payload), &http->http_payload);
+ TEST_P(msg_header_offset(msg, http, http_via), &http->http_via);
+
+ TEST_P(msg_header_offset(msg, http, http_via), &http->http_via);
+ TEST_P(msg_header_offset(msg, http, http_host), &http->http_host);
+ TEST_P(msg_header_offset(msg, http, http_from), &http->http_from);
+ TEST_P(msg_header_offset(msg, http, http_referer), &http->http_referer);
+ TEST_P(msg_header_offset(msg, http, http_connection),
+ &http->http_connection);
+
+ TEST_P(msg_header_offset(msg, http, http_accept), &http->http_accept);
+ TEST_P(msg_header_offset(msg, http, http_accept_charset),
+ &http->http_accept_charset);
+ TEST_P(msg_header_offset(msg, http, http_accept_encoding),
+ &http->http_accept_encoding);
+ TEST_P(msg_header_offset(msg, http, http_accept_language),
+ &http->http_accept_language);
+ TEST_P(msg_header_offset(msg, http, http_accept_ranges),
+ &http->http_accept_ranges);
+ TEST_P(msg_header_offset(msg, http, http_allow),
+ &http->http_allow);
+ TEST_P(msg_header_offset(msg, http, http_te),
+ &http->http_te);
+
+ TEST_P(msg_header_offset(msg, http, http_authorization),
+ &http->http_authorization);
+ TEST_P(msg_header_offset(msg, http, http_www_authenticate),
+ &http->http_www_authenticate);
+ TEST_P(msg_header_offset(msg, http, http_proxy_authenticate),
+ &http->http_proxy_authenticate);
+ TEST_P(msg_header_offset(msg, http, http_proxy_authorization),
+ &http->http_proxy_authorization);
+
+ TEST_P(msg_header_offset(msg, http, http_age),
+ &http->http_age);
+ TEST_P(msg_header_offset(msg, http, http_cache_control),
+ &http->http_cache_control);
+ TEST_P(msg_header_offset(msg, http, http_date),
+ &http->http_date);
+ TEST_P(msg_header_offset(msg, http, http_expires),
+ &http->http_expires);
+ TEST_P(msg_header_offset(msg, http, http_if_match),
+ &http->http_if_match);
+ TEST_P(msg_header_offset(msg, http, http_if_modified_since),
+ &http->http_if_modified_since);
+ TEST_P(msg_header_offset(msg, http, http_if_none_match),
+ &http->http_if_none_match);
+ TEST_P(msg_header_offset(msg, http, http_if_range),
+ &http->http_if_range);
+ TEST_P(msg_header_offset(msg, http, http_if_unmodified_since),
+ &http->http_if_unmodified_since);
+
+ TEST_P(msg_header_offset(msg, http, http_etag),
+ &http->http_etag);
+ TEST_P(msg_header_offset(msg, http, http_expect),
+ &http->http_expect);
+ TEST_P(msg_header_offset(msg, http, http_last_modified),
+ &http->http_last_modified);
+ TEST_P(msg_header_offset(msg, http, http_location),
+ &http->http_location);
+ TEST_P(msg_header_offset(msg, http, http_max_forwards),
+ &http->http_max_forwards);
+ TEST_P(msg_header_offset(msg, http, http_pragma),
+ &http->http_pragma);
+ TEST_P(msg_header_offset(msg, http, http_range),
+ &http->http_range);
+ TEST_P(msg_header_offset(msg, http, http_retry_after),
+ &http->http_retry_after);
+ TEST_P(msg_header_offset(msg, http, http_trailer),
+ &http->http_trailer);
+ TEST_P(msg_header_offset(msg, http, http_upgrade),
+ &http->http_upgrade);
+ TEST_P(msg_header_offset(msg, http, http_vary),
+ &http->http_vary);
+ TEST_P(msg_header_offset(msg, http, http_warning),
+ &http->http_warning);
+
+ TEST_P(msg_header_offset(msg, http, http_user_agent),
+ &http->http_user_agent);
+ TEST_P(msg_header_offset(msg, http, http_server),
+ &http->http_server);
+
+ TEST_P(msg_header_offset(msg, http, http_mime_version),
+ &http->http_mime_version);
+ TEST_P(msg_header_offset(msg, http, http_content_language),
+ &http->http_content_language);
+ TEST_P(msg_header_offset(msg, http, http_content_location),
+ &http->http_content_location);
+ TEST_P(msg_header_offset(msg, http, http_content_md5),
+ &http->http_content_md5);
+ TEST_P(msg_header_offset(msg, http, http_content_range),
+ &http->http_content_range);
+
+ TEST_P(msg_header_offset(msg, http, http_content_encoding),
+ &http->http_content_encoding);
+ TEST_P(msg_header_offset(msg, http, http_transfer_encoding),
+ &http->http_transfer_encoding);
+
+ TEST_P(msg_header_offset(msg, http, http_content_type),
+ &http->http_content_type);
+ TEST_P(msg_header_offset(msg, http, http_content_length),
+ &http->http_content_length);
+
+ TEST_SIZE(http_via_class->hc_params,
+ offsetof(http_via_t, v_common));
+ TEST_SIZE(http_host_class->hc_params,
+ offsetof(http_host_t, h_common));
+ TEST_SIZE(http_from_class->hc_params,
+ offsetof(http_from_t, g_common));
+ TEST_SIZE(http_referer_class->hc_params,
+ offsetof(http_referer_t, loc_common));
+ TEST_SIZE(http_connection_class->hc_params,
+ offsetof(http_connection_t, k_items));
+
+ TEST_SIZE(http_accept_class->hc_params,
+ offsetof(http_accept_t, ac_params));
+ TEST_SIZE(http_accept_charset_class->hc_params,
+ offsetof(http_accept_charset_t, aa_params));
+ TEST_SIZE(http_accept_encoding_class->hc_params,
+ offsetof(http_accept_encoding_t, aa_params));
+ TEST_SIZE(http_accept_language_class->hc_params,
+ offsetof(http_accept_language_t, aa_params));
+ TEST_SIZE(http_accept_ranges_class->hc_params,
+ offsetof(http_accept_ranges_t, k_items));
+ TEST_SIZE(http_allow_class->hc_params,
+ offsetof(http_allow_t, k_items));
+ TEST_SIZE(http_te_class->hc_params,
+ offsetof(http_te_t, te_params));
+
+ TEST_SIZE(http_authorization_class->hc_params,
+ offsetof(http_authorization_t, au_params));
+ TEST_SIZE(http_www_authenticate_class->hc_params,
+ offsetof(http_www_authenticate_t, au_params));
+ TEST_SIZE(http_proxy_authenticate_class->hc_params,
+ offsetof(http_proxy_authenticate_t, au_params));
+ TEST_SIZE(http_proxy_authorization_class->hc_params,
+ offsetof(http_proxy_authorization_t, au_params));
+
+ TEST_SIZE(http_age_class->hc_params,
+ offsetof(http_age_t, x_common));
+ TEST_SIZE(http_cache_control_class->hc_params,
+ offsetof(http_cache_control_t, k_items));
+ TEST_SIZE(http_date_class->hc_params,
+ offsetof(http_date_t, d_common));
+ TEST_SIZE(http_expires_class->hc_params,
+ offsetof(http_expires_t, d_common));
+ TEST_SIZE(http_if_match_class->hc_params,
+ offsetof(http_if_match_t, k_items));
+ TEST_SIZE(http_if_modified_since_class->hc_params,
+ offsetof(http_if_modified_since_t, d_common));
+ TEST_SIZE(http_if_none_match_class->hc_params,
+ offsetof(http_if_none_match_t, k_items));
+ TEST_SIZE(http_if_range_class->hc_params,
+ offsetof(http_if_range_t, ifr_common));
+ TEST_SIZE(http_if_unmodified_since_class->hc_params,
+ offsetof(http_if_unmodified_since_t, d_common));
+
+ TEST_SIZE(http_etag_class->hc_params,
+ offsetof(http_etag_t, g_common));
+ TEST_SIZE(http_expect_class->hc_params,
+ offsetof(http_expect_t, g_common));
+ TEST_SIZE(http_last_modified_class->hc_params,
+ offsetof(http_last_modified_t, d_common));
+ TEST_SIZE(http_location_class->hc_params,
+ offsetof(http_location_t, loc_common));
+ TEST_SIZE(http_max_forwards_class->hc_params,
+ offsetof(http_max_forwards_t, mf_common));
+ TEST_SIZE(http_pragma_class->hc_params,
+ offsetof(http_pragma_t, k_items));
+ TEST_SIZE(http_range_class->hc_params,
+ offsetof(http_range_t, rng_specs));
+ TEST_SIZE(http_retry_after_class->hc_params,
+ offsetof(http_retry_after_t, ra_common));
+ TEST_SIZE(http_trailer_class->hc_params,
+ offsetof(http_trailer_t, k_items));
+ TEST_SIZE(http_upgrade_class->hc_params,
+ offsetof(http_upgrade_t, k_items));
+ TEST_SIZE(http_vary_class->hc_params,
+ offsetof(http_vary_t, k_items));
+ TEST_SIZE(http_warning_class->hc_params,
+ offsetof(http_warning_t, w_common));
+
+ TEST_SIZE(http_user_agent_class->hc_params,
+ offsetof(http_user_agent_t, g_common));
+ TEST_SIZE(http_server_class->hc_params,
+ offsetof(http_server_t, g_common));
+
+ TEST_SIZE(http_mime_version_class->hc_params,
+ offsetof(http_mime_version_t, g_common));
+ TEST_SIZE(http_content_language_class->hc_params,
+ offsetof(http_content_language_t, k_items));
+ TEST_SIZE(http_content_location_class->hc_params,
+ offsetof(http_content_location_t, g_common));
+ TEST_SIZE(http_content_md5_class->hc_params,
+ offsetof(http_content_md5_t, g_common));
+ TEST_SIZE(http_content_range_class->hc_params,
+ offsetof(http_content_range_t, cr_common));
+
+ TEST_SIZE(http_content_encoding_class->hc_params,
+ offsetof(http_content_encoding_t, k_items));
+ TEST_SIZE(http_transfer_encoding_class->hc_params,
+ offsetof(http_transfer_encoding_t, k_items));
+
+ TEST_SIZE(http_content_type_class->hc_params,
+ offsetof(http_content_type_t, c_params));
+ TEST_SIZE(http_content_length_class->hc_params,
+ offsetof(http_content_length_t, l_common));
+
+ su_home_unref(home);
+
+ END();
+}
+
+int count(msg_common_t *h)
+{
+ http_header_t *sh = (http_header_t *)h;
+ unsigned n;
+
+ for (n = 0; sh; sh = sh->sh_next)
+ n++;
+
+ return n;
+}
+
+int len(msg_common_t *h)
+{
+ msg_header_t *sh = (msg_header_t *)h;
+ unsigned n;
+
+ for (n = 0; sh; sh = sh->sh_next) {
+ if (n) n +=2;
+ n += msg_header_field_e(NULL, 0, sh, 0);
+ }
+
+ return n;
+}
+
+static int http_header_test(void)
+{
+ su_home_t home[1] = { SU_HOME_INIT(home) };
+
+ BEGIN();
+
+ {
+ http_request_t *rq;
+
+ TEST_1(rq = http_request_make(home, "GET / HTTP/1.0"));
+
+ TEST(rq->rq_method, http_method_get);
+ TEST_S(rq->rq_method_name, "GET");
+ TEST_S(rq->rq_url->url_path, "");
+ TEST_1(rq->rq_url->url_root);
+ TEST_S(url_as_string(home, rq->rq_url), "/");
+ TEST_P(rq->rq_version, http_version_1_0);
+
+ TEST_1(rq = http_request_make(home, "GET / HTTP/1.2"));
+
+ TEST(rq->rq_method, http_method_get);
+ TEST_S(rq->rq_method_name, "GET");
+ TEST_S(rq->rq_url->url_path, "");
+ TEST_1(rq->rq_url->url_root);
+ TEST_S(url_as_string(home, rq->rq_url), "/");
+ TEST_S(rq->rq_version, "HTTP/1.2");
+
+ TEST_1(rq = http_request_make(home, "GET /foo"));
+ TEST(rq->rq_method, http_method_get);
+ TEST_S(rq->rq_method_name, "GET");
+ TEST_S(rq->rq_url->url_path, "foo");
+ TEST_1(rq->rq_url->url_root);
+ TEST_S(url_as_string(home, rq->rq_url), "/foo");
+ TEST_S(rq->rq_version, "");
+ TEST_P(rq->rq_version, http_version_0_9);
+ }
+
+ {
+ http_status_t *st;
+
+ st = http_status_make(home, "HTTP/1.0 100 Continue"); TEST_1(st);
+ TEST_S(st->st_version, "HTTP/1.0");
+ TEST_P(st->st_version, http_version_1_0);
+ TEST(st->st_status, 100);
+ TEST_S(st->st_phrase, "Continue");
+
+ st = http_status_make(home, "HTTP/1.1 200"); TEST_1(st);
+ TEST_S(st->st_version, "HTTP/1.1");
+ TEST(st->st_status, 200);
+ TEST_S(st->st_phrase, "");
+
+ st = http_status_make(home, "HTTP/1.1 200 Ok"); TEST_1(st);
+ TEST_S(st->st_version, "HTTP/1.1");
+ TEST_P(st->st_version, http_version_1_1);
+ TEST(st->st_status, 200);
+ TEST_S(st->st_phrase, "Ok");
+
+ st = http_status_make(home, "HTTP 99 Ok "); TEST_1(st);
+ TEST_S(st->st_version, "HTTP");
+ TEST(st->st_status, 99);
+ TEST_S(st->st_phrase, "Ok");
+
+ st = http_status_make(home, "HTTP/1.2 200 Ok"); TEST_1(st);
+ TEST_S(st->st_version, "HTTP/1.2");
+ TEST(st->st_status, 200);
+ TEST_S(st->st_phrase, "Ok");
+ }
+
+ {
+ http_content_range_t *cr;
+
+ cr = http_content_range_make(home, "bytes 0 - 499 / *"); TEST_1(cr);
+ TEST64(cr->cr_first, 0);
+ TEST64(cr->cr_last, 499);
+ TEST64(cr->cr_length, (http_off_t)-1);
+
+ cr = http_content_range_make(home, "bytes 500-999/9913133"); TEST_1(cr);
+ TEST64(cr->cr_first, 500);
+ TEST64(cr->cr_last, 999);
+ TEST64(cr->cr_length, 9913133);
+
+ TEST_1(!http_content_range_make(home, "bytes = 0 - 499 / *,"));
+ }
+
+ {
+ http_cookie_t *c;
+
+ c = http_cookie_make(home, "$Version=1;"
+ "foo=bar;$Domain=.nokia.com;$Path=\"\"");
+ TEST_1(c);
+ TEST_1(c->c_params);
+ TEST_S(c->c_version, "1");
+ TEST_S(c->c_name, "foo=bar");
+ TEST_S(c->c_domain, ".nokia.com");
+ TEST_S(c->c_path, "\"\"");
+
+ c = http_cookie_make(home, "$Version=1;"
+ "foo=bar;$Domain=.nokia.com;$Path=\"\", , "
+ "bar=bazzz;$Domain=.research.nokia.com;$Path=\"\";"
+ "hum=ham;$Domain=.nokia.fi;$Path=\"/sofia\""
+ );
+
+ TEST_1(c);
+ TEST_1(c->c_params);
+ TEST_S(c->c_version, "1");
+ TEST_S(c->c_name, "foo=bar");
+ TEST_S(c->c_domain, ".nokia.com");
+ TEST_S(c->c_path, "\"\"");
+
+ c = http_cookie_make(home, "foo=bar=baz1");
+
+ TEST_1(c);
+ TEST_1(c->c_params);
+ TEST_S(c->c_params[0], "foo=bar=baz1");
+ }
+
+ {
+ http_set_cookie_t *sc;
+
+ sc = http_set_cookie_make(home, "foo=bar;Domain=.nokia.com;Path=\"\""
+ ";Foo=bar;Version=1;Secure;Max-age=1212;"
+ "Comment=\"Jummi Jammmi\"");
+ TEST_1(sc);
+ TEST_1(sc->sc_params);
+ TEST_S(sc->sc_name, "foo=bar");
+ TEST_S(sc->sc_version, "1");
+ TEST_S(sc->sc_domain, ".nokia.com");
+ TEST_S(sc->sc_max_age, "1212");
+ TEST_S(sc->sc_path, "\"\"");
+ TEST_S(sc->sc_comment, "\"Jummi Jammmi\"");
+ TEST(sc->sc_secure, 1);
+
+ sc = http_set_cookie_make(home, "foo=bar;Domain=.nokia.com;Path=\"\""
+ ";Foo=bar;Version=1");
+
+ TEST_1(sc);
+ TEST_1(sc->sc_params);
+ TEST_S(sc->sc_name, "foo=bar");
+ TEST_S(sc->sc_version, "1");
+ TEST_S(sc->sc_domain, ".nokia.com");
+ TEST_P(sc->sc_max_age, NULL);
+ TEST_S(sc->sc_path, "\"\"");
+ TEST_S(sc->sc_comment, NULL);
+ TEST(sc->sc_secure, 0);
+
+
+ sc = http_set_cookie_make(home,
+ "CUSTOMER=WILE_E_COYOTE; "
+ "path=/; "
+ "expires=Wednesday, 09-Nov-99 23:12:40 GMT");
+
+ TEST_1(sc);
+ TEST_1(sc->sc_params);
+ TEST_S(sc->sc_name, "CUSTOMER=WILE_E_COYOTE");
+ TEST_S(sc->sc_version, NULL);
+ TEST_S(sc->sc_domain, NULL);
+ TEST_S(sc->sc_max_age, NULL);
+ TEST_S(sc->sc_path, "/");
+ TEST_S(sc->sc_comment, NULL);
+ TEST(sc->sc_secure, 0);
+ }
+
+ {
+ http_range_t *rng;
+
+ rng = http_range_make(home, "bytes = 0 - 499"); TEST_1(rng);
+ TEST_S(rng->rng_unit, "bytes");
+ TEST_1(rng->rng_specs);
+ TEST_S(rng->rng_specs[0], "0-499");
+ TEST_P(rng->rng_specs[1], NULL);
+
+ rng = http_range_make(home, "bytes=,500 - 999"); TEST_1(rng);
+ TEST_S(rng->rng_unit, "bytes");
+ TEST_1(rng->rng_specs);
+ TEST_S(rng->rng_specs[0], "500-999");
+ TEST_P(rng->rng_specs[1], NULL);
+
+ rng = http_range_make(home, "bytes= - 500"); TEST_1(rng);
+ TEST_S(rng->rng_unit, "bytes");
+ TEST_1(rng->rng_specs);
+ TEST_S(rng->rng_specs[0], "-500");
+ TEST_P(rng->rng_specs[1], NULL);
+
+ rng = http_range_make(home, "bytes=9500-"); TEST_1(rng);
+ TEST_S(rng->rng_unit, "bytes");
+ TEST_1(rng->rng_specs);
+ TEST_S(rng->rng_specs[0], "9500-");
+ TEST_P(rng->rng_specs[1], NULL);
+
+ rng = http_range_make(home, "bytes=0- 0 , - 1"); TEST_1(rng);
+ TEST_S(rng->rng_unit, "bytes");
+ TEST_1(rng->rng_specs);
+ TEST_S(rng->rng_specs[0], "0-0");
+ TEST_S(rng->rng_specs[1], "-1");
+ TEST_P(rng->rng_specs[2], NULL);
+
+ rng = http_range_make(home, "bytes=500-600 , 601 - 999 ,,"); TEST_1(rng);
+ TEST_S(rng->rng_unit, "bytes");
+ TEST_1(rng->rng_specs);
+ TEST_S(rng->rng_specs[0], "500-600");
+ TEST_S(rng->rng_specs[1], "601-999");
+ TEST_P(rng->rng_specs[2], NULL);
+
+ rng = http_range_make(home, "bytes=500-700,601-999"); TEST_1(rng);
+ TEST_S(rng->rng_unit, "bytes");
+ TEST_1(rng->rng_specs);
+ TEST_S(rng->rng_specs[0], "500-700");
+ TEST_S(rng->rng_specs[1], "601-999");
+ TEST_P(rng->rng_specs[2], NULL);
+ }
+
+ {
+ http_date_t *d;
+ char const *s;
+ char b[64];
+
+ d = http_date_make(home, s = "Wed, 15 Nov 1995 06:25:24 GMT"); TEST_1(d);
+ TEST(d->d_time, 2208988800UL + 816416724);
+ TEST_1(http_date_e(b, sizeof b, (msg_header_t*)d, 0) > 0);
+ TEST_S(b, s);
+ d = http_date_make(home, s = "Wed, 15 Nov 1995 04:58:08 GMT"); TEST_1(d);
+ TEST(d->d_time, 2208988800UL + 816411488);
+ TEST_1(http_date_e(b, sizeof b, (msg_header_t*)d, 0) > 0);
+ TEST_S(b, s);
+ d = http_date_make(home, s = "Tue, 15 Nov 1994 08:12:31 GMT"); TEST_1(d);
+ TEST(d->d_time, 2208988800UL + 784887151);
+ TEST_1(http_date_e(b, sizeof b, (msg_header_t*)d, 0) > 0);
+ TEST_S(b, s);
+ d = http_date_make(home, "Fri Jan 30 12:21:09 2004"); TEST_1(d);
+ TEST(d->d_time, 2208988800UL + 1075465269);
+ d = http_date_make(home, "Fri Jan 1 12:21:09 2004"); TEST_1(d);
+ TEST(d->d_time, 2208988800UL + 1072959669);
+ d = http_date_make(home, "Tuesday, 15-Nov-94 08:12:31 GMT"); TEST_1(d);
+ TEST(d->d_time, 2208988800UL + 784887151);
+ }
+
+ {
+ http_retry_after_t *ra;
+ char const *s;
+ char b[64];
+
+ ra = http_retry_after_make(home, s = "Wed, 15 Nov 1995 06:25:24 GMT");
+ TEST_1(ra);
+ TEST(ra->ra_date + ra->ra_delta, 2208988800UL + 816416724);
+ TEST_1(http_retry_after_e(b, sizeof b, (msg_header_t*)ra, 0) > 0);
+ TEST_S(b, s);
+ ra = http_retry_after_make(home, s = "Wed, 15 Nov 1995 04:58:08 GMT");
+ TEST_1(ra);
+ TEST(ra->ra_date + ra->ra_delta, 2208988800UL + 816411488);
+ TEST_1(http_retry_after_e(b, sizeof b, (msg_header_t*)ra, 0) > 0);
+ TEST_S(b, s);
+ ra = http_retry_after_make(home, s = "Tue, 15 Nov 1994 08:12:31 GMT");
+ TEST_1(ra);
+ TEST(ra->ra_date + ra->ra_delta, 2208988800UL + 784887151);
+ TEST_1(http_retry_after_e(b, sizeof b, (msg_header_t*)ra, 0) > 0);
+ TEST_S(b, s);
+ ra = http_retry_after_make(home, "Fri Jan 30 12:21:09 2004");
+ TEST_1(ra);
+ TEST(ra->ra_date + ra->ra_delta, 2208988800UL + 1075465269);
+ ra = http_retry_after_make(home, "Fri Jan 1 12:21:09 2004");
+ TEST_1(ra);
+ TEST(ra->ra_date + ra->ra_delta, 2208988800UL + 1072959669);
+ ra = http_retry_after_make(home, "Tuesday, 15-Nov-94 08:12:31 GMT");
+ TEST_1(ra);
+ TEST(ra->ra_date + ra->ra_delta, 2208988800UL + 784887151);
+ ra = http_retry_after_make(home, "121");
+ TEST_1(ra);
+ TEST(ra->ra_date, 0);
+ TEST(ra->ra_delta, 121);
+ }
+
+ {
+ http_location_t *l;
+
+ TEST_1(l = http_location_make(home, "http://www.google.fi/cxfer?c=PREF%3D:TM%3D1105378671:S%3DfoewuOwfszMIFJbP&prev=/"));
+ }
+
+ su_home_deinit(home);
+
+ END();
+}
+
+static int http_parser_test(void)
+{
+ msg_t *msg;
+ http_t *http;
+
+ BEGIN();
+
+ {
+ char data[] =
+ "HTTP/1.1 200\r\n"
+ "Server: Apache/1.3.11 (Unix) tomcat/1.0\r\n"
+ "Transfer-Encoding: chunked, gzip\r\n"
+ "Transfer-Encoding: deflate\r\n"
+ "TE: chunked, gzip\r\n"
+ "TE: deflate\r\n"
+ "Content-Encoding: identity, gzip\r\n"
+ "Content-Type: text/html\r\n"
+ "Content-Encoding: deflate\r\n"
+ "Set-Cookie: PREF=ID=1eab07c269cd7e5a:LD=fi:TM=1094601448:LM=1094601448:S=Ik6IEs3W3vamd8Xu; "
+ "expires=Sun, 17-Jan-2038 19:14:07 GMT ; path=/; domain=.google.fi\r\n"
+ "Set-Cookie: CUSTOMER=WILE_E_COYOTE; "
+ "path=/; "
+ "expires=Wednesday, 09-Nov-99 23:12:40 GMT\r\n"
+ "\r\n"
+ "4c\r\n"
+ "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\r\n"
+ "\r\n"
+ "<html>\r\n"
+ "\r\n"
+ "\r\n9\r\n"
+ "</html>\r\n"
+ "\r\n0\r\n"
+ "Date: Mon, 21 Oct 2002 13:10:41 GMT\r\n"
+ "\n";
+
+ TEST_1(msg = read_message_byte_by_byte(data));
+
+ http = msg_object(msg); TEST_1(http);
+
+ TEST_1(http->http_status);
+ TEST_1(http->http_payload);
+ TEST_1(http->http_payload->pl_next);
+ TEST_1(http->http_date);
+ TEST_1(http->http_te);
+ TEST_1(http->http_transfer_encoding);
+ TEST_1(http->http_transfer_encoding->k_items);
+ TEST_1(http->http_content_encoding);
+ TEST_1(http->http_content_encoding->k_items);
+ TEST_1(http->http_content_encoding->k_items);
+ TEST_S(http->http_content_encoding->k_items[0], "identity");
+ TEST_S(http->http_content_encoding->k_items[1], "gzip");
+ TEST_S(http->http_content_encoding->k_items[2], "deflate");
+ TEST_P(http->http_content_encoding->k_items[3], NULL);
+ TEST_1(http->http_set_cookie);
+ TEST_1(http->http_set_cookie->sc_next);
+
+ msg_destroy(msg);
+ }
+
+ END();
+}
+
+static int test_http_encoding(void)
+{
+ http_header_t *h, *h1;
+ msg_t *msg;
+ http_t *http;
+ su_home_t *home;
+ char b[160];
+ size_t n;
+
+ BEGIN();
+
+ TEST_1(home = su_home_new(sizeof *home));
+
+ msg = read_message(
+ "GET http://bar.com/foo/ HTTP/1.1\r\n"
+ "Accept: text/html\r\n"
+ "Accept-Charset: iso-8859-1\r\n"
+ "Accept-Encoding: gzip\r\n"
+ "Accept-Language: fi\r\n"
+ "Authorization: Basic dXNlcjE6c2VjcmV0\r\n"
+ "Expect: 100-continue\r\n"
+ "From: user at nokia.com\r\n"
+ "Host: www.nokia.com:80\r\n"
+ "If-Match: \"entity_tag001\"\r\n"
+ "If-Modified-Since: Tue, 11 Jul 2000 18:23:51 GMT\r\n"
+ "If-None-Match: \"entity_tag001\", \"tag02\"\r\n"
+ "If-Range: Tue, 11 Jul 2000 18:23:51 GMT\r\n"
+ "If-Unmodified-Since: Tue, 11 Jul 2000 18:23:51 GMT\r\n"
+ "Location: a+a+://\r\n"
+ "Max-Forwards: 3\r\n"
+ "Proxy-Authorization: Basic dXNlcjE6c2VjcmV0\r\n"
+ "Range: bytes=100-599\r\n"
+ "Referer: http://www.microsoft.com/resources.asp\r\n"
+ "TE: trailers\r\n"
+ "User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)\r\n"
+ "Cookie: $Version=\"1\";user=\"WILE_E_COYOTE\";$Path=\"/acme\"\r\n"
+ "Cache-Control: max-age=10\r\n"
+ "Pragma: no-cache\r\n"
+ "Transfer-Encoding: chunked, deflate\r\n"
+ "Upgrade: SHTTP/1.3, TLS/1.0\r\n"
+ "Via: HTTP/1.1 Proxy1\r\n"
+ "Proxy-Connection: keep-alive\r\n"
+ "Connection: close\r\n"
+ "Date: Tue, 11 Jul 2000 18:23:51 GMT\r\n"
+ "Trailer: Date, Connection\r\n"
+ "Warning: 2112 www.nokia.com \"Disconnected Operation\"\r\n"
+ /* This is here just because we cannot include two Retry-After
+ headers in a single message */
+ "Retry-After: 60\r\n"
+ "\r\n"
+ );
+ http = http_object(msg);
+
+ TEST_1(msg); TEST_1(http); TEST_1(!http->http_error);
+
+ for (h = (http_header_t *)http->http_request; h; h = h->sh_succ) {
+
+ if (h == (http_header_t*)http->http_payload)
+ break;
+
+ TEST_1(h1 = msg_header_dup(home, h));
+ n = msg_header_e(b, sizeof b, h1, 0);
+ if (n != h->sh_len)
+ TEST_SIZE(n, h->sh_len);
+ TEST_M(b, h->sh_data, n);
+ su_free(home, h1);
+ }
+
+ msg_destroy(msg), msg = NULL;
+
+ msg = read_message(
+ "HTTP/1.1 200 Ok\r\n"
+ "Accept-Ranges: none\r\n"
+ "Age: 2147483648\r\n"
+ "ETag: \"b38b9-17dd-367c5dcd\"\r\n"
+ "Location: http://localhost/redirecttarget.asp\r\n"
+ "Proxy-Authenticate: Basic realm=\"Nokia Internet Proxy\"\r\n"
+ "Retry-After: Tue, 11 Jul 2000 18:23:51 GMT\r\n"
+ "Server: Microsoft-IIS/5.0\r\n"
+ "Vary: Date\r\n"
+ "WWW-Authenticate: Digest realm=\"Nokia Intranet\", nonce=\"3wWGOvaWn3n+hFv8PK2ABQ==\", opaque=\"+GNywA==\", algorithm=MD5, qop=\"auth-int\"\r\n"
+ "Set-Cookie: user=\"WILE_E_COYOTE\";Version=\"1\";Path=\"/acme\"\r\n"
+ "Allow: GET, HEAD\r\n"
+ /* This is here just because we cannot include two If-Range
+ headers in a single message */
+ "If-Range: \"tag02\"\r\n"
+ "Content-Encoding: gzip\r\n"
+ "Content-Language: en\r\n"
+ "Content-Length: 70\r\n"
+ "Content-Location: http://localhost/page.asp\r\n"
+ "Content-MD5: LLO7gLaGqGt4BI6HouiWng==\r\n"
+ "Content-Range: bytes 2543-4532/7898\r\n"
+ "Content-Type: text/html\r\n"
+ "Expires: Tue, 11 Jul 2000 18:23:51 GMT\r\n"
+ "Last-Modified: Tue, 11 Jul 2000 18:23:51 GMT\r\n"
+ "\r\n"
+ "<html><head><title>Heippa!</title></head><body>Heippa!</body></html>"
+ "\r\n");
+ http = http_object(msg);
+
+ TEST_1(msg); TEST_1(http); TEST_1(!http->http_error);
+
+ for (h = (http_header_t *)http->http_status; h; h = h->sh_succ) {
+ if (h == (http_header_t*)http->http_payload)
+ break;
+
+ TEST_1(h1 = msg_header_dup(home, h));
+ n = msg_header_e(b, sizeof b, h1, 0);
+ TEST_SIZE(n, h->sh_len);
+ TEST_M(b, h->sh_data, n);
+ su_free(home, h1);
+ }
+
+ msg_destroy(msg), msg = NULL;
+
+ su_home_check(home);
+ su_home_zap(home);
+
+ END();
+}
+
+
+static int http_chunk_test(void)
+{
+ msg_t *msg;
+ http_t *http;
+
+ BEGIN();
+
+ {
+ char data[] =
+ "\nHTTP/1.1 200 OK\r\n"
+ "Server: Apache/1.3.11 (Unix) tomcat/1.0\r\n"
+ "Transfer-Encoding: chunked\r\n"
+ "Content-Type: text/html\r\n"
+ "\r\n"
+ "4c\r\n"
+ "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\r\n"
+ "\r\n"
+ "<html>\r\n"
+ "\r\n"
+ "\r\n9\r\n"
+ "</html>\r\n"
+ "\r\n0\r\n"
+ "Date: Mon, 21 Oct 2002 13:10:41 GMT\r\n"
+ "\n";
+
+ TEST_1(msg = read_message_byte_by_byte(data));
+
+ http = msg_object(msg); TEST_1(http);
+
+ TEST_1(http->http_status);
+ TEST_1(http->http_payload);
+ TEST_1(http->http_payload->pl_next);
+ TEST_1(http->http_date);
+
+ msg_destroy(msg);
+ }
+
+ {
+ /* Use LF only as line delimiter */
+ char data[] =
+ "HTTP/1.1 200 OK\n"
+ "Server: Apache/1.3.11 (Unix) tomcat/1.0\n"
+ "Transfer-Encoding: chunked\n"
+ "Content-Type: text/html\n"
+ "\n"
+ "48\n"
+ "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\n"
+ "\n"
+ "<html>\n"
+ "\n"
+ "\n8\n"
+ "</html>\n"
+ "\n0\n"
+ "Date: Mon, 21 Oct 2002 13:10:41 GMT\n"
+ "\n";
+
+ TEST_1(msg = read_message_byte_by_byte(data));
+
+ http = msg_object(msg); TEST_1(http);
+
+ TEST_1(http->http_status);
+ TEST_1(http->http_payload);
+ TEST_1(http->http_payload->pl_next);
+ TEST_1(http->http_date);
+
+ msg_destroy(msg);
+ }
+
+ {
+ /* Use CR only as line delimiter */
+ char data[] =
+ "HTTP/1.1 200 OK\r"
+ "Server: Apache/1.3.11 (Unix) tomcat/1.0\r"
+ "Transfer-Encoding: chunked\r"
+ "Content-Type: text/html\r"
+ "\r"
+ "48\r"
+ "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\r"
+ "\r"
+ "<html>\r"
+ "\r"
+ "\r8\r"
+ "</html>\r"
+ "\r0\r"
+ "Date: Mon, 21 Oct 2002 13:10:41 GMT\r"
+ "\r";
+
+ TEST_1(msg = read_message_byte_by_byte(data));
+
+ http = msg_object(msg); TEST_1(http);
+
+ TEST_1(http->http_status);
+ TEST_1(http->http_payload);
+ TEST_1(http->http_payload->pl_next);
+ TEST_1(http->http_date);
+
+ msg_destroy(msg);
+ }
+
+ END();
+}
+
+static int http_tag_test(void)
+{
+ BEGIN();
+
+ {
+ msg_t *msg;
+ http_t *http;
+
+ http_referer_t *r;
+ http_upgrade_t *u;
+
+ char data[] =
+ "HTTP/1.1 200 OK\r\n"
+ "Server: Apache/1.3.11 (Unix) tomcat/1.0\r\n"
+ "\r\n";
+
+ TEST_1(msg = read_message_byte_by_byte(data));
+
+ http = msg_object(msg); TEST_1(http);
+
+ TEST_1(http->http_status);
+ TEST_1(http->http_server);
+
+ r = http_referer_make(NULL, "ftp://ftp.funet.fi"); TEST_1(r);
+ u = http_upgrade_make(NULL, "HTTP/1.1, TLS/1.1"); TEST_1(u);
+
+ TEST_1(u->k_items);
+ TEST_S(u->k_items[0], "HTTP/1.1");
+ TEST_S(u->k_items[1], "TLS/1.1");
+ TEST_1(!u->k_items[2]);
+
+ TEST(http_add_tl(msg, http,
+ HTTPTAG_SERVER(HTTP_NONE->sh_server),
+ HTTPTAG_USER_AGENT_STR(NULL),
+ HTTPTAG_USER_AGENT(NULL),
+ HTTPTAG_REFERER(r),
+ HTTPTAG_MAX_FORWARDS_STR("1"),
+ HTTPTAG_HEADER((http_header_t*)u),
+ HTTPTAG_HEADER_STR("Vary: *\r\n\r\nfoo"),
+ TAG_END()),
+ 5);
+
+ TEST_P(http->http_server, NULL);
+ TEST_1(http->http_referer);
+ TEST_1(http->http_max_forwards);
+ TEST_1(http->http_upgrade);
+ TEST_1(http->http_vary);
+ TEST_1(http->http_payload);
+
+ msg_destroy(msg);
+ }
+
+ END();
+}
+
+static
+int test_query_parser(void)
+{
+ BEGIN();
+
+ {
+ char query[] = "foo=bar&bar=baz";
+ char *foo = NULL, *bar = NULL, *baz = "default";
+
+ TEST_SIZE(http_query_parse(NULL, NULL), -1);
+
+ TEST_SIZE(http_query_parse(query,
+ "foo=", &foo,
+ "bar=", &bar,
+ "baz=", &baz,
+ NULL), 2);
+ TEST_S(foo, "bar");
+ TEST_S(bar, "baz");
+ TEST_S(baz, "default");
+ }
+
+ {
+ char q2[] = "f%6fo=b%61r&bar=baz&bazibazuki";
+
+ char *foo = NULL, *bar = NULL, *baz = NULL;
+
+ TEST_SIZE(http_query_parse(q2,
+ "foo=", &foo,
+ "bar=", &bar,
+ "baz", &baz,
+ NULL),
+ 3);
+
+ TEST_S(foo, "bar");
+ TEST_S(bar, "baz");
+ TEST_S(baz, "ibazuki");
+
+ }
+
+ END();
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/ChangeLog Thu Dec 21 01:30:28 2006
@@ -0,0 +1,14 @@
+2005-10-27 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Fixed token64_e() prototype in ipt/token64.[hc].
+
+ M ./libsofia-sip-ua/ipt/token64.c -1 +1
+ M ./libsofia-sip-ua/ipt/token64.h -1 +1
+
+2005-07-24 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * sha1.c: Added RFC 3174 copyright notice.
+
+2005-07-18 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * Initial import of the module to Sofia-SIP tree.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/Doxyfile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/Doxyfile Thu Dec 21 01:30:28 2006
@@ -0,0 +1,12 @@
+PROJECT_NAME = "ipt"
+OUTPUT_DIRECTORY = ../docs/html/ips
+
+INPUT = ipt.docs sofia-sip .
+
+ at INCLUDE = ../docs/Doxyfile.conf
+
+TAGFILES += ../docs/su.doxytags=../su
+GENERATE_TAGFILE = ../docs/ipt.doxytags
+
+ALIASES +=
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/Makefile.am Thu Dec 21 01:30:28 2006
@@ -0,0 +1,54 @@
+#
+# Makefile.am for ipt module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+INCLUDES = -I$(srcdir)/../su -I../su
+
+# ----------------------------------------------------------------------
+# Build targets
+
+noinst_LTLIBRARIES = libipt.la
+
+check_PROGRAMS = torture_base64
+
+TESTS = torture_base64
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+
+nobase_include_sofia_HEADERS = \
+ sofia-sip/rc4.h \
+ sofia-sip/base64.h \
+ sofia-sip/string0.h sofia-sip/token64.h \
+ sofia-sip/uniqueid.h
+
+libipt_la_SOURCES = base64.c string0.c token64.c
+
+EXTRA_DIST = sofia-sip/utf8.h \
+ utf8internal.h \
+ utf8.c ucs2.c ucs4.c rc4.c \
+ utf8test.c
+
+COVERAGE_INPUT = $(libipt_la_SOURCES) $(include_sofia_HEADERS)
+
+LDADD = libipt.la \
+ ../sresolv/libsresolv.la \
+ ../su/libsu.la
+
+torture_base64_LDFLAGS = -static
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+
+EXTRA_DIST += Doxyfile ipt.docs
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+
+include ../sofia.am
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/Makefile.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1,694 @@
+# 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.
+
+ at SET_MAKE@
+
+#
+# Makefile.am for ipt module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+# common Makefile targets for libsofia-sip-ua modules
+# ---------------------------------------------------
+
+
+SOURCES = $(libipt_la_SOURCES) torture_base64.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 = torture_base64$(EXEEXT)
+DIST_COMMON = $(nobase_include_sofia_HEADERS) $(srcdir)/../sofia.am \
+ $(srcdir)/Makefile.am $(srcdir)/Makefile.in ChangeLog
+subdir = libsofia-sip-ua/ipt
+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 =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libipt_la_LIBADD =
+am_libipt_la_OBJECTS = base64.lo string0.lo token64.lo
+libipt_la_OBJECTS = $(am_libipt_la_OBJECTS)
+torture_base64_SOURCES = torture_base64.c
+torture_base64_OBJECTS = torture_base64.$(OBJEXT)
+torture_base64_LDADD = $(LDADD)
+torture_base64_DEPENDENCIES = libipt.la ../sresolv/libsresolv.la \
+ ../su/libsu.la
+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 = $(libipt_la_SOURCES) torture_base64.c
+DIST_SOURCES = $(libipt_la_SOURCES) torture_base64.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|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(include_sofiadir)"
+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)/../su -I../su
+
+# ----------------------------------------------------------------------
+# Build targets
+noinst_LTLIBRARIES = libipt.la
+TESTS = torture_base64
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+nobase_include_sofia_HEADERS = \
+ sofia-sip/rc4.h \
+ sofia-sip/base64.h \
+ sofia-sip/string0.h sofia-sip/token64.h \
+ sofia-sip/uniqueid.h
+
+libipt_la_SOURCES = base64.c string0.c token64.c
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+EXTRA_DIST = sofia-sip/utf8.h utf8internal.h utf8.c ucs2.c ucs4.c \
+ rc4.c utf8test.c Doxyfile ipt.docs
+COVERAGE_INPUT = $(libipt_la_SOURCES) $(include_sofia_HEADERS)
+LDADD = libipt.la \
+ ../sresolv/libsresolv.la \
+ ../su/libsu.la
+
+torture_base64_LDFLAGS = -static
+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
+
+all: 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/ipt/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu libsofia-sip-ua/ipt/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-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
+libipt.la: $(libipt_la_OBJECTS) $(libipt_la_DEPENDENCIES)
+ $(LINK) $(libipt_la_LDFLAGS) $(libipt_la_OBJECTS) $(libipt_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
+torture_base64$(EXEEXT): $(torture_base64_OBJECTS) $(torture_base64_DEPENDENCIES)
+ @rm -f torture_base64$(EXEEXT)
+ $(LINK) $(torture_base64_LDFLAGS) $(torture_base64_OBJECTS) $(torture_base64_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/base64.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/string0.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/token64.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/torture_base64.Po at am__quote@
+
+.c.o:
+ at am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+ at am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ at am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at 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: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(include_sofiadir)"; do \
+ test -z "$$dir" || $(mkdir_p) "$$dir"; \
+ done
+install: 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."
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+ 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-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-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-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-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-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) $<
+
+ at ENABLE_COVERAGE_TRUE@coverage:
+ at 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)
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+# 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:
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/base64.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/base64.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,251 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE base64.c
+ *
+ * Implementation of BASE64 encoding and decoding functions.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include "sofia-sip/base64.h"
+
+static unsigned char const code[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+#define B64NOP 128
+#define B64EOF 64
+
+/**Decode a BASE64-encoded string.
+ *
+ * The function base64_d() decodes a string @a b64s encoded with BASE64. It
+ * stores the result in the buffer @a buf of @a bsiz bytes.
+ *
+ * If the @a buf is NULL, the function just returns the length of decoded
+ * data. In any case, no decoded data is stored in @a buf beyond @a bsiz.
+ * The function always returns the full length of decodable data.
+ *
+ * @param buf Buffer to store decoded data
+ * @param bsiz Size of @a buf
+ * @param b64s Base64-encoded string.
+ *
+ * @return Length of data that can be decoded in bytes.
+ *
+ * @sa <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>,
+ * <i>"Multipurpose Internet Mail Extensions (MIME) Part One:
+ * Format of Internet Message Bodies"</i>,
+ * N. Freed, N. Borenstein, November 1996.
+ *
+ * @par Example
+ * The following example code decodes a string of BASE64 data into a
+ * memory area allocated from heap:
+ * @code
+ * int decoder(char const *encoded, void **return_decoded)
+ * {
+ * int len = base64_d(NULL, 0, encoded);
+ * void *decoded = malloc(len);
+ * base64_d(decoded, len, encoded);
+ * *return_decoded = decoded;
+ * return len;
+ * }
+ * @endcode
+ */
+isize_t base64_d(char buf[], isize_t bsiz, char const *b64s)
+{
+ static unsigned char decode[256] = "";
+ unsigned char const *s = (unsigned char const *)b64s;
+ unsigned char c, b1, b2 = B64EOF, b3 = B64EOF, b4 = B64EOF;
+ unsigned long w;
+ isize_t i, len = 0, total_len = 0;
+
+ if (b64s == NULL)
+ return 0;
+
+ if (decode['\0'] != B64EOF) {
+ /* Prepare decoding table */
+ for (i = 1; i < 256; i++)
+ decode[i] = B64NOP;
+
+ for (i = 0; i < 64; i++) {
+ decode[code[i]] = (unsigned char)i;
+ }
+ decode['='] = B64EOF;
+ decode['\0'] = B64EOF;
+ }
+
+ /* Calculate length */
+ while ((c = decode[*s++]) != B64EOF) {
+ if (c != B64NOP)
+ len++;
+ }
+
+ total_len = len = len * 3 / 4;
+
+ if (buf == NULL || bsiz == 0)
+ return total_len;
+
+ if (len > bsiz)
+ len = bsiz;
+
+ for (i = 0, s = (unsigned char const *)b64s; i < len; ) {
+
+ while ((b1 = decode[*s++]) == B64NOP)
+ ;
+ if (b1 != B64EOF)
+ while ((b2 = decode[*s++]) == B64NOP)
+ ;
+ if (b2 != B64EOF)
+ while ((b3 = decode[*s++]) == B64NOP)
+ ;
+ if (b3 != B64EOF)
+ while ((b4 = decode[*s++]) == B64NOP)
+ ;
+
+ if (((b1 | b2 | b3 | b4) & (B64NOP|B64EOF)) == 0) {
+ /* Normal case, 4 B64 chars to 3 data bytes */
+ w = (b1 << 18) | (b2 << 12) | (b3 << 6) | b4;
+ buf[i++] = (unsigned char)(w >> 16);
+ buf[i++] = (unsigned char)(w >> 8);
+ buf[i++] = (unsigned char)(w);
+ continue;
+ }
+ else {
+ /* EOF */
+ if ((b1 | b2) & B64EOF) {
+ /* fputs("base64dec: strange eof ===\n", stderr); */
+ break;
+ }
+ buf[i++] = (b1 << 2) | (b2 >> 4);
+ if (b3 != B64EOF) {
+ buf[i++] = ((b2 & 15) << 4) | ((b3 >> 2) & 15);
+ if (b4 != B64EOF) {
+ buf[i++] = ((b3 & 3) << 6) | b4;
+ }
+ }
+ break;
+ }
+ }
+
+#if 0
+ printf("base64_d returns, decoded %d bytes\n", total_len);
+ for (i = 0; i < len; i++)
+ printf("%02x", buf[i]);
+ printf("\n");
+#endif
+
+ return total_len;
+}
+
+/**Encode data with BASE64.
+ *
+ * The function base64_e() encodes @a dsiz bytes of @a data into @a buf.
+ *
+ * @note The function base64_e() uses at most @a bsiz bytes from @a buf.
+ *
+ * If @a bsiz is zero, the function just returns the length of BASE64
+ * encoding, excluding the final @c NUL.
+ *
+ * If encoded string is longer than that @a bsiz, the function terminates
+ * string with @c NUL at @a buf[bsiz-1], but returns the length of encoding as
+ * usual.
+ *
+ * @param buf buffer for encoded data
+ * @param bsiz size of @a buffer
+ * @param data data to be encoded
+ * @param dsiz size of @a data
+ *
+ * @return The function base64_e() return length of encoded string,
+ * excluding the final NUL.
+ *
+ * @sa <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>,
+ * <i>"Multipurpose Internet Mail Extensions (MIME) Part One:
+ * Format of Internet Message Bodies"</i>,
+ * N. Freed, N. Borenstein, November 1996.
+ *
+ */
+isize_t base64_e(char buf[], isize_t bsiz, void *data, isize_t dsiz)
+{
+ unsigned char *s = (unsigned char *)buf;
+ unsigned char *b = (unsigned char *)data;
+ unsigned long w;
+
+ isize_t i, n, slack = (unsigned)dsiz % 3;
+ isize_t dsize = dsiz - slack, bsize = bsiz;
+
+ if (bsize == 0)
+ s = NULL;
+
+ for (i = 0, n = 0; i < dsize; i += 3, n += 4) {
+ w = (b[i] << 16) | (b[i+1] << 8) | b[i+2];
+
+ if (s) {
+ if (n + 4 < bsize) {
+ s[n + 0] = code[(w >> 18) & 63];
+ s[n + 1] = code[(w >> 12) & 63];
+ s[n + 2] = code[(w >> 6) & 63];
+ s[n + 3] = code[(w) & 63];
+ } else {
+ if (n + 1 < bsize)
+ s[n + 0] = code[(w >> 18) & 63];
+ if (n + 2 < bsize)
+ s[n + 1] = code[(w >> 12) & 63];
+ if (n + 3 < bsize)
+ s[n + 2] = code[(w >> 6) & 63];
+ s[bsize - 1] = '\0';
+ s = NULL;
+ }
+ }
+ }
+
+ if (slack) {
+ if (s) {
+ if (slack == 2)
+ w = (b[i] << 16) | (b[i+1] << 8);
+ else
+ w = (b[i] << 16);
+
+ if (n + 1 < bsize)
+ s[n + 0] = code[(w >> 18) & 63];
+ if (n + 2 < bsize)
+ s[n + 1] = code[(w >> 12) & 63];
+ if (n + 3 < bsize)
+ s[n + 2] = (slack == 2) ? code[(w >> 6) & 63] : '=';
+ if (n + 3 < bsize)
+ s[n + 3] = '=';
+ if (n + 4 >= bsize)
+ s[bsize - 1] = '\0', s = NULL;
+ }
+ n += 4;
+ }
+
+ if (s)
+ s[n] = '\0';
+
+ return n;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/ipt.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/ipt.docs Thu Dec 21 01:30:28 2006
@@ -0,0 +1,23 @@
+/* -*- c -*- */
+
+/**@MODULEPAGE "ipt" - Utility Module
+ *
+ * @section ipt_meta Module Meta Information
+ *
+ * Utility library for IP Telephony applications.
+ *
+ * @CONTACT Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @STATUS @SofiaSIP Core library
+ *
+ * @LICENSE LGPL
+ *
+ * @section ipt_overview Overview
+ *
+ * This module contain some routines useful for IPT applications, like
+ * - base64.h BASE64 encoding/decoding,
+ * - token64.h encoding/decoding binary as SIP/HTTP token,
+ * - utf8.h UTF8 encoding/decoding,
+ * - sha1.h SHA1 hash routines, and
+ * - rc4.h arcfour random number generator.
+ */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/rc4.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/rc4.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,264 @@
+/**@CFILE rc4.c Arcfour pseudorandom generator.
+ *
+ * @author Pekka Pessi <ppessi at hut.fi>
+ *
+ * Copyright (c) 1996 Pekka Pessi. All rights reserved.
+ *
+ * This source code is provided for unrestricted use. Users may copy or
+ * modify this source code without charge.
+ *
+ * THIS SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND
+ * INCLUDING THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE
+ * PRACTICE.
+ *
+ * This source code is provided with no support and without any obligation
+ * on the part of author to assist in its use, correction, modification or
+ * enhancement.
+ *
+ * AUTHOR SHALL HAVE NO LIABILITY WITH RESPECT TO THE INFRINGEMENT OF
+ * COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE OR ANY PART
+ * THEREOF.
+ *
+ * In no event will author be liable for any lost revenue or profits or
+ * other special, indirect and consequential damages, even if author has
+ * been advised of the possibility of such damages.
+ *
+ * @date Created: Sun Jun 9 12:43:17 1996 ppessi
+ */
+
+#include "config.h"
+
+#include "sofia-sip/rc4.h"
+
+void rc4_init(const void *vseed, isize_t seed_len, rc4_t *state) {
+ short i; rc4_u8 j; rc4_u8 k;
+
+ const rc4_u8 *seed = (const rc4_u8 *)vseed;
+ rc4_u8 *array = state->rc4_array;
+
+ state->rc4_i = 0;
+ state->rc4_j = 0;
+
+ for (i = 0; i < 256; i++)
+ array[i] = (rc4_u8) i;
+
+ for (i = 0, j = 0, k = 0;
+ i < 256;
+ i++, k++, k >= seed_len ? k = 0 : 0) {
+ rc4_u8 a = array[i];
+ rc4_u8 b = array[j += a + seed[k]];
+
+ array[i] = b;
+ array[j] = a;
+ }
+}
+
+void rc4(void *buffer, isize_t len, rc4_t *state) {
+ rc4_u8 *buf = (rc4_u8 *)buffer;
+ rc4_u8 *array = state->rc4_array;
+ rc4_u8 i = state->rc4_i;
+ rc4_u8 j = state->rc4_j;
+
+ while (len-- > 0) {
+ rc4_u8 a = array[++i];
+ rc4_u8 b = array[j += a];
+
+ array[i] = b;
+ array[j] = a;
+
+ *buf++ ^= array[(a + b) & 255];
+ }
+
+ state->rc4_i = i;
+ state->rc4_j = j;
+}
+
+#ifdef RC4_TESTING
+
+rc4_u8 key_0[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
+rc4_u8 input_0[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef };
+rc4_u8 output_0[] = { 0x75, 0xb7, 0x87, 0x80, 0x99, 0xe0, 0xc5, 0x96 };
+
+rc4_u8 key_1[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, };
+rc4_u8 input_1[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
+rc4_u8 output_1[] = { 0x74, 0x94, 0xc2, 0xe7, 0x10, 0x4b, 0x08, 0x79, };
+
+rc4_u8 key_2[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
+rc4_u8 input_2[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
+rc4_u8 output_2[] = { 0xde, 0x18, 0x89, 0x41, 0xa3, 0x37, 0x5d, 0x3a, };
+
+rc4_u8 key_3[] = { 0xef, 0x01, 0x23, 0x45, };
+rc4_u8 input_3[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
+rc4_u8 output_3[] = { 0xd6, 0xa1, 0x41, 0xa7, 0xec, 0x3c, 0x38, 0xdf, 0xbd, 0x61, };
+rc4_u8 key_4[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, };
+rc4_u8 input_4[] = {
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, };
+
+rc4_u8 output_4[] = {
+ 0x75, 0x95, 0xc3, 0xe6, 0x11, 0x4a, 0x09, 0x78, 0x0c, 0x4a, 0xd4,
+ 0x52, 0x33, 0x8e, 0x1f, 0xfd, 0x9a, 0x1b, 0xe9, 0x49, 0x8f,
+ 0x81, 0x3d, 0x76, 0x53, 0x34, 0x49, 0xb6, 0x77, 0x8d, 0xca,
+ 0xd8, 0xc7, 0x8a, 0x8d, 0x2b, 0xa9, 0xac, 0x66, 0x08, 0x5d,
+ 0x0e, 0x53, 0xd5, 0x9c, 0x26, 0xc2, 0xd1, 0xc4, 0x90, 0xc1,
+ 0xeb, 0xbe, 0x0c, 0xe6, 0x6d, 0x1b, 0x6b, 0x1b, 0x13, 0xb6,
+ 0xb9, 0x19, 0xb8, 0x47, 0xc2, 0x5a, 0x91, 0x44, 0x7a, 0x95,
+ 0xe7, 0x5e, 0x4e, 0xf1, 0x67, 0x79, 0xcd, 0xe8, 0xbf, 0x0a,
+ 0x95, 0x85, 0x0e, 0x32, 0xaf, 0x96, 0x89, 0x44, 0x4f, 0xd3,
+ 0x77, 0x10, 0x8f, 0x98, 0xfd, 0xcb, 0xd4, 0xe7, 0x26, 0x56,
+ 0x75, 0x00, 0x99, 0x0b, 0xcc, 0x7e, 0x0c, 0xa3, 0xc4, 0xaa,
+ 0xa3, 0x04, 0xa3, 0x87, 0xd2, 0x0f, 0x3b, 0x8f, 0xbb, 0xcd,
+ 0x42, 0xa1, 0xbd, 0x31, 0x1d, 0x7a, 0x43, 0x03, 0xdd, 0xa5,
+ 0xab, 0x07, 0x88, 0x96, 0xae, 0x80, 0xc1, 0x8b, 0x0a, 0xf6,
+ 0x6d, 0xff, 0x31, 0x96, 0x16, 0xeb, 0x78, 0x4e, 0x49, 0x5a,
+ 0xd2, 0xce, 0x90, 0xd7, 0xf7, 0x72, 0xa8, 0x17, 0x47, 0xb6,
+ 0x5f, 0x62, 0x09, 0x3b, 0x1e, 0x0d, 0xb9, 0xe5, 0xba, 0x53,
+ 0x2f, 0xaf, 0xec, 0x47, 0x50, 0x83, 0x23, 0xe6, 0x71, 0x32,
+ 0x7d, 0xf9, 0x44, 0x44, 0x32, 0xcb, 0x73, 0x67, 0xce, 0xc8,
+ 0x2f, 0x5d, 0x44, 0xc0, 0xd0, 0x0b, 0x67, 0xd6, 0x50, 0xa0,
+ 0x75, 0xcd, 0x4b, 0x70, 0xde, 0xdd, 0x77, 0xeb, 0x9b, 0x10,
+ 0x23, 0x1b, 0x6b, 0x5b, 0x74, 0x13, 0x47, 0x39, 0x6d, 0x62,
+ 0x89, 0x74, 0x21, 0xd4, 0x3d, 0xf9, 0xb4, 0x2e, 0x44, 0x6e,
+ 0x35, 0x8e, 0x9c, 0x11, 0xa9, 0xb2, 0x18, 0x4e, 0xcb, 0xef,
+ 0x0c, 0xd8, 0xe7, 0xa8, 0x77, 0xef, 0x96, 0x8f, 0x13, 0x90,
+ 0xec, 0x9b, 0x3d, 0x35, 0xa5, 0x58, 0x5c, 0xb0, 0x09, 0x29,
+ 0x0e, 0x2f, 0xcd, 0xe7, 0xb5, 0xec, 0x66, 0xd9, 0x08, 0x4b,
+ 0xe4, 0x40, 0x55, 0xa6, 0x19, 0xd9, 0xdd, 0x7f, 0xc3, 0x16,
+ 0x6f, 0x94, 0x87, 0xf7, 0xcb, 0x27, 0x29, 0x12, 0x42, 0x64,
+ 0x45, 0x99, 0x85, 0x14, 0xc1, 0x5d, 0x53, 0xa1, 0x8c, 0x86,
+ 0x4c, 0xe3, 0xa2, 0xb7, 0x55, 0x57, 0x93, 0x98, 0x81, 0x26,
+ 0x52, 0x0e, 0xac, 0xf2, 0xe3, 0x06, 0x6e, 0x23, 0x0c, 0x91,
+ 0xbe, 0xe4, 0xdd, 0x53, 0x04, 0xf5, 0xfd, 0x04, 0x05, 0xb3,
+ 0x5b, 0xd9, 0x9c, 0x73, 0x13, 0x5d, 0x3d, 0x9b, 0xc3, 0x35,
+ 0xee, 0x04, 0x9e, 0xf6, 0x9b, 0x38, 0x67, 0xbf, 0x2d, 0x7b,
+ 0xd1, 0xea, 0xa5, 0x95, 0xd8, 0xbf, 0xc0, 0x06, 0x6f, 0xf8,
+ 0xd3, 0x15, 0x09, 0xeb, 0x0c, 0x6c, 0xaa, 0x00, 0x6c, 0x80,
+ 0x7a, 0x62, 0x3e, 0xf8, 0x4c, 0x3d, 0x33, 0xc1, 0x95, 0xd2,
+ 0x3e, 0xe3, 0x20, 0xc4, 0x0d, 0xe0, 0x55, 0x81, 0x57, 0xc8,
+ 0x22, 0xd4, 0xb8, 0xc5, 0x69, 0xd8, 0x49, 0xae, 0xd5, 0x9d,
+ 0x4e, 0x0f, 0xd7, 0xf3, 0x79, 0x58, 0x6b, 0x4b, 0x7f, 0xf6,
+ 0x84, 0xed, 0x6a, 0x18, 0x9f, 0x74, 0x86, 0xd4, 0x9b, 0x9c,
+ 0x4b, 0xad, 0x9b, 0xa2, 0x4b, 0x96, 0xab, 0xf9, 0x24, 0x37,
+ 0x2c, 0x8a, 0x8f, 0xff, 0xb1, 0x0d, 0x55, 0x35, 0x49, 0x00,
+ 0xa7, 0x7a, 0x3d, 0xb5, 0xf2, 0x05, 0xe1, 0xb9, 0x9f, 0xcd,
+ 0x86, 0x60, 0x86, 0x3a, 0x15, 0x9a, 0xd4, 0xab, 0xe4, 0x0f,
+ 0xa4, 0x89, 0x34, 0x16, 0x3d, 0xdd, 0xe5, 0x42, 0xa6, 0x58,
+ 0x55, 0x40, 0xfd, 0x68, 0x3c, 0xbf, 0xd8, 0xc0, 0x0f, 0x12,
+ 0x12, 0x9a, 0x28, 0x4d, 0xea, 0xcc, 0x4c, 0xde, 0xfe, 0x58,
+ 0xbe, 0x71, 0x37, 0x54, 0x1c, 0x04, 0x71, 0x26, 0xc8, 0xd4,
+ 0x9e, 0x27, 0x55, 0xab, 0x18, 0x1a, 0xb7, 0xe9, 0x40, 0xb0,
+ 0xc0, };
+
+#include <stdio.h>
+
+void printout(const char *title, rc4_u8 *data, int len) {
+ int i;
+
+ puts(title);
+
+ for (i = 0; i < len; i++) {
+ printf("0x%02x ", data[i]);
+ }
+
+ putchar('\n');
+}
+
+int main() {
+ int failed = 0;
+
+ rc4_t state[1];
+
+ rc4_init(key_0, sizeof key_0, state);
+ rc4(input_0, sizeof input_0, state);
+ if (memcmp(input_0, output_0, sizeof input_0)) {
+ printout("Test 0 output", input_0, sizeof input_0);
+ failed = 1;
+ }
+
+ if (!failed) {
+ puts("RC4 seems to work\n");
+ }
+
+ rc4_prepare_key(key_1, sizeof key_1, state);
+ rc4(input_1, sizeof input_1, state);
+ if (memcmp(input_1, output_1, sizeof input_1)) {
+ printout("Test 1 output", input_1, sizeof input_1);
+ failed = 1;
+ }
+
+ rc4_prepare_key(key_2, sizeof key_2, state);
+ rc4(input_2, sizeof input_2, state);
+ if (memcmp(input_2, output_2, sizeof input_2)) {
+ printout("Test 2 output", input_2, sizeof input_2);
+ failed = 1;
+ }
+
+ rc4_prepare_key(key_3, sizeof key_3, state);
+ rc4(input_3, sizeof input_3, state);
+ if (memcmp(input_3, output_3, sizeof input_3)) {
+ printout("Test 3 output", input_3, sizeof input_3);
+ failed = 1;
+ }
+
+ rc4_prepare_key(key_4, sizeof key_4, state);
+ rc4(input_4, sizeof input_4, state);
+ if (memcmp(input_4, output_4, sizeof input_4)) {
+ printout("Test 4 output", input_4, sizeof input_4);
+ failed = 1;
+ }
+
+ exit(failed);
+}
+
+#endif
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/base64.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/base64.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,62 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef BASE64_H
+#define BASE64_H
+
+/**@file sofia-sip/base64.h
+ *
+ * @brief Base64 encoding and decoding functions.
+ *
+ * This module contains base64 encoding and decoding functions. Base64
+ * encodes arbitrary octet strings as strings containing characters @c
+ * [A-Za-z0-9+/=]. Base64 is defined as part of MIME mail format, but it is
+ * used widely by other text-based protocols as well.
+ *
+ * @sa <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>,
+ * <i>"Multipurpose Internet Mail Extensions (MIME) Part One:
+ * Format of Internet Message Bodies"</i>,
+ * N. Freed, N. Borenstein,
+ * November 1996.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ */
+
+#ifndef SU_TYPES_H
+#include <sofia-sip/su_types.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** Decode a BASE64-encoded string. */
+SOFIAPUBFUN isize_t base64_d(char buf[], isize_t bsiz, char const *b64s);
+/** Encode data with BASE64. */
+SOFIAPUBFUN isize_t base64_e(char buf[], isize_t bsiz, void *data, isize_t dsiz);
+
+/** Calculate size of n bytes encoded in base64 */
+#define BASE64_SIZE(n) ((((n) + 2) / 3) * 4)
+
+SOFIA_END_DECLS
+
+#endif /* !BASE_64 */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/rc4.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/rc4.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,69 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef RC4_H
+/** Defined when <sofia-sip/rc4.h> has been included. */
+#define RC4_H
+
+/**@file sofia-sip/rc4.h
+ * @brief Arcfour random number generator.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Sun Jun 9 14:32:58 1996 ppessi
+ */
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#ifndef SU_TYPES_H
+#include <sofia-sip/su_types.h>
+#endif
+
+/** Byte. */
+typedef uint8_t rc4_u8;
+
+/** RC4 context.
+ *
+ * The RC4 context is accessed and modified through rc4_init() and rc4()
+ * functions only.
+ */
+typedef struct {
+ uint8_t rc4_i;
+ uint8_t rc4_j;
+ uint8_t rc4_array[256];
+} rc4_t;
+
+/** Key RC4 context. */
+SOFIAPUBFUN void rc4_init(const void *seed, isize_t seed_len, rc4_t *state);
+
+/** Generate RC4 stream. */
+SOFIAPUBFUN void rc4(void *buffer, isize_t len, rc4_t *state);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* !defined RC4_H */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/string0.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/string0.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,162 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef STRING0_H
+/** Defined when <sofia-sip/string0.h> is included. */
+#define STRING0_H
+
+/**@file sofia-sip/string0.h
+ *
+ * @brief String comparison functions accepting NULL pointers
+ *
+ * This module contains string comparison functions that can be called
+ * with NULL pointer as argument.
+ *
+ */
+
+#ifndef SU_CONFIG_H
+#include <sofia-sip/su_config.h>
+#endif
+
+#include <string.h>
+
+SOFIA_BEGIN_DECLS
+
+#if SU_HAVE_INLINE
+su_inline
+#else
+SOFIAPUBFUN
+#endif
+int
+ str0cmp(char const *a, char const *b),
+ str0ncmp(char const *a, char const *b, size_t n),
+ str0casecmp(char const *a, char const *b),
+ str0ncasecmp(char const *a, char const *b, size_t n);
+
+#if SU_HAVE_INLINE
+su_inline
+#else
+SOFIAPUBFUN
+#endif
+size_t
+strnspn(char const *s, size_t size, char const *term),
+ strncspn(char const *s, size_t ssize, char const *reject);
+
+#if SU_HAVE_INLINE
+int str0cmp(char const *a, char const *b)
+{
+ if (a == NULL) a = "";
+ if (b == NULL) b = "";
+ return strcmp(a, b);
+}
+
+int str0ncmp(char const *a, char const *b, size_t n)
+{
+ if (a == NULL) a = "";
+ if (b == NULL) b = "";
+ return strncmp(a, b, n);
+}
+
+int str0casecmp(char const *a, char const *b)
+{
+ if (a == NULL) a = "";
+ if (b == NULL) b = "";
+ return strcasecmp(a, b);
+}
+
+int str0ncasecmp(char const *a, char const *b, size_t n)
+{
+ if (a == NULL) a = "";
+ if (b == NULL) b = "";
+ return strncasecmp(a, b, n);
+}
+
+size_t strnspn(char const *s, size_t ssize, char const *term)
+{
+ size_t n;
+ size_t tsize = strlen(term);
+
+ if (tsize == 0) {
+ return 0;
+ }
+ else if (tsize == 1) {
+ char c, t = term[0];
+ for (n = 0; n < ssize && (c = s[n]) && c == t; n++)
+ ;
+ }
+ else if (tsize == 2) {
+ char c, t1 = term[0], t2 = term[1];
+ for (n = 0; n < ssize && (c = s[n]) && (c == t1 || c == t2); n++)
+ ;
+ }
+ else {
+ size_t i;
+ char c, t1 = term[0], t2 = term[1];
+ for (n = 0; n < ssize && (c = s[n]) && (c == t1 || c == t2); n++) {
+ for (i = 2; i < tsize; i++)
+ if (c == term[i])
+ return n;
+ }
+ }
+
+ return n;
+}
+
+size_t strncspn(char const *s, size_t ssize, char const *reject)
+{
+ size_t n;
+ size_t rsize = strlen(reject);
+
+ if (rsize == 0) {
+ for (n = 0; n < ssize && s[n]; n++)
+ ;
+ }
+ else if (rsize == 1) {
+ char c, rej = reject[0];
+ for (n = 0; n < ssize && (c = s[n]) && c != rej; n++)
+ ;
+ }
+ else if (rsize == 2) {
+ char c, rej1 = reject[0], rej2 = reject[1];
+ for (n = 0; n < ssize && (c = s[n]) && c != rej1 && c != rej2; n++)
+ ;
+ }
+ else {
+ size_t i;
+ char c, rej1 = reject[0], rej2 = reject[1];
+ for (n = 0; n < ssize && (c = s[n]) && c != rej1 && c != rej2; n++) {
+ for (i = 2; i < rsize; i++)
+ if (c == reject[i])
+ return n;
+ }
+ }
+
+ return n;
+}
+
+#endif
+
+SOFIA_END_DECLS
+
+#endif /* !STRING0_H */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/token64.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/token64.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,52 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef TOKEN64_H
+#define TOKEN64_H
+
+/**@file sofia-sip/token64.h
+ *
+ * @brief Token64 encoding.
+ *
+ * This module contains token64 encoding functions. Token64 encodes
+ * arbitrary octet strings as http header tokens containing only characters
+ * in range @c [-+A-Za-z0-9].
+ *
+ */
+
+#ifndef SU_TYPES_H
+#include <sofia-sip/su_types.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+SOFIAPUBFUN isize_t token64_e(char b[], isize_t bsiz,
+ void const *data, isize_t dlen);
+
+/** Calculate size of n bytes encoded in token-64 */
+#define TOKEN64_SIZE(n) (((n + 2) / 3) * 4)
+
+SOFIA_END_DECLS
+
+#endif /* !TOKEN64_H */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/uniqueid.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/uniqueid.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,51 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef UNIQUEID_H
+/** Defined when <sofia-sip/uniqueid.h> has been included. */
+#define UNIQUEID_H
+
+/**@file sofia-sip/uniqueid.h
+ *
+ * Compatibility functions to handle GloballyUniqueID.
+ *
+ * This file just includes <su_uniqueid.h>.
+ *
+ * @author Pekka Pessi <pessi at research.nokia.com>
+ *
+ * @date Created: Tue Apr 15 06:31:41 1997 pessi
+ */
+
+/* Compatibility functionality */
+#define guid_t su_guid_t
+#define guid_generate su_guid_generate
+#define guid_sprintf su_guid_sprintf
+#define guid_strlen su_guid_strlen
+#define randint su_randint
+#define randmem su_randmem
+
+#include <sofia-sip/su_uniqueid.h>
+
+
+#endif
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/utf8.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/utf8.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,178 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@file sofia-sip/utf8.h
+ * Encoding/Decoding Functions for UCS Transformation Format UTF-8.
+ *
+ * UTF-8 encoding codes the ISO 10646 (Unicode, UCS2 and UCS4) characters as
+ * variable length (1 - 6 bytes) strings of 8-bit characters.
+ *
+ * @author Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * @date Created: Tue Apr 21 15:32:38 1998 pessi
+
+ * @sa <a href="ftp://ftp.ietf.org/rfc/rfc2279.txt">RFC 2279</a>,
+ * <i>"UTF-8, a transformation format of ISO 10646"</i>,
+ * F. Yergeau. January 1998.
+ *
+ */
+
+#ifndef UTF8_H
+/** Defined when <sofia-sip/utf8.h> has been included */
+#define UTF8_H
+
+#ifndef SU_TYPES_H
+#include <sofia-sip/su_types.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+typedef unsigned char utf8;
+typedef unsigned short utf16;
+typedef unsigned char ucs1;
+typedef unsigned short ucs2;
+typedef unsigned int ucs4;
+
+SOFIAPUBFUN size_t utf8_width(const utf8 *);
+
+/* Latin-1 encoding/decoding */
+SOFIAPUBFUN size_t ucs18decode(char *dst, size_t dst_size, const utf8 *s);
+SOFIAPUBFUN size_t ucs1encode(utf8 *dst, const ucs1 *s, size_t n,
+ const char quote[128]);
+SOFIAPUBFUN size_t ucs1declen(const utf8 *s);
+SOFIAPUBFUN size_t ucs1enclen(const ucs1 *s, size_t n, const char quote[128]);
+
+/* UCS2 (BMP) encoding/decoding */
+size_t ucs2decode(ucs2 *dst, size_t dst_size, const utf8 *s);
+size_t ucs2encode(utf8 *dst, const ucs2 *s, size_t n, const char quote[128]);
+size_t ucs2declen(const utf8 *s);
+size_t ucs2enclen(const ucs2 *s, size_t n, const char quote[128]);
+
+size_t ucs4decode(ucs4 *dst, size_t dst_size, const utf8 *s);
+size_t ucs4encode(utf8 *dst, const ucs4 *s, size_t n, const char quote[128]);
+size_t ucs4declen(const utf8 *s);
+size_t ucs4enclen(const ucs4 *s, size_t n, const char quote[128]);
+
+size_t ucs2len(ucs2 const *s);
+int ucs2cmp(ucs2 const *s1, ucs2 const *s2);
+int ucs2ncmp(ucs2 const *s1, ucs2 const *s2, size_t n);
+
+size_t ucs4len(ucs4 const *s);
+int ucs4cmp(ucs4 const *s1, ucs4 const *s2);
+int ucs4ncmp(ucs4 const *s1, ucs4 const *s2, size_t n);
+
+/*
+ * IS_UCS4_n tests whether UCS4 character should be represented
+ * with 'n' byte utf8 string
+ */
+#define IS_UCS4_1(x) ((ucs4)(x) <= 0x7fu)
+#define IS_UCS4_2(x) (0x80u <= (ucs4)(x) && (ucs4)(x) <= 0x7ffu)
+#define IS_UCS4_3(x) (0x800u <= (ucs4)(x) && (ucs4)(x) <= 0xffffu)
+#define IS_UCS4_4(x) (0x10000u <= (ucs4)(x) && (ucs4)(x) <= 0x1fFFFFu)
+#define IS_UCS4_5(x) (0x200000u <= (ucs4)(x) && (ucs4)(x) <= 0x3ffFFFFu)
+#define IS_UCS4_6(x) (0x4000000u <= (ucs4)(x) && (ucs4)(x) <= 0x7fffFFFFu)
+
+/* Special test for ISO-8859-1 characters */
+#define IS_UCS4_I(x) (0x80u <= (ucs4)(x) && (ucs4)(x) <= 0xffu)
+
+/* Length of an UCS4 character in UTF8 encoding */
+#define UTF8_LEN4(x) (IS_UCS4_1(x) || IS_UCS4_2(x) && 2 || \
+ IS_UCS4_3(x) && 3 || IS_UCS4_4(x) && 4 || \
+ IS_UCS4_5(x) && 5 || IS_UCS4_6(x) && 6)
+
+/* Length of an UCS2 character in UTF8 encoding */
+#define UTF8_LEN2(x) (IS_UCS4_1(x) || IS_UCS4_2(x) && 2 || IS_UCS4_3(x) && 3)
+
+/*
+ * IS_UTF8_n tests the length of the next wide character
+ */
+#define IS_UTF8_1(c) (0x00 == ((c) & 0x80))
+#define IS_UTF8_2(c) (0xc0 == ((c) & 0xe0))
+#define IS_UTF8_3(c) (0xe0 == ((c) & 0xf0))
+#define IS_UTF8_4(c) (0xf0 == ((c) & 0xf8))
+#define IS_UTF8_5(c) (0xf8 == ((c) & 0xfc))
+#define IS_UTF8_6(c) (0xfc == ((c) & 0xfe))
+
+/* Extension byte? */
+#define IS_UTF8_X(c) (0x80 == ((c) & 0xc0))
+/* ISO-8859-1 character? */
+#define IS_UTF8_I(c) (0xc0 == ((c) & 0xfc))
+
+#define IS_UTF8_S1(s) \
+(IS_UTF8_1(s[0]))
+#define IS_UTF8_S2(s) \
+(IS_UTF8_2(s[0])&&((s)[1]&192)==128)
+#define IS_UTF8_SI(s) \
+(IS_UTF8_I(s[0])&&((s)[1]&192)==128)
+#define IS_UTF8_S3(s) \
+(IS_UTF8_3(s[0])&& ((s)[1]&192)==128&&((s)[2]&192)==128)
+#define IS_UTF8_S4(s) \
+(IS_UTF8_4(s[0])&& ((s)[1]&192)==128&&((s)[2]&192)==128&&((s)[3]&192)==128)
+#define IS_UTF8_S5(s) \
+(IS_UTF8_5(s[0])&& ((s)[1]&192)==128&&((s)[2]&192)==128&&\
+ ((s)[3]&192)==128&&((s)[4]&192)==128)
+#define IS_UTF8_S6(s) \
+(IS_UTF8_6(s[0])&& ((s)[1]&192)==128&&((s)[2]&192)==128&&((s)[3]&192)==128&&\
+ ((s)[4]&192)==128&&((s)[5]&192)==128)
+
+#define UCS4_S1(s) ((ucs4)(s[0]))
+#define UCS4_S2(s) ((ucs4)\
+ (((s[0])&31)<<6)|((s[1])&63))
+#define UCS4_S3(s) ((ucs4)\
+ (((s[0])&15)<<12)|(((s[1])&63)<<6)|((s[2])&63))
+#define UCS4_S4(s) ((ucs4)\
+ (((s[0])&7)<<18)|(((s[1])&63)<<12)|(((s[2])&63)<<6)|\
+ ((s[3])&63))
+#define UCS4_S5(s) ((ucs4)\
+ (((s[0])&3)<<24)|(((s[1])&63)<<18)|(((s[2])&63)<<12)|\
+ (((s[3])&63)<<6)|((s[4])&63))
+#define UCS4_S6(s) ((ucs4)\
+ (((s[0])&1)<<30)|(((s[1])&63)<<24)|(((s[2])&63)<<18)|\
+ (((s[3])&63)<<12)|(((s[4])&63)<<6)|((s[5])&63))
+
+#define UTF8_S1(s,c) ((s)[0]=(c))
+#define UTF8_S2(s,c) ((s)[0]=(((c)>>6)&31)|0xc0,\
+ (s)[1]=((c)&63)|128)
+#define UTF8_S3(s,c) ((s)[0]=(((c)>>12)&15)|0xe0,\
+ (s)[1]=((c>>6)&63)|128,\
+ (s)[2]=((c)&63)|128)
+#define UTF8_S4(s,c) ((s)[0]=(((c)>>18)&7)|0xf0,\
+ (s)[1]=((c>>12)&63)|128,\
+ (s)[2]=((c>>6)&63)|128,\
+ (s)[3]=((c)&63)|128)
+#define UTF8_S5(s,c) ((s)[0]=(((c)>>24)&3)|0xf8,\
+ (s)[1]=((c>>18)&63)|128,\
+ (s)[2]=((c>>12)&63)|128,\
+ (s)[3]=((c>>6)&63)|128,\
+ (s)[4]=((c)&63)|128)
+#define UTF8_S6(s,c) ((s)[0]=(((c)>>30)&1)|0xfc,\
+ (s)[1]=((c>>24)&63)|128,\
+ (s)[2]=((c>>18)&63)|128,\
+ (s)[3]=((c>>12)&63)|128,\
+ (s)[4]=((c>>6)&63)|128,\
+ (s)[5]=((c)&63)|128)
+
+SOFIA_END_DECLS
+
+#endif /* UTF8_H */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/string0.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/string0.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,42 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE string0.c
+ *
+ * Expand string0 functions non-inline.
+ *
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <sofia-sip/su_config.h>
+
+#undef SU_HAVE_INLINE
+#undef su_inline
+
+#define SU_HAVE_INLINE 1
+#define su_inline
+
+#include "sofia-sip/string0.h"
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/token64.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/token64.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,102 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE token64.c
+ *
+ * Token encoding.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Apr 3 10:45:47 2002 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <assert.h>
+
+#include "sofia-sip/token64.h"
+
+static const char code[65] =
+"0123456789-abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+/** Encode data as an http token.
+ *
+ * @note
+ * A token is case-independent, so this is really not a good idea.
+ * Use msg_random_token() instead.
+ */
+isize_t token64_e(char b[], isize_t bsiz, void const *data, isize_t dlen)
+{
+ size_t i, n, slack;
+ unsigned char const *h = data;
+ char *s = b, *end = b + bsiz;
+ long w;
+
+ if (dlen <= 0) {
+ if (bsiz && b) *b = '\0';
+ return 0;
+ }
+
+ n = (8 * dlen + 5) / 6;
+ if (bsiz == 0 || b == NULL)
+ return n;
+
+ if (b + n >= end)
+ dlen = 6 * bsiz / 8;
+ else
+ end = b + n + 1;
+
+ slack = dlen % 3;
+ dlen -= slack;
+
+ for (i = 0; i < dlen; i += 3, s += 4) {
+ unsigned char h0 = h[i], h1 = h[i + 1], h2 = h[i + 2];
+
+ s[0] = code[h0 >> 2];
+ s[1] = code[((h0 << 4)|(h1 >> 4)) & 63];
+ s[2] = code[((h1 << 4)|(h2 >> 6)) & 63];
+ s[3] = code[(h2) & 63];
+ }
+
+ if (slack) {
+ if (slack == 2)
+ w = (h[i] << 16) | (h[i+1] << 8);
+ else
+ w = (h[i] << 16);
+
+ if (s < end) *s++ = code[(w >> 18) & 63];
+ if (s < end) *s++ = code[(w >> 12) & 63];
+ if (s < end && slack == 2) *s++ = code[(w >> 6) & 63];
+ }
+
+ if (s < end)
+ *s++ = '\0';
+ else
+ end[-1] = '\0';
+
+ assert(end == s);
+
+ return n;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/torture_base64.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/torture_base64.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,187 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**
+ * @file torture_base64.c
+ * @brief Test BASE64 encoding/decoding
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com> \n
+ *
+ * @date Created: Tue Feb 1 13:29:09 EET 2005 ppessi
+ *
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "sofia-sip/base64.h"
+
+int tstflags = 0;
+#define TSTFLAGS tstflags
+
+char const *name = "torture_base64";
+
+#include <sofia-sip/tstdef.h>
+
+char const constant[] = "not changed";
+
+int test_encoding(void)
+{
+ char buffer[32];
+
+ BEGIN();
+
+ TEST_SIZE(base64_e(buffer, sizeof buffer, "\0\020\203", 3), 4);
+ TEST_S(buffer, "ABCD");
+
+ strcpy(buffer + 5, "not changed");
+ TEST_SIZE(base64_e(buffer, 5, "\0\020\203", 3), 4);
+ TEST_S(buffer + 5, "not changed");
+ TEST_S(buffer, "ABCD");
+
+ strcpy(buffer + 4, "not changed");
+ TEST_SIZE(base64_e(buffer, 4, "\0\020\203", 3), 4);
+ TEST_S(buffer + 4, "not changed");
+ TEST_S(buffer, "ABC");
+
+ strcpy(buffer + 3, "not changed");
+ TEST_SIZE(base64_e(buffer, 3, "\0\020\203", 3), 4);
+ TEST_S(buffer + 3, "not changed");
+ TEST_S(buffer, "AB");
+
+ strcpy(buffer + 2, "not changed");
+ TEST_SIZE(base64_e(buffer, 2, "\0\020\203", 3), 4);
+ TEST_S(buffer + 2, "not changed");
+ TEST_S(buffer, "A");
+
+ strcpy(buffer + 1, "not changed");
+ TEST_SIZE(base64_e(buffer, 1, "\0\020\203", 3), 4);
+ TEST_S(buffer + 1, "not changed");
+ TEST_S(buffer, "");
+
+ strcpy(buffer + 5, "not changed");
+ TEST_SIZE(base64_e(buffer, 5, "\0\020", 2), 4);
+ TEST_S(buffer + 5, "not changed");
+ TEST_S(buffer, "ABA=");
+
+ strcpy(buffer + 4, "not changed");
+ TEST_SIZE(base64_e(buffer, 4, "\0\020", 2), 4);
+ TEST_S(buffer + 4, "not changed");
+ TEST_S(buffer, "ABA");
+
+ strcpy(buffer + 3, "not changed");
+ TEST_SIZE(base64_e(buffer, 3, "\0\020", 2), 4);
+ TEST_S(buffer + 3, "not changed");
+ TEST_S(buffer, "AB");
+
+ strcpy(buffer + 2, "not changed");
+ TEST_SIZE(base64_e(buffer, 2, "\0\020", 2), 4);
+ TEST_S(buffer + 2, "not changed");
+ TEST_S(buffer, "A");
+
+ strcpy(buffer + 1, "not changed");
+ TEST_SIZE(base64_e(buffer, 1, "\0\020", 2), 4);
+ TEST_S(buffer + 1, "not changed");
+ TEST_S(buffer, "");
+
+ strcpy(buffer + 5, "not changed");
+ TEST_SIZE(base64_e(buffer, 5, "\0", 1), 4);
+ TEST_S(buffer + 5, "not changed");
+ TEST_S(buffer, "AA==");
+
+ strcpy(buffer + 4, "not changed");
+ TEST_SIZE(base64_e(buffer, 4, "\0", 1), 4);
+ TEST_S(buffer + 4, "not changed");
+ TEST_S(buffer, "AA=");
+
+ strcpy(buffer + 3, "not changed");
+ TEST_SIZE(base64_e(buffer, 3, "\0", 1), 4);
+ TEST_S(buffer + 3, "not changed");
+ TEST_S(buffer, "AA");
+
+ strcpy(buffer + 2, "not changed");
+ TEST_SIZE(base64_e(buffer, 2, "\0", 1), 4);
+ TEST_S(buffer + 2, "not changed");
+ TEST_S(buffer, "A");
+
+ strcpy(buffer + 1, "not changed");
+ TEST_SIZE(base64_e(buffer, 1, "\0", 1), 4);
+ TEST_S(buffer + 1, "not changed");
+ TEST_S(buffer, "");
+
+ END();
+}
+
+int test_decoding(void)
+{
+ char buffer[32];
+
+ BEGIN();
+
+ strcpy(buffer + 0, "not changed");
+ TEST_SIZE(base64_d((void *)buffer, 0, "ABCD"), 3);
+ TEST_S(buffer + 0, "not changed");
+
+ TEST_SIZE(base64_d((void *)buffer, 3, "ABCD"), 3);
+ TEST_M(buffer, "\0\020\203", 3);
+
+ TEST_SIZE(base64_d(NULL, 3, "ABCD"), 3);
+
+ TEST_SIZE(base64_d((void *)buffer, 3, "A B C D !!"), 3);
+ TEST_M(buffer, "\0\020\203", 3);
+
+ END();
+}
+
+
+void usage(void)
+{
+ fprintf(stderr,
+ "usage: %s [-v]\n",
+ name);
+}
+
+int main(int argc, char *argv[])
+{
+ int retval = 0;
+ int i;
+
+ for (i = 1; argv[i]; i++) {
+ if (strcmp(argv[i], "-v") == 0)
+ tstflags |= tst_verbatim;
+ else
+ usage();
+ }
+
+ retval |= test_encoding(); fflush(stdout);
+ retval |= test_decoding(); fflush(stdout);
+
+ return retval;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/ucs2.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/ucs2.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,192 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE ucs2.c UCS2 (Unicode, ISO Basic Multilingual Plane) string handling.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Apr 21 15:32:02 1998 pessi
+ *
+ */
+
+#include "config.h"
+
+#include <sofia-sip/utf8.h>
+#include "utf8internal.h"
+
+/*
+ * Decode utf8 string into ucs2 string,
+ * return number of ucs2 characters decoded
+ */
+size_t ucs2decode(ucs2 *dst, size_t dst_size, const utf8 *s)
+{
+ ucs2 v, *d = dst;
+
+ if (s) do {
+ if (dst_size == 0)
+ break;
+ if (IS_UTF8_S1(s))
+ v = UCS4_S1(s), s += 1;
+ else if (IS_UTF8_S2(s))
+ v = UCS4_S2(s), s += 2;
+ else if (IS_UTF8_S3(s))
+ v = UCS4_S3(s), s += 3;
+ else {
+ s++;
+ continue; /* skip illegal characters */
+ }
+ *d++ = v;
+ dst_size--;
+ } while (*s);
+
+ if (dst_size)
+ *d = 0;
+
+ return d - dst;
+}
+
+/*
+ * Encode ucs2 string into utf8 string,
+ * return number of utf8 bytes encoded including final zero
+ *
+ * 'quote' may contain an optional quoting table containing
+ * non-zero for all ASCII characters to quote
+ *
+ */
+size_t ucs2encode(utf8 *dst, const ucs2 *s, size_t n, const char quote[128])
+{
+ utf8 *d = dst;
+ ucs2 c;
+
+ if (s) while (n-- > 0) {
+ c = *s++;
+
+ if (IS_UCS4_1(c)) {
+ if (quote && quote[c]) {
+ UTF8_S2(d, c);
+ d += 2;
+ }
+ else {
+ if (!c) /* zero must be represented as UTF8_2 */
+ break;
+ UTF8_S1(d, (utf8) c);
+ d += 1;
+ }
+ }
+ else if (IS_UCS4_2(c)) {
+ UTF8_S2(d, c);
+ d += 2;
+ }
+ else /* if (IS_UCS4_3(c)) */ {
+ UTF8_S3(d, c);
+ d += 3;
+ }
+ }
+
+ *d++ = 0;
+ return d - dst;
+}
+
+/*
+ * Length of UCS2 (BMP, Unicode) string decoded from UTF8
+ */
+size_t ucs2declen(const utf8 *s)
+{
+ size_t len = 0;
+ size_t errors = 0; /* errors */
+
+ UTF8_ANALYZE(s, len, len, len, errors, errors);
+
+ if (errors)
+ return 0;
+
+ return len;
+}
+
+/*
+ * Length of UTF8 encoding of a UCS2 string, including final zero
+ */
+size_t ucs2enclen(const ucs2 *s, size_t n, const char quote[128])
+{
+ size_t len = 1;
+ ucs2 c;
+
+ while (n-- > 0) {
+ c = *s++;
+ if (c < 0x80u)
+ if (quote && quote[c])
+ len += 2;
+ else {
+ if (!c) break;
+ len += 1;
+ }
+ else if (c < 0x800u)
+ len += 2;
+ else /* if (c < 0x10000u) */
+ len += 3;
+ }
+
+ return len;
+}
+
+/*
+ * Length of UCS2 string (number of non-zero UCS2 characters before zero)
+ */
+size_t ucs2len(ucs2 const *s)
+{
+ size_t len = 0;
+
+ if (s) while (*s++)
+ len++;
+
+ return len;
+}
+
+/*
+ * Compare UCS2 (BMP, Unicode) string
+ */
+int ucs2cmp(ucs2 const *s1, ucs2 const *s2)
+{
+ int retval = s1 - s2;
+
+ if (s1 && s2)
+ while ((retval = (*s1 - *s2)) && (*s1++) && (*s2++))
+ ;
+
+ return retval;
+}
+
+/*
+ * Compare UCS2 (BMP, Unicode) string
+ */
+int ucs2ncmp(ucs2 const *s1, ucs2 const *s2, size_t n)
+{
+ int retval = 0;
+
+ if (s1 && s2)
+ while (n-- > 0 && (retval = (*s1 - *s2)) && (*s1++) && (*s2++))
+ ;
+
+ return retval;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/ucs4.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/ucs4.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,216 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE ucs4.c UCS-4 routines
+ *
+ * @author Pekka Pessi <pessi at research.nokia.com>
+ *
+ * @date Created: Tue Apr 21 15:32:02 1998 pessi
+ */
+
+#include "config.h"
+
+#include <sofia-sip/utf8.h>
+#include "utf8internal.h"
+
+/*
+ * Decode utf8 string into ucs4 string,
+ * return number of ucs4 characters decoded
+ */
+size_t ucs4decode(ucs4 *dst, size_t dst_size, const utf8 *s)
+{
+ ucs4 v, *d = dst;
+
+ if (s) while (*s) {
+ if (dst_size == 0)
+ break;
+ if (IS_UTF8_S1(s))
+ v = UCS4_S1(s), s += 1;
+ else if (IS_UTF8_S2(s))
+ v = UCS4_S2(s), s += 2;
+ else if (IS_UTF8_S3(s))
+ v = UCS4_S3(s), s += 3;
+ else if (IS_UTF8_S4(s))
+ v = UCS4_S4(s), s += 4;
+ else if (IS_UTF8_S5(s))
+ v = UCS4_S5(s), s += 5;
+ else if (IS_UTF8_S6(s))
+ v = UCS4_S6(s), s += 6;
+ else {
+ s++;
+ continue; /* skip illegal characters */
+ }
+ *d++ = v;
+ dst_size--;
+ };
+
+ if (dst_size)
+ *d = 0;
+
+ return d - dst;
+}
+
+/*
+ * Encode ucs4 string into utf8 string,
+ * return number of utf8 bytes encoded including final zero
+ *
+ * 'quote' may contain an optional quoting table containing
+ * non-zero for all ASCII characters to quote
+ *
+ */
+size_t ucs4encode(utf8 *dst, const ucs4 *s, size_t n, const char quote[128])
+{
+ utf8 *d = dst;
+ ucs4 c;
+
+ if (s) while (n-- > 0) {
+ c = *s++;
+
+ if (IS_UCS4_1(c)) {
+ if (quote && quote[c]) {
+ UTF8_S2(d, c);
+ d += 2;
+ }
+ else {
+ if (!c) /* zero must be represented as UTF8_2 */
+ break;
+ UTF8_S1(d, c);
+ d += 1;
+ }
+ }
+ else if (IS_UCS4_2(c)) {
+ UTF8_S2(d, c);
+ d += 2;
+ }
+ else if (IS_UCS4_3(c)) {
+ UTF8_S3(d, c);
+ d += 3;
+ }
+ else if (IS_UCS4_4(c)) {
+ UTF8_S4(d, c);
+ d += 4;
+ }
+ else if (IS_UCS4_5(c)) {
+ UTF8_S5(d, c);
+ d += 5;
+ }
+ else if (IS_UCS4_6(c)) {
+ UTF8_S6(d, c);
+ d += 6;
+ }
+ else {
+ /* skip illegal (negative) characters */
+ }
+ }
+
+ *d++ = 0;
+ return d - dst;
+}
+
+/*
+ * Length of UCS4 string decoded from UTF8
+ */
+size_t ucs4declen(const utf8 *s)
+{
+ size_t len = 0;
+ size_t errors = 0; /* errors */
+
+ UTF8_ANALYZE(s, len, len, len, len, errors);
+
+ if (errors)
+ return 0;
+
+ return len;
+}
+
+/*
+ * Length of UTF8 encoding of a UCS4 string, including final zero
+ */
+size_t ucs4enclen(const ucs4 *s, size_t n, const char quote[128])
+{
+ size_t len = 1;
+ ucs4 c;
+
+ while (n-- > 0) {
+ c = *s++;
+ if (c < 0x80u)
+ if (quote && quote[c])
+ len += 2;
+ else {
+ if (!c) break;
+ len += 1;
+ }
+ else if (c < 0x800u)
+ len += 2;
+ else if (c < 0x10000u)
+ len += 3;
+ else if (c < 0x200000u)
+ len += 4;
+ else if (c < 0x4000000u)
+ len += 5;
+ else if (c < 0x80000000u)
+ len += 6;
+ }
+
+ return len;
+}
+
+/*
+ * Length of UCS4 string (number of non-zero UCS4 characters before zero)
+ */
+size_t ucs4len(ucs4 const *s)
+{
+ size_t len = 0;
+
+ if (s) while (*s++)
+ len++;
+
+ return len;
+}
+
+/*
+ * Compare UCS4 string
+ */
+int ucs4cmp(ucs4 const *s1, ucs4 const *s2)
+{
+ int retval;
+
+ while ((retval = (*s1 - *s2)) && (*s1++) && (*s2++))
+ ;
+
+ return retval;
+}
+
+/*
+ * Compare UCS4 string prefix
+ */
+int ucs4ncmp(ucs4 const *s1, ucs4 const *s2, size_t n)
+{
+ int retval = 0;
+
+ while (n-- > 0 && (retval = (*s1 - *s2)) && (*s1++) && (*s2++))
+ ;
+
+ return retval;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/utf8.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/utf8.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,91 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE utf8.c
+ *
+ * utf8 string handling.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Apr 21 15:32:02 1998 pessi
+ */
+
+#include "config.h"
+
+#include <sofia-sip/utf8.h>
+#include "utf8internal.h"
+
+#ifndef _WIN32
+#include <assert.h>
+#endif
+
+/** Width of an UTF8 character cell (1, 2 or 4 bytes) */
+size_t utf8_width(const utf8 *s)
+{
+ size_t w8 = 0, w16 = 0, w32 = 0;
+ size_t errors = 0; /* errors */
+
+ UTF8_ANALYZE(s, w8, w8, w16, w32, errors);
+
+ if (errors)
+ return 0;
+
+ return w32 ? 4 : (w16 ? 2 : 1);
+}
+
+/** Convert UTF8 string @a s to ISO-Latin-1 string @a dst. */
+size_t ucs18decode(char *dst, size_t dst_size, const utf8 *s)
+{
+#ifndef _WIN32
+ assert(!"implemented");
+#endif
+ return 0;
+}
+
+/** Convert ISO-Latin-1 string @a s to UTF8 string in @a dst. */
+size_t ucs1encode(utf8 *dst, const ucs1 *s, size_t n, const char quote[128])
+{
+#ifndef _WIN32
+ assert(!"implemented");
+#endif
+ return 0;
+}
+
+/** Calculate number of characters in UTF8 string @a s. */
+size_t ucs1declen(const utf8 *s)
+{
+#ifndef _WIN32
+ assert(!"implemented");
+#endif
+ return 0;
+}
+
+/** Calculate length of UTF8 encoding of string @a s. */
+size_t ucs1enclen(const ucs1 *s, size_t n, const char quote[128])
+{
+#ifndef _WIN32
+ assert(!"implemented");
+#endif
+ return 0;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/utf8internal.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/utf8internal.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,85 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef UTF8INTERNAL_H
+#define UTF8INTERNAL_H
+
+/**@IFILE utf8internal.h
+ * UTF-8 macros.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Apr 21 15:32:02 1998 pessi
+ */
+
+#define UTF8_ANALYZE(s, ascii, latin1, ucs2, ucs4, errors) \
+do { \
+ if (s) while (*s) { \
+ utf8 c = *s++; \
+ if (IS_UTF8_1(c)) \
+ ascii++; \
+ else if (IS_UTF8_I(c)) { \
+ if (IS_UTF8_X(s[0])) \
+ latin1++, s++; \
+ else \
+ errors++; \
+ } \
+ else if (IS_UTF8_2(c)) { \
+ if (IS_UTF8_X(s[0])) \
+ ucs2++, s++; \
+ else \
+ errors++; \
+ } \
+ else if (IS_UTF8_3(c)) { \
+ if (IS_UTF8_X(s[0]) && IS_UTF8_X(s[1])) \
+ ucs2++, s++, s++; \
+ else \
+ errors++; \
+ } \
+ else if (IS_UTF8_4(c)) { \
+ if (IS_UTF8_X(s[0]) && IS_UTF8_X(s[1]) && IS_UTF8_X(s[2])) \
+ ucs4++, s++, s++, s++; \
+ else \
+ errors++; \
+ } \
+ else if (IS_UTF8_5(c)) { \
+ if (IS_UTF8_X(s[0]) && IS_UTF8_X(s[1]) && \
+ IS_UTF8_X(s[2]) && IS_UTF8_X(s[3])) \
+ ucs4++, s++, s++, s++, s++; \
+ else \
+ errors++; \
+ } \
+ else if (IS_UTF8_6(c)) { \
+ if (IS_UTF8_X(s[0]) && IS_UTF8_X(s[1]) && \
+ IS_UTF8_X(s[2]) && IS_UTF8_X(s[3]) && IS_UTF8_X(s[4])) \
+ ucs4++, s++, s++, s++, s++, s++; \
+ else \
+ errors++; \
+ } \
+ else \
+ errors++; \
+ } \
+} while(0)
+
+#endif /* UTF8INTERNAL_H */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/utf8test.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/ipt/utf8test.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,188 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@internal
+ * @CFILE utf8test.c UTF8 encoding - decoding tests
+ *
+ * @author Pekka Pessi <pessi at research.nokia.com>
+ *
+ * @date Created: Tue Apr 21 15:32:38 1998 pessi
+ */
+
+#include "config.h"
+
+#include <sofia-sip/utf8.h>
+#include <stdio.h>
+#include <string.h>
+
+int main(int argc, char *argv[])
+{
+ static ucs4 ucs4test0[] = {
+ 0x41u, 0xC1u, 0x841u, 0x10041u, 0x200041u, 0x4000041u, 0
+ };
+ static utf8 ucs4test1[] =
+ "A"
+ "\303\201"
+ "\340\241\201"
+ "\360\220\201\201"
+ "\370\210\200\201\201"
+ "\374\204\200\200\201\201";
+
+ static ucs2 ucs2test0[] = {
+ 0x41u, 0xC1u, 0x841u, 0
+ };
+ static utf8 ucs2test1[] =
+ "A"
+ "\303\201"
+ "\340\241\201";
+
+ ucs4 ucs4s[1024] = { 0 };
+ ucs2 ucs2s[1024] = { 0 };
+ utf8 utf8s[1024] = { 0 };
+
+ size_t len;
+ int result = 0;
+ int i;
+
+ puts("testing ucs4len(ucs4test0)");
+
+ len = ucs4len(ucs4test0);
+ if (len != 6) {
+ printf("ucs4len(ucs4test0) returns %u\n", len);
+ result = 1;
+ }
+ else puts("OK");
+
+ puts("testing ucs4declen(ucs4test1)");
+
+ len = ucs4declen(ucs4test1);
+ if (len != 6) {
+ printf("ucs4declen(ucs4test1) returns %u\n", len);
+ result = 1;
+ }
+ else puts("OK");
+
+ puts("testing ucs4enclen(ucs4test0, 6, NULL)");
+
+ len = ucs4enclen(ucs4test0, 6, NULL);
+ if (len != 22) {
+ printf("ucs4enclen(ucs4test0, 6, NULL) returns %u\n", len);
+ result = 1;
+ }
+ else puts("OK");
+
+ puts("testing ucs4enclen(ucs4test0, 5, NULL)");
+
+ len = ucs4enclen(ucs4test0, 5, NULL);
+ if (len != 16) {
+ printf("ucs4enclen(ucs4test0, 5, NULL) returns %u\n", len);
+ result = 1;
+ }
+ else puts("OK");
+
+ puts("testing ucs4encode(utf8s, ucs4test0, 6, NULL)");
+
+ if (ucs4encode(utf8s, ucs4test0, 6, NULL) != 22 ||
+ strcmp((char *)utf8s, (char*)ucs4test1)) {
+ printf("ucs4encode(utf8s, ucs4test0, 6, NULL) fails\n");
+ result = 1;
+ printf("\tutf8s=\"%s\"\n", utf8s);
+ }
+ else puts("OK");
+
+ puts("testing ucs4decode(ucs4s, sizeof(ucs4s), ucs4test1)");
+
+ if (ucs4decode(ucs4s, sizeof(ucs4s)/sizeof(*ucs4s), ucs4test1) != 6
+ || ucs4cmp(ucs4s, ucs4test0)) {
+ printf("ucs4decode(ucs4s, sizeof(ucs4s), ucs4test1) fails\n");
+ result = 1;
+ for (i = 0; i < 8; i++) {
+ printf("\tucs4s[%d]=0x%x\n", i, ucs4s[i]);
+ }
+ }
+ else puts("OK");
+
+ /* UCS2 */
+
+ puts("testing ucs2len(ucs2test0)");
+
+ len = ucs2len(ucs2test0);
+ if (len != 3) {
+ printf("ucs2len(ucs2test0) returns %u\n", len);
+ result = 1;
+ }
+ else puts("OK");
+
+ puts("testing ucs2declen(ucs2test1)");
+
+ len = ucs2declen(ucs2test1);
+ if (len != 3) {
+ printf("ucs2declen(ucs2test1) returns %u\n", len);
+ result = 1;
+ }
+ else puts("OK");
+
+ puts("testing ucs2enclen(ucs2test0, 3, NULL)");
+
+ len = ucs2enclen(ucs2test0, 3, NULL);
+ if (len != 7) {
+ printf("ucs2enclen(ucs2test1, 3, NULL) returns %u\n", len);
+ result = 1;
+ }
+ else puts("OK");
+
+ puts("testing ucs2enclen(ucs2test0, 2, NULL)");
+
+ len = ucs2enclen(ucs2test0, 2, NULL);
+ if (len != 4) {
+ printf("ucs2enclen(ucs2test1, NULL) returns %u\n", len);
+ result = 1;
+ }
+ else puts("OK");
+
+ puts("testing ucs2encode(utf8s, ucs2test0, 3, NULL)");
+
+ if (ucs2encode(utf8s, ucs2test0, 3, NULL) != 7 ||
+ strcmp((char *)utf8s, (char*)ucs2test1)) {
+ printf("ucs2encode(utf8s, ucs2test0, 3, NULL) fails\n");
+ result = 1;
+ printf("\tutf8s=\"%s\"\n", utf8s);
+ }
+ else puts("OK");
+
+ puts("testing ucs2decode(ucs2s, sizeof(ucs2s)/sizeof(*ucs2s), ucs2test1)");
+
+ if (ucs2decode(ucs2s, sizeof(ucs2s)/sizeof(*ucs2s), ucs2test1) != 3 ||
+ ucs2cmp(ucs2s, ucs2test0)) {
+ printf("ucs2decode(ucs2s, sizeof(ucs2s)/sizeof(*ucs2s), ucs2test1) fails\n");
+ result = 1;
+ for (i = 0; i < 8; i++) {
+ printf("\tucs2s[%d]=0x%x\n", i, ucs2s[i]);
+ }
+ }
+ else puts("OK");
+
+
+ return result;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/ChangeLog Thu Dec 21 01:30:28 2006
@@ -0,0 +1,24 @@
+2005-11-08 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Renamed auth_digest_test.c as test_auth_digest.c.
+
+2005-10-21 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Generate opaque only if opaque parameter has value "*".
+
+ M ./libsofia-sip-ua/iptsec/auth_module.c -14 +20
+
+2005-09-06 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * auth_digest_test.c: Using opaque to match credentials (as per
+ auth_digest_credentials()).
+
+ * auth_plugin.h, auth_module.c: Added auth_digest_credentials.
+
+2005-08-10 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * auth_module.c: Using unsigned as type of hash!
+
+2005-07-18 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * Initial import of the module to Sofia-SIP tree.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/Doxyfile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/Doxyfile Thu Dec 21 01:30:28 2006
@@ -0,0 +1,20 @@
+PROJECT_NAME = "iptsec"
+OUTPUT_DIRECTORY = ../docs/html/iptsec
+
+INPUT = iptsec.docs sofia-sip .
+
+ at INCLUDE = ../docs/Doxyfile.conf
+
+TAGFILES += ../docs/su.doxytags=../su
+TAGFILES += ../docs/ipt.doxytags=../ipt
+TAGFILES += ../docs/bnf.doxytags=../bnf
+TAGFILES += ../docs/url.doxytags=../url
+TAGFILES += ../docs/msg.doxytags=../msg
+TAGFILES += ../docs/sip.doxytags=../sip
+TAGFILES += ../docs/sresolv.doxytags=../sresolv
+TAGFILES += ../docs/tport.doxytags=../tport
+TAGFILES += ../docs/nta.doxytags=../nta
+
+GENERATE_TAGFILE = ../docs/iptsec.doxytags
+
+ALIASES +=
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/Makefile.am Thu Dec 21 01:30:28 2006
@@ -0,0 +1,80 @@
+#
+# Makefile.am for iptsec module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+INCLUDES = -I$(srcdir)/../bnf -I../bnf \
+ -I$(srcdir)/../ipt -I../ipt \
+ -I$(srcdir)/../http -I../http \
+ -I$(srcdir)/../msg -I../msg \
+ -I$(srcdir)/../nta -I../nta \
+ -I$(srcdir)/../sip -I../sip \
+ -I$(srcdir)/../url -I../url \
+ -I$(srcdir)/../su -I../su
+
+# ----------------------------------------------------------------------
+# Build targets
+
+noinst_LTLIBRARIES = libiptsec.la
+
+check_PROGRAMS = test_auth_digest
+
+TESTS = test_auth_digest
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+
+BUILT_SOURCES = auth_tag_ref.c
+
+nobase_include_sofia_HEADERS = \
+ sofia-sip/auth_common.h \
+ sofia-sip/auth_client.h sofia-sip/auth_digest.h \
+ sofia-sip/auth_module.h sofia-sip/auth_plugin.h \
+ sofia-sip/auth_client_plugin.h \
+ $(NTLM_HEADER)
+
+libiptsec_la_SOURCES = iptsec_debug.h \
+ auth_client.c auth_common.c auth_digest.c \
+ auth_module.c auth_tag.c auth_tag_ref.c \
+ auth_plugin.c auth_plugin_delayed.c \
+ auth_module_http.c auth_module_sip.c \
+ $(NTLM_SOURCE) \
+ iptsec_debug.c
+
+NTLM_HEADER = sofia-sip/auth_ntlm.h
+if HAVE_NTLM
+NTLM_SOURCE = auth_ntlm.c auth_client_ntlm.c auth_plugin_ntlm.c
+endif
+
+EXTRA_libiptsec_la_SOURCES = \
+ auth_ntlm.c auth_client_ntlm.c auth_plugin_ntlm.c
+
+COVERAGE_INPUT = $(libiptsec_la_SOURCES) $(include_sofia_HEADERS)
+
+LDADD = libiptsec.la \
+ ../http/libhttp.la \
+ ../nta/libnta.la \
+ ../sip/libsip.la \
+ ../msg/libmsg.la \
+ ../url/liburl.la \
+ ../bnf/libbnf.la \
+ ../ipt/libipt.la \
+ ../su/libsu.la
+
+test_auth_digest_LDFLAGS = -static
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+
+EXTRA_DIST = Doxyfile iptsec.docs testpasswd \
+ auth_module_sip.c auth_module_http.c $(BUILT_SOURCES)
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+
+include ../sofia.am
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/Makefile.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1,752 @@
+# 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.
+
+ at SET_MAKE@
+
+#
+# Makefile.am for iptsec module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+# common Makefile targets for libsofia-sip-ua modules
+# ---------------------------------------------------
+
+
+SOURCES = $(libiptsec_la_SOURCES) $(EXTRA_libiptsec_la_SOURCES) test_auth_digest.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 = test_auth_digest$(EXEEXT)
+DIST_COMMON = $(nobase_include_sofia_HEADERS) $(srcdir)/../sofia.am \
+ $(srcdir)/Makefile.am $(srcdir)/Makefile.in ChangeLog
+subdir = libsofia-sip-ua/iptsec
+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 =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libiptsec_la_LIBADD =
+am__libiptsec_la_SOURCES_DIST = iptsec_debug.h auth_client.c \
+ auth_common.c auth_digest.c auth_module.c auth_tag.c \
+ auth_tag_ref.c auth_plugin.c auth_plugin_delayed.c \
+ auth_module_http.c auth_module_sip.c auth_ntlm.c \
+ auth_client_ntlm.c auth_plugin_ntlm.c iptsec_debug.c
+ at HAVE_NTLM_TRUE@am__objects_1 = auth_ntlm.lo auth_client_ntlm.lo \
+ at HAVE_NTLM_TRUE@ auth_plugin_ntlm.lo
+am_libiptsec_la_OBJECTS = auth_client.lo auth_common.lo auth_digest.lo \
+ auth_module.lo auth_tag.lo auth_tag_ref.lo auth_plugin.lo \
+ auth_plugin_delayed.lo auth_module_http.lo auth_module_sip.lo \
+ $(am__objects_1) iptsec_debug.lo
+libiptsec_la_OBJECTS = $(am_libiptsec_la_OBJECTS)
+test_auth_digest_SOURCES = test_auth_digest.c
+test_auth_digest_OBJECTS = test_auth_digest.$(OBJEXT)
+test_auth_digest_LDADD = $(LDADD)
+test_auth_digest_DEPENDENCIES = libiptsec.la ../http/libhttp.la \
+ ../nta/libnta.la ../sip/libsip.la ../msg/libmsg.la \
+ ../url/liburl.la ../bnf/libbnf.la ../ipt/libipt.la \
+ ../su/libsu.la
+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 = $(libiptsec_la_SOURCES) $(EXTRA_libiptsec_la_SOURCES) \
+ test_auth_digest.c
+DIST_SOURCES = $(am__libiptsec_la_SOURCES_DIST) \
+ $(EXTRA_libiptsec_la_SOURCES) test_auth_digest.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|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(include_sofiadir)"
+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)/../bnf -I../bnf \
+ -I$(srcdir)/../ipt -I../ipt \
+ -I$(srcdir)/../http -I../http \
+ -I$(srcdir)/../msg -I../msg \
+ -I$(srcdir)/../nta -I../nta \
+ -I$(srcdir)/../sip -I../sip \
+ -I$(srcdir)/../url -I../url \
+ -I$(srcdir)/../su -I../su
+
+
+# ----------------------------------------------------------------------
+# Build targets
+noinst_LTLIBRARIES = libiptsec.la
+TESTS = test_auth_digest
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+BUILT_SOURCES = auth_tag_ref.c
+nobase_include_sofia_HEADERS = \
+ sofia-sip/auth_common.h \
+ sofia-sip/auth_client.h sofia-sip/auth_digest.h \
+ sofia-sip/auth_module.h sofia-sip/auth_plugin.h \
+ sofia-sip/auth_client_plugin.h \
+ $(NTLM_HEADER)
+
+libiptsec_la_SOURCES = iptsec_debug.h \
+ auth_client.c auth_common.c auth_digest.c \
+ auth_module.c auth_tag.c auth_tag_ref.c \
+ auth_plugin.c auth_plugin_delayed.c \
+ auth_module_http.c auth_module_sip.c \
+ $(NTLM_SOURCE) \
+ iptsec_debug.c
+
+NTLM_HEADER = sofia-sip/auth_ntlm.h
+ at HAVE_NTLM_TRUE@NTLM_SOURCE = auth_ntlm.c auth_client_ntlm.c auth_plugin_ntlm.c
+EXTRA_libiptsec_la_SOURCES = \
+ auth_ntlm.c auth_client_ntlm.c auth_plugin_ntlm.c
+
+COVERAGE_INPUT = $(libiptsec_la_SOURCES) $(include_sofia_HEADERS)
+LDADD = libiptsec.la \
+ ../http/libhttp.la \
+ ../nta/libnta.la \
+ ../sip/libsip.la \
+ ../msg/libmsg.la \
+ ../url/liburl.la \
+ ../bnf/libbnf.la \
+ ../ipt/libipt.la \
+ ../su/libsu.la
+
+test_auth_digest_LDFLAGS = -static
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+EXTRA_DIST = Doxyfile iptsec.docs testpasswd \
+ auth_module_sip.c auth_module_http.c $(BUILT_SOURCES)
+
+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
+
+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/iptsec/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu libsofia-sip-ua/iptsec/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-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
+libiptsec.la: $(libiptsec_la_OBJECTS) $(libiptsec_la_DEPENDENCIES)
+ $(LINK) $(libiptsec_la_LDFLAGS) $(libiptsec_la_OBJECTS) $(libiptsec_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
+test_auth_digest$(EXEEXT): $(test_auth_digest_OBJECTS) $(test_auth_digest_DEPENDENCIES)
+ @rm -f test_auth_digest$(EXEEXT)
+ $(LINK) $(test_auth_digest_LDFLAGS) $(test_auth_digest_OBJECTS) $(test_auth_digest_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/auth_client.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/auth_client_ntlm.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/auth_common.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/auth_digest.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/auth_module.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/auth_module_http.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/auth_module_sip.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/auth_ntlm.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/auth_plugin.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/auth_plugin_delayed.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/auth_plugin_ntlm.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/auth_tag.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/auth_tag_ref.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/iptsec_debug.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_auth_digest.Po at am__quote@
+
+.c.o:
+ at am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+ at am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ at am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at 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 $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(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-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-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-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-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-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-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) $<
+
+ at ENABLE_COVERAGE_TRUE@coverage:
+ at 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)
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+# 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:
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_client.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_client.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1023 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE auth_client.c Authenticators for SIP client
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Feb 14 18:32:58 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <sofia-sip/su.h>
+#include <sofia-sip/su_md5.h>
+
+#include "sofia-sip/auth_common.h"
+#include "sofia-sip/auth_client.h"
+#include "sofia-sip/auth_client_plugin.h"
+
+#include <sofia-sip/msg_types.h>
+#include <sofia-sip/msg_header.h>
+
+#include <sofia-sip/auth_digest.h>
+
+#include <sofia-sip/base64.h>
+#include <sofia-sip/su_uniqueid.h>
+#include <sofia-sip/string0.h>
+
+#include <sofia-sip/su_debug.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <assert.h>
+
+static auth_client_t *ca_create(su_home_t *home,
+ char const *scheme,
+ char const *realm);
+
+static void ca_destroy(su_home_t *home, auth_client_t *ca);
+
+static int ca_challenge(auth_client_t *ca,
+ msg_auth_t const *auth,
+ msg_hclass_t *credential_class,
+ char const *scheme,
+ char const *realm);
+
+static int ca_info(auth_client_t *ca,
+ msg_auth_info_t const *ai,
+ msg_hclass_t *credential_class);
+
+static int ca_credentials(auth_client_t *ca,
+ char const *scheme,
+ char const *realm,
+ char const *user,
+ char const *pass);
+
+static int ca_clear_credentials(auth_client_t *ca,
+ char const *scheme,
+ char const *realm);
+
+
+/** Initialize authenticators.
+ *
+ * The function auc_challenge() merges the challenge @a ch to the list of
+ * authenticators @a auc_list.
+ *
+ * @param[in,out] auc_list list of authenticators to be updated
+ * @param[in,out] home memory home used for allocating authenticators
+ * @param[in] ch challenge to be processed
+ * @param[in] crcl credential class
+ *
+ * @retval 1 when challenge was updated
+ * @retval 0 when there was no new challenges
+ * @retval -1 upon an error
+ */
+int auc_challenge(auth_client_t **auc_list,
+ su_home_t *home,
+ msg_auth_t const *ch,
+ msg_hclass_t *crcl)
+{
+ auth_client_t **cca;
+ int retval = 0;
+
+ /* Go through each challenge in Authenticate or Proxy-Authenticate headers */
+ for (; ch; ch = ch->au_next) {
+ char const *scheme = ch->au_scheme;
+ char const *realm = msg_header_find_param(ch->au_common, "realm=");
+ int matched = 0, updated;
+
+ if (!scheme || !realm)
+ continue;
+
+ /* Update matching authenticator */
+ for (cca = auc_list; (*cca); cca = &(*cca)->ca_next) {
+ updated = ca_challenge((*cca), ch, crcl, scheme, realm);
+ if (updated < 0)
+ return -1;
+ if (updated == 0)
+ continue; /* No match, next */
+ matched = 1;
+ if (updated > 1)
+ retval = 1; /* Updated authenticator */
+ }
+
+ if (!matched) {
+ /* There was no matching authenticator, create a new one */
+ *cca = ca_create(home, scheme, realm);
+ if (ca_challenge((*cca), ch, crcl, scheme, realm) < 0) {
+ ca_destroy(home, *cca), *cca = NULL;
+ return -1;
+ }
+ retval = 1; /* Updated authenticator */
+ }
+ }
+
+ return retval;
+}
+
+/** Update authentication client.
+ *
+ * @retval -1 upon an error
+ * @retval 0 when challenge did not match
+ * @retval 1 when challenge did match but was not updated
+ * @retval 2 when challenge did match and updated client
+ */
+static
+int ca_challenge(auth_client_t *ca,
+ msg_auth_t const *ch,
+ msg_hclass_t *credential_class,
+ char const *scheme,
+ char const *realm)
+{
+ int stale = 0;
+
+ assert(ca); assert(ch);
+
+ if (!ca || !ch)
+ return -1;
+
+ if (strcmp(ca->ca_scheme, scheme))
+ return 0;
+ if (strcmp(ca->ca_realm, realm))
+ return 0;
+
+ if (ca->ca_credential_class &&
+ ca->ca_credential_class != credential_class)
+ return 0;
+
+ if (!ca->ca_auc)
+ return 1;
+
+ if (ca->ca_auc->auc_challenge)
+ stale = ca->ca_auc->auc_challenge(ca, ch);
+ if (stale < 0)
+ return -1;
+
+ if (!ca->ca_credential_class)
+ stale = 1, ca->ca_credential_class = credential_class;
+
+ return stale ? 2 : 1;
+}
+
+/** Store authentication info to authenticators.
+ *
+ * The function auc_info() feeds the authentication data from the
+ * authentication info @a info to the list of authenticators @a auc_list.
+ *
+ * @param[in,out] auc_list list of authenticators to be updated
+ * @param[in] info info to be processed
+ * @param[in] crcl corresponding credential class
+ *
+ * The authentication info can be in either Authentication-Info or in
+ * Proxy-Authentication-Info headers.
+ * If the header is Authentication-Info, the @a crcl should be
+ * #sip_authorization_class or #http_authorization_class.
+ * Likewise, If the header is Proxy-Authentication-Info, the @a crcl should
+ * be #sip_proxy_authorization_class or #http_proxy_authorization_class.
+
+ * The authentication into usually contains next nonce or mutual
+ * authentication information. We handle only nextnonce parameter.
+ *
+ * @bug
+ * The result can be quite unexpected if there are more than one
+ * authenticator with the given type (specified by @a crcl). In principle,
+ * SIP allows more than one challenge for a single request.
+ *
+ * @retval number of challenges to updated
+ * @retval 0 when there was no challenge to update
+ * @retval -1 upon an error
+ */
+int auc_info(auth_client_t **auc_list,
+ msg_auth_info_t const *ai,
+ msg_hclass_t *credential_class)
+{
+ auth_client_t *ca;
+ int retval = 0;
+
+ /* Go through each challenge in Authenticate or Proxy-Authenticate headers */
+
+ /* Update matching authenticator */
+ for (ca = *auc_list; ca; ca = ca->ca_next) {
+ int updated = ca_info(ca, ai, credential_class);
+ if (updated < 0)
+ return -1;
+ if (updated >= 1)
+ retval = 1; /* Updated authenticator */
+ }
+
+ return retval;
+}
+
+/** Update authentication client with authentication info.
+ *
+ * @retval -1 upon an error
+ * @retval 0 when challenge did not match
+ * @retval 1 when challenge did match but was not updated
+ * @retval 2 when challenge did match and updated client
+ */
+static
+int ca_info(auth_client_t *ca,
+ msg_auth_info_t const *ai,
+ msg_hclass_t *credential_class)
+{
+ assert(ca); assert(ai);
+
+ if (!ca || !ai)
+ return -1;
+
+ if (!ca->ca_credential_class)
+ return 0;
+
+ if (ca->ca_credential_class != credential_class)
+ return 0;
+
+ if (!ca->ca_auc
+ || (size_t)ca->ca_auc->auc_plugin_size <=
+ offsetof(auth_client_plugin_t, auc_info)
+ || !ca->ca_auc->auc_info)
+ return 0;
+
+ return ca->ca_auc->auc_info(ca, ai);
+}
+
+
+/**Feed authentication data to the authenticator.
+ *
+ * The function auc_credentials() is used to provide the authenticators in
+ * with authentication data (user name, secret). The authentication data
+ * has format as follows:
+ *
+ * scheme:"realm":user:pass
+ *
+ * For instance, @c Basic:"nokia-proxy":ppessi:verysecret
+ *
+ * @todo The authentication data format sucks.
+ *
+ * @param[in,out] auc_list list of authenticators
+ * @param[in,out] home memory home used for allocations
+ * @param[in] data colon-separated authentication data
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error
+ */
+int auc_credentials(auth_client_t **auc_list, su_home_t *home,
+ char const *data)
+{
+ int retval = 0, match;
+ char *s0, *s;
+ char *scheme = NULL, *user = NULL, *pass = NULL, *realm = NULL;
+
+ s0 = s = su_strdup(NULL, data);
+
+ /* Parse authentication data */
+ /* Data is string like "Basic:\"agni\":user1:secret" */
+ if (s && (s = strchr(scheme = s, ':')))
+ *s++ = 0;
+ if (s && (s = strchr(realm = s, ':')))
+ *s++ = 0;
+ if (s && (s = strchr(user = s, ':')))
+ *s++ = 0;
+ if (s && (s = strchr(pass = s, ':')))
+ *s++ = 0;
+
+ if (scheme && realm && user && pass) {
+ for (; *auc_list; auc_list = &(*auc_list)->ca_next) {
+ match = ca_credentials(*auc_list, scheme, realm, user, pass);
+ if (match < 0) {
+ retval = -1;
+ break;
+ }
+ if (match)
+ retval++;
+ }
+ }
+
+ su_free(NULL, s0);
+
+ return retval;
+}
+
+/**Feed authentication data to the authenticator.
+ *
+ * The function auc_credentials() is used to provide the authenticators in
+ * with authentication tuple (scheme, realm, user name, secret).
+ *
+ * scheme:"realm":user:pass
+ *
+ * @todo The authentication data format sucks.
+ *
+ * @param[in,out] auc_list list of authenticators
+ * @param[in] scheme scheme to use (NULL, if any)
+ * @param[in] realm realm to use (NULL, if any)
+ * @param[in] user username
+ * @param[in] pass password
+ *
+ * @retval number of matching clients
+ * @retval 0 when no matching client was found
+ * @retval -1 upon an error
+ */
+int auc_all_credentials(auth_client_t **auc_list,
+ char const *scheme,
+ char const *realm,
+ char const *user,
+ char const *pass)
+{
+ int retval = 0, match;
+
+#if HAVE_SC_CRED_H
+ /* XXX: add */
+#endif
+
+ if (user && pass) {
+ for (; *auc_list; auc_list = &(*auc_list)->ca_next) {
+ match = ca_credentials(*auc_list, scheme, realm, user, pass);
+ if (match < 0)
+ return -1;
+ if (match)
+ retval++;
+ }
+ }
+
+ return retval;
+}
+
+int ca_credentials(auth_client_t *ca,
+ char const *scheme,
+ char const *realm,
+ char const *user,
+ char const *pass)
+{
+ assert(ca);
+
+ if (!ca || !ca->ca_scheme || !ca->ca_realm)
+ return -1;
+
+ if ((scheme != NULL && strcasecmp(scheme, ca->ca_scheme)) ||
+ (realm != NULL && strcmp(realm, ca->ca_realm)))
+ return -1;
+
+ ca->ca_user = su_strdup(ca->ca_home, user);
+ ca->ca_pass = su_strdup(ca->ca_home, pass);
+
+ if (!ca->ca_user || !ca->ca_pass)
+ return -1;
+
+ return 1;
+}
+
+
+/** Copy authentication data from @a src to @a dst.
+ *
+ * @retval >0 if credentials were copied
+ * @retval 0 if there was no credentials to copy
+ * @retval <0 if an error occurred.
+ */
+int auc_copy_credentials(auth_client_t **dst,
+ auth_client_t const *src)
+{
+ int retval = 0;
+
+ if (!dst)
+ return -1;
+
+ for (;*dst; dst = &(*dst)->ca_next) {
+ auth_client_t *d = *dst;
+ auth_client_t const *ca;
+
+ for (ca = src; ca; ca = ca->ca_next) {
+ char *u, *p;
+ if (!ca->ca_user || !ca->ca_pass)
+ continue;
+ if (!ca->ca_scheme[0] || strcmp(ca->ca_scheme, d->ca_scheme))
+ continue;
+ if (!ca->ca_realm[0] || strcmp(ca->ca_realm, d->ca_realm))
+ continue;
+
+ if (d->ca_user && strcmp(d->ca_user, ca->ca_user) == 0 &&
+ d->ca_pass && strcmp(d->ca_pass, ca->ca_pass) == 0) {
+ retval++;
+ break;
+ }
+
+ u = su_strdup(d->ca_home, ca->ca_user);
+ p = su_strdup(d->ca_home, ca->ca_pass);
+ if (!u || !p)
+ return -1;
+
+ if (d->ca_user) su_free(d->ca_home, (void *)d->ca_user);
+ if (d->ca_pass) su_free(d->ca_home, (void *)d->ca_pass);
+ d->ca_user = u, d->ca_pass = p;
+ retval++;
+ break;
+ }
+ }
+
+ return retval;
+}
+
+
+/**Clear authentication data from the authenticator.
+ *
+ * The function auc_clear_credentials() is used to remove the credentials
+ * from the authenticators.
+ *
+ * @param[in,out] auc_list list of authenticators
+ * @param[in] scheme scheme (if non-null, remove only matching credentials)
+ * @param[in] realm realm (if non-null, remove only matching credentials)
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error
+ */
+int auc_clear_credentials(auth_client_t **auc_list,
+ char const *scheme,
+ char const *realm)
+{
+ int retval = 0;
+
+ for (; *auc_list; auc_list = &(*auc_list)->ca_next) {
+ int match = ca_clear_credentials(*auc_list, scheme, realm);
+ if (match < 0) {
+ retval = -1;
+ break;
+ }
+ if (match)
+ retval++;
+ }
+
+ return retval;
+}
+
+static
+int ca_clear_credentials(auth_client_t *ca,
+ char const *scheme,
+ char const *realm)
+{
+ assert(ca);
+
+ if (!ca || !ca->ca_scheme || !ca->ca_realm)
+ return -1;
+
+ if ((scheme != NULL && strcasecmp(scheme, ca->ca_scheme)) ||
+ (realm != NULL && strcmp(realm, ca->ca_realm)))
+ return -1;
+
+ su_free(ca->ca_home, (void *)ca->ca_user), ca->ca_user = NULL;
+ su_free(ca->ca_home, (void *)ca->ca_pass), ca->ca_pass = NULL;
+
+ return 1;
+}
+
+/** Check if we have all required credentials.
+ *
+ * @retval 1 when authorization can proceed
+ * @retval 0 when there is not enough credentials
+ */
+int auc_has_authorization(auth_client_t **auc_list)
+{
+ auth_client_t const *ca;
+
+ if (auc_list == NULL)
+ return 0;
+
+ /* Make sure every challenge has credentials */
+ for (ca = *auc_list; ca; ca = ca->ca_next) {
+ if (!ca->ca_user || !ca->ca_pass || !ca->ca_credential_class)
+ return 0;
+ }
+
+ return 1;
+}
+
+/**Authorize a request.
+ *
+ * The function auc_authorization() is used to add correct authentication
+ * headers to a request. The authentication headers will contain the
+ * credentials generated by the list of authenticators.
+ *
+ * @param[in,out] auc_list list of authenticators
+ * @param[out] msg message to be authenticated
+ * @param[out] pub headers of the message
+ * @param[in] method request method
+ * @param[in] url request URI
+ * @param[in] body message body (NULL if empty)
+ *
+ * @retval 1 when successful
+ * @retval 0 when there is not enough credentials
+ * @retval -1 upon an error
+ */
+int auc_authorization(auth_client_t **auc_list, msg_t *msg, msg_pub_t *pub,
+ char const *method,
+ url_t const *url,
+ msg_payload_t const *body)
+{
+ auth_client_t *ca;
+ msg_mclass_t const *mc = msg_mclass(msg);
+
+ if (auc_list == NULL || msg == NULL)
+ return -1;
+
+ if (!auc_has_authorization(auc_list))
+ return 0;
+
+ if (pub == NULL)
+ pub = msg_object(msg);
+
+ /* Remove existing credentials */
+ for (ca = *auc_list; ca; ca = ca->ca_next) {
+ msg_header_t **hh = msg_hclass_offset(mc, pub, ca->ca_credential_class);
+
+ while (hh && *hh)
+ msg_header_remove(msg, pub, *hh);
+ }
+
+ /* Insert new credentials */
+ for (; *auc_list; auc_list = &(*auc_list)->ca_next) {
+ su_home_t *home = msg_home(msg);
+ msg_header_t *h = NULL;
+
+ ca = *auc_list;
+
+ if (!ca->ca_auc)
+ continue;
+
+ if (ca->ca_auc->auc_authorize(ca, home, method, url, body, &h) < 0
+ || msg_header_insert(msg, pub, h) < 0)
+ return -1;
+ }
+
+ return 1;
+}
+
+/**Generate headers authorizing a request.
+ *
+ * The function auc_authorization_headers() is used to generate
+ * authentication headers for a request. The list of authentication headers
+ * will contain the credentials generated by the list of authenticators.
+ *
+ * @param[in] auc_list list of authenticators
+ * @param[in] home memory home used to allocate headers
+ * @param[in] method request method
+ * @param[in] url request URI
+ * @param[in] body message body (NULL if empty)
+ * @param[out] return_headers authorization headers return value
+ *
+ * @retval 1 when successful
+ * @retval 0 when there is not enough credentials
+ * @retval -1 upon an error
+ */
+int auc_authorization_headers(auth_client_t **auc_list,
+ su_home_t *home,
+ char const *method,
+ url_t const *url,
+ msg_payload_t const *body,
+ msg_header_t **return_headers)
+{
+ auth_client_t *ca;
+
+ /* Make sure every challenge has credentials */
+ if (!auc_has_authorization(auc_list))
+ return 0;
+
+ /* Create new credential headers */
+ for (; *auc_list; auc_list = &(*auc_list)->ca_next) {
+ msg_header_t *h = NULL;
+
+ ca = *auc_list;
+
+ if (!ca->ca_auc)
+ continue;
+
+ if (ca->ca_auc->auc_authorize(ca, home, method, url, body, &h) < 0)
+ return -1;
+
+ *return_headers = h;
+
+ while (*return_headers)
+ return_headers = &(*return_headers)->sh_next;
+ }
+
+ return 1;
+}
+
+/* ---------------------------------------------------------------------- */
+/* Basic scheme */
+
+static int auc_basic_authorization(auth_client_t *ca,
+ su_home_t *h,
+ char const *method,
+ url_t const *url,
+ msg_payload_t const *body,
+ msg_header_t **);
+
+const auth_client_plugin_t ca_basic_plugin =
+{
+ /* auc_plugin_size: */ sizeof ca_basic_plugin,
+ /* auc_size: */ sizeof (auth_client_t),
+ /* auc_name: */ "Basic",
+ /* auc_challenge: */ NULL,
+ /* auc_authorize: */ auc_basic_authorization,
+ /* auc_info: */ NULL
+};
+
+/**Create a basic authorization header.
+ *
+ * The function auc_basic_authorization() creates a basic authorization
+ * header from username @a user and password @a pass. The authorization
+ * header type is determined by @a hc - it can be sip_authorization_class,
+ * sip_proxy_authorization_class, http_authorization_class, or
+ * http_proxy_authorization_class, for instance.
+ *
+ * @param home memory home used to allocate memory for the new header
+ * @param hc header class for the header to be created
+ * @param user user name
+ * @param pass password
+ *
+ * @return
+ * The function auc_basic_authorization() returns a pointer to newly created
+ * authorization header, or NULL upon an error.
+ */
+int auc_basic_authorization(auth_client_t *ca,
+ su_home_t *home,
+ char const *method,
+ url_t const *url,
+ msg_payload_t const *body,
+ msg_header_t **return_headers)
+{
+ msg_hclass_t *hc = ca->ca_credential_class;
+ char const *user = ca->ca_user;
+ char const *pass = ca->ca_pass;
+ size_t ulen, plen, uplen, b64len, basiclen;
+ char *basic, *base64, *userpass;
+ char buffer[71];
+
+ if (user == NULL || pass == NULL)
+ return -1;
+
+ ulen = strlen(user), plen = strlen(pass), uplen = ulen + 1 + plen;
+ b64len = BASE64_SIZE(uplen);
+ basiclen = strlen("Basic ") + b64len;
+
+ if (sizeof(buffer) > basiclen + 1)
+ basic = buffer;
+ else
+ basic = malloc(basiclen + 1);
+
+ /*
+ * Basic authentication consists of username and password separated by
+ * colon and then base64 encoded.
+ */
+ strcpy(basic, "Basic ");
+ base64 = basic + strlen("Basic ");
+ userpass = base64 + b64len - uplen;
+ memcpy(userpass, user, ulen);
+ userpass[ulen] = ':';
+ memcpy(userpass + ulen + 1, pass, plen);
+ userpass[uplen] = '\0';
+
+ base64_e(base64, b64len + 1, userpass, uplen);
+
+ base64[b64len] = '\0';
+
+ *return_headers = msg_header_make(home, hc, basic);
+
+ if (buffer != basic)
+ free(basic);
+
+ return *return_headers ? 0 : -1;
+}
+
+/* ---------------------------------------------------------------------- */
+/* Digest scheme */
+
+typedef struct auth_digest_client_s
+{
+ auth_client_t cda_client;
+
+ int cda_ncount;
+ char const *cda_cnonce;
+ auth_challenge_t cda_ac[1];
+} auth_digest_client_t;
+
+static int auc_digest_challenge(auth_client_t *ca,
+ msg_auth_t const *ch);
+static int auc_digest_authorization(auth_client_t *ca,
+ su_home_t *h,
+ char const *method,
+ url_t const *url,
+ msg_payload_t const *body,
+ msg_header_t **);
+static int auc_digest_info(auth_client_t *ca,
+ msg_auth_info_t const *ai);
+
+static const auth_client_plugin_t ca_digest_plugin =
+{
+ /* auc_plugin_size: */ sizeof ca_digest_plugin,
+ /* auc_size: */ sizeof (auth_digest_client_t),
+ /* auc_name: */ "Digest",
+ /* auc_challenge: */ auc_digest_challenge,
+ /* auc_authorize: */ auc_digest_authorization,
+ /* auc_info: */ auc_digest_info
+};
+
+/** Store a digest authorization challenge.
+ */
+static int auc_digest_challenge(auth_client_t *ca, msg_auth_t const *ch)
+{
+ su_home_t *home = ca->ca_home;
+ auth_digest_client_t *cda = (auth_digest_client_t *)ca;
+ auth_challenge_t ac[1] = {{ sizeof ac }};
+ int stale;
+
+ if (auth_digest_challenge_get(home, ac, ch->au_params) < 0)
+ goto error;
+
+ /* Check that we can handle the challenge */
+ if (!ac->ac_md5 && !ac->ac_md5sess)
+ goto error;
+ if (ac->ac_qop && !ac->ac_auth && !ac->ac_auth_int)
+ goto error;
+
+ stale = ac->ac_stale || str0cmp(ac->ac_nonce, cda->cda_ac->ac_nonce);
+
+ if (ac->ac_qop && (cda->cda_cnonce == NULL || ac->ac_stale)) {
+ su_guid_t guid[1];
+ char *cnonce;
+ if (cda->cda_cnonce != NULL)
+ /* Free the old one if we are updating after stale=true */
+ su_free(home, (void *)cda->cda_cnonce);
+ su_guid_generate(guid);
+ cda->cda_cnonce = cnonce = su_alloc(home, BASE64_SIZE(sizeof(guid)) + 1);
+ base64_e(cnonce, BASE64_SIZE(sizeof(guid)) + 1, guid, sizeof(guid));
+ cda->cda_ncount = 0;
+ }
+
+ auth_digest_challenge_free_params(home, cda->cda_ac);
+
+ *cda->cda_ac = *ac;
+
+ return stale ? 2 : 1;
+
+ error:
+ auth_digest_challenge_free_params(home, ac);
+ return -1;
+}
+
+static int auc_digest_info(auth_client_t *ca,
+ msg_auth_info_t const *ai)
+{
+ auth_digest_client_t *cda = (auth_digest_client_t *)ca;
+ su_home_t *home = ca->ca_home;
+ char const *nextnonce = NULL;
+ issize_t n;
+
+ n = auth_get_params(home, ai->ai_params,
+ "nextnonce=", &nextnonce,
+ NULL);
+
+ if (n <= 0)
+ return n;
+
+ cda->cda_ac->ac_nonce = nextnonce;
+
+ return 1;
+}
+
+/**Create a digest authorization header.
+ *
+ * Creates a digest authorization header from username @a user and password
+ * @a pass, client nonce @a cnonce, client nonce count @a nc, request method
+ * @a method, request URI @a uri and message body @a data. The authorization
+ * header type is determined by @a hc - it can be either
+ * sip_authorization_class or sip_proxy_authorization_class, as well as
+ * http_authorization_class or http_proxy_authorization_class.
+ *
+ * @return
+ * Returns a pointer to newly created authorization header, or NULL upon an
+ * error.
+ */
+static
+int auc_digest_authorization(auth_client_t *ca,
+ su_home_t *home,
+ char const *method,
+ url_t const *url,
+ msg_payload_t const *body,
+ msg_header_t **return_headers)
+{
+ auth_digest_client_t *cda = (auth_digest_client_t *)ca;
+ msg_hclass_t *hc = ca->ca_credential_class;
+ char const *user = ca->ca_user;
+ char const *pass = ca->ca_pass;
+ auth_challenge_t const *ac = cda->cda_ac;
+ char const *cnonce = cda->cda_cnonce;
+ unsigned nc = ++cda->cda_ncount;
+ char *uri = url_as_string(home, url);
+ void const *data = body ? body->pl_data : "";
+ usize_t dlen = body ? body->pl_len : 0;
+
+ msg_header_t *h;
+ auth_hexmd5_t sessionkey, response;
+ auth_response_t ar[1] = {{ 0 }};
+ char ncount[17];
+
+ ar->ar_size = sizeof(ar);
+ ar->ar_username = user;
+ ar->ar_realm = ac->ac_realm;
+ ar->ar_nonce = ac->ac_nonce;
+ ar->ar_algorithm = NULL;
+ ar->ar_md5 = ac->ac_md5;
+ ar->ar_md5sess = ac->ac_md5sess;
+ ar->ar_opaque = ac->ac_opaque;
+ ar->ar_qop = NULL;
+ ar->ar_auth = ac->ac_auth;
+ ar->ar_auth_int = ac->ac_auth_int;
+ ar->ar_uri = uri;
+
+ /* If there is no qop, we MUST NOT include cnonce or nc */
+ if (!ar->ar_auth && !ar->ar_auth_int)
+ cnonce = NULL;
+
+ if (cnonce) {
+ snprintf(ncount, sizeof(ncount), "%08x", nc);
+ ar->ar_cnonce = cnonce;
+ ar->ar_nc = ncount;
+ }
+
+ auth_digest_sessionkey(ar, sessionkey, pass);
+ auth_digest_response(ar, response, sessionkey, method, data, dlen);
+
+ h = msg_header_format(home, hc,
+ "Digest "
+ "username=\"%s\", "
+ "realm=\"%s\", "
+ "nonce=\"%s"
+ "%s%s"
+ "%s%s"
+ "%s%s, "
+ "uri=\"%s\", "
+ "response=\"%s\""
+ "%s%s"
+ "%s%s",
+ ar->ar_username,
+ ar->ar_realm,
+ ar->ar_nonce,
+ cnonce ? "\", cnonce=\"" : "",
+ cnonce ? cnonce : "",
+ ar->ar_opaque ? "\", opaque=\"" : "",
+ ar->ar_opaque ? ar->ar_opaque : "",
+ ar->ar_algorithm ? "\", algorithm=" : "",
+ ar->ar_algorithm ? ar->ar_algorithm : "",
+ ar->ar_uri,
+ response,
+ ar->ar_auth || ar->ar_auth_int ? ", qop=" : "",
+ ar->ar_auth_int ? "auth-int" :
+ (ar->ar_auth ? "auth" : ""),
+ cnonce ? ", nc=" : "",
+ cnonce ? ncount : "");
+
+ su_free(home, uri);
+
+ if (!h)
+ return -1;
+ *return_headers = h;
+ return 0;
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+#define MAX_AUC 20
+
+static auth_client_plugin_t const *ca_plugins[MAX_AUC] =
+{
+ &ca_digest_plugin, &ca_basic_plugin, NULL
+};
+
+/** Register an authentication client plugin */
+int auc_register_plugin(auth_client_plugin_t const *plugin)
+{
+ int i;
+
+ if (plugin == NULL ||
+ plugin->auc_name == NULL ||
+ plugin->auc_authorize == NULL)
+ return errno = EFAULT, -1;
+
+ if (plugin->auc_size < (int) sizeof (auth_client_t))
+ return errno = EINVAL, -1;
+
+ for (i = 0; i < MAX_AUC; i++) {
+ if (ca_plugins[i] == NULL ||
+ strcmp(plugin->auc_name, ca_plugins[i]->auc_name) == 0) {
+ ca_plugins[i] = plugin;
+ return 0;
+ }
+ }
+
+ return errno = ENOMEM, -1;
+}
+
+/** Allocate an (possibly extended) auth_client_t structure. */
+static
+auth_client_t *ca_create(su_home_t *home,
+ char const *scheme,
+ char const *realm)
+{
+ auth_client_plugin_t const *auc = NULL;
+ auth_client_t *ca;
+ size_t aucsize = (sizeof *ca), realmlen, size;
+ char *s;
+ int i;
+
+ if (scheme == NULL || realm == NULL)
+ return (void)(errno = EFAULT), NULL;
+
+ realmlen = strlen(realm) + 1;
+
+ for (i = 0; i < MAX_AUC; i++) {
+ auc = ca_plugins[i];
+ if (!auc || strcasecmp(auc->auc_name, scheme) == 0)
+ break;
+ }
+
+ aucsize = auc ? (size_t)auc->auc_size : (sizeof *ca);
+ size = aucsize + realmlen;
+ if (!auc)
+ size += strlen(scheme) + 1;
+
+ ca = su_home_clone(home, (isize_t)size);
+ if (!ca)
+ return ca;
+
+ s = (char *)ca + aucsize;
+ ca->ca_auc = auc;
+ ca->ca_realm = strcpy(s, realm);
+ ca->ca_scheme = auc ? auc->auc_name : strcpy(s + realmlen, scheme);
+
+ return ca;
+}
+
+void ca_destroy(su_home_t *home, auth_client_t *ca)
+{
+ su_free(home, ca);
+}
+
+
+#if HAVE_SOFIA_SIP
+#include <sofia-sip/sip.h>
+
+/**Authorize a SIP request.
+ *
+ * The function auc_authorize() is used to add correct authentication
+ * headers to a SIP request. The authentication headers will contain the
+ * credentials generated by the list of authenticators.
+ *
+ * @param[in,out] auc_list list of authenticators
+ * @param[in,out] msg message to be authenticated
+ * @param[in,out] sip sip headers of the message
+ *
+ * @retval 1 when successful
+ * @retval 0 when there is not enough credentials
+ * @retval -1 upon an error
+ */
+int auc_authorize(auth_client_t **auc_list, msg_t *msg, sip_t *sip)
+{
+ sip_request_t *rq = sip ? sip->sip_request : NULL;
+
+ if (!rq)
+ return 0;
+
+ return auc_authorization(auc_list, msg, (msg_pub_t *)sip,
+ rq->rq_method_name,
+ /*
+ RFC 3261 defines the protection domain based
+ only on realm, so we do not bother get a
+ correct URI to auth module.
+ */
+ rq->rq_url,
+ sip->sip_payload);
+}
+#endif
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_client_ntlm.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_client_ntlm.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,239 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE auth_client_ntlm.c NTLM authenticator for SIP client
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed May 24 21:44:39 EEST 2006
+ */
+
+#include "config.h"
+
+#include <sofia-sip/su.h>
+#include <sofia-sip/su_md5.h>
+
+#include "sofia-sip/auth_ntlm.h"
+#include "sofia-sip/auth_client.h"
+#include "sofia-sip/auth_client_plugin.h"
+
+#include <sofia-sip/msg_header.h>
+
+#include <sofia-sip/auth_digest.h>
+
+#include <sofia-sip/base64.h>
+#include <sofia-sip/su_uniqueid.h>
+#include <sofia-sip/string0.h>
+
+#include <sofia-sip/su_debug.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <assert.h>
+
+typedef struct auth_ntlm_client_s
+{
+ auth_client_t ntlm_client;
+
+ int ntlm_ncount;
+ char const *ntlm_cnonce;
+ auth_challenge_t ntlm_ac[1];
+} auth_ntlm_client_t;
+
+static int auc_ntlm_challenge(auth_client_t *ca,
+ msg_auth_t const *ch);
+static int auc_ntlm_authorization(auth_client_t *ca,
+ su_home_t *h,
+ char const *method,
+ url_t const *url,
+ msg_payload_t const *body,
+ msg_header_t **);
+
+auth_client_plugin_t const _ntlm_client_plugin =
+{
+ sizeof ca_ntlm_plugin,
+ sizeof (auth_ntlm_client_t),
+ "NTLM",
+ auc_ntlm_challenge,
+ auc_ntlm_authorization
+};
+
+auth_client_plugin_t const * const ntlm_client_plugin = _ntlm_client_plugin;
+
+/** Store a ntlm authorization challenge.
+ */
+static int auc_ntlm_challenge(auth_client_t *ca, msg_auth_t const *ch)
+{
+ su_home_t *home = ca->ca_home;
+ auth_ntlm_client_t *ntlm = (auth_ntlm_client_t *)ca;
+ auth_challenge_t ac[1] = {{ sizeof ac }};
+ int stale;
+
+ if (auth_ntlm_challenge_get(home, ac, ch->au_params) < 0)
+ goto error;
+
+ /* Check that we can handle the challenge */
+ if (!ac->ac_md5 && !ac->ac_md5sess)
+ goto error;
+ if (ac->ac_qop && !ac->ac_auth && !ac->ac_auth_int)
+ goto error;
+
+ stale = ac->ac_stale || str0cmp(ac->ac_nonce, ntlm->ntlm_ac->ac_nonce);
+
+ if (ac->ac_qop && (ntlm->ntlm_cnonce == NULL || ac->ac_stale)) {
+ su_guid_t guid[1];
+ char *cnonce;
+ if (ntlm->ntlm_cnonce != NULL)
+ /* Free the old one if we are updating after stale=true */
+ su_free(home, (void *)ntlm->ntlm_cnonce);
+ su_guid_generate(guid);
+ ntlm->ntlm_cnonce = cnonce = su_alloc(home, BASE64_SIZE(sizeof(guid)) + 1);
+ base64_e(cnonce, BASE64_SIZE(sizeof(guid)) + 1, guid, sizeof(guid));
+ ntlm->ntlm_ncount = 0;
+ }
+
+ auth_ntlm_challenge_free_params(home, ntlm->ntlm_ac);
+
+ *ntlm->ntlm_ac = *ac;
+
+ return stale ? 2 : 1;
+
+ error:
+ auth_ntlm_challenge_free_params(home, ac);
+ return -1;
+}
+
+
+/**Create a NTLM authorization header.
+ *
+ * Creates a ntlm authorization header from username @a user and password
+ * @a pass, client nonce @a cnonce, client nonce count @a nc, request method
+ * @a method, request URI @a uri and message body @a data. The authorization
+ * header type is determined by @a hc - it can be either
+ * sip_authorization_class or sip_proxy_authorization_class, as well as
+ * http_authorization_class or http_proxy_authorization_class.
+ *
+ * @param home memory home used to allocate memory for the new header
+ * @param hc header class for the header to be created
+ * @param user user name
+ * @param pass password
+ * @param ac challenge structure
+ * @param cnonce client nonce
+ * @param nc client nonce count
+ * @param method request method
+ * @param uri request uri
+ * @param data message body
+ * @param dlen length of message body
+ *
+ * @return
+ * Returns a pointer to newly created authorization header, or NULL upon an
+ * error.
+ */
+int auc_ntlm_authorization(auth_client_t *ca,
+ su_home_t *home,
+ char const *method,
+ url_t const *url,
+ msg_payload_t const *body,
+ msg_header_t **return_headers)
+{
+ auth_ntlm_client_t *ntlm = (auth_ntlm_client_t *)ca;
+ msg_hclass_t *hc = ca->ca_credential_class;
+ char const *user = ca->ca_user;
+ char const *pass = ca->ca_pass;
+ auth_challenge_t const *ac = ntlm->ntlm_ac;
+ char const *cnonce = ntlm->ntlm_cnonce;
+ unsigned nc = ++ntlm->ntlm_ncount;
+ char *uri = url_as_string(home, url);
+ void const *data = body ? body->pl_data : "";
+ int dlen = body ? body->pl_len : 0;
+
+ msg_header_t *h;
+ auth_hexmd5_t sessionkey, response;
+ auth_response_t ar[1] = {{ 0 }};
+ char ncount[17];
+
+ ar->ar_size = sizeof(ar);
+ ar->ar_username = user;
+ ar->ar_realm = ac->ac_realm;
+ ar->ar_nonce = ac->ac_nonce;
+ ar->ar_algorithm = NULL;
+ ar->ar_md5 = ac->ac_md5;
+ ar->ar_md5sess = ac->ac_md5sess;
+ ar->ar_opaque = ac->ac_opaque;
+ ar->ar_qop = NULL;
+ ar->ar_auth = ac->ac_auth;
+ ar->ar_auth_int = ac->ac_auth_int;
+ ar->ar_uri = uri;
+
+ /* If there is no qop, we MUST NOT include cnonce or nc */
+ if (!ar->ar_auth && !ar->ar_auth_int)
+ cnonce = NULL;
+
+ if (cnonce) {
+ snprintf(ncount, sizeof(ncount), "%08x", nc);
+ ar->ar_cnonce = cnonce;
+ ar->ar_nc = ncount;
+ }
+
+ auth_ntlm_sessionkey(ar, sessionkey, pass);
+ auth_ntlm_response(ar, response, sessionkey, method, data, dlen);
+
+ h = msg_header_format(home, hc,
+ "NTLM "
+ "username=\"%s\", "
+ "realm=\"%s\", "
+ "nonce=\"%s"
+ "%s%s"
+ "%s%s"
+ "%s%s, "
+ "uri=\"%s\", "
+ "response=\"%s\""
+ "%s%s"
+ "%s%s",
+ ar->ar_username,
+ ar->ar_realm,
+ ar->ar_nonce,
+ cnonce ? "\", cnonce=\"" : "",
+ cnonce ? cnonce : "",
+ ar->ar_opaque ? "\", opaque=\"" : "",
+ ar->ar_opaque ? ar->ar_opaque : "",
+ ar->ar_algorithm ? "\", algorithm=" : "",
+ ar->ar_algorithm ? ar->ar_algorithm : "",
+ ar->ar_uri,
+ response,
+ ar->ar_auth || ar->ar_auth_int ? ", qop=" : "",
+ ar->ar_auth_int ? "auth-int" :
+ (ar->ar_auth ? "auth" : ""),
+ cnonce ? ", nc=" : "",
+ cnonce ? ncount : "");
+
+ su_free(home, uri);
+
+ if (!h)
+ return -1;
+ *return_headers = h;
+ return 0;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_common.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_common.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,203 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE auth_common.c
+ *
+ * Functions common to both client and server authentication.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Original Created: Thu Feb 22 12:10:37 2001 ppessi
+ * @date Created: Wed May 17 13:37:50 EEST 2006 ppessi
+ */
+
+#include "config.h"
+
+#include "sofia-sip/auth_common.h"
+#include "sofia-sip/msg_header.h"
+
+#include <string.h>
+#include <stdarg.h>
+#include <assert.h>
+
+#if !HAVE_STRCASESTR
+char *strcasestr(char const *haystack, char const *needle);
+#endif
+
+static inline int has_token(char const *qstring, char const *token);
+
+/**
+ * Parse authentication parameters.
+ *
+ * The function auth_get_params() searches for the authentication parameters
+ * in @a params. The parameter list @a params is seached for each parameter
+ * given in in vararg section, and if it is found, its value is assigned to
+ * the given address.
+ *
+ * @note The field name should contain the equal ("=") sign.
+ *
+ * @return
+ * The function auth_get_params() returns number of parameters found in
+ * params, or -1 upon an error.
+ */
+issize_t auth_get_params(su_home_t *home,
+ char const * const params[], ...
+ /* char const *fmt, char const **return_value */)
+{
+ int n, j;
+ size_t len, namelen;
+ char const *fmt, *expected;
+ char const *value, *p, **return_value;
+ va_list(ap);
+
+ assert(params);
+
+ if (!params) return -1;
+
+ va_start(ap, params);
+
+ for (n = 0; (fmt = va_arg(ap, char const *));) {
+ return_value = va_arg(ap, char const **);
+ len = strlen(fmt);
+ if (!len)
+ continue;
+ namelen = strcspn(fmt, "=");
+ expected = fmt + namelen + 1;
+ value = NULL;
+
+ if (expected[0]) {
+ /* value match: format is name=expected,
+ if expected is found in parameter value,
+ return non-NULL pointer in *return_value */
+ for (j = 0; (p = params[j++]);) {
+ if (strcasecmp(p, fmt) == 0) {
+ /* Matched the whole parameter with fmt name=expected */
+ value = p;
+ break;
+ }
+ else if (strncasecmp(p, fmt, namelen) ||
+ p[namelen] != '=')
+ continue;
+
+ p = p + namelen + 1;
+
+ if (p[0] == '"' && has_token(p, expected)) {
+ /* Quoted parameter value has expected value,
+ * e.g., qop=auth matches qop="auth,auth-int" */
+ value = p;
+ break;
+ }
+ else if (strcasecmp(p, expected) == 0) {
+ /* Parameter value matches with extected value
+ * e.g., qop=auth matches qop=auth */
+ value = p;
+ break;
+ }
+ }
+ }
+ else {
+ /* format is name= , return unquoted parameter value after = */
+ for (j = 0; (p = params[j++]);) {
+ if (strncasecmp(p, fmt, len))
+ continue;
+
+ if (p[len] == '"')
+ value = msg_unquote_dup(home, p + len);
+ else
+ value = su_strdup(home, p + len);
+
+ if (value == NULL)
+ return -1;
+
+ break;
+ }
+ }
+
+ if (value) {
+ *return_value = value;
+ n++;
+ }
+ }
+
+ va_end(ap);
+
+ return n;
+}
+
+int auth_struct_copy(void *dst, void const *src, isize_t s_size)
+{
+ int d_size = *(int *)dst;
+
+ if (d_size < 0)
+ return -1;
+
+ if ((size_t)d_size > s_size) {
+ memcpy(dst, src, s_size);
+ memset((char *)dst + s_size, 0, d_size - s_size);
+ }
+ else {
+ memcpy(dst, src, d_size);
+ *(int *)dst = d_size;
+ }
+ return 0;
+}
+
+static inline int has_token(char const *qstring, char const *token)
+{
+ size_t n = strlen(token);
+ char const *q;
+
+ q = strcasestr(qstring, token);
+ return (q &&
+ (q[n] == 0 || strchr("\", \t", q[n])) &&
+ (q == qstring || strchr("\", \t", q[-1])));
+}
+
+
+/** Compare two strings, even if they are quoted */
+int auth_strcmp(char const *quoted, char const *unquoted)
+{
+ size_t i, j;
+
+ if (quoted[0] != '"')
+ return strcmp(quoted, unquoted);
+
+ /* Compare quoted with unquoted */
+
+ for (i = 1, j = 0; ; i++, j++) {
+ char q = quoted[i], u = unquoted[j];
+
+ if (q == '"')
+ q = '\0';
+ else if (q == '\\' && u != '\0')
+ q = quoted[i++];
+
+ if (q - u)
+ return q - u;
+
+ if (q == '\0')
+ return 0;
+ }
+}
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_digest.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_digest.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,350 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE auth_digest.c
+ *
+ * Implementation for digest authentication.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Feb 22 12:10:37 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <sofia-sip/su_md5.h>
+#include "sofia-sip/auth_common.h"
+#include "sofia-sip/auth_digest.h"
+#include "sofia-sip/msg_header.h"
+#include "sofia-sip/auth_common.h"
+
+#include "iptsec_debug.h"
+
+#include <string.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <assert.h>
+
+/**Get digest-challenge parameters.
+ *
+ * The function digest_challenge_get() searches for the digest authentication
+ * parameters in @a params. The parameters are assigned to the appropriate
+ * fields in @a ac structure.
+ *
+ * @return
+ *
+ * The function digest_challenge_get() returns number of parameters
+ * found, or -1 upon an error.
+ */
+issize_t auth_digest_challenge_get(su_home_t *home,
+ auth_challenge_t *ac0,
+ char const * const params[])
+{
+ ssize_t n;
+ auth_challenge_t ac[1] = {{ 0 }};
+ char const *md5 = NULL, *md5sess = NULL, *sha1 = NULL,
+ *stale = NULL,
+ *qop_auth = NULL, *qop_auth_int = NULL;
+
+ ac->ac_size = sizeof(ac);
+
+ assert(ac0);
+ assert(ac0->ac_size >= (int) sizeof(*ac));
+
+ if (ac0 == NULL || params == NULL)
+ return -1;
+
+ n = auth_get_params(home, params,
+ "realm=", &ac->ac_realm,
+ "domain=", &ac->ac_domain,
+ "nonce=", &ac->ac_nonce,
+ "opaque=", &ac->ac_opaque,
+ "algorithm=", &ac->ac_algorithm,
+ "qop=", &ac->ac_qop,
+ "algorithm=md5", &md5,
+ "algorithm=md5-sess", &md5sess,
+ "algorithm=sha1", &sha1,
+ "stale=true", &stale,
+ "qop=auth", &qop_auth,
+ "qop=auth-int", &qop_auth_int,
+ NULL);
+ if (n < 0)
+ return n;
+
+ ac->ac_stale = stale != NULL;
+ ac->ac_md5 = md5 != NULL || ac->ac_algorithm == NULL;
+ ac->ac_md5sess = md5sess != NULL;
+ ac->ac_sha1 = sha1 != NULL;
+ ac->ac_auth = qop_auth != NULL;
+ ac->ac_auth_int = qop_auth_int != NULL;
+
+ auth_struct_copy(ac0, ac, sizeof(ac));
+
+ SU_DEBUG_5(("%s(): got "MOD_ZD"\n", "auth_digest_challenge_get", n));
+
+ return n;
+}
+
+/** Free challenge parameters */
+void auth_digest_challenge_free_params(su_home_t *home, auth_challenge_t *ac)
+{
+ if (ac->ac_realm)
+ su_free(home, (void *)ac->ac_realm), ac->ac_realm = NULL;
+ if (ac->ac_domain)
+ su_free(home, (void *)ac->ac_domain), ac->ac_domain = NULL;
+ if (ac->ac_nonce)
+ su_free(home, (void *)ac->ac_nonce), ac->ac_nonce = NULL;
+ if (ac->ac_opaque)
+ su_free(home, (void *)ac->ac_opaque), ac->ac_opaque = NULL;
+ if (ac->ac_algorithm)
+ su_free(home, (void *)ac->ac_algorithm), ac->ac_algorithm = NULL;
+ if (ac->ac_qop)
+ su_free(home, (void *)ac->ac_qop), ac->ac_qop = NULL;
+}
+
+/**Get digest-response parameters.
+ *
+ * The function auth_response_get() searches for the digest authentication
+ * parameters in @a params. The parameters are assigned to the appropriate
+ * fields in @a ar structure.
+ *
+ * @return
+ *
+ * The function auth_response_get() returns number of parameters
+ * found, or -1 upon an error.
+ */
+issize_t auth_digest_response_get(su_home_t *home,
+ auth_response_t *ar0,
+ char const *const params[])
+{
+ ssize_t n;
+ auth_response_t ar[1] = {{ 0 }};
+ char const *md5 = NULL, *md5sess = NULL, *sha1 = NULL,
+ *qop_auth = NULL, *qop_auth_int = NULL;
+
+ ar->ar_size = sizeof(ar);
+
+ assert(ar0); assert(params); assert(ar0->ar_size >= (int) sizeof(ar));
+
+ if (ar0 == NULL || params == NULL)
+ return -1;
+
+ n = auth_get_params(home, params,
+ "username=", &ar->ar_username,
+ "realm=", &ar->ar_realm,
+ "nonce=", &ar->ar_nonce,
+ "uri=", &ar->ar_uri,
+ "response=", &ar->ar_response,
+ "algorithm=", &ar->ar_algorithm,
+ "opaque=", &ar->ar_opaque,
+ "cnonce=", &ar->ar_cnonce,
+ "qop=", &ar->ar_qop,
+ "nc=", &ar->ar_nc,
+ "algorithm=md5", &md5,
+ "algorithm=md5-sess", &md5sess,
+ "algorithm=sha1", &sha1,
+ "qop=auth", &qop_auth,
+ "qop=auth-int", &qop_auth_int,
+ NULL);
+ if (n < 0)
+ return n;
+
+ ar->ar_md5 = md5 != NULL || ar->ar_algorithm == NULL;
+ ar->ar_md5sess = md5sess != NULL;
+ ar->ar_sha1 = sha1 != NULL;
+ ar->ar_auth = qop_auth != NULL;
+ ar->ar_auth_int = qop_auth_int != NULL;
+
+ auth_struct_copy(ar0, ar, sizeof(ar));
+
+ SU_DEBUG_7(("%s: "MOD_ZD"\n", "auth_digest_response_get", n));
+
+ return n;
+}
+
+static void unquote_update(su_md5_t md5[1], char const *quoted)
+{
+ if (!quoted)
+ /*xyzzy*/;
+ else if (quoted[0] == '"') {
+ char const *q;
+ size_t n;
+
+ for (q = quoted + 1; *q; q += n + 2) {
+ n = strcspn(q, "\"\\");
+ su_md5_update(md5, q, n);
+ if (q[n] == '"' || q[n] == '\0')
+ break;
+ su_md5_update(md5, q + n + 1, 1);
+ }
+ }
+ else
+ su_md5_strupdate(md5, quoted);
+}
+
+/** Generate A1 hash for digest authentication.
+ */
+int auth_digest_a1(auth_response_t *ar,
+ auth_hexmd5_t ha1,
+ char const *secret)
+{
+ su_md5_t md5[1];
+
+ /* Calculate A1 */
+ su_md5_init(md5);
+ su_md5_strupdate(md5, ar->ar_username);
+ su_md5_update(md5, ":", 1);
+ unquote_update(md5, ar->ar_realm);
+ su_md5_update(md5, ":", 1);
+ su_md5_strupdate(md5, secret);
+
+ su_md5_hexdigest(md5, ha1);
+
+ SU_DEBUG_5(("auth_digest_a1() has A1 = MD5(%s:%s:%s) = %s\n",
+ ar->ar_username, ar->ar_realm, secret, ha1));
+
+ return 0;
+}
+
+int auth_digest_a1sess(auth_response_t *ar,
+ auth_hexmd5_t ha1sess,
+ char const *ha1)
+{
+ su_md5_t md5[1];
+
+ su_md5_init(md5);
+ su_md5_strupdate(md5, ha1);
+ su_md5_update(md5, ":", 1);
+ unquote_update(md5, ar->ar_nonce);
+ su_md5_update(md5, ":", 1);
+ unquote_update(md5, ar->ar_cnonce);
+
+ su_md5_hexdigest(md5, ha1sess);
+
+ SU_DEBUG_5(("auth_sessionkey has A1' = MD5(%s:%s:%s) = %s\n",
+ ha1, ar->ar_nonce, ar->ar_cnonce, ha1sess));
+
+ return 0;
+}
+
+/** Generate MD5 session key for digest authentication.
+ */
+int auth_digest_sessionkey(auth_response_t *ar,
+ auth_hexmd5_t ha1,
+ char const *secret)
+{
+ if (ar->ar_md5sess)
+ ar->ar_algorithm = "MD5-sess";
+ else if (ar->ar_md5)
+ ar->ar_algorithm = "MD5";
+ else
+ return -1;
+
+ if (ar->ar_md5sess) {
+ auth_hexmd5_t base_ha1;
+ auth_digest_a1(ar, base_ha1, secret);
+ auth_digest_a1sess(ar, ha1, base_ha1);
+ } else {
+ auth_digest_a1(ar, ha1, secret);
+ }
+
+ return 0;
+}
+
+/** Generate response for digest authentication.
+ *
+ */
+int auth_digest_response(auth_response_t *ar,
+ auth_hexmd5_t response,
+ auth_hexmd5_t const ha1,
+ char const *method_name,
+ void const *data, isize_t dlen)
+{
+ su_md5_t md5[1];
+ auth_hexmd5_t Hentity, HA2;
+
+ if (ar->ar_auth_int)
+ ar->ar_qop = "auth-int";
+ else if (ar->ar_auth)
+ ar->ar_qop = "auth";
+ else
+ ar->ar_qop = NULL;
+
+ /* Calculate Hentity */
+ if (ar->ar_auth_int) {
+ if (data && dlen) {
+ su_md5_init(md5);
+ su_md5_update(md5, data, dlen);
+ su_md5_hexdigest(md5, Hentity);
+ } else {
+ strcpy(Hentity, "d41d8cd98f00b204e9800998ecf8427e");
+ }
+ }
+
+ /* Calculate A2 */
+ su_md5_init(md5);
+ su_md5_strupdate(md5, method_name);
+ su_md5_update(md5, ":", 1);
+ unquote_update(md5, ar->ar_uri);
+ if (ar->ar_auth_int) {
+ su_md5_update(md5, ":", 1);
+ su_md5_update(md5, Hentity, sizeof(Hentity) - 1);
+ }
+ su_md5_hexdigest(md5, HA2);
+
+ SU_DEBUG_5(("A2 = MD5(%s:%s%s%s)\n", method_name, ar->ar_uri,
+ ar->ar_auth_int ? ":" : "", ar->ar_auth_int ? Hentity : ""));
+
+ /* Calculate response */
+ su_md5_init(md5);
+ su_md5_update(md5, ha1, 32);
+ su_md5_update(md5, ":", 1);
+ unquote_update(md5, ar->ar_nonce);
+
+ if (ar->ar_auth || ar->ar_auth_int) {
+ su_md5_update(md5, ":", 1);
+ su_md5_strupdate(md5, ar->ar_nc);
+ su_md5_update(md5, ":", 1);
+ unquote_update(md5, ar->ar_cnonce);
+ su_md5_update(md5, ":", 1);
+ su_md5_strupdate(md5, ar->ar_qop);
+ }
+
+ su_md5_update(md5, ":", 1);
+ su_md5_update(md5, HA2, 32);
+ su_md5_hexdigest(md5, response);
+
+ SU_DEBUG_5(("auth_response: %s = MD5(%s:%s%s%s%s%s%s%s:%s) (qop=%s)\n",
+ response, ha1, ar->ar_nonce,
+ ar->ar_auth || ar->ar_auth_int ? ":" : "",
+ ar->ar_auth || ar->ar_auth_int ? ar->ar_nc : "",
+ ar->ar_auth || ar->ar_auth_int ? ":" : "",
+ ar->ar_auth || ar->ar_auth_int ? ar->ar_cnonce : "",
+ ar->ar_auth || ar->ar_auth_int ? ":" : "",
+ ar->ar_auth || ar->ar_auth_int ? ar->ar_qop : "",
+ HA2,
+ ar->ar_qop ? ar->ar_qop : "NONE"));
+
+ return 0;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_module.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_module.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1529 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE auth_module.c
+ * @brief Authentication verification module
+ *
+ * The authentication module provides server or proxy-side authentication
+ * verification for network elements like registrars, presence servers, and
+ * proxies.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Wed Apr 11 15:14:03 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <sofia-sip/auth_digest.h>
+
+#include "iptsec_debug.h"
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+static char const __func__[] = "auth_mod";
+#endif
+
+#include <sofia-sip/su_debug.h>
+
+#include <sofia-sip/su_wait.h>
+#include <sofia-sip/su_alloc.h>
+#include <sofia-sip/su_tagarg.h>
+
+#include <sofia-sip/base64.h>
+#include <sofia-sip/su_md5.h>
+
+#include <sofia-sip/msg_parser.h>
+#include <sofia-sip/msg_date.h>
+
+#include "sofia-sip/auth_module.h"
+#include "sofia-sip/auth_plugin.h"
+
+#define APW_HASH(apw) ((apw)->apw_index)
+
+char const auth_internal_server_error[] = "Internal server error";
+
+static void auth_md5_hmac_key(auth_mod_t *am);
+
+HTABLE_PROTOS_WITH(auth_htable, aht, auth_passwd_t, usize_t, unsigned);
+HTABLE_BODIES_WITH(auth_htable, aht, auth_passwd_t, APW_HASH,
+ usize_t, unsigned);
+
+/**Allocate an authentication module instance.
+ *
+ * The function auth_mod_alloc() allocates an authentication module object.
+ *
+ */
+auth_mod_t *auth_mod_alloc(auth_scheme_t *scheme,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ auth_mod_t *am = NULL;
+
+ if ((am = su_home_new(scheme->asch_size))) {
+ am->am_scheme = scheme;
+ am->am_refcount = 1;
+ }
+
+ return am;
+}
+
+/**Initialize an authentication module instance.
+ *
+ * The function auth_mod_init_default() initializes an authentication module
+ * object used to authenticate the requests.
+ *
+ * @param am
+ * @param base
+ * @param root
+ * @param tag,value,... tagged argument list
+ *
+ * @TAGS
+ * AUTHTAG_REALM(), AUTHTAG_OPAQUE(), AUTHTAG_DB(), AUTHTAG_QOP(),
+ * AUTHTAG_ALGORITHM(), AUTHTAG_EXPIRES(), AUTHTAG_NEXT_EXPIRES(),
+ * AUTHTAG_BLACKLIST(), AUTHTAG_FORBIDDEN(), AUTHTAG_ANONYMOUS(),
+ * AUTHTAG_FAKE(), AUTHTAG_ALLOW(), AUTHTAG_REMOTE(), and
+ * AUTHTAG_MASTER_KEY().
+ *
+ * @return 0 if successful
+ * @return -1 upon an error
+ */
+int auth_init_default(auth_mod_t *am,
+ auth_scheme_t *base,
+ su_root_t *root,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ int retval = 0;
+
+ ta_list ta;
+
+ char const *realm = NULL, *opaque = NULL, *db = NULL, *allows = NULL;
+ char const *qop = NULL, *algorithm = NULL;
+ unsigned expires = 60 * 60, next_expires = 5 * 60;
+ unsigned blacklist = 5;
+ int forbidden = 0;
+ int anonymous = 0;
+ int fake = 0;
+ url_string_t const *remote = NULL;
+ char const *master_key = "fish";
+ char *s;
+
+ ta_start(ta, tag, value);
+
+ /* Authentication stuff */
+ tl_gets(ta_args(ta),
+ AUTHTAG_REALM_REF(realm),
+ AUTHTAG_OPAQUE_REF(opaque),
+ AUTHTAG_DB_REF(db),
+ AUTHTAG_QOP_REF(qop),
+ AUTHTAG_ALGORITHM_REF(algorithm),
+ AUTHTAG_EXPIRES_REF(expires),
+ AUTHTAG_NEXT_EXPIRES_REF(next_expires),
+ AUTHTAG_BLACKLIST_REF(blacklist),
+ AUTHTAG_FORBIDDEN_REF(forbidden),
+ AUTHTAG_ANONYMOUS_REF(anonymous),
+ AUTHTAG_FAKE_REF(fake),
+ AUTHTAG_ALLOW_REF(allows),
+ AUTHTAG_REMOTE_REF(remote),
+ AUTHTAG_MASTER_KEY_REF(master_key),
+ TAG_NULL());
+
+ if (!realm) realm = "*";
+ if (!allows) allows = "ACK, BYE, CANCEL";
+
+ am->am_realm = su_strdup(am->am_home, realm);
+ am->am_opaque = su_strdup(am->am_home, opaque);
+ am->am_db = su_strdup(am->am_home, db);
+ s = su_strdup(am->am_home, allows);
+ if (s)
+ msg_commalist_d(am->am_home, &s, &am->am_allow, NULL);
+ am->am_expires = expires;
+ am->am_next_exp = next_expires;
+ am->am_blacklist = blacklist;
+ am->am_forbidden = forbidden;
+ am->am_anonymous = anonymous;
+ am->am_fake = fake;
+ am->am_remote = url_hdup(am->am_home, (url_t *)remote);
+ am->am_algorithm = algorithm ? su_strdup(am->am_home, algorithm) : "MD5";
+ am->am_nextnonce = !algorithm || strcasecmp(algorithm, "MD5") == 0;
+ if (next_expires == 0)
+ am->am_nextnonce = 0;
+ am->am_qop = su_strdup(am->am_home, qop);
+
+ if (master_key) {
+ su_md5_t md5[1];
+
+ su_md5_init(md5);
+ su_md5_strupdate(md5, master_key);
+ su_md5_strupdate(md5, "70P 53KR37");
+ su_md5_digest(md5, am->am_master_key);
+ }
+
+ auth_md5_hmac_key(am);
+
+ /* Make sure that we have something
+ that can be used to identify credentials */
+ if (am->am_opaque && strcmp(am->am_opaque, "*") == 0) {
+#ifndef HOST_NAME_MAX
+#define HOST_NAME_MAX 255
+#endif
+ char hostname[HOST_NAME_MAX + 1];
+ su_md5_t md5[1];
+ uint8_t hmac[6];
+
+ gethostname(hostname, sizeof hostname);
+
+ auth_md5_hmac_init(am, md5);
+
+ su_md5_strupdate(md5, hostname);
+ su_md5_update(md5, ":", 1);
+ if (am->am_remote)
+ url_update(md5, am->am_remote);
+
+ auth_md5_hmac_digest(am, md5, hmac, sizeof hmac);
+
+ base64_e(hostname, sizeof hostname, hmac, sizeof hmac);
+
+ am->am_opaque = su_strdup(am->am_home, hostname);
+
+ if (!am->am_opaque) {
+ retval = -1;
+ SU_DEBUG_1(("%s: cannot create unique identifier\n", __func__));
+ }
+ }
+
+ if (retval < 0)
+ ;
+ else if (db) {
+ retval = auth_readdb(am);
+ if (retval == -1) {
+ int err = errno;
+ SU_DEBUG_1(("auth-module: %s: %s\n", am->am_db, strerror(err)));
+ errno = err;
+ }
+ }
+ else {
+ retval = auth_htable_resize(am->am_home, am->am_users, 0);
+ }
+
+ ta_end(ta);
+
+ return retval;
+}
+
+/** Destroy (a reference to) an authentication module. */
+void auth_mod_destroy(auth_mod_t *am)
+{
+ if (am && am->am_refcount != 0 && --am->am_refcount == 0) {
+ am->am_scheme->asch_destroy(am);
+ su_home_zap(am->am_home);
+ }
+}
+
+/** Do-nothing destroy function.
+ *
+ * The auth_destroy_default() is the default member function called by
+ * auth_mod_destroy().
+ */
+void auth_destroy_default(auth_mod_t *am)
+{
+}
+
+/** Create a new reference to authentication module. */
+auth_mod_t *auth_mod_ref(auth_mod_t *am)
+{
+ if (!am || am->am_refcount == 0)
+ return NULL;
+
+ am->am_refcount++;
+
+ return am;
+}
+
+/** Destroy a reference to an authentication module. */
+void auth_mod_unref(auth_mod_t *am)
+{
+ auth_mod_destroy(am);
+}
+
+/** Get authenticatin module name. @NEW_1_12_4. */
+char const *auth_mod_name(auth_mod_t *am)
+{
+ return am ? am->am_scheme->asch_method : "<nil>";
+}
+
+/** Initialize a auth_status_t stucture.
+ *
+ * @retval NULL upon an error
+ * @relates auth_status_t
+ */
+auth_status_t *auth_status_init(void *p, isize_t size)
+{
+ return auth_status_init_with(p, size, 500, auth_internal_server_error);
+}
+
+/** Initialize a auth_status_t stucture.
+ *
+ * @retval NULL upon an error
+ * @relates auth_status_t
+ */
+auth_status_t *auth_status_init_with(void *p,
+ isize_t size,
+ int status,
+ char const *phrase)
+{
+ auth_status_t *as;
+
+ if (!p || size < (sizeof *as))
+ return NULL;
+
+ if (size > INT_MAX) size = INT_MAX;
+
+ as = memset(p, 0, size);
+ as->as_home->suh_size = (int)size;
+
+ /* su_home_init(as->as_home); */
+
+ as->as_status = status, as->as_phrase = phrase;
+
+ return as;
+}
+
+/** Allocate a new auth_status_t structure. @relates auth_status_t */
+
+auth_status_t *auth_status_new(su_home_t *home)
+{
+ auth_status_t *as = su_home_clone(home, (sizeof *as));
+ if (as) {
+ as->as_status = 500;
+ as->as_phrase = auth_internal_server_error;
+ }
+ return as;
+}
+
+/** Create a new reference to an auth_status_t structure.
+ * @relates auth_status_t
+ */
+auth_status_t *auth_status_ref(auth_status_t *as)
+{
+ return (auth_status_t *)su_home_ref(as->as_home);
+}
+
+/** Destroy (a reference to) an auth_status_t structure. @relates auth_status_t
+ */
+void auth_status_unref(auth_status_t *as)
+{
+ su_home_unref(as->as_home);
+}
+
+/** Authenticate user.
+ *
+ * The function auth_mod_method() invokes scheme-specific authentication
+ * operation where the user's credentials are checked using scheme-specific
+ * method. The authentication result along with an optional challenge header
+ * is stored in the @a as structure.
+ *
+ * @param am pointer to authentication module object [in]
+ * @param as pointer to authentication status structure [in/out]
+ * @param credentials pointer to a header with user's credentials [in]
+ * @param ach pointer to a structure describing challenge [in]
+ *
+ * The @a ach structure defines what kind of response and challenge header
+ * is returned to the user. For example, a server authentication is
+ * implemented with 401 response code and phrase along with WWW-Authenticate
+ * header template in the @a ach structure.
+ *
+ * The auth_mod_method() returns the authentication result in the
+ * #auth_mod_t @a as structure. The @a as->as_status describes the result
+ * as follows:
+ * - <i>as->as_status == 0</i> authentication is successful
+ * - <i>as->as_status == 100</i> authentication is pending
+ * - <i>as->as_status >= 400</i> authentication fails,
+ * return as_status as an error code to client
+ *
+ * When the authentication is left pending, the client must set the
+ * as_callback pointer in @a as structure to an appropriate callback
+ * function. The callback is invoked when the authentication is completed,
+ * either successfully or with an error.
+ *
+ * Note that the authentication module may generate a new challenge each
+ * time authentication is used (e.g., Digest using MD5 algorithm). Such a
+ * challenge header is stored in the @a as->as_response return-value field.
+ *
+ * @note The authentication plugin may use the given reference to @a as, @a
+ * credentials and @a ach structures until the asynchronous authentication
+ * completes. Therefore, they should not be allocated from stack unless
+ * application uses strictly synchronous authentication schemes only (Basic
+ * and Digest).
+ *
+ * @note This function should be called auth_mod_check().
+ */
+void auth_mod_verify(auth_mod_t *am,
+ auth_status_t *as,
+ msg_auth_t *credentials,
+ auth_challenger_t const *ach)
+{
+ char const *wildcard, *host;
+
+ if (!am || !as || !ach)
+ return;
+
+ wildcard = strchr(am->am_realm, '*');
+
+ host = as->as_domain;
+
+ /* Initialize per-request realm */
+ if (as->as_realm)
+ ;
+ else if (!wildcard) {
+ as->as_realm = am->am_realm;
+ }
+ else if (!host) {
+ return; /* Internal error */
+ }
+ else if (strcmp(am->am_realm, "*") == 0) {
+ as->as_realm = host;
+ }
+ else {
+ /* Replace * with hostpart */
+ as->as_realm = su_sprintf(as->as_home, "%.*s%s%s",
+ (int)(wildcard - am->am_realm), am->am_realm,
+ host,
+ wildcard + 1);
+ }
+
+ am->am_scheme->asch_check(am, as, credentials, ach);
+}
+
+/** Make a challenge header.
+ *
+ * This function invokes plugin-specific member function generating a
+ * challenge header. Client uses the challenge header contents when
+ * prompting the user for a username and password then generates its
+ * credential header using the parameters given in the challenge header.
+ *
+ * @param am pointer to authentication module object
+ * @param as pointer to authentication status structure (return-value)
+ * @param ach pointer to a structure describing challenge
+ *
+ * The auth_mod_challenge() returns the challenge header, appropriate
+ * response code and reason phrase in the #auth_status_t structure. The
+ * auth_mod_challenge() is currently always synchronous function.
+ */
+void auth_mod_challenge(auth_mod_t *am,
+ auth_status_t *as,
+ auth_challenger_t const *ach)
+{
+ if (am && as && ach)
+ am->am_scheme->asch_challenge(am, as, ach);
+}
+
+
+/** Cancel asynchronous authentication.
+ *
+ * The auth_mod_cancel() function cancels a pending authentication.
+ * Application can reclaim the authentication status, credential and
+ * challenger objects by using auth_mod_cancel().
+ */
+void auth_mod_cancel(auth_mod_t *am, auth_status_t *as)
+{
+ if (am && as)
+ am->am_scheme->asch_cancel(am, as);
+}
+
+/** Do-nothing cancel function.
+ *
+ * The auth_cancel_default() is the default member function called by
+ * auth_mod_cancel().
+ */
+void auth_cancel_default(auth_mod_t *am, auth_status_t *as)
+{
+}
+
+/* ====================================================================== */
+/* Basic authentication scheme */
+
+static void auth_method_basic_x(auth_mod_t *am,
+ auth_status_t *as,
+ msg_auth_t *au,
+ auth_challenger_t const *ach);
+
+auth_scheme_t auth_scheme_basic[1] =
+ {{
+ "Basic", /* asch_method */
+ sizeof (auth_mod_t), /* asch_size */
+ auth_init_default, /* asch_init */
+ auth_method_basic_x, /* asch_check */
+ auth_challenge_basic, /* asch_challenge */
+ auth_cancel_default, /* asch_cancel */
+ auth_destroy_default /* asch_destroy */
+ }};
+
+/**Authenticate a request with @b Basic authentication.
+ *
+ * This function reads user database before authentication, if needed.
+ */
+static
+void auth_method_basic_x(auth_mod_t *am,
+ auth_status_t *as,
+ msg_auth_t *au,
+ auth_challenger_t const *ach)
+{
+ if (am) {
+ auth_readdb_if_needed(am);
+ auth_method_basic(am, as, au, ach);
+ }
+}
+
+/** Authenticate a request with @b Basic authentication scheme.
+ *
+ */
+void auth_method_basic(auth_mod_t *am,
+ auth_status_t *as,
+ msg_auth_t *au,
+ auth_challenger_t const *ach)
+{
+ char *userpass, buffer[128];
+ size_t n, upsize;
+ char *pass;
+ auth_passwd_t *apw;
+
+ if (!as->as_realm)
+ return;
+
+ userpass = buffer, upsize = sizeof buffer;
+
+ for (au = auth_mod_credentials(au, "Basic", NULL);
+ au;
+ au = auth_mod_credentials(au->au_next, "Basic", NULL)) {
+ if (!au->au_params)
+ continue;
+ n = base64_d(userpass, upsize - 1, au->au_params[0]);
+ if (n < 0 || n >= INT_MAX)
+ continue;
+ if (n >= upsize) {
+ upsize = n + 1;
+ userpass = realloc(userpass == buffer ? NULL : userpass, upsize);
+ if (userpass == NULL)
+ continue;
+ base64_d(userpass, upsize - 1, au->au_params[0]);
+ }
+ userpass[n] = 0;
+ if (!(pass = strchr(userpass, ':')))
+ continue;
+ *pass++ = '\0';
+ SU_DEBUG_5(("auth_method_basic: %s => %s:%s\n",
+ au->au_params[0], userpass, pass));
+
+ if (!(apw = auth_mod_getpass(am, userpass, as->as_realm)))
+ continue;
+ if (strcmp(apw->apw_pass, pass))
+ continue;
+
+ as->as_user = apw->apw_user;
+ as->as_anonymous = apw == am->am_anon_user;
+ as->as_ident = apw->apw_ident;
+ as->as_match = (msg_header_t *)au;
+ as->as_status = 0; /* Successful authentication! */
+
+ break;
+ }
+
+ if (userpass != buffer)
+ free(userpass);
+
+ if (au)
+ return;
+
+ if (auth_allow_check(am, as))
+ auth_challenge_basic(am, as, ach);
+}
+
+/** Construct a challenge header for @b Basic authentication scheme. */
+void auth_challenge_basic(auth_mod_t *am,
+ auth_status_t *as,
+ auth_challenger_t const *ach)
+{
+ as->as_status = ach->ach_status;
+ as->as_phrase = ach->ach_phrase;
+ as->as_response = msg_header_format(as->as_home, ach->ach_header,
+ "Basic realm=\"%s\"", as->as_realm);
+}
+
+/* ====================================================================== */
+/* Digest authentication scheme */
+
+static void auth_method_digest_x(auth_mod_t *am,
+ auth_status_t *as,
+ msg_auth_t *au,
+ auth_challenger_t const *ach);
+
+auth_scheme_t auth_scheme_digest[1] =
+ {{
+ "Digest", /* asch_method */
+ sizeof (auth_mod_t), /* asch_size */
+ auth_init_default, /* asch_init */
+ auth_method_digest_x, /* asch_check */
+ auth_challenge_digest, /* asch_challenge */
+ auth_cancel_default, /* asch_cancel */
+ auth_destroy_default /* asch_destroy */
+ }};
+
+struct nonce {
+ msg_time_t issued;
+ uint32_t count;
+ uint16_t nextnonce;
+ uint8_t digest[6];
+};
+
+#define AUTH_DIGEST_NONCE_LEN (BASE64_SIZE(sizeof (struct nonce)) + 1)
+
+/** Authenticate a request with @b Digest authentication scheme.
+ *
+ * This function reads user database before authentication, if needed.
+ */
+static
+void auth_method_digest_x(auth_mod_t *am,
+ auth_status_t *as,
+ msg_auth_t *au,
+ auth_challenger_t const *ach)
+{
+ if (am) {
+ auth_readdb_if_needed(am);
+ auth_method_digest(am, as, au, ach);
+ }
+}
+
+/** Authenticate a request with @b Digest authentication scheme.
+ */
+void auth_method_digest(auth_mod_t *am,
+ auth_status_t *as,
+ msg_auth_t *au,
+ auth_challenger_t const *ach)
+{
+ as->as_allow = as->as_allow || auth_allow_check(am, as) == 0;
+
+ if (as->as_realm)
+ au = auth_digest_credentials(au, as->as_realm, am->am_opaque);
+ else
+ au = NULL;
+
+ if (as->as_allow) {
+ SU_DEBUG_5(("%s: allow unauthenticated %s\n", __func__, as->as_method));
+ as->as_status = 0, as->as_phrase = NULL;
+ as->as_match = (msg_header_t *)au;
+ return;
+ }
+
+ if (au) {
+ auth_response_t ar[1] = {{ sizeof(ar) }};
+ auth_digest_response_get(as->as_home, ar, au->au_params);
+ as->as_match = (msg_header_t *)au;
+ auth_check_digest(am, as, ar, ach);
+ }
+ else {
+ /* There was no matching credentials, send challenge */
+ SU_DEBUG_5(("%s: no credentials matched\n", __func__));
+ auth_challenge_digest(am, as, ach);
+ }
+}
+
+/** Verify digest authentication */
+void auth_check_digest(auth_mod_t *am,
+ auth_status_t *as,
+ auth_response_t *ar,
+ auth_challenger_t const *ach)
+{
+ char const *a1;
+ auth_hexmd5_t a1buf, response;
+ auth_passwd_t *apw;
+ char const *phrase;
+ msg_time_t now = msg_now();
+
+ if (am == NULL || as == NULL || ar == NULL || ach == NULL) {
+ if (as) {
+ as->as_status = 500, as->as_phrase = "Internal Server Error";
+ as->as_response = NULL;
+ }
+ return;
+ }
+
+ phrase = "Bad authorization";
+
+#define PA "Authorization missing "
+
+ if ((!ar->ar_username && (phrase = PA "username")) ||
+ (!ar->ar_nonce && (phrase = PA "nonce")) ||
+ (!ar->ar_uri && (phrase = PA "URI")) ||
+ (!ar->ar_response && (phrase = PA "response")) ||
+ /* (!ar->ar_opaque && (phrase = PA "opaque")) || */
+ /* Check for qop */
+ (ar->ar_qop &&
+ ((ar->ar_auth &&
+ strcasecmp(ar->ar_qop, "auth") &&
+ strcasecmp(ar->ar_qop, "\"auth\"")) ||
+ (ar->ar_auth_int &&
+ strcasecmp(ar->ar_qop, "auth-int") &&
+ strcasecmp(ar->ar_qop, "\"auth-int\"")))
+ && (phrase = PA "has invalid qop"))) {
+ assert(phrase);
+ SU_DEBUG_5(("auth_method_digest: 400 %s\n", phrase));
+ as->as_status = 400, as->as_phrase = phrase;
+ as->as_response = NULL;
+ return;
+ }
+
+ if (as->as_nonce_issued == 0 /* Already validated nonce */ &&
+ auth_validate_digest_nonce(am, as, ar, now) < 0) {
+ as->as_blacklist = am->am_blacklist;
+ auth_challenge_digest(am, as, ach);
+ return;
+ }
+
+ if (as->as_stale) {
+ auth_challenge_digest(am, as, ach);
+ return;
+ }
+
+ apw = auth_mod_getpass(am, ar->ar_username, ar->ar_realm);
+
+ if (apw && apw->apw_hash)
+ a1 = apw->apw_hash;
+ else if (apw && apw->apw_pass)
+ auth_digest_a1(ar, a1buf, apw->apw_pass), a1 = a1buf;
+ else
+ auth_digest_a1(ar, a1buf, "xyzzy"), a1 = a1buf, apw = NULL;
+
+ if (ar->ar_md5sess)
+ auth_digest_a1sess(ar, a1buf, a1), a1 = a1buf;
+
+ auth_digest_response(ar, response, a1,
+ as->as_method, as->as_body, as->as_bodylen);
+
+ if (!apw || strcmp(response, ar->ar_response)) {
+
+ if (am->am_forbidden) {
+ as->as_status = 403, as->as_phrase = "Forbidden";
+ as->as_response = NULL;
+ as->as_blacklist = am->am_blacklist;
+ }
+ else {
+ auth_challenge_digest(am, as, ach);
+ as->as_blacklist = am->am_blacklist;
+ }
+ SU_DEBUG_5(("auth_method_digest: response did not match\n"));
+
+ return;
+ }
+
+ assert(apw);
+
+ as->as_user = apw->apw_user;
+ as->as_anonymous = apw == am->am_anon_user;
+ as->as_ident = apw->apw_ident;
+
+ if (am->am_nextnonce || am->am_mutual)
+ auth_info_digest(am, as, ach);
+
+ if (am->am_challenge)
+ auth_challenge_digest(am, as, ach);
+
+ SU_DEBUG_7(("auth_method_digest: successful authentication\n"));
+
+ as->as_status = 0; /* Successful authentication! */
+ as->as_phrase = "";
+}
+
+/** Construct a challenge header for @b Digest authentication scheme. */
+void auth_challenge_digest(auth_mod_t *am,
+ auth_status_t *as,
+ auth_challenger_t const *ach)
+{
+ char const *u, *d;
+ char nonce[AUTH_DIGEST_NONCE_LEN];
+
+ auth_generate_digest_nonce(am, nonce, sizeof nonce, 0, msg_now());
+
+ u = as->as_uri;
+ d = as->as_pdomain;
+
+ as->as_response =
+ msg_header_format(as->as_home, ach->ach_header,
+ "Digest"
+ " realm=\"%s\","
+ "%s%s%s"
+ "%s%s%s"
+ " nonce=\"%s\","
+ "%s%s%s"
+ "%s" /* stale */
+ " algorithm=%s"
+ "%s%s%s",
+ as->as_realm,
+ u ? " uri=\"" : "", u ? u : "", u ? "\"," : "",
+ d ? " domain=\"" : "", d ? d : "", d ? "\"," : "",
+ nonce,
+ am->am_opaque ? " opaque=\"" : "",
+ am->am_opaque ? am->am_opaque : "",
+ am->am_opaque ? "\"," : "",
+ as->as_stale ? " stale=true," : "",
+ am->am_algorithm,
+ am->am_qop ? ", qop=\"" : "",
+ am->am_qop ? am->am_qop : "",
+ am->am_qop ? "\"" : "");
+
+ if (!as->as_response)
+ as->as_status = 500, as->as_phrase = auth_internal_server_error;
+ else
+ as->as_status = ach->ach_status, as->as_phrase = ach->ach_phrase;
+}
+
+/** Construct a info header for @b Digest authentication scheme. */
+void auth_info_digest(auth_mod_t *am,
+ auth_status_t *as,
+ auth_challenger_t const *ach)
+{
+ if (!ach->ach_info)
+ return;
+
+ if (am->am_nextnonce) {
+ char nonce[AUTH_DIGEST_NONCE_LEN];
+
+ auth_generate_digest_nonce(am, nonce, sizeof nonce, 1, msg_now());
+
+ as->as_info =
+ msg_header_format(as->as_home, ach->ach_info, "nextnonce=\"%s\"", nonce);
+ }
+}
+
+
+/* ====================================================================== */
+/* Password database */
+
+static inline void
+auth_htable_append_local(auth_htable_t *pr, auth_passwd_t *apw);
+
+/** Get an passwd entry for user. */
+auth_passwd_t *auth_mod_getpass(auth_mod_t *am,
+ char const *user,
+ char const *realm)
+{
+ auth_passwd_t *apw, **slot;
+ unsigned hash;
+
+ if (am == NULL || user == NULL)
+ return NULL;
+
+ hash = msg_hash_string(user);
+
+ for (slot = auth_htable_hash(am->am_users, hash);
+ (apw = *slot);
+ slot = auth_htable_next(am->am_users, slot)) {
+ if (hash != apw->apw_index)
+ continue;
+ if (strcmp(user, apw->apw_user))
+ continue;
+ if (realm && apw->apw_realm[0] && strcmp(realm, apw->apw_realm))
+ continue;
+ break; /* Found it */
+ }
+
+ return apw;
+}
+
+/** Add a password entry. */
+auth_passwd_t *auth_mod_addpass(auth_mod_t *am,
+ char const *user,
+ char const *realm)
+{
+ auth_passwd_t *apw, **slot;
+ unsigned index;
+
+ if (am == NULL || user == NULL)
+ return NULL;
+
+ index = msg_hash_string(user);
+
+ for (slot = auth_htable_hash(am->am_users, index);
+ (apw = *slot);
+ slot = auth_htable_next(am->am_users, slot)) {
+ if (index != apw->apw_index)
+ continue;
+ if (strcmp(user, apw->apw_user))
+ continue;
+ if (realm && strcmp(realm, apw->apw_realm))
+ continue;
+ break; /* Found it */
+ }
+
+ if (realm == NULL)
+ realm = "";
+
+ if (!apw) {
+ size_t ulen = strlen(user) + 1, rlen = strlen(realm) + 1;
+ size_t size = sizeof *apw + ulen + rlen;
+
+ apw = su_alloc(am->am_home, size);
+
+ if (apw) {
+ memset(apw, 0, sizeof *apw);
+ apw->apw_index = index;
+ apw->apw_user = memcpy((char *)(apw + 1), user, ulen);
+ apw->apw_realm = memcpy((char *)apw->apw_user + ulen, realm, rlen);
+
+ if (!auth_htable_is_full(am->am_users)) {
+ *slot = apw, am->am_users->aht_used++;
+ } else {
+ if (auth_htable_resize(am->am_home, am->am_users, 0) < 0)
+ su_free(am->am_home, apw), apw = NULL;
+ else
+ auth_htable_append(am->am_users, apw);
+ }
+ }
+ }
+
+ return apw;
+}
+
+static ssize_t readfile(su_home_t *, FILE *,
+ void **contents, int add_trailing_lf);
+static int auth_readdb_internal(auth_mod_t *am, int always);
+
+/** Read authentication database */
+int auth_readdb(auth_mod_t *am)
+{
+ return auth_readdb_internal(am, 1);
+}
+
+/** Read authentication database only when needed */
+int auth_readdb_if_needed(auth_mod_t *am)
+{
+ struct stat st[1];
+
+ if (!am->am_stat || !am->am_db)
+ return 0;
+
+ if (stat(am->am_db, st) != -1 &&
+ st->st_dev == am->am_stat->st_dev &&
+ st->st_ino == am->am_stat->st_ino &&
+ st->st_size == am->am_stat->st_size &&
+ memcmp(&st->st_mtime, &am->am_stat->st_mtime,
+ (sizeof st->st_mtime)) == 0)
+ /* Nothing has changed or passwd file is removed */
+ return 0;
+
+ return auth_readdb_internal(am, 0);
+}
+
+#if HAVE_FLOCK
+#include <sys/file.h>
+#endif
+
+#define auth_apw_local auth_readdb_internal
+
+/** Read authentication database */
+static
+int auth_readdb_internal(auth_mod_t *am, int always)
+{
+ FILE *f;
+ char *data, *s;
+ size_t len, i, n, N;
+ auth_passwd_t *apw;
+
+ if (!am->am_stat)
+ am->am_stat = su_zalloc(am->am_home, sizeof (*am->am_stat));
+
+ f = fopen(am->am_db, "rb");
+
+ if (f) {
+ void *buffer = NULL;
+ auth_passwd_t *fresh = NULL;
+
+#if HAVE_FLOCK
+ int locked;
+
+ /* Obtain shared lock on the database file */
+ if (flock(fileno(f), LOCK_SH | (always ? 0 : LOCK_NB)) == 0) {
+ locked = 1;
+ } else {
+ locked = 0;
+
+ if (errno == ENOLCK) {
+ ;
+ }
+ else if (errno == EWOULDBLOCK) {
+ SU_DEBUG_3(("auth(%s): user file \"%s\" is busy, trying again later\n",
+ am->am_scheme->asch_method, am->am_db));
+ fclose(f);
+ return always ? -1 : 0;
+ }
+ else {
+ SU_DEBUG_3(("auth(%s): flock(\"%s\"): %s (%u)\n",
+ am->am_scheme->asch_method, am->am_db,
+ strerror(errno), errno));
+ fclose(f);
+ return always ? -1 : 0;
+ }
+ }
+#endif
+ if (am->am_stat)
+ stat(am->am_db, am->am_stat); /* too bad if this fails */
+
+ len = readfile(am->am_home, f, &buffer, 1);
+
+#if HAVE_FLOCK
+ /* Release shared lock on the database file */
+ if (locked && flock(fileno(f), LOCK_UN) == -1) {
+ SU_DEBUG_0(("auth(%s): un-flock(\"%s\"): %s (%u)\n",
+ am->am_scheme->asch_method, am->am_db, strerror(errno), errno));
+ fclose(f);
+ return -1;
+ }
+#endif
+
+ fclose(f);
+
+ if (len < 0)
+ return -1;
+
+ /* Count number of entries in new buffer */
+ for (i = am->am_anonymous, s = data = buffer;
+ s < data + len;
+ s += n + strspn(s + n, "\r\n")) {
+ n = strcspn(s, "\r\n");
+ if (*s != '#' && *s != '\n' && *s != '\r')
+ i++;
+ }
+
+ N = i, i = 0;
+
+ if (N > 0) {
+ if (auth_htable_resize(am->am_home, am->am_users, N) < 0 ||
+ !(fresh = su_zalloc(am->am_home, sizeof(*fresh) * N))) {
+ su_free(am->am_home, buffer);
+ return -1;
+ }
+ }
+
+ if (am->am_anonymous) {
+ assert(i < N);
+
+ apw = fresh + i++;
+
+ apw->apw_index = msg_hash_string("anonymous");
+ apw->apw_user = "anonymous";
+ apw->apw_pass = "";
+ apw->apw_realm = "";
+
+ am->am_anon_user = apw;
+
+ if (auth_htable_is_full(am->am_users))
+ auth_htable_resize(am->am_home, am->am_users, 0);
+
+ auth_htable_append_local(am->am_users, apw);
+ }
+
+ apw = NULL;
+
+ for (data = buffer, s = data;
+ s < data + len && i < N;
+ s += n + strspn(s + n, "\r\n")) {
+ char *user, *pass, *realm, *ident;
+
+ n = strcspn(s, "\r\n");
+ if (*s == '#')
+ continue;
+
+ user = s;
+ s[n++] = '\0';
+ if (!(pass = strchr(user, ':')))
+ continue;
+
+ *pass++ = '\0';
+ if (!*pass || !*user)
+ continue;
+
+ realm = ""; ident = "";
+
+ if ((realm = strchr(pass, ':'))) {
+ *realm++ = '\0';
+ if ((ident = strchr(realm, ':')))
+ *ident++ = '\0';
+ }
+
+ apw = fresh + i++;
+
+ apw->apw_index = msg_hash_string(user);
+ apw->apw_user = user;
+ apw->apw_ident = ident;
+
+ /* Check for htdigest format */
+ if (span_hexdigit(realm) == 32 && realm[32] == '\0') {
+ apw->apw_realm = pass;
+ apw->apw_hash = realm;
+ } else {
+ apw->apw_pass = pass;
+ apw->apw_realm = realm;
+ }
+
+ if (auth_htable_is_full(am->am_users))
+ auth_htable_resize(am->am_home, am->am_users, 0);
+
+ auth_htable_append_local(am->am_users, apw);
+ }
+
+ assert(i <= N);
+ N = i;
+
+ /* Remove from hash those entries that were read from old passwd file */
+ for (i = 0; i < am->am_local_count; i++) {
+ if (am->am_locals[i].apw_type == auth_apw_local)
+ auth_htable_remove(am->am_users, &am->am_locals[i]);
+ }
+
+ if (am->am_locals)
+ su_free(am->am_home, am->am_locals); /* Free old entries */
+ if (am->am_buffer)
+ su_free(am->am_home, am->am_buffer); /* Free old passwd file contents */
+
+ SU_DEBUG_5(("auth(%s): read %u entries from \"%s\"\n",
+ am->am_scheme->asch_method, (unsigned)N, am->am_db));
+
+ am->am_locals = fresh;
+ am->am_local_count = N;
+ am->am_buffer = buffer;
+
+ return 0;
+ }
+
+ return -1;
+}
+
+/** Append to hash, remove existing user */
+static inline void
+auth_htable_append_local(auth_htable_t *aht, auth_passwd_t *apw)
+{
+ auth_passwd_t **slot;
+
+ apw->apw_type = auth_apw_local;
+
+ /* Append to hash */
+ for (slot = auth_htable_hash(aht, apw->apw_index);
+ *slot;
+ slot = auth_htable_next(aht, slot)) {
+ if (strcmp((*slot)->apw_user, apw->apw_user) == 0) {
+ if ((*slot)->apw_type == auth_apw_local) {
+ (*slot)->apw_type = NULL;
+ assert(aht->aht_used > 0); aht->aht_used--;
+ apw->apw_extended = (*slot)->apw_extended;
+ *slot = NULL;
+ break;
+ }
+ else {
+ /* We insert local before external entry */
+ auth_passwd_t *swap = apw;
+ apw = *slot;
+ *slot = swap;
+ }
+ }
+ }
+
+ aht->aht_used++; assert(aht->aht_used <= aht->aht_size);
+
+ *slot = apw;
+}
+
+static
+ssize_t readfile(su_home_t *home,
+ FILE *f,
+ void **contents,
+ int add_trailing_lf)
+{
+ /* Read in whole (binary!) file */
+ char *buffer = NULL;
+ long size;
+ size_t len;
+
+ /* Read whole file in */
+ if (fseek(f, 0, SEEK_END) < 0 ||
+ (size = ftell(f)) < 0 ||
+ fseek(f, 0, SEEK_SET) < 0 ||
+ (long)(len = (size_t)size) != size ||
+ size + 2 > SSIZE_MAX) {
+ SU_DEBUG_1(("%s: unable to determine file size (%s)\n",
+ __func__, strerror(errno)));
+ return -1;
+ }
+
+ if (!(buffer = su_alloc(home, len + 2)) ||
+ fread(buffer, 1, len, f) != len) {
+ SU_DEBUG_1(("%s: unable to read file (%s)\n", __func__, strerror(errno)));
+ if (buffer)
+ su_free(home, buffer);
+ return -1;
+ }
+
+ if (add_trailing_lf) {
+ /* Make sure that the buffer has trailing newline */
+ if (len == 0 || buffer[len - 1] != '\n')
+ buffer[len++] = '\n';
+ }
+
+ buffer[len] = '\0';
+ *contents = buffer;
+
+ return len;
+}
+
+/* ====================================================================== */
+/* Helper functions */
+
+/** Check if request method is on always-allowed list.
+ *
+ * @return 0 if allowed
+ * @return 1 otherwise
+ */
+int auth_allow_check(auth_mod_t *am, auth_status_t *as)
+{
+ char const *method = as->as_method;
+ int i;
+
+ if (method && strcmp(method, "ACK") == 0) /* Hack */
+ return as->as_status = 0;
+
+ if (!method || !am->am_allow)
+ return 1;
+
+ if (am->am_allow[0] && strcmp(am->am_allow[0], "*") == 0)
+ return as->as_status = 0;
+
+ for (i = 0; am->am_allow[i]; i++)
+ if (strcmp(am->am_allow[i], method) == 0)
+ return as->as_status = 0;
+
+ return 1;
+}
+
+/** Find a credential header with matching scheme and realm. */
+msg_auth_t *auth_mod_credentials(msg_auth_t *auth,
+ char const *scheme,
+ char const *realm)
+{
+ char const *arealm;
+
+ for (;auth; auth = auth->au_next) {
+ if (strcasecmp(auth->au_scheme, scheme))
+ continue;
+
+ if (!realm)
+ return auth;
+
+ arealm = msg_header_find_param(auth->au_common, "realm=");
+
+ if (!arealm)
+ continue;
+
+ if (arealm[0] == '"') {
+ /* Compare quoted arealm with unquoted realm */
+ int i, j;
+ for (i = 1, j = 0; arealm[i] != 0; i++, j++) {
+ if (arealm[i] == '"' && realm[j] == 0)
+ return auth;
+
+ if (arealm[i] == '\\' && arealm[i + 1] != '\0')
+ i++;
+
+ if (arealm[i] != realm[j])
+ break;
+ }
+ } else {
+ if (strcmp(arealm, realm) == 0)
+ return auth;
+ }
+ }
+
+ return NULL;
+}
+
+/** Find a Digest credential header with matching realm and opaque. */
+msg_auth_t *auth_digest_credentials(msg_auth_t *auth,
+ char const *realm,
+ char const *opaque)
+{
+ char const *arealm, *aopaque;
+
+ for (;auth; auth = auth->au_next) {
+ if (strcasecmp(auth->au_scheme, "Digest"))
+ continue;
+
+ if (realm) {
+ int cmp = 1;
+
+ arealm = msg_header_find_param(auth->au_common, "realm=");
+ if (!arealm)
+ continue;
+
+ if (arealm[0] == '"') {
+ /* Compare quoted arealm with unquoted realm */
+ int i, j;
+ for (i = 1, j = 0, cmp = 1; arealm[i] != 0; i++, j++) {
+ if (arealm[i] == '"' && realm[j] == 0) {
+ cmp = 0;
+ break;
+ }
+
+ if (arealm[i] == '\\' && arealm[i + 1] != '\0')
+ i++;
+
+ if (arealm[i] != realm[j])
+ break;
+ }
+ }
+ else {
+ cmp = strcmp(arealm, realm);
+ }
+
+ if (cmp)
+ continue;
+ }
+
+ if (opaque) {
+ int cmp = 1;
+
+ aopaque = msg_header_find_param(auth->au_common, "opaque=");
+ if (!aopaque)
+ continue;
+
+ if (aopaque[0] == '"') {
+ /* Compare quoted aopaque with unquoted opaque */
+ int i, j;
+ for (i = 1, j = 0, cmp = 1; aopaque[i] != 0; i++, j++) {
+ if (aopaque[i] == '"' && opaque[j] == 0) {
+ cmp = 0;
+ break;
+ }
+
+ if (aopaque[i] == '\\' && aopaque[i + 1] != '\0')
+ i++;
+
+ if (aopaque[i] != opaque[j])
+ break;
+ }
+ } else {
+ cmp = strcmp(aopaque, opaque);
+ }
+
+ if (cmp)
+ continue;
+ }
+
+ return auth;
+ }
+
+ return NULL;
+}
+
+/** Generate nonce parameter.
+ *
+ * @param am pointer to authentication module object
+ * @param buffer string buffer for nonce [OUT]
+ * @param bsize size of buffer [IN]
+ * @param nextnonce true if this is a "nextnonce" [IN]
+ * @param now current time [IN]
+ */
+isize_t auth_generate_digest_nonce(auth_mod_t *am,
+ char buffer[],
+ size_t bsize,
+ int nextnonce,
+ msg_time_t now)
+{
+ struct nonce nonce[1] = {{ 0 }};
+ su_md5_t md5[1];
+
+ am->am_count += 3730029547U; /* 3730029547 is a prime */
+
+ nonce->issued = now;
+ nonce->count = am->am_count;
+ nonce->nextnonce = nextnonce != 0;
+
+ /* Calculate HMAC of nonce data */
+ auth_md5_hmac_init(am, md5);
+ su_md5_update(md5, nonce, offsetof(struct nonce, digest));
+ auth_md5_hmac_digest(am, md5, nonce->digest, sizeof nonce->digest);
+
+ return base64_e(buffer, bsize, nonce, sizeof(nonce));
+}
+
+
+/** Validate nonce parameter.
+ *
+ * @param am pointer to authentication module object
+ * @param as authentication status structure [OUT]
+ * @param ar decoded authentication response from client [IN]
+ * @param now current time [IN]
+ */
+int auth_validate_digest_nonce(auth_mod_t *am,
+ auth_status_t *as,
+ auth_response_t *ar,
+ msg_time_t now)
+{
+ struct nonce nonce[1] = {{ 0 }};
+ su_md5_t md5[1];
+ uint8_t hmac[sizeof nonce->digest];
+ unsigned expires;
+
+ /* Check nonce */
+ if (!ar->ar_nonce) {
+ SU_DEBUG_5(("auth_method_digest: no nonce\n"));
+ return -1;
+ }
+ if (base64_d((void*)nonce, (sizeof nonce), ar->ar_nonce) != (sizeof nonce)) {
+ SU_DEBUG_5(("auth_method_digest: too short nonce\n"));
+ return -1;
+ }
+
+ /* Calculate HMAC over decoded nonce data */
+ auth_md5_hmac_init(am, md5);
+ su_md5_update(md5, nonce, offsetof(struct nonce, digest));
+ auth_md5_hmac_digest(am, md5, hmac, sizeof hmac);
+
+ if (memcmp(nonce->digest, hmac, sizeof nonce->digest)) {
+ SU_DEBUG_5(("auth_method_digest: bad nonce\n"));
+ return -1;
+ }
+
+ as->as_nonce_issued = nonce->issued;
+ as->as_nextnonce = nonce->nextnonce != 0;
+
+ expires = nonce->nextnonce ? am->am_next_exp : am->am_expires;
+
+ if (nonce->issued > now ||
+ (expires && nonce->issued + expires < now)) {
+ SU_DEBUG_5(("auth_method_digest: nonce expired %lu seconds ago "
+ "(lifetime %u)\n",
+ now - (nonce->issued + expires), expires));
+ as->as_stale = 1;
+ }
+
+ /* We should also check cnonce, nc... */
+
+ return 0;
+}
+
+
+/* ====================================================================== */
+/* HMAC routines */
+static
+void auth_md5_hmac_key(auth_mod_t *am)
+{
+ size_t i;
+ uint8_t ipad[SU_MD5_DIGEST_SIZE];
+ uint8_t opad[SU_MD5_DIGEST_SIZE];
+
+ assert(SU_MD5_DIGEST_SIZE == sizeof am->am_master_key);
+
+ /* Derive HMAC ipad and opad from master key */
+ for (i = 0; i < sizeof am->am_master_key; i++) {
+ ipad[i] = am->am_master_key[i] ^ 0x36;
+ opad[i] = am->am_master_key[i] ^ 0x5C;
+ }
+
+ /* Pre-calculate sum of ipad */
+ su_md5_init(&am->am_hmac_ipad);
+ su_md5_update(&am->am_hmac_ipad, ipad, sizeof ipad);
+
+ /* Pre-calculate sum of opad */
+ su_md5_init(&am->am_hmac_opad);
+ su_md5_update(&am->am_hmac_opad, opad, sizeof opad);
+}
+
+void auth_md5_hmac_init(auth_mod_t *am, struct su_md5_t *imd5)
+{
+ *imd5 = am->am_hmac_ipad;
+}
+
+void auth_md5_hmac_digest(auth_mod_t *am, struct su_md5_t *imd5,
+ void *hmac, size_t size)
+{
+ uint8_t digest[SU_MD5_DIGEST_SIZE];
+ su_md5_t omd5[1];
+
+ /* inner sum */
+ su_md5_digest(imd5, digest);
+
+ *omd5 = am->am_hmac_opad;
+ su_md5_update(omd5, digest, sizeof *digest);
+
+ /* outer sum */
+ if (size == sizeof digest) {
+ su_md5_digest(omd5, hmac);
+ }
+ else {
+ su_md5_digest(omd5, digest);
+
+ if (size > sizeof digest) {
+ memset((char *)hmac + (sizeof digest), 0, size - sizeof digest);
+ size = sizeof digest;
+ }
+
+ memcpy(hmac, digest, size);
+ }
+}
+
+/* ====================================================================== */
+/* Compatibility interface */
+
+void auth_mod_method(auth_mod_t *am,
+ auth_status_t *as,
+ msg_auth_t *credentials,
+ auth_challenger_t const *ach)
+{
+ auth_mod_verify(am, as, credentials, ach);
+}
+
+void auth_mod_check_client(auth_mod_t *am,
+ auth_status_t *as,
+ msg_auth_t *credentials,
+ auth_challenger_t const *ach)
+{
+ auth_mod_verify(am, as, credentials, ach);
+}
+
+
+void auth_mod_challenge_client(auth_mod_t *am,
+ auth_status_t *as,
+ auth_challenger_t const *ach)
+{
+ auth_mod_challenge(am, as, ach);
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_module_http.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_module_http.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,82 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**
+ * @file auth_module_http.c
+ * @brief Authenticate HTTP request
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Jari Urpalainen <Jari.Urpalainen at nokia.com>
+ *
+ * @date Created: Thu Jan 15 17:23:21 2004 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <string.h>
+
+#include <sofia-sip/http.h>
+#include <sofia-sip/http_header.h>
+#include <sofia-sip/http_status.h>
+
+#include <sofia-sip/auth_module.h>
+
+static auth_challenger_t http_server_challenger[] =
+ {{ HTTP_401_UNAUTHORIZED, http_www_authenticate_class }};
+
+static auth_challenger_t http_proxy_challenger[] =
+ {{ HTTP_407_PROXY_AUTH, http_proxy_authenticate_class }};
+
+const char *auth_mod_check_http(auth_mod_t *am,
+ auth_status_t *as,
+ http_t const *http,
+ auth_kind_t proxy)
+{
+ msg_auth_t *credentials =
+ proxy ? http->http_proxy_authorization : http->http_authorization;
+ auth_challenger_t const *challenger =
+ proxy ? http_proxy_challenger : http_server_challenger;
+
+ if (http->http_request) {
+ if (!as->as_method)
+ as->as_method = http->http_request->rq_method_name;
+#if 0
+ if (!as->as_uri)
+ as->as_uri = http->http_request->rq_url;
+#endif
+ }
+
+ if (http->http_payload && !as->as_body)
+ as->as_body = http->http_payload->pl_data,
+ as->as_bodylen = http->http_payload->pl_len;
+
+ /* Call real authentication method */
+ auth_mod_check_client(am, as, credentials, challenger);
+
+ if (as->as_status)
+ return NULL;
+ else
+ return as->as_user;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_module_sip.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_module_sip.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,93 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**
+ * @file auth_module_sip.c
+ * @brief Authenticate SIP request
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Jari Urpalainen <Jari.Urpalainen at nokia.com>
+ *
+ * @date Created: Thu Jan 15 17:23:21 2004 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <string.h>
+
+#include <sofia-sip/sip.h>
+#include <sofia-sip/sip_header.h>
+#include <sofia-sip/sip_status.h>
+
+#include <sofia-sip/nta.h>
+
+#include <sofia-sip/auth_module.h>
+
+static auth_challenger_t sip_server_challenger[] =
+ {{ SIP_401_UNAUTHORIZED, sip_www_authenticate_class,
+ sip_authentication_info_class
+ }};
+
+static auth_challenger_t sip_proxy_challenger[] =
+ {{ SIP_407_PROXY_AUTH_REQUIRED, sip_proxy_authenticate_class }};
+
+/** Authenticate an incoming SIP request.
+ *
+ * The function auth_mod_check() completes the @a as structure and calls the
+ * scheme-specific authentication method performing the actual
+ * authentication.
+ *
+ * A successful authentication is indicated by setting @a as->as_status to
+ * 0. The authentication module sets @a as->as_match as the matching
+ * credential header.
+ */
+void auth_mod_check(auth_mod_t *am,
+ auth_status_t *as,
+ sip_t const *sip,
+ auth_kind_t proxy)
+{
+ msg_auth_t *credentials;
+ auth_challenger_t const *challenger;
+
+ if (as == NULL || sip == NULL)
+ return;
+
+ if (am == NULL) {
+ as->as_status = 0;
+ return;
+ }
+
+ credentials = proxy ? sip->sip_proxy_authorization : sip->sip_authorization;
+ challenger = proxy ? sip_proxy_challenger : sip_server_challenger;
+
+ if (sip->sip_request)
+ as->as_method = sip->sip_request->rq_method_name;
+
+ if (sip->sip_payload)
+ as->as_body = sip->sip_payload->pl_data,
+ as->as_bodylen = sip->sip_payload->pl_len;
+
+ auth_mod_method(am, as, credentials, challenger);
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_ntlm.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_ntlm.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,323 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE auth_ntlm.c
+ *
+ * Implementation for digest authentication.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Feb 22 12:10:37 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <stdarg.h>
+#include <assert.h>
+
+#include <sofia-sip/su_md5.h>
+#include "sofia-sip/auth_digest.h"
+#include "sofia-sip/auth_ntlm.h"
+
+#include "iptsec_debug.h"
+
+static inline int has_token(char const *qstring, char const *token);
+
+
+/**Get ntlm-challenge parameters.
+ *
+ * The function ntlm_challenge_get() searches for the ntlm authentication
+ * parameters in @a params. The parameters are assigned to the appropriate
+ * fields in @a ac structure.
+ *
+ * @return
+ *
+ * The function ntlm_challenge_get() returns number of parameters
+ * found, or -1 upon an error.
+ */
+issize_t auth_ntlm_challenge_get(su_home_t *home,
+ auth_challenge_t *ac0,
+ char const * const params[])
+{
+ ssize_t n;
+ auth_challenge_t ac[1] = {{ 0 }};
+ char const *md5 = NULL, *md5sess = NULL, *sha1 = NULL,
+ *qop_auth = NULL, *qop_auth_int = NULL;
+
+ ac->ac_size = sizeof(ac);
+
+ assert(ac0);
+ assert(ac0->ac_size >= sizeof(*ac));
+
+ if (ac0 == NULL || params == NULL)
+ return -1;
+
+ n = auth_get_params(home, params,
+ "realm=", &ac->ac_realm,
+ "domain=", &ac->ac_domain,
+ "nonce=", &ac->ac_nonce,
+ "opaque=", &ac->ac_opaque,
+ "stale=", &ac->ac_stale,
+ "algorithm=", &ac->ac_algorithm,
+ "qop=", &ac->ac_qop,
+ "algorithm=md5", &md5,
+ "algorithm=md5-sess", &md5sess,
+ "algorithm=sha1", &sha1,
+ "qop=auth", &qop_auth,
+ "qop=auth-int", &qop_auth_int,
+ NULL);
+ if (n < 0)
+ return n;
+
+ if (ac->ac_stale && strcasecmp(ac->ac_stale, "true") != 0)
+ ac->ac_stale = NULL;
+
+ ac->ac_md5 = md5 != NULL || ac->ac_algorithm == NULL;
+ ac->ac_md5sess = md5sess != NULL;
+ ac->ac_sha1 = sha1 != NULL;
+ ac->ac_auth = qop_auth != NULL;
+ ac->ac_auth_int = qop_auth_int != NULL;
+
+ auth_struct_copy(ac0, ac, sizeof(ac));
+
+ SU_DEBUG_5(("%s(): got %d\n", "auth_ntlm_challenge_get", n));
+
+ return n;
+}
+
+/**Get ntlm-response parameters.
+ *
+ * The function auth_response_get() searches for the ntlm authentication
+ * parameters in @a params. The parameters are assigned to the appropriate
+ * fields in @a ar structure.
+ *
+ * @return
+ *
+ * The function auth_response_get() returns number of parameters
+ * found, or -1 upon an error.
+ */
+issize_t auth_ntlm_response_get(su_home_t *home,
+ auth_response_t *ar0,
+ char const *const params[])
+{
+ ssize_t n;
+ auth_response_t ar[1] = {{ 0 }};
+ char const *md5 = NULL, *md5sess = NULL, *sha1 = NULL,
+ *qop_auth = NULL, *qop_auth_int = NULL;
+
+ ar->ar_size = sizeof(ar);
+
+ assert(ar0); assert(params); assert(ar0->ar_size >= sizeof(ar));
+
+ if (ar0 == NULL || params == NULL)
+ return -1;
+
+ n = auth_get_params(home, params,
+ "username=", &ar->ar_username,
+ "realm=", &ar->ar_realm,
+ "nonce=", &ar->ar_nonce,
+ "uri=", &ar->ar_uri,
+ "response=", &ar->ar_response,
+ "algorithm=", &ar->ar_algorithm,
+ "opaque=", &ar->ar_opaque,
+ "cnonce=", &ar->ar_cnonce,
+ "qop=", &ar->ar_qop,
+ "nc=", &ar->ar_nc,
+ "algorithm=md5", &md5,
+ "algorithm=md5-sess", &md5sess,
+ "algorithm=sha1", &sha1,
+ "qop=auth", &qop_auth,
+ "qop=auth-int", &qop_auth_int,
+ NULL);
+ if (n < 0)
+ return n;
+
+ ar->ar_md5 = md5 != NULL || ar->ar_algorithm == NULL;
+ ar->ar_md5sess = md5sess != NULL;
+ ar->ar_sha1 = sha1 != NULL;
+ ar->ar_auth = qop_auth != NULL;
+ ar->ar_auth_int = qop_auth_int != NULL;
+
+ auth_struct_copy(ar0, ar, sizeof(ar));
+
+ SU_DEBUG_7(("%s: %d\n", "auth_ntlm_response_get", n));
+
+ return n;
+}
+
+#if 0
+
+/** Generate A1 hash for digest authentication.
+ */
+int auth_digest_a1(auth_response_t *ar,
+ auth_hexmd5_t ha1,
+ char const *secret)
+{
+ su_md5_t md5[1];
+
+ /* Calculate A1 */
+ su_md5_init(md5);
+ su_md5_strupdate(md5, ar->ar_username);
+ su_md5_update(md5, ":", 1);
+ unquote_update(md5, ar->ar_realm);
+ su_md5_update(md5, ":", 1);
+ su_md5_strupdate(md5, secret);
+
+ su_md5_hexdigest(md5, ha1);
+
+ SU_DEBUG_5(("auth_digest_a1() has A1 = MD5(%s:%s:%s) = %s\n",
+ ar->ar_username, ar->ar_realm, secret, ha1));
+
+ return 0;
+}
+
+int auth_digest_a1sess(auth_response_t *ar,
+ auth_hexmd5_t ha1sess,
+ char const *ha1)
+{
+ su_md5_t md5[1];
+
+ su_md5_init(md5);
+ su_md5_strupdate(md5, ha1);
+ su_md5_update(md5, ":", 1);
+ unquote_update(md5, ar->ar_nonce);
+ su_md5_update(md5, ":", 1);
+ unquote_update(md5, ar->ar_cnonce);
+
+ su_md5_hexdigest(md5, ha1sess);
+
+ SU_DEBUG_5(("auth_sessionkey has A1' = MD5(%s:%s:%s) = %s\n",
+ ha1, ar->ar_nonce, ar->ar_cnonce, ha1sess));
+
+ return 0;
+}
+
+/** Generate MD5 session key for digest authentication.
+ */
+int auth_digest_sessionkey(auth_response_t *ar,
+ auth_hexmd5_t ha1,
+ char const *secret)
+{
+ if (ar->ar_md5sess)
+ ar->ar_algorithm = "MD5-sess";
+ else if (ar->ar_md5)
+ ar->ar_algorithm = "MD5";
+ else
+ return -1;
+
+ if (ar->ar_md5sess) {
+ auth_hexmd5_t base_ha1;
+ auth_digest_a1(ar, base_ha1, secret);
+ auth_digest_a1sess(ar, ha1, base_ha1);
+ } else {
+ auth_digest_a1(ar, ha1, secret);
+ }
+
+ return 0;
+}
+
+#endif /* 0 */
+
+
+#if 0
+
+/** Generate response for digest authentication.
+ *
+ */
+int auth_digest_response(auth_response_t *ar,
+ auth_hexmd5_t response,
+ auth_hexmd5_t const ha1,
+ char const *method_name,
+ void const *data, issize_t dlen)
+{
+ su_md5_t md5[1];
+ auth_hexmd5_t Hentity, HA2;
+
+ if (ar->ar_auth_int)
+ ar->ar_qop = "auth-int";
+ else if (ar->ar_auth)
+ ar->ar_qop = "auth";
+ else
+ ar->ar_qop = NULL;
+
+ /* Calculate Hentity */
+ if (ar->ar_auth_int) {
+ if (data && dlen) {
+ su_md5_init(md5);
+ su_md5_update(md5, data, dlen);
+ su_md5_hexdigest(md5, Hentity);
+ } else {
+ strcpy(Hentity, "d41d8cd98f00b204e9800998ecf8427e");
+ }
+ }
+
+ /* Calculate A2 */
+ su_md5_init(md5);
+ su_md5_strupdate(md5, method_name);
+ su_md5_update(md5, ":", 1);
+ unquote_update(md5, ar->ar_uri);
+ if (ar->ar_auth_int) {
+ su_md5_update(md5, ":", 1);
+ su_md5_update(md5, Hentity, sizeof(Hentity) - 1);
+ }
+ su_md5_hexdigest(md5, HA2);
+
+ SU_DEBUG_5(("A2 = MD5(%s:%s%s%s)\n", method_name, ar->ar_uri,
+ ar->ar_auth_int ? ":" : "", ar->ar_auth_int ? Hentity : ""));
+
+ /* Calculate response */
+ su_md5_init(md5);
+ su_md5_update(md5, ha1, 32);
+ su_md5_update(md5, ":", 1);
+ unquote_update(md5, ar->ar_nonce);
+
+ if (ar->ar_auth || ar->ar_auth_int) {
+ su_md5_update(md5, ":", 1);
+ su_md5_strupdate(md5, ar->ar_nc);
+ su_md5_update(md5, ":", 1);
+ unquote_update(md5, ar->ar_cnonce);
+ su_md5_update(md5, ":", 1);
+ su_md5_strupdate(md5, ar->ar_qop);
+ }
+
+ su_md5_update(md5, ":", 1);
+ su_md5_update(md5, HA2, 32);
+ su_md5_hexdigest(md5, response);
+
+ SU_DEBUG_5(("auth_response: %s = MD5(%s:%s%s%s%s%s%s%s:%s) (qop=%s)\n",
+ response, ha1, ar->ar_nonce,
+ ar->ar_auth || ar->ar_auth_int ? ":" : "",
+ ar->ar_auth || ar->ar_auth_int ? ar->ar_nc : "",
+ ar->ar_auth || ar->ar_auth_int ? ":" : "",
+ ar->ar_auth || ar->ar_auth_int ? ar->ar_cnonce : "",
+ ar->ar_auth || ar->ar_auth_int ? ":" : "",
+ ar->ar_auth || ar->ar_auth_int ? ar->ar_qop : "",
+ HA2,
+ ar->ar_qop ? ar->ar_qop : "NONE"));
+
+ return 0;
+}
+
+#endif
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_plugin.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_plugin.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,157 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**
+ * @file auth_plugin.c
+ * @brief Plugin interface for authentication verification modules.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Apr 27 15:23:31 2004 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include <sofia-sip/auth_digest.h>
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+static char const __func__[] = "auth_plugin";
+#endif
+
+#include <sofia-sip/su_debug.h>
+
+#include <sofia-sip/su_wait.h>
+#include <sofia-sip/su_alloc.h>
+#include <sofia-sip/su_tagarg.h>
+
+#include "sofia-sip/auth_module.h"
+#include "sofia-sip/auth_plugin.h"
+
+extern auth_scheme_t auth_scheme_basic[];
+extern auth_scheme_t auth_scheme_digest[];
+extern auth_scheme_t auth_scheme_delayed[];
+
+enum { N = 32 };
+
+static auth_scheme_t *schemes[N] = {
+ auth_scheme_basic,
+ auth_scheme_digest,
+ auth_scheme_delayed
+};
+
+/** Register an authentication plugin.
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error
+ */
+int auth_mod_register_plugin(auth_scheme_t *asch)
+{
+ int i;
+
+ for (i = 0; schemes[i]; i++) {
+ if (i == N)
+ return -1;
+ }
+
+ schemes[i] = asch;
+
+ return 0;
+}
+
+/**Create an authentication plugin module.
+ *
+ * The function auth_mod_create() creates a module used to authenticate the
+ * requests.
+ *
+ * @param root pointer to a su_root_t object
+ * @param tag,value,... tagged argument list
+ *
+ * @TAGS
+ * AUTHTAG_METHOD(), AUTHTAG_REALM(), AUTHTAG_DB(), AUTHTAG_ALLOW(),
+ * AUTHTAG_QOP(), AUTHTAG_ALGORITHM(), AUTHTAG_EXPIRES(),
+ * AUTHTAG_BLACKLIST(), AUTHTAG_FORBIDDEN(), AUTHTAG_ANONYMOUS(),
+ * AUTHTAG_REMOTE().
+ */
+auth_mod_t *auth_mod_create(su_root_t *root,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ auth_mod_t *am = NULL;
+
+ ta_list ta;
+
+ char const *method = NULL;
+
+ ta_start(ta, tag, value);
+
+ tl_gets(ta_args(ta),
+ AUTHTAG_METHOD_REF(method),
+ TAG_NULL());
+
+ if (method) {
+ auth_scheme_t *bscheme = NULL;
+ char const *base;
+ size_t len;
+
+ base = strrchr(method, '+');
+ if (base)
+ len = base++ - method;
+ else
+ len = strlen(method);
+
+ if (base == NULL)
+ ;
+ else if (strcasecmp(base, "Basic") == 0)
+ bscheme = auth_scheme_basic;
+ else if (strcasecmp(base, "Digest") == 0)
+ bscheme = auth_scheme_digest;
+
+ if (base == NULL || bscheme) {
+ int i;
+
+ for (i = 0; schemes[i] && i < N; i++) {
+ if (strncasecmp(schemes[i]->asch_method, method, len) == 0 &&
+ schemes[i]->asch_method[len] == 0) {
+ am = auth_mod_alloc(schemes[i], ta_tags(ta));
+ if (schemes[i]->asch_init(am, bscheme, root, ta_tags(ta)) == -1) {
+ auth_mod_destroy(am), am = NULL;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ ta_end(ta);
+
+ return am;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_plugin_delayed.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_plugin_delayed.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,231 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE auth_plugin_delayed.c
+ *
+ * @brief Plugin for delayed authentication.
+ *
+ * This authentication plugin provides authentication operation that is
+ * intentionally delayed. It serves as an example of server-side
+ * authentication plugins.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Wed Apr 11 15:14:03 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+
+#define SU_MSG_ARG_T struct auth_splugin_t
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+static char const __func__[] = "auth_plugin_delayed";
+#endif
+
+#include <sofia-sip/su_debug.h>
+#include <sofia-sip/su_wait.h>
+
+#include <sofia-sip/su_alloc.h>
+#include <sofia-sip/su_tagarg.h>
+
+#include "sofia-sip/auth_module.h"
+#include "sofia-sip/auth_plugin.h"
+
+struct auth_plugin_t
+{
+ su_root_t *ap_root;
+ auth_scheme_t *ap_base;
+ auth_splugin_t *ap_list;
+ auth_splugin_t**ap_tail;
+};
+
+/* Digest (or Basic) with delay */
+
+static int delayed_auth_init(auth_mod_t *am,
+ auth_scheme_t *base,
+ su_root_t *root,
+ tag_type_t tag, tag_value_t value, ...);
+
+static void delayed_auth_method(auth_mod_t *am,
+ auth_status_t *as,
+ msg_auth_t *auth,
+ auth_challenger_t const *ach);
+
+static void delayed_auth_challenge(auth_mod_t *am,
+ auth_status_t *as,
+ auth_challenger_t const *ach);
+
+static void delayed_auth_cancel(auth_mod_t *am, auth_status_t *as);
+
+static void delayed_auth_destroy(auth_mod_t *am);
+
+auth_scheme_t auth_scheme_delayed[1] =
+ {{
+ "Delayed",
+ sizeof (struct { auth_mod_t mod[1]; auth_plugin_t plug[1]; }),
+ delayed_auth_init,
+ delayed_auth_method,
+ delayed_auth_challenge,
+ delayed_auth_cancel,
+ delayed_auth_destroy
+ }};
+
+static int delayed_auth_init(auth_mod_t *am,
+ auth_scheme_t *base,
+ su_root_t *root,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ auth_plugin_t *ap = AUTH_PLUGIN(am);
+ int retval = -1;
+ ta_list ta;
+
+ ta_start(ta, tag, value);
+
+ if (root && base && auth_init_default(am, base, root, ta_tags(ta)) != -1) {
+ ap->ap_root = root;
+ ap->ap_base = base;
+ ap->ap_tail = &ap->ap_list;
+
+ retval = 0;
+ }
+
+ ta_end(ta);
+
+ return retval;
+}
+
+struct auth_splugin_t
+{
+ void const *asp_tag;
+ auth_splugin_t *asp_next;
+ auth_splugin_t **asp_prev;
+ auth_mod_t *asp_am;
+ auth_status_t *asp_as;
+ msg_auth_t *asp_header;
+ auth_challenger_t const *asp_ach;
+ int asp_canceled;
+};
+
+
+static void delayed_auth_method_recv(su_root_magic_t *rm,
+ su_msg_r msg,
+ auth_splugin_t *u);
+
+static void delayed_auth_method(auth_mod_t *am,
+ auth_status_t *as,
+ msg_auth_t *auth,
+ auth_challenger_t const *ach)
+{
+ auth_plugin_t *ap = AUTH_PLUGIN(am);
+ su_msg_r mamc = SU_MSG_R_INIT;
+ auth_splugin_t *asp;
+
+ if (su_msg_create(mamc,
+ su_root_task(ap->ap_root),
+ su_root_task(ap->ap_root),
+ delayed_auth_method_recv,
+ sizeof *asp) == SU_FAILURE) {
+ as->as_status = 500;
+ as->as_phrase = "Asynchronous authentication failure";
+ return;
+ }
+
+ asp = su_msg_data(mamc); assert(asp);
+
+ asp->asp_tag = delayed_auth_cancel;
+ asp->asp_am = am;
+ asp->asp_as = as;
+ asp->asp_header = auth;
+ asp->asp_ach = ach;
+ asp->asp_canceled = 0;
+
+ if (su_msg_send(mamc) == SU_FAILURE) {
+ su_msg_destroy(mamc);
+ as->as_status = 500;
+ as->as_phrase = "Asynchronous authentication failure";
+ return;
+ }
+
+ as->as_plugin = asp;
+
+ as->as_status = 100;
+ as->as_phrase = "Trying";
+
+ return;
+}
+
+static void delayed_auth_method_recv(su_root_magic_t *rm,
+ su_msg_r msg,
+ auth_splugin_t *asp)
+{
+ auth_mod_t *am = asp->asp_am;
+ auth_plugin_t *ap = AUTH_PLUGIN(am);
+
+ if (asp->asp_canceled)
+ return;
+
+ ap->ap_base->asch_check(am, asp->asp_as, asp->asp_header, asp->asp_ach);
+
+ if (asp->asp_as->as_callback)
+ asp->asp_as->as_callback(asp->asp_as->as_magic, asp->asp_as);
+}
+
+static void delayed_auth_challenge(auth_mod_t *am,
+ auth_status_t *as,
+ auth_challenger_t const *ach)
+{
+ auth_plugin_t *ap = AUTH_PLUGIN(am);
+
+ /* Invoke member function of base scheme */
+ ap->ap_base->asch_challenge(am, as, ach);
+}
+
+static void delayed_auth_cancel(auth_mod_t *am, auth_status_t *as)
+{
+ auth_plugin_t *ap = AUTH_PLUGIN(am);
+
+ (void)ap; /* xyzzy */
+
+ if (as->as_plugin && as->as_plugin->asp_tag == delayed_auth_cancel)
+ as->as_plugin->asp_canceled = 1;
+
+ as->as_status = 500, as->as_phrase = "Authentication canceled";
+}
+
+static void delayed_auth_destroy(auth_mod_t *am)
+{
+ auth_plugin_t *ap = AUTH_PLUGIN(am);
+
+ /* Invoke member function of base scheme */
+ ap->ap_base->asch_destroy(am);
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_plugin_ntlm.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_plugin_ntlm.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,391 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE auth_plugin_ntlm.c
+ *
+ * @brief Plugin for delayed authentication.
+ *
+ * This authentication plugin provides authentication operation that is
+ * intentionally delayed. It serves as an example of server-side
+ * authentication plugins.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Wed Apr 11 15:14:03 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include <sofia-sip/su_debug.h>
+#include <sofia-sip/su_wait.h>
+
+#include <sofia-sip/su_alloc.h>
+#include <sofia-sip/su_tagarg.h>
+
+#include "sofia-sip/auth_module.h"
+#include "sofia-sip/auth_plugin.h"
+#include "sofia-sip/auth_ntlm.h"
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+static char const __func__[] = "auth_plugin_ntml";
+#endif
+
+/* ====================================================================== */
+/* NTLM authentication scheme */
+
+static int auth_init_ntlm(auth_mod_t *am,
+ auth_scheme_t *base,
+ su_root_t *root,
+ tag_type_t tag, tag_value_t value, ...);
+
+static void auth_method_ntlm_x(auth_mod_t *am,
+ auth_status_t *as,
+ msg_auth_t *au,
+ auth_challenger_t const *ach);
+
+auth_scheme_t auth_scheme_ntlm[1] =
+ {{
+ "NTLM", /* asch_method */
+ sizeof (auth_mod_t), /* asch_size */
+ auth_init_default, /* asch_init */
+ auth_method_ntlm_x, /* asch_check */
+ auth_challenge_ntlm, /* asch_challenge */
+ auth_cancel_default, /* asch_cancel */
+ auth_destroy_default /* asch_destroy */
+ }};
+
+#define AUTH_NTLM_NONCE_LEN (BASE64_SIZE(sizeof (struct nonce)) + 1)
+
+static int auth_init_ntlm(auth_mod_t *am,
+ auth_scheme_t *base,
+ su_root_t *root,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ auth_plugin_t *ap = AUTH_PLUGIN(am);
+ int retval = -1;
+ ta_list ta;
+
+ ta_start(ta, tag, value);
+
+ if (auth_init_default(am, NULL, root, ta_tags(ta)) != -1) {
+ retval = 0;
+ }
+
+ ta_end(ta);
+
+ return retval;
+}
+
+
+/** Authenticate a request with @b NTLM authentication scheme.
+ *
+ * This function reads user database before authentication, if needed.
+ */
+static
+void auth_method_ntlm_x(auth_mod_t *am,
+ auth_status_t *as,
+ msg_auth_t *au,
+ auth_challenger_t const *ach)
+{
+ if (am) {
+ auth_readdb_if_needed(am);
+ auth_method_ntlm(am, as, au, ach);
+ }
+}
+
+/** Authenticate a request with @b Ntlm authentication scheme.
+ */
+void auth_method_ntlm(auth_mod_t *am,
+ auth_status_t *as,
+ msg_auth_t *au,
+ auth_challenger_t const *ach)
+{
+ as->as_allow = as->as_allow || auth_allow_check(am, as) == 0;
+
+ if (as->as_realm)
+ au = auth_ntlm_credentials(au, as->as_realm, am->am_opaque,
+ am->am_gssapi_data, am->am_targetname);
+
+ else
+ au = NULL;
+
+ if (as->as_allow) {
+ SU_DEBUG_5(("%s: allow unauthenticated %s\n", __func__, as->as_method));
+ as->as_status = 0, as->as_phrase = NULL;
+ as->as_match = (msg_header_t *)au;
+ return;
+ }
+
+ if (au) {
+ auth_response_t ar[1] = {{ sizeof(ar) }};
+ auth_ntlm_response_get(as->as_home, ar, au->au_params);
+ as->as_match = (msg_header_t *)au;
+ auth_check_ntlm(am, as, ar, ach);
+ }
+ else {
+ /* There was no matching credentials, send challenge */
+ SU_DEBUG_5(("%s: no credentials matched\n", __func__));
+ auth_challenge_ntlm(am, as, ach);
+ }
+}
+
+
+/** Find a NTLM credential header with matching realm and opaque. */
+msg_auth_t *auth_ntlm_credentials(msg_auth_t *auth,
+ char const *realm,
+ char const *opaque,
+ char const *gssapidata,
+ char const *targetname)
+{
+ char const *agssapidata, *atargetname;
+
+ for (;auth; auth = auth_mod_credentials(auth->au_next)) {
+ if (strcasecmp(auth->au_scheme, "NTLM"))
+ continue;
+
+ if (gssapidata) {
+ agssapidata = msg_header_find_param(auth->au_common, "gssapi-data=");
+ if (!agssapidata || auth_strcmp(agssapidata, gssapidata))
+ continue;
+ }
+
+ if (targetname) {
+ atargetname = msg_header_find_param(auth->au_common, "targetname=");
+ if (!atargetname || auth_strcmp(atargetname, targetname))
+ continue;
+ }
+
+ return auth;
+ }
+
+ return NULL;
+}
+
+
+/** Check ntlm authentication */
+void auth_check_ntlm(auth_mod_t *am,
+ auth_status_t *as,
+ auth_response_t *ar,
+ auth_challenger_t const *ach)
+{
+ char const *a1;
+ auth_hexmd5_t a1buf, response;
+ auth_passwd_t *apw;
+ char const *phrase;
+ msg_time_t now = msg_now();
+
+ if (am == NULL || as == NULL || ar == NULL || ach == NULL) {
+ if (as) {
+ as->as_status = 500, as->as_phrase = "Internal Server Error";
+ as->as_response = NULL;
+ }
+ return;
+ }
+
+ phrase = "Bad authorization";
+
+#define PA "Authorization missing "
+
+ if ((!ar->ar_username && (phrase = PA "username")) ||
+ (!ar->ar_nonce && (phrase = PA "nonce")) ||
+ (!ar->ar_uri && (phrase = PA "URI")) ||
+ (!ar->ar_response && (phrase = PA "response")) ||
+ /* (!ar->ar_opaque && (phrase = PA "opaque")) || */
+ /* Check for qop */
+ (ar->ar_qop &&
+ ((ar->ar_auth &&
+ strcasecmp(ar->ar_qop, "auth") &&
+ strcasecmp(ar->ar_qop, "\"auth\"")) ||
+ (ar->ar_auth_int &&
+ strcasecmp(ar->ar_qop, "auth-int") &&
+ strcasecmp(ar->ar_qop, "\"auth-int\"")))
+ && (phrase = PA "has invalid qop"))) {
+ assert(phrase);
+ SU_DEBUG_5(("auth_method_ntlm: 400 %s\n", phrase));
+ as->as_status = 400, as->as_phrase = phrase;
+ as->as_response = NULL;
+ return;
+ }
+
+ /* XXX - replace */
+#if 0
+ if (as->as_nonce_issued == 0 /* Already validated nonce */ &&
+ auth_validate_ntlm_nonce(am, as, ar, now) < 0) {
+#else
+ if (as->as_nonce_issued == 0 /* Already validated nonce */ &&
+ auth_validate_digest_nonce(am, as, ar, now) < 0) {
+#endif
+ as->as_blacklist = am->am_blacklist;
+ auth_challenge_ntlm(am, as, ach);
+ return;
+ }
+
+ if (as->as_stale) {
+ auth_challenge_ntlm(am, as, ach);
+ return;
+ }
+
+ apw = auth_mod_getpass(am, ar->ar_username, ar->ar_realm);
+
+#if 0
+ if (apw && apw->apw_hash)
+ a1 = apw->apw_hash;
+ else if (apw && apw->apw_pass)
+ auth_ntlm_a1(ar, a1buf, apw->apw_pass), a1 = a1buf;
+ else
+ auth_ntlm_a1(ar, a1buf, "xyzzy"), a1 = a1buf, apw = NULL;
+
+ if (ar->ar_md5sess)
+ auth_ntlm_a1sess(ar, a1buf, a1), a1 = a1buf;
+#else
+ if (apw && apw->apw_hash)
+ a1 = apw->apw_hash;
+ else if (apw && apw->apw_pass)
+ auth_digest_a1(ar, a1buf, apw->apw_pass), a1 = a1buf;
+ else
+ auth_digest_a1(ar, a1buf, "xyzzy"), a1 = a1buf, apw = NULL;
+
+ if (ar->ar_md5sess)
+ auth_digest_a1sess(ar, a1buf, a1), a1 = a1buf;
+#endif
+
+ /* XXX - replace with auth_ntlm_response */
+#if 0
+ auth_ntlm_response(ar, response, a1,
+ as->as_method, as->as_body, as->as_bodylen);
+#else
+ auth_digest_response(ar, response, a1,
+ as->as_method, as->as_body, as->as_bodylen);
+#endif
+
+ if (!apw || strcmp(response, ar->ar_response)) {
+ if (am->am_forbidden) {
+ as->as_status = 403, as->as_phrase = "Forbidden";
+ as->as_blacklist = am->am_blacklist;
+ as->as_response = NULL;
+ }
+ else {
+ auth_challenge_ntlm(am, as, ach);
+ as->as_blacklist = am->am_blacklist;
+ }
+ SU_DEBUG_5(("auth_method_ntlm: response did not match\n"));
+
+ return;
+ }
+
+ assert(apw);
+
+ as->as_user = apw->apw_user;
+ as->as_anonymous = apw == am->am_anon_user;
+
+ if (am->am_nextnonce || am->am_mutual)
+ auth_info_ntlm(am, as, ach);
+
+ if (am->am_challenge)
+ auth_challenge_ntlm(am, as, ach);
+
+ SU_DEBUG_7(("auth_method_ntlm: successful authentication\n"));
+
+ as->as_status = 0; /* Successful authentication! */
+ as->as_phrase = "";
+}
+
+/** Construct a challenge header for @b Ntlm authentication scheme. */
+void auth_challenge_ntlm(auth_mod_t *am,
+ auth_status_t *as,
+ auth_challenger_t const *ach)
+{
+ char const *u, *d;
+ char nonce[AUTH_NTLM_NONCE_LEN];
+
+#if 0
+ auth_generate_ntlm_nonce(am, nonce, sizeof nonce, 0, msg_now());
+#else
+ auth_generate_digest_nonce(am, nonce, sizeof nonce, 0, msg_now());
+#endif
+
+ u = as->as_uri;
+ d = as->as_pdomain;
+
+ as->as_response =
+ msg_header_format(as->as_home, ach->ach_header,
+ "Ntlm"
+ " realm=\"%s\","
+ "%s%s%s"
+ "%s%s%s"
+ " nonce=\"%s\","
+ "%s%s%s"
+ "%s" /* stale */
+ " algorithm=%s"
+ "%s%s%s",
+ as->as_realm,
+ u ? " uri=\"" : "", u ? u : "", u ? "\"," : "",
+ d ? " domain=\"" : "", d ? d : "", d ? "\"," : "",
+ nonce,
+ am->am_opaque ? " opaque=\"" : "",
+ am->am_opaque ? am->am_opaque : "",
+ am->am_opaque ? "\"," : "",
+ as->as_stale ? " stale=true," : "",
+ am->am_algorithm,
+ am->am_qop ? ", qop=\"" : "",
+ am->am_qop ? am->am_qop : "",
+ am->am_qop ? "\"" : "");
+
+ if (!as->as_response)
+ as->as_status = 500, as->as_phrase = auth_internal_server_error;
+ else
+ as->as_status = ach->ach_status, as->as_phrase = ach->ach_phrase;
+}
+
+/** Construct a info header for @b Ntlm authentication scheme. */
+void auth_info_ntlm(auth_mod_t *am,
+ auth_status_t *as,
+ auth_challenger_t const *ach)
+{
+ if (!ach->ach_info)
+ return;
+
+ if (am->am_nextnonce) {
+ char nonce[AUTH_NTLM_NONCE_LEN];
+
+ /* XXX - replace */
+#if 0
+ auth_generate_ntlm_nonce(am, nonce, sizeof nonce, 1, msg_now());
+#else
+ auth_generate_digest_nonce(am, nonce, sizeof nonce, 1, msg_now());
+#endif
+
+ as->as_info =
+ msg_header_format(as->as_home, ach->ach_info, "nextnonce=\"%s\"", nonce);
+ }
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_tag.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_tag.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,252 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE auth_tag.c
+ * @brief Tags for authentication verification module for NTA servers.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Wed Apr 11 15:14:03 2001 ppessi
+ */
+
+#include "config.h"
+
+#define TAG_NAMESPACE "auth"
+
+#include "sofia-sip/auth_module.h"
+
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/url_tag_class.h>
+
+/**@def AUTHTAG_ANY()
+ *
+ * Filter tag matching any AUTHTAG_*().
+ */
+tag_typedef_t authtag_any = NSTAG_TYPEDEF(*);
+
+/**@def AUTHTAG_MODULE()
+ *
+ * Pointer to an authentication server module (auth_mod_t).
+ *
+ * The tag item AUTHTAG_MODULE() contains pointer to an authentication server
+ * module. It is used to pass an already initialized authentication module
+ * to a server object (like web server or registrar object).
+ */
+tag_typedef_t authtag_module = PTRTAG_TYPEDEF(module);
+
+/**@def AUTHTAG_METHOD()
+ *
+ * Name of the authentication scheme.
+ *
+ * The tag AUTHTAG_METHOD() specifies the authentication module and scheme
+ * to be used by the auth_module. The name can specify a basic
+ * authentication module, like "Digest" or "Basic", or an plugin module,
+ * like "SGMF+Digest".
+ *
+ * @sa See <auth_plugin.h> for plugin interface.
+ */
+tag_typedef_t authtag_method = STRTAG_TYPEDEF(method);
+
+/**@def AUTHTAG_REALM()
+ *
+ * Authentication realm used by authentication server.
+ *
+ * The tag authtag_method specifies the authentication realm used by the @b
+ * auth_module. For servers, the domain name in the request URI is inserted
+ * in the realm returned to the client if the realm string contains an
+ * asterisk @c "*". Only the first asterisk is replaced by request domain
+ * name.
+ *
+ * @p Default Value
+ * "*".
+ */
+tag_typedef_t authtag_realm = STRTAG_TYPEDEF(realm);
+
+/**@def AUTHTAG_OPAQUE()
+ *
+ * Opaque data used by authentication server.
+ *
+ * The tag authtag_opaque is used to pass opaque data to the @b auth_module.
+ * The opaque data will be included in all the challenges (however, the data
+ * is prefixed with a "." and other opaque data used by the algorithms.
+ *
+ * @p Default Value
+ * "".
+ */
+tag_typedef_t authtag_opaque = STRTAG_TYPEDEF(opaque);
+
+/**@def AUTHTAG_DB()
+ *
+ * Name of authentication database used by authentication server.
+ *
+ * The tag AUTHTAG_DB() specifies the file name used to store the
+ * authentication data. The file contains triplets as follows:
+ *
+ * @code
+ * user:password:realm
+ * @endcode
+ *
+ * @note
+ * Currently, the passwords are stored as plaintext.
+ */
+tag_typedef_t authtag_db = STRTAG_TYPEDEF(db);
+
+/**@def AUTHTAG_QOP()
+ *
+ * Quality-of-protection used by Digest authentication.
+ *
+ * The tag AUTHTAG_QOP() specifies the qop scheme to be used by the
+ * digest authentication.
+ */
+tag_typedef_t authtag_qop = STRTAG_TYPEDEF(qop);
+
+/**@def AUTHTAG_ALGORITHM()
+ *
+ * Authentication algorithm used by Digest authentication.
+ *
+ * The tag AUTHTAG_ALGORITHM() specifies the qop scheme to be used by the
+ * digest authentication.
+ */
+tag_typedef_t authtag_algorithm = STRTAG_TYPEDEF(algorithm);
+
+/**@def AUTHTAG_EXPIRES()
+ *
+ * Nonce expiration time for Digest authentication.
+ *
+ * The tag AUTHTAG_EXPIRES() specifies the time in seconds that a nonce is
+ * considered valid. If 0, the nonce lifetime unbounded. The default time is
+ * 3600 seconds.
+ */
+tag_typedef_t authtag_expires = UINTTAG_TYPEDEF(expires);
+
+/**@def AUTHTAG_NEXT_EXPIRES()
+ *
+ * Next nonce expiration time for Digest authentication.
+ *
+ * The tag AUTHTAG_NEXT_EXPIRES() specifies the time in seconds that a
+ * nextnonce sent in Authentication-Info header is considered valid. If 0,
+ * the nonce lifetime is unbounded. The default time is 3600 seconds.
+ */
+tag_typedef_t authtag_next_expires = UINTTAG_TYPEDEF(next_expires);
+
+/**@def AUTHTAG_BLACKLIST()
+ *
+ * Blacklist time.
+ *
+ * The tag AUTHTAG_BLACKLIST() specifies the time the server delays its
+ * response if it is given bad credentials or malformed nonce. The default
+ * time is 5 seconds.
+ *
+ * @todo Implement delayed response.
+ */
+tag_typedef_t authtag_blacklist = UINTTAG_TYPEDEF(blacklist);
+
+/**@def AUTHTAG_FORBIDDEN()
+ *
+ * Respond with 403 Forbidden.
+ *
+ * When given a true argument, the tag AUTHTAG_FORBIDDEN() specifies that the
+ * server responds with 403 Forbidden (instead of 401/407) when it receives
+ * bad credentials.
+ */
+tag_typedef_t authtag_forbidden = BOOLTAG_TYPEDEF(forbidden);
+
+/**@def AUTHTAG_ANONYMOUS()
+ *
+ * Allow anonymous access.
+ *
+ * When given a true argument, the tag AUTHTAG_ANONYMOUS() allows
+ * authentication module to accept the account "anonymous" with an empty
+ * password. The auth_status_t::as_anonymous flag is set in auth_status_t
+ * structure after anonymous authentication.
+ */
+tag_typedef_t authtag_anonymous = BOOLTAG_TYPEDEF(anonymous);
+
+/**@def AUTHTAG_FAKE()
+ *
+ * Fake authentication process.
+ *
+ * When given a true argument, the tag AUTHTAG_FAKE() causes authentication
+ * module to allow access with any password when the username is valid. The
+ * auth_status_t::as_fake flag is set in auth_status_t structure after a
+ * fake authentication.
+ */
+tag_typedef_t authtag_fake = BOOLTAG_TYPEDEF(fake);
+
+/**@def AUTHTAG_REMOTE()
+ *
+ * Remote authenticator URL.
+ *
+ * The tag AUTHTAG_REMOTE() is used to specify URL for remote authenticator.
+ * The meaning of the URL is specific to the authentication module. The
+ * authentication module is selected by AUTHTAG_METHOD().
+ */
+tag_typedef_t authtag_remote = URLTAG_TYPEDEF(remote);
+
+/**@def AUTHTAG_ALLOW()
+ *
+ * Comma-separated list of methods that are not challenged.
+ *
+ * The tag AUTHTAG_ALLOW() takes its argument a string containing a
+ * comma-separated list of methods, for example,
+ * @code
+ * AUTHTAG_ALLOW("ACK, BYE, CANCEL").
+ * @endcode
+ *
+ * The specified methods are not challenged by the authentication module.
+ * For example, this may include SIP ACK method or SIP methods only used
+ * within an already established dialog.
+ */
+tag_typedef_t authtag_allow = STRTAG_TYPEDEF(allow);
+
+/**@def AUTHTAG_MASTER_KEY()
+ *
+ * Private master key for the authentication module.
+ *
+ * The tag AUTHTAG_MASTER_KEY() specifies a private master key that can be
+ * used by the authentication module for various purposes (for instance,
+ * validating that nonces are really generated by it).
+ */
+tag_typedef_t authtag_master_key = STRTAG_TYPEDEF(master_key);
+
+/**@def AUTHTAG_CACHE_USERS()
+ *
+ * Time to cache user data.
+ *
+ * The tag AUTHTAG_CACHE_USERS() specifies how many seconds the user data is
+ * cached locally. Default value is typically 30 minutes.
+ */
+tag_typedef_t authtag_cache_users = UINTTAG_TYPEDEF(cache_users);
+
+/**@def AUTHTAG_CACHE_ERRORS()
+ *
+ * Time to cache errors.
+ *
+ * The tag AUTHTAG_CACHE_ERRORS() specifies the lifetime in seconds for
+ * errors in the local authentication data cache. Note that the errors
+ * generated locally (e.g., because of connectivity problem with
+ * authentication server) have maximum lifetime of 2 minutes.
+ */
+tag_typedef_t authtag_cache_errors = UINTTAG_TYPEDEF(cache_errors);
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/iptsec.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/iptsec.docs Thu Dec 21 01:30:28 2006
@@ -0,0 +1,72 @@
+/* -*- C -*- */
+
+/**@MODULEPAGE "iptsec" - Authentication Module
+ *
+ * @section iptsec_meta Module Meta Information
+ *
+ * The iptsec module currently provides interfaces to HTTP
+ * Basic and Digest authentication, used by HTTP and SIP protocol elements.
+ * There are both
+ * @ref auth_client "client-side" and
+ * @ref auth_module "server-side"
+ * (authentication verification) functionality available.
+ *
+ * @CONTACT Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @STATUS @SofiaSIP Core library
+ *
+ * @LICENSE LGPL
+ *
+ * @section auth_module Server Verifying Authentication
+ *
+ * The file <auth_module.h> defines the interface used by a server verifying
+ * the authentication from client. After the server has created an @ref
+ * auth_mod_t "authentication module", the usual authentication operation is
+ * simple enough:
+
+ * -# server initializes an #auth_status_t structure with information from
+ * the request
+ * -# server calls auth_mod_method()
+ * -# server checks the status from auth_status_t structure, sends an error
+ * response to the client if authentication fails
+ * -# server proceeds serving the authenticated request.
+ *
+ * If the operation is asynchronous, only a preliminary result is stored in
+ * the auth_status_t structure when the call to auth_mod_method() returns.
+ * In that case, the application can assign a callback function to the
+ * structure. The callback function is invoked when the authentication
+ * operation is completed. An asynchronous authentication operation can be
+ * terminated before its completion by calling auth_mod_cancel().
+ *
+ * @subsection auth_module_tags Server-Side Authentication Parameters
+ *
+ * When the server creates the authentication module with auth_mod_create(),
+ * it can specify numerous parameters affecting the authentication protocol
+ * and algorithms. The parameter tags are defined in <auth_module.h>. The
+ * most important parameters include:
+ *
+ * - AUTHTAG_METHOD(),
+ * - AUTHTAG_ALGORITHM(),
+ * - AUTHTAG_QOP(), and
+ * - AUTHTAG_REMOTE().
+ *
+ * @section auth_client Client Authenticating User
+ *
+ * The file <auth_client.h> defines the interface used by a client
+ * authenticating a user with a server. Because there may be multiple
+ * servers or proxies requiring authentication, the client-side
+ * authentication information is represented using a list of #auth_client_t
+ * objects. The client-side operation is as follows:
+ *
+ * -# send a request
+ * -# get a response with specific response code (401 or 407) and challenge
+ * -# store the challenge to a list with auc_challenge()
+ * -# prompt user and feed credentials (username and password) to the list
+ * with auc_credentials() or auc_all_credentials()
+ * -# authorize a request (add credential headers to it) with
+ * auc_authorization() and resend the request
+ *
+ * If there are several username/password pairs for multiple authentication
+ * realms required, the application must provide the corresponding realm as
+ * an argument to auc_all_credentials().
+ */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/iptsec_debug.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/iptsec_debug.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,61 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@file iptsec_debug.c
+ * @brief Debug log for IPTSEC module.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Dec 19 15:55:30 2002 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+
+#include "iptsec_debug.h"
+
+/**@var IPTSEC_DEBUG
+ *
+ * Environment variable determining the debug log level for @b iptsec
+ * module.
+ *
+ * The IPTSEC_DEBUG environment variable is used to determine the debug
+ * logging level for @b iptsec module. The default level is 3.
+ *
+ * @sa <su_debug.h>, iptsec_log, SOFIA_DEBUG
+ */
+extern char const IPTSEC_DEBUG[];
+
+#ifndef SU_DEBUG
+#define SU_DEBUG 3
+#endif
+
+/**Debug log for @b iptsec module.
+ *
+ * The iptsec_log is the log object used by @b iptsec module. The level of
+ * #iptsec_log is set using #IPTSEC_DEBUG environment variable.
+ */
+su_log_t iptsec_log[] = { SU_LOG_INIT("iptsec", "IPTSEC_DEBUG", SU_DEBUG) };
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/iptsec_debug.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/iptsec_debug.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,50 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef IPTSEC_DEBUG_H
+/** Defined when <iptsec_debug.h> has been included. */
+#define IPTSEC_DEBUG_H
+
+/**@file iptsec_debug.h
+ * @brief Debug log for IPTSEC module.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Dec 19 15:56:35 2002 ppessi
+ */
+
+#include <sofia-sip/su_log.h>
+
+SOFIA_BEGIN_DECLS
+
+/** Common log for application and srvlib components. */
+SOFIAPUBVAR su_log_t iptsec_log[];
+
+SOFIA_END_DECLS
+
+#define SU_LOG (iptsec_log)
+
+#include <sofia-sip/su_debug.h>
+
+#endif /* !defined IPTSEC_DEBUG_H */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_client.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_client.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,108 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef AUTH_CLIENT_H
+/** Defined when <sofia-sip/auth_client.h> has been included. */
+#define AUTH_CLIENT_H
+
+/**@file sofia-sip/auth_client.h
+ *
+ * @brief Client-side authenticator library.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Feb 14 17:09:44 2001 ppessi
+ */
+
+#ifndef MSG_TYPES_H
+#include <sofia-sip/msg_types.h>
+#endif
+
+#ifndef URL_H
+#include <sofia-sip/url.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** Authenticator object. */
+typedef struct auth_client_s auth_client_t;
+
+SOFIAPUBFUN
+int auc_challenge(auth_client_t **auc, su_home_t *home,
+ msg_auth_t const *auth,
+ msg_hclass_t *crcl);
+
+SOFIAPUBFUN
+int auc_credentials(auth_client_t **auc, su_home_t *home, char const *data);
+
+SOFIAPUBFUN
+int auc_info(auth_client_t **auc_list,
+ msg_auth_info_t const *ai,
+ msg_hclass_t *credential_class);
+
+SOFIAPUBFUN
+int auc_all_credentials(auth_client_t **auc_list,
+ char const *scheme,
+ char const *realm,
+ char const *user,
+ char const *pass);
+
+SOFIAPUBFUN
+int auc_clear_credentials(auth_client_t **auc_list,
+ char const *scheme,
+ char const *realm);
+
+SOFIAPUBFUN
+int auc_copy_credentials(auth_client_t **dst, auth_client_t const *src);
+
+SOFIAPUBFUN
+int auc_has_authorization(auth_client_t **auc_list);
+
+SOFIAPUBFUN
+int auc_authorization(auth_client_t **auc_list, msg_t *msg, msg_pub_t *pub,
+ char const *method,
+ url_t const *url,
+ msg_payload_t const *body);
+
+SOFIAPUBFUN
+int auc_authorization_headers(auth_client_t **auc_list,
+ su_home_t *home,
+ char const *method,
+ url_t const *url,
+ msg_payload_t const *body,
+ msg_header_t **return_headers);
+
+struct sip_s;
+
+SOFIAPUBFUN
+int auc_authorize(auth_client_t **auc, msg_t *msg, struct sip_s *sip);
+
+typedef struct auth_client_plugin auth_client_plugin_t;
+
+SOFIAPUBFUN
+int auc_register_plugin(auth_client_plugin_t const *plugin);
+
+SOFIA_END_DECLS
+
+#endif
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_client_plugin.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_client_plugin.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,88 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef AUTH_CLIENT_PLUGIN_H
+/** Defined when <sofia-sip/auth_client_plugin.h> has been included. */
+#define AUTH_CLIENT_PLUGIN_H
+
+/**@file sofia-sip/auth_client_plugin.h
+ * @brief Client-side plugin interface for authentication
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Fri May 19 16:18:21 EEST 2006
+ */
+
+#ifndef AUTH_CLIENT_H
+#include "sofia-sip/auth_client.h"
+#endif
+
+#ifndef MSG_HEADER_H
+#include <sofia-sip/msg_header.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/* ====================================================================== */
+
+struct auth_client_s {
+ su_home_t ca_home[1];
+ auth_client_plugin_t const *ca_auc;
+
+ auth_client_t *ca_next;
+
+ char const *ca_scheme;
+ char const *ca_realm;
+ char *ca_user;
+ char *ca_pass;
+
+ msg_hclass_t *ca_credential_class;
+};
+
+struct auth_client_plugin
+{
+ int auc_plugin_size; /* Size of this structure */
+ int auc_size; /* Size of the client structure */
+
+ char const *auc_name; /* Name of the autentication scheme */
+
+ /** Store challenge */
+ int (*auc_challenge)(auth_client_t *ca,
+ msg_auth_t const *ch);
+
+ /** Authorize request. */
+ int (*auc_authorize)(auth_client_t *ca,
+ su_home_t *h,
+ char const *method,
+ url_t const *url,
+ msg_payload_t const *body,
+ msg_header_t **return_headers);
+
+ /** Store nextnonce from Authentication-Info or Proxy-Authentication-Info. */
+ int (*auc_info)(auth_client_t *ca, msg_auth_info_t const *ai);
+};
+
+SOFIA_END_DECLS
+
+#endif /* !defined AUTH_CLIENT_PLUGIN_H */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_common.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_common.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,55 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef AUTH_COMMON_H
+/** Defined when <sofia-sip/auth_common.h> has been included. */
+#define AUTH_COMMON_H
+
+/**@file sofia-sip/auth_common.h
+ *
+ * Functions common for client/server.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Fri May 19 15:54:08 EEST 2006 ppessi
+ */
+
+#ifndef SU_ALLOC_H
+#include <sofia-sip/su_alloc.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+SOFIAPUBFUN issize_t auth_get_params(su_home_t *home,
+ char const * const params[], ...
+ /* char const * name,
+ char const **return_value */);
+
+SOFIAPUBFUN int auth_struct_copy(void *dst, void const *src, isize_t s_size);
+
+SOFIAPUBFUN int auth_strcmp(char const *quoted, char const *unquoted);
+
+SOFIA_END_DECLS
+
+#endif
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_digest.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_digest.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,167 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef AUTH_DIGEST_H
+/** Defined when <sofia-sip/auth_digest.h> has been included. */
+#define AUTH_DIGEST_H
+
+/**@file sofia-sip/auth_digest.h
+ * Datatypes and functions for Digest authentication.
+ *
+ * The structures and functions here follow the RFC 2617.
+ *
+ * @sa @RFC2617,
+ * <i>"HTTP Authentication: Basic and Digest Access Authentication"</i>,
+ * J. Franks et al,
+ * June 1999.
+ *
+ * @sa @RFC3261 section 22
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Feb 22 12:25:55 2001 ppessi
+ */
+
+#ifndef SU_ALLOC_H
+#include <sofia-sip/su_alloc.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** Parameters for digest-challenge.
+ *
+ * The digest-challenge is sent by server or proxy to client. It can be
+ * included in, e.g, WWW-Authenticate or Proxy-Authenticate headers.
+ *
+ * @code
+ * challenge = "Digest" digest-challenge
+ * digest-challenge = 1#( realm | [domain] | nonce |
+ * [opaque] | [stale] | [algorithm] |
+ * [qop-options] | [auth-param] )
+ * domain = "domain" "=" <"> URI ( 1*SP URI ) <">
+ * URI = absoluteURI | abs_path
+ * nonce = "nonce" "=" nonce-value
+ * nonce-value = quoted-string
+ * opaque = "opaque" "=" quoted-string
+ * stale = "stale" "=" ( "true" | "false" )
+ * algorithm = "algorithm" "=" ( "MD5" | "MD5-sess" | token )
+ * qop-options = "qop" "=" <"> 1#qop-value <">
+ * qop-value = "auth" | "auth-int" | token
+ * @endcode
+ *
+ * @sa @RFC2617
+ */
+typedef struct {
+ int ac_size;
+ char const *ac_realm; /**< realm */
+ char const *ac_domain; /**< domain */
+ char const *ac_nonce; /**< nonce */
+ char const *ac_opaque; /**< opaque */
+ char const *ac_algorithm; /**< algorithm */
+ char const *ac_qop; /**< qop */
+ unsigned ac_stale : 1; /**< stale=true */
+ unsigned ac_md5 : 1; /**< algorithm=MS5 (or missing) */
+ unsigned ac_md5sess : 1; /**< algorithm=MD5-sess */
+ unsigned ac_sha1 : 1; /**< algorithm=sha1 (SSA Hash) */
+ unsigned ac_auth : 1; /**< qop=auth */
+ unsigned ac_auth_int : 1; /**< qop=auth-int */
+ unsigned : 0;
+} auth_challenge_t;
+
+/** Digest parameters for digest-response in Authorize.
+ *
+ * The digest-response is sent by the client to a server or a proxy. It can
+ * be included in, e.g., Authorization or Proxy-Authorization headers.
+ *
+ * @code
+ * credentials = "Digest" digest-response
+ * digest-response = 1#( username | realm | nonce | digest-uri |
+ * response | [ algorithm ] | [cnonce] | [opaque] |
+ * [message-qop] | [nonce-count] | [auth-param] )
+ * username = "username" "=" username-value
+ * username-value = quoted-string
+ * digest-uri = "uri" "=" digest-uri-value
+ * digest-uri-value = request-uri ; As specified by HTTP/1.1
+ * message-qop = "qop" "=" qop-value
+ * cnonce = "cnonce" "=" cnonce-value
+ * cnonce-value = nonce-value
+ * nonce-count = "nc" "=" nc-value
+ * nc-value = 8LHEX
+ * response = "response" "=" request-digest
+ * request-digest = <"> 32LHEX <">
+ * LHEX = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" |
+ * "8" | "9" | "a" | "b" | "c" | "d" | "e" | "f"
+ * @endcode
+ */
+typedef struct {
+ int ar_size;
+ char const *ar_username;
+ char const *ar_realm; /**< realm */
+ char const *ar_nonce; /**< nonce */
+ char const *ar_uri; /**< uri */
+ char const *ar_response; /**< response */
+ char const *ar_algorithm; /**< algorithm */
+ char const *ar_cnonce; /**< cnonce */
+ char const *ar_opaque; /**< opaque */
+ char const *ar_qop; /**< qop */
+ char const *ar_nc; /**< nonce count */
+ unsigned ar_md5 : 1; /**< MS5 algorithm */
+ unsigned ar_md5sess : 1; /**< MD5-sess algorithm */
+ unsigned ar_sha1 : 1; /**< SHA1 algorithm */
+ unsigned ar_auth : 1; /**< qop=auth */
+ unsigned ar_auth_int : 1; /**< qop=auth-int */
+ unsigned : 0;
+} auth_response_t;
+
+typedef char auth_hexmd5_t[33];
+
+SOFIAPUBFUN issize_t auth_digest_challenge_get(su_home_t *, auth_challenge_t *,
+ char const * const params[]);
+SOFIAPUBFUN void auth_digest_challenge_free_params(su_home_t *home,
+ auth_challenge_t *ac);
+SOFIAPUBFUN issize_t auth_digest_response_get(su_home_t *, auth_response_t *,
+ char const * const params[]);
+
+SOFIAPUBFUN int auth_digest_a1(auth_response_t *ar,
+ auth_hexmd5_t ha1,
+ char const *secret);
+
+SOFIAPUBFUN int auth_digest_a1sess(auth_response_t *ar,
+ auth_hexmd5_t ha1sess,
+ char const *ha1);
+
+SOFIAPUBFUN int auth_digest_sessionkey(auth_response_t *, auth_hexmd5_t ha1,
+ char const *secret);
+SOFIAPUBFUN int auth_digest_response(auth_response_t *, auth_hexmd5_t response,
+ auth_hexmd5_t const ha1,
+ char const *method_name,
+ void const *data, isize_t dlen);
+
+SOFIAPUBFUN int auth_struct_copy(void *dst, void const *src, isize_t s_size);
+
+SOFIAPUBFUN int auth_strcmp(char const *quoted, char const *unquoted);
+
+SOFIA_END_DECLS
+
+#endif
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_module.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_module.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,404 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef AUTH_MODULE_H
+/** Defined when <sofia-sip/auth_module.h> has been included. */
+#define AUTH_MODULE_H
+
+/**@file sofia-sip/auth_module.h
+ * @brief Authentication verification interface.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Mon Jul 23 19:21:24 2001 ppessi
+ */
+
+#ifndef SU_TAG_H
+#include <sofia-sip/su_tag.h>
+#endif
+#ifndef SU_WAIT_H
+#include <sofia-sip/su_wait.h>
+#endif
+#ifndef MSG_TYPES_H
+#include <sofia-sip/msg_types.h>
+#endif
+#ifndef URL_H
+#include <sofia-sip/url.h>
+#endif
+#ifndef URL_TAG_H
+#include <sofia-sip/url_tag.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+typedef struct auth_mod_t auth_mod_t;
+/** Authentication operation. */
+typedef struct auth_status_t auth_status_t;
+
+#ifdef AUTH_MAGIC_T
+typedef AUTH_MAGIC_T auth_magic_t;
+#else
+typedef void auth_magic_t;
+#endif
+
+/** Virtual table for authentication plugin. */
+typedef struct auth_scheme const auth_scheme_t;
+
+/** Opaque data used by authentication plugin module. */
+typedef struct auth_plugin_t auth_plugin_t;
+/** Opaque user data used by plugin module. */
+typedef struct auth_splugin_t auth_splugin_t;
+/** Opaque authentication operation data used by plugin module. */
+typedef struct auth_uplugin_t auth_uplugin_t;
+
+/** Callback from completeted asynchronous authentication operation. */
+typedef void auth_callback_t(auth_magic_t *, auth_status_t *);
+
+/**Authentication operation result.
+ *
+ * The auth_status_t structure is used to store the status of the
+ * authentication operation and all the related data. The application
+ * verifying the authentication fills the auth_status_t structure, then
+ * calls auth_mod_method() (or auth_mod_challenge()). The operation result
+ * is stored in the structure.
+ *
+ * If the operation is asynchronous, only a preliminary result is stored in
+ * the auth_status_t structure when the call to auth_mod_method() returns.
+ * In that case, the application @b must assign a callback function to the
+ * structure. The callback function is invoked when the authentication
+ * operation is completed.
+ *
+ * It is recommended that the auth_status_t structure is allocated with
+ * auth_status_new() or initialized with auth_status_init() or
+ * auth_status_init_with() functions.
+ */
+struct auth_status_t
+{
+ su_home_t as_home[1]; /**< Memory home for authentication */
+
+ int as_status; /**< Return authorization status [out] */
+ char const *as_phrase; /**< Return response phrase [out] */
+ char const *as_user; /**< Authenticated username [in/out] */
+ char const *as_display; /**< Return user's real name [in/out] */
+
+ url_t const *as_user_uri; /* Return user's identity [in/out] */
+ char const *as_ident; /**< Identities [out] */
+ unsigned as_profile; /**< User profile (group) [out] */
+
+ su_addrinfo_t *as_source; /**< Source address [in] */
+
+ char const *as_realm; /**< Authentication realm [in] */
+ char const *as_domain; /**< Hostname [in] */
+ char const *as_uri; /**< Request-URI [in] */
+ char const *as_pdomain; /**< Domain parameter [in] (ignored). */
+ char const *as_method; /**< Method name to authenticate [in] */
+
+ void const *as_body; /**< Message body to protect [in] */
+ isize_t as_bodylen; /**< Length of message body [in] */
+
+ msg_time_t as_nonce_issued; /**< Nonce issue time [out] */
+ unsigned as_blacklist; /**< Blacklist time [out] */
+ unsigned as_anonymous:1;/**< Return true if user is anonymous [out] */
+ unsigned as_stale:1; /**< Credentials were stale [out] */
+ unsigned as_allow:1; /**< Method cannot be challenged [out] */
+ unsigned as_nextnonce:1; /**< Client used nextnonce [out] */
+ unsigned :0;
+
+ msg_header_t *as_response; /**< Authentication challenge [out] */
+ msg_header_t *as_info; /**< Authentication-Info [out] */
+ msg_header_t *as_match; /**< Used authentication header [out] */
+
+ /** @defgroup Callback information for asynchronous operation. */
+ /** @{ */
+ auth_magic_t *as_magic; /**< Application data [in] */
+ auth_callback_t*as_callback; /**< Completion callback [in] */
+ /** @} */
+
+ /** Pointer to extended state, used exclusively by plugin modules. */
+ auth_splugin_t *as_plugin;
+};
+
+/** Authentication challenge.
+ *
+ * This structure defines what kind of response and challenge header is
+ * returned to the user. For example, a server authentication is implemented
+ * with 401 response code and phrase along with header class for
+ * @b WWW-Authenticate header in the @a ach structure.
+ */
+typedef struct auth_challenger
+{
+ int ach_status; /**< Response status for challenge response */
+ char const *ach_phrase; /**< Response phrase for challenge response */
+ msg_hclass_t *ach_header; /**< Header class for challenge header */
+ msg_hclass_t *ach_info;
+} auth_challenger_t;
+
+SOFIAPUBVAR char const auth_internal_server_error[];
+
+#define AUTH_STATUS_INIT \
+ {{ SU_HOME_INIT(auth_status_t) }, 500, auth_internal_server_error, NULL }
+
+#define AUTH_STATUS_DEINIT(as) \
+ su_home_deinit(as->as_home)
+
+#define AUTH_RESPONSE_INIT(as) AUTH_STATUS_INIT
+#define AUTH_RESPONSE_DEINIT(as) AUTH_STATUS_DEINIT(as)
+
+SOFIAPUBFUN int auth_mod_register_plugin(auth_scheme_t *asch);
+
+SOFIAPUBFUN auth_mod_t *auth_mod_create(su_root_t *root,
+ tag_type_t, tag_value_t, ...);
+SOFIAPUBFUN void auth_mod_destroy(auth_mod_t *);
+
+SOFIAPUBFUN auth_mod_t *auth_mod_ref(auth_mod_t *am);
+SOFIAPUBFUN void auth_mod_unref(auth_mod_t *am);
+
+SOFIAPUBFUN char const *auth_mod_name(auth_mod_t *am);
+
+SOFIAPUBFUN auth_status_t *auth_status_init(void *, isize_t size);
+SOFIAPUBFUN auth_status_t *auth_status_init_with(void *, isize_t size,
+ int status,
+ char const *phrase);
+
+SOFIAPUBFUN auth_status_t *auth_status_new(su_home_t *);
+
+SOFIAPUBFUN auth_status_t *auth_status_ref(auth_status_t *as);
+
+SOFIAPUBFUN void auth_status_unref(auth_status_t *as);
+
+SOFIAPUBFUN void auth_mod_verify(auth_mod_t *am,
+ auth_status_t *as,
+ msg_auth_t *credentials,
+ auth_challenger_t const *ach);
+
+SOFIAPUBFUN void auth_mod_challenge(auth_mod_t *am,
+ auth_status_t *as,
+ auth_challenger_t const *ach);
+
+SOFIAPUBFUN void auth_mod_authorize(auth_mod_t *am,
+ auth_status_t *as,
+ auth_challenger_t const *ach);
+
+SOFIAPUBFUN void auth_mod_cancel(auth_mod_t *am, auth_status_t *as);
+
+/* ====================================================================== */
+/* Deprecated functions */
+
+typedef enum {
+ auth_server,
+ auth_proxy,
+ auth_proxy_consume,
+ auth_consume
+} auth_kind_t;
+
+SOFIAPUBFUN void auth_mod_method(auth_mod_t *am,
+ auth_status_t *as,
+ msg_auth_t *credentials,
+ auth_challenger_t const *ach);
+
+SOFIAPUBFUN void auth_mod_check_client(auth_mod_t *am,
+ auth_status_t *as,
+ msg_auth_t *credentials,
+ auth_challenger_t const *ach);
+
+SOFIAPUBFUN void auth_mod_challenge_client(auth_mod_t *am,
+ auth_status_t *as,
+ auth_challenger_t const *ach);
+
+#ifdef SIP_H
+SOFIAPUBFUN void auth_mod_check(auth_mod_t *am,
+ auth_status_t *as,
+ sip_t const *sip,
+ auth_kind_t proxy);
+#endif
+
+#ifdef HTTP_H
+SOFIAPUBFUN const char *auth_mod_check_http(auth_mod_t *am,
+ auth_status_t *as,
+ http_t const *http,
+ auth_kind_t proxy);
+#endif
+
+/* ====================================================================== */
+/* Tags */
+
+#define AUTHTAG_ANY() authtag_any, ((tag_value_t)0)
+SOFIAPUBVAR tag_typedef_t authtag_any;
+
+/** Pointer to an authentication server (auth_mod_t). */
+#define AUTHTAG_MODULE(x) authtag_module, authtag_module_v((x))
+SOFIAPUBVAR tag_typedef_t authtag_module;
+
+#define AUTHTAG_MODULE_REF(x) authtag_module_ref, authtag_module_vr((&x))
+SOFIAPUBVAR tag_typedef_t authtag_module_ref;
+
+#if SU_HAVE_INLINE
+static inline tag_value_t authtag_module_v(auth_mod_t *v) {
+ return (tag_value_t)v;
+}
+static inline tag_value_t authtag_module_vr(auth_mod_t **vp) {
+ return (tag_value_t)vp;
+}
+#else
+#define authtag_module_v(v) ((tag_value_t)(v))
+#define authtag_module_vr(v) ((tag_value_t)(v))
+#endif
+
+/** Authentication scheme used by authentication module. */
+#define AUTHTAG_METHOD(x) authtag_method, tag_str_v((x))
+SOFIAPUBVAR tag_typedef_t authtag_method;
+
+#define AUTHTAG_METHOD_REF(x) authtag_method_ref, tag_str_vr((&x))
+SOFIAPUBVAR tag_typedef_t authtag_method_ref;
+
+/** Authentication realm used by authentication server. */
+#define AUTHTAG_REALM(x) authtag_realm, tag_str_v((x))
+SOFIAPUBVAR tag_typedef_t authtag_realm;
+
+#define AUTHTAG_REALM_REF(x) authtag_realm_ref, tag_str_vr((&x))
+SOFIAPUBVAR tag_typedef_t authtag_realm_ref;
+
+/** Opaque authentication data always included in challenge. */
+#define AUTHTAG_OPAQUE(x) authtag_opaque, tag_str_v((x))
+SOFIAPUBVAR tag_typedef_t authtag_opaque;
+
+#define AUTHTAG_OPAQUE_REF(x) authtag_opaque_ref, tag_str_vr((&x))
+SOFIAPUBVAR tag_typedef_t authtag_opaque_ref;
+
+/** Name of authentication database used by authentication server. */
+#define AUTHTAG_DB(x) authtag_db, tag_str_v((x))
+SOFIAPUBVAR tag_typedef_t authtag_db;
+
+#define AUTHTAG_DB_REF(x) authtag_db_ref, tag_str_vr((&x))
+SOFIAPUBVAR tag_typedef_t authtag_db_ref;
+
+/** Quality-of-protection used by digest authentication. */
+#define AUTHTAG_QOP(x) authtag_qop, tag_str_v((x))
+SOFIAPUBVAR tag_typedef_t authtag_qop;
+
+#define AUTHTAG_QOP_REF(x) authtag_qop_ref, tag_str_vr((&x))
+SOFIAPUBVAR tag_typedef_t authtag_qop_ref;
+
+/** Algorithm used by digest authentication. */
+#define AUTHTAG_ALGORITHM(x) authtag_algorithm, tag_str_v((x))
+SOFIAPUBVAR tag_typedef_t authtag_algorithm;
+
+#define AUTHTAG_ALGORITHM_REF(x) authtag_algorithm_ref, tag_str_vr((&x))
+SOFIAPUBVAR tag_typedef_t authtag_algorithm_ref;
+
+/** Nonce lifetime. */
+#define AUTHTAG_EXPIRES(x) authtag_expires, tag_uint_v((x))
+SOFIAPUBVAR tag_typedef_t authtag_expires;
+
+#define AUTHTAG_EXPIRES_REF(x) authtag_expires_ref, tag_uint_vr((&x))
+SOFIAPUBVAR tag_typedef_t authtag_expires_ref;
+
+/** Lifetime for nextnonce, 0 disables nextnonce. */
+#define AUTHTAG_NEXT_EXPIRES(x) authtag_next_expires, tag_uint_v((x))
+SOFIAPUBVAR tag_typedef_t authtag_next_expires;
+
+#define AUTHTAG_NEXT_EXPIRES_REF(x) \
+ authtag_next_expires_ref, tag_uint_vr((&x))
+SOFIAPUBVAR tag_typedef_t authtag_next_expires_ref;
+
+/** Extra delay when responding if provided invalid credentials or nonce. */
+#define AUTHTAG_BLACKLIST(x) authtag_blacklist, tag_uint_v((x))
+SOFIAPUBVAR tag_typedef_t authtag_blacklist;
+
+#define AUTHTAG_BLACKLIST_REF(x) authtag_blacklist_ref, tag_uint_vr((&x))
+SOFIAPUBVAR tag_typedef_t authtag_blacklist_ref;
+
+/** Respond with 403 Forbidden if given invalid credentials. */
+#define AUTHTAG_FORBIDDEN(x) authtag_forbidden, tag_bool_v((x))
+SOFIAPUBVAR tag_typedef_t authtag_forbidden;
+
+#define AUTHTAG_FORBIDDEN_REF(x) authtag_forbidden_ref, tag_bool_vr((&x))
+SOFIAPUBVAR tag_typedef_t authtag_forbidden_ref;
+
+/** Allow anonymous access. */
+#define AUTHTAG_ANONYMOUS(x) authtag_anonymous, tag_bool_v((x))
+SOFIAPUBVAR tag_typedef_t authtag_anonymous;
+
+#define AUTHTAG_ANONYMOUS_REF(x) authtag_anonymous_ref, tag_bool_vr((&x))
+SOFIAPUBVAR tag_typedef_t authtag_anonymous_ref;
+
+/** Fake authentication procedure - do not check result. */
+#define AUTHTAG_FAKE(x) authtag_fake, tag_bool_v((x))
+SOFIAPUBVAR tag_typedef_t authtag_fake;
+
+#define AUTHTAG_FAKE_REF(x) authtag_fake_ref, tag_bool_vr((&x))
+SOFIAPUBVAR tag_typedef_t authtag_fake_ref;
+
+/** HSS client structure. */
+#define AUTHTAG_HSS(x) authtag_hss, tag_ptr_v((x))
+SOFIAPUBVAR tag_typedef_t authtag_hss;
+
+#define AUTHTAG_HSS_REF(x) authtag_hss_ref, tag_ptr_vr((&x), (x))
+SOFIAPUBVAR tag_typedef_t authtag_hss_ref;
+
+/** Remote authenticator URL. */
+#define AUTHTAG_REMOTE(x) authtag_remote, urltag_url_v((x))
+SOFIAPUBVAR tag_typedef_t authtag_remote;
+
+#define AUTHTAG_REMOTE_REF(x) authtag_remote_ref, urltag_url_vr((&x))
+SOFIAPUBVAR tag_typedef_t authtag_remote_ref;
+
+/** Comma-separated list of methods never challenged. */
+#define AUTHTAG_ALLOW(x) authtag_allow, tag_str_v((x))
+SOFIAPUBVAR tag_typedef_t authtag_allow;
+
+#define AUTHTAG_ALLOW_REF(x) authtag_allow_ref, tag_str_vr((&x))
+SOFIAPUBVAR tag_typedef_t authtag_allow_ref;
+
+/** Check that user exists, don't do authentication. */
+#define AUTHTAG_FAKE(x) authtag_fake, tag_bool_v((x))
+SOFIAPUBVAR tag_typedef_t authtag_fake;
+
+#define AUTHTAG_FAKE_REF(x) authtag_fake_ref, tag_bool_vr((&x))
+SOFIAPUBVAR tag_typedef_t authtag_fake_ref;
+
+/** Master key in base64 for the authentication module. */
+#define AUTHTAG_MASTER_KEY(x) authtag_master_key, tag_str_v((x))
+SOFIAPUBVAR tag_typedef_t authtag_master_key;
+
+#define AUTHTAG_MASTER_KEY_REF(x) authtag_master_key_ref, tag_str_vr((&x))
+SOFIAPUBVAR tag_typedef_t authtag_master_key_ref;
+
+/** Cache time for authentication data. */
+#define AUTHTAG_CACHE_USERS(x) authtag_cache_users, tag_uint_v((x))
+SOFIAPUBVAR tag_typedef_t authtag_cache_users;
+
+#define AUTHTAG_CACHE_USERS_REF(x) authtag_cache_users_ref, tag_uint_vr((&x))
+SOFIAPUBVAR tag_typedef_t authtag_cache_users_ref;
+
+/** Cache time for errors. */
+#define AUTHTAG_CACHE_ERRORS(x) authtag_cache_errors, tag_uint_v((x))
+SOFIAPUBVAR tag_typedef_t authtag_cache_errors;
+
+#define AUTHTAG_CACHE_ERRORS_REF(x) authtag_cache_errors_ref, tag_uint_vr((&x))
+SOFIAPUBVAR tag_typedef_t authtag_cache_errors_ref;
+
+SOFIA_END_DECLS
+
+#endif
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_ntlm.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_ntlm.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,117 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef AUTH_NTLM_H
+/** Defined when <sofia-sip/auth_ntlm.h> has been included. */
+#define AUTH_NTLM_H
+
+/**@file sofia-sip/auth_ntlm.h
+ * Datatypes and functions for Ntlm authentication.
+ *
+ * The structures and functions here follow the RFC 2617.
+ *
+ * @sa
+ * <a href="ftp://ftp.ietf.org/rfc/rfc2617.txt">RFC 2617</a>,
+ * <i>"HTTP Authentication: Basic and Ntlm Access Authentication"</i>,
+ * J. Franks et al,
+ * June 1999.
+ *
+ * @sa Section 19 from
+ * <a href="ftp://ftp.ietf.org/internet-drafts/draft-ietf-sip-rfc2543bis-04.txt>draft-ietf-sip-rfc2543bis-04</a>.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Feb 22 12:25:55 2001 ppessi
+ */
+
+#ifndef SU_ALLOC_H
+#include <sofia-sip/su_alloc.h>
+#endif
+
+#ifndef AUTH_PLUGIN_H
+#include <sofia-sip/auth_plugin.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+issize_t auth_ntlm_challenge_get(su_home_t *, auth_challenge_t *,
+ char const * const params[]);
+issize_t auth_ntlm_response_get(su_home_t *, auth_response_t *,
+ char const * const params[]);
+
+int auth_ntlm_a1(auth_response_t *ar,
+ auth_hexmd5_t ha1,
+ char const *secret);
+
+int auth_ntlm_a1sess(auth_response_t *ar,
+ auth_hexmd5_t ha1sess,
+ char const *ha1);
+
+int auth_ntlm_sessionkey(auth_response_t *, auth_hexmd5_t ha1,
+ char const *secret);
+int auth_ntlm_response(auth_response_t *, auth_hexmd5_t response,
+ auth_hexmd5_t const ha1,
+ char const *method_name, void const *data, issize_t dlen);
+
+/** NTLM scheme */
+msg_auth_t *auth_ntlm_credentials(msg_auth_t *auth,
+ char const *realm,
+ char const *opaque,
+ char const *gssapidata,
+ char const *targetname);
+
+void auth_challenge_ntlm(auth_mod_t *am,
+ auth_status_t *as,
+ auth_challenger_t const *ach);
+
+
+void auth_method_ntlm(auth_mod_t *am,
+ auth_status_t *as,
+ msg_auth_t *au,
+ auth_challenger_t const *ach);
+
+
+void auth_check_ntlm(auth_mod_t *am,
+ auth_status_t *as,
+ auth_response_t *ar,
+ auth_challenger_t const *ach);
+
+int auth_generate_ntlm_nonce(auth_mod_t *am,
+ char buffer[],
+ size_t buffer_len,
+ int nextnonce,
+ msg_time_t now);
+
+int auth_validate_ntlm_nonce(auth_mod_t *am,
+ auth_status_t *as,
+ auth_response_t *ar,
+ msg_time_t now);
+
+void auth_info_ntlm(auth_mod_t *am,
+ auth_status_t *as,
+ auth_challenger_t const *ach);
+
+SOFIA_END_DECLS
+
+#endif
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_plugin.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_plugin.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,266 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef AUTH_PLUGIN_H
+/** Defined when <sofia-sip/auth_plugin.h> has been included. */
+#define AUTH_PLUGIN_H
+
+/**@file sofia-sip/auth_plugin.h
+ * @brief Plugin interface for authentication verification modules.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Apr 27 15:22:07 2004 ppessi
+ */
+
+#ifndef AUTH_MODULE_H
+#include "sofia-sip/auth_module.h"
+#endif
+
+#ifndef AUTH_DIGEST_H
+#include "sofia-sip/auth_digest.h"
+#endif
+
+#ifndef AUTH_COMMON_H
+#include "sofia-sip/auth_common.h"
+#endif
+
+#ifndef MSG_DATE_H
+#include <sofia-sip/msg_date.h>
+#endif
+
+#ifndef SU_MD5_H
+#include <sofia-sip/su_md5.h>
+#endif
+
+#include <sofia-sip/htable.h>
+
+SOFIA_BEGIN_DECLS
+
+/* ====================================================================== */
+/* Plugin interface for authentication */
+
+/** Authentication scheme */
+struct auth_scheme
+{
+ /** Name */
+ char const *asch_method;
+
+ /** Size of module object */
+ usize_t asch_size;
+
+ /** Initialize module. Invoked by auth_mod_create(). */
+ int (*asch_init)(auth_mod_t *am,
+ auth_scheme_t *base,
+ su_root_t *root,
+ tag_type_t tag, tag_value_t value, ...);
+
+ /** Check authentication. Invoked by auth_mod_method(). */
+ void (*asch_check)(auth_mod_t *am,
+ auth_status_t *as,
+ msg_auth_t *auth,
+ auth_challenger_t const *ch);
+
+ /** Create a challenge. Invoked by auth_mod_challenge(). */
+ void (*asch_challenge)(auth_mod_t *am,
+ auth_status_t *as,
+ auth_challenger_t const *ch);
+
+ /** Cancel an asynchronous authentication request.
+ * Invoked by auth_mod_cancel().
+ */
+ void (*asch_cancel)(auth_mod_t *am,
+ auth_status_t *as);
+
+ /** Reclaim resources an authentication module.
+ *
+ * Invoked by auth_mod_destroy()/auth_mod_unref().
+ */
+ void (*asch_destroy)(auth_mod_t *am);
+
+};
+
+/** User data structure */
+typedef struct
+{
+ unsigned apw_index; /**< Key to hash table */
+ void const *apw_type; /**< Magic pointer */
+
+ char const *apw_user; /**< Username */
+ char const *apw_realm; /**< Realm */
+ char const *apw_pass; /**< Password */
+ char const *apw_hash; /**< MD5 of the username, realm and pass */
+ char const *apw_ident; /**< Identity information */
+ auth_uplugin_t *apw_extended; /**< Method-specific extension */
+} auth_passwd_t;
+
+
+HTABLE_DECLARE_WITH(auth_htable, aht, auth_passwd_t, usize_t, unsigned);
+
+struct stat;
+
+/** Common data for authentication module */
+struct auth_mod_t
+{
+ su_home_t am_home[1];
+ unsigned am_refcount; /**< Number of references to this module */
+
+ /* User database / cache */
+ char const *am_db; /**< User database file name */
+ struct stat *am_stat; /**< State of user file when read */
+ auth_htable_t am_users[1]; /**< Table of users */
+
+ void *am_buffer; /**< Buffer for database */
+ auth_passwd_t *am_locals; /**< Entries from local user file */
+ size_t am_local_count; /**< Number of entries from local user file */
+
+ auth_passwd_t *am_anon_user; /**< Special entry for anonymous user */
+
+ /* Attributes */
+ url_t *am_remote; /**< Remote authenticator */
+ char const *am_realm; /**< Our realm */
+ char const *am_opaque; /**< Opaque identification data */
+ char const *am_gssapi_data; /**< NTLM data */
+ char const *am_targetname; /**< NTLM target name */
+ auth_scheme_t *am_scheme; /**< Authentication scheme (Digest, Basic). */
+ char const **am_allow; /**< Methods to allow without authentication */
+ msg_param_t am_algorithm; /**< Defauilt algorithm */
+ msg_param_t am_qop; /**< Default qop (quality-of-protection) */
+ unsigned am_expires; /**< Nonce lifetime */
+ unsigned am_next_exp; /**< Next nonce lifetime */
+ unsigned am_blacklist; /**< Extra delay if bad credentials. */
+ unsigned am_forbidden:1;/**< Respond with 403 if bad credentials */
+ unsigned am_anonymous:1;/**< Allow anonymous access */
+ unsigned am_challenge:1;/**< Challenge even if successful */
+ unsigned am_nextnonce:1;/**< Send next nonce in responses */
+ unsigned am_mutual:1; /**< Mutual authentication */
+ unsigned am_fake:1; /**< Fake authentication */
+
+ unsigned :0; /**< Pad */
+ unsigned am_count; /**< Nonce counter */
+
+ uint8_t am_master_key[16]; /**< Private master key */
+
+ su_md5_t am_hmac_ipad; /**< MD5 with inner pad */
+ su_md5_t am_hmac_opad; /**< MD5 with outer pad */
+};
+
+SOFIAPUBFUN
+auth_passwd_t *auth_mod_getpass(auth_mod_t *am,
+ char const *user,
+ char const *realm);
+
+SOFIAPUBFUN
+auth_passwd_t *auth_mod_addpass(auth_mod_t *am,
+ char const *user,
+ char const *realm);
+
+SOFIAPUBFUN int auth_readdb_if_needed(auth_mod_t *am);
+
+SOFIAPUBFUN int auth_readdb(auth_mod_t *am);
+
+SOFIAPUBFUN msg_auth_t *auth_mod_credentials(msg_auth_t *auth,
+ char const *scheme,
+ char const *realm);
+
+SOFIAPUBFUN auth_mod_t *auth_mod_alloc(auth_scheme_t *scheme,
+ tag_type_t, tag_value_t, ...);
+
+#define AUTH_PLUGIN(am) (auth_plugin_t *)((am) + 1)
+
+SOFIAPUBFUN
+int auth_init_default(auth_mod_t *am,
+ auth_scheme_t *base,
+ su_root_t *root,
+ tag_type_t tag, tag_value_t value, ...);
+
+/** Default cancel method */
+SOFIAPUBFUN void auth_cancel_default(auth_mod_t *am, auth_status_t *as);
+
+/** Default destroy method */
+SOFIAPUBFUN void auth_destroy_default(auth_mod_t *am);
+
+/** Basic scheme */
+SOFIAPUBFUN
+void auth_method_basic(auth_mod_t *am,
+ auth_status_t *as,
+ msg_auth_t *auth,
+ auth_challenger_t const *ach);
+
+SOFIAPUBFUN
+void auth_challenge_basic(auth_mod_t *am,
+ auth_status_t *as,
+ auth_challenger_t const *ach);
+
+/** Digest scheme */
+SOFIAPUBFUN
+msg_auth_t *auth_digest_credentials(msg_auth_t *auth,
+ char const *realm,
+ char const *opaque);
+
+SOFIAPUBFUN
+void auth_method_digest(auth_mod_t *am,
+ auth_status_t *as,
+ msg_auth_t *au,
+ auth_challenger_t const *ach);
+
+SOFIAPUBFUN
+void auth_info_digest(auth_mod_t *am,
+ auth_status_t *as,
+ auth_challenger_t const *ach);
+
+SOFIAPUBFUN
+void auth_check_digest(auth_mod_t *am,
+ auth_status_t *as,
+ auth_response_t *ar,
+ auth_challenger_t const *ach);
+
+SOFIAPUBFUN
+void auth_challenge_digest(auth_mod_t *am,
+ auth_status_t *as,
+ auth_challenger_t const *ach);
+
+SOFIAPUBFUN
+isize_t auth_generate_digest_nonce(auth_mod_t *am,
+ char buffer[],
+ size_t buffer_len,
+ int nextnonce,
+ msg_time_t now);
+
+SOFIAPUBFUN
+int auth_validate_digest_nonce(auth_mod_t *am,
+ auth_status_t *as,
+ auth_response_t *ar,
+ msg_time_t now);
+
+SOFIAPUBFUN int auth_allow_check(auth_mod_t *am, auth_status_t *as);
+
+/** Init md5 for MD5-based HMAC */
+SOFIAPUBFUN void auth_md5_hmac_init(auth_mod_t *am, su_md5_t *md5);
+SOFIAPUBFUN void auth_md5_hmac_digest(auth_mod_t *am, su_md5_t *md5,
+ void *hmac, size_t size);
+
+SOFIA_END_DECLS
+
+#endif /* !defined AUTH_PLUGIN_H */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/test_auth_digest.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/test_auth_digest.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1217 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_auth_digest.c
+ *
+ * @brief Test authentication functions for "Digest" scheme.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Feb 22 12:10:37 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#if HAVE_SOFIA_SIP
+#define PROTOCOL "SIP/2.0"
+#include <sofia-sip/sip.h>
+#include <sofia-sip/sip_header.h>
+#include <sofia-sip/sip_hclasses.h>
+#else
+#define PROTOCOL "HTTP/1.1"
+#include <sofia-sip/http.h>
+#include <sofia-sip/http_header.h>
+#define sip_authentication_info_class http_authentication_info_class
+#define sip_authorization http_authorization
+#define sip_authorization_class http_authorization_class
+#define sip_authorization_make http_authorization_make
+#define sip_authorization_t http_authorization_t
+#define sip_default_mclass http_default_mclass
+#define sip_object http_object
+#define sip_payload http_payload
+#define sip_proxy_authenticate_make http_proxy_authenticate_make
+#define sip_proxy_authenticate_t http_proxy_authenticate_t
+#define sip_proxy_authorization_make http_proxy_authorization_make
+#define sip_proxy_authorization_t http_proxy_authorization_t
+#define sip_request http_request
+#define sip_request_t http_request_t
+#define sip_t http_t
+#define sip_www_authenticate http_www_authenticate
+#define sip_www_authenticate_class http_www_authenticate_class
+#define sip_www_authenticate http_www_authenticate
+#define sip_www_authenticate_make http_www_authenticate_make
+#define sip_www_authenticate_t http_www_authenticate_t
+#endif
+
+#include <sofia-sip/auth_digest.h>
+#include <sofia-sip/auth_client.h>
+#include <sofia-sip/msg_header.h>
+#include <sofia-sip/su_wait.h>
+
+int tstflags;
+char *argv0;
+
+#define TSTFLAGS tstflags
+
+#include <sofia-sip/tstdef.h>
+
+#if defined(_WIN32)
+#include <fcntl.h>
+#endif
+
+char const name[] = "test_auth_digest";
+
+/* Fake su_time() implementation */
+#include <time.h>
+
+unsigned offset;
+
+void su_time(su_time_t *tv)
+{
+ tv->tv_sec = time(NULL) + offset +
+ /* Seconds from 1.1.1900 to 1.1.1970 */ 2208988800UL ;
+ tv->tv_usec = 555555;
+}
+
+int test_digest()
+{
+ char challenge[] = "Digest "
+ "realm=\"garage.sr.ntc.nokia.com\", "
+ "nonce=\"MjAwMS0wMS0yMSAxNTowODo1OA==\", "
+ "algorithm=MD5, "
+ "qop=\"auth\"";
+
+ char response[] =
+ "DIGEST USERNAME=\"digest\", "
+ "REALM=\"garage.sr.ntc.nokia.com\", "
+ "NONCE=\"MjAwMS0wMS0yMSAxNTowODo1OA==\", "
+ "RESPONSE=\"d9d7f1ae99a013cb05f319f0f678251d\", "
+ "URI=\"sip:garage.sr.ntc.nokia.com\"";
+
+ char rfc2617[] =
+ "Digest username=\"Mufasa\", "
+ "realm=\"testrealm at host.com\", "
+ "nonce=\"dcd98b7102dd2f0e8b11d0f600bfb0c093\", "
+ "cnonce=\"0a4f113b\", "
+ "nc=\"00000001\", "
+ "qop=\"auth\", "
+ "algorithm=\"md5\", "
+ "uri=\"/dir/index.html\"";
+
+ char indigo[] =
+ "Digest username=\"user1\", "
+ "realm=\"nokia-proxy\", "
+ "nonce=\"0YXwH29PCT4lEz8+YJipQg==\", "
+ "uri=\"sip:nokia at 62.254.248.33\", "
+ "response=\"dd22a698b1a9510c4237c52e0e2cbfac\", "
+ "algorithm=MD5, "
+ "cnonce=\"V2VkIEF1ZyAxNSAxNzozNDowNyBHTVQrMDE6MDAgMjAwMVtCQDI0YmZhYQ==\", "
+ "opaque=\"WiMlvw==\", "
+ "qop=auth, "
+ "nc=000000002";
+
+ char proxy_authenticate[] =
+ "Digest realm=\"IndigoSw\", "
+ "domain=\"indigosw.com aol.com\", "
+ "nonce=\"V2VkIEF1ZyAxNSAxNzoxNzozNyBCU1QgMjAwMVtCQDE3OWU4Yg==\", "
+ "opaque=\"Nzg5MWU3YjZiNDQ0YzI2Zg==\", "
+ "stale=false, "
+ "algorithm=md5, "
+ "qop=\"auth, auth-int\"";
+
+ sip_www_authenticate_t *wa;
+ sip_authorization_t *au;
+ sip_proxy_authenticate_t *pa;
+ sip_proxy_authorization_t *pz;
+
+ auth_challenge_t ac[1] = {{ sizeof(ac) }};
+ auth_response_t ar[1] = {{ sizeof(ar) }};
+ su_home_t home[1] = {{ sizeof(home) }};
+
+ auth_hexmd5_t sessionkey, hresponse;
+
+ BEGIN();
+
+ TEST0(wa = sip_www_authenticate_make(home, challenge));
+ TEST_SIZE(auth_digest_challenge_get(home, ac, wa->au_params), 6);
+ TEST_S(ac->ac_realm, "garage.sr.ntc.nokia.com");
+ TEST_S(ac->ac_nonce, "MjAwMS0wMS0yMSAxNTowODo1OA==");
+ TEST_S(ac->ac_algorithm, "MD5");
+ TEST_1(ac->ac_md5); TEST_1(!ac->ac_md5sess); TEST_1(!ac->ac_sha1);
+ TEST_S(ac->ac_qop, "auth");
+ TEST_1(ac->ac_auth); TEST_1(!ac->ac_auth_int);
+
+ TEST0(au = sip_authorization_make(home, response));
+ TEST_SIZE(auth_digest_response_get(home, ar, au->au_params), 5);
+
+ TEST0(au = sip_authorization_make(home, rfc2617));
+ TEST_SIZE(auth_digest_response_get(home, ar, au->au_params), 10);
+
+ TEST0(auth_digest_sessionkey(ar, sessionkey, "Circle Of Life") == 0);
+ if (tstflags & tst_verbatim)
+ printf("%s: sessionkey=\"%s\"\n", name, sessionkey);
+ TEST0(strcmp(sessionkey, "939e7578ed9e3c518a452acee763bce9") == 0);
+
+ TEST0(auth_digest_response(ar, hresponse, sessionkey, "GET", NULL, 0) == 0);
+ if (tstflags & tst_verbatim)
+ printf("%s: hresponse=\"%s\"\n", name, hresponse);
+ TEST0(strcmp(hresponse, "6629fae49393a05397450978507c4ef1") == 0);
+
+ TEST0(au = sip_authorization_make(home, indigo));
+ TEST_SIZE(auth_digest_response_get(home, ar, au->au_params), 12);
+ TEST0(auth_digest_sessionkey(ar, sessionkey, "secret") == 0);
+ TEST0(auth_digest_response(ar, hresponse, sessionkey, "BYE", NULL, 0) == 0);
+ TEST0(strcmp(hresponse, "dd22a698b1a9510c4237c52e0e2cbfac") == 0);
+
+ TEST0(pa = sip_proxy_authenticate_make(home, proxy_authenticate));
+ TEST_SIZE(auth_digest_challenge_get(home, ac, pa->au_params), 9);
+
+ TEST_S(ac->ac_realm, "IndigoSw");
+ TEST_1(ac->ac_auth);
+ TEST_1(ac->ac_auth_int);
+
+ {
+ char challenge[] =
+ "Digest realm=\"opera.ntc.nokia.com\", "
+ "nonce=\"InyiWI+qIdvDKkO2jFK7mg==\"";
+
+ char credentials[] =
+ "Digest username=\"samuel.privat.saturday at opera.ntc.nokia.com\", "
+ "realm=\"opera.ntc.nokia.com\", nonce=\"InyiWI+qIdvDKkO2jFK7mg==\", "
+ "algorithm=MD5, uri=\"sip:opera.ntc.nokia.com\", "
+ "response=\"4b4edab897dafce8d9af4b37abcdc086\"";
+
+ memset(ac, 0, sizeof(ac)); ac->ac_size = sizeof(ac);
+ memset(ar, 0, sizeof(ar)); ar->ar_size = sizeof(ar);
+
+ TEST0(pa = sip_www_authenticate_make(home, challenge));
+ TEST_SIZE(auth_digest_challenge_get(home, ac, pa->au_params), 2);
+
+ TEST0(pz = sip_proxy_authorization_make(home, credentials));
+ TEST_SIZE(auth_digest_response_get(home, ar, pz->au_params), 7);
+
+ ar->ar_md5 = ac->ac_md5 || ac->ac_algorithm == NULL;
+
+ TEST0(!auth_digest_sessionkey(ar, sessionkey, "1123456789ABCDEF"));
+ TEST0(!auth_digest_response(ar, hresponse, sessionkey, "REGISTER", NULL, 0));
+ TEST_S(hresponse, "4b4edab897dafce8d9af4b37abcdc086");
+ }
+
+ if (0) {
+ /*
+ RFC 2069:
+ that the username for this document is "Mufasa", and the password is
+ "CircleOfLife".
+
+ The first time the client requests the document, no Authorization
+ header is sent, so the server responds with:
+
+HTTP/1.1 401 Unauthorized
+WWW-Authenticate: Digest realm="testrealm at host.com",
+ nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
+ opaque="5ccc069c403ebaf9f0171e9517f40e41"
+
+ The client may prompt the user for the username and password, after
+ which it will respond with a new request, including the following
+ Authorization header:
+
+Authorization: Digest username="Mufasa",
+ realm="testrealm at host.com",
+ nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
+ uri="/dir/index.html",
+ response="e966c932a9242554e42c8ee200cec7f6",
+ opaque="5ccc069c403ebaf9f0171e9517f40e41"
+ */
+
+ char challenge[] =
+ "Digest realm=\"testrealm at host.com\", "
+ "nonce=\"dcd98b7102dd2f0e8b11d0f600bfb0c093\", "
+ "opaque=\"5ccc069c403ebaf9f0171e9517f40e41\"";
+
+ char rfc2069_cred[] =
+ "Digest username=\"Mufasa\", "
+ "realm=\"testrealm at host.com\", "
+ "nonce=\"dcd98b7102dd2f0e8b11d0f600bfb0c093\", "
+ "uri=\"/dir/index.html\", "
+ "response=\"e966c932a9242554e42c8ee200cec7f6\", "
+ "opaque=\"5ccc069c403ebaf9f0171e9517f40e41\"";
+
+ memset(ac, 0, sizeof(ac)); ac->ac_size = sizeof(ac);
+ memset(ar, 0, sizeof(ar)); ar->ar_size = sizeof(ar);
+
+ TEST0(pa = sip_www_authenticate_make(home, challenge));
+ TEST_SIZE(auth_digest_challenge_get(home, ac, pa->au_params), 3);
+
+ TEST0(pz = sip_proxy_authorization_make(home, rfc2069_cred));
+ TEST_SIZE(auth_digest_response_get(home, ar, pz->au_params), 6);
+
+ ar->ar_md5 = ac->ac_md5 || ac->ac_algorithm == NULL;
+
+ TEST_S(ar->ar_username, "Mufasa");
+ TEST0(!auth_digest_sessionkey(ar, sessionkey, "CircleOfLife"));
+ TEST0(!auth_digest_response(ar, hresponse, sessionkey, "GET", NULL, 0));
+ TEST_S(hresponse, "e966c932a9242554e42c8ee200cec7f6");
+ }
+
+ {
+ char worldcom_chal[] =
+ "Digest realm=\"WCOM\", nonce=\"ce2292f3f748fbe239bda9e852e8b986\"";
+
+ char worldcom_cred[] =
+ "Digest realm=\"WCOM\", username=\"jari\", "
+ "nonce=\"ce2292f3f748fbe239bda9e852e8b986\", "
+ "response=\"ea692d202019d41a75c70df4b2401e2f\", "
+ "uri=\"sip:1234 at 209.132.126.82\"";
+
+ memset(ac, 0, sizeof(ac)); ac->ac_size = sizeof(ac);
+ memset(ar, 0, sizeof(ar)); ar->ar_size = sizeof(ar);
+
+ TEST0(pa = sip_proxy_authenticate_make(home, worldcom_chal));
+ TEST_SIZE(auth_digest_challenge_get(home, ac, pa->au_params), 2);
+
+ TEST0(pz = sip_proxy_authorization_make(home, worldcom_cred));
+ TEST_SIZE(auth_digest_response_get(home, ar, pz->au_params), 5);
+
+ ar->ar_md5 = ac->ac_md5 || ac->ac_algorithm == NULL;
+
+ TEST0(!auth_digest_sessionkey(ar, sessionkey, "pass"));
+ TEST0(!auth_digest_response(ar, hresponse, sessionkey, "REGISTER", NULL, 0));
+ TEST_S(hresponse, "ea692d202019d41a75c70df4b2401e2f");
+ }
+
+ {
+ char etri_chal[] =
+ "Digest realm=\"nokia-proxy\", domain=\"sip:194.2.188.133\", "
+ "nonce=\"wB7JBwIb/XhtgfGp1VuPoQ==\", opaque=\"wkJxwA==\", "
+ ", algorithm=MD5, qop=\"auth\"";
+
+ char etri_cred[] =
+ "Digest username=\"myhuh\", realm=\"nokia-proxy\", "
+ "nonce=\"wB7JBwIb/XhtgfGp1VuPoQ==\", uri=\"sip:194.2.188.133\", "
+ "response=\"32960a62bdc202171ca5a294dc229a6d\", "
+ "opaque=\"wkJxwA==\"" /* , qop=\"auth\"" */;
+
+ memset(ac, 0, sizeof(ac)); ac->ac_size = sizeof(ac);
+ memset(ar, 0, sizeof(ar)); ar->ar_size = sizeof(ar);
+
+ TEST0(pa = sip_proxy_authenticate_make(home, etri_chal));
+ TEST_SIZE(auth_digest_challenge_get(home, ac, pa->au_params), 8);
+
+ TEST0(pz = sip_proxy_authorization_make(home, etri_cred));
+ TEST_SIZE(auth_digest_response_get(home, ar, pz->au_params), 6 /* 8 */);
+
+ ar->ar_md5 = ac->ac_md5 || ac->ac_algorithm == NULL;
+
+ TEST(auth_digest_sessionkey(ar, sessionkey, "myhuh"), 0);
+ TEST(auth_digest_response(ar, hresponse, sessionkey, "REGISTER", NULL, 0), 0);
+ TEST_S(hresponse, "32960a62bdc202171ca5a294dc229a6d");
+ }
+
+ {
+ char chal[] =
+ "Digest realm=\"nokia-proxy\", domain=\"sip:10.21.32.63\", "
+ "nonce=\"GjbLsrozHC6Lx95C57vGlw==\", opaque=\"HN22wQ==\", algorithm=MD5";
+
+ char cred[] =
+ "digest username=\"test1\",realm=\"nokia-proxy\","
+ "nonce=\"GjbLsrozHC6Lx95C57vGlw==\",opaque=\"HN22wQ==\","
+ "uri=\"sip:10.21.32.63\",response=\"e86db25d96713482e35378504caaba6b\","
+ "algorithm=\"MD5\"";
+
+ memset(ac, 0, sizeof(ac)); ac->ac_size = sizeof(ac);
+ memset(ar, 0, sizeof(ar)); ar->ar_size = sizeof(ar);
+
+ TEST0(pa = sip_proxy_authenticate_make(home, chal));
+ TEST_SIZE(auth_digest_challenge_get(home, ac, pa->au_params), 6);
+
+ TEST0(pz = sip_proxy_authorization_make(home, cred));
+ TEST_SIZE(auth_digest_response_get(home, ar, pz->au_params), 8);
+
+ ar->ar_md5 = ac->ac_md5 || ac->ac_algorithm == NULL;
+
+ TEST(auth_digest_sessionkey(ar, sessionkey, "test1"), 0);
+ TEST(auth_digest_response(ar, hresponse, sessionkey, "REGISTER", NULL, 0), 0);
+ TEST_S(hresponse, "db41913e8964dde69a1519739f35a302");
+ }
+
+ {
+ char challenge[] =
+ "Digest realm=\"nokia-proxy\", domain=\"sip:194.2.188.133\", "
+ "nonce=\"3wWGOvaWn3n+hFv8PK2ABQ==\", opaque=\"+GNywA==\", "
+ "algorithm=MD5, qop=\"auth-int\"";
+ char credentials[] =
+ "Digest username=\"test\", realm=\"nokia-proxy\", "
+ "nonce=\"3wWGOvaWn3n+hFv8PK2ABQ==\", "
+ "cnonce=\"11RkhFg9EdaIRD36w0EMVA==\", opaque=\"+GNywA==\", "
+ "uri=\"sip:3000 at 194.2.188.133\", algorithm=MD5, "
+ "response=\"26e8b9aaacfca2d68770fab1ec04e2c7\", "
+ "qop=auth-int, nc=00000001";
+ char data[] =
+ "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"
+ "<presence>\n"
+ "<presentity uri=\"sip:3000 at 194.2.188.133\"/>\n"
+ "<atom atomid=\"BQpTalFpkMyF9hOlR8olWQ==\">\n"
+ "<address uri=\"sip:3000 at 194.2.188.133\" priority=\" 0\">\n"
+ "<status status=\"open\"/>\n"
+ "<class class=\"business\"/>\n"
+ "<duplex duplex=\"full\"/>\n"
+ "<feature feature=\"voicemail\"/>\n"
+ "<mobility mobility=\"fixed\"/>\n"
+ "<note>\n"
+ "</note>\n"
+ "</address>\n"
+ "</atom>\n"
+ "</presence>\n";
+
+ memset(ac, 0, sizeof(ac)); ac->ac_size = sizeof(ac);
+ memset(ar, 0, sizeof(ar)); ar->ar_size = sizeof(ar);
+
+ TEST0(pa = sip_proxy_authenticate_make(home, challenge));
+ TEST_SIZE(auth_digest_challenge_get(home, ac, pa->au_params), 8);
+
+ TEST0(pz = sip_proxy_authorization_make(home, credentials));
+ TEST_SIZE(auth_digest_response_get(home, ar, pz->au_params), 12);
+
+ ar->ar_md5 = ac->ac_md5 || ac->ac_algorithm == NULL;
+
+ TEST0(!auth_digest_sessionkey(ar, sessionkey, "test"));
+ TEST0(!auth_digest_response(ar, hresponse, sessionkey, "REGISTER",
+ data, strlen(data)));
+ TEST_S(hresponse, "26e8b9aaacfca2d68770fab1ec04e2c7");
+ }
+
+ su_home_deinit(home);
+
+ END();
+}
+
+#include <sofia-sip/msg_addr.h>
+
+msg_t *read_message(int flags, char const buffer[])
+{
+ int n, m;
+ msg_t *msg;
+ msg_iovec_t iovec[2];
+
+ n = strlen(buffer);
+ if (n == 0)
+ return NULL;
+
+ msg = msg_create(sip_default_mclass(), flags);
+ if (msg_recv_iovec(msg, iovec, 2, n, 1) < 0) {
+ perror("msg_recv_iovec");
+ }
+ memcpy(iovec->mv_base, buffer, n);
+ msg_recv_commit(msg, n, 1);
+
+ m = msg_extract(msg);
+ if (m < 0) {
+ fprintf(stderr, "test_auth_digest: parsing error\n");
+ return NULL;
+ }
+
+ return msg;
+}
+
+#define AUTH_MAGIC_T su_root_t
+
+#include <sofia-sip/auth_module.h>
+
+static
+void test_callback(su_root_t *root, auth_status_t *as)
+{
+ su_root_break(root);
+}
+
+static
+void init_as(auth_status_t *as)
+{
+ memset(as, 0, sizeof *as);
+ as->as_home->suh_size = (sizeof *as);
+ su_home_init(as->as_home);
+ as->as_method = "REGISTER";
+ as->as_status = 500;
+ as->as_phrase = "Infernal Error";
+}
+
+static
+void deinit_as(auth_status_t *as)
+{
+ su_home_deinit(as->as_home);
+ memset(as, 0, sizeof *as);
+}
+
+static
+void reinit_as(auth_status_t *as)
+{
+ deinit_as(as); init_as(as);
+}
+
+/* Test digest authentication client and server */
+int test_digest_client()
+{
+ BEGIN();
+
+ {
+ char challenge[] =
+ PROTOCOL " 401 Unauthorized\r\n"
+ "Call-ID:0e3dc2b2-dcc6-1226-26ac-258b5ce429ab\r\n"
+ "CSeq:32439043 REGISTER\r\n"
+ "From:surf3.ims3.so.noklab.net <sip:surf3 at ims3.so.noklab.net>;tag=I8hFdg0H3OK\r\n"
+ "To:<sip:surf3 at ims3.so.noklab.net>\r\n"
+ "Via:SIP/2.0/UDP 10.21.36.70:23800;branch=z9hG4bKJjKGu9vIHqf;received=10.21.36.70;rport\r\n"
+ "WWW-Authenticate:Digest algorithm=MD5,nonce=\"h7wIpP+atU+/+Zau5UwLMA==\",realm=\"ims3.so.noklab.net\"\r\n"
+ "Content-Length:0\r\n"
+ "Security-Server:digest\r\n"
+ "r\n";
+
+ char request[] =
+ "REGISTER sip:ims3.so.noklab.net " PROTOCOL "\r\n"
+ "Via: SIP/2.0/UDP 10.21.36.70:23800;rport;branch=z9hG4bKRE18GFwa3AS\r\n"
+ "Max-Forwards: 80\r\n"
+ "From: surf3.ims3.so.noklab.net <sip:surf3 at ims3.so.noklab.net>;tag=I8hFdg0H3OK\r\n"
+ "To: <sip:surf3 at ims3.so.noklab.net>\r\n"
+ "Call-ID: 0e3dc2b2-dcc6-1226-26ac-258b5ce429ab\r\n"
+ "CSeq: 32439044 REGISTER\r\n"
+ "Contact: <sip:10.21.36.70:23800>\r\n"
+ "Expires: 3600\r\n"
+ "Supported: timer, 100rel\r\n"
+ "Security-Client: digest\r\n"
+ "Security-Verify: digest;d-ver=\"1234\"\r\n"
+ "Content-Length: 0\r\n"
+ "r\n";
+
+ msg_t *m1, *m2;
+ sip_t *sip;
+ auth_client_t *aucs = NULL;
+ sip_request_t *rq;
+ su_home_t *home;
+ su_root_t *root;
+ char *srcdir, *s, *testpasswd;
+ auth_mod_t *am;
+ auth_status_t as[1];
+ sip_www_authenticate_t *au;
+ auth_challenger_t ach[1] =
+ {{ 401, "Authorization required",
+ sip_www_authenticate_class,
+ sip_authentication_info_class
+ }};
+
+ TEST_1(home = su_home_new(sizeof(*home)));
+
+ TEST_1(m1 = read_message(MSG_DO_EXTRACT_COPY, challenge));
+ TEST_1(sip = sip_object(m1));
+
+ TEST(auc_challenge(&aucs, home, sip->sip_www_authenticate,
+ sip_authorization_class), 1);
+ msg_destroy(m1);
+
+ TEST(auc_all_credentials(&aucs, "Digest", "\"ims3.so.noklab.net\"",
+ "surf3.private at ims3.so.noklab.net", "1234"), 1);
+
+ TEST_1(m2 = read_message(MSG_DO_EXTRACT_COPY, request));
+ TEST_1(sip = sip_object(m2));
+ TEST_P(sip->sip_authorization, NULL);
+ TEST_1(rq = sip->sip_request);
+ TEST(auc_authorization(&aucs, m2, (msg_pub_t*)sip, rq->rq_method_name,
+ rq->rq_url, sip->sip_payload), 1);
+ TEST_1(sip->sip_authorization);
+ TEST_S(msg_params_find(sip->sip_authorization->au_params,
+ "response="),
+ "\"860f5ecc9990772e16937750ced9594d\"");
+
+ TEST(auc_authorization(&aucs, m2, (msg_pub_t*)sip, rq->rq_method_name,
+ (url_t *)"sip:surf3 at ims3.so.noklab.net",
+ sip->sip_payload), 1);
+ TEST_1(sip->sip_authorization);
+ TEST_S(msg_params_find(sip->sip_authorization->au_params,
+ "response="),
+ "\"9ce0d6a5869b4e09832d5b705453cbfc\"");
+
+ srcdir = getenv("srcdir");
+ if (srcdir == NULL) {
+ srcdir = su_strdup(home, argv0);
+ if ((s = strrchr(srcdir, '/')))
+ *s = '\0';
+ else
+ srcdir = ".";
+ }
+ TEST_1(testpasswd = su_sprintf(home, "%s/testpasswd", srcdir));
+
+ TEST_1(root = su_root_create(NULL));
+
+ TEST_1(am = auth_mod_create(NULL,
+ AUTHTAG_METHOD("Digest"),
+ AUTHTAG_REALM("ims3.so.noklab.net"),
+ AUTHTAG_DB(testpasswd),
+ AUTHTAG_OPAQUE("+GNywA=="),
+ TAG_END()));
+
+ init_as(as);
+ auth_mod_check_client(am, as, sip->sip_authorization, ach);
+ TEST(as->as_status, 401);
+
+ TEST_1(au = sip_authorization_make(home,
+ "Digest username=\"user1\", "
+ "nonce=\"3wWGOvaWn3n+hFv8PK2ABQ==\", "
+ "opaque=\"+GNywA==\", "
+ "uri=\"sip:3000 at 194.2.188.133\", "
+ "response=\"26e8b9aaacfca2d6"
+ "8770fab1ec04e2c7\", "
+ "realm=\"ims3.so.noklab.net\""));
+
+ reinit_as(as);
+ auth_mod_check_client(am, as, au, ach);
+ TEST(as->as_status, 401);
+
+ {
+ char const *username = au->au_params[0];
+ char const *nonce = au->au_params[1];
+ char const *opaque = au->au_params[2];
+ char const *uri = au->au_params[3];
+ char const *response = au->au_params[4];
+ char const *realm = au->au_params[5];
+
+ TEST_S(username, "username=\"user1\"");
+ TEST_S(nonce, "nonce=\"3wWGOvaWn3n+hFv8PK2ABQ==\"");
+ TEST_S(opaque, "opaque=\"+GNywA==\"");
+ TEST_S(uri, "uri=\"sip:3000 at 194.2.188.133\"");
+ TEST_S(response, "response=\"26e8b9aaacfca2d68770fab1ec04e2c7\"");
+
+ TEST(msg_params_remove((msg_param_t *)au->au_params, "username"), 1);
+ reinit_as(as);
+ auth_mod_check_client(am, as, au, ach);
+ TEST(as->as_status, 400);
+ msg_params_add(home, (msg_param_t **)&au->au_params, username);
+
+ TEST(msg_params_remove((msg_param_t *)au->au_params, "nonce"), 1);
+ reinit_as(as);
+ auth_mod_check_client(am, as, au, ach);
+ TEST(as->as_status, 400);
+ msg_params_add(home, (msg_param_t **) &au->au_params, nonce);
+
+ TEST(msg_params_remove((msg_param_t *)au->au_params, "opaque"), 1);
+ reinit_as(as);
+ auth_mod_check_client(am, as, au, ach);
+ TEST(as->as_status, 401); /* We use opaque to match authorization */
+ msg_params_add(home, (msg_param_t **) &au->au_params, opaque);
+
+ TEST(msg_params_remove((msg_param_t *)au->au_params, "uri"), 1);
+ reinit_as(as);
+ auth_mod_check_client(am, as, au, ach);
+ TEST(as->as_status, 400);
+ msg_params_add(home, (msg_param_t **) &au->au_params, uri);
+
+ TEST(msg_params_remove((msg_param_t *)au->au_params, "response"), 1);
+ reinit_as(as);
+ auth_mod_check_client(am, as, au, ach);
+ TEST(as->as_status, 400);
+ msg_params_add(home, (msg_param_t **)&au->au_params, response);
+
+ TEST(msg_params_remove((msg_param_t *)au->au_params, "realm"), 1);
+ reinit_as(as);
+ auth_mod_check_client(am, as, au, ach);
+ TEST(as->as_status, 401); /* au is ignored by auth_module */
+ msg_params_add(home, (msg_param_t **)&au->au_params, realm);
+
+ reinit_as(as);
+ auth_mod_check_client(am, as, au, ach);
+ TEST(as->as_status, 401);
+ }
+
+ as->as_response = (msg_header_t *)
+ sip_www_authenticate_make(as->as_home, "Unknown realm=\"huu haa\"");
+ TEST_1(as->as_response);
+ TEST(auc_challenge(&aucs, home, (msg_auth_t *)as->as_response,
+ sip_authorization_class), 1);
+ aucs = NULL;
+
+ reinit_as(as);
+ auth_mod_check_client(am, as, NULL, ach);
+ TEST(as->as_status, 401);
+ TEST(auc_challenge(&aucs, home, (msg_auth_t *)as->as_response,
+ sip_authorization_class), 1);
+ reinit_as(as);
+
+ TEST(auc_all_credentials(&aucs, "Digest", "\"ims3.so.noklab.net\"",
+ "user1", "secret"), 1);
+
+ msg_header_remove(m2, (void *)sip, (void *)sip->sip_authorization);
+
+ TEST(auc_authorization(&aucs, m2, (msg_pub_t*)sip, rq->rq_method_name,
+ (url_t *)"sip:surf3 at ims3.so.noklab.net",
+ sip->sip_payload), 1);
+ TEST_1(sip->sip_authorization);
+
+ TEST_1(msg_params_find(sip->sip_authorization->au_params, "cnonce=") == 0);
+ TEST_1(msg_params_find(sip->sip_authorization->au_params, "nc=") == 0);
+
+ auth_mod_check_client(am, as, sip->sip_authorization, ach);
+ TEST(as->as_status, 0);
+ TEST_1(as->as_info); /* challenge for next round */
+ auth_mod_destroy(am);
+ aucs = NULL;
+
+ TEST_1(am = auth_mod_create(NULL,
+ AUTHTAG_METHOD("Digest"),
+ AUTHTAG_REALM("ims3.so.noklab.net"),
+ AUTHTAG_DB(testpasswd),
+ AUTHTAG_ALGORITHM("MD5-sess"),
+ AUTHTAG_QOP("auth"),
+ AUTHTAG_OPAQUE("opaque=="),
+ TAG_END()));
+
+ reinit_as(as);
+ auth_mod_check_client(am, as, NULL, ach); TEST(as->as_status, 401);
+
+ {
+ msg_auth_t *au = (msg_auth_t *)as->as_response;
+ int i;
+ char *equal;
+
+ if (au->au_params)
+ for (i = 0; au->au_params[i]; i++) {
+ if (strncasecmp(au->au_params[i], "realm=", 6) == 0)
+ continue;
+ equal = strchr(au->au_params[i], '=');
+ if (equal)
+ msg_unquote(equal + 1, equal + 1);
+ }
+
+ TEST(auc_challenge(&aucs, home, au, sip_authorization_class), 1);
+ reinit_as(as);
+ }
+
+ TEST(auc_all_credentials(&aucs, "Digest", "\"ims3.so.noklab.net\"",
+ "user1", "secret"), 1);
+ msg_header_remove(m2, (void *)sip, (void *)sip->sip_authorization);
+ TEST(auc_authorization(&aucs, m2, (msg_pub_t*)sip, rq->rq_method_name,
+ (url_t *)"sip:surf3 at ims3.so.noklab.net",
+ sip->sip_payload), 1);
+ TEST_1(sip->sip_authorization);
+
+ auth_mod_check_client(am, as, sip->sip_authorization, ach);
+ TEST(as->as_status, 0);
+ TEST_1(as->as_info == NULL); /* No challenge for next round */
+
+ /* Test with changed payload */
+
+ reinit_as(as);
+ as->as_body = "foo"; as->as_bodylen = 3;
+ auth_mod_check_client(am, as, sip->sip_authorization, ach);
+ TEST(as->as_status, 0);
+
+ reinit_as(as); aucs = NULL;
+
+ /* Test without opaque */
+ {
+ msg_auth_t *au;
+ char const *opaque;
+
+ auth_mod_check_client(am, as, NULL, ach); TEST(as->as_status, 401);
+
+ au = (void *)msg_header_dup(home, as->as_response); TEST_1(au);
+
+ TEST_1(msg_params_find_slot((msg_param_t *)au->au_params, "opaque"));
+
+ opaque = *msg_params_find_slot((msg_param_t *)au->au_params, "opaque");
+
+ TEST(msg_params_remove((msg_param_t *)au->au_params, "opaque"), 1);
+
+ TEST(auc_challenge(&aucs, home, au, sip_authorization_class), 1);
+ TEST(auc_all_credentials(&aucs, "Digest", "\"ims3.so.noklab.net\"",
+ "user1", "secret"), 1);
+ msg_header_remove(m2, (void *)sip, (void *)sip->sip_authorization);
+
+ TEST(auc_authorization(&aucs, m2, (msg_pub_t*)sip, rq->rq_method_name,
+ (url_t *)"sip:surf3 at ims3.so.noklab.net",
+ sip->sip_payload), 1);
+
+ TEST_1(sip->sip_authorization);
+ msg_params_add(home,
+ (msg_param_t **)&sip->sip_authorization->au_params,
+ opaque);
+
+ reinit_as(as);
+ auth_mod_check_client(am, as, sip->sip_authorization, ach);
+ TEST(as->as_status, 0);
+ }
+
+ reinit_as(as); auth_mod_destroy(am); aucs = NULL;
+
+ /* Test nextnonce */
+ {
+ char const *nonce1, *nextnonce, *nonce2;
+
+ reinit_as(as); auth_mod_destroy(am); aucs = NULL;
+
+ TEST_1(am = auth_mod_create(NULL,
+ AUTHTAG_METHOD("Digest"),
+ AUTHTAG_REALM("ims3.so.noklab.net"),
+ AUTHTAG_DB(testpasswd),
+ AUTHTAG_ALGORITHM("MD5"),
+ AUTHTAG_QOP("auth-int"),
+ AUTHTAG_EXPIRES(90),
+ /* Generate nextnonce
+ if NEXT_EXPIRES in nonzero */
+ AUTHTAG_NEXT_EXPIRES(900),
+ TAG_END()));
+
+ reinit_as(as);
+ auth_mod_check_client(am, as, NULL, ach); TEST(as->as_status, 401);
+
+ TEST(auc_challenge(&aucs, home, (msg_auth_t *)as->as_response,
+ sip_authorization_class), 1);
+ TEST(auc_all_credentials(&aucs, "Digest", "\"ims3.so.noklab.net\"",
+ "user1", "secret"), 1);
+ msg_header_remove(m2, (void *)sip, (void *)sip->sip_authorization);
+ TEST(auc_authorization(&aucs, m2, (msg_pub_t*)sip, rq->rq_method_name,
+ (url_t *)"sip:surf3 at ims3.so.noklab.net",
+ sip->sip_payload), 1);
+ TEST_1(sip->sip_authorization);
+ TEST_1(nonce1 = msg_header_find_param(sip->sip_authorization->au_common, "nonce"));
+
+ reinit_as(as);
+ auth_mod_check_client(am, as, sip->sip_authorization, ach);
+ TEST(as->as_status, 0);
+ /* We got authentication-info */
+ TEST_1(as->as_info);
+ /* It contains nextnonce */
+ TEST_1(nextnonce = msg_header_find_param(as->as_info->sh_common, "nextnonce"));
+
+ /* Store it in authenticator */
+ TEST(auc_info(&aucs, (msg_auth_info_t const *)as->as_info, sip_authorization_class), 1);
+
+ msg_header_remove(m2, (void *)sip, (void *)sip->sip_authorization);
+ TEST(auc_authorization(&aucs, m2, (msg_pub_t*)sip, rq->rq_method_name,
+ (url_t *)"sip:surf3 at ims3.so.noklab.net",
+ sip->sip_payload), 1);
+ TEST_1(sip->sip_authorization);
+ TEST_1(nonce2 = msg_header_find_param(sip->sip_authorization->au_common, "nonce"));
+
+ /*
+ * Make sure that server-side sends nextnonce in Authentication-info
+ * header, nextnonce differs from nonce sent in Challenge
+ */
+ TEST_1(strcmp(nonce1, nextnonce));
+ /* And client-side uses it */
+ TEST_S(nonce2, nextnonce);
+
+ auth_mod_destroy(am); aucs = NULL;
+ }
+
+ TEST_1(am = auth_mod_create(NULL,
+ AUTHTAG_METHOD("Digest"),
+ AUTHTAG_REALM("ims3.so.noklab.net"),
+ AUTHTAG_DB(testpasswd),
+ AUTHTAG_ALGORITHM("MD5-sess"),
+ AUTHTAG_QOP("auth-int"),
+ TAG_END()));
+
+ reinit_as(as);
+ auth_mod_check_client(am, as, NULL, ach); TEST(as->as_status, 401);
+
+ TEST(auc_challenge(&aucs, home, (msg_auth_t *)as->as_response,
+ sip_authorization_class), 1);
+ TEST(auc_all_credentials(&aucs, "Digest", "\"ims3.so.noklab.net\"",
+ "user1", "secret"), 1);
+ msg_header_remove(m2, (void *)sip, (void *)sip->sip_authorization);
+ TEST(auc_authorization(&aucs, m2, (msg_pub_t*)sip, rq->rq_method_name,
+ (url_t *)"sip:surf3 at ims3.so.noklab.net",
+ sip->sip_payload), 1);
+ TEST_1(sip->sip_authorization);
+
+ reinit_as(as);
+ auth_mod_check_client(am, as, sip->sip_authorization, ach);
+ TEST(as->as_status, 0);
+ auth_mod_destroy(am); aucs = NULL;
+
+ TEST_1(am = auth_mod_create(NULL,
+ AUTHTAG_METHOD("Digest"),
+ AUTHTAG_REALM("ims3.so.noklab.net"),
+ AUTHTAG_DB(testpasswd),
+ AUTHTAG_ALGORITHM("MD5-sess"),
+ AUTHTAG_QOP("auth,auth-int"),
+ AUTHTAG_FORBIDDEN(1),
+ AUTHTAG_ANONYMOUS(1),
+ TAG_END()));
+
+ reinit_as(as);
+ auth_mod_check_client(am, as, NULL, ach); TEST(as->as_status, 401);
+
+ TEST(auc_challenge(&aucs, home, (msg_auth_t *)as->as_response,
+ sip_authorization_class), 1);
+ TEST(auc_all_credentials(&aucs, "Digest", "\"ims3.so.noklab.net\"",
+ "user1", "secret"), 1);
+ msg_header_remove(m2, (void *)sip, (void *)sip->sip_authorization);
+ TEST(auc_authorization(&aucs, m2, (msg_pub_t*)sip, rq->rq_method_name,
+ (url_t *)"sip:surf3 at ims3.so.noklab.net",
+ sip->sip_payload), 1);
+ TEST_1(sip->sip_authorization);
+
+ reinit_as(as);
+ auth_mod_check_client(am, as, sip->sip_authorization, ach);
+ TEST(as->as_status, 0);
+
+ au = (void*)msg_header_copy(msg_home(m2), (void*)sip->sip_authorization);
+
+ /* Test with invalid qop (bug #2329) */
+ msg_params_replace(msg_home(m2), (void *)&au->au_params,
+ "qop=\"auth,auth-int\"");
+ reinit_as(as);
+ auth_mod_check_client(am, as, au, ach);
+ TEST(as->as_status, 400);
+
+ reinit_as(as);
+ as->as_body = "foo"; as->as_bodylen = 3;
+ auth_mod_check_client(am, as, sip->sip_authorization, ach);
+ TEST(as->as_status, 403);
+
+ reinit_as(as);
+ as->as_body = ""; as->as_bodylen = 0;
+ as->as_method = "OPTIONS";
+ auth_mod_check_client(am, as, sip->sip_authorization, ach);
+ TEST(as->as_status, 403);
+
+ /* Test staleness check */
+ offset = 2 * 3600;
+ reinit_as(as);
+ auth_mod_check_client(am, as, sip->sip_authorization, ach);
+ TEST(as->as_status, 401);
+ TEST_1(au = (void *)as->as_response); TEST_1(au->au_params);
+ TEST_S(msg_params_find(au->au_params, "stale="), "true");
+ aucs = NULL;
+
+ /* Test anonymous operation */
+ reinit_as(as);
+ auth_mod_check_client(am, as, NULL, ach); TEST(as->as_status, 401);
+ TEST(auc_challenge(&aucs, home, (msg_auth_t *)as->as_response,
+ sip_authorization_class), 1);
+ reinit_as(as);
+
+ TEST(auc_all_credentials(&aucs, "Digest", "\"ims3.so.noklab.net\"",
+ "anonymous", ""), 1);
+ msg_header_remove(m2, (void *)sip, (void *)sip->sip_authorization);
+ TEST(auc_authorization(&aucs, m2, (msg_pub_t*)sip, rq->rq_method_name,
+ (url_t *)"sip:surf3 at ims3.so.noklab.net",
+ sip->sip_payload), 1);
+ TEST_1(sip->sip_authorization);
+
+ auth_mod_check_client(am, as, sip->sip_authorization, ach);
+ TEST(as->as_status, 0);
+ auth_mod_destroy(am); aucs = NULL;
+
+ /* Test Basic authentication scheme */
+ TEST_1(am = auth_mod_create(root,
+ AUTHTAG_METHOD("Basic"),
+ AUTHTAG_REALM("ims3.so.noklab.net"),
+ AUTHTAG_DB(testpasswd),
+ TAG_END()));
+
+ reinit_as(as);
+ auth_mod_check_client(am, as, NULL, ach);
+ TEST(as->as_status, 401);
+
+ TEST(auc_challenge(&aucs, home, (msg_auth_t *)as->as_response,
+ sip_authorization_class), 1);
+ reinit_as(as);
+
+ TEST(auc_all_credentials(&aucs, "Basic", "\"ims3.so.noklab.net\"",
+ "user1", "secret"), 1);
+ msg_header_remove(m2, (void *)sip, (void *)sip->sip_authorization);
+ TEST(auc_authorization(&aucs, m2, (msg_pub_t*)sip, rq->rq_method_name,
+ (url_t *)"sip:surf3 at ims3.so.noklab.net",
+ sip->sip_payload), 1);
+ TEST_1(sip->sip_authorization);
+
+ auth_mod_check_client(am, as, sip->sip_authorization, ach);
+ TEST(as->as_status, 0);
+
+ aucs = NULL;
+
+ reinit_as(as);
+ auth_mod_check_client(am, as, NULL, ach);
+ TEST(as->as_status, 401);
+
+ TEST(auc_challenge(&aucs, home, (msg_auth_t *)as->as_response,
+ sip_authorization_class), 1);
+ reinit_as(as);
+
+ TEST(auc_all_credentials(&aucs, "Basic", "\"ims3.so.noklab.net\"",
+ "very-long-user-name-that-surely-exceeds-the-static-buffer",
+ "at-least-when-used-with-the-even-longer-password"), 1);
+ msg_header_remove(m2, (void *)sip, (void *)sip->sip_authorization);
+ TEST(auc_authorization(&aucs, m2, (msg_pub_t*)sip, rq->rq_method_name,
+ (url_t *)"sip:surf3 at ims3.so.noklab.net",
+ sip->sip_payload), 1);
+ TEST_1(sip->sip_authorization);
+
+ auth_mod_check_client(am, as, sip->sip_authorization, ach);
+ TEST(as->as_status, 0);
+
+ auth_mod_destroy(am); deinit_as(as); aucs = NULL;
+
+ /* Test asynchronous operation */
+ aucs = NULL;
+ TEST_1(am = auth_mod_create(root,
+ AUTHTAG_METHOD("Delayed+Digest"),
+ AUTHTAG_REALM("ims3.so.noklab.net"),
+ AUTHTAG_DB(testpasswd),
+ AUTHTAG_ALGORITHM("MD5-sess"),
+ AUTHTAG_QOP("auth-int"),
+ AUTHTAG_REMOTE((void *)"http://localhost:9"),
+ TAG_END()));
+
+ reinit_as(as);
+ as->as_callback = test_callback;
+ as->as_magic = root;
+ auth_mod_check_client(am, as, NULL, ach);
+ TEST(as->as_status, 100);
+ su_root_run(root);
+ TEST(as->as_status, 401);
+
+ TEST(auc_challenge(&aucs, home, (msg_auth_t *)as->as_response,
+ sip_authorization_class), 1);
+
+ reinit_as(as);
+ as->as_callback = test_callback;
+ as->as_magic = root;
+
+ TEST(auc_all_credentials(&aucs, "Digest", "\"ims3.so.noklab.net\"",
+ "user1", "secret"), 1);
+ msg_header_remove(m2, (void *)sip, (void *)sip->sip_authorization);
+ TEST(auc_authorization(&aucs, m2, (msg_pub_t*)sip, rq->rq_method_name,
+ (url_t *)"sip:surf3 at ims3.so.noklab.net",
+ sip->sip_payload), 1);
+ TEST_1(sip->sip_authorization);
+
+ auth_mod_check_client(am, as, sip->sip_authorization, ach);
+ TEST(as->as_status, 100);
+ su_root_run(root);
+ TEST(as->as_status, 0);
+
+ auth_mod_destroy(am); aucs = NULL;
+
+ deinit_as(as);
+ msg_destroy(m2);
+
+ su_root_destroy(root);
+
+ su_home_unref(home);
+ }
+
+ END();
+}
+
+#if HAVE_FLOCK
+#include <sys/file.h>
+#endif
+
+#include <sofia-sip/auth_plugin.h>
+
+char tmppasswd[] = "/tmp/test_auth_digest.XXXXXX";
+
+#include <unistd.h>
+
+static void rmtmp(void)
+{
+ if (tmppasswd[0])
+ unlink(tmppasswd);
+}
+
+char const passwd[] =
+ "# Comment\n"
+ "malformed line\n"
+ "user1:secret:\n"
+ /* user2 has password "secret", too */
+ "user2:realm:4cbc2aff0b5b2b33675c0731c0db1c14\n"
+ /* duplicate user. fun */
+ "user1:secret:realm\n"
+ /* empty line */
+ "\n";
+
+/* Test digest authentication client and server */
+int test_module_io()
+{
+ auth_mod_t *am, am0[1];
+ auth_passwd_t *apw, *apw2;
+ int tmpfd;
+
+ BEGIN();
+
+#ifndef _WIN32
+ tmpfd = mkstemp(tmppasswd); TEST_1(tmpfd != -1);
+#else
+ tmpfd = open(tmppasswd, O_WRONLY); TEST_1(tmpfd != -1);
+#endif
+ atexit(rmtmp); /* Make sure temp file is unlinked */
+
+ TEST_SIZE(write(tmpfd, passwd, strlen(passwd)), strlen(passwd));
+ TEST(close(tmpfd), 0);
+
+ /* Test file reading operation */
+ am = auth_mod_create(NULL,
+ AUTHTAG_METHOD("Digest"),
+ AUTHTAG_REALM("realm"),
+ AUTHTAG_DB(tmppasswd),
+ AUTHTAG_ALGORITHM("MD5-sess"),
+ AUTHTAG_QOP("auth-int"),
+ TAG_END()); TEST_1(am);
+
+ apw = auth_mod_getpass(am, "user1", NULL); TEST_1(apw);
+ TEST_S(apw->apw_realm, "realm");
+
+ apw = auth_mod_getpass(am, "user2", NULL); TEST_1(apw);
+ TEST_S(apw->apw_hash, "4cbc2aff0b5b2b33675c0731c0db1c14");
+
+ apw2 = apw;
+
+ *am0 = *am;
+
+ TEST_1(auth_readdb_if_needed(am) == 0);
+
+ apw = auth_mod_getpass(am, "user2", NULL); TEST_1(apw);
+ TEST_P(apw, apw2);
+
+ apw = auth_mod_addpass(am, "user3", "realm"); TEST_1(apw);
+ /* user3 with password fisu */
+ apw->apw_hash = "056595147630692bb29d1855089bc95b";
+
+ {
+ char const user3[] = "user3:realm:7df96b4718bd933af4883c8b73c96318\n";
+ tmpfd = open(tmppasswd, O_WRONLY|O_APPEND, 0); TEST_1(tmpfd != -1);
+ /* user3 with password fish */
+ TEST_SIZE(write(tmpfd, user3, strlen(user3)), strlen(user3));
+ TEST_1(close(tmpfd) == 0);
+ }
+
+#if HAVE_FLOCK
+ /* Test flock(). */
+ tmpfd = open(tmppasswd, O_RDONLY);
+
+ TEST_1(flock(tmpfd, LOCK_EX) != -1);
+
+ TEST_1(auth_readdb_if_needed(am) == 0);
+
+ /* there should be no changes in user table */
+ apw = auth_mod_getpass(am, "user2", NULL); TEST_1(apw);
+ TEST_P(apw, apw2);
+
+ TEST_1(flock(tmpfd, LOCK_UN) != -1);
+#endif
+
+ TEST_1(auth_readdb_if_needed(am) == 0);
+
+ apw = auth_mod_getpass(am, "user2", "realm"); TEST_1(apw);
+ TEST_1(apw != apw2);
+
+ /* Local user3 overrides non-local */
+ apw = auth_mod_getpass(am, "user3", "realm"); TEST_1(apw);
+ TEST_S(apw->apw_hash, "7df96b4718bd933af4883c8b73c96318");
+
+ /* Test truncating */
+ {
+ char const user1[] = "user1:secret:\n";
+ tmpfd = open(tmppasswd, O_WRONLY|O_TRUNC, 0); TEST_1(tmpfd != -1);
+ TEST_SIZE(write(tmpfd, user1, strlen(user1)), strlen(user1));
+ TEST_1(close(tmpfd) == 0);
+ }
+
+ TEST_1(auth_readdb_if_needed(am) == 0);
+
+ apw = auth_mod_getpass(am, "user2", "realm"); TEST_1(apw == NULL);
+
+ /* Non-local user3 is kept in database */
+ apw = auth_mod_getpass(am, "user3", "realm"); TEST_1(apw);
+ TEST_S(apw->apw_hash, "056595147630692bb29d1855089bc95b");
+
+ auth_mod_destroy(am);
+
+ if (unlink(tmppasswd) == 0)
+ tmppasswd[0] = '\0';
+
+ END();
+}
+
+#include <sofia-sip/su_log.h>
+
+extern su_log_t iptsec_log[];
+
+static
+void usage(void)
+{
+ fprintf(stderr, "usage: %s [-v] [-l n]\n", name);
+}
+
+int main(int argc, char *argv[])
+{
+ int retval = 0;
+ int i;
+
+ argv0 = argv[0];
+
+ su_init();
+
+ for (i = 1; argv[i]; i++) {
+ if (argv[i] && strcmp(argv[i], "-v") == 0)
+ tstflags |= tst_verbatim;
+ else if (strncmp(argv[i], "-l", 2) == 0) {
+ int level = 3;
+ char *rest = NULL;
+
+ if (argv[i][2])
+ level = strtol(argv[i] + 2, &rest, 10);
+ else if (argv[i + 1])
+ level = strtol(argv[i + 1], &rest, 10), i++;
+ else
+ level = 3, rest = "";
+
+ if (rest == NULL || *rest)
+ usage();
+
+ su_log_set_level(iptsec_log, level);
+ } else {
+ usage();
+ }
+ }
+
+ if ((TSTFLAGS & tst_verbatim))
+ su_log_soft_set_level(iptsec_log, 9);
+ else
+ su_log_soft_set_level(iptsec_log, 0);
+
+ retval |= test_digest();
+ retval |= test_digest_client();
+
+ retval |= test_module_io();
+
+ su_deinit();
+
+ return retval;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/testpasswd
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/testpasswd Thu Dec 21 01:30:28 2006
@@ -0,0 +1,3 @@
+user1:secret:
+user2:fish:
+very-long-user-name-that-surely-exceeds-the-static-buffer:at-least-when-used-with-the-even-longer-password:
\ No newline at end of file
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/ChangeLog Thu Dec 21 01:30:28 2006
@@ -0,0 +1,53 @@
+2006-01-17 Martti Mela <martti.mela at nokia.com>
+
+ * msg_mime.c: defines for Mac OS X (which are lacking EBADMSG).
+
+2005-11-08 Pekka Pessi <Pekka.Pessi at 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 at nokia.com>
+
+ * Fixed msg_home() macro.
+
+ M ./libsofia-sip-ua/msg/msg.h -1 +1
+
+2005-10-10 Pekka Pessi <Pekka.Pessi at 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 at nokia.com>
+
+ * Makefile.am: Do not include msg_test_class.o in libmsg.
+
+2005-08-01 Pekka Pessi <Pekka.Pessi at 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 at nokia.com>
+
+ * Initial import of the module to Sofia-SIP tree.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/Doxyfile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/Doxyfile Thu Dec 21 01:30:28 2006
@@ -0,0 +1,17 @@
+PROJECT_NAME = "msg"
+OUTPUT_DIRECTORY = ../docs/html/msg
+
+INPUT = msg.docs . sofia-sip
+
+ at INCLUDE = ../docs/Doxyfile.conf
+ at 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
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/Makefile.am Thu Dec 21 01:30:28 2006
@@ -0,0 +1,117 @@
+#
+# Makefile.am for msg module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at 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 $<
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/Makefile.in Thu Dec 21 01:30:28 2006
@@ -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.
+
+ at SET_MAKE@
+
+#
+# Makefile.am for msg module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at 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
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/msg.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/msg_auth.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/msg_basic.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/msg_date.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/msg_generic.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/msg_header_copy.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/msg_header_make.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/msg_mclass.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/msg_mime.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/msg_mime_table.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/msg_name_hash.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/msg_parser.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/msg_parser_util.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/msg_tag.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_class.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_msg.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_table.Po at am__quote@
+
+.c.o:
+ at am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+ at am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ at am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at 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) $<
+
+ at ENABLE_COVERAGE_TRUE@coverage:
+ at 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:
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,409 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@file msg.c Message object implementation.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at 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;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg.docs Thu Dec 21 01:30:28 2006
@@ -0,0 +1,506 @@
+/* -*- text -*- */
+
+/**@MODULEPAGE "msg" - Message Parser Module
+
+ at 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.
+
+ at CONTACT Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ at STATUS @SofiaSIP Core library
+
+ at LICENSE LGPL
+
+ at par Contributor(s):
+- Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ at 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
+
+ at 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:
+
+ at code
+typedef struct msg_accept_s sip_accept_t;
+typedef struct msg_accept_s http_accept_t;
+ at 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>.
+
+ at 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.
+
+ at image html sip-parser.gif Separating byte stream to messages
+ at 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.
+
+ at 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:
+ at 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 ) ]
+ at 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:
+
+ at 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;
+ at 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.
+
+ at 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.
+
+ at 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:
+ at 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;
+ at 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.
+
+ at 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:
+ at code
+BYE sip:joe at 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 at example.edu>;tag=77241a86
+To: Joe User <sip:joe at example.com>;tag=7c6276c1
+Call-ID: 4c4e911b at pc104.example.edu
+CSeq: 2
+ at endcode
+
+The figure below shows the layout of the BYE message above after parsing:
+
+ at image html sip-parser2.gif BYE message and its representation in C
+ at 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.
+
+ at 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.
+
+ at 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;
+}
+ at 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.
+
+ at 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 }};
+ at 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:
+
+ at code
+ msg = msg_create(mclass, 0);
+ if (!msg)
+ return NULL;
+ at 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.
+
+ at code
+ m = msg_recv_iovec(msg, iovec, 2, n, 1);
+ if (m < 0) {
+ msg_destroy(msg);
+ return NULL;
+ }
+ at endcode
+
+These assumptions hold always true when you call msg_recv_iovec() first
+time with a complete message:
+
+ at code
+ assert(m >= 1 && m <= 2);
+ assert(iovec[0].mv_len + iovec[1].mv_len == n);
+ at 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.
+
+ at 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);
+ at 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.
+
+ at code
+ m = msg_extract(msg);
+ assert(m != 0);
+ if (m < 0) {
+ msg_destroy(msg);
+ return NULL;
+ }
+ return msg;
+}
+ at 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.
+ */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_auth.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_auth.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,156 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup msg_parser
+ * @CFILE msg_auth.c
+ *
+ * Functions for handling authentication-related headers
+ *
+ * @author Pekka Pessi <Pekka.Pessi at 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;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_basic.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_basic.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,357 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@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 at 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;
+}
+
+/* ====================================================================== */
+
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_date.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_date.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,413 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@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 at 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;
+}
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_generic.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_generic.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,234 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup msg_parser
+ * @file msg_generic.c
+ * @brief Functions for generic headers
+ *
+ * @author Pekka Pessi <Pekka.Pessi at 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;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_header_copy.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_header_copy.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,534 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup msg_headers
+ * @CFILE msg_header_copy.c
+ *
+ * Copying and duplicating headers structures.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at 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;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_header_make.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_header_make.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,180 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup msg_headers
+ * @CFILE msg_header_make.c
+ *
+ * Creating message headers from strings.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at 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;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_internal.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_internal.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,151 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#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 at 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 */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_mclass.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_mclass.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,387 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup msg_parser
+ * @CFILE msg_mclass.c
+ *
+ * Message factory object.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at 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;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_mime.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_mime.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,2176 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup msg_mime
+ * @CFILE msg_mime.c
+ *
+ * MIME-related headers and MIME multipart bodies for SIP/HTTP/RTSP.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Jun 13 02:57:51 2000 ppessi
+ *
+ *
+ */
+
+#include "config.h"
+
+#define _GNU_SOURCE 1
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <errno.h>
+#include <assert.h>
+
+#include <sofia-sip/su_alloc.h>
+
+#include "msg_internal.h"
+#include "sofia-sip/msg.h"
+#include "sofia-sip/msg_mime.h"
+
+#include <sofia-sip/su_uniqueid.h>
+#include <sofia-sip/su_errno.h>
+
+#if !HAVE_MEMMEM
+void *memmem(const void *haystack, size_t haystacklen,
+ const void *needle, size_t needlelen);
+#endif
+
+size_t memspn(const void *mem, size_t memlen,
+ const void *accept, size_t acceptlen);
+size_t memcspn(const void *mem, size_t memlen,
+ const void *reject, size_t rejectlen);
+
+/** Protocol version of MIME */
+char const msg_mime_version_1_0[] = "MIME/1.0";
+
+/* Internally used version of msg_header_t */
+union msg_mime_u
+{
+ msg_common_t sh_common[1];
+ struct {
+ msg_common_t shn_common;
+ msg_header_t *shn_next;
+ } sh_header_next[1];
+
+ msg_multipart_t sh_multipart[1];
+
+ msg_accept_t sh_accept[1];
+ msg_accept_any_t sh_accept_any[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_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_warning_t sh_warning[1];
+ msg_unknown_t sh_unknown[1];
+ msg_separator_t sh_separator[1];
+ msg_payload_t sh_payload[1];
+};
+
+#include <sofia-sip/msg_parser.h>
+#include <sofia-sip/msg_mime_protos.h>
+
+/** Define a header class for headers without any extra data to copy */
+#define MSG_HEADER_CLASS_G(c, l, s, kind) \
+ MSG_HEADER_CLASS(msg_, c, l, s, g_common, kind, msg_generic, msg_generic)
+
+#define msg_generic_update NULL
+
+/** Define a header class for a msg_list_t kind of header */
+#define MSG_HEADER_CLASS_LIST(c, l, s, kind) \
+ MSG_HEADER_CLASS(msg_, c, l, s, k_items, kind, msg_list, msg_list)
+
+#define msg_list_update NULL
+
+/* ====================================================================== */
+
+/** Calculate length of line ending (0, 1 or 2). @internal */
+#define CRLF_TEST(b) ((b)[0] == '\r' ? ((b)[1] == '\n') + 1 : (b)[0] =='\n')
+
+/**@ingroup msg_mime
+ * @defgroup msg_multipart MIME Multipart Body
+ *
+ * Representing MIME multipart bodies and their manipulation.
+ *
+ * The #msg_multipart_t is an object for storing MIME multipart message
+ * bodies. It includes message components used for framing and identifying
+ * message parts. Its syntax is defined in @RFC2046 as follows:
+ *
+ * @code
+ *
+ * multipart-body := [preamble CRLF]
+ * dash-boundary transport-padding CRLF
+ * body-part *encapsulation
+ * close-delimiter transport-padding
+ * [CRLF epilogue]
+ *
+ * preamble := discard-text
+ *
+ * discard-text := *(*text CRLF)
+ * ; May be ignored or discarded.
+ *
+ * dash-boundary := "--" boundary
+ * ; boundary taken from the value of boundary parameter
+ * ; of the Content-Type field.
+ *
+ * boundary := 0*69<bchars> bcharsnospace
+ *
+ * bchars := bcharsnospace / " "
+ *
+ * bcharsnospace := DIGIT / ALPHA / "'" / "(" / ")" /
+ * "+" / "_" / "," / "-" / "." /
+ * "/" / ":" / "=" / "?"
+ *
+ * transport-padding := *LWSP-char
+ * ; Composers MUST NOT generate non-zero length
+ * ; transport padding, but receivers MUST be able to
+ * ; handle padding added by message transports.
+ *
+ * body-part := <"message" as defined in @RFC822, with all header fields
+ * optional, not starting with the specified dash-boundary,
+ * and with the delimiter not occurring anywhere in the body
+ * part. Note that the semantics of a part differ from the
+ * semantics of a message, as described in the text.>
+ *
+ * encapsulation := delimiter transport-padding CRLF
+ * body-part
+ *
+ * close-delimiter := delimiter "--"
+ *
+ * delimiter := CRLF dash-boundary
+ *
+ * epilogue := discard-text
+ *
+ * @endcode
+ *
+ * @par Parsing a Multipart Message
+ *
+ * When a message body contains a multipart entity (in other words, it has a
+ * MIME media type of "multipart"), the application can split the multipart
+ * entity into body parts
+ *
+ * The parsing is relatively simple, the application just gives a memory
+ * home object, a Content-Type header object and message body object as an
+ * argument to msg_multipart_parse() function:
+ * @code
+ * if (sip->sip_content_type &&
+ * strncasecmp(sip->sip_content_type, "multipart/", 10) == 0) {
+ * msg_multipart_t *mp;
+ *
+ * if (sip->sip_multipart)
+ * mp = sip->sip_multipart;
+ * else
+ * mp = msg_multipart_parse(msg_home(msg),
+ * sip->sip_content_type,
+ * (sip_payload_t *)sip->sip_payload);
+ *
+ * if (mp)
+ * ... processing multipart ...
+ * else
+ * ... error handling ...
+ * }
+ * @endcode
+ *
+ * The resulting list of msg_multipart_t structures contain the parts of the
+ * multipart entity, each part represented by a separate #msg_multipart_t
+ * structure. Please note that in order to make error recovery possible, the
+ * parsing is not recursive - if multipart contains another multipart, the
+ * application is responsible for scanning for it and parsing it.
+ *
+ * @par Constructing a Multipart Message
+ *
+ * Constructing a multipart body is a bit more hairy. The application needs
+ * a message object (#msg_t), which is used to buffer the encoding of
+ * multipart components.
+ *
+ * As an example, let us create a "multipart/mixed" multipart entity with a
+ * HTML and GIF contents, and convert it into a #sip_payload_t structure:
+ * @code
+ * msg_t *msg = msg_create(sip_default_mclass, 0);
+ * su_home_t *home = msg_home(msg);
+ * sip_t *sip = sip_object(msg);
+ * sip_content_type_t *c;
+ * msg_multipart_t *mp = NULL;
+ * msg_header_t *h = NULL;
+ * char *b;
+ * size_t len, offset;
+ *
+ * mp = msg_multipart_create(home, "text/html;level=3", html, strlen(html));
+ * mp->mp_next = msg_multipart_create(home, "image/gif", gif, giflen);
+ *
+ * c = sip_content_type_make(home, "multipart/mixed");
+ *
+ * // Add delimiters to multipart, and boundary parameter to content-type
+ * if (msg_multipart_complete(home, c, mp) < 0)
+ * return -1; // Error
+ *
+ * // Combine multipart components into the chain
+ * h = NULL;
+ * if (msg_multipart_serialize(&h, mp) < 0)
+ * return -1; // Error
+ *
+ * // Encode all multipart components
+ * len = msg_multipart_prepare(msg, mp, 0);
+ * if (len < 0)
+ * return -1; // Error
+ *
+ * pl = sip_payload_create(home, NULL, len);
+ *
+ * // Copy each element from multipart to pl_data
+ * b = pl->pl_data;
+ * for (offset = 0, h = mp; offset < len; h = h->sh_succ) {
+ * memcpy(b + offset, h->sh_data, h->sh_len);
+ * offset += h->sh_len;
+ * }
+ * @endcode
+ *
+ */
+
+/**Create a part for MIME multipart entity.
+ *
+ * The function msg_multipart_create() allocates a new #msg_multipart_t
+ * object from memory home @a home. If @a content_type is non-NULL, it makes
+ * a #msg_content_type_t header object and adds the header to the
+ * #msg_multipart_t object. If @a dlen is nonzero, it allocates a
+ * msg_payload_t structure of @a dlen bytes for the payload of the newly
+ * created #msg_multipart_t object. If @a data is non-NULL, it copies the @a
+ * dlen bytes of of data to the payload of the newly created
+ * #msg_multipart_t object.
+ *
+ * @return A pointer to the newly created #msg_multipart_t object, or NULL
+ * upon an error.
+ */
+msg_multipart_t *msg_multipart_create(su_home_t *home,
+ char const *content_type,
+ void const *data,
+ isize_t dlen)
+{
+ msg_multipart_t *mp;
+
+ mp = (msg_multipart_t *)msg_header_alloc(home, msg_multipart_class, 0);
+
+ if (mp) {
+ if (content_type)
+ mp->mp_content_type = msg_content_type_make(home, content_type);
+ if (dlen)
+ mp->mp_payload = msg_payload_create(home, data, dlen);
+
+ if ((!mp->mp_content_type && content_type) ||
+ (!mp->mp_payload && dlen)) {
+ su_free(home, mp->mp_content_type);
+ su_free(home, mp->mp_payload);
+ su_free(home, mp);
+ mp = NULL;
+ }
+ }
+
+ return mp;
+}
+
+/** Convert boundary parameter to a search string. */
+static char *
+msg_multipart_boundary(su_home_t *home, char const *b)
+{
+ char *boundary;
+
+ if (!b || !(boundary = su_alloc(home, 2 + 2 + strlen(b) + 2 + 1)))
+ return NULL;
+
+ strcpy(boundary, CR LF "--");
+
+ if (b[0] == '"') /* " See http://bugzilla.gnome.org/show_bug.cgi?id=134216 */
+
+ msg_unquote(boundary + 4, b);
+ else
+ strcpy(boundary + 4, b);
+
+
+ strcat(boundary + 4, CR LF);
+
+ return boundary;
+}
+
+
+/** Boundary chars. */
+static char const bchars[] =
+"'()+_,-./:=?"
+"0123456789"
+"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+"abcdefghijklmnopqrstuvwxyz"
+" ";
+
+#define bchars_len (sizeof(bchars) - 1)
+
+/** Search for a suitable boundary from MIME. */
+static char *
+msg_multipart_search_boundary(su_home_t *home, char const *p, size_t len)
+{
+ size_t m;
+ unsigned crlf;
+ char const *end = p + len;
+ char *boundary;
+
+ if (len < 2)
+ return NULL;
+
+ /* Boundary looks like LF -- string SP* [CR] LF */
+ if (memcmp("--", p, 2) == 0) {
+ /* We can be at boundary beginning, there is no CR LF */
+ m = 2 + memspn(p + 2, len - 2, bchars, bchars_len);
+ if (m + 2 >= len)
+ return NULL;
+ crlf = p[m] == '\r' ? 1 + (p[m + 1] == '\n') : (p[m] == '\n');
+ while (p[m - 1] == ' ' || p[m - 1] == '\t')
+ m--;
+ if (m > 2 && crlf) {
+ boundary = su_alloc(home, 2 + m + 2 + 1);
+ if (boundary) {
+ memcpy(boundary, CR LF, 2);
+ memcpy(boundary + 2, p, m);
+ strcpy(boundary + m + 2, CR LF);
+ }
+ return boundary;
+ }
+ }
+
+ /* Look for LF -- */
+ for (;(p = memmem(p, end - p, LF "--", 3)); p += 3) {
+ len = end - p;
+ m = 3 + memspn(p + 3, len - 3, bchars, bchars_len);
+ if (m + 2 >= len)
+ return NULL;
+ crlf = p[m] == '\r' ? 1 + (p[m + 1] == '\n') : (p[m] == '\n');
+ while (p[m - 1] == ' ' || p[m - 1] == '\t')
+ m--;
+ m--;
+ if (m > 2 && crlf) {
+ boundary = su_alloc(home, 2 + m + 2 + 1);
+ if (boundary) {
+ memcpy(boundary, CR LF, 2);
+ memcpy(boundary + 2, p + 1, m);
+ strcpy(boundary + 2 + m, CR LF);
+ }
+ return boundary;
+ }
+ }
+
+ return NULL;
+}
+
+/** Parse a MIME multipart.
+ *
+ * The function msg_multipart_parse() parses a MIME multipart message. The
+ * common syntax of multiparts is described in @RFC2046 (section 7).
+ *
+ * @param[in,out] home home for allocating structures
+ * @param[in] c content-type header for multipart
+ * @param[in] pl payload structure for multipart
+ *
+ * After parsing, the @a pl will contain the plain-text preamble (if any).
+ *
+ * @note If no @b Content-Type header is given, the msg_multipart_parse()
+ * tries to look for a suitable boundary. Currently, it takes first
+ * boundary-looking string and uses that, so it can be fooled with, for
+ * instance, signature @c "--Pekka".
+ */
+msg_multipart_t *msg_multipart_parse(su_home_t *home,
+ msg_content_type_t const *c,
+ msg_payload_t *pl)
+{
+ msg_multipart_t *mp = NULL, *all = NULL, **mmp = &all;
+ /* Dummy msg object */
+ msg_t msg[1] = {{{ SU_HOME_INIT(msg) }}};
+ size_t len, m, blen;
+ char *boundary, *p, *next, save;
+ char const *b, *end;
+ msg_param_t param;
+
+ p = pl->pl_data; len = pl->pl_len; end = p + len;
+
+ su_home_init(msg_home(msg));
+ msg->m_class = msg_multipart_mclass;
+ msg->m_tail = &msg->m_chain;
+
+ /* Get boundary from Content-Type */
+ if (c && (param = msg_header_find_param(c->c_common, "boundary=")))
+ boundary = msg_multipart_boundary(msg_home(msg), param);
+ else
+ boundary = msg_multipart_search_boundary(msg_home(msg), p, len);
+
+ if (!boundary)
+ return NULL;
+
+ m = strlen(boundary) - 2, blen = m - 1;
+
+ /* Find first delimiter */
+ if (memcmp(boundary + 2, p, m - 2) == 0)
+ b = p, p = p + m - 2, len -= m - 2;
+ else if ((p = memmem(p, len, boundary + 1, m - 1))) {
+ if (p != pl->pl_data && p[-1] == '\r')
+ b = --p, p = p + m, len -= m;
+ else
+ b = p, p = p + m - 1, len -= m - 1;
+ }
+ else {
+ su_home_deinit(msg_home(msg));
+ return NULL;
+ }
+
+ /* Split multipart into parts */
+ for (;;) {
+ while (p[0] == ' ')
+ p++;
+
+ p += p[0] == '\r' ? 1 + (p[1] == '\n') : (p[0] == '\n');
+
+ len = end - p;
+
+ if (len < blen)
+ break;
+
+ next = memmem(p, len, boundary + 1, m = blen);
+
+ if (!next)
+ break; /* error */
+
+ if (next != p && next[-1] == '\r')
+ next--, m++;
+
+ mp = (msg_multipart_t *)msg_header_alloc(msg_home(msg), msg_multipart_class, 0);
+ if (mp == NULL)
+ break; /* error */
+ *mmp = mp; mmp = &mp->mp_next;
+
+ /* Put delimiter transport-padding CRLF here */
+ mp->mp_common->h_data = b;
+ mp->mp_common->h_len = p - b;
+
+ /* .. and body-part here */
+ mp->mp_data = p;
+ mp->mp_len = next - p;
+
+ if (next[m] == '-' && next[m + 1] == '-') {
+ /* We found close-delimiter */
+ assert(mp);
+ if (!mp)
+ break; /* error */
+ mp->mp_close_delim = (msg_payload_t *)
+ msg_header_alloc(msg_home(msg), msg_payload_class, 0);
+ if (!mp->mp_close_delim)
+ break; /* error */
+ /* Include also transport-padding and epilogue in the close-delimiter */
+ mp->mp_close_delim->pl_data = next;
+ mp->mp_close_delim->pl_len = p + len - next;
+ break;
+ }
+
+ b = next; p = next + m;
+ }
+
+ if (!mp || !mp->mp_close_delim) {
+ su_home_deinit(msg_home(msg));
+ /* Delimiter error */
+ return NULL;
+ }
+
+ /* Parse each part */
+ for (mp = all; mp; mp = mp->mp_next) {
+ msg->m_object = (msg_pub_t *)mp; p = mp->mp_data; next = p + mp->mp_len;
+
+ if (msg->m_tail)
+ mp->mp_common->h_prev = msg->m_tail,
+ *msg->m_tail = (msg_header_t *)mp;
+
+ msg->m_chain = (msg_header_t *)mp;
+ msg->m_tail = &mp->mp_common->h_succ;
+
+ save = *next; *next = '\0'; /* NUL-terminate this part */
+
+ for (len = next - p; len > 0; len -= m, p += m) {
+ if (IS_CRLF(p[0])) {
+ m = msg_extract_separator(msg, (msg_pub_t*)mp, p, len, 1);
+ assert(m > 0);
+
+ p += m; len -= m;
+
+ if (len > 0) {
+ m = msg_extract_payload(msg, (msg_pub_t*)mp, NULL, len, p, len, 1);
+ assert(m > 0);
+ assert(len == m);
+ }
+ break;
+ }
+
+ m = msg_extract_header(msg, (msg_pub_t*)mp, p, len, 1);
+
+ if (m <= 0) {
+ assert(m > 0);
+ /* Xyzzy */
+ }
+ }
+
+ *next = save; /* XXX - Should we leave the payload NUL-terminated? */
+ }
+
+ /* Postprocess */
+ blen = strlen(boundary);
+
+ for (mp = all; mp; mp = mp->mp_next) {
+ mp->mp_data = boundary;
+ mp->mp_len = blen;
+
+ assert(mp->mp_payload || mp->mp_separator);
+
+ if (mp->mp_close_delim) {
+ msg_header_t **tail;
+
+ if (mp->mp_payload)
+ tail = &mp->mp_payload->pl_common->h_succ;
+ else
+ tail = &mp->mp_separator->sep_common->h_succ;
+
+ assert(msg->m_chain == (msg_header_t *)mp);
+ assert(*tail == NULL);
+
+ mp->mp_close_delim->pl_common->h_prev = tail;
+ *tail = (msg_header_t *)mp->mp_close_delim;
+ }
+ }
+
+ msg_fragment_clear(pl->pl_common);
+ pl->pl_len = all->mp_data - (char *)pl->pl_data;
+
+ su_home_move(home, msg_home(msg)); su_home_deinit(msg_home(msg));
+
+ return all;
+}
+
+/**Add all missing parts to the multipart.
+ *
+ * Add missing components such as boundaries between body parts, separators
+ * between body-part headers and data, and close-delimiter after last
+ * body-part to the multipart message.
+ *
+ * @param[in,out] home home for allocating structures
+ * @param[in,out] c content-type header for multipart
+ * @param[in,out] mp pointer to first multipart structure
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error
+ *
+ * @ERRORS
+ * @ERROR EBADMSG
+ * The @b Content-Type header @a c is malformed, or multipart message
+ * contains a malformed @b Content-Type header.
+ * @ERROR ENOMEM
+ * A memory allocation failed.
+ * @ERROR EINVAL
+ * The function msg_multipart_complete() was given invalid arguments.
+ */
+int msg_multipart_complete(su_home_t *home,
+ msg_content_type_t *c,
+ msg_multipart_t *mp)
+{
+ char *boundary;
+ char const *b;
+ size_t blen, m;
+
+ if (c == NULL || mp == NULL)
+ return (errno = EINVAL), -1;
+
+ if (!(b = msg_header_find_param(c->c_common, "boundary="))) {
+ /* Generate boundary */
+ enum { tlen = 16 * 4 / 3 };
+ char token[sizeof("boundary=") + tlen + 1];
+
+ if (mp->mp_data) {
+ b = mp->mp_data;
+ m = mp->mp_len;
+
+ if (strncmp(b, CR LF "--", 4) == 0)
+ b += 4, m -= 4;
+ else if (strncmp(b, "--", 2) == 0)
+ b += 2, m -= 2;
+ else
+ return (errno = EBADMSG), -1;
+ /* XXX - quoting? */
+ b = su_sprintf(home, "boundary=\"%.*s\"", (int)m, b);
+ }
+ else {
+ strcpy(token, "boundary=");
+ msg_random_token(token + strlen("boundary="), (size_t)tlen, NULL, 0);
+ b = su_strdup(home, token);
+ }
+
+ if (!b)
+ return -1;
+
+ msg_params_replace(home, (msg_param_t **)&c->c_params, b);
+
+ b += strlen("boundary=");
+ }
+
+ if (!(boundary = msg_multipart_boundary(home, b)))
+ return -1;
+
+ blen = strlen(boundary); m = blen - 2;
+
+ for (; mp; mp = mp->mp_next) {
+ if (mp->mp_data == NULL) {
+ mp->mp_data = boundary, mp->mp_len = blen;
+ } else {
+ if (mp->mp_len < 3)
+ return -1;
+ if (mp->mp_data[0] == '\r' && mp->mp_data[1] == '\n') {
+ if (mp->mp_len < m || memcmp(mp->mp_data + 2, boundary + 2, m - 2))
+ return -1;
+ } else if (mp->mp_data[0] == '\n') {
+ if (mp->mp_len < m - 1 || memcmp(mp->mp_data + 1, boundary + 2, m - 2))
+ return -1;
+ } else {
+ if (mp->mp_len < m - 2 || memcmp(mp->mp_data, boundary + 2, m - 2))
+ return -1;
+ }
+ }
+
+ if (mp->mp_next == NULL) {
+ if (!mp->mp_close_delim)
+ mp->mp_close_delim = msg_payload_format(home, "%.*s--" CR LF,
+ (int)m, boundary);
+ if (!mp->mp_close_delim)
+ return -1;
+ }
+ else if (mp->mp_close_delim) {
+ msg_payload_t *e = mp->mp_close_delim;
+
+ mp->mp_close_delim = NULL;
+
+ if (e->pl_common->h_prev)
+ *e->pl_common->h_prev = e->pl_common->h_succ;
+ if (e->pl_common->h_succ)
+ e->pl_common->h_succ->sh_prev = e->pl_common->h_prev;
+ }
+
+ mp->mp_common->h_data = mp->mp_data;
+ mp->mp_common->h_len = mp->mp_len;
+
+ if (!mp->mp_separator)
+ if (!(mp->mp_separator = msg_separator_make(home, CR LF)))
+ return -1;
+
+ if (mp->mp_multipart) {
+ c = mp->mp_content_type;
+ if (c == NULL)
+ return (errno = EBADMSG), -1;
+
+ if (msg_multipart_complete(home, c, mp->mp_multipart) < 0)
+ return -1;
+ }
+
+ if (!mp->mp_payload)
+ if (!(mp->mp_payload = msg_payload_create(home, NULL, 0)))
+ return -1;
+ }
+
+ return 0;
+}
+
+/** Serialize a multipart message.
+ *
+ */
+msg_header_t *msg_multipart_serialize(msg_header_t **head0,
+ msg_multipart_t *mp)
+{
+ msg_header_t *h_succ_all = NULL;
+ msg_header_t *h, **head, **hh, *h0, *h_succ;
+ void *hend;
+
+#define is_in_chain(h) ((h) && ((msg_frg_t*)(h))->h_prev != NULL)
+#define insert(head, h) \
+ ((h)->sh_succ = *(head), *(head) = (h), \
+ (h)->sh_prev = (head), (head) = &(h)->sh_succ)
+
+ if (mp == NULL || head0 == NULL)
+ return NULL;
+
+ h_succ_all = *head0; head = head0;
+
+ for (; mp; mp = mp->mp_next) {
+ h0 = (msg_header_t *)mp;
+
+ assert(mp->mp_separator); assert(mp->mp_payload);
+ assert(mp->mp_next || mp->mp_close_delim);
+
+ if (!mp->mp_separator || !mp->mp_payload ||
+ (!mp->mp_next && !mp->mp_close_delim))
+ return NULL;
+
+ if ((void *)mp == h_succ_all)
+ h_succ_all = NULL;
+
+ *head0 = h0; h0->sh_prev = head;
+
+ if (is_in_chain(mp->mp_separator))
+ hend = mp->mp_separator;
+ else if (is_in_chain(mp->mp_payload))
+ hend = mp->mp_payload;
+ else if (is_in_chain(mp->mp_multipart))
+ hend = mp->mp_multipart;
+ else if (is_in_chain(mp->mp_close_delim))
+ hend = mp->mp_close_delim;
+ else if (is_in_chain(mp->mp_next))
+ hend = mp->mp_next;
+ else
+ hend = NULL;
+
+ /* Search latest header in chain */
+ for (head = &mp->mp_common->h_succ;
+ *head && *head != hend;
+ head = &(*head)->sh_succ)
+ ;
+
+ h_succ = *head;
+
+ /* Serialize headers */
+ for (hh = &((msg_pub_t*)mp)->msg_request;
+ (char *)hh < (char *)&mp->mp_separator;
+ hh++) {
+ h = *hh; if (!h) continue;
+ for (h = *hh; h; h = h->sh_next) {
+ if (h == h_succ || !is_in_chain(h)) {
+ *head = h; h->sh_prev = head; head = &h->sh_succ;
+ while (*head && *head != hend)
+ head = &(*head)->sh_succ;
+ if (h == h_succ)
+ h_succ = *head;
+ }
+ else {
+ /* XXX Check that h is between head and hend */
+ }
+ }
+ }
+
+ if (!is_in_chain(mp->mp_separator)) {
+ insert(head, (msg_header_t *)mp->mp_separator);
+ } else {
+ assert(h_succ == (msg_header_t *)mp->mp_separator);
+ mp->mp_separator->sep_common->h_prev = head;
+ *head = (msg_header_t *)mp->mp_separator;
+ head = &mp->mp_separator->sep_common->h_succ;
+ h_succ = *head;
+ }
+
+ if (!is_in_chain(mp->mp_payload)) {
+ insert(head, (msg_header_t *)mp->mp_payload);
+ } else {
+ assert(h_succ == (msg_header_t *)mp->mp_payload);
+ mp->mp_payload->pl_common->h_prev = head;
+ *head = (msg_header_t *)mp->mp_payload;
+ head = &mp->mp_payload->pl_common->h_succ;
+ h_succ = *head;
+ }
+
+ if (mp->mp_multipart) {
+ if ((*head = h_succ))
+ h_succ->sh_prev = head;
+ if (!(h = msg_multipart_serialize(head, mp->mp_multipart)))
+ return NULL;
+ head = &h->sh_succ; h_succ = *head;
+ }
+
+ if (mp->mp_close_delim) {
+ if (!is_in_chain(mp->mp_close_delim)) {
+ insert(head, (msg_header_t*)mp->mp_close_delim);
+ } else {
+ assert(h_succ == (msg_header_t *)mp->mp_close_delim);
+ mp->mp_close_delim->pl_common->h_prev = head;
+ *head = (msg_header_t *)mp->mp_close_delim;
+ head = &mp->mp_close_delim->pl_common->h_succ;
+ }
+
+ if (h_succ_all)
+ *head = h_succ_all, h_succ_all->sh_prev = head;
+
+ return (msg_header_t *)mp->mp_close_delim;
+ }
+
+ *head = h_succ;
+
+ head0 = head;
+ }
+
+ assert(!mp);
+
+ return NULL;
+}
+
+/** Encode a multipart.
+ *
+ * @return The size of multipart in bytes, or -1 upon an error.
+ */
+issize_t msg_multipart_prepare(msg_t *msg, msg_multipart_t *mp, int flags)
+{
+ if (!mp || !mp->mp_data)
+ return -1;
+
+ if (!mp->mp_common->h_data ||
+ mp->mp_common->h_len != mp->mp_len - 2 ||
+ memcmp(mp->mp_common->h_data, mp->mp_data + 2, mp->mp_len - 2)) {
+ mp->mp_common->h_data = mp->mp_data + 2;
+ mp->mp_common->h_len = mp->mp_len - 2;
+ }
+
+ return msg_headers_prepare(msg, (msg_header_t *)mp, flags);
+}
+
+/** Decode a multipart. */
+issize_t msg_multipart_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
+{
+ su_home_t tmphome[1] = { SU_HOME_INIT(tmphome) };
+ msg_payload_t pl[1];
+ msg_multipart_t *mp, *result;
+
+ assert(h && msg_is_multipart(h));
+
+ msg_payload_init(pl);
+
+ result = (msg_multipart_t *)h;
+
+ pl->pl_data = s;
+ pl->pl_len = slen;
+
+ mp = msg_multipart_parse(tmphome, NULL, pl);
+
+ if (mp) {
+ *result = *mp;
+
+ if (result->mp_common->h_succ->sh_prev)
+ result->mp_common->h_succ->sh_prev =
+ &result->mp_common->h_succ;
+
+ su_free(tmphome, mp);
+
+ su_home_move(home, tmphome);
+ }
+
+ su_home_deinit(tmphome);
+
+ return mp ? 0 : -1;
+}
+
+/** Encode a multipart.
+ *
+ * Please note that here we just encode a element, the msg_multipart_t
+ * itself.
+ */
+issize_t msg_multipart_e(char b[], isize_t bsiz, msg_header_t const *h, int flags)
+{
+ return msg_payload_e(b, bsiz, h, flags);
+}
+
+/** Calculate extra size of a multipart */
+isize_t msg_multipart_dup_xtra(msg_header_t const *h, isize_t offset)
+{
+ msg_multipart_t const *mp = (msg_multipart_t *)h;
+ msg_header_t const * const *hh;
+
+ offset = msg_payload_dup_xtra(h, offset);
+
+ for (hh = (msg_header_t const **)&((msg_pub_t *)mp)->msg_request;
+ (char *)hh <= (char *)&mp->mp_close_delim;
+ hh++) {
+ for (h = *hh; h; h = h->sh_next) {
+ MSG_STRUCT_SIZE_ALIGN(offset);
+ offset = h->sh_class->hc_dxtra(h, offset + h->sh_class->hc_size);
+ }
+ }
+
+ return offset;
+}
+
+/** Duplicate one msg_multipart_t object */
+char *msg_multipart_dup_one(msg_header_t *dst, msg_header_t const *src,
+ char *b, isize_t xtra)
+{
+ msg_multipart_t const *mp = (msg_multipart_t *)src;
+ msg_header_t *h, **hh;
+ char *end = b + xtra;
+
+ b = msg_payload_dup_one(dst, src, b, xtra);
+
+ for (hh = &((msg_pub_t*)mp)->msg_request;
+ (char *)hh <= (char *)&mp->mp_close_delim;
+ hh++) {
+ for (h = *hh; h; h = h->sh_next) {
+ MSG_STRUCT_ALIGN(b);
+ dst = (msg_header_t *)b;
+ memset(dst, 0, sizeof dst->sh_common);
+ dst->sh_class = h->sh_class;
+ b = h->sh_class->hc_dup_one(dst, h, b + h->sh_class->hc_size, end - b);
+ if (h->sh_class->hc_update)
+ msg_header_update_params(h->sh_common, 0);
+ assert(b <= end);
+ }
+ }
+
+ return b;
+}
+
+#if 0
+msg_hclass_t msg_multipart_class[] =
+MSG_HEADER_CLASS(msg_, multipart, NULL, "", mp_common, append, msg_multipart);
+#endif
+
+/**Calculate Q value.
+ *
+ * The function msg_q_value() converts q-value string @a q to numeric value
+ * in range (0..1000). Q values are used, for instance, to describe
+ * relative priorities of registered contacts.
+ *
+ * @param q q-value string ("1" | "." 1,3DIGIT)
+ *
+ * @return
+ * The function msg_q_value() returns an integer in range 0 .. 1000.
+ */
+unsigned msg_q_value(char const *q)
+{
+ unsigned value = 0;
+
+ if (!q)
+ return 500;
+ if (q[0] != '0' && q[0] != '.' && q[0] != '1')
+ return 500;
+ while (q[0] == '0')
+ q++;
+ if (q[0] >= '1' && q[0] <= '9')
+ return 1000;
+ if (q[0] == '\0')
+ return 0;
+ if (q[0] != '.')
+ /* Garbage... */
+ return 500;
+
+ if (q[1] >= '0' && q[1] <= '9') {
+ value = (q[1] - '0') * 100;
+ if (q[2] >= '0' && q[2] <= '9') {
+ value += (q[2] - '0') * 10;
+ if (q[3] >= '0' && q[3] <= '9') {
+ value += (q[3] - '0');
+ if (q[4] > '5' && q[4] <= '9')
+ /* Round upwards */
+ value += 1;
+ else if (q[4] == '5')
+ value += value & 1; /* Round to even */
+ }
+ }
+ }
+
+ return value;
+}
+
+/** Parse media type (type/subtype).
+ *
+ * The function msg_mediatype_d() parses a mediatype string.
+ *
+ * @param[in,out] ss string to be parsed
+ * @param[out] type value result for media type
+ *
+ * @retval 0 when successful,
+ * @retval -1 upon an error.
+ */
+issize_t msg_mediatype_d(char **ss, char const **type)
+{
+ char *s = *ss;
+ char const *result = s;
+ size_t l1 = 0, l2 = 0, n;
+
+ /* Media type consists of two tokens, separated by / */
+
+ l1 = span_token(s);
+ for (n = l1; IS_LWS(s[n]); n++);
+ if (s[n] == '/') {
+ for (n++; IS_LWS(s[n]); n++);
+ l2 = span_token(s + n);
+ n += l2;
+ }
+
+ if (l1 == 0 || l2 == 0)
+ return -1;
+
+ /* If there is extra ws between tokens, compact version */
+ if (n > l1 + 1 + l2) {
+ s[l1] = '/';
+ memmove(s + l1 + 1, s + n - l2, l2);
+ s[l1 + 1 + l2] = 0;
+ }
+
+ s += n;
+
+ while (IS_WS(*s)) *s++ = '\0';
+
+ *ss = s;
+
+ if (type)
+ *type = result;
+
+ return 0;
+}
+
+/* ====================================================================== */
+
+/**@ingroup msg_mime
+ * @defgroup msg_accept Accept Header
+ *
+ * The @b Accept request-header field can be used to specify certain media
+ * types which are acceptable for the response. Its syntax is defined in
+ * [H14.1, S20.1] as follows:
+ *
+ * @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
+ *
+ */
+
+/**@ingroup msg_accept
+ * @typedef typedef struct msg_accept_s msg_accept_t;
+ *
+ * The structure msg_accept_t contains representation of an @b Accept
+ * header.
+ *
+ * The msg_accept_t 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
+ */
+
+msg_hclass_t msg_accept_class[] =
+MSG_HEADER_CLASS(msg_, accept, "Accept", "", ac_params, apndlist,
+ msg_accept, msg_accept);
+
+issize_t msg_accept_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
+{
+ msg_accept_t *ac = (msg_accept_t *)h;
+
+ while (*s == ',') /* Ignore empty entries (comma-whitespace) */
+ *s = '\0', s += span_lws(s + 1) + 1;
+
+ if (*s == '\0') {
+ /* Empty Accept list is not an error */
+ ac->ac_type = ac->ac_subtype = "";
+ return 0;
+ }
+
+ /* "Accept:" #(type/subtyp ; *(parameters))) */
+ if (msg_mediatype_d(&s, &ac->ac_type) == -1)
+ return -1;
+ if (!(ac->ac_subtype = strchr(ac->ac_type, '/')))
+ return -1;
+ ac->ac_subtype++;
+
+ if (*s == ';' && msg_params_d(home, &s, &ac->ac_params) == -1)
+ return -1;
+
+ return msg_parse_next_field(home, h, s, slen);
+}
+
+issize_t msg_accept_e(char b[], isize_t bsiz, msg_header_t const *h, int flags)
+{
+ char *b0 = b, *end = b + bsiz;
+ msg_accept_t const *ac = (msg_accept_t *)h;
+
+ assert(msg_is_accept(h));
+
+ if (ac->ac_type) {
+ MSG_STRING_E(b, end, ac->ac_type);
+ MSG_PARAMS_E(b, end, ac->ac_params, flags);
+ }
+ MSG_TERM_E(b, end);
+
+ return b - b0;
+}
+
+isize_t msg_accept_dup_xtra(msg_header_t const *h, isize_t offset)
+{
+ msg_accept_t const *ac = (msg_accept_t *)h;
+
+ if (ac->ac_type) {
+ MSG_PARAMS_SIZE(offset, ac->ac_params);
+ offset += MSG_STRING_SIZE(ac->ac_type);
+ }
+
+ return offset;
+}
+
+/** Duplicate one msg_accept_t object */
+char *msg_accept_dup_one(msg_header_t *dst, msg_header_t const *src,
+ char *b, isize_t xtra)
+{
+ msg_accept_t *ac = (msg_accept_t *)dst;
+ msg_accept_t const *o = (msg_accept_t *)src;
+ char *end = b + xtra;
+
+ if (o->ac_type) {
+ b = msg_params_dup(&ac->ac_params, o->ac_params, b, xtra);
+ MSG_STRING_DUP(b, ac->ac_type, o->ac_type);
+ if ((ac->ac_subtype = strchr(ac->ac_type, '/')))
+ ac->ac_subtype++;
+ }
+
+ assert(b <= end); (void)end;
+
+ return b;
+}
+
+/** Update parameter(s) for Accept header. */
+int msg_accept_update(msg_common_t *h,
+ char const *name, isize_t namelen,
+ char const *value)
+{
+ msg_accept_t *ac = (msg_accept_t *)h;
+
+ if (name == NULL) {
+ ac->ac_q = NULL;
+ }
+ else if (namelen == 1 && strncasecmp(name, "q", 1) == 0) {
+ /* XXX - check for invalid value? */
+ ac->ac_q = value;
+ }
+
+ return 0;
+}
+
+/* ====================================================================== */
+
+/** Decode an Accept-* header. */
+issize_t msg_accept_any_d(su_home_t *home,
+ msg_header_t *h,
+ char *s, isize_t slen)
+{
+ /** @relatesalso msg_accept_any_s */
+ msg_accept_any_t *aa = (msg_accept_any_t *)h;
+
+ while (*s == ',') /* Ignore empty entries (comma-whitespace) */
+ *s = '\0', s += span_lws(s + 1) + 1;
+
+ if (*s == '\0')
+ return -2; /* Empty list */
+
+ /* "Accept-*:" 1#(token *(SEMI accept-param)) */
+ if (msg_token_d(&s, &aa->aa_value) == -1)
+ return -1;
+
+ if (*s == ';' && msg_params_d(home, &s, &aa->aa_params) == -1)
+ return -1;
+
+ return msg_parse_next_field(home, h, s, slen);
+}
+
+/** Encode an Accept-* header field. */
+issize_t msg_accept_any_e(char b[], isize_t bsiz, msg_header_t const *h, int f)
+{
+ /** @relatesalso msg_accept_any_s */
+ char *b0 = b, *end = b + bsiz;
+ msg_accept_any_t const *aa = (msg_accept_any_t *)h;
+
+ MSG_STRING_E(b, end, aa->aa_value);
+ MSG_PARAMS_E(b, end, aa->aa_params, flags);
+ MSG_TERM_E(b, end);
+
+ return b - b0;
+}
+
+/** Calculate extra memory used by accept-* headers. */
+isize_t msg_accept_any_dup_xtra(msg_header_t const *h, isize_t offset)
+{
+ /** @relatesalso msg_accept_any_s */
+ msg_accept_any_t const *aa = (msg_accept_any_t *)h;
+
+ MSG_PARAMS_SIZE(offset, aa->aa_params);
+ offset += MSG_STRING_SIZE(aa->aa_value);
+
+ return offset;
+}
+
+/** Duplicate one msg_accept_any_t object. */
+char *msg_accept_any_dup_one(msg_header_t *dst, msg_header_t const *src,
+ char *b, isize_t xtra)
+{
+ /** @relatesalso msg_accept_any_s */
+ msg_accept_any_t *aa = (msg_accept_any_t *)dst;
+ msg_accept_any_t const *o = (msg_accept_any_t *)src;
+ char *end = b + xtra;
+
+ b = msg_params_dup(&aa->aa_params, o->aa_params, b, xtra);
+ MSG_STRING_DUP(b, aa->aa_value, o->aa_value);
+
+ assert(b <= end); (void)end;
+
+ return b;
+}
+
+/** Update parameter(s) for Accept-* header. */
+int msg_accept_any_update(msg_common_t *h,
+ char const *name, isize_t namelen,
+ char const *value)
+{
+ msg_accept_any_t *aa = (msg_accept_any_t *)h;
+
+ if (name == NULL) {
+ aa->aa_q = NULL;
+ }
+ else if (namelen == 1 && strncasecmp(name, "q", 1) == 0) {
+ aa->aa_q = value;
+ }
+
+ return 0;
+}
+
+/* ====================================================================== */
+
+/**@ingroup msg_mime
+ * @defgroup msg_accept_charset Accept-Charset Header
+ *
+ * The Accept-Charset header is similar to Accept, but restricts the
+ * character set that are acceptable in the response. Its syntax is
+ * defined in [H14.2] as follows:
+ *
+ * @code
+ * Accept-Charset = "Accept-Charset" ":"
+ * 1#( ( charset | "*" )[ ";" "q" "=" qvalue ] )
+ * @endcode
+ *
+ */
+
+/**@ingroup msg_accept_charset
+ * @typedef typedef struct msg_accept_charset_s msg_accept_charset_t;
+ *
+ * The structure msg_accept_encoding_t contains representation of @b
+ * Accept-Charset header.
+ *
+ * The msg_accept_charset_t is defined as follows:
+ * @code
+ * typedef struct {
+ * msg_common_t aa_common[1]; // Common fragment info
+ * msg_accept_any_t *aa_next; // Pointer to next Accept-Charset
+ * char const *aa_value; // Charset
+ * msg_param_t const *aa_params; // Parameter list
+ * char const *aa_q; // Q-value
+ * } msg_accept_charset_t;
+ * @endcode
+ */
+
+msg_hclass_t msg_accept_charset_class[1] =
+ MSG_HEADER_CLASS(msg_, accept_charset, "Accept-Charset", "",
+ aa_params, apndlist, msg_accept_any, msg_accept_any);
+
+issize_t msg_accept_charset_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
+{
+ return msg_accept_any_d(home, h, s, slen);
+}
+
+issize_t msg_accept_charset_e(char b[], isize_t bsiz, msg_header_t const *h, int f)
+{
+ assert(msg_is_accept_charset(h));
+ return msg_accept_any_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/**@ingroup msg_mime
+ * @defgroup msg_accept_encoding Accept-Encoding Header
+ *
+ * The Accept-Encoding header is similar to Accept, but restricts the
+ * content-codings that are acceptable in the response. Its syntax is
+ * defined in [H14.3, S20.2] as follows:
+ *
+ * @code
+ * Accept-Encoding = "Accept-Encoding" ":"
+ * 1#( codings [ ";" "q" "=" qvalue ] )
+ * codings = ( content-coding | "*" )
+ * content-coding = token
+ * @endcode
+ *
+ */
+
+/**@ingroup msg_accept_encoding
+ * @typedef typedef struct msg_accept_encoding_s msg_accept_encoding_t;
+ *
+ * The structure msg_accept_encoding_t contains representation of @b
+ * Accept-Encoding header.
+ *
+ * The msg_accept_encoding_t is defined as follows:
+ * @code
+ * typedef struct {
+ * msg_common_t aa_common[1]; // Common fragment info
+ * msg_accept_any_t *aa_next; // Pointer to next Accept-Encoding
+ * char const *aa_value; // Content-coding
+ * msg_param_t const *aa_params; // Parameter list
+ * char const *aa_q; // Q-value
+ * } msg_accept_encoding_t;
+ * @endcode
+ */
+
+msg_hclass_t msg_accept_encoding_class[1] =
+ MSG_HEADER_CLASS(msg_, accept_encoding, "Accept-Encoding", "",
+ aa_params, apndlist, msg_accept_any, msg_accept_any);
+
+issize_t msg_accept_encoding_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
+{
+ return msg_accept_any_d(home, h, s, slen);
+}
+
+issize_t msg_accept_encoding_e(char b[], isize_t bsiz, msg_header_t const *h, int f)
+{
+ return msg_accept_any_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/**@ingroup msg_mime
+ * @defgroup msg_accept_language Accept-Language Header
+ *
+ * The Accept-Language header allows the client to indicate to the server in
+ * which language it would prefer to receive reason phrases, session
+ * descriptions or status responses carried as message bodies. Its syntax is
+ * defined in [H14.4, S20.3] as follows:
+ *
+ * @code
+ * Accept-Language = "Accept-Language" ":"
+ * 1#( language-range [ ";" "q" "=" qvalue ] )
+ *
+ * language-range = ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) | "*" )
+ * @endcode
+ *
+ */
+
+/**@ingroup msg_accept_language
+ * @typedef typedef struct msg_accept_language_s msg_accept_language_t;
+ *
+ * The structure msg_accept_language_t contains representation of @b
+ * Accept-Language header.
+ *
+ * The msg_accept_language_t is defined as follows:
+ * @code
+ * typedef struct {
+ * msg_common_t aa_common[1]; // Common fragment info
+ * msg_accept_any_t *aa_next; // Pointer to next Accept-Encoding
+ * char const *aa_value; // Language-range
+ * msg_param_t const *aa_params; // Parameter list
+ * char const *aa_q; // Q-value
+ * } msg_accept_language_t;
+ * @endcode
+ */
+
+msg_hclass_t msg_accept_language_class[1] =
+ MSG_HEADER_CLASS(msg_, accept_language, "Accept-Language", "",
+ aa_params, apndlist, msg_accept_any, msg_accept_any);
+
+issize_t msg_accept_language_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
+{
+ return msg_accept_any_d(home, h, s, slen);
+}
+
+issize_t msg_accept_language_e(char b[], isize_t bsiz, msg_header_t const *h, int f)
+{
+ assert(msg_is_accept_language(h));
+ return msg_accept_any_e(b, bsiz, h, f);
+}
+
+
+/* ====================================================================== */
+
+/**@ingroup msg_mime
+ * @defgroup msg_content_disposition Content-Disposition Header
+ *
+ * The Content-Disposition header field describes how the message body or,
+ * in the case of multipart messages, a message body part is to be
+ * interpreted by the UAC or UAS. Its syntax is defined in [S20.11]
+ * as follows:
+ *
+ * @code
+ * Content-Disposition = "Content-Disposition" ":"
+ * disposition-type *( ";" disposition-param )
+ * disposition-type = "render" | "session" | "icon" | "alert"
+ * | disp-extension-token
+ * disposition-param = "handling" "="
+ * ( "optional" | "required" | other-handling )
+ * | generic-param
+ * other-handling = token
+ * disp-extension-token = token
+ * @endcode
+ *
+ * The Content-Disposition header was extended by
+ * draft-lennox-sip-reg-payload-01.txt section 3.1 as follows:
+ *
+ * @code
+ * Content-Disposition = "Content-Disposition" ":"
+ * disposition-type *( ";" disposition-param )
+ * disposition-type /= "script" | "sip-cgi" | token
+ * disposition-param /= action-param
+ * / modification-date-param
+ * action-param = "action" "=" action-value
+ * action-value = "store" | "remove" | token
+ * modification-date-param = "modification-date" "=" quoted-date-time
+ * quoted-date-time = <"> SIP-date <">
+ * @endcode
+ */
+
+/**@ingroup msg_content_disposition
+ * @typedef struct msg_content_disposition_s msg_content_disposition_t;
+ *
+ * The structure msg_content_disposition_t contains representation of an @b
+ * Content-Disposition header.
+ *
+ * The msg_content_disposition_t is defined as follows:
+ * @code
+ * typedef 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
+ * msg_param_t cd_handling; // Value of @b handling parameter
+ * unsigned cd_required:1; // True if handling=required
+ * unsigned cd_optional:1; // True if handling=optional
+ * } msg_content_disposition_t;
+ * @endcode
+ */
+
+msg_hclass_t msg_content_disposition_class[] =
+MSG_HEADER_CLASS(msg_, content_disposition, "Content-Disposition", "",
+ cd_params, single, msg_content_disposition,
+ msg_content_disposition);
+
+issize_t msg_content_disposition_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
+{
+ msg_content_disposition_t *cd = (msg_content_disposition_t *)h;
+
+ if (msg_token_d(&s, &cd->cd_type) < 0 ||
+ (*s == ';' && msg_params_d(home, &s, &cd->cd_params) < 0))
+ return -1;
+
+ if (cd->cd_params)
+ msg_header_update_params(cd->cd_common, 0);
+
+ return 0;
+}
+
+issize_t msg_content_disposition_e(char b[], isize_t bsiz, msg_header_t const *h, int f)
+{
+ char *b0 = b, *end = b + bsiz;
+ msg_content_disposition_t const *cd = (msg_content_disposition_t *)h;
+
+ assert(msg_is_content_disposition(h));
+
+ MSG_STRING_E(b, end, cd->cd_type);
+ MSG_PARAMS_E(b, end, cd->cd_params, f);
+
+ MSG_TERM_E(b, end);
+
+ return b - b0;
+}
+
+isize_t msg_content_disposition_dup_xtra(msg_header_t const *h, isize_t offset)
+{
+ msg_content_disposition_t const *cd = (msg_content_disposition_t *)h;
+
+ MSG_PARAMS_SIZE(offset, cd->cd_params);
+ offset += MSG_STRING_SIZE(cd->cd_type);
+
+ return offset;
+}
+
+/** Duplicate one msg_content_disposition_t object */
+char *msg_content_disposition_dup_one(msg_header_t *dst,
+ msg_header_t const *src,
+ char *b, isize_t xtra)
+{
+ msg_content_disposition_t *cd = (msg_content_disposition_t *)dst;
+ msg_content_disposition_t const *o = (msg_content_disposition_t *)src;
+ char *end = b + xtra;
+
+ b = msg_params_dup(&cd->cd_params, o->cd_params, b, xtra);
+ MSG_STRING_DUP(b, cd->cd_type, o->cd_type);
+
+ assert(b <= end); (void)end;
+
+ return b;
+}
+
+/** Update Content-Disposition parameters */
+int msg_content_disposition_update(msg_common_t *h,
+ char const *name, isize_t namelen,
+ char const *value)
+{
+ msg_content_disposition_t *cd = (msg_content_disposition_t *)h;
+
+ if (name == NULL) {
+ cd->cd_handling = NULL, cd->cd_required = 0, cd->cd_optional = 0;
+ }
+ else if (namelen == strlen("handling") &&
+ strncasecmp(name, "handling", namelen) == 0) {
+ cd->cd_handling = value;
+ cd->cd_required = strcasecmp(value, "required") == 0;
+ cd->cd_optional = strcasecmp(value, "optional") == 0;
+ }
+
+ return 0;
+}
+
+/* ====================================================================== */
+
+/**@ingroup msg_mime
+ * @defgroup msg_content_encoding Content-Encoding Header
+ *
+ * The Content-Encoding header indicates what additional content codings
+ * have been applied to the entity-body. Its syntax is defined in [H14.11]
+ * and [S20.12] as follows:
+ *
+ * @code
+ * Content-Encoding = ( "Content-Encoding" / "e" ) ":" 1#content-coding
+ * content-coding = token
+ * @endcode
+ */
+
+/**@ingroup msg_content_encoding
+ * @typedef struct msg_list_s msg_content_encoding_t;
+ *
+ * The structure msg_content_encoding_t contains representation of an @b
+ * Content-Encoding header.
+ *
+ * The msg_content_encoding_t is defined as follows:
+ * @code
+ * typedef 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
+ * } msg_content_encoding_t;
+ * @endcode
+ */
+
+msg_hclass_t msg_content_encoding_class[] =
+ MSG_HEADER_CLASS_LIST(content_encoding, "Content-Encoding", "e", list);
+
+issize_t msg_content_encoding_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
+{
+ msg_content_encoding_t *e = (msg_content_encoding_t *)h;
+ return msg_commalist_d(home, &s, &e->k_items, msg_token_scan);
+}
+
+issize_t msg_content_encoding_e(char b[], isize_t bsiz, msg_header_t const *h, int f)
+{
+ assert(msg_is_content_encoding(h));
+ return msg_list_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/**@ingroup msg_mime
+ * @defgroup msg_content_language Content-Language Header
+ *
+ * The Content-Language header describes the natural language(s) of the
+ * intended audience for the enclosed message body. Note that this might not
+ * be equivalent to all the languages used within the message-body. Its
+ * syntax is defined in [H14.12, S20.13] as follows:
+ *
+ * @code
+ * Content-Language = "Content-Language" ":" 1#language-tag
+ * @endcode
+ * or
+ * @code
+ * Content-Language = "Content-Language" HCOLON
+ * language-tag *(COMMA language-tag)
+ * language-tag = primary-tag *( "-" subtag )
+ * primary-tag = 1*8ALPHA
+ * subtag = 1*8ALPHA
+ * @endcode
+ *
+ */
+
+/**@ingroup msg_content_language
+ * @typedef typedef struct msg_content_language_s msg_content_language_t;
+ *
+ * The structure msg_content_language_t contains representation of @b
+ * Content-Language header.
+ *
+ * The msg_content_language_t is defined as follows:
+ * @code
+ * typedef struct {
+ * msg_common_t k_common[1]; // Common fragment info
+ * msg_content_language_t *k_next; // (Content-Encoding header)
+ * msg_param_t *k_items; // List of languages
+ * } msg_content_language_t;
+ * @endcode
+ */
+
+msg_hclass_t msg_content_language_class[] =
+MSG_HEADER_CLASS_LIST(content_language, "Content-Language", "", list);
+
+issize_t msg_content_language_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
+{
+ msg_content_language_t *k = (msg_content_language_t *)h;
+ return msg_commalist_d(home, &s, &k->k_items, msg_token_scan);
+}
+
+issize_t msg_content_language_e(char b[], isize_t bsiz, msg_header_t const *h, int f)
+{
+ assert(msg_is_content_language(h));
+ return msg_list_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/**@ingroup msg_mime
+ * @defgroup msg_content_length Content-Length Header
+ *
+ * The Content-Length header indicates the size of the message-body in
+ * decimal number of octets. Its syntax is defined in [S10.18] as
+ * follows:
+ *
+ * @code
+ * Content-Length = ( "Content-Length" / "l" ) HCOLON 1*DIGIT
+ * @endcode
+ *
+ */
+
+/**@ingroup msg_content_length
+ * @typedef typedef struct msg_content_length_s msg_content_length_t;
+ *
+ * The structure msg_content_length_t contains representation of a
+ * Content-Length header.
+ *
+ * The msg_content_length_t is defined as follows:
+ * @code
+ * typedef 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; // Numeric value
+ * } msg_content_length_t;
+ * @endcode
+ */
+
+#define msg_content_length_d msg_numeric_d
+#define msg_content_length_e msg_numeric_e
+
+msg_hclass_t msg_content_length_class[] =
+MSG_HEADER_CLASS(msg_, content_length, "Content-Length", "l",
+ l_common, single_critical, msg_default, msg_generic);
+
+/**@ingroup msg_content_length
+ * Create a @b Content-Length header object.
+ *
+ * The function msg_content_length_create() creates a Content-Length
+ * header object with the value @a n. The memory for the header is
+ * allocated from the memory home @a home.
+ *
+ * @param home memory home
+ * @param n payload size in bytes
+ *
+ * @return
+ * The function msg_content_length_create() returns a pointer to newly
+ * created @b Content-Length header object when successful or NULL upon
+ * an error.
+ */
+msg_content_length_t *msg_content_length_create(su_home_t *home, uint32_t n)
+{
+ msg_content_length_t *l = (msg_content_length_t *)
+ msg_header_alloc(home, msg_content_length_class, 0);
+
+ if (l)
+ l->l_length = n;
+
+ return l;
+}
+
+
+/* ====================================================================== */
+
+/**@ingroup msg_mime
+ * @defgroup msg_content_md5 Content-MD5 Header
+ *
+ * The Content-MD5 header is an MD5 digest of the entity-body for the
+ * purpose of providing an end-to-end message integrity check (MIC) of the
+ * message-body. Its syntax is defined in [@RFC1864, H14.15] as follows:
+ *
+ * @code
+ * Content-MD5 = "Content-MD5" ":" md5-digest
+ * md5-digest = <base64 of 128 bit MD5 digest as per @RFC1864>
+ * @endcode
+ */
+
+/**@ingroup msg_content_md5
+ * @typedef struct msg_generic_s msg_content_md5_t;
+ *
+ * The structure msg_content_md5_t contains representation of an @b
+ * Content-MD5 header.
+ *
+ * The msg_content_md5_t is defined as follows:
+ * @code
+ * typedef 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
+ * } msg_content_md5_t;
+ * @endcode
+ */
+
+#define msg_content_md5_d msg_generic_d
+#define msg_content_md5_e msg_generic_e
+msg_hclass_t msg_content_md5_class[] =
+MSG_HEADER_CLASS_G(content_md5, "Content-MD5", "", single);
+
+/* ====================================================================== */
+
+/**@ingroup msg_mime
+ * @defgroup msg_content_id Content-ID Header
+ *
+ * The Content-ID header is an unique identifier of an entity-body. The
+ * Content-ID value may be used for uniquely identifying MIME entities in
+ * several contexts, particularly for caching data referenced by the
+ * message/external-body mechanism. Its syntax is defined in [RFC2045] as
+ * follows:
+ *
+ * @code
+ * Content-ID = "Content-ID" ":" msg-id
+ * msg-id = [CFWS] "<" id-left "@" id-right ">" [CFWS]
+ * id-left = dot-atom-text / no-fold-quote / obs-id-left
+ * id-right = dot-atom-text / no-fold-literal / obs-id-right
+ * @endcode
+ */
+
+/**@ingroup msg_content_id
+ * @typedef msg_generic_t msg_content_id_t;
+ * Content-ID Header Structure.
+ * @code
+ * typedef struct
+ * {
+ * msg_common_t g_common[1]; // Common fragment info
+ * msg_content_id_t *g_next; // Link to next header
+ * char const *g_string; // Header value
+ * }
+ * @endcode
+ */
+
+#define msg_content_id_d msg_generic_d
+#define msg_content_id_e msg_generic_e
+msg_hclass_t msg_content_id_class[] =
+MSG_HEADER_CLASS_G(content_id, "Content-ID", "", single);
+
+/* ====================================================================== */
+
+/**@ingroup msg_mime
+ * @defgroup msg_content_type Content-Type Header
+ *
+ * The @b Content-Type header indicates the media type of the message-body
+ * sent to the recipient. Its syntax is defined in [H3.7, S20.15]
+ * as follows:
+ *
+ * @code
+ * Content-Type = ( "Content-Type" | "c" ) ":" media-type
+ * media-type = type "/" subtype *( ";" parameter )
+ * type = token
+ * subtype = token
+ * @endcode
+ */
+
+/**@ingroup msg_content_type
+ * @typedef typedef struct msg_content_type_s msg_content_type_t;
+ *
+ * The structure msg_content_type_t contains representation of @b
+ * Content-Type header.
+ *
+ * The msg_content_type_t is defined as follows:
+ * @code
+ * typedef struct msg_content_type_s {
+ * msg_common_t c_common[1]; // Common fragment info
+ * msg_unknown_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
+ * } msg_content_type_t;
+ * @endcode
+ *
+ * The @a c_type is always void of whitespace, that is, there is no
+ * whitespace around the slash.
+ */
+
+#define msg_content_type_update NULL
+
+msg_hclass_t msg_content_type_class[] =
+MSG_HEADER_CLASS(msg_, content_type, "Content-Type", "c", c_params,
+ single, msg_content_type, msg_content_type);
+
+issize_t msg_content_type_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
+{
+ msg_content_type_t *c;
+
+ assert(h);
+
+ c = (msg_content_type_t *)h;
+
+ /* "Content-type:" type/subtyp *(; parameter))) */
+ if (msg_mediatype_d(&s, &c->c_type) == -1 || /* compacts token / token */
+ (c->c_subtype = strchr(c->c_type, '/')) == NULL ||
+ (*s == ';' && msg_params_d(home, &s, &c->c_params) == -1) ||
+ (*s != '\0'))
+ return -1;
+
+ c->c_subtype++;
+
+ return 0;
+}
+
+issize_t msg_content_type_e(char b[], isize_t bsiz, msg_header_t const *h, int flags)
+{
+ char *b0 = b, *end = b + bsiz;
+ msg_content_type_t const *c = (msg_content_type_t *)h;
+
+ assert(msg_is_content_type(h));
+
+ MSG_STRING_E(b, end, c->c_type);
+ MSG_PARAMS_E(b, end, c->c_params, flags);
+ MSG_TERM_E(b, end);
+
+ return b - b0;
+}
+
+isize_t msg_content_type_dup_xtra(msg_header_t const *h, isize_t offset)
+{
+ msg_content_type_t const *c = (msg_content_type_t *)h;
+
+ MSG_PARAMS_SIZE(offset, c->c_params);
+ offset += MSG_STRING_SIZE(c->c_type);
+
+ return offset;
+}
+
+/** Duplicate one msg_content_type_t object */
+char *msg_content_type_dup_one(msg_header_t *dst, msg_header_t const *src,
+ char *b, isize_t xtra)
+{
+ msg_content_type_t *c = (msg_content_type_t *)dst;
+ msg_content_type_t const *o = (msg_content_type_t *)src;
+ char *end = b + xtra;
+
+ b = msg_params_dup(&c->c_params, o->c_params, b, xtra);
+ MSG_STRING_DUP(b, c->c_type, o->c_type);
+ c->c_subtype = strchr(c->c_type, '/');
+ c->c_subtype++;
+
+ assert(b <= end); (void)end;
+
+ return b;
+}
+
+/* ====================================================================== */
+
+/**@ingroup msg_mime
+ * @defgroup msg_mime_version MIME-Version Header
+ *
+ * MIME-Version header indicates what version of the protocol was used
+ * to construct the message. Its syntax is defined in [H19.4.1, S20.24]
+ * as follows:
+ *
+ * @code
+ * MIME-Version = "MIME-Version" ":" 1*DIGIT "." 1*DIGIT
+ * @endcode
+ */
+
+/**@ingroup msg_mime_version
+ * @typedef struct msg_generic_s msg_mime_version_t;
+ *
+ * The structure msg_mime_version_t contains representation of an @b
+ * MIME-Version header.
+ *
+ * The msg_mime_version_t is defined as follows:
+ * @code
+ * typedef 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
+ * } msg_mime_version_t;
+ * @endcode
+ */
+
+msg_hclass_t msg_mime_version_class[] =
+MSG_HEADER_CLASS_G(mime_version, "MIME-Version", "", single);
+
+issize_t msg_mime_version_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
+{
+ return msg_generic_d(home, h, s, slen);
+}
+
+issize_t msg_mime_version_e(char b[], isize_t bsiz, msg_header_t const *h, int f)
+{
+ assert(msg_is_mime_version(h));
+ return msg_generic_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/**@ingroup msg_mime
+ * @defgroup msg_content_location Content-Location Header
+ *
+ *
+ */
+
+/**@ingroup msg_content_location
+ * @typedef struct msg_generic_s msg_content_location_t;
+ *
+ * The structure msg_content_location_t contains representation of an @b
+ * Content-Location header.
+ *
+ * The msg_content_location_t is defined as follows:
+ * @code
+ * typedef 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
+ * } msg_content_location_t;
+ * @endcode
+ */
+
+#define msg_content_location_d msg_generic_d
+#define msg_content_location_e msg_generic_e
+msg_hclass_t msg_content_location_class[] =
+MSG_HEADER_CLASS_G(content_location, "Content-Location", "", single);
+
+
+/* ====================================================================== */
+#if 0
+/**@ingroup msg_mime
+ * @defgroup msg_content_base Content-Base Header
+ *
+ * @RFC2617:
+ * Content-Base was deleted from the specification: it was not
+ * implemented widely, and there is no simple, safe way to introduce it
+ * without a robust extension mechanism. In addition, it is used in a
+ * similar, but not identical fashion in MHTML [45].
+ *
+ */
+
+
+/**@ingroup msg_content_base
+ * @typedef msg_generic_t msg_content_base_t;
+ * Content-Base Header Structure.
+ * @code
+ * typedef struct
+ * {
+ * msg_common_t g_common[1]; // Common fragment info
+ * msg_content_base_t *g_next; // Link to next header
+ * char const *g_string; // Header value
+ * }
+ * @endcode
+ */
+
+#define msg_content_base_d msg_generic_d
+#define msg_content_base_e msg_generic_e
+msg_hclass_t msg_content_base_class[] =
+MSG_HEADER_CLASS_G(content_base, "Content-Base", "", single);
+
+#endif
+
+/* ====================================================================== */
+
+/**@ingroup msg_mime
+ * @defgroup msg_content_transfer_encoding Content-Transfer-Encoding Header
+ *
+ *
+ */
+
+/**@ingroup msg_content_transfer_encoding
+ * @typedef struct msg_generic_s msg_content_transfer_encoding_t;
+ *
+ * The structure msg_content_transfer_encoding_t contains representation of
+ * an @b Content-Transfer-Encoding header.
+ *
+ * The msg_content_transfer_encoding_t is defined as follows:
+ * @code
+ * typedef 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
+ * } msg_content_transfer_encoding_t;
+ * @endcode
+ */
+
+
+#define msg_content_transfer_encoding_d msg_generic_d
+#define msg_content_transfer_encoding_e msg_generic_e
+msg_hclass_t msg_content_transfer_encoding_class[] =
+MSG_HEADER_CLASS_G(content_transfer_encoding, "Content-Transfer-Encoding",
+ "", single);
+
+/* ====================================================================== */
+
+/**@ingroup msg_mime
+ * @defgroup msg_warning Warning Header
+ *
+ * The Warning response-header field is used to carry additional information
+ * about the status of a response. Its syntax is defined in [S20.43]
+ * as follows:
+ *
+ * @code
+ * Warning = "Warning" HCOLON warning-value *(COMMA warning-value)
+ * warning-value = warn-code SP warn-agent SP warn-text
+ * warn-code = 3DIGIT
+ * warn-agent = hostport / pseudonym
+ * ; the name or pseudonym of the server adding
+ * ; the Warning header, for use in debugging
+ * warn-text = quoted-string
+ * pseudonym = token
+ * @endcode
+ */
+
+/**@ingroup msg_warning
+ * @typedef struct msg_warning_s msg_warning_t;
+ *
+ * The structure msg_warning_t contains representation of an @b
+ * Warning header.
+ *
+ * The msg_warning_t is defined as follows:
+ * @code
+ * typedef 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
+ * } msg_warning_t;
+ * @endcode
+ */
+
+issize_t msg_warning_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
+{
+ msg_warning_t *w = (msg_warning_t *)h;
+ char *text;
+
+ while (*s == ',') /* Ignore empty entries (comma-whitespace) */
+ *s = '\0', s += span_lws(s + 1) + 1;
+
+ /* Parse protocol */
+ if (!IS_DIGIT(*s))
+ return -1;
+ w->w_code = strtoul(s, &s, 10);
+ skip_lws(&s);
+
+ /* Host (and port) */
+ if (msg_hostport_d(&s, &w->w_host, &w->w_port) == -1)
+ return -1;
+ if (msg_quoted_d(&s, &text) == -1)
+ return -1;
+ if (msg_unquote(text, text) == NULL)
+ return -1;
+
+ w->w_text = text;
+
+ return msg_parse_next_field(home, h, s, slen);
+}
+
+issize_t msg_warning_e(char b[], isize_t bsiz, msg_header_t const *h, int f)
+{
+ msg_warning_t const *w = (msg_warning_t *)h;
+ char const *port = w->w_port;
+ int n;
+ size_t m;
+
+ n = snprintf(b, bsiz, "%03u %s%s%s ",
+ w->w_code, w->w_host, port ? ":" : "", port ? port : "");
+ if (n < 0)
+ return n;
+
+ m = msg_unquoted_e((size_t)n < bsiz ? b + n : NULL, bsiz - n, w->w_text);
+
+ if (b && n + m < bsiz)
+ b[n + m] = '\0';
+
+ return n + m;
+}
+
+isize_t msg_warning_dup_xtra(msg_header_t const *h, isize_t offset)
+{
+ msg_warning_t const *w = (msg_warning_t *)h;
+
+ offset += MSG_STRING_SIZE(w->w_host);
+ offset += MSG_STRING_SIZE(w->w_port);
+ offset += MSG_STRING_SIZE(w->w_text);
+
+ return offset;
+}
+
+char *msg_warning_dup_one(msg_header_t *dst,
+ msg_header_t const *src,
+ char *b,
+ isize_t xtra)
+{
+ msg_warning_t *w = (msg_warning_t *)dst;
+ msg_warning_t const *o = (msg_warning_t *)src;
+ char *end = b + xtra;
+
+ w->w_code = o->w_code;
+ MSG_STRING_DUP(b, w->w_host, o->w_host);
+ MSG_STRING_DUP(b, w->w_port, o->w_port);
+ MSG_STRING_DUP(b, w->w_text, o->w_text);
+
+ assert(b <= end); (void)end;
+
+ return b;
+}
+
+#define msg_warning_update NULL
+
+msg_hclass_t msg_warning_class[] =
+ MSG_HEADER_CLASS(msg_, warning, "Warning", "", w_common, append,
+ msg_warning, msg_warning);
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_mime_table.c.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_mime_table.c.in Thu Dec 21 01:30:28 2006
@@ -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 at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@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 at 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)
+
+
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_name_hash.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_name_hash.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,58 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup test_msg
+ * @CFILE msg_name_hash.c
+ *
+ * Calculate hash for given header name.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at 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);
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_parser.awk
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_parser.awk Thu Dec 21 01:30:28 2006
@@ -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 at nokia.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+#
+# --------------------------------------------------------------------
+#
+# Contributor(s): Pekka.Pessi at 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;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_parser.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_parser.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,3042 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup msg_parser
+ * @CFILE msg_parser.c
+ *
+ * HTTP-like message parser engine.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Oct 5 14:01:24 2000 ppessi
+ *
+ */
+
+/*#define NDEBUG*/
+
+#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_header.h"
+#include "sofia-sip/bnf.h"
+#include "sofia-sip/msg_parser.h"
+#include "sofia-sip/msg_mclass.h"
+#include "sofia-sip/msg_mclass_hash.h"
+#include "sofia-sip/msg_mime.h"
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+static char const __func__[] = "msg_parser";
+#endif
+
+static int _msg_header_add_dup_as(msg_t *msg,
+ msg_pub_t *pub,
+ msg_hclass_t *hc,
+ msg_header_t const *src);
+
+static void msg_insert_chain(msg_t *msg, msg_pub_t *pub, int prepend,
+ msg_header_t **head, msg_header_t *h);
+static void msg_insert_here_in_chain(msg_t *msg,
+ msg_header_t **prev,
+ msg_header_t *h);
+static inline msg_header_t *msg_chain_remove(msg_t *msg, msg_header_t *h);
+
+#ifndef NDEBUG
+static int msg_chain_loop(msg_header_t const *h);
+static int msg_chain_errors(msg_header_t const *h);
+#endif
+
+/* ====================================================================== */
+/* Message properties */
+
+/** Get message flags. */
+unsigned msg_get_flags(msg_t const *msg, unsigned mask)
+{
+ return msg ? msg->m_object->msg_flags & mask : 0;
+}
+
+/** Set message flags. */
+unsigned msg_set_flags(msg_t *msg, unsigned mask)
+{
+ return msg ? msg->m_object->msg_flags |= mask : 0;
+}
+
+/** Clear message flags. */
+unsigned msg_zap_flags(msg_t *msg, unsigned mask)
+{
+ return msg ? msg->m_object->msg_flags &= ~mask : 0;
+}
+
+/** Test if streaming is in progress. */
+int msg_is_streaming(msg_t const *msg)
+{
+ return msg && msg->m_streaming != 0;
+}
+
+/** Enable/disable streaming */
+void msg_set_streaming(msg_t *msg, enum msg_streaming_status what)
+{
+ if (msg)
+ msg->m_streaming = what != 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/** Test if header is not in the chain */
+#define msg_header_is_removed(h) ((h)->sh_prev == NULL)
+
+static inline int msg_is_request(msg_header_t const *h)
+{
+ return h->sh_class->hc_hash == msg_request_hash;
+}
+
+static inline int msg_is_status(msg_header_t const *h)
+{
+ return h->sh_class->hc_hash == msg_status_hash;
+}
+
+/* ====================================================================== */
+/* Message buffer management */
+
+/** Allocate a buffer of @a size octets, with slack of #msg_min_size. */
+void *msg_buf_alloc(msg_t *msg, usize_t size)
+{
+ struct msg_mbuffer_s *mb = msg->m_buffer;
+ size_t room = mb->mb_size - mb->mb_commit - mb->mb_used;
+ size_t target_size;
+
+ if (mb->mb_data && room >= (unsigned)size)
+ return mb->mb_data + mb->mb_used + mb->mb_commit;
+
+ target_size =
+ msg_min_size * ((size + mb->mb_commit) / msg_min_size + 1) - mb->mb_commit;
+
+ return msg_buf_exact(msg, target_size);
+}
+
+/** Allocate a buffer exactly of @a size octets, without any slack. */
+void *msg_buf_exact(msg_t *msg, usize_t size)
+{
+ struct msg_mbuffer_s *mb = msg->m_buffer;
+ size_t room = mb->mb_size - mb->mb_commit - mb->mb_used;
+ char *buffer;
+ int realloc;
+
+ if (mb->mb_data && room >= (unsigned)size)
+ return mb->mb_data + mb->mb_used + mb->mb_commit;
+
+ size += mb->mb_commit;
+
+ if (msg->m_maxsize && msg->m_size + size > msg->m_maxsize + 1) {
+ msg->m_object->msg_flags |= MSG_FLG_TOOLARGE;
+ errno = msg->m_errno = ENOBUFS;
+ return NULL;
+ }
+
+ realloc = !mb->mb_used && !msg->m_set_buffer;
+
+ if (realloc)
+ buffer = su_realloc(msg->m_home, mb->mb_data, size);
+ else
+ buffer = su_alloc(msg->m_home, size);
+
+ if (!buffer)
+ return NULL;
+
+ if (!realloc && mb->mb_commit && mb->mb_data)
+ memcpy(buffer, mb->mb_data + mb->mb_used, mb->mb_commit);
+
+ msg->m_set_buffer = 0;
+
+ mb->mb_data = buffer;
+ mb->mb_size = size;
+ mb->mb_used = 0;
+
+ return buffer + mb->mb_commit;
+}
+
+/** Commit data into buffer. */
+usize_t msg_buf_commit(msg_t *msg, usize_t size, int eos)
+{
+ if (msg) {
+ struct msg_mbuffer_s *mb = msg->m_buffer;
+ assert(mb->mb_used + mb->mb_commit + size <= mb->mb_size);
+
+ mb->mb_commit += size;
+ mb->mb_eos = eos;
+
+ if (mb->mb_used == 0 && !msg->m_chunk && !msg->m_set_buffer) {
+ size_t slack = mb->mb_size - mb->mb_commit;
+
+ if (eos || slack >= msg_min_size) {
+ /* realloc and cut down buffer */
+ size_t new_size;
+ void *new_data;
+
+ if (eos)
+ new_size = mb->mb_commit + 1;
+ else
+ new_size = mb->mb_commit + msg_min_size;
+
+ new_data = su_realloc(msg->m_home, mb->mb_data, new_size);
+ if (new_data) {
+ mb->mb_data = new_data, mb->mb_size = new_size;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+/** Get length of committed data */
+usize_t msg_buf_committed(msg_t const *msg)
+{
+ if (msg)
+ return msg->m_buffer->mb_commit;
+ else
+ return 0;
+}
+
+/** Get committed data */
+void *msg_buf_committed_data(msg_t const *msg)
+{
+ return msg && msg->m_buffer->mb_data ?
+ msg->m_buffer->mb_data + msg->m_buffer->mb_used
+ : NULL;
+}
+
+usize_t msg_buf_size(msg_t const *msg)
+{
+ assert(msg);
+ if (msg) {
+ struct msg_mbuffer_s const *mb = msg->m_buffer;
+ return mb->mb_size - mb->mb_commit - mb->mb_used;
+ }
+ else
+ return 0;
+}
+
+static inline
+void msg_buf_used(msg_t *msg, usize_t used)
+{
+ msg->m_size += used;
+ msg->m_buffer->mb_used += used;
+ if (msg->m_buffer->mb_commit > used)
+ msg->m_buffer->mb_commit -= used;
+ else
+ msg->m_buffer->mb_commit = 0;
+}
+
+/** Set buffer. */
+void msg_buf_set(msg_t *msg, void *b, usize_t size)
+{
+ if (msg) {
+ struct msg_mbuffer_s *mb = msg->m_buffer;
+
+ assert(!msg->m_set_buffer); /* This can be set only once */
+
+ mb->mb_data = b;
+ mb->mb_size = size;
+ mb->mb_used = 0;
+ mb->mb_commit = 0;
+ mb->mb_eos = 0;
+
+ msg->m_set_buffer = 1;
+ }
+}
+
+/** Move unparsed data from src to dst */
+void *msg_buf_move(msg_t *dst, msg_t const *src)
+{
+ void *retval;
+ struct msg_mbuffer_s *db = dst->m_buffer;
+ struct msg_mbuffer_s const *sb = src->m_buffer;
+
+ if (!dst || !src)
+ return NULL;
+
+ if (sb->mb_eos)
+ retval = msg_buf_exact(dst, sb->mb_commit + 1);
+ else
+ retval = msg_buf_alloc(dst, sb->mb_commit + 1);
+
+ if (retval == NULL)
+ return NULL;
+
+ memcpy(retval, sb->mb_data + sb->mb_used, sb->mb_commit);
+
+ db->mb_commit += sb->mb_commit;
+ db->mb_eos = sb->mb_eos;
+
+ return retval;
+}
+
+/**Obtain I/O vector for receiving the data.
+ *
+ * @relatesalso msg_s
+ *
+ * Allocate buffers for receiving @a n bytes
+ * of data available from network. Function returns the buffers in the I/O vector
+ * @a vec. The @a vec is allocated by the caller, the available length is
+ * given as @a veclen. If the protocol is message-oriented like UDP or SCTP
+ * and the available data ends at message boundary, the caller should set
+ * the @a exact as 1. Otherwise some extra buffer (known as @em slack) is
+ * allocated).
+ *
+ * Currently, the msg_recv_iovec() allocates receive buffers in at most two
+ * blocks, so the caller should allocate at least two elements for the I/O
+ * vector @a vec.
+ *
+ * @param[in] msg message object
+ * @param[out] vec I/O vector
+ * @param[in] veclen available length of @a vec
+ * @param[in] n number of possibly available bytes
+ * @param[in] exact true if data ends at message boundary
+ *
+ * @return
+ * The length of I/O vector to
+ * receive data, 0 if there are not enough buffers, or -1 upon an error.
+ *
+ * @sa msg_iovec(), su_vrecv()
+ */
+issize_t msg_recv_iovec(msg_t *msg, msg_iovec_t vec[], isize_t veclen,
+ usize_t n, int exact)
+{
+ size_t i = 0;
+ size_t len = 0;
+ msg_payload_t *chunk;
+ char *buf;
+
+ if (n == 0)
+ return 0;
+
+ if (veclen == 0)
+ vec = NULL;
+
+ for (chunk = msg->m_chunk; chunk; chunk = MSG_CHUNK_NEXT(chunk)) {
+ buf = MSG_CHUNK_BUFFER(chunk);
+ len = MSG_CHUNK_AVAIL(chunk);
+
+ if (len == 0)
+ continue;
+ if (!buf)
+ break;
+
+#if SU_HAVE_WINSOCK
+ /* WSABUF has u_long */
+ if (len > SU_IOVECLEN_MAX)
+ len = SU_IOVECLEN_MAX;
+#endif
+ if (len > n)
+ len = n;
+ if (vec)
+ vec[i].mv_base = buf, vec[i].mv_len = (su_ioveclen_t)len;
+ i++;
+ if (len == n)
+ return i;
+ if (i == veclen)
+ vec = NULL;
+ n -= len;
+ }
+
+ if (!chunk && msg->m_chunk && msg_get_flags(msg, MSG_FLG_FRAGS)) {
+ /*
+ * If the m_chunk is the last fragment for this message,
+ * receive rest of the data to the next message
+ */
+ if (msg->m_next == NULL)
+ msg->m_next = msg_create(msg->m_class, msg->m_oflags);
+ if (msg->m_next) {
+ msg->m_next->m_maxsize = msg->m_maxsize;
+ msg_addr_copy(msg->m_next, msg);
+ }
+ msg = msg->m_next;
+ if (msg == NULL)
+ return 0;
+ }
+
+ if (exact)
+ buf = msg_buf_exact(msg, n + 1), len = n;
+ else if (chunk && len > n && !msg_get_flags(msg, MSG_FLG_CHUNKING))
+ buf = msg_buf_exact(msg, len + 1);
+ else
+ buf = msg_buf_alloc(msg, n + 1), len = msg_buf_size(msg);
+
+ if (buf == NULL)
+ return -1;
+
+ if (vec)
+ vec[i].mv_base = buf, vec[i].mv_len = (su_ioveclen_t)n;
+
+ if (chunk) {
+ assert(chunk->pl_data == NULL); assert(chunk->pl_common->h_len == 0);
+
+ chunk->pl_common->h_data = chunk->pl_data = buf;
+
+ if (len < MSG_CHUNK_AVAIL(chunk)) {
+ msg_header_t *h = (void*)chunk;
+ h->sh_succ = msg_header_alloc(msg_home(msg), h->sh_class, 0);
+ if (!h->sh_succ)
+ return -1;
+ h->sh_succ->sh_prev = &h->sh_succ;
+ chunk->pl_next = (msg_payload_t *)h->sh_succ;
+ chunk->pl_next->pl_len = chunk->pl_len - len;
+ chunk->pl_len = len;
+ }
+ else if (len > MSG_CHUNK_AVAIL(chunk)) {
+ len = MSG_CHUNK_AVAIL(chunk);
+ }
+
+ msg_buf_used(msg, len);
+ }
+
+ return i + 1;
+
+#if 0
+ if ((msg->m_ssize || msg->m_stream)
+ /* && msg_get_flags(msg, MSG_FLG_BODY) */) {
+ /* Streaming */
+ msg_buffer_t *b, *b0;
+
+ /* Calculate available size of current buffers */
+ for (b = msg->m_stream, len = 0; b && n > len; b = b->b_next)
+ len += b->b_avail - b->b_size;
+
+ /* Allocate new buffers */
+ if (n > len && msg_buf_external(msg, n, 0) < 0)
+ return -1;
+
+ for (b0 = msg->m_stream; b0; b0 = b0->b_next)
+ if (b0->b_avail != b0->b_size)
+ break;
+
+ for (b = b0; b && n > 0; i++, b = b->b_next) {
+ len = b->b_size - b->b_avail;
+ len = n < len ? n : len;
+ if (vec && i < veclen)
+ vec[i].mv_base = b->b_data + b->b_avail, vec[i].mv_len = len;
+ else
+ vec = NULL;
+ n -= len;
+ }
+
+ return i + 1;
+ }
+#endif
+}
+
+
+/** Obtain a buffer for receiving data.
+ *
+ * @relatesalso msg_s
+ */
+issize_t msg_recv_buffer(msg_t *msg, void **return_buffer)
+{
+ void *buffer;
+
+ if (!msg)
+ return -1;
+
+ if (return_buffer == NULL)
+ return_buffer = &buffer;
+
+ if (msg->m_chunk) {
+ msg_payload_t *pl;
+
+ for (pl = msg->m_chunk; pl; pl = pl->pl_next) {
+ size_t n = MSG_CHUNK_AVAIL(pl);
+ if (n) {
+ *return_buffer = MSG_CHUNK_BUFFER(pl);
+ return n;
+ }
+ }
+
+ return 0;
+ }
+
+ if (msg_get_flags(msg, MSG_FLG_FRAGS)) {
+ /* Message is complete */
+ return 0;
+ }
+ else if ((*return_buffer = msg_buf_alloc(msg, 2))) {
+ return msg_buf_size(msg) - 1;
+ }
+ else {
+ return -1;
+ }
+}
+
+
+
+/**Commit @a n bytes of buffers.
+ *
+ * @relatesalso msg_s
+ *
+ * The function msg_recv_commit() is called after @a n bytes of data has
+ * been received to the message buffers and the parser can extract the
+ * received data.
+ *
+ * @param msg pointer to message object
+ * @param n number of bytes received
+ * @param eos true if stream is complete
+ *
+ * @note The @a eos should be always true for message-based transports. It
+ * should also be true when a stram oin stream-based transport ends, for
+ * instance, when TCP FIN is received.
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error.
+ */
+isize_t msg_recv_commit(msg_t *msg, usize_t n, int eos)
+{
+ msg_payload_t *pl;
+
+ if (eos)
+ msg->m_buffer->mb_eos = 1;
+
+ for (pl = msg->m_chunk; pl; pl = pl->pl_next) {
+ size_t len = MSG_CHUNK_AVAIL(pl);
+
+ if (n <= len)
+ len = n;
+
+ pl->pl_common->h_len += len;
+
+ n -= len;
+
+ if (n == 0)
+ return 0;
+ }
+
+ if (msg->m_chunk && msg->m_next)
+ msg = msg->m_next;
+
+ return msg_buf_commit(msg, n, eos);
+}
+
+/**Get a next message of the stream.
+ *
+ * @relatesalso msg_s
+ *
+ * When parsing a transport stream, only the first message in the stream is
+ * created with msg_create(). The rest of the messages should be created
+ * with msg_next() after previous message has been completely received and
+ * parsed.
+ *
+ */
+msg_t *msg_next(msg_t *msg)
+{
+ msg_t *next;
+ usize_t n;
+
+ if (msg && msg->m_next) {
+ next = msg->m_next;
+ msg->m_next = NULL;
+ return next;
+ }
+
+ if ((n = msg_buf_committed(msg))) {
+ if (msg_buf_move(next = msg_create(msg->m_class, msg->m_oflags), msg)) {
+ msg_addr_copy(next, msg);
+ return next;
+ }
+ /* How to indicate error? */
+ msg_destroy(next);
+ }
+
+ return NULL;
+}
+
+/** Set next message of the stream.
+ *
+ * @relatesalso msg_s
+ */
+int msg_set_next(msg_t *msg, msg_t *next)
+{
+ if (!msg || (next && next->m_next))
+ return -1;
+
+ if (msg->m_next && next)
+ next->m_next = msg->m_next;
+
+ msg->m_next = next;
+
+ return 0;
+}
+
+/** Clear committed data.
+ *
+ * @relatesalso msg_s
+ */
+void msg_clear_committed(msg_t *msg)
+{
+ if (msg) {
+ usize_t n = msg_buf_committed(msg);
+
+ if (n)
+ msg_buf_used(msg, n);
+ }
+}
+
+#if 0
+struct sigcomp_udvm;
+
+struct sigcomp_udvm *msg_get_udvm(msg_t *msg);
+struct sigcomp_udvm *msg_set_udvm(msg_t *msg, struct sigcomp_udvm *);
+
+/** Save UDVM. */
+struct sigcomp_udvm *msg_set_udvm(msg_t *msg, struct sigcomp_udvm *udvm)
+{
+ struct sigcomp_udvm *prev = NULL;
+
+ if (msg) {
+ prev = msg->m_udvm;
+ msg->m_udvm = udvm;
+ }
+
+ return prev;
+}
+
+/** Get saved UDVM */
+struct sigcomp_udvm *msg_get_udvm(msg_t *msg)
+{
+ return msg ? msg->m_udvm : NULL;
+}
+
+#endif
+
+/** Mark message as complete.
+ *
+ * @relatesalso msg_s
+ */
+unsigned msg_mark_as_complete(msg_t *msg, unsigned mask)
+{
+ if (msg) {
+ msg->m_streaming = 0;
+ return msg->m_object->msg_flags |= mask | MSG_FLG_COMPLETE;
+ }
+ else {
+ return 0;
+ }
+}
+
+/** Return true if message is complete.
+ *
+ * @relatesalso msg_s
+ */
+int msg_is_complete(msg_t const *msg)
+{
+ return msg && MSG_IS_COMPLETE(msg->m_object);
+}
+
+/** Return true if message has parsing errors.
+ *
+ * @relatesalso msg_s
+*/
+int msg_has_error(msg_t const *msg)
+{
+ return msg->m_object->msg_flags & MSG_FLG_ERROR;
+}
+
+/**Total size of message.
+ *
+ * @relatesalso msg_s
+ */
+usize_t msg_size(msg_t const *msg)
+{
+ return msg ? msg->m_size : 0;
+}
+
+/** Set the maximum size of a message.
+ *
+ * @relatesalso msg_s
+ *
+ * The function msg_maxsize() sets the maximum buffer size of a message. It
+ * returns the previous maximum size. If the @a maxsize is 0, maximum size
+ * is not set, but the current maximum size is returned.
+ *
+ * If the message size exceeds maxsize, msg_errno() returns ENOBUFS,
+ * MSG_FLG_TOOLARGE and MSG_FLG_ERROR flags are set.
+ */
+usize_t msg_maxsize(msg_t *msg, usize_t maxsize)
+{
+ usize_t retval = 0;
+
+ if (msg) {
+ retval = msg->m_maxsize;
+ if (maxsize)
+ msg->m_maxsize = maxsize;
+ }
+
+ return retval;
+}
+
+/**Set the size of next fragment.
+ *
+ * @relatesalso msg_s
+ *
+ * The function msg_streaming_size() sets the size of the message body for
+ * streaming.
+ */
+int msg_streaming_size(msg_t *msg, usize_t ssize)
+{
+ if (!msg)
+ return -1;
+
+ msg->m_ssize = ssize;
+
+ return 0;
+}
+
+/**Allocate a list of external buffers.
+ *
+ * @relatesalso msg_s
+ *
+ * The function msg_buf_external() allocates at most msg_n_fragments
+ * external buffers for the message body.
+ *
+ * @return The function msg_buf_external() returns number of allocated
+ * buffers, or -1 upon an error.
+ */
+issize_t msg_buf_external(msg_t *msg,
+ usize_t N,
+ usize_t blocksize)
+{
+ msg_buffer_t *ext, *b, **bb;
+ size_t i, I;
+
+ assert(N <= 128 * 1024);
+
+ if (msg == NULL)
+ return -1;
+ if (blocksize == 0)
+ blocksize = msg_min_block;
+ if (N == 0)
+ N = blocksize;
+ if (N > blocksize * msg_n_fragments)
+ N = blocksize * msg_n_fragments;
+ if (N > msg->m_ssize)
+ N = msg->m_ssize;
+
+ I = (N + blocksize - 1) / blocksize; assert(I <= msg_n_fragments);
+
+ for (i = 0, bb = &ext; i < I; i++) {
+ *bb = su_zalloc(msg_home(msg), sizeof **bb);
+ if (!*bb)
+ break;
+ bb = &(*bb)->b_next;
+ }
+
+ if (i == I)
+ for (b = ext, i = 0; b; b = b->b_next, i++) {
+ b->b_data = su_alloc(msg_home(msg), b->b_size = blocksize);
+ if (!b->b_data)
+ break;
+ }
+
+ if (i == I) {
+ /* Successful return */
+ for (bb = &msg->m_stream; *bb; bb = &(*bb)->b_next)
+ ;
+
+ *bb = ext;
+
+ if (msg->m_ssize != MSG_SSIZE_MAX)
+ for (b = ext; b; b = b->b_next) {
+ if (msg->m_ssize < b->b_size) {
+ b->b_size = msg->m_ssize;
+ }
+ msg->m_ssize -= b->b_size;
+ }
+
+ return i;
+ }
+
+ for (b = ext; b; b = ext) {
+ ext = b->b_next;
+ su_free(msg_home(msg), b->b_data);
+ su_free(msg_home(msg), b);
+ }
+
+ return -1;
+}
+
+int msg_unref_external(msg_t *msg, msg_buffer_t *b)
+{
+ if (msg && b) {
+ su_free(msg_home(msg), b->b_data);
+ su_free(msg_home(msg), b);
+ return 0;
+ }
+ errno = EINVAL;
+ return -1;
+}
+
+/* ====================================================================== */
+/* Parsing messages */
+
+static inline int extract_incomplete_chunks(msg_t *, int eos);
+static issize_t extract_first(msg_t *, msg_pub_t *,
+ char b[], isize_t bsiz, int eos);
+static inline issize_t extract_next(msg_t *, msg_pub_t *, char *, isize_t bsiz,
+ int eos, int copy);
+static issize_t extract_header(msg_t *, msg_pub_t*,
+ char b[], isize_t bsiz, int eos, int copy);
+static msg_header_t *header_parse(msg_t *, msg_pub_t *, msg_href_t const *,
+ char s[], isize_t slen, int copy_buffer);
+static msg_header_t *error_header_parse(msg_t *msg, msg_pub_t *mo,
+ msg_href_t const *hr);
+static inline issize_t
+extract_trailers(msg_t *msg, msg_pub_t *mo,
+ char *b, isize_t bsiz, int eos, int copy);
+
+/** Calculate length of line ending (0, 1 or 2). @internal */
+#define CRLF_TEST(b) ((b)[0] == '\r' ? ((b)[1] == '\n') + 1 : (b)[0] =='\n')
+
+static inline void
+append_parsed(msg_t *msg, msg_pub_t *mo, msg_href_t const *hr, msg_header_t *h,
+ int always_into_chain);
+
+/**Extract and parse a message from internal buffer.
+ *
+ * @relatesalso msg_s
+ *
+ * This function parses the internal buffer and adds the parsed fragments to
+ * the message object. It marks the successfully parsed data as extracted.
+ *
+ * @param msg message to be parsed
+ *
+ * @retval positive if a complete message was parsed
+ * @retval 0 if message was incomplete
+ * @retval negative if an error occurred
+ */
+int msg_extract(msg_t *msg)
+{
+ msg_pub_t *mo = msg_object(msg);
+ msg_mclass_t const *mc;
+ char *b;
+ ssize_t m;
+ size_t bsiz;
+ int eos;
+
+ if (!msg || !msg->m_buffer->mb_data)
+ return -1;
+
+ assert(mo);
+
+ mc = msg->m_class;
+ mo = msg->m_object;
+ eos = msg->m_buffer->mb_eos;
+
+ if (msg->m_chunk) {
+ int incomplete = extract_incomplete_chunks(msg, eos);
+ if (incomplete < 1 || MSG_IS_COMPLETE(mo))
+ return incomplete;
+ }
+
+ if (mo->msg_flags & MSG_FLG_TRAILERS)
+ msg_set_streaming(msg, 0);
+
+ if (msg->m_buffer->mb_used + msg->m_buffer->mb_commit ==
+ msg->m_buffer->mb_size)
+ /* Why? When? */
+ return 0;
+
+ assert(msg->m_buffer->mb_used + msg->m_buffer->mb_commit <
+ msg->m_buffer->mb_size);
+
+ m = 0;
+
+ b = msg->m_buffer->mb_data + msg->m_buffer->mb_used;
+ bsiz = msg->m_buffer->mb_commit;
+ b[bsiz] = '\0';
+
+ while (msg->m_buffer->mb_commit > 0) {
+ int flags = mo->msg_flags;
+ int copy = MSG_IS_EXTRACT_COPY(flags);
+
+ if (flags & MSG_FLG_COMPLETE)
+ break;
+
+ if (flags & MSG_FLG_TRAILERS)
+ m = extract_trailers(msg, mo, b, bsiz, eos, copy);
+ else if (flags & MSG_FLG_BODY)
+ m = mc->mc_extract_body(msg, mo, b, bsiz, eos);
+ else if (flags & MSG_FLG_HEADERS)
+ m = extract_next(msg, mo, b, bsiz, eos, copy);
+ else
+ m = extract_first(msg, mo, b, bsiz, eos);
+
+ if (m <= 0 || msg->m_chunk)
+ break;
+
+ b += m;
+ bsiz -= m;
+
+ msg_buf_used(msg, (size_t)m);
+ }
+
+ if (eos && bsiz == 0)
+ msg_mark_as_complete(msg, 0);
+
+ if (m < 0 || (mo->msg_flags & MSG_FLG_ERROR)) {
+ msg_mark_as_complete(msg, MSG_FLG_ERROR);
+ return -1;
+ }
+ else if (!MSG_IS_COMPLETE(mo))
+ return 0;
+ else if (!(mo->msg_flags & MSG_FLG_HEADERS)) {
+ msg_mark_as_complete(msg, MSG_FLG_ERROR);
+ return -1;
+ }
+ else
+ return 1;
+}
+
+static
+issize_t extract_first(msg_t *msg, msg_pub_t *mo, char b[], isize_t bsiz, int eos)
+{
+ /* First line */
+ size_t k, l, m, n, xtra;
+ int crlf;
+ msg_header_t *h;
+ msg_href_t const *hr;
+ msg_mclass_t const *mc = msg->m_class;
+
+ for (k = 0; IS_LWS(b[k]); k++) /* Skip whitespace */
+ ;
+ if (!b[k]) return k;
+
+ /* If first token contains no /, this is request, otherwise status line */
+ l = span_token(b + k) + k;
+ if (b[l] != '/')
+ hr = mc->mc_request;
+ else
+ hr = mc->mc_status;
+
+ n = span_non_crlf(b + l) + l;
+ if (!b[n])
+ return eos ? -1 : 0;
+ crlf = CRLF_TEST(b + n);
+
+ for (m = n + crlf; IS_WS(b[m]); m++)
+ ;
+ /* In order to skip possible whitespace after first line, we don't parse
+ first line until first non-ws char from next one has been received */
+ if (!b[m] && !eos)
+ return 0;
+
+ xtra = MSG_IS_EXTRACT_COPY(mo->msg_flags) ? n + 1 - k : 0;
+ if (!(h = msg_header_alloc(msg_home(msg), hr->hr_class, xtra)))
+ return -1;
+
+ if (xtra) {
+ char *bb = memcpy(MSG_HEADER_DATA(h), b, xtra - 1);
+ h->sh_data = b, h->sh_len = n + crlf;
+ b = bb; n = xtra - 1;
+ }
+ else {
+ b = b + k; n = n - k;
+ }
+
+ b[n] = 0;
+
+ if (hr->hr_class->hc_parse(msg_home(msg), h, b, n) < 0)
+ return -1;
+
+ assert(hr->hr_offset);
+
+ append_parsed(msg, mo, hr, h, 1);
+
+ mo->msg_flags |= MSG_FLG_HEADERS;
+
+ return m;
+}
+
+/* Extract header or message body */
+static inline issize_t
+extract_next(msg_t *msg, msg_pub_t *mo, char *b, isize_t bsiz,
+ int eos, int copy)
+{
+ if (IS_CRLF(b[0]))
+ return msg->m_class->mc_extract_body(msg, mo, b, bsiz, eos);
+ else
+ return extract_header(msg, mo, b, bsiz, eos, copy);
+}
+
+/** Extract a header. */
+issize_t msg_extract_header(msg_t *msg, msg_pub_t *mo,
+ char b[], isize_t bsiz, int eos)
+{
+ return extract_header(msg, mo, b, bsiz, eos, 0);
+}
+
+/** Extract a header from buffer @a b.
+ */
+static
+issize_t
+extract_header(msg_t *msg, msg_pub_t *mo, char *b, isize_t bsiz, int eos,
+ int copy_buffer)
+{
+ size_t len, m;
+ size_t name_len = 0, xtra;
+ isize_t n = 0;
+ int crlf = 0, name_len_set = 0;
+ int error = 0;
+ msg_header_t *h;
+ msg_href_t const *hr;
+ msg_mclass_t const *mc = msg->m_class;
+
+ hr = msg_find_hclass(mc, b, &n); /* Get header name */
+ error = n == 0;
+ if (hr == NULL) /* Panic */
+ return -1;
+
+ xtra = span_ws(b + n);
+
+ /* Find next crlf which is not followed by whitespace */
+ do {
+ n += xtra + crlf;
+ if (!eos && bsiz == n)
+ return 0;
+ m = span_non_crlf(b + n);
+ if (!name_len_set && m)
+ name_len = n, name_len_set = 1; /* First non-ws after COLON */
+ n += m;
+ crlf = CRLF_TEST(b + n);
+ xtra = span_ws(b + n + crlf);
+ }
+ while (xtra);
+
+ if (!eos && bsiz == n + crlf)
+ return 0;
+
+ if (hr->hr_class->hc_hash == msg_unknown_hash)
+ name_len = 0, name_len_set = 1;
+
+ if (error) {
+ msg->m_extract_err |= hr->hr_flags;
+ if (hr->hr_class->hc_critical)
+ mo->msg_flags |= MSG_FLG_ERROR;
+ hr = mc->mc_error;
+ copy_buffer = 1;
+ h = error_header_parse(msg, mo, hr);
+ }
+ else {
+ if (!name_len_set)
+ /* Empty header - nothing but name, COLON and LWS */
+ name_len = n;
+ else
+ /* Strip extra whitespace at the end of header */
+ while (n > name_len && IS_LWS(b[n - 1]))
+ n--, crlf++;
+
+ h = header_parse(msg, mo, hr, b + name_len, n - name_len, copy_buffer);
+ }
+
+ if (h == NULL)
+ return -1;
+
+ len = n + crlf;
+
+ /*
+ * If the header contains multiple header fields, set the pointer to the
+ * encodeded data correctly
+ */
+ while (h) {
+ if (copy_buffer)
+ h->sh_data = b, h->sh_len = len;
+ b += len, len = 0;
+ if (h->sh_succ)
+ assert(&h->sh_succ == h->sh_succ->sh_prev);
+ h = h->sh_next;
+ }
+
+ return n + crlf;
+}
+
+static
+msg_header_t *header_parse(msg_t *msg, msg_pub_t *mo,
+ msg_href_t const *hr,
+ char s[], isize_t slen,
+ int copy_buffer)
+{
+ su_home_t *home = msg_home(msg);
+ msg_header_t *h, **hh;
+ msg_hclass_t *hc = hr->hr_class;
+ int n;
+ int add_to_list, clear = 0;
+
+ hh = (msg_header_t **)((char *)mo + hr->hr_offset);
+
+ add_to_list = (hc->hc_kind == msg_kind_list && !copy_buffer && *hh);
+
+ if (add_to_list)
+ h = *hh;
+ else
+ h = msg_header_alloc(home, hc, copy_buffer ? slen + 1 : 0);
+
+ if (!h)
+ return NULL;
+
+ if (copy_buffer)
+ s = memcpy(MSG_HEADER_DATA(h), s, slen);
+
+ s[slen] = '\0';
+
+ if (hc->hc_kind == msg_kind_list && *hh) {
+ n = hc->hc_parse(home, *hh, s, slen);
+ /* Clear if adding new header disturbs existing headers */
+ clear = *hh != h && !copy_buffer;
+ if (clear)
+ msg_fragment_clear((*hh)->sh_common);
+ }
+ else
+ n = hc->hc_parse(home, h, s, slen);
+
+ if (n < 0) {
+ msg->m_extract_err |= hr->hr_flags;
+
+ if (hc->hc_critical)
+ mo->msg_flags |= MSG_FLG_ERROR;
+
+ clear = 0;
+
+ if (!add_to_list) {
+ /* XXX - This should be done by msg_header_free_all() */
+ msg_header_t *h_next;
+ msg_param_t *h_params;
+
+ while (h) {
+ h_next = h->sh_next;
+ if (hc->hc_params) {
+ h_params = *(msg_param_t **)((char *)h + hc->hc_params);
+ if (h_params)
+ su_free(home, h_params);
+ }
+ su_free(home, h);
+ h = h_next;
+ }
+ /* XXX - This should be done by msg_header_free_all() */
+ hr = msg->m_class->mc_error;
+ h = msg_header_alloc(home, hr->hr_class, 0);
+ if (!h)
+ return h;
+
+ h->sh_error->er_name = hc->hc_name;
+ hh = (msg_header_t **)((char *)mo + hr->hr_offset);
+ }
+ }
+
+ if (clear)
+ for (hh = &(*hh)->sh_next; *hh; *hh = (*hh)->sh_next)
+ msg_chain_remove(msg, *hh);
+ else if (h != *hh)
+ append_parsed(msg, mo, hr, h, 0);
+
+ return h;
+}
+
+static
+msg_header_t *error_header_parse(msg_t *msg, msg_pub_t *mo,
+ msg_href_t const *hr)
+{
+ msg_header_t *h;
+
+ h = msg_header_alloc(msg_home(msg), hr->hr_class, 0);
+ if (h)
+ append_parsed(msg, mo, hr, h, 0);
+
+ return h;
+}
+
+/** Complete this header field and parse next header field.
+ *
+ * This function completes parsing a multi-field header like @Accept,
+ * @Contact, @Via or @Warning. It scans for the next header field and
+ * if one is found, it calls the parsing function recursively.
+ *
+ * @param home memory home used ot allocate
+ * new header structures and parameter lists
+ * @param prev pointer to header structure already parsed
+ * @param s header content to parse; should point to the area after
+ * current header field (either end of line or to a comma
+ * separating header fields)
+ * @param slen ignored
+ *
+ * @since New in @VERSION_1_12_4.
+ *
+ * @retval >= 0 when successful
+ * @retval -1 upon an error
+ */
+issize_t msg_parse_next_field(su_home_t *home, msg_header_t *prev,
+ char *s, isize_t slen)
+{
+ msg_hclass_t *hc = prev->sh_class;
+ msg_header_t *h;
+ char *end = s + slen;
+
+ if (*s && *s != ',')
+ return -1;
+
+ if (msg_header_update_params(prev->sh_common, 0) < 0)
+ return -1;
+
+ while (*s == ',') /* Skip comma and following whitespace */
+ *s = '\0', s += span_lws(s + 1) + 1;
+
+ if (*s == 0)
+ return 0;
+
+ h = msg_header_alloc(home, hc, 0);
+ if (!h)
+ return -1;
+
+ prev->sh_succ = h, h->sh_prev = &prev->sh_succ;
+ prev->sh_next = h;
+
+ return hc->hc_parse(home, h, s, end - s);
+}
+
+/** Decode a message header. */
+msg_header_t *msg_header_d(su_home_t *home, msg_t const *msg, char const *b)
+{
+ msg_mclass_t const *mc = msg->m_class;
+ msg_href_t const *hr = mc->mc_unknown;
+ isize_t n; /* Length of header contents */
+ isize_t name_len, xtra;
+ msg_header_t *h;
+ char *bb;
+
+ n = strlen(b);
+ hr = msg_find_hclass(mc, b, &name_len);
+ if (hr == NULL)
+ return NULL;
+
+ /* Strip extra whitespace at the end and begin of header */
+ while (n > name_len && IS_LWS(b[n - 1]))
+ n--;
+ if (name_len < n && IS_LWS(b[name_len]))
+ name_len++;
+
+ xtra = (n - name_len);
+ if (!(h = msg_header_alloc(home, hr->hr_class, xtra + 1)))
+ return NULL;
+
+ bb = memcpy(MSG_HEADER_DATA(h), b + name_len, xtra), bb[xtra] = 0;
+
+ if (hr->hr_class->hc_parse(home, h, bb, xtra) >= 0)
+ return h;
+
+ hr = mc->mc_unknown;
+ su_free(home, h);
+ if (!(h = msg_header_alloc(home, hr->hr_class, n + 1)))
+ return NULL;
+ bb = memcpy(MSG_HEADER_DATA(h), b, n), bb[n] = 0;
+ if (hr->hr_class->hc_parse(home, h, bb, n) < 0)
+ su_free(home, h), h = NULL;
+
+ return h;
+}
+
+/** Extract a separator line */
+issize_t msg_extract_separator(msg_t *msg, msg_pub_t *mo,
+ char b[], isize_t bsiz, int eos)
+{
+ msg_mclass_t const *mc = msg->m_class;
+ msg_href_t const *hr = mc->mc_separator;
+ int l = CRLF_TEST(b); /* Separator length */
+ msg_header_t *h;
+
+ /* Even if a single CR *may* be a payload separator we cannot be sure */
+ if (l == 0 || (!eos && bsiz == 1 && b[0] == '\r'))
+ return 0;
+
+ /* Separator */
+ if (!(h = msg_header_alloc(msg_home(msg), hr->hr_class, 0)))
+ return -1;
+ if (hr->hr_class->hc_parse(msg_home(msg), h, b, l) < 0)
+ return -1;
+
+ h->sh_data = b, h->sh_len = l;
+
+ append_parsed(msg, mo, hr, h, 0);
+
+ return l;
+}
+
+static inline msg_header_t **msg_chain_tail(msg_t const *msg);
+
+/** Extract a message body of @a body_len bytes.
+ */
+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)
+{
+ msg_mclass_t const *mc = msg->m_class;
+ msg_href_t const *hr = mc->mc_payload;
+ msg_header_t *h, *h0;
+ msg_payload_t *pl;
+ char *x;
+
+ if (msg == NULL || mo == NULL)
+ return -1;
+
+ assert(!msg->m_chunk);
+
+ if (return_payload == NULL)
+ return_payload = &h0;
+ *return_payload = NULL;
+
+ assert(body_len > 0);
+
+ /* Allocate header structure for payload */
+ if (!(h = msg_header_alloc(msg_home(msg), hr->hr_class, 0)))
+ return -1;
+
+ append_parsed(msg, mo, hr, h, 0);
+ pl = h->sh_payload;
+ *return_payload = h;
+
+ if (bsiz >= body_len) {
+ /* We have a complete body. */
+ h->sh_data = b, h->sh_len = body_len;
+ pl->pl_data = b, pl->pl_len = body_len;
+ return body_len;
+ }
+
+ if (msg->m_maxsize != 0 && body_len > msg->m_maxsize) {
+ mo->msg_flags |= MSG_FLG_TOOLARGE;
+ return -1;
+ }
+
+ assert(msg->m_buffer->mb_commit == bsiz);
+ assert(b == msg->m_buffer->mb_data + msg->m_buffer->mb_used);
+
+ if (msg->m_buffer->mb_used + body_len <= msg->m_buffer->mb_size) {
+ /* We don't have a complete body, but we have big enough buffer for it. */
+ msg->m_chunk = pl;
+
+ h->sh_data = b, h->sh_len = bsiz;
+ pl->pl_data = b, pl->pl_len = body_len;
+
+ if (msg->m_buffer->mb_used + body_len < msg->m_buffer->mb_size)
+ /* NUL-terminate payload */
+ b[body_len++] = '\0';
+
+ /* Mark the rest of the body as used in the buffer */
+ /* msg_buf_commit(msg, body_len - bsiz, eos); */
+ msg_buf_used(msg, body_len);
+
+ return bsiz;
+ }
+
+ /* We don't have big enough buffer for body. */
+
+ if (msg_get_flags(msg, MSG_FLG_CHUNKING)) {
+ /* Application supports chunking, use multiple chunks for payload */
+ usize_t current, rest;
+
+ current = msg->m_buffer->mb_size - msg->m_buffer->mb_used;
+ rest = body_len - current;
+
+ /* Use all the data from our current buffer */
+ msg_buf_used(msg, current);
+
+ msg->m_chunk = pl;
+
+ h->sh_data = b, h->sh_len = bsiz;
+ pl->pl_data = b, pl->pl_len = current;
+
+ for (;current < body_len; current += rest) {
+ msg_header_t *h0 = h;
+
+ /* Allocate header structure for next payload chunk */
+ if (!(h = msg_header_alloc(msg_home(msg), hr->hr_class, 0)))
+ return -1;
+ if (msg->m_chain)
+ msg_insert_here_in_chain(msg, msg_chain_tail(msg), h);
+ h0->sh_next = h;
+
+ rest = body_len - current;
+
+ if (!msg->m_streaming) {
+ x = msg_buf_exact(msg, rest);
+ if (x == NULL) {
+ mo->msg_flags |= MSG_FLG_TOOLARGE;
+ return -1;
+ }
+ }
+ else {
+ x = NULL;
+ }
+
+ if (x) {
+ /* Mark the just-allocated buffer as used */
+ rest = msg->m_buffer->mb_size - msg->m_buffer->mb_used;
+ msg_buf_used(msg, rest);
+ }
+
+ pl = h->sh_payload;
+
+ h->sh_len = 0, pl->pl_len = rest;
+ h->sh_data = x, pl->pl_data = x;
+ }
+ }
+ else {
+ /* No chunking.
+ *
+ * Allocate a single buffer that contains enough free space for body.
+ *
+ * msg_buf_exact() also copies committed but un-used data
+ * from the old buffer (b[0] .. b[bsiz])
+ * to the new buffer (x[-bsiz-1]..b[-1])
+ */
+ if (!(x = msg_buf_exact(msg, body_len - bsiz + 1))) {
+ if (mo->msg_flags & MSG_FLG_TOOLARGE) {
+ msg_mark_as_complete(msg, MSG_FLG_TRUNC);
+ return bsiz;
+ }
+ return -1;
+ }
+
+ /* Fake un-received data as already received and then use it */
+ /* msg_buf_commit(msg, body_len - bsiz + 1, eos); */
+ msg_buf_used(msg, body_len + 1);
+
+ msg->m_chunk = h->sh_payload;
+
+ x -= bsiz; /* Start of un-used data */
+ x[body_len] = '\0';
+
+ h->sh_data = x, h->sh_len = bsiz;
+ pl->pl_data = x, pl->pl_len = body_len;
+
+ assert(MSG_CHUNK_AVAIL(pl) == body_len - bsiz);
+ }
+
+ return bsiz;
+}
+
+/** Extract incomplete chunks.
+ */
+static inline
+int extract_incomplete_chunks(msg_t *msg, int eos)
+{
+ msg_payload_t *chunk;
+
+ for (chunk = msg->m_chunk; chunk; chunk = MSG_CHUNK_NEXT(chunk)) {
+ if (MSG_CHUNK_AVAIL(chunk) != 0)
+ break;
+
+ /* The incomplete payload fragment is now complete */
+ assert(MSG_CHUNK_BUFFER(chunk) == chunk->pl_data + chunk->pl_len);
+
+ msg->m_size += chunk->pl_common->h_len;
+ }
+
+ msg->m_chunk = chunk;
+
+ if (chunk) {
+ if (eos) {
+ msg_mark_as_complete(msg, MSG_FLG_TRUNC);
+ return 1;
+ }
+ }
+ else {
+ if (msg_get_flags(msg, MSG_FLG_FRAGS))
+ msg_mark_as_complete(msg, 0);
+ }
+
+ /**@retval 1 when message is complete
+ * @retval 0 when message is incomplete
+ * @retval -1 upon an error
+ */
+ return chunk == NULL;
+}
+
+/* Extract trailers */
+static inline issize_t
+extract_trailers(msg_t *msg, msg_pub_t *mo,
+ char *b, isize_t bsiz, int eos, int copy)
+{
+ if (IS_CRLF(b[0])) {
+ msg_mark_as_complete(msg, MSG_FLG_COMPLETE);
+ return CRLF_TEST(b);
+ }
+ else
+ return extract_header(msg, mo, b, bsiz, eos, copy);
+}
+
+/* ====================================================================== */
+/* Preparing (printing/encoding) a message structure for sending */
+
+/* Internal prototypes */
+static inline size_t
+msg_header_name_e(char b[], size_t bsiz, msg_header_t const *h, int flags);
+static size_t msg_header_prepare(msg_mclass_t const *, int flags,
+ msg_header_t *h, msg_header_t **return_next,
+ char *b, size_t bsiz);
+
+/**Encode all message fragments.
+ *
+ * @relatesalso msg_s
+ *
+ * The function msg_prepare() prepares a message for sending. It encodes all
+ * serialized fragments in the message. You have to call msg_serialize()
+ * before calling msg_headers_prepare() in order to make sure that all the
+ * heades and other message fragments are included in the chain.
+ *
+ * After encoding, the msg_common_s::h_data field will point to the encoding
+ * result of size msg_common_s::h_len bytes in in each fragment.
+ *
+ * When multiple header fields are represented as a comma-separated list
+ * within a single header line, the first fragment in the header will
+ * contain all the text belonging to the header. The rest of the header
+ * fields will have zero-length encoding with msg_common_s::h_data that
+ * points to the end of the line.
+ *
+ * @return Total size of the encoded message in bytes, or -1 upon an error.
+ *
+ * @sa msg_extract(), msg_serialize()
+ */
+int msg_prepare(msg_t *msg)
+{
+ int total;
+
+ assert(msg->m_chain);
+ assert(msg_chain_errors(msg->m_chain) == 0);
+
+ /* Get rid of data that was received but not yet used (parsed) */
+ msg_clear_committed(msg);
+
+ total = msg_headers_prepare(msg, msg->m_chain, msg_object(msg)->msg_flags);
+
+ if (total != -1) {
+ msg->m_size = total;
+ msg->m_prepared = 1;
+ }
+
+ return total;
+}
+
+/** Clear 'prepared' flag. */
+void msg_unprepare(msg_t *msg)
+{
+ if (msg) msg->m_prepared = 0;
+}
+
+/** Return true if message is prepared. */
+int msg_is_prepared(msg_t const *msg)
+{
+ return msg && msg->m_prepared;
+}
+
+/**Encode headers in chain.
+ *
+ * The function msg_headers_prepare() encodes all the headers in the header
+ * chain. You have to call msg_serialize() before calling
+ * msg_headers_prepare() in order to make sure that all the heades and other
+ * message fragments are included in the chain.
+ *
+ * @return
+ * The size of all the headers in chain, or -1 upon an error.
+ */
+issize_t msg_headers_prepare(msg_t *msg, msg_header_t *headers, int flags)
+{
+ msg_mclass_t const *mc = msg->m_class;
+ msg_header_t *h, *next;
+ ssize_t n = 0;
+ size_t bsiz = 0, used = 0;
+ char *b;
+ size_t total = 0;
+
+ b = msg_buf_alloc(msg, msg_min_size);
+ bsiz = msg_buf_size(msg);
+
+ if (!b)
+ return -1;
+
+ for (h = headers; h;) {
+
+ if (h->sh_data) {
+ total += h->sh_len;
+ h = h->sh_succ;
+ continue;
+ }
+
+ for (next = h->sh_succ; next; next = next->sh_succ)
+ if (next->sh_class != h->sh_class || next->sh_data)
+ break;
+
+ n = msg_header_prepare(mc, flags, h, &next, b, bsiz - used);
+
+ if (n == (ssize_t)-1) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (used + n >= bsiz) {
+ /* Allocate next buffer */
+ if ((b = msg_buf_alloc(msg, n + 1)) == NULL)
+ return -1;
+ bsiz = msg_buf_size(msg); used = 0;
+ continue;
+ }
+
+ h->sh_data = b, h->sh_len = n;
+
+ for (h = h->sh_succ; h != next; h = h->sh_succ)
+ h->sh_data = b + n, h->sh_len = 0;
+
+ msg_buf_used(msg, n);
+
+ total += n;
+ used += n;
+ b += n;
+ }
+
+ return total;
+}
+
+/** Encode a header or a list of headers */
+static
+size_t msg_header_prepare(msg_mclass_t const *mc, int flags,
+ msg_header_t *h, msg_header_t **return_next,
+ char *b, size_t bsiz)
+{
+ msg_header_t *h0, *next;
+ msg_hclass_t *hc;
+ char const *s;
+ size_t n; ssize_t m;
+ int compact, one_line_list, comma_list;
+
+ assert(h); assert(h->sh_class);
+
+ hc = h->sh_class;
+ compact = MSG_IS_COMPACT(flags);
+ one_line_list = hc->hc_kind == msg_kind_apndlist;
+ comma_list = compact || one_line_list || MSG_IS_COMMA_LISTS(flags);
+
+ for (h0 = h, n = 0; ; h = next) {
+ next = h->sh_succ;
+
+ if (h == h0 && hc->hc_name && hc->hc_name[0])
+ n += msg_header_name_e(b + n, bsiz >= n ? bsiz - n : 0, h, flags);
+
+ if ((m = hc->hc_print(b + n, bsiz >= n ? bsiz - n : 0, h, flags)) == -1) {
+ if (bsiz >= n + 64)
+ m = 2 * (bsiz - n);
+ else
+ m = 128;
+ }
+
+ n += m;
+
+ if (hc->hc_name) {
+ if (!comma_list || !next || next == *return_next)
+ s = CRLF, m = 2;
+ /* Else encode continuation */
+ else if (compact)
+ s = ",", m = 1;
+ else if (one_line_list)
+ s = ", ", m = 2;
+ else
+ s = "," CRLF "\t", m = 4;
+
+ if (bsiz > n + m)
+ memcpy(b + n, s, m);
+ n += m;
+ }
+
+ if (!comma_list || !next || next == *return_next)
+ break;
+ }
+
+ *return_next = next;
+
+ return n;
+}
+
+/** Encode a header.
+ *
+ * The function msg_header_e() encodes a header field in the buffer @a
+ * b[]. The encoding includes its name and trailing CRLF. The function
+ * returns the length of the encoding in bytes, excluding the final @c NUL.
+ * The buffer @a b must be large enough for whole encoding, including the
+ * final @c NUL.
+ *
+ * The @a flags parameter define how the encoding is done. If the flags
+ * specify @c MSG_DO_COMPACT, the encoding is compact (short form with
+ * minimal whitespace).
+ */
+issize_t msg_header_e(char b[], isize_t bsiz, msg_header_t const *h, int flags)
+{
+ size_t n, m;
+
+ assert(h); assert(h->sh_class);
+
+ if (h == NULL || h->sh_class == NULL)
+ return -1;
+
+ n = msg_header_name_e(b, bsiz, h, flags);
+ m = h->sh_class->hc_print(b + n, bsiz > n ? bsiz - n : 0, h, flags);
+ if (h->sh_class->hc_name) {
+ /* Ordinary header */
+ if (bsiz > n + m + strlen(CRLF))
+ strcpy(b + n + m, CRLF);
+ return n + m + strlen(CRLF);
+ }
+ else
+ return m;
+}
+
+/** Encode header name */
+static inline
+size_t
+msg_header_name_e(char b[], size_t bsiz, msg_header_t const *h, int flags)
+{
+ int compact = MSG_IS_COMPACT(flags);
+ char const *name;
+ size_t n, n2;
+
+ if (compact && h->sh_class->hc_short[0])
+ name = h->sh_class->hc_short, n = 1;
+ else
+ name = h->sh_class->hc_name, n = h->sh_class->hc_len;
+
+ if (!name || !name[0])
+ return 0;
+
+ n2 = compact ? n + 1 : n + 2;
+
+ if (n2 < bsiz) {
+ memcpy(b, name, n);
+ b[n++] = ':';
+ if (!compact)
+ b[n++] = ' ';
+ b[n++] = '\0';
+ }
+
+ return n2;
+}
+
+/** Convert a message to a string.
+ *
+ * A message is encoded and the encoding result is returned as a string.
+ * Because the message may contain binary payload (or NUL in headers), the
+ * message length is returned separately in @a *return_len, too.
+ *
+ * Note that the message is serialized as a side effect.
+ *
+ * @param home memory home used to allocate the string
+ * @param msg message to encode
+ * @param pub message object to encode (may be NULL)
+ * @param flags flags used when encoding
+ * @param return_len return-value parameter for encoded message length
+ *
+ * @return Encoding result as a C string.
+ *
+ * @since New in @VERSION_1_12_4
+ *
+ * @sa msg_make(), msg_prepare(), msg_serialize().
+ */
+char *msg_as_string(su_home_t *home, msg_t *msg, msg_pub_t *pub, int flags,
+ size_t *return_len)
+{
+ msg_mclass_t const *mc = msg->m_class;
+ msg_header_t *h, *next;
+ ssize_t n = 0;
+ size_t bsiz = 0, used = 0;
+ char *b, *b2;
+
+ if (pub == NULL)
+ pub = msg->m_object;
+
+ if (msg_serialize(msg, pub) < 0)
+ return NULL;
+
+ if (return_len == NULL)
+ return_len = &used;
+
+ b = su_alloc(home, bsiz = msg_min_size);
+
+ if (!b)
+ return NULL;
+
+ if (pub == msg->m_object)
+ h = msg->m_chain;
+ else
+ h = pub->msg_common->h_succ;
+
+ while (h) {
+ for (next = h->sh_succ; next; next = next->sh_succ)
+ if (next->sh_class != h->sh_class)
+ break;
+
+ n = msg_header_prepare(mc, flags, h, &next, b + used, bsiz - used);
+
+ if (n == -1) {
+ errno = EINVAL;
+ su_free(home, b);
+ return NULL;
+ }
+
+ if (bsiz > used + n) {
+ used += n;
+ h = next;
+ }
+ else {
+ /* Realloc */
+ if (h->sh_succ)
+ bsiz = (used + n + msg_min_size) / msg_min_size * msg_min_size;
+ else
+ bsiz = used + n + 1;
+
+ b2 = su_realloc(home, b, bsiz);
+
+ if (b2 == NULL || bsiz < msg_min_size) {
+ errno = ENOMEM;
+ su_free(home, b);
+ return NULL;
+ }
+
+ continue;
+ }
+ }
+
+ *return_len = used;
+
+ b[used] = '\0'; /* NUL terminate */
+
+ return su_realloc(home, b, used + 1);
+}
+
+/* ====================================================================== */
+/* Handling header chain */
+
+static inline void serialize_first(msg_t *msg, msg_header_t *h);
+static msg_header_t **serialize_one(msg_t *msg, msg_header_t *h,
+ msg_header_t **prev);
+
+/** Return head of the fragment chain */
+msg_header_t **msg_chain_head(msg_t const *msg)
+{
+ return msg ? (msg_header_t **)&msg->m_chain : NULL;
+}
+
+static inline msg_header_t **_msg_chain_head(msg_t const *msg)
+{
+ return msg ? (msg_header_t **)&msg->m_chain : NULL;
+}
+
+/** Return tail of the fragment chain */
+static inline msg_header_t **msg_chain_tail(msg_t const *msg)
+{
+ return msg ? msg->m_tail : NULL;
+}
+
+/** Serialize headers into the fragment chain.
+ *
+ * The msg_serialize() collects the headers and other message components in
+ * the fragment chain. It should be called before msg_prepare().
+ *
+ * @relatesalso msg_s
+ *
+ * @param msg pointer to message object
+ * @param pub public message structure
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error
+ */
+int msg_serialize(msg_t *msg, msg_pub_t *pub)
+{
+ msg_header_t *h, **hh, **end;
+ msg_header_t **separator;
+ msg_header_t **payload;
+ msg_header_t **multipart;
+ msg_mclass_t const *mc = msg->m_class;
+ msg_header_t **tail, ***ptail;
+
+ if (!msg)
+ return errno = EINVAL, -1;
+ if (pub == NULL)
+ pub = msg->m_object;
+
+ /* There must be a first line */
+ if (pub->msg_request)
+ h = pub->msg_request;
+ else if (pub->msg_status)
+ h = pub->msg_status;
+ else
+ return errno = EINVAL, -1;
+
+ serialize_first(msg, h);
+
+ separator = (msg_header_t **)((char *)pub + mc->mc_separator->hr_offset);
+ payload = (msg_header_t **)((char *)pub + mc->mc_payload->hr_offset);
+ if (mc->mc_multipart->hr_class)
+ multipart = (msg_header_t **)((char *)pub + mc->mc_multipart->hr_offset);
+ else
+ multipart = NULL;
+
+ /* Find place to insert headers: before separator, payload and multipart */
+ if (*separator && !msg_header_is_removed(*separator))
+ ptail = &(*separator)->sh_prev;
+ else if (*payload && !msg_header_is_removed(*payload))
+ ptail = &(*payload)->sh_prev;
+ else if (multipart && *multipart && !msg_header_is_removed(*multipart))
+ ptail = &(*multipart)->sh_prev;
+ else
+ ptail = &msg->m_tail;
+
+ tail = *ptail;
+
+ end = (msg_header_t **)((char *)pub + pub->msg_size);
+
+ for (hh = pub->msg_headers; hh < end; hh++) {
+ if (!*hh)
+ continue;
+ if (hh == separator || hh == payload || hh == multipart)
+ continue;
+ tail = serialize_one(msg, *hh, tail);
+ }
+
+ /* Serialize separator, payload and multipart last */
+ if (*separator)
+ tail = serialize_one(msg, *separator, tail);
+
+ *ptail = tail;
+
+ /* Payload comes after separator but before multipart */
+ if (ptail != &(*separator)->sh_prev)
+ ;
+ else if (*payload && !msg_header_is_removed(*payload))
+ ptail = &(*payload)->sh_prev;
+ else if (multipart && *multipart && !msg_header_is_removed(*multipart))
+ ptail = &(*multipart)->sh_prev;
+ else
+ ptail = &msg->m_tail;
+
+ tail = *ptail;
+
+ if (*payload) {
+ tail = serialize_one(msg, *payload, tail);
+ *ptail = tail;
+ }
+
+ if (multipart && *multipart) {
+ msg_header_t *last;
+
+ last = msg_multipart_serialize(tail, (msg_multipart_t *)*multipart);
+
+ msg->m_tail = &last->sh_succ;
+ }
+
+ assert(msg->m_chain && msg_chain_errors(msg->m_chain) == 0);
+
+ return 0;
+}
+
+static inline
+void serialize_first(msg_t *msg, msg_header_t *h)
+{
+ if (msg_header_is_removed(h)) {
+ if ((h->sh_succ = msg->m_chain))
+ h->sh_succ->sh_prev = &h->sh_succ;
+ else
+ msg->m_tail = &h->sh_succ;
+ *(h->sh_prev = &msg->m_chain) = h;
+ }
+}
+
+static
+msg_header_t **serialize_one(msg_t *msg, msg_header_t *h, msg_header_t **prev)
+{
+ msg_header_t *last;
+ msg_header_t *succ = *prev;
+
+ if (msg_header_is_removed(h)) {
+ /* Add the first header in the list to the chain */
+ *prev = h; h->sh_prev = prev;
+ for (last = h; last->sh_succ; last = last->sh_succ) {
+ /* Ensure that chain is connected */
+ assert(last->sh_next == last->sh_succ);
+ assert(last->sh_succ->sh_prev = &last->sh_succ);
+ }
+ prev = &last->sh_succ;
+ }
+
+ if ((h = h->sh_next)) {
+ assert(!msg_is_single(h));
+
+ if (msg_is_single(h)) {
+ for (; h; h = h->sh_next)
+ if (!msg_header_is_removed(h))
+ msg_chain_remove(msg, h);
+ }
+ /* Add the rest of the headers in the list to the chain */
+ else for (; h; h = h->sh_next) {
+ if (msg_header_is_removed(h)) {
+ *prev = h; h->sh_prev = prev;
+ for (;h->sh_succ; h = h->sh_succ)
+ assert(h->sh_succ == h->sh_next);
+ prev = &h->sh_succ;
+ }
+ }
+ }
+
+ *prev = succ;
+
+ return prev;
+}
+
+/**Fill an I/O vector with message contents.
+ *
+ * @relatesalso msg_s
+ *
+ * Calculate number of entries in the I/O vector
+ * required to send a message @a msg. It also fills in the I/O vector array,
+ * if it is provided by the caller and it is large enough.
+ *
+ * @param msg pointer to message object
+ * @param vec I/O vector (may be NULL)
+ * @param veclen length of I/O vector in @a vec
+ *
+ * @return
+ * Number of entries of I/O
+ * vector required by @a msg, or 0 upon an error.
+ *
+ * @note The caller should check that the I/O vector @a vec has enough
+ * entries. If the @a vec is too short, it should allocate big enough
+ * vector and re-invoke msg_iovec().
+ *
+ * @sa msg_recv_iovec(), su_vsend()
+ */
+isize_t msg_iovec(msg_t *msg, msg_iovec_t vec[], isize_t veclen)
+{
+ size_t len = 0, n = 0;
+ char const *p = NULL;
+ msg_header_t *h;
+
+ size_t total = 0;
+
+ if (veclen <= 0)
+ veclen = 0;
+
+ for (h = msg->m_chain; h; h = h->sh_succ) {
+ if (h->sh_data != p) {
+ p = h->sh_data; len = h->sh_len;
+
+ if (p == NULL)
+ return 0;
+
+ if (vec && n != veclen)
+ /* new iovec entry */
+ vec[n].mv_base = (void *)p, vec[n].mv_len = (su_ioveclen_t)len;
+ else
+ vec = NULL;
+
+ p += len; n++;
+ }
+ else {
+ /* extend old entry */
+ len = h->sh_len;
+ if (vec)
+ vec[n-1].mv_len += (su_ioveclen_t)len;
+ p += len;
+ }
+
+ total += len;
+ }
+
+ msg->m_size = total;
+
+ return n;
+}
+
+/** Insert a header to existing header chain.
+ *
+ * Headers are either inserted just before the payload, or after the first
+ * line, depending on their type.
+ *
+ * @param[in] msg message object
+ * @param[in,out] pub public message structure
+ * @param prepend if true, add before same type of headers (instead after them)
+ * @param head head of chain
+ * @param h header to insert
+ *
+ */
+static
+void msg_insert_chain(msg_t *msg,
+ msg_pub_t *pub,
+ int prepend,
+ msg_header_t **head,
+ msg_header_t *h)
+{
+ msg_mclass_t const *mc = msg->m_class;
+ msg_header_t **hh;
+ msg_header_t **separator;
+ msg_header_t **payload;
+
+ assert(msg && pub && head && h);
+
+ separator = (msg_header_t **)((char *)pub + mc->mc_separator->hr_offset);
+ payload = (msg_header_t **)((char *)pub + mc->mc_payload->hr_offset);
+
+ if (msg_is_request(h)) {
+ if (pub->msg_status)
+ pub->msg_status = NULL;
+ hh = head;
+ }
+ else if (msg_is_status(h)) {
+ if (pub->msg_request)
+ pub->msg_request = NULL;
+ hh = head;
+ }
+ else if (msg_is_payload(h)) {
+ /* Append */
+ hh = msg_chain_tail(msg);
+ }
+ else if (prepend) {
+ if (!msg_is_request(*head) && !msg_is_status(*head))
+ hh = head;
+ else
+ hh = &((*head)->sh_succ);
+ }
+ /* Append headers before separator or payload */
+ else if (*separator && (*separator)->sh_prev)
+ hh = (*separator)->sh_prev;
+ else if (*payload && (*payload)->sh_prev)
+ hh = (*payload)->sh_prev;
+ else
+ hh = msg_chain_tail(msg);
+
+ msg_insert_here_in_chain(msg, hh, h);
+}
+
+/** Insert one or more message header to the chain.
+ *
+ * The function msg_insert_here_in_chain() appends message header to the
+ * chain of headers after the given header.
+ *
+ * @param msg message
+ * @param prev pointer to h_succ of previous fragment in the list
+ * @param h header to be inserted.
+ *
+ * @return The pointer to the last header inserted.
+ */
+static
+void msg_insert_here_in_chain(msg_t *msg,
+ msg_header_t **prev,
+ msg_header_t *h)
+{
+ if (h) {
+ msg_header_t *last, *next;
+ assert(h->sh_prev == NULL);
+ assert(prev);
+ assert(!msg_chain_errors(h));
+
+ for (last = h; last->sh_succ; last = last->sh_succ)
+ ;
+
+ last->sh_succ = next = *prev;
+ *prev = h;
+ h->sh_prev = prev;
+ if (next)
+ next->sh_prev = &last->sh_succ;
+ else
+ msg->m_tail = &last->sh_succ;
+
+ assert(msg->m_chain && msg_chain_errors(msg->m_chain) == 0);
+ }
+}
+
+/**
+ * Remove a message from header chain.
+ *
+ * The function @c msg_chain_remove() removes a message header from the header
+ * chain.
+ *
+ * @param msg pointer to the message
+ * @param h pointer to the header in the list to be removed
+ *
+ * @return The pointer to the header just removed.
+ */
+static inline
+msg_header_t *msg_chain_remove(msg_t *msg, msg_header_t *h)
+{
+ if (h) {
+ if (h->sh_prev) {
+ assert(*h->sh_prev == h);
+ assert(h->sh_succ == NULL || h->sh_succ->sh_prev == &h->sh_succ);
+
+ *h->sh_prev = h->sh_succ;
+ }
+
+ if (h->sh_succ)
+ h->sh_succ->sh_prev = h->sh_prev;
+ else if (msg && h->sh_prev)
+ msg->m_tail = h->sh_prev;
+
+ h->sh_succ = NULL; h->sh_prev = NULL;
+
+ if (msg)
+ assert(msg_chain_errors(msg->m_chain) == 0);
+ }
+ return h;
+}
+
+#ifndef NDEBUG
+/**Check if header chain contains any loops.
+ *
+ * @return
+ * Return 0 if no loop, -1 otherwise.
+ */
+static
+int msg_chain_loop(msg_header_t const *h)
+{
+ msg_header_t const *h2;
+
+ if (!h) return 0;
+
+ for (h2 = h->sh_succ; h && h2 && h2->sh_succ; h = h->sh_succ) {
+ if (h == h2 || h == h2->sh_succ)
+ return 1;
+
+ h2 = h2->sh_succ->sh_succ;
+
+ if (h == h2)
+ return 1;
+ }
+
+ return 0;
+}
+
+/** Check header chain consistency.
+ *
+ * @return
+ * Return 0 if consistent, number of errors otherwise.
+ */
+static
+int msg_chain_errors(msg_header_t const *h)
+{
+ if (msg_chain_loop(h))
+ return -1;
+
+ for (; h; h = h->sh_succ) {
+ if (h->sh_succ && h->sh_succ->sh_prev != &h->sh_succ)
+ return -1;
+ if (h->sh_prev && h != (*h->sh_prev))
+ return -1;
+ }
+
+ return 0;
+}
+#endif
+
+/* ====================================================================== */
+/* Handling message structure - allocating, adding and removing headers */
+
+/** Allocate a header structure
+ *
+ * The msg_header_alloc() function allocates a generic MO header structure
+ * and returns a pointer to it.
+ *
+ * @param home memory home
+ * @param hc header class
+ * @param extra amount of extra memory to be allocated after header structure
+ *
+ * @return
+ * A pointer to the newly created header object, or @c NULL upon an error.
+ */
+msg_header_t *msg_header_alloc(su_home_t *home,
+ msg_hclass_t *hc,
+ isize_t extra)
+{
+ isize_t size = hc->hc_size;
+ msg_header_t *h = su_alloc(home, size + extra);
+
+ if (h) {
+ memset(h, 0, size);
+ h->sh_class = hc;
+ }
+
+ return h;
+}
+
+/**Add a (list of) header(s) to the header structure and fragment chain.
+ *
+ * The function @c msg_header_add() adds a header or list of headers into
+ * the given place within the message structure. It also inserts the headers
+ * into the the message fragment chain, if it exists.
+ *
+ * If the header is a prepend header, the new header is inserted before
+ * existing headers of the same class. If the header is an append header,
+ * the new header is inserted after existing headers of the same class. If
+ * the header is a singleton, existing headers of the same class are
+ * removed. If the header is a list header, the values in the new header are
+ * added to the existing list.
+ *
+ * @param msg message owning the fragment chain
+ * @param pub public message structure
+ * @param hh place in message structure to which header is added
+ * @param h list of header(s) to be added
+ */
+int msg_header_add(msg_t *msg,
+ msg_pub_t *pub,
+ msg_header_t **hh,
+ msg_header_t *h)
+{
+ msg_header_t **head, *old = NULL, *end;
+
+ if (msg == NULL || h == NULL || h == MSG_HEADER_NONE || hh == NULL)
+ return -1;
+ if (pub == NULL)
+ pub = msg->m_object;
+
+ head = _msg_chain_head(msg);
+
+ if (*head) {
+ msg_header_t *sh, **prev;
+
+ for (sh = h, prev = NULL; sh; sh = sh->sh_next) {
+ sh->sh_succ = sh->sh_next;
+ sh->sh_prev = prev;
+ prev = &sh->sh_succ;
+ }
+ }
+
+ switch (h->sh_class->hc_kind) {
+ case msg_kind_single:
+ case msg_kind_list:
+ old = (*hh);
+ break;
+ case msg_kind_append:
+ case msg_kind_apndlist:
+ while (*hh)
+ hh = &(*hh)->sh_next;
+ break;
+ case msg_kind_prepend:
+ for (end = h; end->sh_next; end = end->sh_next)
+ ;
+ end->sh_next = *hh;
+ }
+
+ if (*head) {
+ /* Insert into existing fragment chain */
+ msg_insert_chain(msg, pub, msg_is_prepend(h), head, h);
+
+ /* Remove replaced fragment */
+ if (old)
+ msg_chain_remove(msg, old);
+ }
+
+ /* Insert into header list */
+ *hh = h;
+
+ return 0;
+}
+
+/**Prepend a (list of) header(s) to the header structure and fragment chain.
+ *
+ * The function @c msg_header_prepend() adds a header or list of headers into
+ * the given place within the message structure. It also inserts the headers
+ * into the the message fragment chain, if it exists.
+ *
+ * Unlike msg_header_add(), msg_header_prepend() always inserts header @a h
+ * before other headers of the same class. If the header is a singleton,
+ * existing headers of the same class are removed. If the header is a list
+ * header, the values in the new header are prepended to the existing list.
+ *
+ * @param msg message owning the fragment chain
+ * @param pub public message structure
+ * @param hh place in message structure to which header is added
+ * @param h list of header(s) to be added
+ */
+int msg_header_prepend(msg_t *msg,
+ msg_pub_t *pub,
+ msg_header_t **hh,
+ msg_header_t *h)
+{
+ msg_header_t **head, *old = NULL, *end;
+
+ assert(msg && pub);
+
+ if (msg == NULL || h == NULL || h == MSG_HEADER_NONE || hh == NULL)
+ return -1;
+ if (pub == NULL)
+ pub = msg->m_object;
+
+ head = _msg_chain_head(msg);
+
+ if (*head) {
+ msg_header_t *sh, **prev;
+
+ for (sh = h, prev = NULL; sh; sh = sh->sh_next) {
+ sh->sh_succ = sh->sh_next;
+ sh->sh_prev = prev;
+ prev = &sh->sh_succ;
+ }
+ }
+
+ switch (h->sh_class->hc_kind) {
+ case msg_kind_single:
+ case msg_kind_list:
+ old = (*hh);
+ break;
+ case msg_kind_append:
+ case msg_kind_apndlist:
+ case msg_kind_prepend:
+ for (end = h; end->sh_next; end = end->sh_next)
+ ;
+ end->sh_next = *hh;
+ break;
+ }
+
+ if (*head) {
+ /* Insert into existing fragment chain */
+ msg_insert_chain(msg, pub, 1, head, h);
+
+ /* Remove replaced fragment */
+ if (old)
+ msg_chain_remove(msg, old);
+ }
+
+ /* Insert into header list */
+ *hh = h;
+
+ return 0;
+}
+
+
+/** Find place to insert header of the class @a hc. */
+msg_header_t **
+msg_hclass_offset(msg_mclass_t const *mc, msg_pub_t const *mo, msg_hclass_t *hc)
+{
+ int i;
+
+ assert(mc && hc);
+
+ if (mc == NULL || hc == NULL)
+ return NULL;
+
+ if (hc->hc_hash > 0) {
+ unsigned j, N = mc->mc_hash_size;
+ for (j = hc->hc_hash % N; mc->mc_hash[j].hr_class; j = (j + 1) % N)
+ if (mc->mc_hash[j].hr_class == hc) {
+ return (msg_header_t **)((char *)mo + mc->mc_hash[j].hr_offset);
+ }
+ }
+ else
+ /* Header has no name. */
+ for (i = 0; i <= 6; i++)
+ if (hc->hc_hash == mc->mc_request[i].hr_class->hc_hash)
+ return (msg_header_t **)((char *)mo + mc->mc_request[i].hr_offset);
+
+ return NULL;
+}
+
+/** Append a parsed header object into the message structure */
+static inline void
+append_parsed(msg_t *msg, msg_pub_t *mo, msg_href_t const *hr, msg_header_t *h,
+ int always_into_chain)
+{
+ msg_header_t **hh;
+
+ assert(msg); assert(hr->hr_offset);
+
+ hh = (msg_header_t **)((char *)mo + hr->hr_offset);
+
+ if (msg->m_chain || always_into_chain)
+ msg_insert_here_in_chain(msg, msg_chain_tail(msg), h);
+
+ if (*hh && msg_is_single(h)) {
+ /* If there is multiple instances of single headers,
+ put the extra headers into the list of erroneous headers */
+ msg_error_t **e;
+
+ for (e = &mo->msg_error; *e; e = &(*e)->er_next)
+ ;
+ *e = (msg_error_t *)h;
+
+ msg->m_extract_err |= hr->hr_flags;
+ if (hr->hr_class->hc_critical)
+ mo->msg_flags |= MSG_FLG_ERROR;
+
+ return;
+ }
+
+ while (*hh)
+ hh = &(*hh)->sh_next;
+ *hh = h;
+}
+
+static int _msg_header_add_list_items(msg_t *msg,
+ msg_header_t **hh,
+ msg_header_t const *src);
+
+/**Duplicate and add a (list of) header(s) to the message.
+ *
+ * The function @c msg_header_add_dup() duplicates and adds a (list of)
+ * header(s) into a message structure.
+ *
+ * When inserting headers into the fragment chain, a request (or status) is
+ * inserted first and replaces the existing request (or status). Other
+ * headers are inserted after the request or status.
+ *
+ * If the header is a singleton, existing headers with the same class are
+ * removed.
+ *
+ * @param msg message owning the fragment chain
+ * @param pub public message structure to which header is added
+ * @param src list of header(s) to be added
+ */
+int msg_header_add_dup(msg_t *msg,
+ msg_pub_t *pub,
+ msg_header_t const *src)
+{
+ msg_header_t *h, **hh = NULL;
+ msg_hclass_t *hc = NULL;
+
+ if (msg == NULL)
+ return -1;
+ if (src == NULL || src == MSG_HEADER_NONE)
+ return 0;
+ if (pub == NULL)
+ pub = msg->m_object;
+
+ for ( ;src; src = src->sh_next) {
+ assert(src->sh_class);
+
+ if (!src->sh_class)
+ return -1;
+
+ if (hc != src->sh_class)
+ hh = msg_hclass_offset(msg->m_class, pub, hc = src->sh_class);
+
+ if (hh == NULL)
+ return -1;
+
+ if (!*hh || hc->hc_kind != msg_kind_list) {
+ int size = hc->hc_size;
+ isize_t xtra = hc->hc_dxtra(src, size) - size;
+ char *end;
+
+ if (!(h = msg_header_alloc(msg_home(msg), hc, xtra)))
+ return -1; /* error */
+
+ if (!(end = hc->hc_dup_one(h, src, (char *)h + size, xtra)))
+ return -1; /* error */
+
+ if (hc->hc_update)
+ msg_header_update_params(h->sh_common, 0);
+
+ assert(end == (char *)h + size + xtra);
+
+ if (msg_header_add(msg, pub, hh, h) < 0)
+ return -1;
+
+ hh = &h->sh_next;
+ }
+ else {
+ if (_msg_header_add_list_items(msg, hh, src) < 0)
+ break;
+ }
+ }
+
+ if (src)
+ return -1;
+
+ return 0;
+}
+
+/**Duplicate a header as a given type and add the duplicate into message.
+ *
+ * The function @c msg_header_add_dup_as() duplicates a header as a instance
+ * of the given header class. It adds the new copy into the message.
+ *
+ * When inserting headers into the fragment chain, a request (or status) is
+ * inserted first and replaces the existing request (or status). Other
+ * headers are inserted after the request or status.
+ *
+ * If the header is a singleton, existing headers with the same class are
+ * removed.
+ *
+ * @param msg message owning the fragment chain
+ * @param pub public message structure to which header is added
+ * @param hc header class for header target type
+ * @param src list of header(s) to be duplicated and added
+ */
+int msg_header_add_dup_as(msg_t *msg,
+ msg_pub_t *pub,
+ msg_hclass_t *hc,
+ msg_header_t const *src)
+{
+ if (msg == NULL || hc == NULL)
+ return -1;
+ if (src == NULL || src == MSG_HEADER_NONE)
+ return 0;
+ if (pub == NULL)
+ pub = msg->m_object;
+
+ return _msg_header_add_dup_as(msg, pub, hc, src);
+}
+
+/** Duplicate and add a (list of) header to a message */
+static
+int _msg_header_add_dup_as(msg_t *msg,
+ msg_pub_t *pub,
+ msg_hclass_t *hc,
+ msg_header_t const *src)
+{
+ msg_header_t *h, **hh;
+
+ hh = msg_hclass_offset(msg->m_class, pub, hc);
+
+ if (hh == NULL)
+ return -1;
+
+ if (*hh && hc->hc_kind == msg_kind_list)
+ return _msg_header_add_list_items(msg, hh, src);
+
+ if (!(h = msg_header_dup_as(msg_home(msg), hc, src)))
+ return -1;
+
+ return msg_header_add(msg, pub, hh, h);
+}
+
+/* Add list items */
+static int _msg_header_add_list_items(msg_t *msg,
+ msg_header_t **hh,
+ msg_header_t const *src)
+{
+ msg_header_t *h = *hh;
+ msg_param_t **s = msg_header_params(src->sh_common);
+
+ if (!s || !*s)
+ return 0;
+
+ msg_fragment_clear(h->sh_common);
+
+ /* Remove empty headers */
+ for (hh = &h->sh_next; *hh; *hh = (*hh)->sh_next)
+ msg_chain_remove(msg, *hh);
+
+ if (msg_header_join_items(msg_home(msg), h->sh_common, src->sh_common, 1)
+ < 0)
+ return -1;
+
+ return 0;
+}
+
+/** Parse a string as a given header field and add result to the message. */
+int msg_header_add_make(msg_t *msg,
+ msg_pub_t *pub,
+ msg_hclass_t *hc,
+ char const *s)
+{
+ msg_header_t *h, **hh;
+
+ if (msg == NULL)
+ return -1;
+ if (pub == NULL)
+ pub = msg->m_object;
+
+ hh = msg_hclass_offset(msg->m_class, pub, hc);
+
+ if (hh == NULL)
+ return -1;
+
+ if (!s)
+ return 0;
+
+ if (*hh && hc->hc_kind == msg_kind_list) {
+ /* Add list items */
+ msg_header_t *h = *hh;
+ msg_param_t **d;
+ char *s0;
+
+ skip_lws(&s);
+
+ d = msg_header_params(h->sh_common); assert(d);
+
+ msg_fragment_clear(h->sh_common);
+
+ /* Remove empty headers */
+ for (hh = &h->sh_next; *hh; *hh = (*hh)->sh_next)
+ msg_chain_remove(msg, *hh);
+
+ s0 = su_strdup(msg_home(msg), s);
+
+ if (!s0 || msg_commalist_d(msg_home(msg), &s0, d, msg_token_scan) < 0)
+ return -1;
+
+ return 0;
+ }
+
+ if (!(h = msg_header_make(msg_home(msg), hc, s)))
+ return -1;
+
+ return msg_header_add(msg, pub, hh, h);
+}
+
+/**Add string contents to message.
+ *
+ * Duplicate a string containing headers (or a message body, if the string
+ * starts with linefeed), parse it and add resulting header objects to the
+ * message object.
+ *
+ * @param msg message object
+ * @param pub message header structure where heades are added (may be NULL)
+ * @param str string to be copied and parsed (not modified, may be NULL)
+ *
+ * @retval 0 when succesful
+ * @retval -1 upon an error
+ */
+int msg_header_add_str(msg_t *msg,
+ msg_pub_t *pub,
+ char const *str)
+{
+ char *s;
+
+ if (!msg)
+ return -1;
+ if (!str)
+ return 0;
+
+ s = su_strdup(msg_home(msg), str);
+
+ if (s == NULL)
+ return -1;
+
+ return msg_header_parse_str(msg, pub, s);
+}
+
+/**Add string to message.
+ *
+ * Parse a string containing headers (or a message body, if the string
+ * starts with linefeed) and add resulting header objects to the message
+ * object.
+ *
+ * @param msg message object
+ * @param pub message header structure where heades are added (may be NULL)
+ * @param s string to be parsed (and modified)
+ *
+ * @retval 0 when succesful
+ * @retval -1 upon an error
+ *
+ * @sa msg_header_add_str(), url_headers_as_string()
+ *
+ * @since New in @VERSION_1_12_4.
+ */
+int msg_header_parse_str(msg_t *msg,
+ msg_pub_t *pub,
+ char *s)
+{
+ if (!msg)
+ return -1;
+
+ if (pub == NULL)
+ pub = msg->m_object;
+
+ if (s) {
+ size_t ssiz = strlen(s), used = 0;
+ ssize_t n = 1;
+
+ while (ssiz > used) {
+ if (IS_CRLF(s[used]))
+ break;
+ n = msg_extract_header(msg, pub, s + used, ssiz - used, 1);
+ if (n <= 0)
+ break;
+ used += n;
+ }
+
+ if (n > 0 && ssiz > used) {
+ used += CRLF_TEST(s + used);
+ if (ssiz > used)
+ msg_extract_payload(msg, pub, NULL, ssiz - used,
+ s + used, ssiz - used, 1);
+ }
+
+ if (n <= 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+/** Insert a (list of) header(s) to the fragment chain.
+ *
+ * The function @c msg_header_insert() inserts header or list of headers
+ * into a message structure. It also inserts them into the the message
+ * fragment chain, if it exists.
+ *
+ * When inserting headers into the fragment chain, a request (or status) is
+ * inserted first and replaces the existing request (or status). Other
+ * headers are inserted after the request or status.
+ *
+ * If there can be only one header field of this type (hc_kind is
+ * msg_kind_single), existing header objects with the same class are
+ * removed.
+ *
+ * @param msg message object owning the fragment chain
+ * @param pub public message structure to which header is added
+ * @param h list of header(s) to be added
+ */
+int msg_header_insert(msg_t *msg, msg_pub_t *pub, msg_header_t *h)
+{
+ msg_header_t **hh;
+
+ assert(msg);
+
+ if (msg == NULL || h == NULL || h == MSG_HEADER_NONE ||
+ h->sh_class == NULL)
+ return -1;
+ if (pub == NULL)
+ pub = msg->m_object;
+
+ hh = msg_hclass_offset(msg->m_class, pub, h->sh_class);
+
+ return msg_header_add(msg, pub, hh, h);
+}
+
+/**Remove a header from the header structure and fragment chain.
+ *
+ * The function @c msg_header_remove() removes a header from a message
+ * structure. It also removes the message from the message fragment chain
+ * and clears the encoding of other headers objects that share same
+ * encoding.
+ *
+ * @param msg message owning the fragment chain
+ * @param pub public message structure to which header is added
+ * @param h header to be removed
+ */
+int msg_header_remove(msg_t *msg, msg_pub_t *pub, msg_header_t *h)
+{
+ msg_header_t **hh, **hh0;
+
+ if (msg == NULL || h == NULL || h == MSG_HEADER_NONE ||
+ h->sh_class == NULL)
+ return -1;
+ if (pub == NULL)
+ pub = msg->m_object;
+
+ /* First, remove from public structure (msg_pub_t) */
+ hh0 = msg_hclass_offset(msg->m_class, pub, h->sh_class);
+ if (!hh0)
+ return -1;
+
+ for (hh = hh0; *hh; hh = &(*hh)->sh_next) {
+ if (*hh == h) {
+ *hh = h->sh_next;
+ break;
+ }
+ }
+
+ if (h->sh_data) {
+ void const *data = (char *)h->sh_data + h->sh_len;
+ for (hh = hh0; *hh; hh = &(*hh)->sh_next) {
+ if (data == (char *)(*hh)->sh_data + (*hh)->sh_len) {
+ (*hh)->sh_data = NULL, (*hh)->sh_len = 0;
+ }
+ }
+ }
+
+ msg_chain_remove(msg, h);
+
+ return 0;
+}
+
+
+/**Remove a header list from the header structure and fragment chain.
+ *
+ * The function @c msg_header_remove_all() removes a list of headers from a
+ * message structure. It also removes the message from the message fragment
+ * chain and clears the encoding of other headers objects that share same
+ * encoding.
+ *
+ * @param msg message owning the fragment chain
+ * @param pub public message structure to which header is added
+ * @param h header list to be removed
+ */
+int msg_header_remove_all(msg_t *msg, msg_pub_t *pub, msg_header_t *h)
+{
+ msg_header_t **hh, **hh0;
+ void const *data;
+
+ if (msg == NULL || h == NULL || h == MSG_HEADER_NONE ||
+ h->sh_class == NULL)
+ return -1;
+ if (pub == NULL)
+ pub = msg->m_object;
+
+ hh0 = msg_hclass_offset(msg->m_class, pub, h->sh_class);
+ if (!hh0)
+ return -1;
+
+ data = (char *)h->sh_data + h->sh_len;
+
+ /* First, remove from public structure (msg_pub_t) */
+ for (hh = hh0; *hh; hh = &(*hh)->sh_next) {
+ if (*hh == h) {
+ break;
+ }
+ if (data && data == (char *)(*hh)->sh_data + (*hh)->sh_len) {
+ h->sh_data = NULL, h->sh_len = 0;
+ (*hh)->sh_data = NULL, (*hh)->sh_len = 0;
+ }
+ }
+
+ /* Remove from header chain */
+ while (h) {
+ h->sh_data = NULL, h->sh_len = 0;
+ msg_chain_remove(msg, h);
+ h = h->sh_next;
+ }
+
+ *hh = NULL;
+
+ return 0;
+}
+
+
+/** Replace a header item with a (list of) header(s).
+ *
+ * The function @c msg_header_replace() removes a header structure from
+ * message and replaces it with a new one or a list of headers. It inserts
+ * the new headers into the the message fragment chain, if it exists.
+ *
+ * @param msg message object owning the fragment chain
+ * @param pub public message structure to which header is added
+ * @param replaced old header to be removed
+ * @param h list of header(s) to be added
+ */
+int msg_header_replace(msg_t *msg,
+ msg_pub_t *pub,
+ msg_header_t *replaced,
+ msg_header_t *h)
+{
+ msg_header_t *h0, *last, **hh, **hh0;
+
+ if (msg == NULL || replaced == NULL)
+ return -1;
+ if (h == NULL || h == MSG_HEADER_NONE || h->sh_class == NULL)
+ return msg_header_remove(msg, pub, replaced);
+ if (pub == NULL)
+ pub = msg->m_object;
+
+ hh = hh0 = msg_hclass_offset(msg->m_class, pub, h->sh_class);
+ if (hh == NULL)
+ return -1;
+ if (replaced == NULL)
+ return msg_header_add(msg, pub, hh, h);
+
+ assert(h->sh_prev == NULL); /* Must not be in existing chain! */
+
+ for (last = h; last->sh_next; last = last->sh_next) {
+ if ((last->sh_succ = last->sh_next))
+ last->sh_next->sh_prev = &last->sh_succ;
+ }
+
+ for (h0 = *hh; h0; hh = &h0->sh_next, h0 = *hh) {
+ if (replaced == h0)
+ break;
+ }
+
+ if (h0 == NULL)
+ return -1;
+
+ *hh = h; /* Replace in list */
+ last->sh_next = replaced->sh_next;
+
+ if (replaced->sh_prev) {
+ *replaced->sh_prev = h;
+ h->sh_prev = replaced->sh_prev;
+ if ((last->sh_succ = replaced->sh_succ))
+ last->sh_succ->sh_prev = &last->sh_succ;
+ if (msg->m_tail == &replaced->sh_succ)
+ msg->m_tail = &last->sh_succ;
+ }
+
+ assert(msg->m_tail != &replaced->sh_succ);
+
+ replaced->sh_next = NULL;
+ replaced->sh_prev = NULL;
+ replaced->sh_succ = NULL;
+
+ if (replaced->sh_data) {
+ /* Remove cached encoding if it is shared with more than one header fragments */
+ int cleared = 0;
+ void const *data = (char *)replaced->sh_data + replaced->sh_len;
+
+ for (hh = hh0; *hh; hh = &(*hh)->sh_next) {
+ if (data == (char *)(*hh)->sh_data + (*hh)->sh_len) {
+ (*hh)->sh_data = NULL, (*hh)->sh_len = 0, cleared = 1;
+ }
+ }
+
+ if (cleared)
+ replaced->sh_data = NULL, replaced->sh_len = 0;
+ }
+
+ return 0;
+}
+
+/** Free a header structure */
+void msg_header_free(su_home_t *home, msg_header_t *h)
+{
+ su_free(home, h);
+}
+
+/** Free a (list of) header structures */
+void msg_header_free_all(su_home_t *home, msg_header_t *h)
+{
+ msg_header_t *h_next;
+
+ while (h) {
+ h_next = h->sh_next;
+ su_free(home, h);
+ h = h_next;
+ }
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_parser_util.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_parser_util.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1991 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup msg_parser
+ * @CFILE msg_parser_util.c
+ *
+ * Text-message parser helper functions.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Aug 28 16:26:34 2001 ppessi
+ *
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <limits.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/bnf.h"
+
+#include "sofia-sip/url.h"
+
+static issize_t msg_comma_scanner(char *start);
+
+/**
+ * Parse first line.
+ *
+ * Splits the first line from a message into three whitespace-separated
+ * parts.
+ */
+int msg_firstline_d(char *s, char **return_part2, char **return_part3)
+{
+ char *s1 = s, *s2, *s3;
+ size_t n;
+
+ /* Split line into three segments separated by whitespace */
+ if (s1[n = span_non_ws(s1)]) {
+ s1[n] = '\0';
+ s2 = s1 + n + 1;
+ while (IS_WS(*s2))
+ s2++;
+ }
+ else {
+ /* Hopeless - no WS in first line */
+ return -1;
+ }
+
+ n = span_non_ws(s2);
+
+ if (s2[n]) {
+ s2[n++] = '\0';
+ while (IS_WS(s2[n]))
+ n++;
+ }
+
+ s3 = s2 + n;
+
+ *return_part2 = s2;
+
+ *return_part3 = s3;
+
+ return 0;
+}
+
+/**Parse a token.
+ *
+ * Parses a token from string pointed by @a *ss. It stores the token value
+ * in @a return_token, and updates the @a ss to the end of token and
+ * possible whitespace.
+ */
+issize_t msg_token_d(char **ss, char const **return_token)
+{
+ char *s = *ss;
+ size_t n = span_token(s);
+ if (n) {
+ for (; IS_LWS(s[n]); n++)
+ s[n] = '\0';
+ *return_token = s;
+ *ss = s + n;
+ return n;
+ }
+ else
+ return -1;
+}
+
+/** Parse a 32-bit unsigned int.
+ *
+ * The function msg_uint32_d() parses a 32-bit unsigned integer in string
+ * pointed by @a *ss. It stores the value in @a return_token and updates the
+ * @a ss to the end of integer and possible whitespace.
+ *
+ * @retval length of parsed integer, or -1 upon an error.
+ */
+issize_t msg_uint32_d(char **ss, uint32_t *return_value)
+{
+ char const *s = *ss, *s0 = s;
+ uint32_t value;
+ unsigned digit;
+
+ if (!IS_DIGIT(*s))
+ return -1;
+
+ for (value = 0; IS_DIGIT(*s); s++) {
+ digit = *s - '0';
+ if (value > 429496729U)
+ return -1;
+ else if (value == 429496729U && digit > 5)
+ return -1;
+ value = 10 * value + digit;
+ }
+
+ if (*s) {
+ if (!IS_LWS(*s))
+ return (issize_t)-1;
+ skip_lws(&s);
+ }
+
+ *ss = (char *)s;
+ *return_value = value;
+
+ return s - s0;
+}
+
+
+/** Parse any list.
+ *
+ * Parses a list of items, separated by @a sep. The parsed string is passed
+ * in @a *ss, which is updated to point to the first non-linear-whitespace
+ * character after the list. The function modifies the string as it parses
+ * it.
+ *
+ * The parsed items are appended to the list @a *append_list. If there the
+ * list in @a *append_list is NULL, allocate a new list and return it in @a
+ * *append_list. Empty list items are ignored, and are not appended to the
+ * list.
+ *
+ * The function @b must be passed a scanning function @a scanner. The
+ * scanning function scans for a legitimate list item, for example, a token.
+ * It should also compact the list item, for instance, if the item consists
+ * of @c name=value parameter definitions it should remove whitespace around
+ * "=" sign. The scanning function returns the length of the scanned item,
+ * including any linear whitespace after it.
+ *
+ * @param[in] home memory home for allocating list pointers
+ * @param[in,out] ss pointer to pointer to string to be parsed
+ * @param[in,out] append_list pointer to list
+ * where parsed list items are appended
+ * @param[in] sep separator character
+ * @param[in] scanner pointer to function for scanning a single item
+ *
+ * @retval 0 if successful.
+ * @retval -1 upon an error.
+ */
+issize_t msg_any_list_d(su_home_t *home,
+ char **ss,
+ msg_param_t **append_list,
+ issize_t (*scanner)(char *s),
+ int sep)
+{
+ char const *auto_list[MSG_N_PARAMS];
+ char const **list = auto_list, **re_list;
+ int N = MSG_N_PARAMS, n = 0;
+ issize_t tlen;
+ char *s = *ss;
+ char const **start;
+
+ if (!scanner)
+ return -1;
+
+ if (*append_list) {
+ list = *append_list;
+ while (list[n])
+ n++;
+ N = MSG_PARAMS_NUM(n + 1);
+ }
+
+ start = &list[n];
+
+ skip_lws(&s);
+
+ while (*s) {
+ tlen = scanner(s);
+
+ if (tlen < 0 || (s[tlen] && s[tlen] != sep && s[tlen] != ','))
+ goto error;
+
+ if (tlen > 0) {
+ if (n + 1 == N) { /* Reallocate list? */
+ N = MSG_PARAMS_NUM(N + 1);
+ if (list == auto_list || list == *append_list) {
+ re_list = su_alloc(home, N * sizeof(*list));
+ if (re_list)
+ memcpy(re_list, list, n * sizeof(*list));
+ }
+ else
+ re_list = su_realloc(home, list, N * sizeof(*list));
+ if (!re_list)
+ goto error;
+ list = re_list;
+ }
+
+ list[n++] = s;
+ s += tlen;
+ }
+
+ if (*s == sep) {
+ *s++ = '\0';
+ skip_lws(&s);
+ }
+ else if (*s)
+ break;
+ }
+
+ *ss = s;
+
+ if (n > 0 && list == auto_list) {
+ size_t size = sizeof(*list) * MSG_PARAMS_NUM(n + 1);
+ list = su_alloc(home, size);
+ if (!list) return -1;
+ memcpy((void *)list, auto_list, n * sizeof(*list));
+ }
+
+ list[n] = NULL;
+ if (n == 0)
+ list = NULL;
+
+ *append_list = list;
+ return 0;
+
+ error:
+ *start = NULL;
+ if (list != auto_list && list != *append_list)
+ su_free(home, list);
+ return -1;
+}
+
+/** Scan an attribute (name [= value]) pair.
+ *
+ * The attribute consists of name (a token) and optional value, separated by
+ * equal sign. The value can be a token or quoted string.
+ *
+ * This function compacts the scanned value. It removes the
+ * whitespace around equal sign "=" by moving the equal sign character and
+ * value towards name.
+ *
+ * If there is whitespace within the scanned value or after it,
+ * NUL-terminates the scanned attribute.
+ *
+ * @retval > 0 number of characters scanned,
+ * including the whitespace within the value
+ * @retval -1 upon an error
+ */
+issize_t msg_attribute_value_scanner(char *s)
+{
+ char *p = s;
+ size_t tlen;
+
+ skip_token(&s);
+
+ if (s == p) /* invalid parameter name */
+ return -1;
+
+ tlen = s - p;
+
+ if (IS_LWS(*s)) { *s++ = '\0'; skip_lws(&s); }
+
+ if (*s == '=') {
+ char *v;
+ s++;
+ skip_lws(&s);
+
+ /* get value */
+ if (*s == '"') {
+ size_t qlen = span_quoted(s);
+ if (!qlen)
+ return -1;
+ v = s; s += qlen;
+ }
+ else {
+ v = s;
+ skip_param(&s);
+ if (s == v)
+ return -1;
+ }
+
+ if (p + tlen + 1 != v) {
+ memmove(p + tlen + 1, v, s - v);
+ p[tlen] = '=';
+ p[tlen + 1 + (s - v)] = '\0';
+ }
+ }
+
+ if (IS_LWS(*s)) { *s++ = '\0'; skip_lws(&s); }
+
+ return s - p;
+}
+
+/**Parse an attribute-value list.
+ *
+ * Parses an attribute-value list, which has syntax as follows:
+ * @code
+ * av-list = (av-pair *(";" av-pair)
+ * av-pair = token ["=" ( value / quoted-string) ] ; optional value
+ * @endcode
+ *
+ * @param[in] home pointer to a memory home
+ * @param[in,out] ss pointer to string at the start of parameter list
+ * @param[in,out] append_list pointer to list
+ * where parsed list items are appended
+ *
+ * @retval >= 0 if successful
+ * @retval -1 upon an error
+ */
+issize_t msg_avlist_d(su_home_t *home,
+ char **ss,
+ msg_param_t const **append_list)
+{
+ char const *stack[MSG_N_PARAMS];
+ char const **params;
+ size_t n = 0, N;
+ char *s = *ss;
+
+ if (!*s)
+ return -1;
+
+ if (*append_list) {
+ params = (char const **)*append_list;
+ for (n = 0; params[n]; n++)
+ ;
+ N = MSG_PARAMS_NUM(n + 1);
+ } else {
+ params = stack;
+ N = MSG_PARAMS_NUM(1);
+ }
+
+ for (;;) {
+ char *p;
+ size_t tlen;
+
+ /* XXX - we should handle also quoted parameters */
+
+ skip_lws(&s);
+ p = s;
+ skip_token(&s);
+ tlen = s - p;
+ if (!tlen) /* invalid parameter name */
+ goto error;
+
+ if (IS_LWS(*s)) { *s++ = '\0'; skip_lws(&s); }
+
+ if (*s == '=') {
+ char *v;
+ s++;
+ skip_lws(&s);
+
+ /* get value */
+ if (*s == '"') {
+ size_t qlen = span_quoted(s);
+ if (!qlen)
+ goto error;
+ v = s; s += qlen;
+ }
+ else {
+ v = s;
+ skip_param(&s);
+ if (s == v)
+ goto error;
+ }
+ if (p + tlen + 1 != v) {
+ p = memmove(v - tlen - 1, p, tlen);
+ p[tlen] = '=';
+ }
+
+ }
+
+ if (IS_LWS(*s)) { *s++ = '\0'; skip_lws(&s); }
+
+ if (n == N) {
+ /* Reallocate params */
+ char **nparams = su_alloc(home,
+ (N = MSG_PARAMS_NUM(N + 1)) * sizeof(*params));
+ if (!nparams) {
+ goto error;
+ }
+ params = memcpy(nparams, params, n * sizeof(*params));
+ }
+
+ params[n++] = p;
+
+ if (*s != ';')
+ break;
+
+ *s++ = '\0';
+ }
+
+ *ss = s;
+
+ if (params == stack) {
+ size_t size = sizeof(*params) * MSG_PARAMS_NUM(n + 1);
+ params = su_alloc(home, size);
+ if (!params) return -1;
+ memcpy((void *)params, stack, n * sizeof(*params));
+ }
+ else if (n == N) {
+ /* Reallocate params */
+ char **nparams = su_alloc(home,
+ (N = MSG_PARAMS_NUM(N + 1)) * sizeof(*params));
+ if (!nparams) {
+ goto error;
+ }
+ params = memcpy(nparams, params, n * sizeof(*params));
+ }
+
+ params[n] = NULL;
+
+ *append_list = params;
+
+ return 0;
+
+ error:
+ if (params != stack)
+ su_free(home, params);
+ return -1;
+}
+
+/**Parse a semicolon-separated parameter list starting with semicolon.
+ *
+ * Parse a parameter list, which has syntax as follows:
+ * @code
+ * *(";" token [ "=" (token | quoted-string)]).
+ * @endcode
+ *
+ * @param[in] home pointer to a memory home
+ * @param[in,out] ss pointer to string at the start of parameter list
+ * @param[in,out] append_list pointer to list
+ * where parsed list items are appended
+ *
+ * @retval >= 0 if successful
+ * @retval -1 upon an error
+ *
+ * @sa msg_avlist_d()
+ */
+issize_t msg_params_d(su_home_t *home,
+ char **ss,
+ msg_param_t const **append_list)
+{
+ if (**ss == ';') {
+ *(*ss)++ = '\0';
+ *append_list = NULL;
+ return msg_avlist_d(home, ss, append_list);
+ }
+
+ if (IS_LWS(**ss)) {
+ *(*ss)++ = '\0'; skip_lws(ss);
+ }
+
+ return 0;
+}
+
+/** Encode a list of parameters */
+isize_t msg_params_e(char b[], isize_t bsiz, msg_param_t const pparams[])
+{
+ int i;
+ char *end = b + bsiz, *b0 = b;
+ msg_param_t p;
+
+ if (pparams)
+ for (i = 0; (p = pparams[i]); i++) {
+ if (p[0]) {
+ MSG_CHAR_E(b, end, ';');
+ MSG_STRING_E(b, end, p);
+ }
+ }
+
+ return b - b0;
+}
+
+/** Duplicate a parameter list */
+char *msg_params_dup(msg_param_t const **d, msg_param_t const s[],
+ char *b, isize_t xtra)
+{
+ char *end = b + xtra;
+ char **pp;
+ int i;
+ isize_t n;
+
+ n = msg_params_count(s);
+
+ if (n == 0) {
+ *d = NULL;
+ return b;
+ }
+
+ MSG_STRUCT_ALIGN(b);
+ pp = (char **)b;
+
+ b += sizeof(*pp) * MSG_PARAMS_NUM(n + 1);
+
+ for (i = 0; s[i]; i++) {
+ MSG_STRING_DUP(b, pp[i], s[i]);
+ }
+ pp[i] = NULL;
+
+ assert(b <= end); (void)end;
+
+ *d = (msg_param_t const *)pp;
+
+ return b;
+}
+
+
+/** Parse a comma-separated list.
+ *
+ * Parses a comma-separated list. The parsed string is passed in @a *ss,
+ * which is updated to point to the first non-linear-whitespace character
+ * after the list. The function modifies the string as it parses it.
+ *
+ * A pointer to the resulting list is returned in @a *retval. If there
+ * already is a list in @a *retval, new items are appended. Empty list items
+ * are ignored, and are not included in the list.
+ *
+ * The function can be passed an optional scanning function. The scanning
+ * function scans for a legitimate list item, for example, a token. It also
+ * compacts the list item, for instance, if the item consists of @c
+ * name=value parameter definitions. The scanning function returns the
+ * length of the scanned item, including any linear whitespace after it.
+ *
+ * By default, the scanning function accepts tokens, quoted strings or
+ * separators (except comma, of course).
+ *
+ * @param[in] home memory home for allocating list pointers
+ * @param[in,out] ss pointer to pointer to string to be parsed
+ * @param[in,out] append_list pointer to list
+ * where parsed list items are appended
+ * @param[in] scanner pointer to function scanning a single item
+ * (optional)
+ *
+ * @retval 0 if successful.
+ * @retval -1 upon an error.
+ */
+issize_t msg_commalist_d(su_home_t *home,
+ char **ss,
+ msg_param_t **append_list,
+ issize_t (*scanner)(char *s))
+{
+ scanner = scanner ? scanner : msg_comma_scanner;
+ return msg_any_list_d(home, ss, append_list, scanner, ',');
+}
+
+/** Token scanner for msg_commalist_d() accepting also empty entries. */
+issize_t msg_token_scan(char *start)
+{
+ char *s = start;
+ skip_token(&s);
+
+ if (IS_LWS(*s))
+ *s++ = '\0';
+ skip_lws(&s);
+
+ return s - start;
+}
+
+/** Scan and compact a comma-separated item */
+static
+issize_t msg_comma_scanner(char *start)
+{
+ size_t tlen;
+ char *s, *p;
+
+ s = p = start;
+
+ if (s[0] == ',')
+ return 0;
+
+ for (;;) {
+ /* Grab next section - token, quoted string, or separator character */
+ char c = *s;
+
+ if (IS_TOKEN(c))
+ tlen = span_token(s);
+ else if (c == '"')
+ tlen = span_quoted(s);
+ else /* if (IS_SEPARATOR(c)) */
+ tlen = 1;
+
+ if (tlen == 0)
+ return -1;
+
+ if (p != s)
+ memmove(p, s, tlen); /* Move section to end of paramexter */
+ p += tlen; s += tlen;
+
+ skip_lws(&s); /* Skip possible LWS */
+
+ if (*s == '\0' || *s == ',') { /* Test for possible end */
+ if (p != s) *p = '\0';
+ return s - start;
+ }
+
+ if (IS_TOKEN(c) && IS_TOKEN(*s))
+ *p++ = ' '; /* Two tokens must be separated by LWS */
+ }
+}
+
+/** Parse a comment.
+ *
+ * Parses a multilevel comment. The comment assigned to return-value
+ * parameter @a return_comment is NUL-terminated. The string at return-value
+ * parameter @a ss is updated to point to first non-linear-whitespace
+ * character after the comment.
+ */
+issize_t msg_comment_d(char **ss, char const **return_comment)
+{
+ /* skip comment */
+ int level = 1;
+ char *s = *ss;
+
+ assert(s[0] == '(');
+
+ if (*s != '(')
+ return -1;
+
+ *s++ = '\0';
+
+ if (return_comment)
+ *return_comment = s;
+
+ while (level) switch (*s++) {
+ case '(': level++; break;
+ case ')': level--; break;
+ case '\0': /* ERROR */ return -1;
+ }
+
+ assert(s[-1] == ')');
+
+ s[-1] = '\0';
+ skip_lws(&s);
+ *ss = s;
+
+ return 0;
+}
+
+/** Parse a quoted string */
+issize_t msg_quoted_d(char **ss, char **return_quoted)
+{
+ char *s= *ss, *s0 = s;
+ ssize_t n = span_quoted(s);
+
+ if (n <= 0)
+ return -1;
+
+ *return_quoted = s;
+ s += n;
+ if (IS_LWS(*s)) {
+ *s++ = '\0';
+ skip_lws(&s); /* skip linear whitespace */
+ }
+
+ *ss = s;
+
+ return s - s0;
+}
+
+#if 0
+/** Calculate length of string when quoted. */
+int msg_quoted_len(char const *u)
+{
+ int rv;
+
+ if (!u)
+ return 0;
+
+ rv = span_token_lws(u);
+ if (u[rv]) {
+ /* We need to quote string */
+ int n;
+ int extra = 2; /* quote chars */
+
+ /* Find all characters to quote */
+ for (n = strcspn(u + rv, "\\\""); u[rv + n]; rv += n)
+ extra++;
+
+ rv += extra;
+ }
+
+ return rv;
+}
+#endif
+
+/**Parse @e host[":"port] pair.
+ *
+ * Parses a @e host[":"port] pair. The caller passes function a pointer to a
+ * string via @a ss, and pointers to which parsed host and port are assigned
+ * via @a hhost and @a pport, respectively. The value-result parameter @a
+ * *pport must be initialized to default value (e.g., NULL).
+ *
+ * @param ss pointer to pointer to string to be parsed
+ * @param return_host value-result parameter for @e host
+ * @param return_port value-result parameter for @e port
+
+ * @return
+ * Returns zero when successful, and a negative value upon an error. The
+ * parsed values for host and port are assigned via @a return_host and @a
+ * return_port, respectively. The function also updates the pointer @a *ss,
+ * so if call is successful, the @a *ss points to first
+ * non-linear-whitespace character after @e host[":"port] pair.
+ *
+ * @note
+ * If there is no whitespace after @e port, the value in @a *pport may not be
+ * NUL-terminated. The calling function @b must NUL terminate the value by
+ * setting the @a **ss to NUL after first examining its value.
+ */
+int msg_hostport_d(char **ss,
+ char const **return_host,
+ char const **return_port)
+{
+ char *host, *s = *ss;
+ char *port = NULL;
+
+ /* Host name */
+ host = s;
+ if (s[0] != '[') {
+ skip_token(&s); if (host == s) return -1;
+ }
+ else {
+ /* IPv6 */
+ size_t n = strspn(++s, HEX ":.");
+ if (s[n] != ']') return -1;
+ s += n + 1;
+ }
+
+ if (IS_LWS(*s)) { *s++ = '\0'; skip_lws(&s); }
+
+ if (s[0] == ':') {
+ unsigned long nport;
+ *s++ = '\0'; skip_lws(&s);
+ if (!IS_DIGIT(*s))
+ return -1;
+ port = s;
+ nport = strtoul(s, &s, 10);
+ if (nport > 65535)
+ return -1;
+ if (IS_LWS(*s)) {
+ *s++ = '\0';
+ skip_lws(&s);
+ }
+ }
+
+ *return_host = host;
+ *return_port = port;
+
+ *ss = s;
+
+ return 0;
+}
+
+/** Find a header parameter.
+ *
+ * Searches for given parameter @a name from the header. If parameter is
+ * found, it returns a non-NULL pointer to the parameter value. If there is
+ * no value for the name (in form "name" or "name=value"), the returned pointer
+ * points to a NUL character.
+ *
+ * @param h pointer to header structure
+ * @param name parameter name (with or without "=" sign)
+ *
+ * @return
+ * A pointer to parameter value, or NULL if parameter was not found.
+ */
+char const *msg_header_find_param(msg_common_t const *h, char const *name)
+{
+ if (h && h->h_class->hc_params) {
+ msg_param_t const **params = (msg_param_t const **)
+ ((char *)h + h->h_class->hc_params);
+ return msg_params_find(*params, name);
+ }
+
+ return NULL;
+}
+
+/**Modify a parameter value or list item in a header.
+ *
+ * A header parameter @a param can be just a C-string (@a is_item > 0), or
+ * it can have internal format <i>name [ "=" value]</i>. In the latter case,
+ * the value part following = is ignored when replacing or removing the
+ * parameter.
+ *
+ * @param home memory home used to re-allocate parameter list in header
+ * @param h pointer to a header
+ * @param param parameter to be replaced or added
+ * @param is_item how to interpret @a param:
+ * - 1 case-sensitive, no structure
+ * - 0 case-insensitive, <i>name [ "=" value ]</i>
+ * @param remove_replace_add what operation to do:
+ * - -1 remove
+ * - 0 replace
+ * - 1 add
+ *
+ * @retval 1 if parameter was replaced or removed successfully
+ * @retval 0 if parameter was added successfully,
+ * or there was nothing to remove
+ * @retval -1 upon an error
+ */
+static
+int msg_header_param_modify(su_home_t *home, msg_common_t *h,
+ char const *param,
+ int is_item,
+ int remove_replace_add)
+{
+ msg_param_t *params, **pointer_to_params;
+ size_t plen, n;
+
+ if (!h || !h->h_class->hc_params || !param)
+ return -1;
+
+ pointer_to_params = (msg_param_t **)((char *)h + h->h_class->hc_params);
+ params = *pointer_to_params;
+
+ plen = is_item > 0 ? strlen(param) : strcspn(param, "=");
+ n = 0;
+
+ if (params) {
+ /* Existing list, try to replace or remove */
+ for (; params[n]; n++) {
+ char const *maybe = params[n];
+
+ if (remove_replace_add > 0)
+ continue;
+
+ if (is_item > 0) {
+ if (strcmp(maybe, param) == 0) {
+ if (remove_replace_add == 0)
+ return 1;
+ }
+ }
+ else {
+ if (strncasecmp(maybe, param, plen) == 0 &&
+ (maybe[plen] == '=' || maybe[plen] == 0))
+ break;
+ }
+ }
+ }
+
+ /* Not found? */
+ if (!params || !params[n]) {
+ if (remove_replace_add < 0)
+ return 0; /* Nothing to remove */
+ else
+ remove_replace_add = 1; /* Add instead of replace */
+ }
+
+ if (remove_replace_add < 0) { /* Remove */
+ for (; params[n]; n++)
+ params[n] = params[n + 1];
+ }
+ else {
+ if (remove_replace_add > 0) { /* Add */
+ size_t m_before = MSG_PARAMS_NUM(n + 1);
+ size_t m_after = MSG_PARAMS_NUM(n + 2);
+
+ assert(!params || !params[n]);
+
+ if (m_before != m_after || !params) {
+ msg_param_t *p;
+ /* XXX - we should know when to do realloc */
+ p = su_alloc(home, m_after * sizeof(*p));
+ if (!p) return -1;
+ if (n > 0)
+ memcpy(p, params, n * sizeof(p[0]));
+ *pointer_to_params = params = p;
+ }
+ params[n + 1] = NULL;
+ }
+
+ params[n] = param; /* Add .. or replace */
+ }
+
+ msg_fragment_clear(h);
+
+ if (h->h_class->hc_update) {
+ /* Update shortcuts */
+ size_t namelen;
+ char const *name, *value;
+
+ name = param;
+ namelen = strcspn(name, "=");
+
+ if (remove_replace_add < 0)
+ value = NULL;
+ else
+ value = param + namelen + (name[namelen] == '=');
+
+ h->h_class->hc_update(h, name, namelen, value);
+ }
+
+ return remove_replace_add <= 0; /* 0 when added, 1 otherwise */
+}
+
+/** Add a parameter to a header.
+ *
+ * You should use this function only when the header accepts multiple
+ * parameters (or list items) with the same name. If that is not the case,
+ * you should use msg_header_replace_param().
+ *
+ * @note This function @b does @b not duplicate @p param. The caller should
+ * have allocated the @a param from the memory home associated with header
+ * @a h.
+ *
+ * The possible shortcuts to parameter values are updated. For example, the
+ * "received" parameter in @Via header has shortcut in structure #sip_via_t,
+ * the @ref sip_via_s::v_received "v_received" field. The shortcut is usully
+ * a pointer to the parameter value. If the parameter was
+ * "received=127.0.0.1" the @ref sip_via_s::v_received "v_received" field
+ * would be a pointer to "127.0.0.1". If the parameter was "received=" or
+ * "received", the shortcut would be a pointer to an empty string, "".
+ *
+ * @param home memory home used to re-allocate parameter list in header
+ * @param h pointer to a header
+ * @param param parameter to be replaced or added
+ *
+ * @retval 0 if parameter was added
+ * @retval -1 upon an error
+ *
+ * @sa msg_header_replace_param(), msg_header_remove_param(),
+ * msg_header_update_params(),
+ * #msg_common_t, #msg_header_t,
+ * #msg_hclass_t, msg_hclass_t::hc_params, msg_hclass_t::hc_update
+ */
+int msg_header_add_param(su_home_t *home, msg_common_t *h, char const *param)
+{
+ return msg_header_param_modify(home, h, param,
+ 0 /* case-insensitive name=value */,
+ 1 /* add */);
+}
+
+
+
+/** Replace or add a parameter to a header.
+ *
+ * A header parameter @a param is a string of format <i>name "=" value</i>
+ * or just name. The value part following "=" is ignored when selecting a
+ * parameter to replace.
+ *
+ * @note This function @b does @b not duplicate @p param. The caller should
+ * have allocated the @a param from the memory home associated with header
+ * @a h.
+ *
+ * The possible shortcuts to parameter values are updated. For example, the
+ * "received" parameter in @Via header has shortcut in structure #sip_via_t,
+ * the @ref sip_via_s::v_received "v_received" field.
+ *
+ * @param home memory home used to re-allocate parameter list in header
+ * @param h pointer to a header
+ * @param param parameter to be replaced or added
+ *
+ * @retval 0 if parameter was added
+ * @retval 1 if parameter was replaced
+ * @retval -1 upon an error
+ *
+ * @sa msg_header_add_param(), msg_header_remove_param(),
+ * msg_header_update_params(),
+ * #msg_common_t, #msg_header_t,
+ * #msg_hclass_t, msg_hclass_t::hc_params, msg_hclass_t::hc_update
+ */
+int msg_header_replace_param(su_home_t *home,
+ msg_common_t *h,
+ char const *param)
+{
+ return msg_header_param_modify(home, h, param,
+ 0 /* case-insensitive name=value */,
+ 0 /* replace */);
+}
+
+/** Remove a parameter from header.
+ *
+ * The parameter name is given as token optionally followed by "=" sign and
+ * value. The "=" and value after it are ignored when selecting a parameter
+ * to remove.
+ *
+ * The possible shortcuts to parameter values are updated. For example, the
+ * "received" parameter in @Via header has shortcut in structure #sip_via_t,
+ * the @ref sip_via_s::v_received "v_received" field. The shortcut to
+ * removed parameter would be set to NULL.
+ *
+ * @param h pointer to a header
+ * @param name name of parameter to be removed
+ *
+ * @retval 1 if a parameter was removed
+ * @retval 0 if no parameter was not removed
+ * @retval -1 upon an error
+ *
+ * @sa msg_header_add_param(), msg_header_replace_param(),
+ * msg_header_update_params(),
+ * #msg_common_t, #msg_header_t,
+ * #msg_hclass_t, msg_hclass_t::hc_params, msg_hclass_t::hc_update
+ */
+int msg_header_remove_param(msg_common_t *h, char const *name)
+{
+ return msg_header_param_modify(NULL, h, name,
+ 0 /* case-insensitive name=value */,
+ -1 /* remove */);
+}
+
+/** Update shortcuts to parameter values.
+ *
+ * Update the shortcuts to parameter values in parameter list. For example,
+ * the "received" parameter in @Via header has shortcut in structure
+ * #sip_via_t, the @ref sip_via_s::v_received "v_received" field. The
+ * shortcut is usully a pointer to the parameter value. If the parameter was
+ * "received=127.0.0.1" the @ref sip_via_s::v_received "v_received" field
+ * would be a pointer to "127.0.0.1". If the parameter was "received=" or
+ * "received", the shortcut would be a pointer to an empty string, "".
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error
+ *
+ * @sa msg_header_add_param(), msg_header_replace_param(),
+ * msg_header_update_params(),
+ * #msg_common_t, #msg_header_t,
+ * #msg_hclass_t, msg_hclass_t::hc_params, msg_hclass_t::hc_update
+ */
+int msg_header_update_params(msg_common_t *h, int clear)
+{
+ msg_hclass_t *hc;
+ unsigned char offset;
+ msg_update_f *update;
+ int retval;
+ msg_param_t const *params;
+ size_t n;
+ char const *p, *v;
+
+ if (h == NULL)
+ return errno = EFAULT, -1;
+
+ hc = h->h_class; offset = hc->hc_params; update = hc->hc_update;
+
+ if (offset == 0 || update == NULL)
+ return 0;
+
+ if (clear)
+ update(h, NULL, 0, NULL);
+
+ params = *(msg_param_t **)((char *)h + offset);
+ if (params == NULL)
+ return 0;
+
+ retval = 0;
+
+ for (p = *params; p; p = *++params) {
+ n = strcspn(p, "=");
+ v = p + n + (p[n] == '=');
+ if (update(h, p, n, v) < 0)
+ retval = -1;
+ }
+
+ return retval;
+}
+
+
+/** Find a header item.
+ *
+ * Searches for given item @a name from the header. If item is found, the
+ * function returns a non-NULL pointer to the item.
+ *
+ * @param h pointer to header structure
+ * @param item item
+ *
+ * @return
+ * A pointer to item, or NULL if it was not found.
+ *
+ * @since New in @VERSION_1_12_4
+ *
+ * @sa msg_header_replace_item(), msg_header_remove_item(),
+ * @Allow, @AllowEvents
+ */
+char const *msg_header_find_item(msg_common_t const *h, char const *item)
+{
+ if (h && h->h_class->hc_params) {
+ char const * const * items =
+ *(char const * const * const *)
+ ((char *)h + h->h_class->hc_params);
+
+ if (items)
+ for (; *items; items++) {
+ if (strcmp(item, *items) == 0) {
+ return *items;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+
+/**Add an item to a header.
+ *
+ * This function treats a #msg_header_t as set of C strings. The @a item is
+ * a C string. If no identical string is found from the list, it is added to
+ * the list.
+ *
+ * The shortcuts, if any, to item values are updated accordingly.
+ *
+ * @param home memory home used to re-allocate list in header
+ * @param h pointer to a header
+ * @param item item to be removed
+ *
+ * @retval 0 if item was added
+ * @retval 1 if item was replaced
+ * @retval -1 upon an error
+ *
+ * @since New in @VERSION_1_12_4.
+ *
+ * @sa msg_header_remove_item(), @Allow, @AllowEvents,
+ * msg_header_replace_param(), msg_header_remove_param(),
+ * #msg_common_t, #msg_header_t, #msg_list_t
+ * #msg_hclass_t, msg_hclass_t::hc_params
+ */
+int msg_header_replace_item(su_home_t *home,
+ msg_common_t *h,
+ char const *item)
+{
+ return msg_header_param_modify(home, h, item,
+ 1 /* string item */,
+ 0 /* replace */);
+}
+
+/**Remove an item from a header.
+ *
+ * This function treats a #msg_header_t as set of C strings. The @a item is a
+ * C string. If identical string is found from the list, it is removed.
+ *
+ * The shortcuts, if any, to item values are updated accordingly.
+ *
+ * @param h pointer to a header
+ * @param name item to be removed
+ *
+ * @retval 0 if item was added
+ * @retval 1 if item was replaced
+ * @retval -1 upon an error
+ *
+ * @since New in @VERSION_1_12_4.
+ *
+ * @sa msg_header_replace_item(), @Allow, @AllowEvents,
+ * msg_header_replace_param(), msg_header_remove_param(),
+ * #msg_common_t, #msg_header_t, #msg_list_t
+ * #msg_hclass_t, msg_hclass_t::hc_params
+ */
+int msg_header_remove_item(msg_common_t *h, char const *name)
+{
+ return msg_header_param_modify(NULL, h, name,
+ 1 /* item */,
+ -1 /* remove */);
+}
+
+
+/** Find a parameter from a parameter list.
+ *
+ * Searches for given parameter @a token from the parameter list. If
+ * parameter is found, it returns a non-NULL pointer to the parameter value.
+ * If there is no value for the parameter (the parameter is of form "name"
+ * or "name="), the returned pointer points to a NUL character.
+ *
+ * @param params list (or vector) of parameters
+ * @param token parameter name (with or without "=" sign)
+ *
+ * @return
+ * A pointer to parameter value, or NULL if parameter was not found.
+ */
+msg_param_t msg_params_find(msg_param_t const params[], msg_param_t token)
+{
+ if (params && token) {
+ size_t i, n = strcspn(token, "=");
+
+ assert(n > 0);
+
+ for (i = 0; params[i]; i++) {
+ msg_param_t param = params[i];
+ if (strncasecmp(param, token, n) == 0) {
+ if (param[n] == '=')
+ return param + n + 1;
+ else if (param[n] == 0)
+ return param + n;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/** Find a slot for parameter from a parameter list.
+ *
+ * Searches for given parameter @a token from the parameter list. If
+ * parameter is found, it returns a non-NULL pointer to the item containing
+ * the parameter.
+ *
+ * @param params list (or vector) of parameters
+ * @param token parameter name (with or without "=" sign)
+ *
+ * @return
+ * A pointer to parameter slot, or NULL if parameter was not found.
+ */
+msg_param_t *msg_params_find_slot(msg_param_t params[], msg_param_t token)
+{
+ if (params && token) {
+ int i;
+ size_t n = strlen(token);
+
+ assert(n > 0);
+
+ for (i = 0; params[i]; i++) {
+ msg_param_t param = params[i];
+ if (strncasecmp(param, token, n) == 0) {
+ if (param[n] == '=')
+ return params + i;
+ else if (param[n] == 0 || token[n - 1] == '=')
+ return params + i;
+ }
+ }
+
+ }
+
+ return NULL;
+}
+
+/** Replace or add a parameter from a list.
+ *
+ * A non-NULL parameter list must have been created by msg_params_d()
+ * or by msg_params_dup().
+ *
+ * @note This function does not duplicate @p param.
+ *
+ * @param home memory home
+ * @param inout_params pointer to pointer to parameter list
+ * @param param parameter to be replaced or added
+ *
+ * @retval 0 if parameter was added
+ * @retval 1 if parameter was replaced
+ * @retval -1 upon an error
+ */
+int msg_params_replace(su_home_t *home,
+ msg_param_t **inout_params,
+ msg_param_t param)
+{
+ msg_param_t *params;
+ size_t i, n;
+
+ assert(inout_params);
+
+ if (param == NULL || param[0] == '=' || param[0] == '\0')
+ return -1;
+
+ params = *inout_params;
+
+ n = strcspn(param, "=");
+
+ if (params) {
+ /* Existing list, try to replace or remove */
+ for (i = 0; params[i]; i++) {
+ msg_param_t maybe = params[i];
+
+ if (!(strncasecmp(maybe, param, n))) {
+ if (maybe[n] == '=' || maybe[n] == 0) {
+ params[i] = param;
+ return 1;
+ }
+ }
+ }
+ }
+
+ /* Not found on list */
+ return msg_params_add(home, inout_params, param);
+}
+
+/** Remove a parameter from a list.
+ *
+ * @retval 1 if parameter was removed
+ * @retval 0 if parameter was not found
+ * @retval -1 upon an error
+ */
+int msg_params_remove(msg_param_t *params, msg_param_t param)
+{
+ size_t i, n;
+
+ if (!params || !param || !param[0])
+ return -1;
+
+ n = strcspn(param, "=");
+ assert(n > 0);
+
+ for (i = 0; params[i]; i++) {
+ msg_param_t maybe = params[i];
+
+ if (strncasecmp(maybe, param, n) == 0) {
+ if (maybe[n] == '=' || maybe[n] == 0) {
+ /* Remove */
+ do {
+ params[i] = params[i + 1];
+ } while (params[i++]);
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/** Calculate number of parameters in a parameter list */
+size_t msg_params_length(char const * const * params)
+{
+ size_t len;
+
+ if (!params)
+ return 0;
+
+ for (len = 0; params[len]; len++)
+ ;
+
+ return len;
+}
+
+
+/**
+ * Add a parameter to a list.
+ *
+ * Add a parameter to the list; the list must have been created by @c
+ * msg_params_d() or by @c msg_params_dup() (or it may contain only @c
+ * NULL).
+ *
+ * @note This function does not duplicate @p param.
+ *
+ * @param home memory home
+ * @param inout_params pointer to pointer to parameter list
+ * @param param parameter to be added
+ *
+ * @retval 0 if parameter was added
+ * @retval -1 upon an error
+ */
+int msg_params_add(su_home_t *home,
+ msg_param_t **inout_params,
+ msg_param_t param)
+{
+ size_t n, m_before, m_after;
+ msg_param_t *p = *inout_params;
+
+ if (param == NULL)
+ return -1;
+
+ /* Count number of parameters */
+ for (n = 0; p && p[n]; n++)
+ ;
+
+ m_before = MSG_PARAMS_NUM(n + 1);
+ m_after = MSG_PARAMS_NUM(n + 2);
+
+ if (m_before != m_after || !p) {
+ p = su_alloc(home, m_after * sizeof(*p));
+ assert(p); if (!p) return -1;
+ if (n)
+ memcpy(p, *inout_params, n * sizeof(*p));
+ *inout_params = p;
+ }
+
+ p[n] = param;
+ p[n + 1] = NULL;
+
+ return 0;
+}
+
+static
+int msg_param_prune(msg_param_t const d[], msg_param_t p, unsigned prune)
+{
+ size_t i, nlen;
+
+ if (prune == 1)
+ nlen = strcspn(p, "=");
+ else
+ nlen = 0;
+
+ for (i = 0; d[i]; i++) {
+ if ((prune == 1 &&
+ strncasecmp(p, d[i], nlen) == 0
+ && (d[i][nlen] == '=' || d[i][nlen] == '\0'))
+ ||
+ (prune == 2 && strcasecmp(p, d[i]) == 0)
+ ||
+ (prune == 3 && strcmp(p, d[i]) == 0))
+ return 1;
+ }
+
+ return 0;
+}
+
+/**Join two parameter lists.
+ *
+ * The function @c msg_params_join() joins two parameter lists; the
+ * first list must have been created by @c msg_params_d() or by @c
+ * msg_params_dup() (or it may contain only @c NULL).
+ *
+ * @param home memory home
+ * @param dst pointer to pointer to destination parameter list
+ * @param src source list
+ * @param prune prune duplicates
+ * @param dup duplicate parameters in src list
+ *
+ * @par Pruning
+ * <table>
+ * <tr><td>0<td>do not prune</tr>
+ * <tr><td>1<td>prune parameters with identical names</tr>
+ * <tr><td>2<td>case-insensitive values</tr>
+ * <tr><td>3<td>case-sensitive values</tr>
+ * </table>
+ *
+ * @return
+ * @retval >= 0 when successful
+ * @retval -1 upon an error
+ */
+issize_t msg_params_join(su_home_t *home,
+ msg_param_t **dst,
+ msg_param_t const *src,
+ unsigned prune,
+ int dup)
+{
+ size_t n, m, n_before, n_after, pruned, total = 0;
+ msg_param_t *d = *dst;
+
+ if (prune > 3)
+ return -1;
+
+ if (src == NULL || *src == NULL)
+ return 0;
+
+ /* Count number of parameters */
+ for (n = 0; d && d[n]; n++)
+ ;
+
+ n_before = MSG_PARAMS_NUM(n + 1);
+
+ for (m = 0, pruned = 0; src[m]; m++) {
+ if (n > 0 && prune > 0 && msg_param_prune(d, src[m], prune)) {
+ pruned++;
+ if (prune > 1)
+ continue;
+ }
+ if (dup)
+ total += strlen(src[m]) + 1;
+ }
+
+ n_after = MSG_PARAMS_NUM(n + m - pruned + 1);
+
+ if (n_before != n_after || !d) {
+ d = su_alloc(home, n_after * sizeof(*d));
+ assert(d); if (!d) return -1;
+ if (n)
+ memcpy(d, *dst, n * sizeof(*d));
+ *dst = d;
+ }
+
+ for (m = 0; src[m]; m++) {
+ if (pruned && msg_param_prune(d, src[m], prune)) {
+ pruned--;
+ if (prune > 1)
+ continue;
+ }
+
+ if (dup)
+ d[n++] = su_strdup(home, src[m]); /* XXX */
+ else
+ d[n++] = src[m];
+ }
+
+ d[n] = NULL;
+
+ return 0;
+}
+
+/**Join header item lists.
+ *
+ * Join items from a source header to the destination header. The item are
+ * compared with the existing ones. If a match is found, it is not added to
+ * the list. If @a duplicate is true, the entries are duplicated while they
+ * are added to the list.
+ *
+ * @param home memory home
+ * @param dst destination header
+ * @param src source header
+ * @param duplicate if true, allocate and copy items that are added
+ *
+ * @return
+ * @retval >= 0 when successful
+ * @retval -1 upon an error
+ *
+ * @NEW_1_12_5.
+ */
+int msg_header_join_items(su_home_t *home,
+ msg_common_t *dst,
+ msg_common_t const *src,
+ int duplicate)
+{
+ size_t N, m, M, i, n_before, n_after, total;
+ char *dup = NULL;
+ msg_param_t *d, **dd, *s;
+ msg_param_t t, *temp, temp0[16];
+ size_t *len, len0[(sizeof temp0)/(sizeof temp0[0])];
+ msg_update_f *update = NULL;
+
+ if (dst == NULL || dst->h_class->hc_params == 0 ||
+ src == NULL || src->h_class->hc_params == 0)
+ return -1;
+
+ s = *(msg_param_t **)((char *)src + src->h_class->hc_params);
+ if (s == NULL)
+ return 0;
+
+ for (M = 0; s[M]; M++);
+
+ if (M == 0)
+ return 0;
+
+ if (M <= (sizeof temp0) / (sizeof temp0[0])) {
+ temp = temp0, len = len0;
+ }
+ else {
+ temp = malloc(M * (sizeof *temp) + M * (sizeof *len));
+ if (!temp) return -1;
+ len = (void *)(temp + M);
+ }
+
+ dd = (msg_param_t **)((char *)dst + dst->h_class->hc_params);
+ d = *dd;
+
+ for (N = 0; d && d[N]; N++);
+
+ for (m = 0, M = 0, total = 0; s[m]; m++) {
+ t = s[m];
+ for (i = 0; i < N; i++)
+ if (strcmp(t, d[i]) == 0)
+ break;
+ if (i < N)
+ continue;
+
+ for (i = 0; i < M; i++)
+ if (strcmp(t, temp[i]) == 0)
+ break;
+ if (i < M)
+ continue;
+
+ temp[M] = t;
+ len[M] = strlen(t);
+ total += len[M++] + 1;
+ }
+
+ if (M == 0)
+ goto success;
+
+ dup = su_alloc(home, total); if (!dup) goto error;
+
+ n_before = MSG_PARAMS_NUM(N + 1);
+ n_after = MSG_PARAMS_NUM(N + M + 1);
+
+ if (d == NULL || n_before != n_after) {
+ d = su_alloc(home, n_after * sizeof(*d)); if (!d) goto error;
+ if (N)
+ memcpy(d, *dd, N * sizeof(*d));
+ *dd = d;
+ }
+
+ update = dst->h_class->hc_update;
+
+ for (m = 0; m < M; m++) {
+ d[N++] = memcpy(dup, temp[m], len[m] + 1);
+
+ if (update)
+ update(dst, dup, len[m], dup + len[m]);
+
+ dup += len[m] + 1;
+ }
+
+ d[N] = NULL;
+
+ success:
+ if (temp != temp0)
+ free(temp);
+ return 0;
+
+ error:
+ if (temp != temp0)
+ free(temp);
+ su_free(home, dup);
+ return -1;
+}
+
+/**Compare parameter lists.
+ *
+ * Compares parameter lists.
+ *
+ * @param a pointer to a parameter list
+ * @param b pointer to a parameter list
+ *
+ * @retval an integer less than zero if @a is less than @a b
+ * @retval an integer zero if @a match with @a b
+ * @retval an integer greater than zero if @a is greater than @a b
+ */
+int msg_params_cmp(char const * const a[], char const * const b[])
+{
+ int c;
+ size_t nlen;
+
+ if (a == NULL || b == NULL)
+ return (a != NULL) - (b != NULL);
+
+ for (;;) {
+ if (*a == NULL || *b == NULL)
+ return (*a != NULL) - (*b != NULL);
+ nlen = strcspn(*a, "=");
+ if ((c = strncasecmp(*a, *b, nlen)))
+ return c;
+ if ((c = strcmp(*a + nlen, *b + nlen)))
+ return c;
+ a++, b++;
+ }
+}
+
+
+/** Unquote string
+ *
+ * Duplicates the string @a q in unquoted form.
+ */
+char *msg_unquote_dup(su_home_t *home, char const *q)
+{
+ char *d;
+ size_t total, n, m;
+
+ /* First, easy case */
+ if (q[0] == '"')
+ q++;
+ n = strcspn(q, "\"\\");
+ if (q[n] == '\0' || q[n] == '"')
+ return su_strndup(home, q, n);
+
+ /* Hairy case - backslash-escaped chars */
+ total = n;
+ for (;;) {
+ if (q[n] == '\0' || q[n] == '"' || q[n + 1] == '\0')
+ break;
+ m = strcspn(q + n + 2, "\"\\");
+ total += m + 1;
+ n += m + 2;
+ }
+
+ if (!(d = su_alloc(home, total + 1)))
+ return NULL;
+
+ for (n = 0;;) {
+ m = strcspn(q, "\"\\");
+ memcpy(d + n, q, m);
+ n += m, q += m;
+ if (q[0] == '\0' || q[0] == '"' || q[1] == '\0')
+ break;
+ d[n++] = q[1];
+ q += 2;
+ }
+ assert(total == n);
+ d[n] = '\0';
+
+ return d;
+}
+
+/** Unquote string */
+char *msg_unquote(char *dst, char const *s)
+{
+ int copy = dst != NULL;
+ char *d = dst;
+
+ if (*s++ != '"')
+ return NULL;
+
+ for (;;) {
+ size_t n = strcspn(s, "\"\\");
+ if (copy)
+ memmove(d, s, n);
+ s += n;
+ d += n;
+
+ if (*s == '\0')
+ return NULL;
+ else if (*s == '"') {
+ if (copy) *d = '\0';
+ return dst;
+ }
+ else {
+ /* Copy quoted char */
+ if ((copy ? (*d++ = *++s) : *++s) == '\0')
+ return NULL;
+ s++;
+ }
+ }
+}
+
+/** Quote string */
+issize_t msg_unquoted_e(char *b, isize_t bsiz, char const *s)
+{
+ char *begin = b;
+ char *end = b + bsiz;
+
+ if (b && b + 1 < end)
+ *b = '"';
+ b++;
+
+ for (;*s;) {
+ size_t n = strcspn(s, "\"\\");
+
+ if (n == 0) {
+ if (b && b + 2 < end)
+ b[0] = '\\', b[1] = s[0];
+ b += 2;
+ s++;
+ }
+ else {
+ if (b && b + n < end)
+ memcpy(b, s, n);
+ b += n;
+ s += n;
+ }
+ }
+
+ if (b && b + 1 < end)
+ *b = '"';
+ b++;
+
+ return b - begin;
+}
+
+
+/** Calculate a simple hash over a string. */
+unsigned long msg_hash_string(char const *id)
+{
+ unsigned long hash = 0;
+
+ if (id)
+ for (; *id; id++) {
+ hash += (unsigned)*id;
+ hash *= 38501U;
+ }
+ else
+ hash *= 38501U;
+
+ if (hash == 0)
+ hash = (unsigned long)-1;
+
+ return hash;
+}
+
+
+/** Calculate the size of a duplicate of a header structure. */
+isize_t msg_header_size(msg_header_t const *h)
+{
+ if (h == NULL || h == MSG_HEADER_NONE)
+ return 0;
+ else
+ return h->sh_class->hc_dxtra(h, h->sh_class->hc_size);
+}
+
+
+/** Encode a message to the buffer.
+ *
+ * The function msg_encode_e encodes a message to a given buffer.
+ * It returns the length of the message to be encoded, even if the
+ * buffer is too small (just like snprintf() is supposed to do).
+ *
+ * @param b buffer (may be NULL)
+ * @param size size of buffer
+ * @param mo public message structure (#sip_t, #http_t)
+ * @param flags see #
+ */
+issize_t msg_object_e(char b[], isize_t size, msg_pub_t const *mo, int flags)
+{
+ size_t rv = 0;
+ ssize_t n;
+ msg_header_t const *h;
+
+ if (mo->msg_request)
+ h = mo->msg_request;
+ else
+ h = mo->msg_status;
+
+ for (; h; h = h->sh_succ) {
+ n = msg_header_e(b, size, h, flags);
+ if (n < 0)
+ return -1;
+ if ((size_t)n < size)
+ b += n, size -= n;
+ else
+ b = NULL, size = 0;
+ rv += n;
+ }
+
+ return rv;
+}
+
+/** Encode header contents. */
+issize_t msg_header_field_e(char b[], isize_t bsiz, msg_header_t const *h, int flags)
+{
+ assert(h); assert(h->sh_class);
+
+ return h->sh_class->hc_print(b, bsiz, h, flags);
+}
+
+/** Get offset of header @a h from structure @a mo. */
+msg_header_t **
+msg_header_offset(msg_t const *msg, msg_pub_t const *mo, msg_header_t const *h)
+{
+ if (h == NULL || h->sh_class == NULL)
+ return NULL;
+
+ return msg_hclass_offset(msg->m_class, mo, h->sh_class);
+}
+
+/**Get a header from the public message structure.
+ *
+ * Gets a pointer to header from a message structure.
+ *
+ * @param pub public message structure from which header is obtained
+ * @param hc header class
+ */
+msg_header_t *
+msg_header_access(msg_pub_t const *pub, msg_hclass_t *hc)
+{
+ msg_header_t * const * hh;
+
+ if (pub == NULL || hc == NULL)
+ return NULL;
+
+ hh = msg_hclass_offset((void *)pub->msg_ident, (msg_pub_t *)pub, hc);
+
+ if (hh)
+ return *hh;
+ else
+ return NULL;
+}
+
+#include <sofia-sip/su_uniqueid.h>
+
+/** Generates a random token.
+ *
+ */
+issize_t msg_random_token(char token[], isize_t tlen,
+ void const *rmemp, isize_t rsize)
+{
+ uint32_t random = 0, rword;
+ uint8_t rbyte;
+ uint8_t const *rmem = rmemp;
+ size_t i;
+ ssize_t n;
+
+ static char const token_chars[33] =
+ /* Create aesthetically pleasing raNDom capS LooK */
+ "aBcDeFgHjKmNpQrStUvXyZ0123456789";
+
+ if (rmem == NULL && rsize == 0)
+ rsize = UINT_MAX;
+
+ if (rsize == 0) {
+ if (token && tlen > 0)
+ strcpy(token, "+");
+ return 1;
+ }
+
+ if (token == NULL) {
+ if (rsize >= tlen * 5 / 8)
+ return tlen;
+ else
+ return rsize / 5 * 8;
+ }
+
+ for (i = 0, n = 0; i < tlen;) {
+ if (n < 5) {
+ if (rsize == 0)
+ ;
+ else if (rmem) {
+ rbyte = *rmem++, rsize--;
+ random = random | (rbyte << n);
+ n += 8;
+ } else {
+ rword = su_random();
+ random = (rword >> 13) & 31;
+ n = 6;
+ }
+ }
+
+ token[i] = token_chars[random & 31];
+ random >>= 5;
+ i++, n -= 5;
+
+ if (n < 0 || (n == 0 && rsize == 0))
+ break;
+ }
+
+ token[i] = 0;
+
+ return i;
+}
+
+
+/** Parse a message.
+ *
+ * Parse a text message with parser @a mc. The @a data is copied and it is
+ * not modified or referenced by the parsed message.
+ *
+ * @par Example
+ * Parse a SIP message fragment (e.g., payload of NOTIFY sent in response to
+ * REFER):
+ * @code
+ * msg_t *m = msg_make(sip_default_mclass(), 0, pl->pl_data, pl->pl_len);
+ * sip_t *frag = sip_object(m);
+ * @endcode
+ *
+ * @param mc message class (parser table)
+ * @param flags message flags (see #msg_flg_user)
+ * @param data message text
+ * @param len size of message text (if -1, use strlen(data))
+ *
+ * @retval A pointer to a freshly allocated and parsed message.
+ *
+ * Upon parsing error, the header structure may be left incomplete. The
+ * #MSG_FLG_ERROR is set in @a msg_object(msg)->msg_flags.
+ *
+ * @since New in @VERSION_1_12_4
+ *
+ * @sa msg_as_string(), msg_extract()
+ */
+msg_t *msg_make(msg_mclass_t const *mc, int flags,
+ void const *data, ssize_t len)
+{
+ msg_t *msg;
+ msg_iovec_t iovec[2];
+
+ if (len == -1)
+ len = strlen(data);
+ if (len == 0)
+ return NULL;
+
+ msg = msg_create(mc, flags);
+
+ su_home_preload(msg_home(msg), 1, len + 1024);
+
+ if (msg_recv_iovec(msg, iovec, 2, len, 1) < 0) {
+ perror("msg_recv_iovec");
+ }
+ assert((ssize_t)iovec->mv_len == len);
+ memcpy(iovec->mv_base, data, len);
+ msg_recv_commit(msg, len, 1);
+
+ if (msg_extract(msg) < 0)
+ msg->m_object->msg_flags |= MSG_FLG_ERROR;
+
+ return msg;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_tag.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_tag.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,371 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE msg_tag.c Message tag classes
+ *
+ * @author Pekka Pessi <Pekka.Pessi at 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
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,173 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#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 at 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 */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_addr.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_addr.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,97 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#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 at 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) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_buffer.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_buffer.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,57 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#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 at 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 */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_date.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_date.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,76 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#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 at 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) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_header.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_header.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,304 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#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 at 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) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mclass.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mclass.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,148 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#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 at 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) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mclass_hash.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mclass_hash.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,77 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#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 at 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 */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mime.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mime.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,242 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#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 at 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 */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mime_protos.h.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mime_protos.h.in Thu Dec 21 01:30:28 2006
@@ -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 at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#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 at 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) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_parser.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_parser.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,309 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#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 at 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 */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_protos.h.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_protos.h.in Thu Dec 21 01:30:28 2006
@@ -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 at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#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 at 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) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_tag_class.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_tag_class.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,65 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#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 at 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) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_types.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_types.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,301 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#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 at 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 */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/test_class.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/test_class.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,413 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup test_msg
+ * @file test_class.c
+ *
+ * Message class for testing parser and transports.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at 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;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/test_class.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/test_class.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,165 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#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 at 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) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/test_msg.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/test_msg.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1718 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup test_msg
+ *
+ * @CFILE test_msg.c
+ *
+ * Torture tests for message parser.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Aug 21 15:18:26 2001 ppessi
+ */
+
+#include "config.h"
+
+#include "test_class.h"
+#include "test_protos.h"
+#include "sofia-sip/msg.h"
+#include "sofia-sip/msg_addr.h"
+#include "sofia-sip/msg_date.h"
+#include "sofia-sip/msg_parser.h"
+#include "sofia-sip/bnf.h"
+#include "sofia-sip/msg_mclass.h"
+#include "sofia-sip/msg_mclass_hash.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <stdio.h>
+#include <assert.h>
+
+static int test_flags = 0;
+#define TSTFLAGS test_flags
+
+#include <sofia-sip/tstdef.h>
+
+char const name[] = "test_msg";
+
+void usage(void)
+{
+ fprintf(stderr, "usage: %s [-v]\n", name);
+}
+
+static int msg_time_test(void)
+{
+ char buf[32];
+ char const *s;
+ char date1900[] = "Mon, 1 Jan 1900 00:00:00 GMT";
+ char date1900_1[] = "Mon, 01 Jan 1900 00:00:01 GMT";
+ char date822[] = "Thursday, 01-Jan-70 00:00:01 GMT";
+ char date822b[] = "Wednesday, 09-Nov-99 23:12:40 GMT";
+ char date822c[] = "Wednesday, 01-Sep-04 23:12:40 GMT";
+ char date2822[] = "Monday, 01-Jan-1900 00:00:01 GMT";
+ char dateasc[] = "Mon Jan 1 00:00:01 1900";
+ msg_time_t now = msg_now(), date = now;
+
+ BEGIN();
+ s = date1900;
+ TEST_1(msg_date_d(&s, &date) == 0);
+ TEST(date, 0);
+ TEST_SIZE(msg_date_e(buf, sizeof(buf), date), strlen(date1900));
+ TEST_SIZE(msg_date_e(buf, sizeof(buf), 1), strlen(date1900_1));
+ TEST_S(buf, date1900_1);
+
+ s = date822;
+ TEST_1(msg_date_d(&s, &date) == 0);
+ TEST(date, 2208988801U);
+
+ s = date822b;
+ TEST_1(msg_date_d(&s, &date) == 0);
+ TEST(date, 3151177960U);
+
+ s = date822c;
+ TEST_1(msg_date_d(&s, &date) == 0);
+ TEST(date, 3303069160U);
+
+ s = date2822;
+ TEST_1(msg_date_d(&s, &date) == 0);
+ TEST(date, 1);
+
+ s = dateasc;
+ TEST_1(msg_date_d(&s, &date) == 0);
+ TEST(date, 1);
+
+ {
+ char error1[] = "Mo";
+ char error2[] = "Mon, 1 Jan 19100 00:00:00 GMT";
+ char error3[] = "Mon, 1 Jan 1900 00:00:";
+ char error4[] = "Mon, 1 Jan 1900 25:00:00 GMT";
+ char noerror5[] = "Mon, 1 Jan 1899 24:00:00 GMT";
+ char error6[] = "Mon, 30 Feb 1896 23:59:59 GMT";
+ char noerror7[] = "Mon, 29 Feb 1896 23:59:59 GMT";
+ char error8[] = "Mon, 32 Jan 1900 24:00:00 GMT";
+ char error9[] = "Mon, 27 Fev 1900 24:00:00 GMT";
+
+ s = error1; TEST_1(msg_date_d(&s, &date) < 0);
+ s = error2; TEST_1(msg_date_d(&s, &date) < 0);
+ s = error3; TEST_1(msg_date_d(&s, &date) < 0);
+ s = error4; TEST_1(msg_date_d(&s, &date) < 0);
+ s = noerror5; TEST_1(msg_date_d(&s, &date) == 0); TEST(date, 0);
+ s = error6; TEST_1(msg_date_d(&s, &date) < 0);
+ s = noerror7; TEST_1(msg_date_d(&s, &date) == 0); TEST(date, 0);
+ s = error8; TEST_1(msg_date_d(&s, &date) < 0);
+ s = error9; TEST_1(msg_date_d(&s, &date) < 0);
+ }
+
+ {
+ char error1[] = "4294967297";
+ char *s;
+ msg_numeric_t x[1];
+
+ memset(x, 0, sizeof (x));
+
+ TEST_1(msg_numeric_d(NULL, (msg_header_t *)x, s = error1, strlen(error1)) < 0);
+ }
+
+ END();
+ return 0;
+}
+
+static int addr_test(void)
+{
+ BEGIN();
+
+ /* It *will* fail. */
+ /* TEST(sizeof(socklen_t), sizeof(msg_addrlen(NULL))); */
+
+ END();
+}
+
+int test_header_parsing(void)
+{
+ BEGIN();
+
+ {
+ /* Test quoting/unquoting */
+ su_home_t home[1] = { SU_HOME_INIT(home) };
+ char *quoted = "\"foo \\b\\a\\r\\\"\\\\\"extra";
+ char *unquoted;
+
+ TEST_1(unquoted = msg_unquote_dup(home, quoted));
+ TEST_S(unquoted, "foo bar\"\\");
+
+ su_home_deinit(home);
+ }
+
+ {
+ /* Test parameter list */
+ su_home_t home[1] = { SU_HOME_INIT(home) };
+ msg_param_t const *params = NULL;
+ char str[] = ";uffe;duffe = \"entten\" ; doo = [::1] ", *s = str;
+ char const canonic[] = ";uffe;duffe=\"entten\";doo=[::1]";
+ char *end = str + strlen(str);
+ char b[sizeof(canonic) + 8];
+
+ TEST_1(msg_params_d(home, &s, ¶ms) >= 0);
+ TEST_1(params != 0);
+ TEST_P(s, end);
+ TEST_S(params[0], "uffe");
+ TEST_S(params[1], "duffe=\042entten\042");
+ TEST_S(params[2], "doo=[::1]");
+ TEST_1(params[3] == NULL);
+ TEST_SIZE(msg_params_e(NULL, 0, params), strlen(canonic));
+ TEST_SIZE(msg_params_e(b, sizeof(b), params), strlen(canonic));
+ TEST_S(b, canonic);
+
+ TEST_S(msg_params_find(params, "uffe"), "");
+ TEST_S(msg_params_find(params, "uffe="), "");
+ TEST_S(msg_params_find(params, "duffe"), "\"entten\"");
+ TEST_S(msg_params_find(params, "duffe="), "\"entten\"");
+ TEST_S(msg_params_find(params, "doo"), "[::1]");
+ TEST_S(msg_params_find(params, "doo="), "[::1]");
+
+ TEST(msg_params_remove((msg_param_t *)params, "uffe"), 1);
+ TEST_S(params[0], "duffe=\042entten\042");
+ TEST_S(params[1], "doo=[::1]");
+ TEST_1(params[2] == NULL);
+
+ TEST(msg_params_remove((msg_param_t *)params, "doo"), 1);
+ TEST_S(params[0], "duffe=\042entten\042");
+ TEST_1(params[1] == NULL);
+
+ su_home_deinit(home);
+ }
+
+ {
+ /* Test that parameter list of length MSG_PARAMS_N is handled correctly */
+ su_home_t home[1] = { SU_HOME_INIT(home) };
+ msg_param_t const *params = NULL;
+ char list1[] = ";one;two;three;four;five;six;seven;eight", *s = list1;
+ char list2[] = ";one;two;three;four;five;six;seven";
+ char list3[] = ";one;two;three;four;five;six;seven, humppaa";
+ char *end3 = strchr(list3, ',');
+ char list4[] = ";one;two;three;four;five;six;seven;eight;nine;ten"
+ ";eleven;twelve;thirteen;fourteen;fiveteen;sixteen";
+ char list5[] = ";one;two;three;four;five;six;seven;eight;nine;ten"
+ ";eleven;twelve;thirteen;fourteen;fiveteen";
+ char list6[] = ";one;two;three;four;five;six;seven;eight;nine;ten"
+ ";eleven;twelve;thirteen;fourteen;fiveteen;sixteen;seventeen";
+ int i;
+
+ TEST_1(msg_params_d(home, &s, ¶ms) >= 0);
+ TEST_1(params);
+ for (i = 0; i < 8; i++)
+ TEST_1(params[i]);
+ TEST_1(params[8] == NULL);
+
+ s = list2, params = NULL;
+ TEST_1(msg_params_d(home, &s, ¶ms) >= 0);
+ TEST_1(params);
+ for (i = 0; i < 7; i++)
+ TEST_1(params[i]);
+ TEST_1(params[7] == NULL);
+
+ s = list3; params = NULL;
+ TEST_1(msg_params_d(home, &s, ¶ms) >= 0);
+ TEST_S(s, end3);
+ TEST_1(params);
+ for (i = 0; i < 7; i++)
+ TEST_1(params[i]);
+ TEST_1(params[7] == NULL);
+
+ s = list4; params = NULL;
+ TEST_1(msg_params_d(home, &s, ¶ms) >= 0);
+ TEST_1(params);
+ for (i = 0; i < 16; i++)
+ TEST_1(params[i]);
+ TEST_1(params[16] == NULL);
+
+ s = list5; params = NULL;
+ TEST_1(msg_params_d(home, &s, ¶ms) >= 0);
+ TEST_1(params);
+ for (i = 0; i < 15; i++)
+ TEST_1(params[i]);
+ TEST_1(params[15] == NULL);
+
+ s = list6 ; params = NULL;
+ TEST_1(msg_params_d(home, &s, ¶ms) >= 0);
+ TEST_1(params);
+ for (i = 0; i < 17; i++)
+ TEST_1(params[i]);
+ TEST_1(params[17] == NULL);
+
+ su_home_deinit(home);
+ }
+
+ {
+ /* Test parameter lists */
+ su_home_t home[1] = { SU_HOME_INIT(home) };
+ unsigned i, j;
+
+ msg_param_t const *p = NULL;
+ char *master = ";0", *list, *end;
+
+ for (i = 1; i < 256; i++) {
+ master = su_sprintf(home, "%s; %u", master, i); TEST_1(master);
+ list = end = su_strdup(home, master);
+ TEST_1(msg_params_d(home, &end, &p) >= 0);
+ TEST_S(end, "");
+ TEST_1(p);
+ for (j = 0; j <= i; j++) {
+ char number[10];
+ snprintf(number, sizeof number, "%u", j);
+ TEST_S(p[j], number);
+ }
+ TEST_1(p[i + 1] == NULL);
+ su_free(home, list);
+ su_free(home, (void *)p), p = NULL;
+ }
+
+ su_home_deinit(home);
+ }
+
+ {
+ /* Test comma-separated list */
+ su_home_t home[1] = { SU_HOME_INIT(home) };
+
+ msg_list_t k1[1] = {{{{ 0 }}}};
+ char list1[] = "foo, bar, baz zi \"baz\"";
+
+ TEST_1(msg_list_d(home, (msg_header_t *)k1, list1, strlen(list1)) >= 0);
+ TEST_1(k1->k_items);
+ TEST_S(k1->k_items[0], "foo");
+ TEST_S(k1->k_items[1], "bar");
+ TEST_S(k1->k_items[2], "baz zi\042baz\042");
+ TEST_1(!k1->k_items[3]);
+
+ su_home_deinit(home);
+ }
+
+ {
+ /* Test that list of length MSG_PARAMS_N is handled correctly */
+ su_home_t home[1] = { SU_HOME_INIT(home) };
+ msg_list_t k2[1] = {{{{ 0 }}}};
+ char list2[] = "one, two, three, four, five, six, seven, eight";
+
+ TEST_1(
+ msg_list_d(home, (msg_header_t *)k2, list2, strlen(list2)) >= 0);
+ TEST_1(k2->k_items);
+ TEST_1(k2->k_items[7]);
+ TEST_1(k2->k_items[8] == NULL);
+
+ su_home_deinit(home);
+ }
+
+ {
+ /* Test that list longer than MSG_PARAMS_N is handled correctly */
+ su_home_t home[1] = { SU_HOME_INIT(home) };
+ msg_list_t k3[1] = {{{{ 0 }}}};
+ char list3[] = "one, two, three, four, five, six, seven, eight, nine";
+
+ TEST_1(
+ msg_list_d(home, (msg_header_t *)k3, list3, strlen(list3)) >= 0);
+ TEST_1(k3->k_items);
+ TEST_1(k3->k_items[7]);
+ TEST_1(k3->k_items[8]);
+ TEST_1(k3->k_items[9] == NULL);
+
+ su_home_deinit(home);
+ }
+
+ {
+ /* Test that long lists are handled correctly */
+ su_home_t home[1] = { SU_HOME_INIT(home) };
+
+ msg_param_t *k = NULL;
+ char *s;
+ char list1[] = "one, two, three, four, five, six, seven, eight";
+ char list2[] = "one, two, three, four, five, six, seven, eight";
+ char list3[] = "one, two, three, four, five, six, seven, eight";
+ char list4[] = "one, two, three, four, five, six, seven, eight, nine";
+
+ s = list1; TEST_1(msg_commalist_d(home, &s, &k, msg_token_scan) >= 0);
+ TEST_1(k);
+ TEST_1(k[7]);
+ TEST_1(k[8] == NULL);
+
+ s = list2; TEST_1(msg_commalist_d(home, &s, &k, msg_token_scan) >= 0);
+ s = list3; TEST_1(msg_commalist_d(home, &s, &k, msg_token_scan) >= 0);
+ s = list4; TEST_1(msg_commalist_d(home, &s, &k, msg_token_scan) >= 0);
+
+ su_home_deinit(home);
+ }
+
+ {
+ /* Test parameter lists */
+ su_home_t home[1] = { SU_HOME_INIT(home) };
+ unsigned i, j;
+
+ msg_param_t *p = NULL;
+ char *master = "0", *list, *end;
+
+ for (i = 1; i < 256; i++) {
+ master = su_sprintf(home, "%s, %u", master, i); TEST_1(master);
+ list = end = su_strdup(home, master);
+ TEST_1(msg_commalist_d(home, &end, &p, msg_token_scan) >= 0);
+ TEST_S(end, "");
+ TEST_1(p);
+ for (j = 0; j <= i; j++) {
+ char number[10];
+ snprintf(number, sizeof number, "%u", j);
+ TEST_S(p[j], number);
+ }
+ TEST_1(p[i + 1] == NULL);
+ su_free(home, list);
+ su_free(home, (void *)p), p = NULL;
+ }
+
+ su_home_deinit(home);
+ }
+
+ {
+ /* Test that errors in lists are handled correctly */
+ su_home_t home[1] = { SU_HOME_INIT(home) };
+
+ msg_param_t *k = NULL;
+ char *s;
+ char list1[] = "one, two, three, four, five, six, seven, foo=\"eight";
+ char list2[] = "one, two, three,,@,$ four, five, six, seven, eight";
+
+ s = list1; TEST_1(msg_commalist_d(home, &s, &k, NULL) < 0);
+ TEST_1(k == NULL);
+
+ s = list2; TEST_1(msg_commalist_d(home, &s, &k, msg_token_scan) < 0);
+
+ su_home_deinit(home);
+ }
+
+ {
+ /* Test empty parameter list */
+ su_home_t home[1] = { SU_HOME_INIT(home) };
+
+ msg_list_t k4[1] = {{{{ 0 }}}};
+ char list4[] = ", ,\t,\r\n\t, , ";
+
+ TEST_1(
+ msg_list_d(home, (msg_header_t *)k4, list4, strlen(list4)) >= 0);
+ TEST_1(k4->k_items == NULL);
+
+ su_home_deinit(home);
+ }
+
+ {
+ /* Test authentication headers */
+ su_home_t home[1] = { SU_HOME_INIT(home) };
+ msg_auth_t au[1] = {{{{ 0 }}}};
+ char s[] = "Basic foo = \"bar==\" ,, bar=baari,"
+ "baz=\"bof,\\\\ \\\" baff\", base\t64/ - is== ,,";
+
+ TEST_1(msg_auth_d(home, (msg_header_t *)au, s, strlen(s)) >= 0);
+ TEST_S(au->au_scheme, "Basic");
+ TEST_1(au->au_params);
+ TEST_S(au->au_params[0], "foo=\042bar==\042");
+ TEST_S(au->au_params[1], "bar=baari");
+ TEST_S(au->au_params[2], "baz=\042bof,\\\\ \\\042 baff\042");
+ TEST_S(au->au_params[3], "base 64/- is==");
+ TEST_1(!au->au_params[4]);
+
+ su_home_deinit(home);
+ }
+
+ /* Test that msg_*_format() works */
+ {
+ su_home_t home[1] = { SU_HOME_INIT(home) };
+
+ msg_content_type_t *c;
+
+ c = msg_content_type_format(home, "%s/%s;%s;%s;%s;%s;%s;%s",
+ "text", "plain",
+ "charset=iso-8859-15",
+ "format=flowed",
+ "q=0.999",
+ "msg-size=782572564",
+ "name-space-url=\"http://www.nokia.com/foo\"",
+ "foo=bar");
+
+ su_home_deinit(home);
+ }
+
+ {
+ /* Test parameter handling */
+ su_home_t home[1] = { SU_HOME_INIT(home) };
+ msg_content_encoding_t *ce;
+
+ ce = msg_content_encoding_make(home, "zip, zap, zup, lz, zl, zz, ll");
+ TEST_1(ce);
+ TEST_S(msg_header_find_param(ce->k_common, "zz"), "");
+ TEST_S(msg_header_find_item(ce->k_common, "zz"), "zz");
+ TEST_P(msg_header_find_param(ce->k_common, "k"), NULL);
+ TEST(msg_header_add_param(home, ce->k_common, "zip"), 0);
+ TEST(msg_header_remove_param(ce->k_common, "zip"), 1);
+ TEST_S(msg_header_find_param(ce->k_common, "zip"), "");
+ TEST(msg_header_remove_param(ce->k_common, "zip"), 1);
+ TEST_P(msg_header_find_param(ce->k_common, "zip"), NULL);
+ TEST(msg_header_remove_param(ce->k_common, "zip"), 0);
+ TEST(msg_header_replace_param(home, ce->k_common, "zip=zap"), 0);
+ TEST_S(msg_header_find_param(ce->k_common, "zip=1"), "zap");
+ TEST(msg_header_replace_param(home, ce->k_common, "zip=zup"), 1);
+ TEST_S(msg_header_find_param(ce->k_common, "zip"), "zup");
+
+ su_home_deinit(home);
+ }
+
+
+ END();
+}
+
+int hash_test(void)
+{
+ int i, j, hash = 0;
+ msg_mclass_t const *mc = msg_test_mclass;
+ msg_hclass_t *hc;
+
+ BEGIN();
+
+ for (i = 0; i < mc->mc_hash_size; i++) {
+ hc = mc->mc_hash[i].hr_class;
+ if (hc == NULL)
+ continue;
+
+ hash = msg_header_name_hash(hc->hc_name, NULL);
+ TEST(hash, hc->hc_hash);
+
+ /* Cross-check hashes */
+ for (j = i + 1; j < mc->mc_hash_size; j++) {
+ if (mc->mc_hash[j].hr_class == NULL)
+ continue;
+ if (hc->hc_hash == mc->mc_hash[j].hr_class->hc_hash)
+ fprintf(stderr, "\t%s and %s have same hash\n",
+ hc->hc_name, mc->mc_hash[j].hr_class->hc_name);
+ TEST_1(hc->hc_hash != mc->mc_hash[j].hr_class->hc_hash);
+ }
+ }
+
+ END();
+}
+
+msg_t *read_msg(char const buffer[])
+{
+ return msg_make(msg_test_mclass, MSG_DO_EXTRACT_COPY, buffer, -1);
+}
+
+/**Check if header chain contains any loops.
+ *
+ * @return
+ * Return 0 if no loop, -1 otherwise.
+ */
+static
+int msg_chain_loop(msg_header_t const *h)
+{
+ msg_header_t const *h2;
+
+ if (!h) return 0;
+
+ for (h2 = h->sh_succ; h && h2 && h2->sh_succ; h = h->sh_succ) {
+ if (h == h2 || h == h2->sh_succ)
+ return 1;
+
+ h2 = h2->sh_succ->sh_succ;
+
+ if (h == h2)
+ return 1;
+ }
+
+ return 0;
+}
+
+/** Check header chain consistency.
+ *
+ * @return
+ * Return 0 if consistent, number of errors otherwise.
+ */
+static
+int msg_chain_errors(msg_header_t const *h)
+{
+ if (msg_chain_loop(h))
+ return -1;
+
+ for (; h; h = h->sh_succ) {
+ if (h->sh_succ && h->sh_succ->sh_prev != &h->sh_succ)
+ return -1;
+ if (h->sh_prev && h != (*h->sh_prev))
+ return -1;
+ }
+
+ return 0;
+}
+
+int test_msg_parsing(void)
+{
+ msg_t *msg, *orig;
+ su_home_t *home;
+ msg_test_t *tst, *otst;
+ msg_request_t *request;
+ msg_status_t *status;
+ msg_content_location_t *location;
+ msg_content_language_t *language;
+ msg_accept_language_t *se;
+ msg_separator_t *separator;
+ msg_payload_t *payload;
+
+ BEGIN();
+
+ msg = read_msg("GET a-life HTTP/1.1" CRLF
+ "Content-Length: 6" CRLF
+ "Accept-Language: en;q=0.8, fi, se ; q = 0.6" CRLF
+ "Foo: bar" CRLF
+ CRLF
+ "test" CRLF);
+
+ home = msg_home(msg);
+ tst = msg_test_public(msg);
+
+ TEST_1(msg);
+ TEST_1(home);
+ TEST_1(tst);
+
+ TEST_P(tst->msg_error, NULL);
+
+ TEST_1(tst->msg_accept_language);
+
+ TEST_1(status = msg_status_make(home, "HTTP/1.1 200 Ok"));
+ TEST(msg_header_insert(msg, (msg_pub_t *)tst, (msg_header_t *)status), 0);
+ TEST_P(tst->msg_status, status); TEST_P(tst->msg_request, NULL);
+
+ TEST_1(request = msg_request_make(home, "GET a-wife HTTP/1.0"));
+ TEST(msg_header_insert(msg, (msg_pub_t *)tst, (msg_header_t *)request), 0);
+ TEST_P(tst->msg_request, request); TEST_P(tst->msg_status, NULL);
+
+ TEST_1(separator = msg_separator_make(home, "\r\n"));
+ TEST(msg_header_insert(msg, (msg_pub_t *)tst, (msg_header_t *)separator), 0);
+ TEST_P(tst->msg_separator, separator);
+ TEST_P(separator->sep_common->h_succ, tst->msg_payload);
+
+ /* Try to add a new payload */
+ TEST_1(payload = msg_payload_make(home, "foofaa\r\n"));
+ TEST(msg_header_insert(msg, (msg_pub_t *)tst, (msg_header_t *)payload), 0);
+ /* It is appended */
+ TEST_P(tst->msg_payload->pl_next, payload);
+ TEST_P(tst->msg_payload->pl_common->h_succ, payload);
+
+ {
+ msg_param_t vs;
+ int vi = 0;
+ msg_param_t foo = "foo=bar";
+
+ vs = NULL;
+ MSG_PARAM_MATCH(vs, foo, "foo");
+ TEST_S(vs, "bar");
+ vs = NULL;
+ MSG_PARAM_MATCH(vs, foo, "fo");
+ TEST_P(vs, NULL);
+ vi = 0;
+ MSG_PARAM_MATCH_P(vi, foo, "foo");
+ TEST(vi, 1);
+ MSG_PARAM_MATCH_P(vi, foo, "fo");
+ TEST(vi, 1);
+ vi = 0;
+ MSG_PARAM_MATCH_P(vi, foo, "fo");
+ TEST(vi, 0);
+ }
+
+ msg_destroy(msg);
+
+ /* Bug #2624: */
+ msg = read_msg("GET /replaces HTTP/1.1" CRLF
+ "Accept-Encoding: gzip" CRLF
+ "Accept-Encoding: bzip2" CRLF
+ "Accept-Encoding: deflate" CRLF
+ "Accept-Language: en;q=0.8, fi, se ; q = 0.6" CRLF
+ );
+ TEST_1(msg);
+ tst = msg_test_public(msg);
+ TEST_1(tst);
+
+ {
+ msg_accept_encoding_t *gzip, *bzip2, *deflate;
+ msg_accept_encoding_t *lzss;
+ msg_accept_language_t *en, *fi, *se;
+ msg_accept_language_t *de, *sv, *sv_fi;
+
+ TEST_1(gzip = tst->msg_accept_encoding);
+ TEST_1(bzip2 = gzip->aa_next);
+ TEST_1(deflate = bzip2->aa_next);
+
+ TEST_1(gzip->aa_common->h_data);
+ TEST_1(lzss = msg_accept_encoding_make(msg_home(msg), "lzss"));
+ TEST(msg_header_replace(msg, (msg_pub_t *)tst, (void *)bzip2, (void *)lzss), 0);
+ TEST_1(gzip->aa_common->h_data);
+
+ TEST_1(en = tst->msg_accept_language);
+ TEST_1(fi = en->aa_next);
+ TEST_1(se = fi->aa_next);
+
+ TEST_S(en->aa_value, "en");
+ TEST_M(en->aa_common->h_data,
+ "Accept-Language: en;q=0.8, fi, se ; q = 0.6" CRLF,
+ en->aa_common->h_len);
+
+ TEST_P((char *)en->aa_common->h_data + en->aa_common->h_len,
+ fi->aa_common->h_data);
+ TEST(fi->aa_common->h_len, 0);
+ TEST_P((char *)en->aa_common->h_data + en->aa_common->h_len,
+ se->aa_common->h_data);
+ TEST(se->aa_common->h_len, 0);
+
+ TEST_1(de = msg_accept_language_make(msg_home(msg), "de;q=0.3"));
+
+ TEST(msg_header_replace(msg, (msg_pub_t *)tst, (void *)se, (void *)de), 0);
+ TEST_P(en->aa_common->h_data, NULL);
+ TEST_P(en->aa_next, fi);
+ TEST_P(fi->aa_next, de);
+ TEST_P(de->aa_next, NULL);
+
+ TEST_P(en->aa_common->h_succ, fi);
+ TEST_P(en->aa_common->h_prev, &deflate->aa_common->h_succ);
+ TEST_P(fi->aa_common->h_succ, de);
+ TEST_P(fi->aa_common->h_prev, &en->aa_common->h_succ);
+ TEST_P(de->aa_common->h_succ, NULL);
+ TEST_P(de->aa_common->h_prev, &fi->aa_common->h_succ);
+
+ TEST_P(se->aa_next, NULL);
+ TEST_P(se->aa_common->h_succ, NULL);
+ TEST_P(se->aa_common->h_prev, NULL);
+
+ TEST_1(sv = msg_accept_language_make(msg_home(msg),
+ "sv;q=0.6,sv_FI;q=0.7"));
+ TEST_1(sv_fi = sv->aa_next);
+
+ TEST(msg_header_replace(msg, (msg_pub_t *)tst, (void *)fi, (void *)sv), 0);
+
+ TEST_P(en->aa_next, sv);
+ TEST_P(sv->aa_next->aa_next, de);
+ TEST_P(de->aa_next, NULL);
+
+ TEST_P(en->aa_common->h_succ, sv);
+ TEST_P(en->aa_common->h_prev, &deflate->aa_common->h_succ);
+ TEST_P(sv->aa_common->h_succ, sv_fi);
+ TEST_P(sv->aa_common->h_prev, &en->aa_common->h_succ);
+ TEST_P(sv_fi->aa_common->h_succ, de);
+ TEST_P(sv_fi->aa_common->h_prev, &sv->aa_common->h_succ);
+ TEST_P(de->aa_common->h_succ, NULL);
+ TEST_P(de->aa_common->h_prev, &sv_fi->aa_common->h_succ);
+
+ TEST(msg_serialize(msg, (msg_pub_t *)tst), 0);
+ }
+
+ /* Bug #2429 */
+ orig = read_msg("GET a-life HTTP/1.1" CRLF
+ "Foo: bar" CRLF
+ "Content-Length: 6" CRLF
+ CRLF
+ "test" CRLF
+ "extra stuff" CRLF);
+ TEST_1(orig);
+ otst = msg_test_public(orig);
+ TEST_1(otst);
+
+ msg = msg_copy(orig);
+ tst = msg_test_public(msg);
+ TEST_1(tst);
+
+ home = msg_home(msg);
+
+ TEST_1(request = msg_request_make(home, "GET a-wife HTTP/1.1"));
+
+ TEST(msg_header_insert(msg, (msg_pub_t *)tst, (void *)request), 0);
+
+ TEST_1(location =
+ msg_content_location_make(home, "http://localhost:8080/wife"));
+
+ TEST(msg_header_insert(msg, (msg_pub_t *)tst, (void *)location), 0);
+
+ TEST(msg_serialize(msg, (msg_pub_t *)tst), 0);
+ TEST_1(msg_prepare(msg) > 0);
+
+ TEST_1(language =
+ msg_content_language_make(home, "se-FI, fi-FI, sv-FI"));
+ TEST(msg_header_insert(msg, (msg_pub_t *)tst, (void *)language), 0);
+
+ TEST_1(se = msg_accept_language_make(home, "se, fi, sv"));
+ TEST_1(se->aa_next); TEST_1(se->aa_next->aa_next);
+ TEST(msg_header_insert(msg, (msg_pub_t *)tst, (void *)se), 0);
+
+ TEST(msg_serialize(msg, (msg_pub_t *)tst), 0);
+ TEST_1(msg_prepare(msg) > 0);
+
+ {
+ char const encoded[] =
+ "GET a-wife HTTP/1.1\r\n";
+
+ TEST_SIZE(request->rq_common->h_len, strlen(encoded));
+ TEST_M(request->rq_common->h_data, encoded, request->rq_common->h_len);
+ }
+
+ {
+ char const encoded[] =
+ "Content-Location: http://localhost:8080/wife\r\n";
+
+ TEST_SIZE(location->g_common->h_len, strlen(encoded));
+ TEST_M(location->g_common->h_data, encoded, location->g_common->h_len);
+ }
+
+ {
+ char const encoded[] =
+ "Content-Language: se-FI, fi-FI, sv-FI\r\n";
+ TEST_SIZE(language->k_common->h_len, strlen(encoded));
+ TEST_M(language->k_common->h_data, encoded, language->k_common->h_len);
+ }
+
+ {
+ char const encoded[] = "Accept-Language: se, fi, sv\r\n";
+ TEST_SIZE(se->aa_common->h_len, strlen(encoded));
+ TEST_M(se->aa_common->h_data, encoded, se->aa_common->h_len);
+ TEST_P((char *)se->aa_common->h_data + se->aa_common->h_len,
+ se->aa_next->aa_common->h_data);
+ TEST_P((char *)se->aa_common->h_data + se->aa_common->h_len,
+ se->aa_next->aa_next->aa_common->h_data);
+ }
+
+ {
+ size_t size = SIZE_MAX;
+ char *s = msg_as_string(msg_home(msg), msg, NULL, 0, &size);
+ TEST_S(s,
+"GET a-wife HTTP/1.1" CRLF
+"Foo: bar" CRLF
+"Content-Length: 6" CRLF
+"Content-Location: http://localhost:8080/wife\r\n"
+"Content-Language: se-FI, fi-FI, sv-FI\r\n"
+"Accept-Language: se, fi, sv\r\n"
+CRLF
+"test" CRLF);
+ }
+
+ msg_destroy(msg);
+
+ END();
+}
+
+static int test_warning(void)
+{
+ msg_warning_t *w;
+ su_home_t *home;
+ char buf[64];
+
+ BEGIN();
+
+ TEST_1(home = su_home_new(sizeof *home));
+
+ TEST_1((w = msg_warning_make(home,
+ "399 host:5060 \"Ok\", "
+ "399 [::1]:39999 \"foo\\\" bar\"")));
+ TEST(w->w_code, 399);
+ TEST_S(w->w_host, "host");
+ TEST_S(w->w_port, "5060");
+ TEST_S(w->w_text, "Ok");
+ TEST_1(w = w->w_next);
+
+ TEST(w->w_code, 399);
+ TEST_S(w->w_host, "[::1]");
+ TEST_S(w->w_port, "39999");
+ TEST_S(w->w_text, "foo\" bar");
+ TEST_1(w->w_next == NULL);
+
+ TEST_1(msg_warning_e(buf, sizeof buf, (msg_header_t *)w, 0) > 0);
+
+ TEST_S(buf, "399 [::1]:39999 \"foo\\\" bar\"");
+
+ su_home_unref(home);
+
+ END();
+}
+
+
+/* Test error handling */
+int test_msg_error(void)
+{
+ msg_t *msg;
+ su_home_t *home;
+ msg_test_t *tst;
+
+ BEGIN();
+
+ msg = read_msg("GET a-life HTTP/1.1" CRLF
+ "Content-Length: 6" CRLF
+ "Content-Language: fi" CRLF
+ "Content-Language: <se>" CRLF
+ "Accept-Language: en;q=0.8, fi, \"\", se ; q = 0.6" CRLF
+ "Foo bar baf: bar" CRLF
+ CRLF
+ "test" CRLF);
+
+ home = msg_home(msg);
+ tst = msg_test_public(msg);
+
+ TEST_1(msg);
+ TEST_1(home);
+ TEST_1(tst);
+
+ TEST_1(tst->msg_error);
+
+ msg_destroy(msg);
+
+ END();
+}
+
+int test_mclass(void)
+{
+ msg_t *msg;
+ su_home_t *home;
+ msg_test_t *tst;
+ msg_request_t *request;
+ msg_status_t *status;
+ msg_separator_t *separator;
+ msg_payload_t *payload;
+ msg_content_length_t *l;
+ msg_content_language_t *la;
+ msg_content_encoding_t *k0, *k;
+ msg_unknown_t *foo;
+
+ BEGIN();
+
+ /* Test that critical errors are signaled */
+ msg = read_msg("GET a-life HTTP/1.1" CRLF
+ "Content-Length: 6bytes" CRLF
+ "Content-Type: *" CRLF
+ "Foo: bar" CRLF
+ "Content-Encoding: identity" CRLF
+ "Content-Language: en" CRLF
+ "Content-Language: en-us" CRLF
+ CRLF
+ "test" CRLF);
+
+ tst = msg_test_public(msg);
+ TEST_1(msg);
+ TEST_1(tst);
+ TEST_1(MSG_HAS_ERROR(tst->msg_flags)); /* Content-Length is critical */
+ msg_destroy(msg);
+
+ msg = read_msg("GET a-life HTTP/1.1" CRLF
+ "Content-Length: 6" CRLF
+ "Content-Type: *" CRLF
+ "Foo: bar" CRLF
+ "Content-Encoding: " CRLF /* XXX */
+ "Content-Language: en" CRLF
+ "Content-Language: en-us" CRLF
+ CRLF
+ "test" CRLF);
+
+ home = msg_home(msg);
+ tst = msg_test_public(msg);
+
+ TEST_1(msg);
+ TEST_1(home);
+ TEST_1(tst);
+
+ TEST_SIZE(msg_iovec(msg, NULL, 0), 1);
+
+ TEST_1(tst->msg_unknown); /* Foo */
+ TEST_1(tst->msg_content_type == NULL);
+ TEST_1(tst->msg_error); /* Content-Type */
+ TEST_1(tst->msg_error->er_next == NULL);
+
+ TEST_1(!MSG_HAS_ERROR(tst->msg_flags)); /* Content-type is not critical */
+
+ TEST_1(la = tst->msg_content_language);
+ TEST_1(la->k_common->h_data);
+ TEST_1(la->k_items);
+ TEST_S(la->k_items[0], "en");
+ TEST_S(la->k_items[1], "en-us");
+ TEST_P(la->k_items[2], NULL);
+ TEST_1(la->k_next);
+ TEST_1(la->k_next->k_common->h_data);
+ TEST_1(la->k_next->k_items == NULL);
+
+ TEST(msg_header_add_make(msg, (msg_pub_t *)tst,
+ msg_content_language_class,
+ "en-gb"), 0);
+ TEST_P(la, tst->msg_content_language);
+ TEST_P(la->k_common->h_data, NULL);
+ TEST_S(la->k_items[2], "en-gb");
+ TEST_P(la->k_next, NULL);
+
+ TEST_1(status = msg_status_make(home, "HTTP/1.1 200 Ok"));
+ TEST(msg_header_insert(msg, (msg_pub_t *)tst, (msg_header_t *)status), 0);
+ TEST_P(tst->msg_status, status); TEST_P(tst->msg_request, NULL);
+
+ TEST_1(request = msg_request_make(home, "GET a-wife HTTP/1.0"));
+ TEST(msg_header_insert(msg, (msg_pub_t *)tst, (msg_header_t *)request), 0);
+ TEST_P(tst->msg_request, request); TEST_P(tst->msg_status, NULL);
+
+ TEST_1(separator = msg_separator_make(home, "\r\n"));
+ TEST(msg_header_insert(msg, (msg_pub_t *)tst, (msg_header_t *)separator), 0);
+ TEST_P(tst->msg_separator, separator);
+ TEST_P(separator->sep_common->h_succ, tst->msg_payload);
+
+ /* Try to add a new payload */
+ TEST_1(payload = msg_payload_make(home, "foofaa\r\n"));
+ TEST(msg_header_insert(msg, (msg_pub_t *)tst, (msg_header_t *)payload), 0);
+ /* The new payload should be appended */
+ TEST_P(tst->msg_payload->pl_next, payload);
+ TEST_P(tst->msg_payload->pl_common->h_succ, payload);
+
+ /* Try to add a new header */
+ TEST_1(l = msg_content_length_create(home,
+ tst->msg_payload->pl_len +
+ payload->pl_len));
+ TEST(msg_header_insert(msg, (msg_pub_t *)tst, (msg_header_t *)l), 0);
+ /* The new header should be last before separator */
+ TEST_P(l->l_common->h_succ, separator);
+
+ TEST_1(foo = tst->msg_unknown);
+ TEST_S(foo->un_name, "Foo");
+ TEST_S(foo->un_value, "bar");
+ foo->un_value = "baz";
+ TEST_1(foo = msg_unknown_dup(home, foo));
+ TEST(msg_header_insert(msg, (msg_pub_t *)tst, (msg_header_t *)foo), 0);
+ TEST_P(tst->msg_unknown->un_next, foo);
+
+ TEST_1(k = msg_content_encoding_make(home, "gzip, compress"));
+ k0 = tst->msg_content_encoding;
+ TEST(msg_header_add_dup(msg, (msg_pub_t *)tst, (msg_header_t *)k), 0);
+ TEST_P(k0, tst->msg_content_encoding);
+ TEST_1(k0->k_items);
+ TEST_S(k0->k_items[0], "gzip");
+ TEST_S(k0->k_items[1], "compress");
+ TEST_P(k0->k_items[2], NULL);
+
+ TEST_1(k = msg_content_encoding_make(home, "gzip, deflate, compress"));
+ TEST(msg_header_add_dup(msg, (msg_pub_t *)tst, (msg_header_t *)k), 0);
+ TEST_P(k0, tst->msg_content_encoding);
+ TEST_1(k0->k_items);
+ TEST_S(k0->k_items[0], "gzip");
+ TEST_S(k0->k_items[1], "compress");
+ TEST_S(k0->k_items[2], "deflate");
+ TEST_P(k0->k_items[3], NULL);
+
+ msg_destroy(msg);
+
+ END();
+}
+
+int test_copy(void)
+{
+ msg_t *msg0, *msg, *msg1, *msg2;
+ su_home_t *home;
+ msg_test_t *tst0, *tst, *copy, *dup;
+ msg_request_t *request;
+ msg_common_t *h, *h_succ;
+ msg_iovec_t iovec[8];
+
+ char const s[] =
+ "GET /a-life HTTP/1.1" CRLF
+ "Content-Length: 6" CRLF
+ "Content-Type: *" CRLF
+ "Foo: bar" CRLF
+ "Content-Language: " CRLF
+ CRLF
+ "test" CRLF;
+
+ BEGIN();
+
+ msg0 = read_msg(s);
+
+ TEST_1(msg0);
+ TEST_1(tst0 = msg_test_public(msg0));
+
+ TEST_SIZE(msg_iovec(msg0, iovec, 8), 1);
+
+ TEST_1(msg = msg_copy(msg0));
+ TEST_1(copy = msg_test_public(msg));
+ TEST_1(copy->msg_request);
+ TEST_1(tst0->msg_request);
+ TEST_S(copy->msg_request->rq_url->url_path,
+ tst0->msg_request->rq_url->url_path);
+ TEST_S(copy->msg_request->rq_url->url_path, "a-life");
+ TEST_P(copy->msg_request->rq_url->url_path,
+ tst0->msg_request->rq_url->url_path);
+
+ msg_destroy(msg);
+
+ TEST_1(msg = msg_dup(msg0));
+ TEST_1(dup = msg_test_public(msg));
+ TEST_1(dup->msg_request);
+ TEST_1(tst0->msg_request);
+ TEST_S(dup->msg_request->rq_url->url_path,
+ tst0->msg_request->rq_url->url_path);
+ TEST_S(dup->msg_request->rq_url->url_path, "a-life");
+ TEST_1(dup->msg_request->rq_url->url_path !=
+ tst0->msg_request->rq_url->url_path);
+
+ msg_destroy(msg);
+
+ TEST_1(msg = msg_copy(msg0)); msg_destroy(msg0);
+
+ TEST_1(home = msg_home(msg));
+ TEST_1(tst = msg_test_public(msg));
+
+ TEST_1(tst->msg_unknown); /* Foo */
+ TEST_1(tst->msg_content_type == NULL);
+ TEST_1(tst->msg_error); /* Content-Type */
+
+ TEST_1(!MSG_HAS_ERROR(tst->msg_flags)); /* Flags are not copied */
+
+ TEST_1(tst0->msg_request);
+ TEST_1(request = tst->msg_request);
+ TEST_P(tst0->msg_request->rq_url->url_path, request->rq_url->url_path);
+
+ TEST_SIZE(msg_iovec(msg, iovec, 8), 1);
+
+ TEST_S(iovec->siv_base, s);
+
+ TEST_1(msg1 = msg_dup(msg));
+ TEST_1(tst = msg_test_public(msg1));
+ TEST_1(tst->msg_request);
+
+ for (h = tst->msg_request->rq_common; h; h = h_succ) {
+ if (h->h_prev)
+ *h->h_prev = NULL;
+ h_succ = (msg_common_t*)h->h_succ;
+ h->h_succ = NULL;
+ }
+
+ TEST_1(msg2 = msg_copy(msg1));
+ msg_destroy(msg2);
+
+ TEST_1(msg2 = msg_dup(msg1));
+ msg_destroy(msg2);
+
+ msg_destroy(msg1);
+ msg_destroy(msg);
+
+ END();
+}
+
+int test_mime(void)
+{
+ msg_t *msg;
+ su_home_t *home;
+ int n;
+ msg_test_t *tst;
+ msg_header_t *h, *h_succ, *head;
+ void *removed;
+ msg_accept_t *ac, *ac0;
+ msg_accept_charset_t *aa;
+ msg_multipart_t *mp, *mp0, *mpX, *mpnew;
+ msg_payload_t *pl;
+ msg_content_type_t *c;
+ msg_content_id_t *cid;
+ msg_content_transfer_encoding_t *cte;
+
+ char const s[] =
+ "GET /a-life HTTP/1.1" CRLF
+ "Accept: text/html;level=4;q=1" CRLF
+ "Accept: text / plain;q=0.9" CRLF
+ "Accept-Charset: *;q=0.1, iso-latin-1, utf-8;q=0.9" CRLF
+ "Accept-Encoding: gzip;q=0.9, deflate" CRLF
+ "Accept-Encoding: , identity ," CRLF
+ "Accept: */*;q=0.2" CRLF
+ "Accept-Language: en;q=0.5, es;q=0.2, fr;q=0.9, fi, x-pig-latin" CRLF
+ "Content-Language: fi, se" CRLF
+ "Content-Language: en, de" CRLF
+ "Content-Disposition: render; required" CRLF
+ "Content-Encoding: gzip, deflate" CRLF
+ "Content-Base: http://localhost/foo" CRLF
+ "MIME-Version: 1.0" CRLF
+ "Content-Type: multipart/alternative ; boundary=\"LaGqGt4BI6Ho\"" CRLF
+ /* "Content-Length: 305" CRLF */
+ "Content-MD5: LLO7gLaGqGt4BI6HouiWng==" CRLF
+ CRLF
+ "test" CRLF
+ CRLF /* 1 */
+ "--LaGqGt4BI6Ho" " " CRLF
+ CRLF /* 2 */
+ "part 1" CRLF /* 3 */
+ CRLF /* 4 */
+ "--LaGqGt4BI6Ho" CRLF
+ "Content-Type: text/plain ; charset = iso-8859-1" CRLF /* 5 */
+ "Content-ID: <m7ZvEEm49xdTT0WCDUgnww at localhost>" CRLF /* 6 */
+ "Content-Transfer-Encoding: quoted-unreadable" CRLF /* 7 */
+ CRLF /* 8 */
+ "part 2" /* 9 */
+ CRLF "--LaGqGt4BI6Ho" /* 10 */
+ "Content-Type: text/html" CRLF /* 11 */
+ "Content-ID: <4SP77aQZ9z6Top2dvLqKPQ at localhost>" CRLF /* 12 */
+ CRLF /* 13 */
+#define BODY3 "<html><body>part 3</body></html>" CRLF
+ BODY3 /* 14 */
+ CRLF /* 15 */
+ "--LaGqGt4BI6Ho--" CRLF;
+
+ BEGIN();
+
+ msg = read_msg(s);
+ home = msg_home(msg);
+ tst = msg_test_public(msg);
+
+ TEST_1(msg);
+ TEST_1(home);
+ TEST_1(tst);
+
+ TEST_1(tst->msg_error == NULL);
+ TEST_1((tst->msg_flags & MSG_FLG_ERROR) == 0);
+
+ TEST_1(ac = tst->msg_accept);
+ TEST_1(ac = ac->ac_next);
+ TEST_S(ac->ac_type, "text/plain");
+ TEST_S(ac->ac_q, "0.9");
+ TEST_1(ac = msg_accept_dup(home, ac));
+ TEST_S(ac->ac_type, "text/plain");
+ TEST_S(ac->ac_q, "0.9");
+ TEST_S(tst->msg_accept->ac_next->ac_q, "0.9");
+ TEST_1(ac->ac_q != tst->msg_accept->ac_next->ac_q);
+
+ TEST_1(ac = msg_accept_make(home, "text / plain"));
+ ac->ac_q = "1.0";
+ TEST_1(ac = msg_accept_dup(home, ac0 = ac));
+ TEST_1(ac->ac_q != ac0->ac_q);
+
+ for (h = (msg_header_t *)tst->msg_request; h; h = h->sh_succ) {
+ TEST_1(h->sh_data);
+ if (h->sh_succ)
+ TEST_P((char*)h->sh_data + h->sh_len, h->sh_succ->sh_data);
+ }
+
+ TEST_1(aa = tst->msg_accept_charset);
+ TEST_S(aa->aa_value, "*"); TEST_S(aa->aa_q, "0.1");
+
+ mp = msg_multipart_parse(home, tst->msg_content_type, tst->msg_payload);
+
+ TEST_1(mp0 = mp);
+
+ TEST_1(mp->mp_data);
+ TEST(memcmp(mp->mp_data, CRLF "--" "LaGqGt4BI6Ho" CRLF, mp->mp_len), 0);
+ TEST_1(mp->mp_common->h_data);
+ TEST_M(mp->mp_common->h_data, CRLF "--" "LaGqGt4BI6Ho" " " CRLF,
+ mp->mp_common->h_len);
+
+ TEST_1(pl = mp->mp_payload); TEST_1(pl->pl_data);
+ TEST_SIZE(strlen("part 1" CRLF), pl->pl_len);
+ TEST(memcmp(pl->pl_data, "part 1" CRLF, pl->pl_len), 0);
+
+ TEST_1(mp = mp->mp_next);
+
+ TEST_1(mp->mp_data);
+ TEST(memcmp(mp->mp_data, CRLF "--" "LaGqGt4BI6Ho" CR LF, mp->mp_len), 0);
+
+ TEST_1(c = mp->mp_content_type);
+ TEST_S(c->c_type, "text/plain"); TEST_S(c->c_subtype, "plain");
+ TEST_1(c->c_params); TEST_1(c->c_params[0]);
+ TEST_S(c->c_params[0], "charset=iso-8859-1");
+
+ TEST_1(cid = mp->mp_content_id);
+
+ TEST_1(cte = mp->mp_content_transfer_encoding);
+ TEST_S(cte->g_string, "quoted-unreadable");
+
+ TEST_1(pl = mp->mp_payload); TEST_1(pl->pl_data);
+ TEST_SIZE(strlen("part 2"), pl->pl_len);
+ TEST(memcmp(pl->pl_data, "part 2", pl->pl_len), 0);
+
+ TEST_1(mp = mp->mp_next);
+
+ TEST_1(mp->mp_data);
+ TEST_M(mp->mp_data, CRLF "--" "LaGqGt4BI6Ho" CRLF, mp->mp_len);
+
+ TEST_1(pl = mp->mp_payload); TEST_1(pl->pl_data);
+ TEST_SIZE(strlen(BODY3), pl->pl_len);
+ TEST(memcmp(pl->pl_data, BODY3, pl->pl_len), 0);
+
+ mpX = mp;
+
+ TEST_1(!(mp = mp->mp_next));
+
+ /* Test serialization */
+ head = NULL;
+ TEST_1(h = msg_multipart_serialize(&head, mp0));
+ TEST_P((void *)h, mpX->mp_close_delim);
+ TEST_1(!msg_chain_errors((msg_header_t *)mp0));
+
+ /* Remove chain */
+ for (h = (msg_header_t *)mp0, n = 0; h; h = h_succ, n++) {
+ h_succ = h->sh_succ;
+ if (h->sh_prev) *h->sh_prev = NULL;
+ h->sh_prev = NULL;
+ h->sh_succ = NULL;
+ }
+
+ TEST(n, 15);
+
+ head = NULL;
+ TEST_1(h = msg_multipart_serialize(&head, mp0));
+ TEST_P(h, mpX->mp_close_delim);
+ TEST_1(!msg_chain_errors((msg_header_t *)mp0));
+
+ for (h = (msg_header_t *)mp0, n = 0; h; h = h_succ, n++) {
+ h_succ = h->sh_succ;
+ }
+
+ TEST(n, 15);
+
+ /* Add a new part to multipart */
+ mpnew = su_zalloc(home, sizeof(*mpnew)); TEST_1(mpnew);
+ removed = mpX->mp_close_delim;
+ mpX->mp_next = mpnew; mpX = mpnew;
+ mpnew->mp_content_type = msg_content_type_make(home, "multipart/mixed");
+ TEST_1(mpnew->mp_content_type);
+ TEST(msg_multipart_complete(msg_home(msg), tst->msg_content_type, mp0), 0);
+
+ head = NULL;
+ TEST_1(h = msg_multipart_serialize(&head, mp0));
+ TEST_P((void *)h, mpX->mp_close_delim);
+ TEST_1(!msg_chain_errors((msg_header_t *)mp0));
+
+ for (h = (msg_header_t *)mp0, n = 0; h; h = h_succ, n++) {
+ h_succ = h->sh_succ;
+ TEST_1(h != removed);
+ }
+
+ TEST(n, 19);
+
+#define remove(h) \
+ (((*((msg_header_t*)(h))->sh_prev = ((msg_header_t*)(h))->sh_succ) ? \
+ (((msg_header_t*)(h))->sh_succ->sh_prev = ((msg_header_t*)(h))->sh_prev) \
+ : NULL), \
+ ((msg_header_t*)(h))->sh_succ = NULL, \
+ ((msg_header_t*)(h))->sh_prev = NULL)
+
+ remove(mp0->mp_separator);
+ remove(mp0->mp_next->mp_payload);
+ remove(mp0->mp_next->mp_next->mp_content_type);
+ remove(mp0->mp_next->mp_next->mp_next->mp_close_delim);
+
+ TEST_1(!msg_chain_errors((msg_header_t *)mp0));
+
+ head = NULL;
+ TEST_1(h = msg_multipart_serialize(&head, mp0));
+ TEST_P(h, mpX->mp_close_delim);
+ TEST_1(!msg_chain_errors((msg_header_t *)mp0));
+
+ for (h = (msg_header_t *)mp0, n = 0; h; h = h_succ, n++) {
+ h_succ = h->sh_succ;
+ if (h_succ == NULL)
+ TEST_P(h, mpX->mp_close_delim);
+ TEST_1(h != removed);
+ }
+
+ TEST(n, 19);
+
+ /* Add an recursive multipart */
+ mpnew = su_zalloc(home, sizeof(*mpnew)); TEST_1(mpnew);
+ mpX->mp_multipart = mpnew;
+ mpnew->mp_content_type = msg_content_type_make(home, "text/plain");
+ TEST_1(mpnew->mp_content_type);
+ TEST(msg_multipart_complete(msg_home(msg), tst->msg_content_type, mp0), 0);
+ TEST_1(mpnew->mp_close_delim);
+
+ head = NULL;
+ TEST_1(h = msg_multipart_serialize(&head, mp0));
+ TEST_P(h, mpX->mp_close_delim);
+
+ TEST_1(!msg_chain_errors((msg_header_t *)mp0));
+
+ for (h = (msg_header_t *)mp0, n = 0; h; h = h_succ, n++)
+ h_succ = h->sh_succ;
+
+ TEST(n, 24);
+
+ su_home_check(home);
+ su_home_zap(home);
+
+ END();
+}
+
+/** Test MIME encoding */
+int test_mime2(void)
+{
+ msg_t *msg;
+ su_home_t *home;
+ int n, m, len;
+ msg_test_t *tst;
+ msg_header_t *h;
+ msg_accept_charset_t *aa;
+ msg_multipart_t *mp;
+ msg_content_type_t *c;
+ msg_payload_t *pl;
+ char const *end;
+
+ char const s[] =
+ "GET /a-life HTTP/1.1" CRLF
+ "Accept: text/html;level=4;q=1" CRLF
+ "Accept: text / plain;q=0.9" CRLF
+ "Accept-Charset: *;q=0.1, iso-latin-1, utf-8;q=0.9" CRLF
+ "Accept-Encoding: gzip;q=0.9, deflate" CRLF
+ "Accept-Encoding: , identity ," CRLF
+ "Accept: */*;q=0.2" CRLF
+ "Accept-Language: en;q=0.5, es;q=0.2, fr;q=0.9, fi, x-pig-latin" CRLF
+ "Content-Language: fi, se" CRLF
+ "Content-Language: en, de" CRLF
+ "Content-Disposition: render; required" CRLF
+ "Content-Encoding: gzip, deflate" CRLF
+ "Content-Base: http://localhost/foo" CRLF
+ "MIME-Version: 1.0" CRLF
+ "Content-Type: multipart/alternative ; boundary=\"LaGqGt4BI6Ho\"" CRLF
+ "Content-MD5: LLO7gLaGqGt4BI6HouiWng==" CRLF
+ CRLF
+ "test" CRLF
+ CRLF /* 1 */
+ "--LaGqGt4BI6Ho" " " CRLF
+ CRLF /* 2 */
+ "part 1" CRLF /* 3 */
+ CRLF /* 4 */
+ "--LaGqGt4BI6Ho" CRLF
+ "Content-Type: text/plain;charset=iso-8859-1" CRLF /* 5 */
+ "Content-ID: <m7ZvEEm49xdTT0WCDUgnww at localhost>" CRLF /* 6 */
+ "Content-Transfer-Encoding: quoted-unreadable" CRLF /* 7 */
+ CRLF /* 8 */
+ "part 2" /* 9 */
+ CRLF "--LaGqGt4BI6Ho" /* 10 */
+ "Content-Type: text/html" CRLF /* 11 */
+ "Content-ID: <4SP77aQZ9z6Top2dvLqKPQ at localhost>" CRLF /* 12 */
+ CRLF /* 13 */
+#define BODY3 "<html><body>part 3</body></html>" CRLF
+ BODY3 /* 14 */
+ CRLF /* 15 */
+ "--LaGqGt4BI6Ho--" CRLF;
+
+ char const part1[] = "This is text\n";
+ char const part2[] = "<html><body>This is html</body></html>";
+ char const part3[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+
+ BEGIN();
+
+ msg = read_msg(s);
+ home = msg_home(msg);
+ tst = msg_test_public(msg);
+
+ TEST_1(msg);
+ TEST_1(home);
+ TEST_1(tst);
+
+ TEST_1(tst->msg_error == NULL);
+ TEST_1((tst->msg_flags & MSG_FLG_ERROR) == 0);
+
+ for (h = (msg_header_t *)tst->msg_request; h; h = h->sh_succ) {
+ TEST_1(h->sh_data);
+ if (h->sh_succ)
+ TEST_P((char*)h->sh_data + h->sh_len, h->sh_succ->sh_data);
+ }
+
+ TEST_1(aa = tst->msg_accept_charset);
+ TEST_S(aa->aa_value, "*"); TEST_S(aa->aa_q, "0.1");
+
+ TEST_1(c = tst->msg_content_type);
+ TEST_1(tst->msg_payload);
+
+ {
+ su_home_t h0[1] = { SU_HOME_INIT(h0) };
+
+ pl = msg_payload_dup(h0, tst->msg_payload); TEST_1(pl);
+
+ mp = msg_multipart_parse(home, c, pl); TEST_1(mp);
+
+ for (n = 0, h = (msg_header_t *)mp; h; h = h->sh_succ, n++)
+ h->sh_data = NULL, h->sh_len = 0;
+ TEST(n, 15);
+
+ n = msg_multipart_prepare(msg, mp, 0);
+
+ TEST_1(end = strstr(s, "--LaGqGt4BI6Ho "));
+ len = strlen(end);
+ TEST(len, n);
+
+ TEST_1(mp = msg_multipart_dup(h0, mp));
+
+ su_home_check(h0);
+ su_home_deinit(h0);
+ }
+
+ /* Test parsing without explicit boundary */
+ {
+ su_home_t h0[1] = { SU_HOME_INIT(h0) };
+
+ pl = msg_payload_dup(h0, tst->msg_payload); TEST_1(pl);
+
+ mp = msg_multipart_parse(h0, NULL, pl);
+ TEST_1(mp);
+
+ for (n = 0, h = (msg_header_t *)mp; h; h = h->sh_succ, n++)
+ h->sh_data = NULL, h->sh_len = 0;
+ TEST(n, 15);
+
+ n = msg_multipart_prepare(msg, mp, 0);
+
+ TEST_1(end = strstr(s, "--LaGqGt4BI6Ho "));
+ len = strlen(end);
+ TEST(len, n);
+
+ TEST_1(mp = msg_multipart_dup(h0, mp));
+
+ su_home_check(h0);
+ su_home_deinit(h0);
+ }
+
+ /* Test parsing without preamble and explicit boundary */
+ {
+ su_home_t h0[1] = { SU_HOME_INIT(h0) };
+
+ pl = msg_payload_dup(h0, tst->msg_payload); TEST_1(pl);
+
+ n = strstr(pl->pl_data, "--LaGqGt4BI6Ho") - (char *)pl->pl_data;
+ pl->pl_data = n + (char *)pl->pl_data; pl->pl_len -= n;
+
+ len = pl->pl_len;
+
+ mp = msg_multipart_parse(h0, NULL, pl); TEST_1(mp);
+
+ for (n = 0, h = (msg_header_t *)mp; h; h = h->sh_succ, n++)
+ h->sh_data = NULL, h->sh_len = 0;
+ TEST(n, 15);
+
+ n = msg_multipart_prepare(msg, mp, 0);
+
+ TEST(len, n);
+
+ TEST_1(mp = msg_multipart_dup(h0, mp));
+
+ su_home_check(h0);
+ su_home_deinit(h0);
+ }
+
+ /* Test parsing without CR's */
+ {
+ su_home_t h0[1] = { SU_HOME_INIT(h0) };
+ char *b;
+
+ pl = msg_payload_dup(h0, tst->msg_payload); TEST_1(pl);
+
+ /* Remove CRs */
+ b = pl->pl_data, len = pl->pl_len;
+ for (n = m = 0; n < len; n++) {
+ if ((b[m] = b[n]) != '\r')
+ m++;
+ }
+ pl->pl_len = m;
+
+ mp = msg_multipart_parse(h0, NULL, pl);
+ TEST_1(mp);
+
+ for (n = 0, h = (msg_header_t *)mp; h; h = h->sh_succ, n++)
+ h->sh_data = NULL, h->sh_len = 0;
+ TEST(n, 15);
+
+ n = msg_multipart_prepare(msg, mp, 0);
+ TEST_1(n > 0);
+
+ TEST_1(mp = msg_multipart_dup(h0, mp));
+
+ su_home_check(h0);
+ su_home_deinit(h0);
+ }
+
+ /* Create a new multipart from three parts */
+ TEST_1(c = msg_content_type_make(home, "multipart/related"));
+
+ TEST_1(mp = msg_multipart_create(home, "text/plain", part1, strlen(part1)));
+ TEST_1(mp->mp_next =
+ msg_multipart_create(home, "text/html", part2, strlen(part2)));
+ TEST_1(mp->mp_next->mp_next =
+ msg_multipart_create(home, "application/octet-stream",
+ part3, sizeof part3));
+
+ TEST(msg_multipart_complete(home, c, mp), 0);
+
+ h = NULL;
+ TEST_P(msg_multipart_serialize(&h, mp), mp->mp_next->mp_next->mp_close_delim);
+
+ TEST_1(msg_multipart_prepare(msg, mp, 0));
+
+ TEST_1(mp = msg_multipart_dup(home, mp));
+
+ su_home_check(home);
+ su_home_zap(home);
+
+ END();
+}
+
+
+/* Test serialization */
+int test_serialize(void)
+{
+ msg_t *msg;
+ su_home_t *home;
+ msg_test_t *tst;
+ msg_mime_version_t *mime;
+ msg_separator_t *sep;
+ msg_payload_t *pl;
+ msg_accept_encoding_t *aen;
+ msg_accept_language_t *ala;
+
+ char const s[] =
+ "GET /a-life HTTP/1.1" CRLF
+ "Accept-Language: fi" CRLF
+ "Accept-Encoding: z0" CRLF
+ "Accept-Language: se, de" CRLF
+ "Accept-Encoding: z1, z2" CRLF
+ "Accept-Language: en, sv" CRLF
+ "Accept-Encoding: z3, z4" CRLF
+ "Content-Length: 6" CRLF
+ CRLF
+ "test" CRLF;
+
+ BEGIN();
+
+ msg = read_msg(s);
+
+ TEST_1(msg); home = msg_home(msg);
+ TEST_1(tst = msg_test_public(msg));
+ TEST(msg_chain_errors((msg_header_t *)tst->msg_request), 0);
+
+ TEST_1(ala = tst->msg_accept_language->aa_next->aa_next);
+ TEST(msg_header_remove(msg, (msg_pub_t *)tst, (msg_header_t *)ala), 0);
+ TEST_S(ala->aa_value, "de");
+
+ TEST_1(ala = tst->msg_accept_language);
+ TEST_1(ala = ala->aa_next); TEST_S(ala->aa_value, "se");
+ /* Make sure that cached encoding of se is reset */
+ TEST_1(ala->aa_common->h_data == NULL);
+ TEST_1(ala->aa_common->h_len == 0);
+ TEST_1(ala = ala->aa_next); TEST_S(ala->aa_value, "en");
+ /* Make sure that cached encoding of en is kept intact */
+ TEST_1(ala->aa_common->h_data != NULL);
+ TEST_1(ala->aa_common->h_len != 0);
+
+ TEST_1(aen = tst->msg_accept_encoding->aa_next->aa_next);
+ TEST(msg_header_remove_all(msg, (msg_pub_t *)tst, (msg_header_t *)aen), 0);
+
+ TEST_1(aen = tst->msg_accept_encoding);
+ TEST_1(aen = aen->aa_next); TEST_S(aen->aa_value, "z1");
+ /* Make sure that cached encoding of z1 is reset */
+ TEST_1(aen->aa_common->h_data == NULL);
+ TEST_1(aen->aa_common->h_len == 0);
+ TEST_1(aen->aa_next == NULL);
+
+ TEST_1(aen->aa_common->h_succ == (void *)ala);
+ TEST_1(ala->aa_next->aa_common);
+ TEST_1(ala->aa_next->aa_common->h_succ == (void *)tst->msg_content_length);
+
+ TEST_1(mime = msg_mime_version_make(home, "1.0"));
+ tst->msg_mime_version = mime;
+
+ TEST(msg_serialize(msg, (msg_pub_t *)tst), 0);
+ TEST(msg_chain_errors((msg_header_t *)tst->msg_request), 0);
+ TEST_P(tst->msg_content_length->l_common->h_succ, mime);
+ TEST_P(mime->g_common->h_succ, tst->msg_separator);
+
+ msg_header_remove(msg, (msg_pub_t *)tst, (msg_header_t *)tst->msg_separator);
+ TEST_1(sep = msg_separator_make(home, CRLF));
+ tst->msg_separator = sep;
+ TEST(msg_serialize(msg, (msg_pub_t *)tst), 0);
+ TEST(msg_chain_errors((msg_header_t *)tst->msg_request), 0);
+ TEST_P(mime->g_common->h_succ, sep);
+ TEST_P(sep->sep_common->h_succ, tst->msg_payload);
+
+ msg_header_remove(msg, (msg_pub_t *)tst, (msg_header_t *)tst->msg_payload);
+ TEST_1(pl = msg_payload_make(home, "foobar" CRLF));
+ pl->pl_next = tst->msg_payload;
+ tst->msg_payload = pl;
+ TEST(msg_serialize(msg, (msg_pub_t *)tst), 0);
+ TEST(msg_chain_errors((msg_header_t *)tst->msg_request), 0);
+ TEST_P(mime->g_common->h_succ, sep);
+ TEST_P(sep->sep_common->h_succ, pl);
+ TEST_P(pl->pl_common->h_succ, pl->pl_next);
+
+ msg_destroy(msg);
+
+ END();
+}
+
+static int random_test(void)
+{
+ struct { uint64_t low, mid, hi; } seed = { 0, 0, 0 };
+ uint8_t zeros[24] = { 0 };
+ uint8_t ones[24];
+
+ char token[33];
+
+ BEGIN();
+
+ memset(ones, 255, sizeof ones);
+
+ TEST_SIZE(msg_random_token(token, 32, (void *)&seed, sizeof(seed)), 32);
+ TEST_S(token, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
+
+ TEST_SIZE(msg_random_token(token, 32, zeros, 4), 7);
+ TEST_S(token, "aaaaaaa");
+ TEST_SIZE(msg_random_token(token, 32, ones, 4), 7);
+ /* Last char may vary.. */
+ token[6] = 0; TEST_S(token, "999999");
+ TEST_SIZE(msg_random_token(token, 32, zeros, 8), 13);
+ TEST_S(token, "aaaaaaaaaaaaa");
+ TEST_SIZE(msg_random_token(token, 32, zeros, 12), 20);
+ TEST_S(token, "aaaaaaaaaaaaaaaaaaaa");
+
+ END();
+}
+
+int main(int argc, char *argv[])
+{
+ int retval = 0;
+ int i;
+
+ for (i = 1; argv[i]; i++) {
+ if (strcmp(argv[i], "-v") == 0)
+ test_flags |= tst_verbatim;
+ else
+ usage();
+ }
+
+ retval |= msg_time_test(); fflush(stdout);
+ retval |= addr_test(); fflush(stdout);
+ retval |= hash_test(); fflush(stdout);
+ retval |= random_test(); fflush(stdout);
+ retval |= test_header_parsing(); fflush(stdout);
+ retval |= test_msg_parsing(); fflush(stdout);
+ retval |= test_warning(); fflush(stdout);
+ retval |= test_msg_error(); fflush(stdout);
+ retval |= test_mclass(); fflush(stdout);
+ retval |= test_copy(); fflush(stdout);
+ retval |= test_mime(); fflush(stdout);
+ retval |= test_mime2(); fflush(stdout);
+ retval |= test_serialize(); fflush(stdout);
+
+ return retval;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/test_protos.h.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/test_protos.h.in Thu Dec 21 01:30:28 2006
@@ -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 at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#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 at 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) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/test_table.c.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/test_table.c.in Thu Dec 21 01:30:28 2006
@@ -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 at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup test_msg
+ *
+ * @CFILE test_table.c
+ * @brief Parser table used for testing.
+ *
+ * #AUTO#
+ *
+ * @author Pekka Pessi <Pekka.Pessi at 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>
+
+
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/ChangeLog Thu Dec 21 01:30:28 2006
@@ -0,0 +1,3 @@
+2005-07-18 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * Initial import of the module to Sofia-SIP tree.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/Doxyfile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/Doxyfile Thu Dec 21 01:30:28 2006
@@ -0,0 +1,21 @@
+PROJECT_NAME = "nea"
+OUTPUT_DIRECTORY = ../docs/html/nea
+
+INPUT = nea.docs sofia-sip .
+
+ at INCLUDE = ../docs/Doxyfile.conf
+
+EXCLUDE_PATTERNS = test*.c torture*.c
+
+TAGFILES += \
+ "../docs/su.doxytags=../su" \
+ "../docs/ipt.doxytags=../ipt" \
+ "../docs/bnf.doxytags=../bnf" \
+ "../docs/url.doxytags=../url" \
+ "../docs/msg.doxytags=../msg" \
+ "../docs/sip.doxytags=../sip" \
+ "../docs/nta.doxytags=../nta"
+
+GENERATE_TAGFILE = ../docs/nea.doxytags
+
+ALIASES +=
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/Makefile.am Thu Dec 21 01:30:28 2006
@@ -0,0 +1,62 @@
+#
+# Makefile.am for nea module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+INCLUDES = -I$(srcdir)/../ipt -I../ipt \
+ -I$(srcdir)/../msg -I../msg \
+ -I$(srcdir)/../nta -I../nta \
+ -I$(srcdir)/../sip -I../sip \
+ -I$(srcdir)/../sresolv -I../sresolv \
+ -I$(srcdir)/../tport -I../tport \
+ -I$(srcdir)/../url -I../url \
+ -I$(srcdir)/../su -I../su
+
+# ----------------------------------------------------------------------
+# Build targets
+
+noinst_LTLIBRARIES = libnea.la
+
+TESTS =
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+
+BUILT_SOURCES = nea_tag_ref.c
+
+nobase_include_sofia_HEADERS =\
+ sofia-sip/nea.h sofia-sip/nea_tag.h
+
+libnea_la_SOURCES = nea.c nea_event.c \
+ nea_server.c nea_debug.h nea_debug.c \
+ nea_tag.c nea_tag_ref.c
+
+COVERAGE_INPUT = $(libnea_la_SOURCES) $(include_sofia_HEADERS)
+
+LDADD = libnea.la \
+ ../nta/libnta.la \
+ ../ipt/libipt.la \
+ ../sip/libsip.la \
+ ../sresolv/libsresolv.la \
+ ../tport/libtport.la \
+ ../stun/libstun.la \
+ ../http/libhttp.la \
+ ../msg/libmsg.la \
+ ../url/liburl.la \
+ ../bnf/libbnf.la \
+ ../su/libsu.la
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+
+EXTRA_DIST = Doxyfile nea.docs $(BUILT_SOURCES)
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+
+include ../sofia.am
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/Makefile.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1,700 @@
+# 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.
+
+ at SET_MAKE@
+
+#
+# Makefile.am for nea module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+# common Makefile targets for libsofia-sip-ua modules
+# ---------------------------------------------------
+
+
+SOURCES = $(libnea_la_SOURCES)
+
+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@
+DIST_COMMON = $(nobase_include_sofia_HEADERS) $(srcdir)/../sofia.am \
+ $(srcdir)/Makefile.am $(srcdir)/Makefile.in ChangeLog
+subdir = libsofia-sip-ua/nea
+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 =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libnea_la_LIBADD =
+am_libnea_la_OBJECTS = nea.lo nea_event.lo nea_server.lo nea_debug.lo \
+ nea_tag.lo nea_tag_ref.lo
+libnea_la_OBJECTS = $(am_libnea_la_OBJECTS)
+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 = $(libnea_la_SOURCES)
+DIST_SOURCES = $(libnea_la_SOURCES)
+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|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(include_sofiadir)"
+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)/../ipt -I../ipt \
+ -I$(srcdir)/../msg -I../msg \
+ -I$(srcdir)/../nta -I../nta \
+ -I$(srcdir)/../sip -I../sip \
+ -I$(srcdir)/../sresolv -I../sresolv \
+ -I$(srcdir)/../tport -I../tport \
+ -I$(srcdir)/../url -I../url \
+ -I$(srcdir)/../su -I../su
+
+
+# ----------------------------------------------------------------------
+# Build targets
+noinst_LTLIBRARIES = libnea.la
+TESTS =
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+BUILT_SOURCES = nea_tag_ref.c
+nobase_include_sofia_HEADERS = \
+ sofia-sip/nea.h sofia-sip/nea_tag.h
+
+libnea_la_SOURCES = nea.c nea_event.c \
+ nea_server.c nea_debug.h nea_debug.c \
+ nea_tag.c nea_tag_ref.c
+
+COVERAGE_INPUT = $(libnea_la_SOURCES) $(include_sofia_HEADERS)
+LDADD = libnea.la \
+ ../nta/libnta.la \
+ ../ipt/libipt.la \
+ ../sip/libsip.la \
+ ../sresolv/libsresolv.la \
+ ../tport/libtport.la \
+ ../stun/libstun.la \
+ ../http/libhttp.la \
+ ../msg/libmsg.la \
+ ../url/liburl.la \
+ ../bnf/libbnf.la \
+ ../su/libsu.la
+
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+EXTRA_DIST = Doxyfile nea.docs $(BUILT_SOURCES)
+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
+
+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/nea/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu libsofia-sip-ua/nea/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-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
+libnea.la: $(libnea_la_OBJECTS) $(libnea_la_DEPENDENCIES)
+ $(LINK) $(libnea_la_LDFLAGS) $(libnea_la_OBJECTS) $(libnea_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nea.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nea_debug.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nea_event.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nea_server.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nea_tag.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nea_tag_ref.Plo at am__quote@
+
+.c.o:
+ at am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+ at am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ at am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at 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-TESTS
+check: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(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-generic clean-libtool 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-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-info-am uninstall-nobase_include_sofiaHEADERS
+
+.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \
+ clean-generic clean-libtool 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-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-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) $<
+
+ at ENABLE_COVERAGE_TRUE@coverage:
+ at 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)
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+# 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:
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/nea.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/nea.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,597 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nea.c Nokia Event Client API agent implementation.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Feb 14 18:32:58 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <assert.h>
+
+#include <sofia-sip/su_tagarg.h>
+
+#include <sofia-sip/sip.h>
+#include <sofia-sip/sip_header.h>
+#include <sofia-sip/sip_util.h>
+#include <sofia-sip/sip_status.h>
+
+#define SU_TIMER_ARG_T struct nea_s
+#define NTA_LEG_MAGIC_T struct nea_s
+#define NTA_OUTGOING_MAGIC_T struct nea_s
+
+#define NEA_TIMER_DELTA 2 /* time to resubscribe without expiration */
+#define EXPIRES_DEFAULT 3600
+
+#include <sofia-sip/su_wait.h>
+
+#include "sofia-sip/nea.h"
+
+struct nea_s {
+ su_home_t nea_home[1];
+ su_timer_t *nea_timer;
+
+ nta_agent_t *nea_agent;
+ nta_leg_t *nea_leg;
+ nta_outgoing_t *nea_oreq; /**< Outstanding request */
+ sip_to_t *nea_to; /**< The other end of subscription :) */
+ nea_notify_f nea_callback; /**< Notify callback */
+ nea_magic_t *nea_context; /**< Application context */
+
+ sip_contact_t *nea_contact; /**< */
+ sip_expires_t *nea_expires; /**< Proposed expiration time */
+
+ nea_state_t nea_state; /**< State of our subscription */
+ sip_time_t nea_deadline; /**< When our subscription expires */
+ tagi_t *nea_args;
+
+ unsigned nea_dialog : 1; /**< Dialog has been established */
+ unsigned nea_notify_received : 1;
+ unsigned nea_terminating : 1;
+ unsigned nea_strict_3265 : 1; /**< Strict mode */
+};
+
+int details = 0;
+
+static int process_nea_request(nea_t *nea,
+ nta_leg_t *leg,
+ nta_incoming_t *ireq,
+ sip_t const *sip);
+
+static int handle_notify(nta_leg_magic_t *lmagic,
+ nta_leg_t *leg,
+ nta_incoming_t *ireq,
+ sip_t const *sip);
+
+static int response_to_subscribe(nea_t *nea,
+ nta_outgoing_t *req,
+ sip_t const *sip);
+
+static int response_to_unsubscribe(nea_t *nea,
+ nta_outgoing_t *req,
+ sip_t const *sip);
+
+static void nea_expires_renew(su_root_magic_t *magic,
+ su_timer_t *timer,
+ nea_t *nea);
+
+/* ---------------------------------------------------------- */
+
+/** Create a event watcher object.
+ *
+ */
+nea_t *nea_create(nta_agent_t *agent,
+ su_root_t *root,
+ nea_notify_f no_callback,
+ nea_magic_t *context,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ nea_t *nea = NULL;
+ ta_list ta;
+ int have_from, have_to, have_contact;
+ sip_expires_t const *expires = NULL;
+ char const *expires_str = NULL;
+ sip_method_t method = sip_method_subscribe;
+ char const *SUBSCRIBE = "SUBSCRIBE";
+ char const *method_name = SUBSCRIBE;
+
+ ta_start(ta, tag, value);
+
+ have_to =
+ tl_find(ta_args(ta), siptag_to) || tl_find(ta_args(ta), siptag_to_str);
+ have_from =
+ tl_find(ta_args(ta), siptag_from) || tl_find(ta_args(ta), siptag_from_str);
+ have_contact =
+ tl_find(ta_args(ta), siptag_contact) ||
+ tl_find(ta_args(ta), siptag_contact_str);
+
+ if (have_to && (nea = su_home_new(sizeof(nea_t)))) {
+ su_home_t *home = nea->nea_home;
+ sip_contact_t *m = nta_agent_contact(agent);
+ sip_from_t *from;
+ sip_to_t const *to;
+ int strict = 0;
+
+ nea->nea_agent = agent;
+ nea->nea_callback = no_callback;
+ nea->nea_context = context;
+
+ if (!have_from)
+ from = sip_from_create(home, (url_string_t*)m->m_url);
+ else
+ from = NULL;
+
+ nea->nea_args = tl_tlist(home,
+ TAG_IF(!have_contact, SIPTAG_CONTACT(m)),
+ ta_tags(ta));
+
+ /* Get and remove Expires header from tag list */
+ tl_gets(nea->nea_args,
+ SIPTAG_EXPIRES_REF(expires),
+ SIPTAG_EXPIRES_STR_REF(expires_str),
+ SIPTAG_TO_REF(to),
+ NEATAG_STRICT_3265_REF(strict),
+ NTATAG_METHOD_REF(method_name),
+ TAG_END());
+
+ nea->nea_strict_3265 = strict;
+
+ if (to)
+ nea->nea_to = sip_to_dup(home, to);
+
+ if (expires)
+ nea->nea_expires = sip_expires_dup(home, expires);
+ else if (expires_str)
+ nea->nea_expires = sip_expires_make(home, expires_str);
+ else
+ nea->nea_expires = sip_expires_create(home, EXPIRES_DEFAULT);
+
+ tl_tremove(nea->nea_args,
+ SIPTAG_EXPIRES(0),
+ SIPTAG_EXPIRES_STR(0),
+ TAG_END());
+
+ if (method_name != SUBSCRIBE)
+ method = sip_method_code(method_name);
+
+ if (method != sip_method_invalid)
+ /* Create the timer object */
+ nea->nea_timer = su_timer_create(su_root_task(root), 0L);
+
+ if (nea->nea_timer) {
+ /* Create leg for NOTIFY requests */
+ nea->nea_leg = nta_leg_tcreate(nea->nea_agent,
+ process_nea_request, nea,
+ TAG_IF(!have_from, SIPTAG_FROM(from)),
+ TAG_NEXT(nea->nea_args));
+
+ if (nea->nea_leg) {
+ nta_leg_tag(nea->nea_leg, NULL);
+ nea->nea_oreq = nta_outgoing_tcreate(nea->nea_leg,
+ response_to_subscribe, nea,
+ NULL,
+ method, method_name,
+ NULL,
+ SIPTAG_EXPIRES(nea->nea_expires),
+ TAG_NEXT(nea->nea_args));
+ }
+ }
+
+ if (!nea->nea_leg ||
+ !nea->nea_oreq ||
+ !nea->nea_timer)
+ nea_destroy(nea), nea = NULL;
+ }
+
+ ta_end(ta);
+ return nea;
+}
+
+
+int nea_update(nea_t *nea,
+ tag_type_t tag,
+ tag_value_t value,
+ ...)
+{
+ ta_list ta;
+ sip_expires_t const *expires = NULL;
+ sip_payload_t const *pl = NULL;
+ sip_content_type_t const *ct = NULL;
+ char const *cts = NULL;
+
+ /* char const *expires_str = NULL; */
+ su_home_t *home = nea->nea_home;
+
+ /* XXX - hack, previous request still waiting for response */
+ if (!nea->nea_leg || nea->nea_oreq)
+ return -1;
+
+ ta_start(ta, tag, value);
+
+ tl_gets(ta_args(ta),
+ SIPTAG_CONTENT_TYPE_REF(ct),
+ SIPTAG_CONTENT_TYPE_STR_REF(cts),
+ SIPTAG_PAYLOAD_REF(pl),
+ SIPTAG_EXPIRES_REF(expires),
+ TAG_NULL());
+
+ if (!pl || (!ct && !cts)) {
+ ta_end(ta);
+ return -1;
+ }
+
+ tl_tremove(nea->nea_args,
+ SIPTAG_CONTENT_TYPE(0),
+ SIPTAG_CONTENT_TYPE_STR(0),
+ SIPTAG_PAYLOAD(0),
+ SIPTAG_PAYLOAD_STR(0),
+ TAG_END());
+
+ su_free(home, nea->nea_expires);
+
+ if (expires)
+ nea->nea_expires = sip_expires_dup(home, expires);
+ else
+ nea->nea_expires = sip_expires_create(home, EXPIRES_DEFAULT);
+
+ /* nta_leg_tag(nea->nea_leg, NULL); */
+ nea->nea_oreq = nta_outgoing_tcreate(nea->nea_leg,
+ response_to_subscribe, nea,
+ NULL,
+ SIP_METHOD_SUBSCRIBE,
+ NULL,
+ SIPTAG_TO(nea->nea_to),
+ SIPTAG_PAYLOAD(pl),
+ TAG_IF(ct, SIPTAG_CONTENT_TYPE(ct)),
+ TAG_IF(cts, SIPTAG_CONTENT_TYPE_STR(cts)),
+ SIPTAG_EXPIRES(nea->nea_expires),
+ TAG_NEXT(nea->nea_args));
+
+ ta_end(ta);
+
+ if (!nea->nea_oreq)
+ return -1;
+
+ return 0;
+}
+
+
+/** Unsubscribe the agent. */
+void nea_end(nea_t *nea)
+{
+ if (nea == NULL)
+ return;
+
+ nea->nea_terminating = 1;
+
+ su_timer_destroy(nea->nea_timer), nea->nea_timer = NULL;
+
+ if (nea->nea_leg && nea->nea_deadline) {
+ nea->nea_oreq =
+ nta_outgoing_tcreate(nea->nea_leg,
+ response_to_unsubscribe,
+ nea,
+ NULL,
+ SIP_METHOD_SUBSCRIBE,
+ NULL,
+ SIPTAG_EXPIRES_STR("0"),
+ TAG_NEXT(nea->nea_args));
+ }
+}
+
+void nea_destroy(nea_t *nea)
+{
+ if (nea == NULL)
+ return;
+
+ if (nea->nea_oreq)
+ nta_outgoing_destroy(nea->nea_oreq), nea->nea_oreq = NULL;
+
+ if (nea->nea_leg)
+ nta_leg_destroy(nea->nea_leg), nea->nea_leg = NULL;
+
+ if (nea->nea_timer) {
+ su_timer_reset(nea->nea_timer);
+ su_timer_destroy(nea->nea_timer), nea->nea_timer = NULL;
+ }
+
+ su_free(NULL, nea);
+}
+
+
+/* Function called by NTA to handle incoming requests belonging to the leg */
+int process_nea_request(nea_t *nea,
+ nta_leg_t *leg,
+ nta_incoming_t *ireq,
+ sip_t const *sip)
+{
+
+ switch (sip->sip_request->rq_method) {
+ case sip_method_notify:
+ return handle_notify(nea, leg, ireq, sip);
+ case sip_method_ack:
+ return 400;
+ default:
+ nta_incoming_treply(ireq, SIP_405_METHOD_NOT_ALLOWED,
+ SIPTAG_ALLOW_STR("NOTIFY"), TAG_END());
+ return 405;
+ }
+}
+
+
+/* Callback function to handle subscription requests */
+int response_to_subscribe(nea_t *nea,
+ nta_outgoing_t *oreq,
+ sip_t const *sip)
+{
+ int status = sip->sip_status->st_status;
+ int error = status >= 300;
+
+ if (status >= 200 && oreq == nea->nea_oreq)
+ nea->nea_oreq = NULL;
+
+ nea->nea_callback(nea, nea->nea_context, sip);
+
+ if (status < 200)
+ return 0;
+
+ nea->nea_oreq = NULL;
+
+ if (status < 300) {
+ sip_time_t now = sip_now();
+ if (!nea->nea_notify_received) {
+ nea->nea_deadline = now +
+ sip_contact_expires(NULL, sip->sip_expires, sip->sip_date,
+ EXPIRES_DEFAULT, now);
+ if (sip->sip_to->a_tag && !nea->nea_dialog) {
+ nea->nea_dialog = 1;
+ nta_leg_rtag(nea->nea_leg, sip->sip_to->a_tag);
+ nta_leg_client_route(nea->nea_leg,
+ sip->sip_record_route, sip->sip_contact);
+ }
+ }
+ }
+ else {
+ nea->nea_deadline = 0;
+ nea->nea_state = nea_terminated;
+ if (status == 301 || status == 302 || status == 305) {
+ sip_contact_t *m;
+
+ for (m = sip->sip_contact; m; m = m->m_next) {
+ if (m->m_url->url_type == url_sip ||
+ m->m_url->url_type == url_sips)
+ break;
+ }
+
+ if (m) {
+ url_string_t const *proxy, *url;
+ if (status == 305)
+ url = NULL, proxy = (url_string_t *)m->m_url;
+ else
+ url = (url_string_t *)m->m_url, proxy = NULL;
+
+ nea->nea_oreq =
+ nta_outgoing_tcreate(nea->nea_leg,
+ response_to_subscribe,
+ nea,
+ proxy,
+ SIP_METHOD_SUBSCRIBE,
+ url,
+ SIPTAG_EXPIRES(nea->nea_expires),
+ TAG_NEXT(nea->nea_args));
+ }
+ } else if (status == 423 && sip->sip_min_expires) {
+ unsigned value = sip->sip_min_expires->me_delta;
+ su_free(nea->nea_home, nea->nea_expires);
+ nea->nea_expires = sip_expires_format(nea->nea_home, "%u", value);
+
+ nea->nea_oreq =
+ nta_outgoing_tcreate(nea->nea_leg,
+ response_to_subscribe,
+ nea,
+ NULL,
+ SIP_METHOD_SUBSCRIBE,
+ NULL,
+ SIPTAG_EXPIRES(nea->nea_expires),
+ TAG_NEXT(nea->nea_args));
+ }
+ }
+
+ if (status >= 200)
+ nta_outgoing_destroy(oreq);
+
+ if (nea->nea_oreq || !error) {
+ su_time_t now = su_now();
+ now.tv_sec = nea->nea_deadline;
+ su_timer_set_at(nea->nea_timer,
+ nea_expires_renew,
+ nea,
+ now);
+ }
+ else
+ nea->nea_callback(nea, nea->nea_context, NULL);
+
+ return 0;
+}
+
+
+int response_to_unsubscribe(nea_t *nea,
+ nta_outgoing_t *orq,
+ sip_t const *sip)
+{
+ int status = sip->sip_status->st_status;
+
+ nea->nea_callback(nea, nea->nea_context, sip);
+
+ if (status >= 200)
+ nta_outgoing_destroy(orq), nea->nea_oreq = NULL;
+ if (status >= 300)
+ nea->nea_callback(nea, nea->nea_context, NULL);
+
+ return 0;
+}
+
+/** handle notifications */
+int handle_notify(nea_t *nea,
+ nta_leg_t *leg,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ sip_subscription_state_t *ss = sip->sip_subscription_state;
+ sip_subscription_state_t ss0[1];
+ char expires[32];
+
+ if (nea->nea_strict_3265) {
+ char const *phrase = NULL;
+
+ if (ss == NULL)
+ phrase = "NOTIFY Has No Subscription-State Header";
+ else if (sip->sip_event == NULL)
+ phrase = "Event Header Missing";
+
+ if (phrase) {
+ nta_incoming_treply(irq, 400, phrase, TAG_END());
+ nta_incoming_destroy(irq);
+ nta_leg_destroy(nea->nea_leg), nea->nea_leg = NULL;
+ nea->nea_state = nea_terminated;
+ nea->nea_callback(nea, nea->nea_context, NULL);
+ return 0;
+ }
+ }
+
+ if (ss == NULL) {
+ /* Do some compatibility stuff here */
+ unsigned long delta = 3600;
+
+ sip_subscription_state_init(ss = ss0);
+
+ if (sip->sip_expires)
+ delta = sip->sip_expires->ex_delta;
+
+ if (delta == 0)
+ ss->ss_substate = "terminated";
+ else
+ ss->ss_substate = "active";
+
+ if (delta > 0) {
+ snprintf(expires, sizeof expires, "%lu", delta);
+ ss->ss_expires = expires;
+ }
+ }
+
+ if (!nea->nea_dialog) {
+ nea->nea_dialog = 1;
+ nta_leg_rtag(nea->nea_leg, sip->sip_from->a_tag);
+ nta_leg_server_route(nea->nea_leg,
+ sip->sip_record_route, sip->sip_contact);
+ }
+
+ nea->nea_notify_received = 1;
+ nea->nea_callback(nea, nea->nea_context, sip);
+
+ if (strcasecmp(ss->ss_substate, "terminated") == 0) {
+ nta_leg_destroy(nea->nea_leg), nea->nea_leg = NULL;
+ nea->nea_state = nea_terminated;
+
+ if (str0casecmp(ss->ss_reason, "deactivated") == 0) {
+ nea->nea_state = nea_embryonic;
+ nea->nea_deadline = sip_now();
+ } else if (str0casecmp(ss->ss_reason, "probation") == 0) {
+ sip_time_t retry = sip_now() + NEA_TIMER_DELTA;
+
+ if (ss->ss_retry_after)
+ retry += strtoul(ss->ss_retry_after, NULL, 10);
+ else
+ retry += NEA_TIMER_DELTA;
+
+ nea->nea_state = nea_embryonic;
+ nea->nea_deadline = retry;
+ } else {
+ nea->nea_deadline = 0;
+ nea->nea_callback(nea, nea->nea_context, NULL);
+ return 200;
+ }
+ }
+ else if (strcasecmp(ss->ss_substate, "pending") == 0)
+ nea->nea_state = nea_pending;
+ else if (strcasecmp(ss->ss_substate, "active") == 0)
+ nea->nea_state = nea_active;
+ else
+ nea->nea_state = nea_extended;
+
+ if (nea->nea_state != nea_embryonic && ss->ss_expires) {
+ unsigned retry = strtoul(ss->ss_expires, NULL, 10);
+ if (retry > 60) retry -= 30; else retry /= 2;
+ nea->nea_deadline = sip_now() + retry;
+ }
+
+ {
+ su_time_t now = su_now();
+ now.tv_sec = nea->nea_deadline;
+ su_timer_set_at(nea->nea_timer,
+ nea_expires_renew,
+ nea,
+ now);
+ }
+
+ return 200;
+}
+
+void nea_expires_renew(su_root_magic_t *magic,
+ su_timer_t *timer,
+ nea_t *nea)
+{
+ sip_time_t now = sip_now();
+
+ /* re-subscribe if expires soon */
+ if (nea->nea_state == nea_terminated ||
+ nea->nea_deadline == 0 ||
+ nea->nea_deadline > now + NEA_TIMER_DELTA)
+ return;
+
+ if (!nea->nea_notify_received) /* Hmph. */
+ return;
+
+ nea->nea_notify_received = 0;
+
+ nea->nea_oreq =
+ nta_outgoing_tcreate(nea->nea_leg,
+ response_to_subscribe,
+ nea,
+ NULL,
+ SIP_METHOD_SUBSCRIBE,
+ NULL,
+ SIPTAG_EXPIRES(nea->nea_expires),
+ TAG_NEXT(nea->nea_args));
+
+ return;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/nea.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/nea.docs Thu Dec 21 01:30:28 2006
@@ -0,0 +1,123 @@
+/* -*- c -*- */
+
+/**@MODULEPAGE "nea" - SIP Events Module
+ *
+ * @section nea_meta Module Meta Information
+ *
+ * Sofia Event API provides an interface to different events used in SIP
+ * presence and conferencing. Interface used both in client and server sides
+ * is presented in <nea.h>.
+ *
+ * @CONTACT Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @STATUS @SofiaSIP Core library
+ *
+ * @LICENSE LGPL
+ *
+ * @section Creating NEA server and events
+ *
+ * @section nea_server_create Creating NEA server
+ *
+ * NEA server generates, receives and sends events to subscribed
+ * parties. The server is presentity specific, ie. a different server
+ * is created for every presentity.
+ *
+ * First, a server object is created. The object uses the NTA @e agent
+ * (#nta_agent_t) that handles incoming and outgoing SIP messages.
+ *
+ * The example below provides a way to create the NEA server. The
+ * function nea_server_create() creates the server. Parameters @e
+ * agent, @e root define the transaction engine. Third parameter is
+ * the address of the presentity. event_callback is a callback
+ * function pointer and is called every time a new user subscribes to
+ * an event that does not exist or requests for payload type that
+ * doesn't match.
+ *
+ * @code
+ * presence_t *presence_create(su_root_t *root,
+ * nta_agent_t *agent,
+ * sip_contact_t const *m)
+ * {
+ * presentity_t *pr = su_home_clone(p->p_home, sizeof (*pr));
+ * ...
+ * pr->pr_nes =
+ * nea_server_create(agent, root,
+ * m->m_url,
+ * MAX_SUBSCRIBERS,
+ * event_callback, pr,
+ * SIPTAG_CONTACT(m),
+ * SIPTAG_SERVER_STR("Sofia-SIP NEA"),
+ * TAG_NULL());
+ * ...
+ * }
+ * @endcode
+ *
+ * @section nea_event_create Creating Events
+ *
+ * Next, events are created. The function nea_event_create () defines
+ * an event, its package and content types (a comma separated
+ * list). The parameter presence_callback defines the callback
+ * function that is called when a someone subscribes to a defined
+ * event.
+ *
+ * @code
+ * #define PRESENCE_PACKAGE "presence"
+ * #define XPIDF_MIME_TYPE "application/xpidf+xml"
+ * #define PIDF_MIME_TYPE "application/cpim-pidf+xml"
+
+ * ne = nea_event_create(pr->pr_nes, presence_callback, ep,
+ * PRESENCE_PACKAGE, NULL,
+ * PIDF_MIME_TYPE,
+ * PIDF_MIME_TYPE "," XPIDF_MIME_TYPE);
+ * @endcode
+ *
+ * @section nea_server_update Operating with event payloads
+ *
+ * A new payload can be inserted to a event with the function
+ * nea_server_update(). The 4th parameter describes if the updated
+ * content is a fake (for unauthorized subscribers). A real payload is
+ * inserted (updated) with the 4th parameter being 0. If the event is
+ * not updated with the content type @a ct before, a new content type
+ * format for the event is created. Otherwise the old payload is
+ * replaced with the new one.
+ *
+ * After the update, subscribers of the event are notified (with SIP
+ * NOTIFY) of the changed payload with nea_server_update ().
+ *
+ * @code
+ * nea_server_update(pr->pr_nes, home, event, 1,
+ * SIPTAG_CONTENT_TYPE(ct),
+ * SIPTAG_PAYLOAD(pl),
+ * TAG_END());
+
+ * nea_server_notify(pr->pr_nes, event);
+ * @endcode
+ *
+ * Obtaining the event's payload and removing it is presented in the
+ * example below. The event is defined as a part of the @a package_t
+ * structure. Function nea_payloads_get() is used to return a payload
+ * (in this case content type being predefined
+ * "application/cpim-pidf+xml"). The real and fake payloads are stored
+ * in the structure #nea_payloads_t. Finally, the payload is removed
+ * with nea_payload_remove().
+ *
+ * @code
+ * int remove_old_payload(package_t *ep)
+ * {
+ * nea_payloads_t *np;
+ * sip_content_type_t *ct;
+ * sip_payload_t *real;
+ * sip_payload_t *fake;
+
+ * event = ep->ep_event;
+
+ * np = nea_payloads_get(event, PIDF_MIME_TYPE);
+ * ct = nea_content_type_get(np);
+ * real = nea_payload_get(np);
+ * fake = nea_fake_get(np);
+ * nea_payload_remove(ep->ep_home, np);
+
+ * return 0;
+ * }
+ * @endcode
+ */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/nea_debug.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/nea_debug.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,83 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/*
+ */
+
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nea_debug.c Debug Log for Nokia Event Client API
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ */
+
+#include <stddef.h>
+
+#include "nea_debug.h"
+
+/**@var NEA_DEBUG
+ *
+ * Environment variable determining the debug log level for @b nea
+ * module.
+ *
+ * The NEA_DEBUG environment variable is used to determine the debug
+ * logging level for @b nea module. The default level is 3.
+ *
+ * @sa <su_debug.h>, nea_log, SOFIA_DEBUG
+ */
+extern char const NEA_DEBUG[];
+
+#ifndef SU_DEBUG
+#define SU_DEBUG 3
+#endif
+
+/**Debug log for @b nea module.
+ *
+ * The nea_log is the log object used by @b nea module. The level of
+ * #nea_log is set using #NEA_DEBUG environment variable.
+ */
+su_log_t nea_log[] = { SU_LOG_INIT("nea", "NEA_DEBUG", SU_DEBUG) };
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/nea_debug.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/nea_debug.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,39 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef NEA_DEBUG_H
+/** Defined when <nea_debug.h> has been included. */
+#define NEA_DEBUG_H
+
+/**@file nea_debug.h
+ * @brief Debug log for @b nea module.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @date Created: Thu Sep 6 19:06:40 2001 ppessi
+ */
+
+#define SU_LOG (nea_log)
+#include <sofia-sip/su_debug.h>
+
+#endif /* !defined(NEA_DEBUG_H) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/nea_event.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/nea_event.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,63 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**
+ * @file nea_event.c
+ * @brief Default MIME type for certain events.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Dec 11 20:28:46 2003 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <string.h>
+
+char const *nea_default_content_type(char const *event)
+{
+ char const *template = strrchr(event, '.');
+
+ if (strcmp(event, "presence") == 0)
+ return "application/pidf+xml";
+ else if (strcmp(event, "cpl") == 0)
+ return "application/cpl+xml";
+ else if (strcmp(event, "reg") == 0)
+ return "application/reginfo+xml";
+ else if (strcmp(event, "presencelist") == 0)
+ return "application/cpim-plidf+xml";
+ else if (strcmp(event, "message-summary") == 0)
+ return "application/simple-message-summary";
+ else if (template && strcmp(template, ".acl") == 0)
+ return "application/vnd.nokia-acl+xml";
+ else if (template && strcmp(template, ".winfo") == 0)
+ return "application/watcherinfo+xml";
+ else if (template && strcmp(template, ".list") == 0)
+ return "application/rlmi+xml";
+ else if (strcmp(event, "rlmi") == 0)
+ return "application/rlmi+xml";
+ else
+ return NULL;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/nea_server.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/nea_server.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,2375 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@file nea_server.c
+ * @brief Nokia Event API - event notifier implementation.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ *
+ * @date Created: Wed Feb 14 18:37:04 EET 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <sofia-sip/sip.h>
+#include <sofia-sip/sip_header.h>
+#include <sofia-sip/sip_util.h>
+#include <sofia-sip/sip_status.h>
+#include <sofia-sip/su_tagarg.h>
+
+#include "nea_debug.h"
+
+#define NONE ((void *)- 1)
+
+#define SU_ROOT_MAGIC_T struct nea_server_s
+#define SU_MSG_ARG_T tagi_t
+
+#define NTA_AGENT_MAGIC_T struct nea_server_s
+#define NTA_LEG_MAGIC_T struct nea_sub_s
+#define NTA_INCOMING_MAGIC_T struct nea_sub_s
+#define NTA_OUTGOING_MAGIC_T struct nea_sub_s
+
+#include <sofia-sip/nea.h>
+#include <sofia-sip/htable.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <limits.h>
+
+/** Number of primary views (with different MIME type or content) */
+#define NEA_VIEW_MAX (8)
+
+/** Server object, created for every notifier.
+ */
+struct nea_server_s {
+ su_home_t nes_home[1];
+ su_root_t *nes_root;
+ su_timer_t *nes_timer;
+
+ nta_agent_t *nes_agent;
+ nta_leg_t *nes_leg;
+
+ nea_sub_t *nes_subscribers;
+
+ sip_require_t *nes_require;
+
+ sip_time_t nes_min_expires;
+ sip_time_t nes_expires;
+ sip_time_t nes_max_expires;
+
+ int nes_max_subs;
+ unsigned nes_throttle; /**< Default throttle */
+ unsigned nes_min_throttle; /**< Minimum throttle */
+ unsigned nes_eventlist:1; /**< Eventlist only */
+ unsigned nes_in_callback : 1;
+ unsigned nes_pending_destroy : 1;
+ unsigned nes_pending_flush : 1;
+ unsigned nes_202_before_notify:1;
+
+ unsigned nes_in_list;
+
+ unsigned nes_throttled; /**< Throttled notifications? */
+
+ char const *nes_server;
+
+ sip_contact_t *nes_eventity_uri;
+ sip_allow_events_t *nes_allow_events;
+
+ sip_allow_t *nes_allow_methods;
+
+ nea_new_event_f *nes_callback;
+ nea_smagic_t *nes_context;
+
+ /** Events.
+ * Each subscriber will be added to one of these. */
+ nea_event_t *nes_events;
+};
+
+
+/** Supported events and their subscribers */
+struct nea_event_s {
+ nea_event_t *ev_next;
+ nea_event_t **ev_prev;
+
+ nea_watcher_f *ev_callback;
+ nea_emagic_t *ev_magic;
+
+ unsigned ev_throttle; /**< Default throttle */
+ unsigned ev_min_throttle; /**< Minimum throttle */
+ unsigned ev_eventlist:1; /**< Eventlist is supported */
+ unsigned ev_reliable:1; /**< Keep all notifications */
+ unsigned :0;
+
+ /** Sequence number of first unsent update */
+ unsigned ev_throttling;
+ unsigned ev_updated; /**< Sequence number for updates */
+ sip_require_t *ev_require; /**< Required features */
+ sip_supported_t *ev_supported; /**< Supported features */
+
+ sip_event_t *ev_event;
+ sip_accept_t const *ev_default;/**< Default content type */
+ sip_accept_t const *ev_accept; /**< Supported content types */
+
+ nea_event_view_t *ev_views[NEA_VIEW_MAX + 1];
+};
+
+typedef struct nea_event_queue_s nea_event_queue_t;
+
+/** Object representing particular view of event */
+struct nea_event_view_s
+{
+ nea_event_view_t *evv_next;
+ nea_event_view_t *evv_primary; /**< Backpointer to the primary view */
+
+ nea_evmagic_t *evv_magic;
+
+ unsigned evv_throttle; /**< Default throttle */
+ unsigned evv_min_throttle; /**< Minimum throttle */
+ unsigned evv_fake:1; /**< This is "fake" (ie. default) view */
+ unsigned evv_private:1; /**< This is private view */
+ unsigned evv_reliable:1; /**< Keep all notifications */
+ unsigned:0;
+
+ /** Queued notification */
+ struct nea_event_queue_s
+ {
+ nea_event_queue_t *evq_next;
+ unsigned evq_updated;
+ unsigned evq_version;
+ sip_content_type_t *evq_content_type;
+ sip_payload_t *evq_payload;
+ } evv_head[1];
+};
+
+#define evv_version evv_head->evq_version
+#define evv_updated evv_head->evq_updated
+#define evv_content_type evv_head->evq_content_type
+#define evv_payload evv_head->evq_payload
+
+
+/** Subscription object
+ */
+struct nea_sub_s {
+ nea_sub_t *s_next;
+ nea_sub_t **s_prev;
+
+ nta_leg_t *s_leg;
+ nta_incoming_t *s_irq;
+ nta_outgoing_t *s_oreq;
+
+ nea_server_t *s_nes;
+
+ sip_contact_t *s_local; /**< Local contact */
+
+ sip_from_t *s_from;
+ sip_contact_t *s_remote; /**< Remote contact */
+ /* sip_accept_t *s_accept; */
+ sip_event_t *s_id;
+
+ nea_event_t *s_event;
+ nea_event_view_t *s_view;
+ nea_state_t s_state;
+
+ char const *s_extended;
+
+ sip_content_type_t *s_content_type; /** Content-Type of SUBSCRIBE body. */
+ sip_payload_t *s_payload; /**< Body of SUBSCRIBE. */
+
+ unsigned s_processing : 1;
+ unsigned s_rejected : 1;
+ unsigned s_pending_flush : 1;
+ unsigned s_garbage : 1;
+ unsigned s_fake : 1; /**< Do not send real information to user */
+ unsigned s_eventlist : 1; /**< Subscriber supported eventlist */
+
+ sip_time_t s_subscribed; /**< When first SUBSCRIBE was recv */
+ sip_time_t s_notified; /**< When last notification was sent */
+ sip_time_t s_expires; /**< Expiration time. */
+
+ unsigned s_version; /**< Version number set by application */
+
+ unsigned s_latest; /**< External version of latest payload */
+ unsigned s_updated; /**< Internal version of latest payload */
+ unsigned s_throttle; /**< Minimum time between notifications */
+};
+
+/* Prototypes */
+
+static void nea_server_pending_flush(nea_server_t *nes);
+
+static int nea_view_update(nea_server_t *nes,
+ nea_event_t *ev,
+ nea_event_view_t **evvp,
+ int private,
+ int fake,
+ tag_type_t tag,
+ tag_value_t value,
+ ...);
+
+static nea_sub_t *nea_sub_create(nea_server_t *nes);
+static int nea_sub_is_removed(nea_sub_t const *s);
+static void nea_sub_remove(nea_sub_t *s);
+static void nea_sub_destroy(nea_sub_t *s);
+
+static
+int nea_server_callback(nea_sub_t *nes_as_sub,
+ nta_leg_t *leg,
+ nta_incoming_t *irq,
+ sip_t const *sip);
+
+static int nea_sub_process_incoming(nea_sub_t *s,
+ nta_leg_t *leg,
+ nta_incoming_t *irq,
+ sip_t const *sip);
+
+static int nea_sub_process_subscribe(nea_sub_t *s,
+ nta_leg_t *leg,
+ nta_incoming_t *irq,
+ sip_t const *sip);
+
+static int nea_sub_notify(nea_server_t *nes,
+ nea_sub_t *s,
+ sip_time_t now,
+ tag_type_t tag, tag_value_t value, ...);
+
+static int response_to_notify(nea_sub_t *s,
+ nta_outgoing_t *oreq,
+ sip_t const *sip);
+
+static void nes_event_timer(nea_server_t *nes,
+ su_timer_t *timer,
+ su_timer_arg_t *arg);
+
+static int nea_view_queue(nea_server_t *nes,
+ nea_event_view_t *evv,
+ nea_event_queue_t *evq);
+
+/** Assign an event view to subscriber. */
+static inline
+void nea_sub_assign_view(nea_sub_t *s, nea_event_view_t *evv)
+{
+ if (s->s_view != evv)
+ /* Make sure we send a notification */
+ s->s_updated = evv->evv_updated - 1;
+ s->s_view = evv;
+ s->s_throttle = evv->evv_throttle;
+}
+
+static inline
+void nea_subnode_init(nea_subnode_t *sn, nea_sub_t *s, sip_time_t now)
+{
+ sn->sn_state = s->s_state;
+ sn->sn_fake = s->s_fake;
+ sn->sn_subscriber = s;
+ sn->sn_event = s->s_event;
+ sn->sn_remote = s->s_from;
+ sn->sn_contact = s->s_remote;
+ sn->sn_content_type = s->s_content_type;
+ sn->sn_payload = s->s_payload;
+ if (s->s_expires != 0 && (int)(s->s_expires - now) > 0)
+ sn->sn_expires = s->s_expires - now;
+ else
+ sn->sn_expires = 0;
+ sn->sn_latest = s->s_latest;
+ sn->sn_throttle = s->s_throttle;
+ sn->sn_eventlist = s->s_eventlist;
+ sn->sn_version = s->s_version;
+ sn->sn_subscribed = now - s->s_subscribed;
+ sn->sn_notified = s->s_notified;
+ sn->sn_view = s->s_view;
+}
+
+/** Create an event server.
+ *
+ * The function nea_server_create() initializes an event server object and
+ * registers it with @b nta. An event server object takes care of all events
+ * for a particular URI (@em eventity).
+ *
+ * @param agent pointer to an @b nta agent object
+ * @param root pointer to an @b root object
+ * @param url url of the server to be created
+ * @param max_subs maximum number of subscriptions
+ * @param callback authorization function,
+ * or @c NULL if no authorization is required
+ * @param context server context (pointer to application data)
+ * @param tag, value, ... optional list of tag parameters
+ *
+ * @TAGS
+ * The function nea_server_create() takes the following tag values as its
+ * arguments:
+ * <dl>
+ *
+ * <dt>SIPTAG_CONTACT() or SIPTAG_CONTACT_STR()
+ * <dd>The target address of the event server.
+ *
+ * <dt>SIPTAG_ALLOW_EVENTS()
+ * <dd>The initial list of events supported by eventity. This list is
+ * extended whenever a new event is created with nea_event_tcreate().
+ *
+ * <dt>SIPTAG_SERVER_STR()
+ * <dd>The @b Server header for the event server.
+ *
+ * <dt>NEATAG_MINSUB()
+ * <dd>Minimum duration of a subscription.
+ *
+ * <dt>NEATAG_THROTTLE()
+ * <dd>Default value for event throttle (by default, 5 seconds).
+ * Throttle determines the minimum interval betweeen notifications. Note
+ * that the notification indicating that the subscription has terminated
+ * will be sent regardless of throttle.
+ *
+ * The default throttle value is used if the subscriber does not include
+ * a throttle parameter in @ref sip_event "Event" header of SUBSCRIBE request.
+ *
+ * <dt>NEATAG_MINTHROTTLE()
+ * <dd>Minimum allowed throttle value (by default, 5 seconds).
+ *
+ * <dt>NEATAG_EVENTLIST()
+ * <dd>If true, the subscribers must support eventlists. If SIPTAG_REQUIRE()
+ * is given, it must contain the "eventlist" feature.
+ *
+ * <dt>NEATAG_DIALOG()
+ * <dd>Give an optional NTA destination leg to event server.
+ *
+ * <dt>SIPTAG_REQUIRE()/SIPTAG_REQUIRE_STR()
+ * <dd>The @b Require header for the event server. The subscribers must
+ * indicate support the specified features.
+ *
+ * </dl>
+ *
+ * @return
+ * The function nea_server_create() returns a pointer to an event server
+ * object, or @c NULL upon an error.
+ */
+nea_server_t *nea_server_create(nta_agent_t *agent,
+ su_root_t *root,
+ url_t const *url,
+ int max_subs,
+ nea_new_event_f *callback,
+ nea_smagic_t *context,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ nea_server_t *nes = NULL;
+ sip_contact_t const *contact = NULL;
+ sip_allow_events_t const *allow_events = NULL;
+ sip_require_t const *rq = NULL;
+ char const *contact_str = NULL;
+ char const *server_str = NULL;
+ char const *rq_str = NULL;
+ unsigned
+ min_expires = 15 * 60,
+ expires = NEA_DEFAULT_EXPIRES,
+ max_expires = 24 * 60 * 60;
+ nta_leg_t *leg = NONE;
+ unsigned throttle = 5, min_throttle = throttle;
+ int eventlist = 0;
+
+ {
+ ta_list ta;
+
+ ta_start(ta, tag, value);
+
+ tl_gets(ta_args(ta),
+ SIPTAG_CONTACT_REF(contact),
+ SIPTAG_CONTACT_STR_REF(contact_str),
+ SIPTAG_ALLOW_EVENTS_REF(allow_events),
+ SIPTAG_SERVER_STR_REF(server_str),
+ SIPTAG_REQUIRE_REF(rq),
+ SIPTAG_REQUIRE_STR_REF(rq_str),
+ NEATAG_MIN_EXPIRES_REF(min_expires),
+ NEATAG_EXPIRES_REF(expires),
+ NEATAG_MAX_EXPIRES_REF(max_expires),
+ NEATAG_DIALOG_REF(leg),
+ NEATAG_THROTTLE_REF(throttle),
+ NEATAG_MINTHROTTLE_REF(min_throttle),
+ NEATAG_EVENTLIST_REF(eventlist),
+ TAG_NULL());
+
+ ta_end(ta);
+ }
+
+ if (throttle < min_throttle)
+ throttle = min_throttle;
+
+ if (!url) {
+ SU_DEBUG_5(("nea_server_create(): invalid url\n"));
+ return NULL;
+ }
+
+ if (min_expires > expires || expires > max_expires) {
+ SU_DEBUG_5(("nea_server_create(): invalid expiration range\n"));
+ return NULL;
+ }
+
+ nes = su_home_new(sizeof(nea_server_t));
+
+ if (nes) {
+ su_home_t *home = nes->nes_home;
+
+ nes->nes_root = root;
+ nes->nes_agent = agent;
+
+ nes->nes_max_subs = max_subs;
+
+ nes->nes_min_expires = min_expires;
+ nes->nes_expires = expires;
+ nes->nes_max_expires = max_expires;
+
+ nes->nes_throttle = throttle;
+ nes->nes_min_throttle = min_throttle;
+
+ if (allow_events)
+ nes->nes_allow_events = sip_allow_events_dup(home, allow_events);
+ else
+ nes->nes_allow_events = sip_allow_events_make(home, "");
+
+ nes->nes_allow_methods = sip_allow_make(home, "SUBSCRIBE");
+
+ nes->nes_server =
+ su_sprintf(home, "%s%snea/" NEA_VERSION_STR " %s",
+ server_str ? server_str : "",
+ server_str ? " " : "",
+ nta_agent_version(agent));
+
+ if (contact)
+ nes->nes_eventity_uri = sip_contact_dup(home, contact);
+ else if (contact_str)
+ nes->nes_eventity_uri = sip_contact_make(home, contact_str);
+ else
+ nes->nes_eventity_uri = sip_contact_create(home, (url_string_t *)url, NULL);
+
+ if (leg != NONE) {
+ nes->nes_leg = leg;
+ if (leg != NULL)
+ nta_leg_bind(leg, nea_server_callback, (nea_sub_t*)nes);
+ } else {
+ nes->nes_leg = nta_leg_tcreate(agent,
+ nea_server_callback,
+ (nea_sub_t*)nes,
+ NTATAG_NO_DIALOG(1),
+ NTATAG_METHOD("SUBSCRIBE"),
+ URLTAG_URL(url),
+ TAG_END());
+ }
+
+ nes->nes_eventlist = eventlist; /* Every event is a list */
+ if (eventlist && rq == NULL && rq_str == NULL)
+ rq_str = "eventlist";
+
+ if (rq)
+ nes->nes_require = sip_require_dup(nes->nes_home, rq);
+ else if (rq_str)
+ nes->nes_require = sip_require_make(nes->nes_home, rq_str);
+
+ nes->nes_timer = su_timer_create(su_root_task(nes->nes_root),
+ nes->nes_min_throttle
+ ? 500L * nes->nes_min_throttle
+ : 500L);
+
+ if (nes->nes_allow_events &&
+ nes->nes_eventity_uri &&
+ (nes->nes_leg || leg == NULL) &&
+ nes->nes_timer) {
+ SU_DEBUG_5(("nea_server_create(%p): success\n", nes));
+ su_timer_set(nes->nes_timer, nes_event_timer, nes);
+
+ nes->nes_callback = callback;
+ nes->nes_context = context;
+ }
+ else {
+ SU_DEBUG_5(("nea_server_create(%p): failed\n", nes));
+ nea_server_destroy(nes), nes = NULL;
+ }
+ }
+
+ return nes;
+}
+
+/** Invoke the new event callback.
+ *
+ * The function nes_event_callback() calls the callback provided by the
+ * application using the notifier object.
+ *
+ * @param nes pointer to notifier object
+ * @param ev pointer to event view
+ * @param s pointer to subscription object
+ * @param sip pointer to subscribe request
+ *
+ * @return
+ * The function nes_event_callback() returns -1 if the notifier object
+ * has been destroyed by the callback function, 0 otherwise.
+ */
+static
+int nes_new_event_callback(nea_server_t *nes,
+ nea_event_t **ev_p,
+ nea_event_view_t **view_p,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ if (nes->nes_callback)
+ return nes->nes_callback(nes->nes_context, nes, ev_p, view_p, irq, sip);
+ else
+ return -1;
+}
+
+/** Shutdown event server.
+ */
+int nea_server_shutdown(nea_server_t *nes,
+ int retry_after)
+{
+ nea_sub_t *s;
+ int status = 200;
+ int in_callback;
+
+ if (nes == NULL)
+ return 500;
+
+ if (nes->nes_in_callback) {
+ SU_DEBUG_5(("nea_server_shutdown(%p) while in callback\n", nes));
+ return 100;
+ }
+
+ SU_DEBUG_5(("nea_server_shutdown(%p)\n", nes));
+
+ in_callback = nes->nes_in_callback; nes->nes_in_callback = 1;
+
+ for (s = nes->nes_subscribers; s; s = s->s_next) {
+ if (s->s_state == nea_terminated)
+ continue;
+ if (s->s_pending_flush)
+ continue;
+ if (s->s_oreq == NULL)
+ nea_sub_auth(s, nea_terminated,
+ TAG_IF(retry_after, NEATAG_REASON("probation")),
+ TAG_IF(!retry_after, NEATAG_REASON("deactivated")),
+ TAG_IF(retry_after, NEATAG_RETRY_AFTER(retry_after)),
+ TAG_END());
+ else
+ status = 180;
+ }
+
+ nes->nes_in_callback = in_callback;
+
+ return 200;
+}
+
+void nea_server_destroy(nea_server_t *nes)
+{
+ if (nes == NULL)
+ return;
+
+ if (nes->nes_in_callback) {
+ SU_DEBUG_5(("nea_server_destroy(%p) while in callback\n", nes));
+ nes->nes_pending_destroy = 1;
+ return;
+ }
+
+ SU_DEBUG_5(("nea_server_destroy(%p)\n", nes));
+
+ nta_leg_destroy(nes->nes_leg), nes->nes_leg = NULL;
+
+ while (nes->nes_subscribers)
+ nea_sub_destroy(nes->nes_subscribers);
+
+ su_timer_destroy(nes->nes_timer), nes->nes_timer = NULL;
+
+ su_home_unref(nes->nes_home);
+}
+
+/* ----------------------------------------------------------------- */
+
+/**Update server payload.
+ *
+ * A nea event server has typed content that is delivered to the
+ * subscribers. Different content types are each assigned a separate primary
+ * view. There can be also primary views with "fake" content, content
+ * delivered to politely blocked subscribers.
+ *
+ * In addition to primary views, there can be secondary views, views
+ * assigned to a single subscriber only.
+ *
+ * @TAGS
+ * The following tagged arguments are accepted:
+ * <dl>
+ *
+ * <dt>SIPTAG_PAYLOAD() or SIPTAG_PAYLOAD_STR()
+ * <dd>Updated event content.
+ *
+ * <dt>SIPTAG_CONTENT_TYPE() or SIPTAG_CONTENT_TYPE_STR().
+ * <dd>MIME type of the content.
+ *
+ * <dt>NEATAG_FAKE(fak)
+ * <dd>If @a fake is true, 'fake' view is updated.
+ *
+ * <dt>NEATAG_VIEW(view)
+ * <dd>If included in tagged arguments, @a view is * updated. Used when
+ * updating secondary view.
+ *
+ * <dt>NEATAG_VERSION(version)
+ * <dd>The application-provided @a version for
+ * event content. After updated content has been sent to subscriber, @a
+ * version is copied to subscriber information structure.
+ *
+ * <dt>NEATAG_EVMAGIC(context)
+ * <dd>Application-provided @a context pointer.
+ * The @a context pointer is returned by nea_view_magic() function.
+ *
+ * <dt>NEATAG_RELIABLE(reliable)
+ * <dd>The @a reliable flag determines how overlapping updates are handled.
+ * If @a reliable is true, all updates are delivered to the subscribers.
+ *
+ * <dt>NEATAG_THROTTLE(throttl)
+ * <dd>Default value for event throttle for updated event view. Throttle
+ * determines the minimum interval in seconds betweeen notifications. Note
+ * that the notification indicating that the subscription has terminated
+ * will be sent regardless of throttle.
+ *
+ * The default throttle value is used if the subscriber does not include
+ * a throttle parameter in @ref sip_event "Event" header of SUBSCRIBE request.
+ *
+ * <dt>NEATAG_MINTHROTTLE()
+ * <dd>Minimum allowed throttle value for updated event view.
+ *
+ * </dl>
+ *
+ * @retval -1 upon an error.
+ * @retval 0 if event document was not updated.
+ * @retval 1 if event document was updated.
+ */
+int nea_server_update(nea_server_t *nes,
+ nea_event_t *ev,
+ tag_type_t tag,
+ tag_value_t value,
+ ...)
+{
+ nea_event_view_t *evv = NULL;
+ int fake = 0, updated;
+
+ ta_list ta;
+
+ if (ev == NULL)
+ ev = nes->nes_events;
+
+ ta_start(ta, tag, value);
+
+ tl_gets(ta_args(ta),
+ NEATAG_FAKE_REF(fake),
+ NEATAG_VIEW_REF(evv),
+ TAG_NULL());
+
+ updated = nea_view_update(nes, ev, &evv, 0, fake, ta_tags(ta));
+
+ ta_end(ta);
+
+ return updated;
+}
+
+static
+int nea_view_update(nea_server_t *nes,
+ nea_event_t *ev,
+ nea_event_view_t **evvp,
+ int private,
+ int fake,
+ tag_type_t tag,
+ tag_value_t value,
+ ...)
+{
+ ta_list ta;
+
+ su_home_t *home = nes->nes_home;
+
+ sip_content_type_t const *ct = NULL;
+ char const *cts = NULL, *pls = NULL;
+ sip_payload_t const *pl = NULL;
+ sip_payload_t *new_pl;
+ nea_event_view_t *evv, **eevv = &evv;
+ nea_event_view_t *primary = NULL, **primary_p = &primary;
+ unsigned version = UINT_MAX;
+ nea_evmagic_t *evmagic = NULL;
+ int reliable = ev->ev_reliable;
+ unsigned throttle = ev->ev_throttle;
+ unsigned min_throttle = ev->ev_min_throttle;
+
+ nea_event_queue_t evq[1] = {{ NULL }};
+
+ ta_start(ta, tag, value);
+
+ tl_gets(ta_args(ta),
+ SIPTAG_CONTENT_TYPE_REF(ct),
+ SIPTAG_CONTENT_TYPE_STR_REF(cts),
+ SIPTAG_PAYLOAD_REF(pl),
+ SIPTAG_PAYLOAD_STR_REF(pls),
+ NEATAG_VERSION_REF(version),
+ NEATAG_EVMAGIC_REF(evmagic),
+ NEATAG_RELIABLE_REF(reliable),
+ NEATAG_THROTTLE_REF(throttle),
+ NEATAG_MINTHROTTLE_REF(min_throttle),
+ TAG_NULL());
+
+ ta_end(ta);
+
+ if (min_throttle < throttle)
+ min_throttle = throttle;
+
+ if (ct == NULL && cts == NULL)
+ return -1;
+
+ if (ct)
+ cts = ct->c_type;
+
+ evv = *evvp;
+
+ if (!evv) {
+ int i;
+
+ /* Check if the payload type already exists */
+ for (i = 0; (evv = ev->ev_views[i]); i++)
+ if (str0casecmp(cts, evv->evv_content_type->c_type) == 0)
+ break;
+
+ if (private && evv == NULL) /* No private view without primary view. */
+ return -1;
+
+ if (i == NEA_VIEW_MAX) /* Too many primary views. */
+ return -1;
+
+ primary_p = eevv = ev->ev_views + i;
+
+ /* Search for fakeness/eventlist/private view */
+ if (evv && (private || evv->evv_private || evv->evv_fake != (unsigned)fake)) {
+ for (eevv = &evv->evv_next; (evv = *eevv); eevv = &evv->evv_next) {
+ if (private || evv->evv_private)
+ continue;
+ if (evv->evv_fake == (unsigned)fake)
+ break;
+ }
+ }
+ }
+
+ /* New event view, allocate and link to chain */
+ if (!evv) {
+ sip_content_type_t *new_ct;
+
+ evv = su_zalloc(home, sizeof (*evv));
+ if (!evv)
+ return -1;
+
+ new_pl = pl ? sip_payload_dup(home, pl)
+ : sip_payload_make(home, pls);
+
+ new_ct = ct ? sip_content_type_dup(home, ct)
+ : sip_content_type_make(home, cts);
+
+ if ((!new_pl && pl) || !new_ct) {
+ su_free(home, evv); su_free(home, new_pl);
+ return -1;
+ }
+
+ *evvp = *eevv = evv;
+
+ evv->evv_primary = *primary_p;
+ evv->evv_private = private != 0;
+ evv->evv_fake = fake != 0;
+ evv->evv_reliable = reliable != 0;
+ evv->evv_magic = evmagic;
+ evv->evv_content_type = new_ct;
+ evv->evv_payload = new_pl;
+ evv->evv_throttle = throttle;
+ evv->evv_min_throttle = min_throttle;
+
+ assert(evv->evv_content_type);
+ }
+ else {
+ if (pl &&
+ evv->evv_payload &&
+ evv->evv_payload->pl_len == pl->pl_len &&
+ memcmp(evv->evv_payload->pl_data, pl->pl_data, pl->pl_len) == 0)
+ return 0;
+ if (!pl && pls && evv->evv_payload &&
+ evv->evv_payload->pl_len == strlen(pls) &&
+ memcmp(evv->evv_payload->pl_data, pls, evv->evv_payload->pl_len) == 0)
+ return 0;
+ if (!pl && !pls && !evv->evv_payload)
+ return 0;
+
+ *evq = *evv->evv_head;
+
+ new_pl = pl ? sip_payload_dup(home, pl) : sip_payload_make(home, pls);
+
+ if (!new_pl && (pl || pls))
+ return -1;
+
+ evv->evv_payload = new_pl;
+ }
+
+ if (version != UINT_MAX)
+ evv->evv_version = version;
+
+ if (!fake)
+ evv->evv_updated = ++ev->ev_updated;
+
+ if (evq->evq_content_type)
+ nea_view_queue(nes, evv, evq);
+
+ SU_DEBUG_7(("nea_server_update(%p): %s (%s)\n",
+ nes, ev->ev_event->o_type, evv->evv_content_type->c_type));
+
+ return 1;
+}
+
+nea_event_view_t *nea_view_create(nea_server_t *nes,
+ nea_event_t *ev,
+ nea_evmagic_t *magic,
+ tag_type_t tag,
+ tag_value_t value,
+ ...)
+{
+ nea_event_view_t *evv = NULL;
+ ta_list ta;
+
+ if (ev == NULL)
+ return NULL;
+
+ ta_start(ta, tag, value);
+
+ nea_view_update(nes, ev, &evv, 1, 0, ta_tags(ta));
+
+ ta_end(ta);
+
+ return evv;
+}
+
+void nea_view_destroy(nea_server_t *nes, nea_event_view_t *evv)
+{
+ nea_event_view_t **evvp;
+ nea_sub_t *s;
+
+ if (nes == NULL || evv == NULL || !evv->evv_private)
+ return;
+
+ assert(evv->evv_primary && evv != evv->evv_primary);
+
+ for (evvp = &evv->evv_primary->evv_next; *evvp; evvp = &(*evvp)->evv_next)
+ if (*evvp == evv) {
+ *evvp = evv->evv_next;
+ break;
+ }
+
+ for (s = nes->nes_subscribers; s; s = s->s_next)
+ if (s->s_view == evv)
+ nea_sub_assign_view(s, evv->evv_primary);
+
+ su_free(nes->nes_home, evv->evv_content_type);
+ su_free(nes->nes_home, evv->evv_payload);
+ su_free(nes->nes_home, evv);
+}
+
+nea_evmagic_t *nea_view_magic(nea_event_view_t const *evv)
+{
+ return evv ? evv->evv_magic : NULL;
+}
+
+void nea_view_set_magic(nea_event_view_t *evv, nea_evmagic_t *magic)
+{
+ if (evv)
+ evv->evv_magic = magic;
+}
+
+unsigned nea_view_version(nea_event_view_t const *evv)
+{
+ return evv ? evv->evv_version : 0;
+}
+
+/** Get primary, non-fake event view for given content type */
+nea_event_view_t *nea_event_view(nea_event_t *ev, char const *content_type)
+{
+ int i;
+ nea_event_view_t *evv;
+
+ /* Check if the payload type already exists */
+ for (i = 0; ev->ev_views[i]; i++)
+ if (str0casecmp(content_type, ev->ev_views[i]->evv_content_type->c_type) == 0)
+ break;
+
+ for (evv = ev->ev_views[i]; evv; evv = evv->evv_next)
+ if (!evv->evv_fake)
+ return evv;
+
+ return ev->ev_views[i];
+}
+
+/** Get the content type for event view */
+sip_content_type_t const *nea_view_content_type(nea_event_view_t const *evv)
+{
+ return evv ? evv->evv_content_type : NULL;
+}
+
+
+/** Queue an old notification if needed. */
+static
+int nea_view_queue(nea_server_t *nes,
+ nea_event_view_t *evv,
+ nea_event_queue_t *evq)
+{
+ nea_sub_t *s = NULL;
+
+ assert(nes && evv && evq);
+
+ if (evv->evv_reliable)
+ for (s = nes->nes_subscribers; s; s = s->s_next) {
+ if (s->s_view != evv)
+ continue;
+ if (s->s_updated > evq->evq_updated)
+ continue;
+ if (s->s_updated == evq->evq_updated && s->s_oreq == NULL)
+ continue;
+ break; /* This */
+ }
+
+ if (s) {
+ nea_event_queue_t *evq0 = su_alloc(nes->nes_home, sizeof *evq);
+
+ if (evq0 == NULL)
+ return -1;
+
+ *evq0 = *evq, evq = evq0;
+
+ /* evq should be copy of old head but with changed payload */
+ assert(evq->evq_next == evv->evv_head->evq_next);
+
+ evv->evv_head->evq_next = evq; /* insert to the queue */
+
+ return 0;
+ }
+
+ su_free(nes->nes_home, (void *)evq->evq_payload);
+
+ return 0;
+}
+
+/** Remove old unneeded notifications. */
+static
+int nea_view_dequeue(nea_server_t *nes,
+ nea_event_t *ev)
+{
+ int i;
+ nea_event_view_t *evv;
+ nea_event_queue_t **prev, *evq;;
+
+ assert(nes && ev);
+
+ for (i = 0; ev->ev_views[i]; i++) {
+ for (evv = ev->ev_views[i]; evv; evv = evv->evv_next) {
+ if (!evv->evv_reliable)
+ continue;
+
+ for (prev = &evv->evv_head->evq_next; *prev; prev = &(*prev)->evq_next)
+ if (ev->ev_throttling >= (*prev)->evq_updated)
+ break;
+
+ /* Free from evq onwards */
+ for (evq = *prev; evq; evq = *prev) {
+ *prev = evq->evq_next;
+ su_free(nes->nes_home, evq->evq_payload);
+ su_free(nes->nes_home, evq);
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------- */
+
+/** Notify watchers.
+ *
+ * @return
+ * The function nea_server_notify() returns number of subscribers that the
+ * notification could be sent, or -1 upon an error.
+ */
+int nea_server_notify(nea_server_t *nes, nea_event_t *ev)
+{
+ sip_time_t now = sip_now();
+ nea_sub_t *s;
+ int notified = 0, throttled = nes->nes_throttled;
+
+ SU_DEBUG_7(("nea_server_notify(%p): %s\n", nes, ev ? ev->ev_event->o_type: ""));
+
+ ++nes->nes_in_list;
+
+ nes->nes_throttled = 0;
+
+ if (ev == NULL)
+ for (ev = nes->nes_events; ev; ev = ev->ev_next)
+ ev->ev_throttling = UINT_MAX;
+ else
+ ev->ev_throttling = UINT_MAX;
+
+ for (s = nes->nes_subscribers; s; s = s->s_next) {
+ if ((ev == NULL || ev == s->s_event) && s->s_state != nea_terminated) {
+ notified += nea_sub_notify(nes, s, now, TAG_END());
+ }
+ }
+
+ if (throttled) {
+ /* Dequeue throttled updates */
+ if (ev == NULL)
+ for (ev = nes->nes_events; ev; ev = ev->ev_next) {
+ nea_view_dequeue(nes, ev);
+ SU_DEBUG_3(("nea_server(): notified %u, throttling at %u\n",
+ notified, ev->ev_throttling));
+ }
+ else {
+ SU_DEBUG_3(("nea_server(): notified %u, throttling at %u\n",
+ notified, ev->ev_throttling));
+ nea_view_dequeue(nes, ev);
+ }
+ }
+
+ if (--nes->nes_in_list == 0 && nes->nes_pending_flush)
+ nea_server_pending_flush(nes);
+
+ return notified;
+}
+
+
+/* ----------------------------------------------------------------- */
+void nea_server_flush(nea_server_t *nes, nea_event_t *event)
+{
+ nea_sub_t *s, **ss;
+ sip_time_t now;
+
+ if (nes == NULL)
+ return;
+
+ now = sip_now();
+
+ for (ss = &nes->nes_subscribers; (s = *ss);) {
+ if ((event == NULL || s->s_event == event) &&
+ (s->s_state == nea_terminated || s->s_expires < now)) {
+ /** On first flush, mark as garbage, remove on second flush */
+ if (!s->s_garbage)
+ s->s_garbage = 1;
+ else if (nes->nes_in_callback || nes->nes_in_list) {
+ nes->nes_pending_flush = 1;
+ (*ss)->s_pending_flush = 1;
+ }
+ else {
+ nea_sub_destroy(*ss);
+ continue;
+ }
+ }
+ ss = &((*ss)->s_next);
+ }
+}
+
+
+/* ----------------------------------------------------------------- */
+static
+void nea_server_pending_flush(nea_server_t *nes)
+{
+ nea_sub_t **ss;
+
+ for (ss = &nes->nes_subscribers; *ss;) {
+ if ((*ss)->s_pending_flush && !(*ss)->s_processing) {
+ nea_sub_destroy(*ss);
+ } else {
+ ss = &((*ss)->s_next);
+ }
+ }
+
+ nes->nes_pending_flush = 0;
+}
+
+/* ----------------------------------------------------------------- */
+nea_sub_t *nea_sub_create(nea_server_t *nes)
+{
+ nea_sub_t *s;
+
+ assert(nes);
+
+ s = su_zalloc(nes->nes_home, sizeof (*s));
+
+ if (s) {
+ s->s_nes = nes;
+ if ((s->s_next = nes->nes_subscribers))
+ s->s_next->s_prev = &s->s_next;
+ s->s_prev = &nes->nes_subscribers;
+ nes->nes_subscribers = s;
+
+ /* Copy default values */
+ s->s_throttle = nes->nes_throttle;
+ }
+
+ return s;
+}
+
+/* ----------------------------------------------------------------- */
+nta_incoming_t *nea_subnode_get_incoming(nea_subnode_t *sn)
+{
+ assert(sn);
+
+ if (sn->sn_subscriber) {
+ return sn->sn_subscriber->s_irq;
+ }
+ return NULL;
+}
+
+/* ----------------------------------------------------------------- */
+void nea_sub_remove(nea_sub_t *s)
+{
+ if (s) {
+ assert(s->s_prev);
+
+ if ((*s->s_prev = s->s_next))
+ s->s_next->s_prev = s->s_prev;
+
+ s->s_prev = NULL;
+ s->s_next = NULL;
+ }
+}
+
+/* ----------------------------------------------------------------- */
+/**Check if subscriber has been removed from list */
+static int nea_sub_is_removed(nea_sub_t const *s)
+{
+ return s->s_prev == NULL;
+}
+
+/* ----------------------------------------------------------------- */
+void nea_sub_destroy(nea_sub_t *s)
+{
+ if (s) {
+ nea_sub_t *del = s;
+ su_home_t *home = del->s_nes->nes_home;
+
+ if (!nea_sub_is_removed(del))
+ nea_sub_remove(del);
+
+ del->s_event = NULL;
+
+ su_free(home, del->s_local), del->s_local = NULL;
+ su_free(home, del->s_remote), del->s_remote = NULL;
+
+ if (del->s_oreq)
+ nta_outgoing_destroy(del->s_oreq), del->s_oreq = NULL;
+ if (del->s_leg)
+ nta_leg_destroy(del->s_leg), del->s_leg = NULL;
+ if (del->s_from)
+ su_free(home, del->s_from), del->s_from = NULL;
+
+ su_free(home, del);
+ }
+}
+
+/** Create a new event.
+ *
+ * The function nea_event_create() creates a new event for the event server.
+ */
+nea_event_t *nea_event_create(nea_server_t *nes,
+ nea_watcher_f *callback,
+ nea_emagic_t *context,
+ char const *name,
+ char const *subname,
+ char const *default_content_type,
+ char const *accept)
+{
+ return nea_event_tcreate(nes, callback, context,
+ name, subname,
+ SIPTAG_CONTENT_TYPE_STR(default_content_type),
+ SIPTAG_ACCEPT_STR(accept),
+ TAG_END());
+}
+
+/** Create a new event (or subevent) with tags */
+nea_event_t *nea_event_tcreate(nea_server_t *nes,
+ nea_watcher_f *callback,
+ nea_emagic_t *context,
+ char const *name,
+ char const *subname,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ nea_event_t *ev, **pev;
+ size_t len = strlen(name);
+ ta_list ta;
+
+ /* Find a matching event */
+ if (subname == NULL) {
+ for (pev = &nes->nes_events; (ev = *pev); pev = &(*pev)->ev_next) {
+ if (strcmp(ev->ev_event->o_type, name) != 0)
+ continue;
+ SU_DEBUG_5(("nea_event_create(): already event %s\n", name));
+ return NULL;
+ }
+ }
+ else {
+ for (pev = &nes->nes_events; (ev = *pev); pev = &(*pev)->ev_next) {
+ if (strncmp(ev->ev_event->o_type, name, len) != 0 ||
+ ev->ev_event->o_type[len] != '.' ||
+ strcmp(subname, ev->ev_event->o_type + len + 1) != 0)
+ continue;
+ SU_DEBUG_5(("nea_event_create(): already event %s.%s\n", name, subname));
+ return NULL;
+ }
+ }
+
+ ta_start(ta, tag, value);
+
+ ev = su_zalloc(nes->nes_home, sizeof (*ev));
+
+ if (ev) {
+ int reliable = 0;
+ sip_content_type_t const *ct = NULL;
+ sip_accept_t const *ac = NULL;
+ sip_supported_t const *k = NULL;
+ sip_require_t const *rq = NULL;
+ char const *ct_str = NULL, *ac_str = NULL, *k_str = NULL, *rq_str = NULL;
+
+ unsigned throttle = nes->nes_throttle, min_throttle = nes->nes_min_throttle;
+ int eventlist = nes->nes_eventlist;
+
+ tl_gets(ta_args(ta),
+ NEATAG_RELIABLE_REF(reliable),
+ NEATAG_THROTTLE_REF(throttle),
+ NEATAG_MINTHROTTLE_REF(min_throttle),
+ NEATAG_EVENTLIST_REF(eventlist),
+ SIPTAG_CONTENT_TYPE_REF(ct),
+ SIPTAG_CONTENT_TYPE_STR_REF(ct_str),
+ SIPTAG_ACCEPT_REF(ac),
+ SIPTAG_ACCEPT_STR_REF(ac_str),
+ SIPTAG_SUPPORTED_REF(k),
+ SIPTAG_SUPPORTED_STR_REF(k_str),
+ SIPTAG_REQUIRE_REF(rq),
+ SIPTAG_REQUIRE_STR_REF(rq_str),
+ TAG_END());
+
+ ev->ev_callback = callback;
+ ev->ev_magic = context;
+ ev->ev_event = sip_event_format(nes->nes_home, "%s%s%s",
+ name,
+ subname ? "." : "",
+ subname ? subname : "");
+
+ ev->ev_reliable = reliable != 0;
+ ev->ev_throttle = throttle;
+ ev->ev_min_throttle = min_throttle;
+ ev->ev_eventlist = eventlist;
+
+ if (eventlist && rq == NULL && rq_str == NULL)
+ rq_str = "eventlist";
+
+ if (rq)
+ ev->ev_require = sip_require_dup(nes->nes_home, rq);
+ else if (rq_str)
+ ev->ev_require = sip_require_make(nes->nes_home, rq_str);
+
+ if (ev->ev_event) {
+#define sip_allow_events_find(k, i) sip_params_find(k->k_items, i)
+ if (!sip_allow_events_find(nes->nes_allow_events,
+ ev->ev_event->o_type))
+ sip_allow_events_add(nes->nes_home, nes->nes_allow_events,
+ ev->ev_event->o_type);
+ }
+
+ if (ct)
+ ev->ev_default = sip_accept_make(nes->nes_home, ct->c_type);
+ else
+ ev->ev_default = sip_accept_make(nes->nes_home, ct_str);
+
+ if (ac == NULL && ac_str == NULL)
+ ac_str = ct ? ct->c_type : ct_str;
+
+ if (ac)
+ ev->ev_accept = sip_accept_dup(nes->nes_home, ac);
+ else
+ ev->ev_accept = sip_accept_make(nes->nes_home, ac_str ? ac_str : "");
+
+ if (k)
+ ev->ev_supported = sip_supported_dup(nes->nes_home, k);
+ else if (k_str)
+ ev->ev_supported = sip_supported_make(nes->nes_home, k_str);
+
+ ev->ev_prev = pev;
+ *pev = ev;
+ }
+
+ ta_end(ta);
+
+ return ev;
+}
+
+
+/* ----------------------------------------------------------------- */
+/** Return magic context bound to nea_event.
+ *
+ * The function returns the magic context bound to the event.
+ *
+ * @param ev pointer to event object
+ *
+ * @return
+ * The function nea_emagic_get() returns the magic context
+ * bound to the event.
+ */
+nea_emagic_t *nea_emagic_get(nea_event_t *ev)
+{
+ assert(ev);
+
+ return ev->ev_magic;
+}
+
+
+/* ----------------------------------------------------------------- */
+/** Get named event */
+nea_event_t *nea_event_get(nea_server_t const *nes, char const *e)
+{
+ nea_event_t *ev = NULL;
+
+ for (ev = nes->nes_events; ev; ev = ev->ev_next)
+ if (e == NULL || strcmp(ev->ev_event->o_type, e) == 0)
+ break;
+
+ return ev;
+}
+
+/* ----------------------------------------------------------------- */
+nta_incoming_t *nea_sub_get_request(nea_sub_t *sub)
+{
+ assert(sub);
+
+ return sub->s_irq;
+}
+
+/** Invoke the event callback.
+ *
+ * The function nes_watcher_callback() calls the callback provided by the
+ * application using the notifier object.
+ *
+ * @param nes pointer to notifier object
+ * @param ev pointer to event view
+ * @param s pointer to subscription object
+ * @param sip pointer to subscribe request
+ *
+ * @return
+ * The function nes_watcher_callback() returns -1 if the notifier object
+ * has been destroyed by the callback function, 0 otherwise.
+ */
+static
+int nes_watcher_callback(nea_server_t *nes,
+ nea_event_t *ev,
+ nea_sub_t *s,
+ sip_t const *sip)
+{
+ if (!nes->nes_in_callback) {
+ nes->nes_in_callback = 1;
+ if (ev->ev_callback) {
+ nea_subnode_t sn[1];
+
+ nea_subnode_init(sn, s, sip_now());
+
+ ev->ev_callback(nes, ev->ev_magic, ev, sn, sip);
+ }
+ nes->nes_in_callback = 0;
+
+ if (nes->nes_in_list)
+ return 0;
+
+ if (nes->nes_pending_destroy) {
+ nea_server_destroy(nes);
+ return -2;
+ }
+
+ if (sip == NULL && nes->nes_pending_flush) {
+ int flushed = s->s_pending_flush;
+ nea_server_pending_flush(nes);
+ if (flushed)
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------- */
+
+#if 0
+/** Process incoming SUBSCRIBE message.
+ *
+ * The function nea_server_add() is called when the notifier receives a
+ * SUBSCRIBE request without existing event dialog.
+ *
+ * @param nes pointer to notifier
+ * @param local_target optional contact header
+ * @param msg pointer to request message
+ * @param sip pointer to SIP view to request message
+ *
+ * @return
+ * The function nea_server_add() returns 0 if successful, -1 upon an
+ * error.
+ *
+ */
+int nea_server_add(nea_server_t *nes,
+ sip_contact_t const *local_target,
+ msg_t *msg, sip_t *sip)
+{
+ su_home_t *home = nes->nes_home;
+ nea_sub_t *s = NULL;
+ url_t target[1];
+
+ s = nea_sub_create(nes);
+
+ s->s_from = sip_from_dup(home, sip->sip_from);
+
+ if (local_target == NULL)
+ local_target = nes->nes_eventity_uri;
+
+ s->s_local = sip_contact_dup(nes->nes_home, local_target);
+
+ *target = *local_target->m_url;
+
+ s->s_leg = nta_leg_tcreate(nes->nes_agent, nea_sub_process_incoming, s,
+ SIPTAG_CALL_ID(sip->sip_call_id),
+ SIPTAG_FROM(sip->sip_to), /* local address */
+ SIPTAG_TO(sip->sip_from), /* remote address */
+ URLTAG_URL(target),
+ TAG_END());
+
+ if (s->s_local && s->s_leg) {
+ nta_leg_tag(s->s_leg, NULL);
+ return 0;
+ }
+ else {
+ nea_sub_destroy(s);
+ return -1;
+ }
+}
+#endif
+
+static
+int nea_server_callback(nea_sub_t *nes_as_sub,
+ nta_leg_t *leg,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ return nea_server_add_irq((nea_server_t *)nes_as_sub, leg, NULL, irq, sip);
+}
+
+/** Process incoming request */
+int nea_server_add_irq(nea_server_t *nes,
+ nta_leg_t *leg,
+ sip_contact_t const *local_target,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ nea_sub_t *s = NULL;
+ s = nea_sub_create(nes);
+
+ s->s_from = sip_from_dup(nes->nes_home, sip->sip_from);
+
+ if (local_target == NULL)
+ local_target = nes->nes_eventity_uri;
+
+ s->s_local = sip_contact_dup(nes->nes_home, local_target);
+
+ if (leg == NULL || leg == nes->nes_leg) {
+ url_t target[1];
+
+ *target = *local_target->m_url;
+
+ s->s_leg = nta_leg_tcreate(nes->nes_agent, nea_sub_process_incoming, s,
+ SIPTAG_FROM(sip->sip_to),
+ SIPTAG_TO(sip->sip_from),
+ SIPTAG_CALL_ID(sip->sip_call_id),
+ URLTAG_URL((url_string_t *)target),
+ TAG_NULL());
+ }
+ else {
+ nta_leg_bind(s->s_leg = leg, nea_sub_process_incoming, s);
+ }
+
+ if (s->s_leg) {
+ if (sip->sip_to->a_tag == NULL) {
+ nta_leg_tag(s->s_leg, NULL);
+ nta_incoming_tag(irq, nta_leg_get_tag(s->s_leg));
+ }
+ nta_leg_server_route(s->s_leg, sip->sip_record_route, sip->sip_contact);
+
+ return nea_sub_process_incoming(s, s->s_leg, irq, sip);
+ }
+ else {
+ nea_sub_destroy(s);
+ return 500;
+ }
+}
+
+
+/* ----------------------------------------------------------------- */
+
+/**Process incoming transactions for event dialog.
+ *
+ * The nea_sub_process_incoming() processes the transactions for event
+ * dialog. Currently, no other methods allowed beside SUBSCRIBE. The
+ * SUBSCRIBE is processed by nea_sub_process_subscribe().
+ *
+ * @param s pointer to subscriber object
+ * @param leg pointer to NTA dialog object
+ * @param irq pointer to NTA server transaction
+ * @param sip pointer to structure containing SIP headers of the request
+ *
+ * The nea_sub_process_incoming() returns 0 if successful, SIP error code
+ * otherwise.
+ */
+int nea_sub_process_incoming(nea_sub_t *s,
+ nta_leg_t *leg,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ int retval;
+
+ s->s_processing = 1;
+ s->s_irq = irq;
+
+ switch(sip->sip_request->rq_method) {
+ case sip_method_subscribe:
+ retval = nea_sub_process_subscribe(s, leg, irq, sip);
+ break;
+
+ default:
+ nta_incoming_treply(irq,
+ retval = SIP_405_METHOD_NOT_ALLOWED,
+ SIPTAG_ALLOW_STR("SUBSCRIBE"),
+ TAG_END());
+ retval = 405;
+ }
+
+ s->s_processing = 0;
+
+ if (s->s_irq)
+ nta_incoming_destroy(irq), s->s_irq = NULL;
+
+ if (s->s_pending_flush || s->s_state == nea_embryonic)
+ nea_sub_destroy(s);
+
+ return retval;
+}
+
+
+/* ----------------------------------------------------------------- */
+
+/**Process incoming SUBSCRIBE transactions for event dialog.
+ *
+ * The function nea_sub_process_subscribe() processes the SUBSCRIBE
+ * transactions for (possible) event dialog.
+ *
+ * @param s pointer to subscriber object
+ * @param leg pointer to NTA dialog object
+ * @param irq pointer to NTA server transaction
+ * @param sip pointer to structure containing SIP headers of the request
+ *
+ * @return
+ * The function nea_sub_process_subscribe() returns 0 if successful, and a
+ * SIP error code otherwise.
+ */
+int nea_sub_process_subscribe(nea_sub_t *s,
+ nta_leg_t *leg,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ nea_server_t *nes = s->s_nes;
+ su_home_t *home = nes->nes_home;
+ nea_event_t *ev = NULL, *ev_maybe = NULL;
+ nea_event_view_t *evv = NULL, *evv_maybe = NULL;
+ sip_time_t delta = 0, now = sip_now();
+ sip_expires_t expires[1] = { SIP_EXPIRES_INIT() };
+ sip_unsupported_t *unsupported;
+ sip_event_t const *o;
+ sip_accept_t const *ac = NULL, *accept = NULL;
+ sip_accept_t *a0 = NULL, *a, *a_next, **aa;
+ sip_accept_t accept_default[1];
+ unsigned proposed_throttle;
+ char const *type, *throttle;
+ int once, what, supported_eventlist, require_eventlist;
+
+ if (sip->sip_payload && !sip->sip_content_type) {
+ nta_incoming_treply(irq, 400, "Missing Content-Type",
+ SIPTAG_SERVER_STR(nes->nes_server),
+ SIPTAG_ALLOW_EVENTS(nes->nes_allow_events),
+ SIPTAG_ALLOW(nes->nes_allow_methods),
+ TAG_NULL());
+ return 0;
+ }
+
+ if (sip->sip_expires &&
+ sip->sip_expires->ex_delta > 0 &&
+ sip->sip_expires->ex_delta < nes->nes_min_expires) {
+ sip_min_expires_t me[1];
+
+ sip_min_expires_init(me);
+
+ me->me_delta = nes->nes_min_expires;
+
+ nta_incoming_treply(irq, 423, "Subscription Interval Too Small",
+ SIPTAG_ACCEPT(accept),
+ SIPTAG_MIN_EXPIRES(me),
+ SIPTAG_SERVER_STR(nes->nes_server),
+ SIPTAG_ALLOW_EVENTS(nes->nes_allow_events),
+ SIPTAG_ALLOW(nes->nes_allow_methods),
+ TAG_NULL());
+ return 0;
+ }
+
+ /* Check features */
+ if (nes->nes_require) {
+ unsupported = sip_has_unsupported2(nes->nes_home,
+ sip->sip_supported,
+ sip->sip_require,
+ nes->nes_require);
+
+ if (unsupported) {
+ nta_incoming_treply(irq, SIP_421_EXTENSION_REQUIRED,
+ SIPTAG_REQUIRE(nes->nes_require),
+ SIPTAG_UNSUPPORTED(unsupported),
+ SIPTAG_SERVER_STR(nes->nes_server),
+ SIPTAG_ALLOW_EVENTS(nes->nes_allow_events),
+ SIPTAG_ALLOW(nes->nes_allow_methods),
+ TAG_NULL());
+ su_free(nes->nes_home, unsupported);
+
+ return 0;
+ }
+ }
+
+ supported_eventlist = sip_has_feature(sip->sip_supported, "eventlist");
+ require_eventlist = sip_has_feature(sip->sip_require, "eventlist");
+ supported_eventlist = supported_eventlist || require_eventlist;
+
+ if (s->s_id && (!sip->sip_event ||
+ str0cmp(s->s_id->o_type, sip->sip_event->o_type) != 0 ||
+ str0cmp(s->s_id->o_id, sip->sip_event->o_id))) {
+ /* Multiple subscriptions per dialog are not supported. */
+ return nta_incoming_treply(irq, 501,
+ "Multiple subscriptions not implemented",
+ SIPTAG_SERVER_STR(nes->nes_server),
+ TAG_NULL());
+ }
+
+ /* Check that subscriber asks for a supported event */
+ for (once = 0; ev == NULL ;once++) {
+ o = sip->sip_event;
+
+ /* Check that we have a matching event */
+ if (o && o->o_type) {
+ for (ev = nes->nes_events; ev; ev = ev->ev_next) {
+ if (strcmp(o->o_type, ev->ev_event->o_type) == 0) {
+ ev_maybe = ev;
+
+ if (ev->ev_eventlist) {
+ if (supported_eventlist)
+ break;
+ } else {
+ if (!supported_eventlist)
+ break;
+ }
+ }
+ }
+ }
+
+ if (!ev && !require_eventlist)
+ ev = ev_maybe;
+
+ if (ev || once)
+ break;
+
+ /* Ask the application either to
+ 1) add a new event or assing us an event/payload (0),
+ 2) take care of transaction (positive), or
+ 3) drop request (negative).
+ */
+ if ((what = nes_new_event_callback(nes, &ev, &evv, irq, sip)) < 0)
+ break;
+ if (what > 0) {
+ s->s_irq = NULL;
+ return 0;
+ }
+ }
+
+ if (ev_maybe == NULL && ev == NULL) {
+ nta_incoming_treply(irq, SIP_489_BAD_EVENT,
+ SIPTAG_SERVER_STR(nes->nes_server),
+ SIPTAG_ALLOW_EVENTS(nes->nes_allow_events),
+ SIPTAG_ALLOW(nes->nes_allow_methods),
+ NULL);
+ return 0;
+ } else if (ev == NULL) {
+ ev = ev_maybe;
+
+ unsupported = sip_has_unsupported(nes->nes_home, ev->ev_supported,
+ sip->sip_require);
+
+ nta_incoming_treply(irq, SIP_420_BAD_EXTENSION,
+ SIPTAG_UNSUPPORTED(unsupported),
+ SIPTAG_REQUIRE(ev->ev_require),
+ SIPTAG_SUPPORTED(ev->ev_supported),
+ SIPTAG_SERVER_STR(nes->nes_server),
+ SIPTAG_ALLOW_EVENTS(nes->nes_allow_events),
+ SIPTAG_ALLOW(nes->nes_allow_methods),
+ TAG_NULL());
+
+ su_free(nes->nes_home, unsupported);
+
+ return 0;
+ }
+
+ if (sip->sip_accept)
+ accept = sip->sip_accept;
+ else if (evv && evv->evv_content_type) {
+ /* Generate accept header from event view specified by application */
+ sip_accept_init(accept_default);
+ accept_default->ac_type = evv->evv_content_type->c_type;
+ accept_default->ac_subtype = evv->evv_content_type->c_subtype;
+
+ accept = a0;
+ }
+ else
+ accept = ev->ev_default;
+
+ for (once = 0; evv == NULL ;once++) {
+ /* If there are multiple accept values with different Q values,
+ insertion sort by Q value */
+ for (ac = accept->ac_next; ac; ac = ac->ac_next) {
+ if (ac->ac_q != accept->ac_q) {
+ if ((a0 = sip_accept_dup(home, accept))) {
+ /* Sort the accept list by Q values */
+ for (a = a0, accept = NULL; a; a = a_next) {
+ a_next = a->ac_next;
+
+ for (aa = (sip_accept_t **)&accept;
+ *aa && sip_q_value((*aa)->ac_q) >= sip_q_value(a->ac_q);
+ aa = &(*aa)->ac_next)
+ ;
+
+ a->ac_next = *aa; *aa = a; /* Insert */
+ }
+ }
+
+ break;
+ }
+ }
+
+ /* Check that subscriber asks for a supported content type */
+ for (ac = accept; ac; ac = ac->ac_next) {
+ int i;
+
+ if (ac->ac_type == NULL || ac->ac_subtype == NULL)
+ continue;
+
+ /* Check all supported content types v. accept */
+ for (i = 0; (evv = ev->ev_views[i]); i++) {
+ assert(evv->evv_content_type && evv->evv_content_type->c_type);
+
+ if (strcmp(ac->ac_type, "*/*") == 0)
+ break;
+
+ type = evv->evv_content_type->c_type;
+
+ if ((strcasecmp(ac->ac_type, type) == 0) ||
+ (strcasecmp(ac->ac_subtype, "*") == 0 &&
+ strncasecmp(ac->ac_type, type,
+ ac->ac_subtype - ac->ac_type) == 0)) {
+ if (evv_maybe == NULL)
+ evv_maybe = evv;
+ }
+ }
+
+ if (evv) /* Found */
+ break;
+ }
+
+ /* Free the sorted Accept list */
+ for (a = a0; a; a = a_next)
+ a_next = a->ac_next, su_free(home, a);
+
+ if (!evv)
+ evv = evv_maybe;
+
+ if (evv || once)
+ break;
+
+ /* Ask the application either to
+ 1) add a new event view or assign us an event view (0),
+ 2) take care of transaction (positive), or
+ 3) drop request (negative).
+ */
+ if ((what = nes_new_event_callback(nes, &ev, &evv, irq, sip)) < 0)
+ break;
+ if (what > 0) {
+ s->s_irq = NULL;
+ return 0;
+ }
+ }
+
+ if (evv == NULL) {
+ SU_DEBUG_3(("nea_server: event %s rejected %u %s\n",
+ ev->ev_event->o_type, SIP_406_NOT_ACCEPTABLE));
+
+ /* There is no media acceptable to watcher */
+ return nta_incoming_treply(irq, SIP_406_NOT_ACCEPTABLE,
+ SIPTAG_ACCEPT(ev->ev_accept),
+ SIPTAG_SERVER_STR(nes->nes_server),
+ SIPTAG_ALLOW_EVENTS(nes->nes_allow_events),
+ SIPTAG_ALLOW(nes->nes_allow_methods),
+ TAG_NULL());
+ }
+
+ /* Do not change private view */
+ if (s->s_view && s->s_view->evv_primary == evv)
+ evv = s->s_view;
+
+ /* Set throttle */
+ if (sip->sip_event &&
+ (throttle = sip_params_find(sip->sip_event->o_params, "throttle="))) {
+ proposed_throttle = strtoul(throttle, NULL, 10);
+
+ if (proposed_throttle < evv->evv_min_throttle)
+ proposed_throttle = evv->evv_min_throttle;
+ } else
+ proposed_throttle = evv->evv_throttle;
+
+ s->s_throttle = proposed_throttle;
+
+ /* Update route, store remote contact */
+ nta_leg_server_route(leg, sip->sip_record_route, sip->sip_contact);
+ su_free(home, s->s_remote);
+ s->s_remote = sip_contact_dup(home, sip->sip_contact);
+
+ /* Store content-type and body */
+ if (sip->sip_content_type) {
+ su_free(home, s->s_content_type);
+ s->s_content_type = sip_content_type_dup(home, sip->sip_content_type);
+ su_free(home, s->s_payload);
+ s->s_payload = sip_payload_dup(home, sip->sip_payload);
+ }
+
+ /* Calculate expiration time for subscription */
+ delta = sip_contact_expires(NULL, sip->sip_expires, sip->sip_date,
+ nes->nes_expires, now);
+ if (delta > nes->nes_max_expires)
+ delta = nes->nes_max_expires;
+ expires->ex_delta = delta;
+
+ if (s->s_subscribed == 0)
+ s->s_subscribed = now;
+ s->s_expires = now + delta;
+ /* s->s_accept = sip_accept_dup(home, accept); */
+ if (s->s_id == NULL)
+ s->s_id = sip_event_dup(home, sip->sip_event);
+ s->s_event = ev;
+ s->s_eventlist = supported_eventlist;
+ nea_sub_assign_view(s, evv);
+ s->s_updated = evv->evv_updated - 1; /* Force notify */
+
+ if (nes->nes_202_before_notify) {
+ nta_incoming_treply(irq, SIP_202_ACCEPTED,
+ SIPTAG_SERVER_STR(nes->nes_server),
+ SIPTAG_ALLOW_EVENTS(nes->nes_allow_events),
+ SIPTAG_ALLOW(nes->nes_allow_methods),
+ SIPTAG_REQUIRE(ev->ev_require),
+ SIPTAG_SUPPORTED(ev->ev_supported),
+ SIPTAG_EXPIRES(expires),
+ SIPTAG_CONTACT(s->s_local),
+ TAG_END());
+ nta_incoming_destroy(irq), s->s_irq = irq = NULL;
+ }
+
+ /* Callback for checking subscriber authorization */
+ if (nes_watcher_callback(nes, ev, s, sip) < 0) {
+ if (irq) {
+ nta_incoming_treply(irq, SIP_503_SERVICE_UNAVAILABLE, TAG_END());
+ nta_incoming_destroy(irq);
+ }
+ return -1;
+ }
+
+ evv = s->s_view; /* Callback can change event view */
+
+ if (s->s_state == nea_embryonic)
+ nea_sub_auth(s, nea_pending, NEATAG_FAKE(1), TAG_END());
+
+ if (s->s_updated != evv->evv_updated && !(irq && s->s_rejected))
+ nea_sub_notify(nes, s, now, TAG_END());
+
+ if (irq) {
+ if (s->s_rejected)
+ nta_incoming_treply(irq, SIP_403_FORBIDDEN,
+ SIPTAG_SERVER_STR(nes->nes_server),
+ TAG_END());
+ else if (s->s_state == nea_active)
+ nta_incoming_treply(irq, SIP_200_OK,
+ SIPTAG_REQUIRE(ev->ev_require),
+ SIPTAG_SUPPORTED(ev->ev_supported),
+ SIPTAG_EXPIRES(expires),
+ SIPTAG_SERVER_STR(nes->nes_server),
+ SIPTAG_CONTACT(s->s_local),
+ SIPTAG_ALLOW_EVENTS(nes->nes_allow_events),
+ SIPTAG_ALLOW(nes->nes_allow_methods),
+ TAG_END());
+ else
+ nta_incoming_treply(irq, SIP_202_ACCEPTED,
+ SIPTAG_REQUIRE(ev->ev_require),
+ SIPTAG_SUPPORTED(ev->ev_supported),
+ SIPTAG_EXPIRES(expires),
+ SIPTAG_SERVER_STR(nes->nes_server),
+ SIPTAG_ALLOW_EVENTS(nes->nes_allow_events),
+ SIPTAG_ALLOW(nes->nes_allow_methods),
+ SIPTAG_CONTACT(s->s_local),
+ TAG_END());
+ }
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------- */
+/**Notify subscriber
+ *
+ * The function nea_sub_notify() sends a notification to the subscriber. The
+ * event type is specified by subscriber event, payload type and payload in
+ * the event view. The responses to the NOTIFY transaction are
+ * processed by response_to_notify().
+ *
+ * @param nes pointer to the notifier object
+ * @param s pointer to the subscription object
+ * @param now current SIP time (if 0, no body is sent,
+ * but updated Subscription-State header only
+ * @param tag,value,... tag list
+ *
+ */
+int nea_sub_notify(nea_server_t *nes, nea_sub_t *s,
+ sip_time_t now,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ int notified = 0;
+ ta_list ta;
+ int subscription_state_change = now == 0;
+ nea_event_t *ev = s->s_event;
+ nea_state_t substate = s->s_state;
+
+ if (s->s_pending_flush || (s->s_oreq && substate != nea_terminated)) {
+ if (ev && ev->ev_throttling > s->s_updated)
+ ev->ev_throttling = s->s_updated;
+ return 0;
+ }
+
+ if (s->s_oreq)
+ nta_outgoing_destroy(s->s_oreq), s->s_oreq = NULL;
+
+ assert(s->s_view); assert(ev);
+
+ if (!subscription_state_change && s->s_view->evv_updated == s->s_updated)
+ return 0;
+
+ if (now == 0)
+ now = sip_now();
+
+ if (s->s_notified + s->s_throttle > now &&
+ /* Do not throttle state termination notification */
+ substate != nea_terminated &&
+ (long)(s->s_expires - now) > 0) {
+ if (ev->ev_throttling > s->s_updated && !s->s_fake)
+ ev->ev_throttling = s->s_updated;
+ nes->nes_throttled++;
+ return 0;
+ }
+
+ ta_start(ta, tag, value);
+ {
+ sip_subscription_state_t ss[1];
+ char expires[32];
+ sip_param_t params[] = { NULL, NULL, NULL };
+ char const *reason = NULL;
+ int fake = 0;
+ char reason_buf[64];
+ unsigned retry_after = (unsigned)-1;
+ char retry_after_buf[64];
+ int i = 0;
+ nta_response_f *callback;
+ nea_event_view_t *evv = s->s_view;
+ nea_event_queue_t *evq, *n_evq;
+
+ assert(ev);
+
+ sip_subscription_state_init(ss);
+
+ tl_gets(ta_args(ta),
+ NEATAG_REASON_REF(reason),
+ NEATAG_FAKE_REF(fake), /* XXX - semantics??? */
+ NEATAG_RETRY_AFTER_REF(retry_after),
+ TAG_END());
+
+ if (substate == nea_terminated) {
+ if (reason)
+ snprintf(reason_buf, sizeof(reason_buf),
+ "reason=%s", reason), params[i++] = reason_buf;
+ if (retry_after != (unsigned)-1)
+ snprintf(retry_after_buf, sizeof(retry_after_buf),
+ "retry-after=%u", retry_after), params[i++] = retry_after_buf;
+ }
+ else if ((long)(s->s_expires - now) <= 0) {
+ substate = nea_terminated;
+ params[i++] = "reason=timeout";
+ }
+ else {
+ snprintf(expires, sizeof(expires),
+ "expires=%lu", (unsigned long)(s->s_expires - now));
+ params[i++] = expires;
+ }
+
+ ss->ss_params = params;
+
+ switch (substate) {
+ case nea_extended: ss->ss_substate = s->s_extended; break;
+ case nea_pending: ss->ss_substate = "pending"; break;
+ case nea_active: ss->ss_substate = "active"; break;
+ case nea_terminated: ss->ss_substate = "terminated"; break;
+ /* Do not send notifys for embryonic subscriptions */
+ case nea_embryonic:
+ ta_end(ta);
+ return 0;
+ }
+
+ callback = substate != nea_terminated ? response_to_notify : NULL;
+
+ for (evq = evv->evv_head; evq->evq_next; evq = evq->evq_next) {
+ if (evq->evq_next->evq_updated <= s->s_updated)
+ break;
+ }
+
+ subscription_state_change = (s->s_view->evv_updated == s->s_updated);
+
+ n_evq = evq->evq_payload ? evq : evv->evv_primary->evv_head;
+
+ s->s_oreq =
+ nta_outgoing_tcreate(s->s_leg,
+ callback, s, NULL,
+ SIP_METHOD_NOTIFY, NULL,
+ SIPTAG_SUBSCRIPTION_STATE(ss),
+ SIPTAG_REQUIRE(ev->ev_require),
+ SIPTAG_SUPPORTED(ev->ev_supported),
+ SIPTAG_USER_AGENT_STR(nes->nes_server),
+ SIPTAG_CONTACT(s->s_local),
+ SIPTAG_EVENT(s->s_id),
+ TAG_IF(!subscription_state_change,
+ SIPTAG_CONTENT_TYPE(n_evq->evq_content_type)),
+ TAG_IF(!subscription_state_change,
+ SIPTAG_PAYLOAD(n_evq->evq_payload)),
+ ta_tags(ta));
+
+
+ notified = s->s_oreq != 0;
+
+ if (notified) {
+ s->s_notified = now;
+ s->s_state = substate; /* XXX - we need state for "waiting" */
+ s->s_latest = evq->evq_version; /* Application version */
+ s->s_updated = evq->evq_updated; /* Internal version */
+ if (ev->ev_throttling > s->s_updated)
+ ev->ev_throttling = s->s_updated;
+ }
+
+ if (callback == NULL) {
+ nta_outgoing_destroy(s->s_oreq), s->s_oreq = NULL;
+ /* Inform the application of a subscriber leaving the subscription. */
+ nes_watcher_callback(nes, ev, s, NULL);
+ }
+ }
+ ta_end(ta);
+
+ return notified;
+}
+
+/* ----------------------------------------------------------------- */
+/**Process responses to the NOTIFY.
+ *
+ * The response_to_notify() processes the responses to the NOTIFY request.
+ * If there was an error with delivering the NOTIFY, the subscription is
+ * considered terminated.
+ *
+ * @param s pointer to subscription object
+ */
+int response_to_notify(nea_sub_t *s,
+ nta_outgoing_t *oreq,
+ sip_t const *sip)
+{
+ nea_server_t *nes = s->s_nes;
+ int status = sip->sip_status->st_status;
+
+ if (status < 200)
+ return 0;
+
+ nta_outgoing_destroy(s->s_oreq), s->s_oreq = NULL;
+
+ if (status < 300) {
+ if (s->s_view->evv_updated != s->s_updated) {
+ sip_time_t now = sip_now();
+
+ if (s->s_notified + s->s_throttle <= now)
+ nea_sub_notify(nes, s, now, TAG_END());
+ else
+ nes->nes_throttled++;
+ }
+ }
+
+ if (s->s_state == nea_terminated || status >= 300) {
+ SU_DEBUG_5(("nea_server: removing subscriber " URL_PRINT_FORMAT "\n",
+ URL_PRINT_ARGS(s->s_from->a_url)));
+ /* Inform the application of a subscriber leaving the subscription. */
+ nes_watcher_callback(nes, s->s_event, s, NULL);
+ }
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------- */
+
+/** Get number of active subscribers.
+ *
+ * The function nea_server_active() counts the number of active subscribers
+ * watching the specified view. If the view is not specified (@a ev is @c
+ * NULL), it counts the number of all subscribers.
+ *
+ * @param nes notifier
+ * @param ev event
+ *
+ * The function nea_server_active() returns number of active subscribers.
+ */
+int nea_server_active(nea_server_t *nes, nea_event_t const *ev)
+{
+ int n = 0;
+ nea_sub_t *s = NULL;
+
+ /* Count the number of subscribers watching this event */
+ for (s = nes->nes_subscribers; s ; s = s->s_next)
+ if (!s->s_pending_flush && s->s_state == nea_active
+ && (ev == NULL || ev == s->s_event))
+ n++;
+
+ return n;
+}
+
+/** Get number of non-embryonic subscribers.
+ *
+ * The function nea_server_non_embryonic() counts the number of pending,
+ * active or terminated subscribers watching the specified view. If the view
+ * is not specified (@a ev is @c NULL), it counts the number of all
+ * subscribers.
+ *
+ * @param nes notifier
+ * @param ev event view
+ *
+ * The function nea_server_active() returns number of active subscribers.
+ */
+int nea_server_non_embryonic(nea_server_t *nes, nea_event_t const *ev)
+{
+ int n = 0;
+ nea_sub_t *s = NULL;
+
+ /* Count the number of subscribers watching this event */
+ for (s = nes->nes_subscribers; s ; s = s->s_next)
+ if (!s->s_pending_flush && s->s_state != nea_embryonic
+ && (ev == NULL || ev == s->s_event))
+ n++;
+
+ return n;
+}
+
+/** Set application version number */
+int nea_sub_version(nea_sub_t *s, unsigned version)
+{
+ if (s)
+ return s->s_version = version;
+ return 0;
+}
+
+/** Authorize a subscription.
+ *
+ * Application can modify the subscription state and authorize the user.
+ * The subscription state has following simple state diagram:
+ *
+ * @code
+ * +---------------+ +------------------+
+ * | | | |
+ * +-----------+ | +---------+ V | +------------+ V +------------+
+ * | embryonic |-+->| pending |--+-+->| authorized |--+->| terminated |
+ * +-----------+ +---------+ +------------+ +------------+
+ *
+ * @endcode
+ *
+ * @TAGS
+ * IF NEATAG_VIEW(view) is included in tagged arguments, @a view is assigned
+ * to the subscriber and the content from the view is delivered to the
+ * subscriber.
+ *
+ * If NEATAG_FAKE(1) is included in tags, content marked as 'fake' is
+ * delivered to the subscriber.
+ *
+ * @retval 0 if successful
+ * @retval -1 upon an error
+ */
+int nea_sub_auth(nea_sub_t *s,
+ nea_state_t state,
+ tag_type_t tag, tag_value_t value, ...)
+{
+
+ ta_list ta;
+ int retval, embryonic, rejected = 0;
+ int fake = 0;
+ char const *reason = NULL;
+ nea_event_view_t *evv = NULL;
+
+ if (s == NULL)
+ return -1;
+ if (state == nea_embryonic)
+ return -1;
+ if (state < s->s_state)
+ return -1;
+
+ ta_start(ta, tag, value);
+
+ embryonic = s->s_state == nea_embryonic;
+
+ s->s_state = state;
+
+ if (tl_gets(ta_args(ta), NEATAG_VIEW_REF(evv), TAG_END()) && evv) {
+ nea_sub_assign_view(s, evv);
+ }
+ else {
+ if (tl_gets(ta_args(ta), NEATAG_FAKE_REF(fake), TAG_END()))
+ s->s_fake = fake;
+
+ if (s->s_view && s->s_view->evv_fake != s->s_fake) {
+ for (evv = s->s_view->evv_primary; evv; evv = evv->evv_next)
+ if (!evv->evv_private && evv->evv_fake == s->s_fake) {
+ nea_sub_assign_view(s, evv);
+ break;
+ }
+ }
+ }
+
+ tl_gets(ta_args(ta), NEATAG_REASON_REF(reason), TAG_END());
+
+ rejected = reason && strcasecmp(reason, "rejected") == 0;
+
+ if (state == nea_terminated && embryonic && rejected && s->s_irq)
+ retval = 0, s->s_rejected = 1;
+ else
+ retval = nea_sub_notify(s->s_nes, s, 0, ta_tags(ta));
+
+ ta_end(ta);
+
+ return retval;
+}
+
+/** Obtain a list of subscribers */
+nea_subnode_t const **nea_server_get_subscribers(nea_server_t *nes,
+ nea_event_t const *ev)
+{
+ nea_sub_t *s;
+ nea_subnode_t **sn_list, *sn;
+ int i, n;
+ sip_time_t now = sip_now();
+
+ n = nea_server_non_embryonic(nes, ev);
+ if (n == 0)
+ return NULL;
+
+ sn_list = su_zalloc(nes->nes_home,
+ (n + 1) * sizeof(sn) + n * sizeof(*sn));
+ if (sn_list) {
+ sn = (nea_subnode_t *)(sn_list + n + 1);
+
+ for (i = 0, s = nes->nes_subscribers; s; s = s->s_next) {
+ if (!s->s_pending_flush && s->s_state != nea_embryonic
+ && (ev == NULL || ev == s->s_event)) {
+ assert(i < n);
+ nea_subnode_init(sn, s, now);
+ sn_list[i++] = sn++;
+ }
+ }
+
+ nes->nes_in_list++;
+
+ sn_list[i] = NULL;
+ }
+
+ return (nea_subnode_t const **)sn_list;
+}
+
+/** Free a list of subscriptions. */
+void nea_server_free_subscribers(nea_server_t *nes,
+ nea_subnode_t const **sn_list)
+{
+ if (sn_list) {
+ su_free(nes->nes_home, (void *)sn_list);
+ if (--nes->nes_in_list == 0 && nes->nes_pending_flush)
+ nea_server_pending_flush(nes);
+ }
+}
+
+/* ----------------------------------------------------------------- */
+void nes_event_timer(nea_server_t *srvr,
+ su_timer_t *timer,
+ su_timer_arg_t *arg)
+{
+ nea_server_t *nes = (nea_server_t *) arg;
+ sip_time_t now = sip_now();
+ nea_sub_t *s = NULL, *s_next = NULL;
+ su_root_t *root = su_timer_root(timer);
+
+ su_timer_set(timer, nes_event_timer, nes);
+
+ nes->nes_in_list++;
+
+ /* Notify and terminate expired subscriptions */
+ for (s = nes->nes_subscribers; s; s = s_next) {
+ s_next = s->s_next;
+ if (s->s_state == nea_terminated)
+ continue;
+ if ((int)(now - s->s_expires) >= 0) {
+ nea_sub_notify(nes, s, now, TAG_END());
+ /* Yield so we can handle received packets */
+ su_root_yield(root);
+ }
+ }
+
+ if (--nes->nes_in_list == 0 && nes->nes_pending_flush)
+ nea_server_pending_flush(nes);
+
+ if (nes->nes_throttled)
+ nea_server_notify(nes, NULL);
+
+ return;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/nea_tag.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/nea_tag.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,64 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nea_tag.c
+ * @brief Tags for Nokia SIP Transaction API
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti Mela at nokia.com>
+ *
+ * @date Created: Tue Jul 24 22:28:34 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <assert.h>
+
+#define TAG_NAMESPACE "nea"
+
+#include "sofia-sip/nea.h"
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/sip_tag_class.h>
+#include <sofia-sip/url_tag_class.h>
+
+tag_typedef_t neatag_any = NSTAG_TYPEDEF(*);
+tag_typedef_t neatag_min_expires = UINTTAG_TYPEDEF(min_expires);
+tag_typedef_t neatag_expires = UINTTAG_TYPEDEF(expires);
+tag_typedef_t neatag_max_expires = UINTTAG_TYPEDEF(max_expires);
+tag_typedef_t neatag_throttle = UINTTAG_TYPEDEF(throttle);
+tag_typedef_t neatag_minthrottle = UINTTAG_TYPEDEF(minthrottle);
+tag_typedef_t neatag_dialog = PTRTAG_TYPEDEF(dialog);
+tag_typedef_t neatag_eventlist = BOOLTAG_TYPEDEF(eventlist);
+tag_typedef_t neatag_fake = BOOLTAG_TYPEDEF(fake);
+tag_typedef_t neatag_reason = STRTAG_TYPEDEF(reason);
+tag_typedef_t neatag_retry_after = UINTTAG_TYPEDEF(retry_after);
+tag_typedef_t neatag_exstate = STRTAG_TYPEDEF(exstate);
+tag_typedef_t neatag_version = INTTAG_TYPEDEF(version);
+tag_typedef_t neatag_view = PTRTAG_TYPEDEF(view);
+tag_typedef_t neatag_evmagic = PTRTAG_TYPEDEF(evmagic);
+tag_typedef_t neatag_reliable = BOOLTAG_TYPEDEF(reliable);
+tag_typedef_t neatag_sub = PTRTAG_TYPEDEF(sub);
+
+tag_typedef_t neatag_strict_3265 = BOOLTAG_TYPEDEF(strict_3265);
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/sofia-sip/nea.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/sofia-sip/nea.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,378 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef NEA_H
+/** Defined when <sofia-sip/nea.h> has been included. */
+#define NEA_H
+/**@file sofia-sip/nea.h
+ * @brief Event API for SIP
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ *
+ * @date Created: Fri Feb 7 13:23:44 EET 2003 ppessi
+ */
+
+#ifndef SU_ALLOC_H
+#include <sofia-sip/su_alloc.h>
+#endif
+
+#include <sofia-sip/su_tag.h>
+
+#ifndef NTA_H
+#include <sofia-sip/nta.h>
+#endif
+
+#ifndef NEA_TAG_H
+#include <sofia-sip/nea_tag.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+#define NEA_VERSION 3.0
+#define NEA_VERSION_STR "3.0"
+
+#define NEA_DEFAULT_EXPIRES 3600
+
+/** Event notifier object. */
+typedef struct nea_server_s nea_server_t;
+
+/** Subscription object. */
+typedef struct nea_sub_s nea_sub_t;
+
+/** Event. */
+typedef struct nea_event_s nea_event_t;
+
+/** Event view. */
+typedef struct nea_event_view_s nea_event_view_t;
+
+#ifndef NEA_SMAGIC_T
+#define NEA_SMAGIC_T struct nea_smagic_t
+#endif
+/** NEA server context */
+typedef NEA_SMAGIC_T nea_smagic_t;
+
+#ifndef NEA_EMAGIC_T
+#define NEA_EMAGIC_T struct nea_emagic_t
+#endif
+/** NEA server event context */
+typedef NEA_EMAGIC_T nea_emagic_t;
+
+#ifndef NEA_EVMAGIC_T
+#define NEA_EVMAGIC_T struct nea_evmagic_t
+#endif
+/** Event view context */
+typedef NEA_EVMAGIC_T nea_evmagic_t;
+
+/** Description of subscription */
+typedef struct nea_subnode_t {
+ nea_state_t sn_state; /**< Subscription state */
+ unsigned sn_fake; /**< True if subscriber is given
+ * fake contents.
+ */
+ unsigned sn_eventlist; /**< Subscriber supports eventlist */
+ nea_sub_t *sn_subscriber; /**< Pointer to subscriber object */
+ nea_event_t *sn_event; /**< Event */
+ sip_from_t const *sn_remote; /**< Identity of subscriber */
+ sip_contact_t const *sn_contact; /**< Contact of subscriber */
+
+ /** Content-Type of SUBSCRIBE body (filter). */
+ sip_content_type_t const *sn_content_type;
+ sip_payload_t const *sn_payload; /**< Body of subscribe*/
+
+ unsigned sn_expires; /**< When subscription expires */
+ unsigned sn_latest; /**< Latest notification version */
+ unsigned sn_throttle; /**< Throttle value */
+ unsigned sn_version; /**< Latest notified version # by application */
+ sip_time_t sn_notified; /**< When latest notify was sent */
+ sip_time_t sn_subscribed; /**< When first SUBSCRIBE was recv */
+ nea_event_view_t *sn_view; /**< Event view for this subscriber */
+} nea_subnode_t;
+
+/** Multiple content types per event. */
+typedef struct nea_payloads_s nea_payloads_t;
+
+/**Unknown event callback.
+ *
+ * The event server invokes this callback function when it has received a
+ * request for an unknown event or event with unknown content type.
+ *
+ * The callback may be called twice for one watcher, once for an unknown
+ * event, another time for an unknown content type.
+ *
+ * @retval 1 application takes care of responding to request
+ * @retval 0 application has added new event or payload format
+ * @retval -1 nea server rejects request
+ */
+typedef int (nea_new_event_f)(nea_smagic_t *context,
+ nea_server_t *nes,
+ nea_event_t **event_p,
+ nea_event_view_t **view_p,
+ nta_incoming_t *irq,
+ sip_t const *sip);
+
+/** Create a notifier server */
+SOFIAPUBFUN
+nea_server_t *nea_server_create(nta_agent_t *agent,
+ su_root_t *root,
+ url_t const *url,
+ int max_subs,
+ nea_new_event_f *callback,
+ nea_smagic_t *context,
+ tag_type_t tag, tag_value_t value,
+ ...);
+
+
+/** Shutdown an event server */
+SOFIAPUBFUN int nea_server_shutdown(nea_server_t *nes, int retry_after);
+
+/** Destroy a server */
+SOFIAPUBFUN void nea_server_destroy(nea_server_t *nes);
+
+/** Zap terminated subscribtions. */
+SOFIAPUBFUN void nea_server_flush(nea_server_t *nes, nea_event_t *event);
+
+/** Update event information */
+SOFIAPUBFUN
+int nea_server_update(nea_server_t *nes,
+ nea_event_t *ev,
+ tag_type_t tag,
+ tag_value_t value,
+ ...);
+
+/** Add a new subscriber from subscribe transaction to an existing notifier. */
+SOFIAPUBFUN
+int nea_server_add_irq(nea_server_t *nes,
+ nta_leg_t *leg,
+ sip_contact_t const *local_target,
+ nta_incoming_t *irq,
+ sip_t const *sip);
+
+/** QAUTH callback function type.
+ *
+ * The event server invokes this callback function upon each incoming
+ * SUBSCRIBE transaction when the subscription has expired. The @a sip is
+ * NULL if the subscription has expired.
+ *
+ * The application determines if the subscription is authorized and relays
+ * the decision to event server via nea_server_auth() function.
+ */
+typedef void (nea_watcher_f)(nea_server_t *nes,
+ nea_emagic_t *context,
+ nea_event_t *event,
+ nea_subnode_t *subnode,
+ sip_t const *sip);
+
+/** Create a new event (or subevent) */
+SOFIAPUBFUN
+nea_event_t *nea_event_create(nea_server_t *nes,
+ nea_watcher_f *callback,
+ nea_emagic_t *context,
+ char const *name,
+ char const *subname,
+ char const *default_content_type,
+ char const *accept);
+
+/** Create a new event (or subevent) with tags */
+SOFIAPUBFUN
+nea_event_t *nea_event_tcreate(nea_server_t *nes,
+ nea_watcher_f *callback,
+ nea_emagic_t *context,
+ char const *name,
+ char const *subname,
+ tag_type_t, tag_value_t, ...);
+
+/** Return magic context bind to nea_event */
+SOFIAPUBFUN nea_emagic_t *nea_emagic_get(nea_event_t *event);
+
+/** Find a nea event object with given event name */
+SOFIAPUBFUN nea_event_t *nea_event_get(nea_server_t const *, char const *name);
+
+/** Get number of active subscribers */
+SOFIAPUBFUN int nea_server_active(nea_server_t *nes, nea_event_t const *ev);
+
+/** Get number of (non-embryonic) subscribers. */
+int nea_server_non_embryonic(nea_server_t *nes, nea_event_t const *ev);
+
+/** Obtain a list of subscriptions.
+ */
+SOFIAPUBFUN
+nea_subnode_t const **nea_server_get_subscribers(nea_server_t *nes,
+ nea_event_t const *ev);
+
+/** Free a list of subscriptions. */
+SOFIAPUBFUN
+void nea_server_free_subscribers(nea_server_t *nes, nea_subnode_t const **);
+
+/** Notify subscribers */
+SOFIAPUBFUN
+int nea_server_notify(nea_server_t *nes,
+ nea_event_t *ev);
+
+/** Notify a subscriber */
+SOFIAPUBFUN
+int nea_server_notify_one(nea_server_t *nes,
+ nea_event_t *ev,
+ nea_sub_t *ns);
+
+#define nea_server_auth nea_sub_auth
+
+/** Get nta_incoming_t from nea_sub_t */
+SOFIAPUBFUN nta_incoming_t *nea_sub_get_request(nea_sub_t *sub);
+
+/** Authorize a subscription */
+SOFIAPUBFUN
+int nea_sub_auth(nea_sub_t *, nea_state_t state,
+ tag_type_t, tag_value_t, ...);
+
+/** Get nta_incoming_t from sn->sn_subscriber */
+SOFIAPUBFUN nta_incoming_t *nea_subnode_get_incoming(nea_subnode_t *sn);
+/** Set subscriber version sequence */
+SOFIAPUBFUN int nea_sub_version(nea_sub_t *, unsigned);
+
+/** Return time until next notification can be sent */
+SOFIAPUBFUN unsigned nea_sub_pending(nea_sub_t const *);
+
+#if 0
+/** Do a remote qauth.
+ *
+ * The function nea_server_qauth() is given as q_callback pointer
+ * to nea_server_create() if remote authentication from url is desired.
+ */
+void nea_server_qauth(nea_server_t *nes,
+ nea_emagic_t *context,
+ nea_sub_t *subscriber,
+ sip_t const *sip);
+#endif
+
+/** Get primary event view for given content type */
+SOFIAPUBFUN
+nea_event_view_t *nea_event_view(nea_event_t *, char const *content_type);
+
+/** Get a content type for event's payload */
+SOFIAPUBFUN
+sip_content_type_t const *nea_view_content_type(nea_event_view_t const *);
+
+/** Get actual payload for an event */
+SOFIAPUBFUN sip_payload_t const *nea_view_payload(nea_event_view_t *);
+
+/** Create a private event view */
+SOFIAPUBFUN nea_event_view_t *nea_view_create(nea_server_t *nes,
+ nea_event_t *ev,
+ nea_evmagic_t *magic,
+ tag_type_t tag,
+ tag_value_t value,
+ ...);
+
+/** Destroy a private event view */
+SOFIAPUBFUN void nea_view_destroy(nea_server_t *nes, nea_event_view_t *ev);
+
+SOFIAPUBFUN nea_evmagic_t *nea_view_magic(nea_event_view_t const *);
+
+SOFIAPUBFUN void nea_view_set_magic(nea_event_view_t *, nea_evmagic_t *magic);
+
+SOFIAPUBFUN unsigned nea_view_version(nea_event_view_t const *);
+
+/** Reliable notify */
+#define NEATAG_RELIABLE(x) neatag_reliable, tag_bool_v((x))
+SOFIAPUBVAR tag_typedef_t neatag_reliable;
+
+#define NEATAG_RELIABLE_REF(x) neatag_reliable_ref, tag_bool_vr((&x))
+SOFIAPUBVAR tag_typedef_t neatag_reliable_ref;
+
+/** Event view handle */
+#define NEATAG_VIEW(x) neatag_view, tag_ptr_v((x))
+SOFIAPUBVAR tag_typedef_t neatag_view;
+
+#define NEATAG_VIEW_REF(x) neatag_view_ref, tag_ptr_vr((&x), (x))
+SOFIAPUBVAR tag_typedef_t neatag_view_ref;
+
+/** Event view magic. */
+#define NEATAG_EVMAGIC(x) neatag_evmagic, tag_ptr_v((x))
+SOFIAPUBVAR tag_typedef_t neatag_evmagic;
+
+#define NEATAG_EVMAGIC_REF(x) neatag_evmagic_ref, tag_ptr_vr((&x), (x))
+SOFIAPUBVAR tag_typedef_t neatag_evmagic_ref;
+
+/** tag for nea_sub_t */
+#define NEATAG_SUB(x) neatag_sub, tag_ptr_v((x))
+SOFIAPUBVAR tag_typedef_t neatag_sub;
+
+#define NEATAG_SUB_REF(x) neatag_sub_ref, tag_ptr_vr((&x), (x))
+SOFIAPUBVAR tag_typedef_t neatag_sub_ref;
+
+
+/* ====================================================================== */
+/* Watcher side */
+
+/** NEA Event Watcher */
+typedef struct nea_s nea_t;
+
+#ifndef NEA_MAGIC_T
+#define NEA_MAGIC_T struct nea_magic_t
+#endif
+
+/** NEA Event Agent context */
+typedef NEA_MAGIC_T nea_magic_t;
+
+/** Event notification callback type.
+ *
+ * This callback is called also when initial or refresh subscribe transaction
+ * completes with the transaction result in @a sip.
+ */
+typedef int (*nea_notify_f)(nea_t *nea,
+ nea_magic_t *context,
+ sip_t const *sip);
+
+/* ====================================================================== */
+/* Client side */
+
+/** Create a subscription agent. */
+SOFIAPUBFUN
+nea_t *nea_create(nta_agent_t *agent,
+ su_root_t *root,
+ nea_notify_f no_callback,
+ nea_magic_t *context,
+ tag_type_t tag,
+ tag_value_t value,
+ ...);
+
+/** Update SUBSCRIBE payload (filter rules) */
+SOFIAPUBFUN
+int nea_update(nea_t *nea,
+ tag_type_t tag,
+ tag_value_t value,
+ ...);
+
+/** Unsubscribe agent. */
+SOFIAPUBFUN void nea_end(nea_t *agent);
+
+/** Destroy a subscription agent. */
+SOFIAPUBFUN void nea_destroy(nea_t *agent);
+
+SOFIAPUBFUN char const *nea_default_content_type(char const *event);
+
+SOFIA_END_DECLS
+
+#endif /* !defined(NEA_H) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/sofia-sip/nea_tag.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nea/sofia-sip/nea_tag.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,174 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef NEA_TAG_H
+/** Defined when <sofia-sip/nea_tag.h> has been included. */
+#define NEA_TAG_H
+
+/**@file sofia-sip/nea_tag.h
+ * @brief Tags for Nokia User Agent Library
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti Mela at nokia.com>
+ *
+ * @date Created: Mon Nov 28 18:54:26 EET 2005 mela
+ */
+
+#ifndef SU_TAG_H
+#include <sofia-sip/su_tag.h>
+#endif
+#ifndef URL_TAG_H
+#include <sofia-sip/url_tag.h>
+#endif
+#ifndef SIP_TAG_H
+#include <sofia-sip/sip_tag.h>
+#endif
+#ifndef NTA_TAG_H
+#include <sofia-sip/nta_tag.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** Event states */
+typedef enum {
+ nea_extended = -1,
+ nea_embryonic = 0, /** Before first notify */
+ nea_pending,
+ nea_active,
+ nea_terminated
+} nea_state_t;
+
+/** Filter tag matching any nea tag. */
+#define NEATAG_ANY() neatag_any, ((tag_value_t)0)
+SOFIAPUBVAR tag_typedef_t neatag_any;
+
+/** Specify the minimum duration of a subscription (by default, 15 minutes) */
+#define NEATAG_MIN_EXPIRES(x) neatag_min_expires, tag_uint_v((x))
+SOFIAPUBVAR tag_typedef_t neatag_min_expires;
+
+#define NEATAG_MIN_EXPIRES_REF(x) neatag_min_expires_ref, tag_uint_vr((&x))
+SOFIAPUBVAR tag_typedef_t neatag_min_expires_ref;
+
+#define NEATAG_MINSUB(x) neatag_min_expires, tag_uint_v((x))
+#define NEATAG_MINSUB_REF(x) neatag_min_expires_ref, tag_uint_vr((&x))
+
+/** Specify the default duration of a subscription (by default, 60 minutes) */
+#define NEATAG_EXPIRES(x) neatag_expires, tag_uint_v((x))
+SOFIAPUBVAR tag_typedef_t neatag_expires;
+
+#define NEATAG_EXPIRES_REF(x) neatag_expires_ref, tag_uint_vr((&x))
+SOFIAPUBVAR tag_typedef_t neatag_expires_ref;
+
+/** Specify the maximum duration of a subscription (by default, 24 hours) */
+#define NEATAG_MAX_EXPIRES(x) neatag_max_expires, tag_uint_v((x))
+SOFIAPUBVAR tag_typedef_t neatag_max_expires;
+
+#define NEATAG_MAX_EXPIRES_REF(x) neatag_max_expires_ref, tag_uint_vr((&x))
+SOFIAPUBVAR tag_typedef_t neatag_max_expires_ref;
+
+/** Indicate/require support for "eventlist" feature. */
+#define NEATAG_EVENTLIST(x) neatag_eventlist, tag_bool_v((x))
+SOFIAPUBVAR tag_typedef_t neatag_eventlist;
+
+#define NEATAG_EVENTLIST_REF(x) neatag_eventlist_ref, tag_bool_vr((&x))
+SOFIAPUBVAR tag_typedef_t neatag_eventlist_ref;
+
+/** Specify the default throttle value for subscription. */
+#define NEATAG_THROTTLE(x) neatag_throttle, tag_uint_v((x))
+SOFIAPUBVAR tag_typedef_t neatag_throttle;
+
+#define NEATAG_THROTTLE_REF(x) neatag_throttle_ref, tag_uint_vr((&x))
+SOFIAPUBVAR tag_typedef_t neatag_throttle_ref;
+
+/** Specify the minimum throttle value for subscription. */
+#define NEATAG_MINTHROTTLE(x) neatag_minthrottle, tag_uint_v((x))
+SOFIAPUBVAR tag_typedef_t neatag_minthrottle;
+
+#define NEATAG_MINTHROTTLE_REF(x) neatag_minthrottle_ref, tag_uint_vr((&x))
+SOFIAPUBVAR tag_typedef_t neatag_minthrottle_ref;
+
+/** Specify dialog handle */
+#define NEATAG_DIALOG(x) neatag_dialog, tag_ptr_v((x))
+SOFIAPUBVAR tag_typedef_t neatag_dialog;
+
+#define NEATAG_DIALOG_REF(x) neatag_dialog_ref, tag_ptr_vr((&x), (x))
+SOFIAPUBVAR tag_typedef_t neatag_dialog_ref;
+
+/* Server-specific tags */
+
+/** Pass pointer to subscription */
+#define NEATAG_SUB(x) neatag_sub, tag_ptr_v((x))
+SOFIAPUBVAR tag_typedef_t neatag_sub;
+
+#define NEATAG_SUB_REF(x) neatag_sub_ref, tag_ptr_vr((&x), (x))
+SOFIAPUBVAR tag_typedef_t neatag_sub_ref;
+
+/** Use fake content. @sa nea_sub_auth() and nea_server_update(). */
+#define NEATAG_FAKE(x) neatag_fake, tag_bool_v((x))
+SOFIAPUBVAR tag_typedef_t neatag_fake;
+
+#define NEATAG_FAKE_REF(x) neatag_fake_ref, tag_bool_vr((&x))
+SOFIAPUBVAR tag_typedef_t neatag_fake_ref;
+
+/** Specify reason for termination */
+#define NEATAG_REASON(x) neatag_reason, tag_str_v((x))
+SOFIAPUBVAR tag_typedef_t neatag_reason;
+
+#define NEATAG_REASON_REF(x) neatag_reason_ref, tag_str_vr((&x))
+SOFIAPUBVAR tag_typedef_t neatag_reason_ref;
+
+/** Specify retry-after for termination */
+#define NEATAG_RETRY_AFTER(x) neatag_retry_after, tag_uint_v((x))
+SOFIAPUBVAR tag_typedef_t neatag_retry_after;
+
+#define NEATAG_RETRY_AFTER_REF(x) neatag_retry_after_ref, tag_uint_vr((&x))
+SOFIAPUBVAR tag_typedef_t neatag_retry_after_ref;
+
+/** Specify extended state for subscription-state */
+#define NEATAG_EXSTATE(x) neatag_exstate, tag_str_v((x))
+SOFIAPUBVAR tag_typedef_t neatag_exstate;
+
+#define NEATAG_EXSTATE_REF(x) neatag_exstate_ref, tag_str_vr((&x))
+SOFIAPUBVAR tag_typedef_t neatag_exstate_ref;
+
+/** Do not try to conform pre-3265 notifiers/watchers */
+#define NEATAG_STRICT_3265(x) neatag_strict_3265, tag_bool_v((x))
+SOFIAPUBVAR tag_typedef_t neatag_strict_3265;
+
+#define NEATAG_STRICT_3265_REF(x) neatag_strict_3265_ref, tag_bool_vr((&x))
+SOFIAPUBVAR tag_typedef_t neatag_strict_3265_ref;
+
+/** Version number of content */
+#define NEATAG_VERSION(x) neatag_version, tag_uint_v((x))
+SOFIAPUBVAR tag_typedef_t neatag_version;
+
+#define NEATAG_VERSION_REF(x) neatag_version_ref, tag_uint_vr((&x))
+SOFIAPUBVAR tag_typedef_t neatag_version_ref;
+
+/** List of all NEA tags. */
+/* extern tag_type_t nea_tag_list[]; */
+
+SOFIA_END_DECLS
+
+#endif
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/ChangeLog Thu Dec 21 01:30:28 2006
@@ -0,0 +1,102 @@
+2005-11-08 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Renamed nta_test.c as test_nta.c.
+
+2005-10-21 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Fixed server-rport feature in nta.c.
+
+ M ./libsofia-sip-ua/nta/nta.c -2 +2
+
+ * Fixed agent_init_contact() in nta/nta.c.
+ The logic for selecting transport parameter for primary contact was flawed.
+ Added some tests, too.
+
+ M ./libsofia-sip-ua/nta/nta.c -9 +20
+ M ./libsofia-sip-ua/nta/nta_test.c +54
+
+2005-10-15 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Fix callerpref bug #1326727.
+
+ Copying Accept-Contact, Reject-Contact, and Request-Disposition from
+ original request to ACK/CANCEL.
+
+ M ./libsofia-sip-ua/nta/nta.c -1 +5
+
+ * Fixed socket() if AF_INET6 is used.
+
+ M ./libsofia-sip-ua/nta/nta_test.c -3 +3
+
+ * Removed Last modified.
+
+ M ./libsofia-sip-ua/nta/nta.c -1
+ M ./libsofia-sip-ua/nta/nta.h -1
+ M ./libsofia-sip-ua/nta/nta_compat.c -1
+ M ./libsofia-sip-ua/nta/nta_compat.h -1
+ M ./libsofia-sip-ua/nta/nta_dll.h -1
+ M ./libsofia-sip-ua/nta/nta_internal.h -1
+ M ./libsofia-sip-ua/nta/nta_stateless.h -1
+ M ./libsofia-sip-ua/nta/nta_tag.c -1
+ M ./libsofia-sip-ua/nta/nta_tag.h -1
+ M ./libsofia-sip-ua/nta/nta_test.c -1
+ M ./libsofia-sip-ua/nta/nta_tport.h -1
+ M ./libsofia-sip-ua/nta/portbind.c -1
+ M ./libsofia-sip-ua/nta/sl_read_payload.c -1
+ M ./libsofia-sip-ua/nta/sl_utils.h -1
+ M ./libsofia-sip-ua/nta/sl_utils_log.c -1
+ M ./libsofia-sip-ua/nta/sl_utils_print.c -1
+
+2005-10-12 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Contact generated by nta now contains URL transport parameter.
+ The transport=UDP was left out from contact URL always. Now it is left out
+ only if both UDP and TCP are supported.
+ Added utility function sip_contact_create_from_via_with_transport().
+
+ M ./libsofia-sip-ua/nta/nta.c -2 +14
+ M ./libsofia-sip-ua/sip/sip_util.c -10 +28
+ M ./libsofia-sip-ua/sip/sip_util.h +6
+
+2005-10-10 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Fixed memory leak in nta_agent_create()/nta_agent_destroy().
+
+ M ./libsofia-sip-ua/nta/nta.c -2 +2
+
+2005-10-04 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Added agent.pem and cafile.pem for TLS testing.
+
+2005-08-29 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * nta.c (nta_agent_set_params()): Returning -1 upon an error.
+
+2005-08-26 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * nta.c, nta_test.c: Fixed alias usage.
+
+2005-08-10 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Now we can start agent without any transport interfaces.
+
+ Added flag for disabling server-side rport.
+
+2005-08-03 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Fixed running tests on IPv6. Added portbind.
+
+2005-07-14 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * nta_internal.h, nta_tag.h, nta_tag.c, nta.c: Added bitmasks for
+ detecting parsing errors.
+
+ * nta.c: Accept CANCELs for non-INVITEs, too.
+
+2005-07-20 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * run_nta_test: Fixed portbind/bind test.
+
+2005-07-18 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * Initial import of the module to Sofia-SIP tree.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/Doxyfile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/Doxyfile Thu Dec 21 01:30:28 2006
@@ -0,0 +1,23 @@
+PROJECT_NAME = "nta"
+OUTPUT_DIRECTORY = ../docs/html/nta
+
+INPUT = nta.docs sofia-sip .
+
+ at INCLUDE = ../docs/Doxyfile.conf
+
+TAGFILES += ../docs/su.doxytags=../su
+TAGFILES += ../docs/ipt.doxytags=../ipt
+TAGFILES += ../docs/bnf.doxytags=../bnf
+TAGFILES += ../docs/url.doxytags=../url
+TAGFILES += ../docs/msg.doxytags=../msg
+TAGFILES += ../docs/sip.doxytags=../sip
+TAGFILES += ../docs/sresolv.doxytags=../sresolv
+TAGFILES += ../docs/tport.doxytags=../tport
+
+GENERATE_TAGFILE = ../docs/nta.doxytags
+
+EXCLUDE_PATTERNS += sl_*.h sl_*.c nta_compat.*
+
+ALIASES +=
+
+ at INCLUDE = ../sip/sip.doxyaliases
\ No newline at end of file
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/Makefile.am Thu Dec 21 01:30:28 2006
@@ -0,0 +1,79 @@
+#
+# Makefile.am for nta module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+INCLUDES = -I$(srcdir)/../ipt -I../ipt \
+ -I$(srcdir)/../msg -I../msg \
+ -I$(srcdir)/../sip -I../sip \
+ -I$(srcdir)/../bnf -I../bnf \
+ -I$(srcdir)/../sresolv -I../sresolv \
+ -I$(srcdir)/../tport -I../tport \
+ -I$(srcdir)/../url -I../url \
+ -I$(srcdir)/../features -I../features \
+ -I$(srcdir)/../su -I../su
+
+# ----------------------------------------------------------------------
+# Build targets
+
+noinst_LTLIBRARIES = libnta.la
+
+check_PROGRAMS = test_nta_api test_nta portbind
+dist_noinst_SCRIPTS = run_test_nta_api run_test_nta
+
+TESTS = run_test_nta_api run_test_nta
+TESTS_ENVIRONMENT = $(SHELL)
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+
+BUILT_SOURCES = nta_tag_ref.c
+
+nobase_include_sofia_HEADERS = \
+ sofia-sip/nta.h sofia-sip/nta_stateless.h \
+ sofia-sip/nta_tport.h sofia-sip/nta_tag.h \
+ sofia-sip/sl_utils.h
+
+libnta_la_SOURCES = nta.c nta_check.c nta_tag.c nta_tag_ref.c \
+ nta_internal.h \
+ sl_utils_print.c sl_utils_log.c \
+ sl_read_payload.c
+
+COVERAGE_INPUT = $(libnta_la_SOURCES) $(include_sofia_HEADERS)
+
+LDADD = libnta.la \
+ ../ipt/libipt.la \
+ ../sip/libsip.la \
+ ../features/libfeatures.la \
+ ../sresolv/libsresolv.la \
+ ../tport/libtport.la \
+ ../http/libhttp.la \
+ ../stun/libstun.la \
+ ../url/liburl.la \
+ ../msg/libmsg.la \
+ ../bnf/libbnf.la \
+ ../su/libsu.la
+
+test_nta_LDFLAGS = -static
+
+MOSTLYCLEANFILES += .test[0-9]*
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+
+EXTRA_DIST = Doxyfile nta.docs sl_utils.docs \
+ agent.pem cafile.pem \
+ invite.msc $(BUILT_SOURCES)
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+
+include ../sofia.am
+
+# Generate list of nta tags
+TAG_DLL_FLAGS = LIST=nta_tag_list
\ No newline at end of file
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/Makefile.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1,763 @@
+# 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.
+
+ at SET_MAKE@
+
+#
+# Makefile.am for nta module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+# common Makefile targets for libsofia-sip-ua modules
+# ---------------------------------------------------
+
+
+
+SOURCES = $(libnta_la_SOURCES) portbind.c test_nta.c test_nta_api.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 = test_nta_api$(EXEEXT) test_nta$(EXEEXT) \
+ portbind$(EXEEXT)
+DIST_COMMON = $(dist_noinst_SCRIPTS) $(nobase_include_sofia_HEADERS) \
+ $(srcdir)/../sofia.am $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in ChangeLog
+subdir = libsofia-sip-ua/nta
+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 =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libnta_la_LIBADD =
+am_libnta_la_OBJECTS = nta.lo nta_check.lo nta_tag.lo nta_tag_ref.lo \
+ sl_utils_print.lo sl_utils_log.lo sl_read_payload.lo
+libnta_la_OBJECTS = $(am_libnta_la_OBJECTS)
+portbind_SOURCES = portbind.c
+portbind_OBJECTS = portbind.$(OBJEXT)
+portbind_LDADD = $(LDADD)
+portbind_DEPENDENCIES = libnta.la ../ipt/libipt.la ../sip/libsip.la \
+ ../features/libfeatures.la ../sresolv/libsresolv.la \
+ ../tport/libtport.la ../http/libhttp.la ../stun/libstun.la \
+ ../url/liburl.la ../msg/libmsg.la ../bnf/libbnf.la \
+ ../su/libsu.la
+test_nta_SOURCES = test_nta.c
+test_nta_OBJECTS = test_nta.$(OBJEXT)
+test_nta_LDADD = $(LDADD)
+test_nta_DEPENDENCIES = libnta.la ../ipt/libipt.la ../sip/libsip.la \
+ ../features/libfeatures.la ../sresolv/libsresolv.la \
+ ../tport/libtport.la ../http/libhttp.la ../stun/libstun.la \
+ ../url/liburl.la ../msg/libmsg.la ../bnf/libbnf.la \
+ ../su/libsu.la
+test_nta_api_SOURCES = test_nta_api.c
+test_nta_api_OBJECTS = test_nta_api.$(OBJEXT)
+test_nta_api_LDADD = $(LDADD)
+test_nta_api_DEPENDENCIES = libnta.la ../ipt/libipt.la \
+ ../sip/libsip.la ../features/libfeatures.la \
+ ../sresolv/libsresolv.la ../tport/libtport.la \
+ ../http/libhttp.la ../stun/libstun.la ../url/liburl.la \
+ ../msg/libmsg.la ../bnf/libbnf.la ../su/libsu.la
+SCRIPTS = $(dist_noinst_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 = $(libnta_la_SOURCES) portbind.c test_nta.c test_nta_api.c
+DIST_SOURCES = $(libnta_la_SOURCES) portbind.c test_nta.c \
+ test_nta_api.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|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(include_sofiadir)"
+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@ .test[0-9]*
+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 = $(SHELL)
+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)/../ipt -I../ipt \
+ -I$(srcdir)/../msg -I../msg \
+ -I$(srcdir)/../sip -I../sip \
+ -I$(srcdir)/../bnf -I../bnf \
+ -I$(srcdir)/../sresolv -I../sresolv \
+ -I$(srcdir)/../tport -I../tport \
+ -I$(srcdir)/../url -I../url \
+ -I$(srcdir)/../features -I../features \
+ -I$(srcdir)/../su -I../su
+
+
+# ----------------------------------------------------------------------
+# Build targets
+noinst_LTLIBRARIES = libnta.la
+dist_noinst_SCRIPTS = run_test_nta_api run_test_nta
+TESTS = run_test_nta_api run_test_nta
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+BUILT_SOURCES = nta_tag_ref.c
+nobase_include_sofia_HEADERS = \
+ sofia-sip/nta.h sofia-sip/nta_stateless.h \
+ sofia-sip/nta_tport.h sofia-sip/nta_tag.h \
+ sofia-sip/sl_utils.h
+
+libnta_la_SOURCES = nta.c nta_check.c nta_tag.c nta_tag_ref.c \
+ nta_internal.h \
+ sl_utils_print.c sl_utils_log.c \
+ sl_read_payload.c
+
+COVERAGE_INPUT = $(libnta_la_SOURCES) $(include_sofia_HEADERS)
+LDADD = libnta.la \
+ ../ipt/libipt.la \
+ ../sip/libsip.la \
+ ../features/libfeatures.la \
+ ../sresolv/libsresolv.la \
+ ../tport/libtport.la \
+ ../http/libhttp.la \
+ ../stun/libstun.la \
+ ../url/liburl.la \
+ ../msg/libmsg.la \
+ ../bnf/libbnf.la \
+ ../su/libsu.la
+
+test_nta_LDFLAGS = -static
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+EXTRA_DIST = Doxyfile nta.docs sl_utils.docs \
+ agent.pem cafile.pem \
+ invite.msc $(BUILT_SOURCES)
+
+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
+
+# Generate list of nta tags
+TAG_DLL_FLAGS = LIST=nta_tag_list
+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/nta/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu libsofia-sip-ua/nta/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-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
+libnta.la: $(libnta_la_OBJECTS) $(libnta_la_DEPENDENCIES)
+ $(LINK) $(libnta_la_LDFLAGS) $(libnta_la_OBJECTS) $(libnta_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
+portbind$(EXEEXT): $(portbind_OBJECTS) $(portbind_DEPENDENCIES)
+ @rm -f portbind$(EXEEXT)
+ $(LINK) $(portbind_LDFLAGS) $(portbind_OBJECTS) $(portbind_LDADD) $(LIBS)
+test_nta$(EXEEXT): $(test_nta_OBJECTS) $(test_nta_DEPENDENCIES)
+ @rm -f test_nta$(EXEEXT)
+ $(LINK) $(test_nta_LDFLAGS) $(test_nta_OBJECTS) $(test_nta_LDADD) $(LIBS)
+test_nta_api$(EXEEXT): $(test_nta_api_OBJECTS) $(test_nta_api_DEPENDENCIES)
+ @rm -f test_nta_api$(EXEEXT)
+ $(LINK) $(test_nta_api_LDFLAGS) $(test_nta_api_OBJECTS) $(test_nta_api_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nta.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nta_check.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nta_tag.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nta_tag_ref.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/portbind.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sl_read_payload.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sl_utils_log.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sl_utils_print.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_nta.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_nta_api.Po at am__quote@
+
+.c.o:
+ at am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+ at am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ at am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at 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 $(LTLIBRARIES) $(SCRIPTS) $(HEADERS)
+installdirs:
+ for dir in "$(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-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-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-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-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-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-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) $<
+
+ at ENABLE_COVERAGE_TRUE@coverage:
+ at 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)
+# 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:
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/agent.pem
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/agent.pem Thu Dec 21 01:30:28 2006
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIDPjCCAqegAwIBAgIHJQIBAZACBjANBgkqhkiG9w0BAQUFADBwMQswCQYDVQQG
+EwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTERMA8GA1UEBxMIU2FuIEpvc2UxDjAM
+BgNVBAoTBXNpcGl0MSkwJwYDVQQLEyBTaXBpdCBUZXN0IENlcnRpZmljYXRlIEF1
+dGhvcml0eTAeFw0wMzEyMDMxODMwMjJaFw0wNjEyMDIxODMwMjJaMGUxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMREwDwYDVQQHEwhTYW4gSm9zZTEO
+MAwGA1UEChMFc2lwaXQxHjAcBgNVBAMTFXBla2thLm5va2lhLnNpcGl0Lm5ldDCB
+nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAsdJn/O6JoIC1I2iXOVJLQypmt9sN
+HmvB84853Qx9KS+xqP3U2nqNMnDQby6ZmTsRHNGAK5QuGugU11wocmYNP0/TQFaz
+KNLhNt0pMBOfpAV9vG6pCSkocObsUo2XFULPTEB/SzGcvE1G1em3XmwRfPA178y9
+L2+sVNT5Vtt5KfMCAwEAAaOB7DCB6TAgBgNVHREEGTAXghVwZWtrYS5ub2tpYS5z
+aXBpdC5uZXQwCQYDVR0TBAIwADAdBgNVHQ4EFgQU1OjdL9cdA0NNbxPDQ9xZUZG6
+NnIwgZoGA1UdIwSBkjCBj4AUa0YXFOqUdiWAVG4TVNqh41QUobahdKRyMHAxCzAJ
+BgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMREwDwYDVQQHEwhTYW4gSm9z
+ZTEOMAwGA1UEChMFc2lwaXQxKTAnBgNVBAsTIFNpcGl0IFRlc3QgQ2VydGlmaWNh
+dGUgQXV0aG9yaXR5ggEAMA0GCSqGSIb3DQEBBQUAA4GBADCO35LJqgiK5OUR+DuT
+N4CfUhsn9T5kDSf2rikna4ZFbuS7smc/oVu4g26HHjt6DKs4UEx9OmyXFslSENZ+
+tFNeVClpHJrPsNwjk/uyjhfeW1NezhXMIi6q8DYcwE5I7r+Uz2XST+jWCTb4obPY
+10ysI7e7/rgCoITe+qO2U35D
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQCx0mf87omggLUjaJc5UktDKma32w0ea8HzjzndDH0pL7Go/dTa
+eo0ycNBvLpmZOxEc0YArlC4a6BTXXChyZg0/T9NAVrMo0uE23SkwE5+kBX28bqkJ
+KShw5uxSjZcVQs9MQH9LMZy8TUbV6bdebBF88DXvzL0vb6xU1PlW23kp8wIDAQAB
+AoGAVtICT64vqBvvVPB2FVimwo5rRI1BJH88XSyq9dBpM7jDp1z3lgyL7/rA6ef4
+uqXqPwXS7HQW5rA1rMikPuawxE5UG31OG3U0+H/OGl0xwAq57mEtRDR8464jSUPY
+l9bzkRpjnEgdUtkLnogm8F4mALexdc3KxIgg3uo/OOg0N5ECQQDZon1JBNEYWxEF
+GBNbEvQthPy7rRLmxontgcsfhRvm5lSbuC+VP1uRHibwwIrXOUZD8uuEVdVZNzfV
+bGPdh70HAkEA0Ss6HyAWczRBzrvC8eVvPmkI9XihdLqUFLTDL0R1sMCISwW/FEeH
+X9yFqOY+y6EJAitzhxtol+0k+UsIJl5ctQJAXU0L6QHnokloQobPxXuasukQcGUC
+dW0oNGowapLmI1cbbqbHv3QqDUyf5Rambx5ewUKjNViW3miNxzFwnshSgQJAINuQ
+gskwnaJM4CPgqM0o333yeVUcz9BraKFItAkmD8D+6AIcFRxzaJykpnac0LIYTy3y
+NPwaPxtynnKp8hUKrQJBAM1i5051UzJVFuRedwtPdGDrfkNwoJm27fwWozSQcBC6
+G5VnTrQ6V8VCJglNzVhy9b2WqlqfWV3D5BCgxyuH984=
+-----END RSA PRIVATE KEY-----
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/cafile.pem
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/cafile.pem Thu Dec 21 01:30:28 2006
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDJDCCAo2gAwIBAgIBADANBgkqhkiG9w0BAQUFADBwMQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTERMA8GA1UEBxMIU2FuIEpvc2UxDjAMBgNVBAoT
+BXNpcGl0MSkwJwYDVQQLEyBTaXBpdCBUZXN0IENlcnRpZmljYXRlIEF1dGhvcml0
+eTAeFw0wMzA3MTgxMjIxNTJaFw0xMzA3MTUxMjIxNTJaMHAxCzAJBgNVBAYTAlVT
+MRMwEQYDVQQIEwpDYWxpZm9ybmlhMREwDwYDVQQHEwhTYW4gSm9zZTEOMAwGA1UE
+ChMFc2lwaXQxKTAnBgNVBAsTIFNpcGl0IFRlc3QgQ2VydGlmaWNhdGUgQXV0aG9y
+aXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDIh6DkcUDLDyK9BEUxkud
++nJ4xrCVGKfgjHm6XaSuHiEtnfELHM+9WymzkBNzZpJu30yzsxwfKoIKugdNUrD4
+N3viCicwcN35LgP/KnbN34cavXHr4ZlqxH+OdKB3hQTpQa38A7YXdaoz6goW2ft5
+Mi74z03GNKP/G9BoKOGd5QIDAQABo4HNMIHKMB0GA1UdDgQWBBRrRhcU6pR2JYBU
+bhNU2qHjVBShtjCBmgYDVR0jBIGSMIGPgBRrRhcU6pR2JYBUbhNU2qHjVBShtqF0
+pHIwcDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExETAPBgNVBAcT
+CFNhbiBKb3NlMQ4wDAYDVQQKEwVzaXBpdDEpMCcGA1UECxMgU2lwaXQgVGVzdCBD
+ZXJ0aWZpY2F0ZSBBdXRob3JpdHmCAQAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0B
+AQUFAAOBgQCWbRvv1ZGTRXxbH8/EqkdSCzSoUPrs+rQqR0xdQac9wNY/nlZbkR3O
+qAezG6Sfmklvf+DOg5RxQq/+Y6I03LRepc7KeVDpaplMFGnpfKsibETMipwzayNQ
+QgUf4cKBiF+65Ue7hZuDJa2EMv8qW4twEhGDYclpFU9YozyS1OhvUg==
+-----END CERTIFICATE-----
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/invite.msc
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/invite.msc Thu Dec 21 01:30:28 2006
@@ -0,0 +1,159 @@
+#
+# MSCs Illustrating NTA Usage
+#
+
+User Agent Client Initiating a Call
+-----------------------------------
+
+ APP ¦ NTA
+User ¦
+Agent ¦
+ | ¦
+ | nta = nta_agent_create
+ |- - - - - - - - - - - - - - - - -> NTA
+ | (msg_cb, contact) ¦ agent
+ | ¦ |
+ | ¦ |
+ |- - ->Call ¦ |
+ | | ¦ |
+ | | leg = nta_leg_create |
+ | |- - - - - - -¦- - - - - - -|- - - -> leg
+ | |(nta, leg_cb, ..., To, From, ... ) |
+ | | ¦ | |
+ | | ¦ | |
+ | | oreq = nta_outgoing_create| |
+ | |- - - - - - -¦- - - - - - -|- - - - - | - - -> outgoing
+ | | (leg, response_cb, INVITE, url, headers...) |
+ | | ¦ | | |
+ | | ¦ | | | INVITE
+ | | ¦ | | |---->
+ | | ¦ | | |
+ | | ¦ | | | 100 Trying
+ | | ¦ | | |<----
+ | | ¦ | | |
+ | | ¦ | | | 180 Ringing
+ | | ¦ | response_cb(180) |<----
+ | ALERT |<--------------------------|----------|------------|
+ |<-------| ¦ | | | 200 OK
+ | | ¦ | response_cb(200) |<----
+ |OFFHOOK |<--------------------------|----------|------------|
+ |<-------| ¦ | | |
+ | | nta_outgoing_destroy | | |
+ | |---------------------------|----------|----------->|
+ | | ¦ | | X
+ | | nta_leg_destroy | |
+ | |---------------------------|--------->|
+ | | ¦ | X
+ | | leg = nta_leg_create |
+ | |- - - - - - -¦- - - - - - -|- - - -> leg
+ | |(nta, leg_cb, ..., To+tag, From, ...) |
+ | | ¦ | |
+ | | oreq = nta_outgoing_create| |
+ | |- - - - - - -¦- - - - - - -|- - - - - | - - -> outgoing
+ | | (leg, ..., ACK, url, headers) | |
+ | | ¦ | | | ACK
+ | | ¦ | | |---->
+ | | nta_outgoing_destroy | | |
+ | |---------------------------|----------|----------->|
+ | | ¦ | | X
+
+
+User Agent Client Releasing a Call
+-----------------------------------
+
+ APP ¦ NTA
+User Call ¦ NTA leg
+Agent | ¦ agent |
+ | | ¦ | |
+ |ONHOOK | ¦ | |
+ |------->| ¦ | |
+ | |oreq = nta_outgoing_create | |
+ | |- - - - - - -¦- - - - - - -|- - - - - | - - -> outgoing
+ | | (leg, ..., BYE, url, headers) | |
+ | | ¦ | | | BYE
+ | | ¦ | | |---->
+ | | ¦ | | |
+ | | ¦ | | | 180 Ringing
+ | | ¦ | response_cb(180) |<----
+ | |<--------------------------|----------|------------|
+ | | ¦ | | | 200 OK
+ | | ¦ | response_cb(200) |<----
+ | |<--------------------------|----------|------------|
+ | | ¦ | | |
+ | |nta_outgoing_destroy | | |
+ | |---------------------------|----------|----------->|
+ | | ¦ | | X
+ | |nta_leg_destroy | |
+ | |---------------------------|--------->|
+ | | ¦ | X
+ | X ¦ |
+
+
+User Agent Server Accepting a Call
+----------------------------------
+
+ APP ¦ NTA
+User ¦ NTA
+Agent ¦ agent
+ | ¦ | INVITE
+ | ¦ |<----------------------
+ | ¦ |
+ | msg_cb(leg, msg) |
+ |<-----------------------------------|
+ | ¦ |
+ |- - -> Call ¦ |
+ | | nta_msg_leg ¦ |
+ | |-------------------------->|- - - -> leg
+ | | (msg, request_cb) | |
+ | | ¦ | |- - - -> incoming
+ | | nta_leg_tag ¦ | | |
+ | |---------------------------|--------->| |
+ | | (tag) ¦ | | |
+ | | ¦ | request_cb(reply) |
+ | |<--------------------------|----------|------------|
+ | | ¦ | | |
+ | | nta_incoming_bind(ireq, ack_cb) | |
+ | |---------------------------|----------|----------->|
+ | | ¦ | | |
+ | | nta_incoming_reply(180) | | |
+ | ALERT |---------------------------|----------|----------->| 180 Ringing
+ |<-------| ¦ | | |---->
+ | | ¦ | | |
+ |OFFHOOK | ¦ | | |
+ |------->| nta_incoming_reply | | |
+ | |---------------------------|----------|----------->| 200 Ok
+ | | (200, sdp) ¦ | | |---->
+ | | ¦ | | |
+ | | ¦ | | | ACK
+ | | ¦ | |ack_cb(ACK) |<----
+ | |<--------------------------|----------|------------|
+ | | ¦ | | |
+ | | nta_incoming_destroy(ireq)| | |
+ | |---------------------------|----------|----------->|
+ | | ¦ | | X
+
+
+User Agent Server Receiving a Call Release
+------------------------------------------
+
+ APP ¦ NTA
+User Call ¦ NTA leg
+Agent | ¦ agent |
+ | | ¦ | | BYE
+ | | ¦ | |<------------------
+ | | ¦ | |
+ | | ¦ | |- - - -> Incoming
+ | | ¦ | | |
+ | | ¦ | request_cb(reply) |
+ | ONHOOK |<--------------------------|----------|------------|
+ |<-------| ¦ | | |
+ | | nta_incoming_reply(200) | | |
+ | |---------------------------|----------|----------->| 200 Ok
+ | | (200, sdp) ¦ | | |---->
+ | | ¦ | | |
+ | | nta_incoming_destroy(ireq)| | |
+ | |---------------------------|----------|----------->|
+ | | ¦ | | X
+ | |nta_leg_destroy | |
+ | |---------------------------|--------->|
+ | X ¦ | X
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,10182 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nta.c
+ * @brief Sofia SIP Transaction API implementation
+ *
+ * This source file has been divided into sections as follows:
+ * 1) agent
+ * 2) tport handling
+ * 3) dispatching messages received from network
+ * 4) message creation, message utility
+ * 5) stateless operation
+ * 6) dialogs (legs)
+ * 7) server transactions (incoming)
+ * 8) client transactions (outgoing)
+ * 9) resolving URLs for client transactions
+ * 10) 100rel reliable responses (reliable)
+ * 11) SigComp handling and public transport interface
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Jun 13 02:57:51 2000 ppessi
+ */
+
+#include "config.h"
+
+#include <sofia-sip/string0.h>
+
+/** @internal SU message argument structure type */
+#define SU_MSG_ARG_T union sm_arg_u
+/** @internal SU timer argument pointer type */
+#define SU_TIMER_ARG_T struct nta_agent_s
+
+#include <sofia-sip/su_alloc.h>
+#include <sofia-sip/su.h>
+#include <sofia-sip/su_time.h>
+#include <sofia-sip/su_wait.h>
+#include <sofia-sip/su_tagarg.h>
+
+#include <sofia-sip/base64.h>
+#include <sofia-sip/su_uniqueid.h>
+
+#include <sofia-sip/sip.h>
+#include <sofia-sip/sip_header.h>
+#include <sofia-sip/sip_util.h>
+#include <sofia-sip/sip_status.h>
+
+#include <sofia-sip/hostdomain.h>
+
+#include <sofia-sip/msg_addr.h>
+#include <sofia-sip/msg_parser.h>
+
+#include "nta_internal.h"
+#include "sofia-sip/nta_stateless.h"
+#include "sofia-sip/url_tag.h"
+
+#if !defined(random) && defined(_WIN32)
+#define random rand
+#endif
+
+#if !defined(EMSGSIZE) && defined(_WIN32)
+#define EMSGSIZE WSAEMSGSIZE
+#endif
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <limits.h>
+#include <errno.h>
+
+/* From AM_INIT/AC_INIT in our "config.h" */
+char const nta_version[] = PACKAGE_VERSION;
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+static char const __func__[] = "nta";
+#endif
+
+#define NONE ((void *)-1)
+
+/* Internal tags */
+
+/* Delay sending of request */
+#define NTATAG_DELAY_SENDING(x) ntatag_delay_sending, tag_bool_v((x))
+#define NTATAG_DELAY_SENDING_REF(x) \
+ntatag_delay_sending_ref, tag_bool_vr(&(x))
+
+extern tag_typedef_t ntatag_delay_sending;
+extern tag_typedef_t ntatag_delay_sending_ref;
+
+/* Allow sending incomplete responses */
+#define NTATAG_INCOMPLETE(x) ntatag_incomplete, tag_bool_v((x))
+#define NTATAG_INCOMPLETE_REF(x) \
+ntatag_incomplete_ref, tag_bool_vr(&(x))
+
+extern tag_typedef_t ntatag_incomplete;
+extern tag_typedef_t ntatag_incomplete_ref;
+
+nta_compressor_vtable_t *nta_compressor_vtable = NULL;
+
+/* Agent */
+static int agent_tag_init(nta_agent_t *self);
+static int agent_timer_init(nta_agent_t *agent);
+static void agent_timer(su_root_magic_t *rm, su_timer_t *, nta_agent_t *);
+static int agent_launch_terminator(nta_agent_t *agent);
+static void agent_kill_terminator(nta_agent_t *agent);
+static int agent_set_params(nta_agent_t *agent, tagi_t *tags);
+static void agent_set_udp_params(nta_agent_t *self, usize_t udp_mtu);
+static int agent_get_params(nta_agent_t *agent, tagi_t *tags);
+
+/* Transport interface */
+static sip_via_t const *agent_tport_via(tport_t *tport);
+static int outgoing_insert_via(nta_outgoing_t *orq, sip_via_t const *);
+static int nta_tpn_by_via(tp_name_t *tpn, sip_via_t const *v, int *using_rport);
+
+static msg_t *nta_msg_create_for_transport(nta_agent_t *agent, int flags,
+ char const data[], usize_t dlen,
+ tport_t const *tport,
+ tp_client_t *via);
+
+static int complete_response(msg_t *response,
+ int status, char const *phrase,
+ msg_t const *request);
+
+#define IF_SIGCOMP_TPTAG_COMPARTMENT(cc) TAG_IF(cc, TPTAG_COMPARTMENT(cc)),
+#define IF_SIGCOMP_TPTAG_COMPARTMENT_REF(cc) TPTAG_COMPARTMENT_REF(cc),
+
+struct sigcomp_compartment;
+
+struct sigcomp_compartment *
+nta_compartment_ref(struct sigcomp_compartment *cc);
+
+static
+struct sigcomp_compartment *
+agent_compression_compartment(nta_agent_t *sa, tport_t *tp, tp_name_t const *tpn,
+ int new_if_needed);
+
+static
+int agent_accept_compressed(nta_agent_t *sa, msg_t *msg,
+ struct sigcomp_compartment *cc);
+
+static int agent_close_compressor(nta_agent_t *sa,
+ struct sigcomp_compartment *cc);
+
+static int agent_zap_compressor(nta_agent_t *sa,
+ struct sigcomp_compartment *cc);
+
+
+static char const * stateful_branch(su_home_t *home, nta_agent_t *);
+static char const * stateless_branch(nta_agent_t *, msg_t *, sip_t const *,
+ tp_name_t const *tp);
+
+#define NTA_BRANCH_PRIME SU_U64_C(0xB9591D1C361C6521)
+#define NTA_TAG_PRIME SU_U64_C(0xB9591D1C361C6521)
+
+HTABLE_PROTOS_WITH(leg_htable, lht, nta_leg_t, size_t, hash_value_t);
+static nta_leg_t *leg_find(nta_agent_t const *sa,
+ char const *method_name,
+ url_t const *request_uri,
+ sip_call_id_t const *i,
+ char const *from_tag,
+ url_t const *from_uri,
+ char const *to_tag,
+ url_t const *to_uri);
+static nta_leg_t *dst_find(nta_agent_t const *sa, url_t const *u0,
+ char const *method);
+static void leg_recv(nta_leg_t *, msg_t *, sip_t *, tport_t *);
+static void leg_free(nta_agent_t *sa, nta_leg_t *leg);
+
+#define NTA_HASH(i, cs) ((i)->i_hash + 26839U * (uint32_t)(cs))
+
+HTABLE_PROTOS_WITH(incoming_htable, iht, nta_incoming_t, size_t, hash_value_t);
+static nta_incoming_t *incoming_create(nta_agent_t *agent,
+ msg_t *request,
+ sip_t *sip,
+ tport_t *tport,
+ char const *tag);
+static int incoming_callback(nta_leg_t *leg, nta_incoming_t *irq, sip_t *sip);
+static void incoming_free(nta_incoming_t *irq);
+static inline void incoming_cut_off(nta_incoming_t *irq);
+static inline void incoming_reclaim(nta_incoming_t *irq);
+static void incoming_queue_init(incoming_queue_t *,
+ unsigned timeout);
+static void incoming_queue_adjust(nta_agent_t *sa,
+ incoming_queue_t *queue,
+ unsigned timeout);
+
+static inline
+nta_incoming_t *incoming_find(nta_agent_t const *agent, sip_t const *sip,
+ sip_via_t const *v,
+ nta_incoming_t **merge,
+ nta_incoming_t **ack);
+static int incoming_reply(nta_incoming_t *irq, msg_t *msg, sip_t *sip);
+static inline int incoming_recv(nta_incoming_t *irq, msg_t *msg, sip_t *sip,
+ tport_t *tport);
+static inline int incoming_ack(nta_incoming_t *irq, msg_t *msg, sip_t *sip,
+ tport_t *tport);
+static inline int incoming_cancel(nta_incoming_t *irq, msg_t *msg, sip_t *sip,
+ tport_t *tport);
+static inline int incoming_merge(nta_incoming_t *irq, msg_t *msg, sip_t *sip,
+ tport_t *tport);
+static inline int incoming_timestamp(nta_incoming_t *, msg_t *, sip_t *);
+static inline int incoming_timer(nta_agent_t *, su_duration_t);
+
+static nta_reliable_t *reliable_mreply(nta_incoming_t *,
+ nta_prack_f *, nta_reliable_magic_t *,
+ msg_t *, sip_t *);
+static int reliable_send(nta_incoming_t *, nta_reliable_t *, msg_t *, sip_t *);
+static int reliable_final(nta_incoming_t *irq, msg_t *msg, sip_t *sip);
+static msg_t *reliable_response(nta_incoming_t *irq);
+static int reliable_recv(nta_incoming_t *, msg_t *, sip_t *, tport_t *);
+static void reliable_flush(nta_incoming_t *irq);
+static void reliable_timeout(nta_incoming_t *irq, int timeout);
+
+HTABLE_PROTOS_WITH(outgoing_htable, oht, nta_outgoing_t, size_t, hash_value_t);
+static nta_outgoing_t *outgoing_create(nta_agent_t *agent,
+ nta_response_f *callback,
+ nta_outgoing_magic_t *magic,
+ url_string_t const *route_url,
+ tp_name_t const *tpn,
+ msg_t *msg,
+ tag_type_t tag, tag_value_t value, ...);
+static void outgoing_queue_init(outgoing_queue_t *,
+ unsigned timeout);
+static void outgoing_queue_adjust(nta_agent_t *sa,
+ outgoing_queue_t *queue,
+ unsigned timeout);
+static void outgoing_free(nta_outgoing_t *orq);
+static inline void outgoing_cut_off(nta_outgoing_t *orq);
+static inline void outgoing_reclaim(nta_outgoing_t *orq);
+static nta_outgoing_t *outgoing_find(nta_agent_t const *sa,
+ msg_t const *msg,
+ sip_t const *sip,
+ sip_via_t const *v);
+static int outgoing_recv(nta_outgoing_t *orq, int status, msg_t *, sip_t *);
+static void outgoing_default_recv(nta_outgoing_t *, int, msg_t *, sip_t *);
+static inline int outgoing_timer(nta_agent_t *, su_duration_t);
+static int outgoing_recv_reliable(nta_outgoing_t *orq, msg_t *msg, sip_t *sip);
+
+/* Internal message passing */
+union sm_arg_u {
+ struct leg_recv_s {
+ nta_leg_t *leg;
+ msg_t *msg;
+ tport_t *tport;
+ } a_leg_recv[1];
+
+ struct outgoing_recv_s {
+ nta_outgoing_t *orq;
+ msg_t *msg;
+ sip_t *sip;
+ int status;
+ } a_outgoing_recv[1];
+
+ incoming_queue_t a_incoming_queue[1];
+ outgoing_queue_t a_outgoing_queue[1];
+};
+
+/* Global module data */
+
+/**@var char const NTA_DEBUG[];
+ *
+ * Environment variable determining the default debug log level.
+ *
+ * The NTA_DEBUG environment variable is used to determine the default
+ * debug logging level. The normal level is 3.
+ *
+ * @sa <su_debug.h>, #su_log_global, #SOFIA_DEBUG
+ */
+extern char const NTA_DEBUG[];
+
+#ifndef SU_DEBUG
+#define SU_DEBUG 3
+#endif
+
+/**Debug log for @b nta module.
+ *
+ * The nta_log is the log object used by @b nta module. The level of
+ * nta_log is set using #NTA_DEBUG environment variable.
+ */
+su_log_t nta_log[] = { SU_LOG_INIT("nta", "NTA_DEBUG", SU_DEBUG) };
+
+/* ====================================================================== */
+/* 1) Agent */
+
+/**
+ * Create an NTA agent object.
+ *
+ * The function nta_agent_create() creates an NTA agent object. The agent
+ * object creates and binds a server socket with address specified in @e url.
+ * If the @e host portion of the @e url is @c "*", the agent listens to all
+ * addresses available on the host.
+ *
+ * When a message is received, the agent object parses it. If the result is
+ * a valid SIP message, the agent object passes the message to the
+ * application by invoking the nta_message_f @e callback function.
+ *
+ * @note
+ * The @e url can be either parsed url (of type url_t ()), or a valid
+ * SIP URL as a string.
+ *
+ * @note
+ * If @e url is @c NULL, the default @e url @c "sip:*" is used.
+ * @par
+ * If @p transport parameters are specified in @a url, agent uses only
+ * specified transport type.
+ *
+ * @par
+ * If an @p maddr parameter is specified in @e url, agent binds to the
+ * specified address, but uses @e host part of @e url when it generates
+ * @Contact and @Via headers. The @p maddr parameter is also included,
+ * unless it equals to @c INADDR_ANY (@p 0.0.0.0 or @p [::]).
+ *
+ * @param root pointer to a su_root_t used for synchronization
+ * @param contact_url URL that agent uses to bind the server sockets
+ * @param callback pointer to callback function
+ * @param magic pointer to user data
+ * @param tag,value,... other arguments
+ *
+ * @note It is possible to provide -1 as @a contact_url.
+ *
+ * @retval handle to the agent when successful,
+ * @retval NULL upon an error.
+ *
+ */
+nta_agent_t *nta_agent_create(su_root_t *root,
+ url_string_t const *contact_url,
+ nta_message_f *callback,
+ nta_agent_magic_t *magic,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ nta_agent_t *agent;
+ ta_list ta;
+
+ if (root == NULL)
+ return su_seterrno(EINVAL), NULL;
+
+ ta_start(ta, tag, value);
+
+ if ((agent = su_home_new(sizeof(*agent)))) {
+ agent->sa_root = root;
+ agent->sa_callback = callback;
+ agent->sa_magic = magic;
+ agent->sa_flags = MSG_DO_CANONIC;
+
+ agent->sa_maxsize = 2 * 1024 * 1024; /* 2 MB */
+ agent->sa_bad_req_mask = ~(sip_mask_response | sip_mask_proxy);
+ agent->sa_bad_resp_mask = ~(sip_mask_request | sip_mask_proxy);
+ agent->sa_t1 = NTA_SIP_T1;
+ agent->sa_t2 = NTA_SIP_T2;
+ agent->sa_t4 = NTA_SIP_T4;
+ agent->sa_t1x64 = 64 * NTA_SIP_T1;
+ agent->sa_drop_prob = 0;
+ agent->sa_is_a_uas = 0;
+ agent->sa_progress = 60 * 1000;
+ agent->sa_user_via = 0;
+ agent->sa_extra_100 = 0;
+ agent->sa_pass_100 = 0;
+ agent->sa_timeout_408 = 1;
+ agent->sa_pass_408 = 0;
+ agent->sa_merge_482 = 0;
+ agent->sa_cancel_2543 = 0;
+ agent->sa_cancel_487 = 1;
+ agent->sa_invite_100rel = 0;
+ agent->sa_timestamp = 0;
+ agent->sa_use_naptr = 1;
+ agent->sa_use_srv = 1;
+ agent->sa_auto_comp = 0;
+ agent->sa_server_rport = 1;
+
+ /* RFC 3261 section 8.1.1.6 */
+ sip_max_forwards_init(agent->sa_max_forwards);
+
+ if (getenv("SIPCOMPACT"))
+ agent->sa_flags |= MSG_DO_COMPACT;
+
+ agent_set_params(agent, ta_args(ta));
+
+ if (agent->sa_mclass == NULL)
+ agent->sa_mclass = sip_default_mclass();
+
+ agent->sa_in.re_t1 = &agent->sa_in.re_list;
+
+ incoming_queue_init(agent->sa_in.proceeding, 0);
+ incoming_queue_init(agent->sa_in.preliminary, agent->sa_t1x64); /* P1 */
+ incoming_queue_init(agent->sa_in.inv_completed, agent->sa_t1x64); /* H */
+ incoming_queue_init(agent->sa_in.inv_confirmed, agent->sa_t4); /* I */
+ incoming_queue_init(agent->sa_in.completed, agent->sa_t1x64); /* J */
+ incoming_queue_init(agent->sa_in.terminated, 0);
+ incoming_queue_init(agent->sa_in.final_failed, 0);
+
+ agent->sa_out.re_t1 = &agent->sa_out.re_list;
+
+ outgoing_queue_init(agent->sa_out.delayed, 0);
+ outgoing_queue_init(agent->sa_out.resolving, 0);
+ outgoing_queue_init(agent->sa_out.trying, agent->sa_t1x64); /* F */
+ outgoing_queue_init(agent->sa_out.completed, agent->sa_t4); /* K */
+ outgoing_queue_init(agent->sa_out.terminated, 0);
+ /* Special queues (states) for outgoing INVITE transactions */
+ outgoing_queue_init(agent->sa_out.inv_calling, agent->sa_t1x64); /* B */
+ outgoing_queue_init(agent->sa_out.inv_proceeding, 0);
+ outgoing_queue_init(agent->sa_out.inv_completed, 32000); /* Timer D */
+
+ if (leg_htable_resize(agent->sa_home, agent->sa_dialogs, 0) < 0 ||
+ leg_htable_resize(agent->sa_home, agent->sa_defaults, 0) < 0 ||
+ outgoing_htable_resize(agent->sa_home, agent->sa_outgoing, 0) < 0 ||
+ incoming_htable_resize(agent->sa_home, agent->sa_incoming, 0) < 0) {
+ SU_DEBUG_0(("nta_agent_create: failure with %s\n", "hash tables"));
+ goto deinit;
+ }
+ SU_DEBUG_9(("nta_agent_create: initialized %s\n", "hash tables"));
+
+ if (contact_url != (url_string_t *)-1 &&
+ nta_agent_add_tport(agent, contact_url, ta_tags(ta)) < 0) {
+ SU_DEBUG_7(("nta_agent_create: failure with %s\n", "transport"));
+ goto deinit;
+ }
+ SU_DEBUG_9(("nta_agent_create: initialized %s\n", "transports"));
+
+ if (agent_tag_init(agent) < 0) {
+ SU_DEBUG_3(("nta_agent_create: failure with %s\n", "random identifiers"));
+ goto deinit;
+ }
+ SU_DEBUG_9(("nta_agent_create: initialized %s\n", "random identifiers"));
+
+ if (agent_timer_init(agent) < 0) {
+ SU_DEBUG_0(("nta_agent_create: failure with %s\n", "timer"));
+ goto deinit;
+ }
+ SU_DEBUG_9(("nta_agent_create: initialized %s\n", "timer"));
+
+ if (agent_launch_terminator(agent) == 0)
+ SU_DEBUG_9(("nta_agent_create: initialized %s\n", "threads"));
+
+#if HAVE_SOFIA_SRESOLV
+ agent->sa_resolver = sres_resolver_create(root, NULL, ta_tags(ta));
+ if (!agent->sa_resolver) {
+ SU_DEBUG_0(("nta_agent_create: failure with %s\n", "resolver"));
+ }
+ SU_DEBUG_9(("nta_agent_create: initialized %s\n", "resolver"));
+#endif
+
+ ta_end(ta);
+
+ return agent;
+
+ deinit:
+ nta_agent_destroy(agent);
+ }
+
+ ta_end(ta);
+
+ return NULL;
+}
+
+/**
+ * Destroy an NTA agent object.
+ *
+ * @param agent the NTA agent object to be destroyed.
+ *
+ */
+void nta_agent_destroy(nta_agent_t *agent)
+{
+ if (agent) {
+ size_t i;
+ outgoing_htable_t *oht = agent->sa_outgoing;
+ incoming_htable_t *iht = agent->sa_incoming;
+ /* Currently, this is pretty pointless, as legs don't keep any resources */
+ leg_htable_t *lht;
+ nta_leg_t *leg;
+
+ for (i = 0, lht = agent->sa_dialogs; i < lht->lht_size; i++) {
+ if ((leg = lht->lht_table[i])) {
+ SU_DEBUG_3(("nta_agent_destroy: destroying dialog with <"
+ URL_PRINT_FORMAT ">\n",
+ URL_PRINT_ARGS(leg->leg_remote->a_url)));
+ leg_free(agent, leg);
+ }
+ }
+
+ for (i = 0, lht = agent->sa_defaults; i < lht->lht_size; i++) {
+ if ((leg = lht->lht_table[i])) {
+ SU_DEBUG_3(("%s: destroying leg for <"
+ URL_PRINT_FORMAT ">\n",
+ __func__, URL_PRINT_ARGS(leg->leg_url)));
+ leg_free(agent, leg);
+ }
+ }
+
+ if (agent->sa_default_leg)
+ leg_free(agent, agent->sa_default_leg);
+
+ for (i = iht->iht_size; i-- > 0; )
+ while (iht->iht_table[i]) {
+ nta_incoming_t *irq = iht->iht_table[i];
+
+ if (!irq->irq_destroyed)
+ SU_DEBUG_3(("%s: destroying %s server transaction from <"
+ URL_PRINT_FORMAT ">\n",
+ __func__, irq->irq_rq->rq_method_name,
+ URL_PRINT_ARGS(irq->irq_from->a_url)));
+
+ incoming_free(irq);
+ }
+
+ for (i = oht->oht_size; i-- > 0;)
+ while (oht->oht_table[i]) {
+ nta_outgoing_t *orq = oht->oht_table[i];
+
+ if (!orq->orq_destroyed)
+ SU_DEBUG_3(("%s: destroying %s client transaction to <"
+ URL_PRINT_FORMAT ">\n",
+ __func__, orq->orq_method_name,
+ URL_PRINT_ARGS(orq->orq_to->a_url)));
+
+ outgoing_free(orq);
+ }
+
+ su_timer_destroy(agent->sa_timer), agent->sa_timer = NULL;
+
+# if HAVE_SOFIA_SRESOLV
+ sres_resolver_destroy(agent->sa_resolver), agent->sa_resolver = NULL;
+# endif
+
+ tport_destroy(agent->sa_tports), agent->sa_tports = NULL;
+
+ agent_kill_terminator(agent);
+
+ su_home_unref(agent->sa_home);
+ }
+}
+
+/** Return agent context. */
+nta_agent_magic_t *nta_agent_magic(nta_agent_t const *agent)
+{
+ return agent ? agent->sa_magic : NULL;
+}
+
+/** Return @Contact header.
+ *
+ * The function nta_agent_contact() returns a @Contact header, which can be
+ * used to reach @a agent.
+ *
+ * @param agent NTA agent object
+ *
+ * @return The function nta_agent_contact() returns a sip_contact_t object
+ * corresponding to the @a agent.
+ *
+ * User agents can insert the @Contact header in the outgoing REGISTER,
+ * INVITE, and ACK requests and replies to incoming INVITE and OPTIONS
+ * transactions.
+ *
+ * Proxies can use the @Contact header to create appropriate @RecordRoute
+ * headers:
+ * @code
+ * r_r = sip_record_route_create(msg_home(msg),
+ * sip->sip_request->rq_url,
+ * contact->m_url);
+ * @endcode
+ */
+sip_contact_t *nta_agent_contact(nta_agent_t const *agent)
+{
+ return agent ? agent->sa_contact : NULL;
+}
+
+/** Return a list of @Via headers.
+ *
+ * The function nta_agent_via() returns @Via headers for all activated
+ * transport.
+ *
+ * @param agent NTA agent object
+ *
+ * @return The function nta_agent_via() returns a list of sip_via_t objects
+ * used by the @a agent.
+ */
+sip_via_t *nta_agent_via(nta_agent_t const *agent)
+{
+ return agent ? agent->sa_vias : NULL;
+}
+
+
+/** Return a list of public (UPnP, STUN) @Via headers.
+ *
+ * The function nta_agent_public_via() returns public @Via headers for all activated
+ * transports.
+ *
+ * @param agent NTA agent object
+ *
+ * @return The function nta_agent_public_via() returns a list of sip_via_t objects
+ * used by the @a agent.
+ */
+sip_via_t *nta_agent_public_via(nta_agent_t const *agent)
+{
+ return agent ? agent->sa_public_vias : NULL;
+}
+
+/** Return @UserAgent header.
+ *
+ * The function nta_agent_name() returns a @UserAgent information with
+ * NTA version.
+ *
+ * @param agent NTA agent object (may be NULL)
+ *
+ * @return The function nta_agent_contact() returns a string containing the
+ * @a agent version.
+ */
+char const *nta_agent_version(nta_agent_t const *agent)
+{
+ return "nta" "/" VERSION;
+}
+
+/** Initialize default tag */
+static int agent_tag_init(nta_agent_t *self)
+{
+ sip_contact_t *m = self->sa_contact;
+ uint32_t hash = 1;
+
+ if (m) {
+
+ if (m->m_url->url_user)
+ hash = 914715421U * hash + msg_hash_string(m->m_url->url_user);
+ if (m->m_url->url_host)
+ hash = 914715421U * hash + msg_hash_string(m->m_url->url_host);
+ if (m->m_url->url_port)
+ hash = 914715421U * hash + msg_hash_string(m->m_url->url_port);
+ if (m->m_url->url_params)
+ hash = 914715421U * hash + msg_hash_string(m->m_url->url_params);
+ }
+
+ if (hash == 0)
+ hash = 914715421U;
+
+ self->sa_branch = NTA_BRANCH_PRIME * su_ntp_now();
+ self->sa_branch *= hash;
+
+ self->sa_tags = NTA_TAG_PRIME * self->sa_branch;
+
+ return 0;
+}
+
+/** Initialize agent timer. */
+static
+int agent_timer_init(nta_agent_t *agent)
+{
+ return su_timer_set(agent->sa_timer =
+ su_timer_create(su_root_task(agent->sa_root),
+ NTA_SIP_T1 / 8),
+ agent_timer,
+ agent);
+}
+
+/**
+ * Agent timer routine.
+ */
+static
+void agent_timer(su_root_magic_t *rm, su_timer_t *timer, nta_agent_t *agent)
+{
+ su_duration_t now = su_time_ms(agent->sa_now = su_now());
+ int again;
+
+ now += now == 0;
+
+ agent->sa_millisec = now;
+
+ again = outgoing_timer(agent, now);
+ again = incoming_timer(agent, now) || again;
+
+ agent->sa_millisec = 0;
+
+ if (again)
+ su_timer_set_at(timer, agent_timer, agent, su_time_add(su_now(), 1));
+ else
+ su_timer_set(timer, agent_timer, agent);
+}
+
+/** Calculate nonzero value for timer */
+static inline
+su_duration_t set_timeout(nta_agent_t const *agent, su_duration_t offset)
+{
+ su_duration_t now;
+
+#if 0
+ if (agent->sa_millisec)
+ now = agent->sa_millisec;
+ else
+#endif
+ now = (su_duration_t)su_time_ms(su_now());
+
+ now += offset;
+
+ return now ? now : 1;
+}
+
+
+/** Return current timeval. */
+static
+su_time_t agent_now(nta_agent_t const *agent)
+{
+ return agent->sa_millisec ? agent->sa_now : su_now();
+}
+
+
+/** Launch transaction terminator task */
+static
+int agent_launch_terminator(nta_agent_t *agent)
+{
+#ifdef TPTAG_THRPSIZE
+ if (agent->sa_tport_threadpool) {
+ su_home_threadsafe(agent->sa_home);
+ return su_clone_start(agent->sa_root,
+ agent->sa_terminator,
+ NULL,
+ NULL,
+ NULL);
+ }
+#endif
+ return -1;
+}
+
+/** Kill transaction terminator task */
+static
+void agent_kill_terminator(nta_agent_t *agent)
+{
+ su_clone_wait(agent->sa_root, agent->sa_terminator);
+}
+
+
+/**Set NTA Parameters.
+ *
+ * The nta_agent_set_params() function sets the stack parameters. The
+ * parameters determine the way NTA handles the retransmissions, how long
+ * NTA keeps transactions alive, does NTA apply proxy or user-agent logic to
+ * INVITE transactions, or how the @Via headers are generated.
+ *
+ * @note
+ * Setting the parameters NTATAG_MAXSIZE(), NTATAG_UDP_MTU(),
+ * NTATAG_SIP_T1X64(), NTATAG_SIP_T1(), NTATAG_SIP_T2(), NTATAG_SIP_T4() to
+ * 0 selects the default value.
+ *
+ * @TAGS
+ * NTATAG_ALIASES(), NTATAG_BAD_REQ_MASK(), NTATAG_BAD_RESP_MASK(),
+ * NTATAG_CANCEL_2543(), NTATAG_CANCEL_487(), NTATAG_DEBUG_DROP_PROB(),
+ * NTATAG_DEFAULT_PROXY(), NTATAG_EXTRA_100(), NTATAG_MAXSIZE(),
+ * NTATAG_MAX_FORWARDS(),
+ * NTATAG_UDP_MTU(), NTATAG_MERGE_482(), NTATAG_PASS_100(),
+ * NTATAG_PRELOAD(), NTATAG_REL100(), NTATAG_RPORT(), NTATAG_SERVER_RPORT(),
+ * NTATAG_TCP_RPORT(),
+ * NTATAG_SIPFLAGS(), NTATAG_SIP_T1X64(), NTATAG_SIP_T1(), NTATAG_SIP_T2(),
+ * NTATAG_SIP_T4(), NTATAG_SMIME(), NTATAG_STATELESS(), NTATAG_TAG_3261(),
+ * NTATAG_TIMEOUT_408(), NTATAG_PASS_408(), NTATAG_UA(), NTATAG_USER_VIA(),
+ * and NTATAG_USE_TIMESTAMP().
+ */
+int nta_agent_set_params(nta_agent_t *agent,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ int retval;
+
+ if (agent) {
+ ta_list ta;
+ ta_start(ta, tag, value);
+ retval = agent_set_params(agent, ta_args(ta));
+ ta_end(ta);
+ } else {
+ su_seterrno(EINVAL);
+ retval = -1;
+ }
+
+ return retval;
+}
+
+/** Internal function for setting tags */
+static
+int agent_set_params(nta_agent_t *agent, tagi_t *tags)
+{
+ int n, m;
+ unsigned bad_req_mask = agent->sa_bad_req_mask;
+ unsigned bad_resp_mask = agent->sa_bad_resp_mask;
+ usize_t maxsize = agent->sa_maxsize;
+ unsigned max_forwards = agent->sa_max_forwards->mf_count;
+ usize_t udp_mtu = agent->sa_udp_mtu;
+ unsigned sip_t1 = agent->sa_t1;
+ unsigned sip_t2 = agent->sa_t2;
+ unsigned sip_t4 = agent->sa_t4;
+ unsigned sip_t1x64 = agent->sa_t1x64;
+ unsigned blacklist = agent->sa_blacklist;
+ int ua = agent->sa_is_a_uas;
+ unsigned progress = agent->sa_progress;
+ int stateless = agent->sa_is_stateless;
+ unsigned drop_prob = agent->sa_drop_prob;
+ int user_via = agent->sa_user_via;
+ int extra_100 = agent->sa_extra_100;
+ int pass_100 = agent->sa_pass_100;
+ int timeout_408 = agent->sa_timeout_408;
+ int pass_408 = agent->sa_pass_408;
+ int merge_482 = agent->sa_merge_482;
+ int cancel_2543 = agent->sa_cancel_2543;
+ int cancel_487 = agent->sa_cancel_487;
+ int invite_100rel = agent->sa_invite_100rel;
+ int use_timestamp = agent->sa_timestamp;
+ int use_naptr = agent->sa_use_naptr;
+ int use_srv = agent->sa_use_srv;
+ void *smime = agent->sa_smime;
+ uint32_t flags = agent->sa_flags;
+ int rport = agent->sa_rport;
+ int server_rport = agent->sa_server_rport;
+ int tcp_rport = agent->sa_tcp_rport;
+ unsigned preload = agent->sa_preload;
+ unsigned threadpool = agent->sa_tport_threadpool;
+ char const *sigcomp = agent->sa_sigcomp_options;
+ char const *algorithm = NONE;
+ msg_mclass_t *mclass = NONE;
+ sip_contact_t const *aliases = NONE;
+ url_string_t const *proxy = NONE;
+ tport_t *tport;
+
+ su_home_t *home = agent->sa_home;
+
+ n = tl_gets(tags,
+ NTATAG_MCLASS_REF(mclass),
+ NTATAG_BAD_REQ_MASK_REF(bad_req_mask),
+ NTATAG_BAD_RESP_MASK_REF(bad_resp_mask),
+ NTATAG_ALIASES_REF(aliases),
+ NTATAG_UA_REF(ua),
+ NTATAG_STATELESS_REF(stateless),
+ NTATAG_MAXSIZE_REF(maxsize),
+ NTATAG_MAX_FORWARDS_REF(max_forwards),
+ NTATAG_UDP_MTU_REF(udp_mtu),
+ NTATAG_SIP_T1_REF(sip_t1),
+ NTATAG_SIP_T2_REF(sip_t2),
+ NTATAG_SIP_T4_REF(sip_t4),
+ NTATAG_SIP_T1X64_REF(sip_t1x64),
+ NTATAG_PROGRESS_REF(progress),
+ NTATAG_BLACKLIST_REF(blacklist),
+ NTATAG_DEBUG_DROP_PROB_REF(drop_prob),
+ NTATAG_USER_VIA_REF(user_via),
+ NTATAG_EXTRA_100_REF(extra_100),
+ NTATAG_PASS_100_REF(pass_100),
+ NTATAG_TIMEOUT_408_REF(timeout_408),
+ NTATAG_PASS_408_REF(pass_408),
+ NTATAG_MERGE_482_REF(merge_482),
+ NTATAG_DEFAULT_PROXY_REF(proxy),
+ NTATAG_CANCEL_2543_REF(cancel_2543),
+ NTATAG_CANCEL_487_REF(cancel_487),
+ NTATAG_REL100_REF(invite_100rel),
+ NTATAG_USE_TIMESTAMP_REF(use_timestamp),
+ NTATAG_USE_NAPTR_REF(use_naptr),
+ NTATAG_USE_SRV_REF(use_srv),
+#if HAVE_SOFIA_SMIME
+ NTATAG_SMIME_REF(smime),
+#endif
+ NTATAG_SIPFLAGS_REF(flags),
+ NTATAG_RPORT_REF(rport),
+ NTATAG_SERVER_RPORT_REF(server_rport),
+ NTATAG_TCP_RPORT_REF(tcp_rport),
+ NTATAG_PRELOAD_REF(preload),
+#ifdef TPTAG_THRPSIZE
+ /* If threadpool is enabled, start a separate "reaper thread" */
+ TPTAG_THRPSIZE_REF(threadpool),
+#endif
+ NTATAG_SIGCOMP_OPTIONS_REF(sigcomp),
+ NTATAG_SIGCOMP_ALGORITHM_REF(algorithm),
+ TAG_END());
+
+ if (mclass != NONE)
+ agent->sa_mclass = mclass ? mclass : sip_default_mclass();
+
+ m = 0;
+ for (tport = agent->sa_tports; tport; tport = tport_next(tport)) {
+ m = tport_set_params(tport, TAG_NEXT(tags));
+ }
+
+ if (n == 0 || m == -1)
+ return m;
+
+ n += m;
+
+ if (aliases != NONE) {
+ sip_contact_t const *m, *m_next;
+
+ m = agent->sa_aliases;
+ agent->sa_aliases = sip_contact_dup(home, aliases);
+
+ for (; m; m = m_next) { /* Free old aliases */
+ m_next = m->m_next;
+ su_free(home, (void *)m);
+ }
+ }
+
+ if (proxy != NONE) {
+ url_t *dp = url_hdup(home, proxy->us_url);
+
+ url_sanitize(dp);
+
+ if (dp == NULL || dp->url_type == url_sip || dp->url_type == url_sips) {
+ if (agent->sa_default_proxy)
+ su_free(home, agent->sa_default_proxy);
+ agent->sa_default_proxy = dp;
+ }
+ else
+ n = -1;
+ }
+
+ if (algorithm != NONE)
+ agent->sa_algorithm = su_strdup(home, algorithm);
+
+ if (str0cmp(sigcomp, agent->sa_sigcomp_options)) {
+ char const * const *l = NULL;
+ char *s = su_strdup(home, sigcomp);
+ char *s1 = su_strdup(home, s), *s2 = s1;
+
+ if (s && s2 && msg_avlist_d(home, &s2, &l) == 0 && *s2 == '\0') {
+ su_free(home, (void *)agent->sa_sigcomp_options);
+ su_free(home, (void *)agent->sa_sigcomp_option_list);
+ agent->sa_sigcomp_options = s;
+ agent->sa_sigcomp_option_free = s1;
+ agent->sa_sigcomp_option_list = l;
+ } else {
+ su_free(home, s);
+ su_free(home, s1);
+ su_free(home, (void *)l);
+ n = -1;
+ }
+ }
+
+ if (maxsize == 0) maxsize = 2 * 1024 * 1024;
+ if (maxsize > NTA_TIME_MAX) maxsize = NTA_TIME_MAX;
+ agent->sa_maxsize = maxsize;
+
+ if (max_forwards == 0) max_forwards = 70; /* Default value */
+ agent->sa_max_forwards->mf_count = max_forwards;
+
+ if (udp_mtu == 0) udp_mtu = 1300;
+ if (udp_mtu > 65535) udp_mtu = 65535;
+ if (agent->sa_udp_mtu != udp_mtu) {
+ agent->sa_udp_mtu = udp_mtu;
+ agent_set_udp_params(agent, udp_mtu);
+ }
+
+ if (sip_t1 == 0) sip_t1 = NTA_SIP_T1;
+ if (sip_t1 > NTA_TIME_MAX) sip_t1 = NTA_TIME_MAX;
+ agent->sa_t1 = sip_t1;
+
+ if (sip_t2 == 0) sip_t2 = NTA_SIP_T2;
+ if (sip_t2 > NTA_TIME_MAX) sip_t2 = NTA_TIME_MAX;
+ agent->sa_t2 = sip_t2;
+
+ if (sip_t4 == 0) sip_t4 = NTA_SIP_T4;
+ if (sip_t4 > NTA_TIME_MAX) sip_t4 = NTA_TIME_MAX;
+ if (agent->sa_t4 != sip_t4) {
+ incoming_queue_adjust(agent, agent->sa_in.inv_confirmed, sip_t4);
+ outgoing_queue_adjust(agent, agent->sa_out.completed, sip_t4);
+ }
+ agent->sa_t4 = sip_t4;
+
+ if (sip_t1x64 == 0) sip_t1x64 = NTA_SIP_T1 * 64;
+ if (sip_t1x64 > NTA_TIME_MAX) sip_t1x64 = NTA_TIME_MAX;
+ if (agent->sa_t1x64 != sip_t1x64) {
+ incoming_queue_adjust(agent, agent->sa_in.preliminary, sip_t1x64);
+ incoming_queue_adjust(agent, agent->sa_in.completed, sip_t1x64);
+ incoming_queue_adjust(agent, agent->sa_in.inv_completed, sip_t1x64);
+ outgoing_queue_adjust(agent, agent->sa_out.trying, sip_t1x64);
+ outgoing_queue_adjust(agent, agent->sa_out.inv_calling, sip_t1x64);
+ }
+ agent->sa_t1x64 = sip_t1x64;
+ agent->sa_blacklist = blacklist;
+
+ if (progress == 0)
+ progress = 60 * 1000;
+ agent->sa_progress = progress;
+
+ agent->sa_bad_req_mask = bad_req_mask;
+ agent->sa_bad_resp_mask = bad_resp_mask;
+
+ agent->sa_is_a_uas = ua != 0;
+ agent->sa_is_stateless = stateless != 0;
+ agent->sa_drop_prob = drop_prob < 1000 ? drop_prob : 1000;
+ agent->sa_user_via = user_via != 0;
+ agent->sa_extra_100 = extra_100 != 0;
+ agent->sa_pass_100 = pass_100 != 0;
+ agent->sa_timeout_408 = timeout_408 != 0;
+ agent->sa_pass_408 = pass_408 != 0;
+ agent->sa_merge_482 = merge_482 != 0;
+ agent->sa_cancel_2543 = cancel_2543 != 0;
+ agent->sa_cancel_487 = cancel_487 != 0;
+ agent->sa_invite_100rel = invite_100rel != 0;
+ agent->sa_timestamp = use_timestamp != 0;
+ agent->sa_use_naptr = use_naptr != 0;
+ agent->sa_use_srv = use_srv != 0;
+ agent->sa_smime = smime;
+ agent->sa_flags = flags & MSG_FLG_USERMASK;
+ agent->sa_rport = rport != 0;
+ agent->sa_server_rport = server_rport != 0;
+ agent->sa_tcp_rport = tcp_rport != 0;
+ agent->sa_preload = preload;
+ agent->sa_tport_threadpool = threadpool;
+
+ return n;
+}
+
+static
+void agent_set_udp_params(nta_agent_t *self, usize_t udp_mtu)
+{
+ tport_t *tp;
+
+ /* Set via fields for the tports */
+ for (tp = tport_primaries(self->sa_tports); tp; tp = tport_next(tp)) {
+ if (tport_is_udp(tp))
+ tport_set_params(tp,
+ TPTAG_TIMEOUT(2 * self->sa_t1x64),
+ TPTAG_MTU(udp_mtu),
+ TAG_END());
+ }
+}
+
+/**Get NTA Parameters.
+ *
+ * The nta_agent_get_params() function retrieves the stack parameters. The
+ * parameters determine the way NTA handles the retransmissions, how long
+ * NTA keeps transactions alive, does NTA apply proxy or user-agent logic to
+ * INVITE transactions, or how the @Via headers are generated.
+ *
+ * @TAGS
+ * NTATAG_ALIASES_REF(), NTATAG_CANCEL_2543_REF(), NTATAG_CANCEL_487_REF(),
+ * NTATAG_CONTACT_REF(), NTATAG_DEBUG_DROP_PROB_REF(),
+ * NTATAG_DEFAULT_PROXY_REF(), NTATAG_EXTRA_100_REF(), NTATAG_MAXSIZE_REF(),
+ * NTATAG_MAX_FORWARDS_REF(),
+ * NTATAG_MERGE_482_REF(), NTATAG_PASS_100_REF(), NTATAG_PRELOAD_REF(),
+ * NTATAG_REL100_REF(), NTATAG_RPORT_REF(), NTATAG_SIPFLAGS_REF(),
+ * NTATAG_SIP_T1X64_REF(), NTATAG_SIP_T1_REF(), NTATAG_SIP_T2_REF(),
+ * NTATAG_SIP_T4_REF(), NTATAG_SMIME_REF(), NTATAG_STATELESS_REF(),
+ * NTATAG_TAG_3261_REF(), NTATAG_TIMEOUT_408_REF(), NTATAG_PASS_408_REF(),
+ * NTATAG_UA_REF(), NTATAG_USER_VIA_REF(), and NTATAG_USE_TIMESTAMP_REF().
+ *
+ */
+int nta_agent_get_params(nta_agent_t *agent,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ int n;
+ ta_list ta;
+
+ if (agent) {
+ ta_start(ta, tag, value);
+ n = agent_get_params(agent, ta_args(ta));
+ ta_end(ta);
+ } else {
+ su_seterrno(EINVAL);
+ n = -1;
+ }
+
+ return n;
+}
+
+/** Get NTA parameters */
+static
+int agent_get_params(nta_agent_t *agent, tagi_t *tags)
+{
+ return
+ tl_tgets(tags,
+ NTATAG_MCLASS(agent->sa_mclass),
+ NTATAG_CONTACT(agent->sa_contact),
+ NTATAG_ALIASES(agent->sa_aliases),
+ NTATAG_UA(agent->sa_is_a_uas),
+ NTATAG_STATELESS(agent->sa_is_stateless),
+ NTATAG_MAXSIZE(agent->sa_maxsize),
+ NTATAG_MAX_FORWARDS(agent->sa_max_forwards->mf_count),
+ NTATAG_UDP_MTU(agent->sa_udp_mtu),
+ NTATAG_SIP_T1(agent->sa_t1),
+ NTATAG_SIP_T2(agent->sa_t2),
+ NTATAG_SIP_T4(agent->sa_t4),
+ NTATAG_SIP_T1X64(agent->sa_t1x64),
+ NTATAG_BLACKLIST(agent->sa_blacklist),
+ NTATAG_DEBUG_DROP_PROB(agent->sa_drop_prob),
+ NTATAG_USER_VIA(agent->sa_user_via),
+ NTATAG_EXTRA_100(agent->sa_extra_100),
+ NTATAG_PASS_100(agent->sa_pass_100),
+ NTATAG_TIMEOUT_408(agent->sa_timeout_408),
+ NTATAG_PASS_408(agent->sa_pass_408),
+ NTATAG_MERGE_482(agent->sa_merge_482),
+ NTATAG_DEFAULT_PROXY(agent->sa_default_proxy),
+ NTATAG_CANCEL_2543(agent->sa_cancel_2543),
+ NTATAG_CANCEL_487(agent->sa_cancel_487),
+ NTATAG_TAG_3261(1),
+ NTATAG_REL100(agent->sa_invite_100rel),
+ NTATAG_USE_TIMESTAMP(agent->sa_timestamp),
+ NTATAG_USE_NAPTR(agent->sa_use_naptr),
+ NTATAG_USE_SRV(agent->sa_use_srv),
+#if HAVE_SOFIA_SMIME
+ NTATAG_SMIME(agent->sa_smime),
+#else
+ NTATAG_SMIME(NULL),
+#endif
+ NTATAG_SIPFLAGS(agent->sa_flags),
+ NTATAG_RPORT(agent->sa_rport),
+ NTATAG_PRELOAD(agent->sa_preload),
+ NTATAG_SIGCOMP_ALGORITHM(agent->sa_algorithm),
+ NTATAG_SIGCOMP_OPTIONS(agent->sa_sigcomp_options ?
+ agent->sa_sigcomp_options :
+ "sip"),
+ TAG_END());
+}
+
+/**Get NTA statistics.
+ *
+ * The nta_agent_get_stats() function retrieves the stack statistics.
+ *
+ * @TAGS
+ * @TAG NTATAG_S_*
+ *
+ */
+int nta_agent_get_stats(nta_agent_t *agent,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ int n;
+ ta_list ta;
+
+ if (!agent)
+ return su_seterrno(EINVAL), -1;
+
+ ta_start(ta, tag, value);
+
+ n = tl_tgets(ta_args(ta),
+ NTATAG_S_IRQ_HASH(agent->sa_incoming->iht_size),
+ NTATAG_S_ORQ_HASH(agent->sa_outgoing->oht_size),
+ NTATAG_S_LEG_HASH(agent->sa_dialogs->lht_size),
+ NTATAG_S_IRQ_HASH_USED(agent->sa_incoming->iht_used),
+ NTATAG_S_ORQ_HASH_USED(agent->sa_outgoing->oht_used),
+ NTATAG_S_LEG_HASH_USED(agent->sa_dialogs->lht_used),
+ NTATAG_S_RECV_MSG(agent->sa_stats->as_recv_msg),
+ NTATAG_S_RECV_REQUEST(agent->sa_stats->as_recv_request),
+ NTATAG_S_RECV_RESPONSE(agent->sa_stats->as_recv_response),
+ NTATAG_S_BAD_MESSAGE(agent->sa_stats->as_bad_message),
+ NTATAG_S_BAD_REQUEST(agent->sa_stats->as_bad_request),
+ NTATAG_S_BAD_RESPONSE(agent->sa_stats->as_bad_response),
+ NTATAG_S_DROP_REQUEST(agent->sa_stats->as_drop_request),
+ NTATAG_S_DROP_RESPONSE(agent->sa_stats->as_drop_response),
+ NTATAG_S_CLIENT_TR(agent->sa_stats->as_client_tr),
+ NTATAG_S_SERVER_TR(agent->sa_stats->as_server_tr),
+ NTATAG_S_DIALOG_TR(agent->sa_stats->as_dialog_tr),
+ NTATAG_S_ACKED_TR(agent->sa_stats->as_acked_tr),
+ NTATAG_S_CANCELED_TR(agent->sa_stats->as_canceled_tr),
+ NTATAG_S_TRLESS_REQUEST(agent->sa_stats->as_trless_request),
+ NTATAG_S_TRLESS_TO_TR(agent->sa_stats->as_trless_to_tr),
+ NTATAG_S_TRLESS_RESPONSE(agent->sa_stats->as_trless_response),
+ NTATAG_S_TRLESS_200(agent->sa_stats->as_trless_200),
+ NTATAG_S_MERGED_REQUEST(agent->sa_stats->as_merged_request),
+ NTATAG_S_SENT_MSG(agent->sa_stats->as_sent_msg),
+ NTATAG_S_SENT_REQUEST(agent->sa_stats->as_sent_request),
+ NTATAG_S_SENT_RESPONSE(agent->sa_stats->as_sent_response),
+ NTATAG_S_RETRY_REQUEST(agent->sa_stats->as_retry_request),
+ NTATAG_S_RETRY_RESPONSE(agent->sa_stats->as_retry_response),
+ NTATAG_S_RECV_RETRY(agent->sa_stats->as_recv_retry),
+ NTATAG_S_TOUT_REQUEST(agent->sa_stats->as_tout_request),
+ NTATAG_S_TOUT_RESPONSE(agent->sa_stats->as_tout_response),
+ TAG_END());
+
+ ta_end(ta);
+
+ return n;
+}
+
+/**Calculate a new unique tag.
+ *
+ * This function generates a series of 2**64 unique tags for @From or @To
+ * headers. The start of the tag series is derived from the NTP time the NTA
+ * agent was initialized.
+ *
+ */
+char const *nta_agent_newtag(su_home_t *home, char const *fmt, nta_agent_t *sa)
+{
+ char tag[(8 * 8 + 4)/ 5 + 1];
+
+ if (sa == NULL)
+ return su_seterrno(EINVAL), NULL;
+
+ /* XXX - use a cryptographically safe func here? */
+ sa->sa_tags += NTA_TAG_PRIME;
+
+ msg_random_token(tag, sizeof(tag) - 1, &sa->sa_tags, sizeof(sa->sa_tags));
+
+ if (fmt && fmt[0])
+ return su_sprintf(home, fmt, tag);
+ else
+ return su_strdup(home, tag);
+}
+
+/**
+ * Calculate branch value.
+ */
+static char const *stateful_branch(su_home_t *home, nta_agent_t *sa)
+{
+ char branch[(8 * 8 + 4)/ 5 + 1];
+
+ /* XXX - use a cryptographically safe func here? */
+ sa->sa_branch += NTA_BRANCH_PRIME;
+
+ msg_random_token(branch, sizeof(branch) - 1,
+ &sa->sa_branch, sizeof(sa->sa_branch));
+
+ return su_sprintf(home, "branch=z9hG4bK%s", branch);
+}
+
+#include <sofia-sip/su_md5.h>
+
+/**
+ * Calculate branch value for stateless operation.
+ *
+ * XXX - should include HMAC of previous @Via line.
+ */
+static
+char const *stateless_branch(nta_agent_t *sa,
+ msg_t *msg,
+ sip_t const *sip,
+ tp_name_t const *tpn)
+{
+ su_md5_t md5[1];
+ uint8_t digest[SU_MD5_DIGEST_SIZE];
+ char branch[(SU_MD5_DIGEST_SIZE * 8 + 4)/ 5 + 1];
+ sip_route_t const *r;
+
+ assert(sip->sip_request);
+
+ if (!sip->sip_via)
+ return stateful_branch(msg_home(msg), sa);
+
+ su_md5_init(md5);
+
+ su_md5_str0update(md5, tpn->tpn_host);
+ su_md5_str0update(md5, tpn->tpn_port);
+
+ url_update(md5, sip->sip_request->rq_url);
+ if (sip->sip_call_id) {
+ su_md5_str0update(md5, sip->sip_call_id->i_id);
+ }
+ if (sip->sip_from) {
+ url_update(md5, sip->sip_from->a_url);
+ su_md5_stri0update(md5, sip->sip_from->a_tag);
+ }
+ if (sip->sip_to) {
+ url_update(md5, sip->sip_to->a_url);
+ /* XXX - some broken implementations include To tag in CANCEL */
+ /* su_md5_str0update(md5, sip->sip_to->a_tag); */
+ }
+ if (sip->sip_cseq) {
+ uint32_t cseq = htonl(sip->sip_cseq->cs_seq);
+ su_md5_update(md5, &cseq, sizeof(cseq));
+ }
+
+ for (r = sip->sip_route; r; r = r->r_next)
+ url_update(md5, r->r_url);
+
+ su_md5_digest(md5, digest);
+
+ msg_random_token(branch, sizeof(branch) - 1, digest, sizeof(digest));
+
+ return su_sprintf(msg_home(msg), "branch=z9hG4bK.%s", branch);
+}
+
+/* ====================================================================== */
+/* 2) Transport interface */
+
+/* Local prototypes */
+static int agent_create_master_transport(nta_agent_t *self, tagi_t *tags);
+static int agent_init_via(nta_agent_t *self, tport_t *primaries, int use_maddr);
+static int agent_init_contact(nta_agent_t *self);
+static void agent_recv_message(nta_agent_t *agent,
+ tport_t *tport,
+ msg_t *msg,
+ sip_via_t *tport_via,
+ su_time_t now);
+static void agent_tp_error(nta_agent_t *agent,
+ tport_t *tport,
+ int errcode,
+ char const *remote);
+static void agent_update_tport(nta_agent_t *agent, tport_t *);
+
+/**For each transport, we have name used by tport module, SRV prefixes used
+ * for resolving, and NAPTR service/conversion.
+ */
+static
+struct sipdns_tport {
+ char name[6]; /**< Named used by tport module */
+ char port[6]; /**< Default port number */
+ char prefix[14]; /**< Prefix for SRV domains */
+ char service[10]; /**< NAPTR service */
+}
+#define SIPDNS_TRANSPORTS (4)
+const sipdns_tports[SIPDNS_TRANSPORTS] = {
+ { "udp", "5060", "_sip._udp.", "SIP+D2U" },
+ { "tcp", "5060", "_sip._tcp.", "SIP+D2T" },
+ { "sctp", "5060", "_sip._sctp.", "SIP+D2S" },
+ { "tls", "5061", "_sips._tcp.", "SIPS+D2T" },
+};
+
+static char const * const tports_sip[] =
+ {
+ "udp", "tcp", "sctp", NULL
+ };
+
+static char const * const tports_sips[] =
+ {
+ "tls", NULL
+ };
+
+static tport_stack_class_t nta_agent_class[1] =
+ {{
+ sizeof(nta_agent_class),
+ agent_recv_message,
+ agent_tp_error,
+ nta_msg_create_for_transport,
+ agent_update_tport,
+ }};
+
+
+/** Add a transport to the agent.
+ *
+ * The function nta_agent_add_tport() creates a new transport and binds it
+ * to the port specified by the @a uri. The @a uri must have sip: or sips:
+ * scheme or be a wildcard uri ("*"). The @a uri syntax allowed is as
+ * follows:
+ *
+ * @code url <scheme>:<host>[:<port>]<url-params> @endcode
+ * where <url-params> may be
+ * @code
+ * ;transport=<xxx>
+ * ;maddr=<actual addr>
+ * ;comp=sigcomp
+ * @endcode
+ *
+ * The scheme part determines which transports are used. "sip" implies UDP
+ * and TCP, "sips" TLS over TCP. In the future, more transports can be
+ * supported, for instance, "sip" can use SCTP or DCCP, "sips" DTLS or TLS
+ * over SCTP.
+ *
+ * The "host" part determines what address/domain name is used in @Contact.
+ * An "*" in "host" part is shorthand for any local IP address. 0.0.0.0
+ * means that the only the IPv4 addresses are used. [::] means that only
+ * the IPv6 addresses are used. If a domain name or a specific IP address
+ * is given as "host" part, an additional "maddr" parameter can be used to
+ * control which addresses are used by the stack when binding listen
+ * sockets for incoming requests.
+ *
+ * The "port" determines what port is used in contact, and to which port the
+ * stack binds in order to listen for incoming requests. Empty or missing
+ * port means that default port should be used (5060 for sip, 5061 for
+ * sips). An "*" in "port" part means any port, i.e., the stack binds to an
+ * ephemeral port.
+ *
+ * The "transport" parameter determines the transport protocol that is used
+ * and how they are preferred. If no protocol is specified, both UDP and TCP
+ * are used for SIP URL and TLS for SIPS URL. The preference can be
+ * indicated with a comma-separated list of transports, for instance,
+ * parameter @code transport=tcp,udp @endocde indicates that TCP is
+ * preferred to UDP.
+ *
+ * The "maddr" parameter determines to which address the stack binds in
+ * order to listen for incoming requests. An "*" in "maddr" parameter is
+ * shorthand for any local IP address. 0.0.0.0 means that only IPv4 sockets
+ * are created. [::] means that only IPv6 sockets are created.
+ *
+ * The "comp" parameter determines the supported compression protocol.
+ * Currently only sigcomp is supported (with suitable library.
+ *
+ * @par Examples:
+ * @code sip:172.21.40.24;maddr=* @endcode \n
+ * @code sip:172.21.40.24:50600;transport=TCP,UDP;comp=sigcomp @endcode \n
+ * @code sips:* @endcode
+ *
+ * @return
+ * On success, zero is returned. On error, -1 is returned, and @a errno is
+ * set appropriately.
+ */
+int nta_agent_add_tport(nta_agent_t *self,
+ url_string_t const *uri,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ url_t *url;
+ char tp[32];
+ char maddr[256];
+ char comp[32];
+ tp_name_t tpn[1] = {{ NULL }};
+ char const * const * tports = tports_sip;
+ int error;
+ ta_list ta;
+
+ if (self == NULL) {
+ su_seterrno(EINVAL);
+ return -1;
+ }
+
+ if (uri == NULL)
+ uri = (url_string_t *)"sip:*";
+ else if (url_string_p(uri) ?
+ strcmp(uri->us_str, "*") == 0 :
+ uri->us_url->url_type == url_any) {
+ uri = (url_string_t *)"sip:*:*";
+ }
+
+ if (!(url = url_hdup(self->sa_home, uri->us_url)) ||
+ (url->url_type != url_sip && url->url_type != url_sips)) {
+ if (url_string_p(uri))
+ SU_DEBUG_1(("nta: %s: invalid bind URL\n", uri->us_str));
+ else
+ SU_DEBUG_1(("nta: invalid bind URL\n"));
+ su_seterrno(EINVAL);
+ return -1;
+ }
+
+ tpn->tpn_canon = url->url_host;
+ tpn->tpn_host = url->url_host;
+ tpn->tpn_port = url_port(url);
+
+ if (url->url_type == url_sip) {
+ tpn->tpn_proto = "*";
+ tports = tports_sip;
+ if (!tpn->tpn_port || !tpn->tpn_port[0])
+ tpn->tpn_port = SIP_DEFAULT_SERV;
+ }
+ else {
+ assert(url->url_type == url_sips);
+ tpn->tpn_proto = "*";
+ tports = tports_sips;
+ if (!tpn->tpn_port || !tpn->tpn_port[0])
+ tpn->tpn_port = SIPS_DEFAULT_SERV;
+ }
+
+ if (url->url_params) {
+ if (url_param(url->url_params, "transport", tp, sizeof(tp)) > 0) {
+ if (strchr(tp, ',')) {
+ int i; char *t, *tps[9];
+
+ /* Split tp into transports */
+ for (i = 0, t = tp; t && i < 8; i++) {
+ tps[i] = t;
+ if ((t = strchr(t, ',')))
+ *t++ = '\0';
+ }
+
+ tps[i] = NULL;
+ tports = (char const * const *)tps;
+ } else {
+ tpn->tpn_proto = tp;
+ }
+ }
+ if (url_param(url->url_params, "maddr", maddr, sizeof(maddr)) > 0)
+ tpn->tpn_host = maddr;
+ if (url_param(url->url_params, "comp", comp, sizeof(comp)) > 0)
+ tpn->tpn_comp = comp;
+
+ if (tpn->tpn_comp &&
+ (nta_compressor_vtable == NULL ||
+ strcasecmp(tpn->tpn_comp, nta_compressor_vtable->ncv_name) != 0)) {
+ SU_DEBUG_1(("nta(%p): comp=%s not supported for " URL_PRINT_FORMAT "\n",
+ self, tpn->tpn_comp, URL_PRINT_ARGS(url)));
+ }
+ }
+
+ ta_start(ta, tag, value);
+
+ if (self->sa_tports == NULL) {
+ if (agent_create_master_transport(self, ta_args(ta)) < 0) {
+ error = su_errno();
+ SU_DEBUG_1(("nta: cannot create master transport: %s\n",
+ su_strerror(error)));
+ goto error;
+ }
+ }
+
+ if (tport_tbind(self->sa_tports, tpn, tports, ta_tags(ta)) < 0) {
+ error = su_errno();
+ SU_DEBUG_1(("nta: bind(%s:%s;transport=%s%s%s%s%s): %s\n",
+ tpn->tpn_canon, tpn->tpn_port, tpn->tpn_proto,
+ tpn->tpn_canon != tpn->tpn_host ? ";maddr=" : "",
+ tpn->tpn_canon != tpn->tpn_host ? tpn->tpn_host : "",
+ tpn->tpn_comp ? ";comp=" : "",
+ tpn->tpn_comp ? tpn->tpn_comp : "",
+ su_strerror(error)));
+ goto error;
+ }
+ else
+ SU_DEBUG_5(("nta: bound to (%s:%s;transport=%s%s%s%s%s)\n",
+ tpn->tpn_canon, tpn->tpn_port, tpn->tpn_proto,
+ tpn->tpn_canon != tpn->tpn_host ? ";maddr=" : "",
+ tpn->tpn_canon != tpn->tpn_host ? tpn->tpn_host : "",
+ tpn->tpn_comp ? ";comp=" : "",
+ tpn->tpn_comp ? tpn->tpn_comp : ""));
+
+ /* XXX - when to use maddr? */
+ if ((agent_init_via(self, tport_primaries(self->sa_tports), 0)) < 0) {
+ error = su_errno();
+ SU_DEBUG_1(("nta: cannot create Via headers\n"));
+ goto error;
+ }
+ else
+ SU_DEBUG_9(("nta: Via fields initialized\n"));
+
+ if ((agent_init_contact(self)) < 0) {
+ error = su_errno();
+ SU_DEBUG_1(("nta: cannot create Contact header\n"));
+ goto error;
+ }
+ else
+ SU_DEBUG_9(("nta: Contact header created\n"));
+
+ su_free(self->sa_home, url);
+ ta_end(ta);
+
+ return 0;
+
+ error:
+ ta_end(ta);
+ su_seterrno(error);
+ return -1;
+}
+
+static
+int agent_create_master_transport(nta_agent_t *self, tagi_t *tags)
+{
+ self->sa_tports =
+ tport_tcreate(self, nta_agent_class, self->sa_root,
+ TPTAG_SDWN_ERROR(0),
+ TPTAG_IDLE(1800000),
+ TPTAG_DEBUG_DROP(self->sa_drop_prob),
+ TAG_NEXT(tags));
+
+ if (!self->sa_tports)
+ return -1;
+
+ SU_DEBUG_9(("nta: master transport created\n"));
+
+ return 0;
+}
+
+
+/** Initialize @Via headers. */
+static
+int agent_init_via(nta_agent_t *self, tport_t *primaries, int use_maddr)
+{
+ sip_via_t *via = NULL, *new_via, *dup_via, *v, **vv = &via;
+ sip_via_t *new_vias, **next_new_via, *new_publics, **next_new_public;
+ tport_t *tp;
+ su_addrinfo_t const *ai;
+
+ su_home_t autohome[SU_HOME_AUTO_SIZE(2048)];
+
+ su_home_auto(autohome, sizeof autohome);
+
+ self->sa_tport_ip4 = 0;
+ self->sa_tport_ip6 = 0;
+ self->sa_tport_udp = 0;
+ self->sa_tport_tcp = 0;
+ self->sa_tport_sctp = 0;
+ self->sa_tport_tls = 0;
+
+ /* Set via fields for the tports */
+ for (tp = primaries; tp; tp = tport_next(tp)) {
+ int maddr, first_via;
+ tp_name_t tpn[1];
+ char const *comp = NULL;
+
+ *tpn = *tport_name(tp);
+
+ assert(tpn->tpn_proto);
+ assert(tpn->tpn_canon);
+ assert(tpn->tpn_host);
+ assert(tpn->tpn_port);
+
+#if 0
+ if (getenv("SIP_UDP_CONNECT")
+ && strcmp(tpn->tpn_proto, "udp") == 0)
+ tport_set_params(tp, TPTAG_CONNECT(1), TAG_END());
+#endif
+
+ if (tport_has_ip4(tp)) self->sa_tport_ip4 = 1;
+
+#if SU_HAVE_IN6
+ if (tport_has_ip6(tp)) self->sa_tport_ip6 = 1;
+#endif
+
+ if (strcasecmp(tpn->tpn_proto, "udp") == 0)
+ self->sa_tport_udp = 1;
+ else if (strcasecmp(tpn->tpn_proto, "tcp") == 0)
+ self->sa_tport_tcp = 1;
+ else if (strcasecmp(tpn->tpn_proto, "sctp") == 0)
+ self->sa_tport_sctp = 1;
+
+ if (tport_has_tls(tp)) self->sa_tport_tls = 1;
+
+ first_via = 1;
+
+ ai = tport_get_address(tp);
+
+ for (; ai; ai = ai->ai_next) {
+ char host[TPORT_HOSTPORTSIZE] = "";
+ char sport[8];
+ char const *canon = ai->ai_canonname;
+ su_sockaddr_t *su = (void *)ai->ai_addr;
+ int port;
+
+ if (su) {
+ inet_ntop(su->su_family, SU_ADDR(su), host, sizeof host);
+ maddr = use_maddr && strcasecmp(canon, host) != 0;
+ port = ntohs(su->su_port);
+ }
+ else {
+ msg_random_token(host, 16, NULL, 0);
+ canon = strcat(host, ".is.invalid");
+ maddr = 0;
+ port = 0;
+ }
+
+ if (strncasecmp(tpn->tpn_proto, "tls", 3)
+ ? port == SIP_DEFAULT_PORT
+ : port == SIPS_DEFAULT_PORT)
+ port = 0;
+
+ snprintf(sport, sizeof sport, ":%u", port);
+
+ comp = tpn->tpn_comp;
+
+ SU_DEBUG_9(("nta: agent_init_via: "
+ "%s/%s %s%s%s%s%s%s (%s)\n",
+ SIP_VERSION_CURRENT, tpn->tpn_proto,
+ canon, port ? sport : "",
+ maddr ? ";maddr=" : "", maddr ? host : "",
+ comp ? ";comp=" : "", comp ? comp : "",
+ tpn->tpn_ident ? tpn->tpn_ident : "*"));
+
+ v = sip_via_format(autohome,
+ "%s/%s %s%s%s%s%s%s",
+ SIP_VERSION_CURRENT, tpn->tpn_proto,
+ canon, port ? sport : "",
+ maddr ? ";maddr=" : "", maddr ? host : "",
+ comp ? ";comp=" : "", comp ? comp : "");
+ if (v == NULL)
+ goto error;
+
+ v->v_comment = tpn->tpn_ident;
+ v->v_common->h_data = tp; /* Nasty trick */
+ *vv = v; vv = &(*vv)->v_next;
+ }
+ }
+
+ /* Duplicate the list bind to the transports */
+ new_via = sip_via_dup(self->sa_home, via);
+ /* Duplicate the complete list shown to the application */
+ dup_via = sip_via_dup(self->sa_home, via);
+
+ if (via && (!new_via || !dup_via)) {
+ msg_header_free(self->sa_home, (void *)new_via);
+ msg_header_free(self->sa_home, (void *)dup_via);
+ goto error;
+ }
+
+ new_vias = NULL, next_new_via = &new_vias;
+ new_publics = NULL, next_new_public = &new_publics;
+
+ /* Set via field magic for the tports */
+ for (tp = primaries; tp; tp = tport_next(tp)) {
+ assert(via->v_common->h_data == tp);
+ v = tport_magic(tp);
+ tport_set_magic(tp, new_via);
+ msg_header_free(self->sa_home, (void *)v);
+
+ if (tport_is_public(tp))
+ *next_new_public = dup_via;
+ else
+ *next_new_via = dup_via;
+
+ while (via->v_next && via->v_next->v_common->h_data == tp)
+ via = via->v_next, new_via = new_via->v_next, dup_via = dup_via->v_next;
+
+ via = via->v_next;
+ /* Break the link in via list between transports */
+ vv = &new_via->v_next, new_via = *vv, *vv = NULL;
+ vv = &dup_via->v_next, dup_via = *vv, *vv = NULL;
+
+ if (tport_is_public(tp))
+ while (*next_new_public) next_new_public = &(*next_new_public)->v_next;
+ else
+ while (*next_new_via) next_new_via = &(*next_new_via)->v_next;
+ }
+
+ assert(dup_via == NULL);
+ assert(new_via == NULL);
+
+ if (self->sa_tport_udp)
+ agent_set_udp_params(self, self->sa_udp_mtu);
+
+ v = self->sa_vias;
+ self->sa_vias = new_vias;
+ msg_header_free(self->sa_home, (void *)v);
+
+ v = self->sa_public_vias;
+ self->sa_public_vias = new_publics;
+ msg_header_free(self->sa_home, (void *)v);
+
+ su_home_deinit(autohome);
+
+ return 0;
+
+ error:
+ su_home_deinit(autohome);
+ return -1;
+}
+
+
+/** Initialize main contact header. */
+static
+int agent_init_contact(nta_agent_t *self)
+{
+ sip_via_t const *v1, *v2;
+ char const *tp;
+
+ if (self->sa_contact)
+ return 0;
+
+ if (self->sa_vias)
+ v1 = self->sa_vias;
+ else
+ v1 = self->sa_public_vias;
+
+ if (!v1)
+ return -1;
+
+ tp = strrchr(v1->v_protocol, '/');
+ if (!tp++)
+ return -1;
+
+ v2 = v1->v_next;
+
+ if (v2 &&
+ strcasecmp(v1->v_host, v2->v_host) == 0 &&
+ str0casecmp(v1->v_port, v2->v_port) == 0) {
+ char const *p1 = v1->v_protocol, *p2 = v2->v_protocol;
+
+ if (strcasecmp(p1, sip_transport_udp))
+ p1 = v2->v_protocol, p2 = v1->v_protocol;
+
+ if (strcasecmp(p1, sip_transport_udp) == 0 &&
+ strcasecmp(p2, sip_transport_tcp) == 0)
+ /* Do not include transport if we have both UDP and TCP */
+ tp = NULL;
+ }
+
+ self->sa_contact =
+ sip_contact_create_from_via_with_transport(self->sa_home, v1, NULL, tp);
+
+ if (!self->sa_contact)
+ return -1;
+
+ return 0;
+}
+
+/** Return @Via line corresponging to tport. */
+static
+sip_via_t const *agent_tport_via(tport_t *tport)
+{
+ sip_via_t *v = tport_magic(tport);
+ while (v && v->v_next)
+ v = v->v_next;
+ return v;
+}
+
+/** Insert @Via to a request message */
+static
+int outgoing_insert_via(nta_outgoing_t *orq,
+ sip_via_t const *via)
+{
+ nta_agent_t *self = orq->orq_agent;
+ msg_t *msg = orq->orq_request;
+ sip_t *sip = sip_object(msg);
+ char const *branch = orq->orq_via_branch;
+ int user_via = orq->orq_user_via;
+ sip_via_t *v;
+ int clear = 0;
+
+ assert(sip); assert(via);
+
+ if (user_via && sip->sip_via) {
+ /* Use existing @Via provided by application */
+ v = sip->sip_via;
+ }
+ else if (msg && via && sip->sip_request &&
+ (v = sip_via_copy(msg_home(msg), via))) {
+ msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)v);
+ }
+ else
+ return -1;
+
+ if (!v->v_rport &&
+ ((self->sa_rport && v->v_protocol == sip_transport_udp) ||
+ (self->sa_tcp_rport && v->v_protocol == sip_transport_tcp)))
+ msg_header_add_param(msg_home(msg), v->v_common, "rport");
+
+ if (!orq->orq_tpn->tpn_comp)
+ msg_header_remove_param(v->v_common, "comp");
+
+ if (branch && branch != v->v_branch) {
+ char const *bvalue = branch + strcspn(branch, "=");
+ if (*bvalue) bvalue++;
+ if (!v->v_branch || strcasecmp(bvalue, v->v_branch))
+ msg_header_replace_param(msg_home(msg), v->v_common, branch);
+ }
+
+ if (via->v_protocol != v->v_protocol &&
+ strcasecmp(via->v_protocol, v->v_protocol))
+ clear = 1, v->v_protocol = via->v_protocol;
+
+ /* XXX - should we do this? */
+ if (via->v_host != v->v_host &&
+ str0cmp(via->v_host, v->v_host))
+ clear = 1, v->v_host = via->v_host;
+
+ if (via->v_port != v->v_port &&
+ str0cmp(via->v_port, v->v_port))
+ clear = 1, v->v_port = via->v_port;
+
+ if (clear)
+ msg_fragment_clear(v->v_common);
+
+ return 0;
+}
+
+/** Get destination name from @Via.
+ *
+ * If @a using_rport is non-null, try rport.
+ * If *using_rport is non-zero, try rport even if <protocol> is not UDP.
+ * If <protocol> is UDP, set *using_rport to zero.
+ */
+static
+int nta_tpn_by_via(tp_name_t *tpn, sip_via_t const *v, int *using_rport)
+{
+ if (!v)
+ return -1;
+
+ tpn->tpn_proto = sip_via_transport(v);
+ tpn->tpn_canon = v->v_host;
+
+ if (v->v_maddr)
+ tpn->tpn_host = v->v_maddr;
+ else if (v->v_received)
+ tpn->tpn_host = v->v_received;
+ else
+ tpn->tpn_host = v->v_host;
+
+ tpn->tpn_port = sip_via_port(v, using_rport);
+ tpn->tpn_comp = v->v_comp;
+ tpn->tpn_ident = NULL;
+
+ return 0;
+}
+
+/** Get transport name from URL. */
+int nta_tpn_by_url(su_home_t *home,
+ tp_name_t *tpn,
+ char const **scheme,
+ char const **port,
+ url_string_t const *us)
+{
+ url_t url[1];
+ isize_t n;
+ char *b;
+
+ n = url_xtra(us->us_url);
+ b = su_alloc(home, n);
+
+ if (b == NULL || url_dup(b, n, url, us->us_url) < 0) {
+ su_free(home, b);
+ return -1;
+ }
+
+ if (url->url_type != url_sip &&
+ url->url_type != url_sips &&
+ url->url_type != url_im &&
+ url->url_type != url_pres) {
+ su_free(home, b);
+ return -1;
+ }
+
+ SU_DEBUG_7(("nta: selecting scheme %s\n", url->url_scheme));
+
+ *scheme = url->url_scheme;
+ if (strcasecmp(url->url_scheme, "sips") == 0)
+ tpn->tpn_proto = "tls";
+ else
+ tpn->tpn_proto = "*";
+ tpn->tpn_canon = url->url_host;
+ tpn->tpn_host = url->url_host;
+
+ if (url->url_params) {
+ for (b = (char *)url->url_params; b[0]; b += n) {
+ n = strcspn(b, ";");
+
+ if (n > 10 && strncasecmp(b, "transport=", 10) == 0)
+ tpn->tpn_proto = b + 10;
+ else if (n > 5 && strncasecmp(b, "comp=", 5) == 0)
+ tpn->tpn_comp = b + 5;
+ else if (n > 6 && strncasecmp(b, "maddr=", 6) == 0)
+ tpn->tpn_host = b + 6;
+
+ if (b[n])
+ b[n++] = '\0';
+ }
+ }
+
+ if ((*port = url->url_port))
+ tpn->tpn_port = url->url_port;
+
+ tpn->tpn_ident = NULL;
+
+ return 0;
+}
+
+/** Handle transport errors. */
+static
+void agent_tp_error(nta_agent_t *agent,
+ tport_t *tport,
+ int errcode,
+ char const *remote)
+{
+ su_llog(nta_log, 1,
+ "nta_agent: tport: %s%s%s\n",
+ remote ? remote : "", remote ? ": " : "",
+ su_strerror(errcode));
+}
+
+/** Handle updated transport addresses */
+static void agent_update_tport(nta_agent_t *self, tport_t *tport)
+{
+ /* Initialize local Vias first */
+ agent_init_via(self, tport_primaries(self->sa_tports), 0);
+
+ if (self->sa_update_tport) {
+ self->sa_update_tport(self->sa_update_magic, self);
+ }
+ else {
+ /* XXX - we should do something else? */
+ SU_DEBUG_3(("nta(%p): transport address updated\n", self));
+ }
+}
+
+/* ====================================================================== */
+/* 3) Message dispatch */
+
+static void agent_recv_request(nta_agent_t *agent,
+ msg_t *msg,
+ sip_t *sip,
+ tport_t *tport);
+static int agent_check_request_via(nta_agent_t *agent,
+ msg_t *msg,
+ sip_t *sip,
+ sip_via_t *v,
+ tport_t *tport);
+static int agent_aliases(nta_agent_t const *, url_t [], tport_t *);
+static void agent_recv_response(nta_agent_t*, msg_t *, sip_t *,
+ sip_via_t *, tport_t*);
+static void agent_recv_garbage(nta_agent_t*, msg_t*, tport_t*);
+
+
+/** Handle incoming message. */
+static
+void agent_recv_message(nta_agent_t *agent,
+ tport_t *tport,
+ msg_t *msg,
+ sip_via_t *tport_via,
+ su_time_t now)
+{
+ sip_t *sip = sip_object(msg);
+
+ agent->sa_millisec = su_time_ms(agent->sa_now = now);
+
+ if (sip && sip->sip_request) {
+ agent_recv_request(agent, msg, sip, tport);
+ }
+ else if (sip && sip->sip_status) {
+ agent_recv_response(agent, msg, sip, tport_via, tport);
+ }
+ else {
+ agent_recv_garbage(agent, msg, tport);
+ }
+
+ agent->sa_millisec = 0;
+}
+
+/** @internal Handle incoming requests. */
+static
+void agent_recv_request(nta_agent_t *agent,
+ msg_t *msg,
+ sip_t *sip,
+ tport_t *tport)
+{
+ nta_leg_t *leg;
+ nta_incoming_t *irq, *merge = NULL, *ack = NULL;
+ sip_method_t method = sip->sip_request->rq_method;
+ char const *method_name = sip->sip_request->rq_method_name;
+ url_t url[1];
+ unsigned cseq = sip->sip_cseq ? sip->sip_cseq->cs_seq : 0;
+ int insane, errors, stream;
+
+ agent->sa_stats->as_recv_msg++;
+ agent->sa_stats->as_recv_request++;
+
+ SU_DEBUG_5(("nta: received %s " URL_PRINT_FORMAT " %s (CSeq %u)\n",
+ method_name,
+ URL_PRINT_ARGS(sip->sip_request->rq_url),
+ sip->sip_request->rq_version, cseq));
+
+ stream = tport_is_stream(tport);
+
+ /* Try to use compression on reverse direction if @Via has comp=sigcomp */
+ if (stream &&
+ sip->sip_via && sip->sip_via->v_comp &&
+ tport_can_send_sigcomp(tport) &&
+ tport_name(tport)->tpn_comp == NULL &&
+ tport_has_compression(tport_parent(tport), sip->sip_via->v_comp)) {
+ tport_set_compression(tport, sip->sip_via->v_comp);
+ }
+
+ if (sip->sip_flags & MSG_FLG_TOOLARGE) {
+ SU_DEBUG_5(("nta: %s (%u) is %s\n",
+ method_name, cseq, sip_413_Request_too_large));
+ agent->sa_stats->as_bad_request++;
+ nta_msg_treply(agent, msg, SIP_413_REQUEST_TOO_LARGE,
+ NTATAG_TPORT(tport),
+ NTATAG_INCOMPLETE(1),
+ TPTAG_SDWN_AFTER(stream),
+ TAG_END());
+ return;
+ }
+
+ insane = 0;
+
+ if (agent->sa_bad_req_mask != ~0U)
+ errors = msg_extract_errors(msg) & agent->sa_bad_req_mask;
+ else
+ errors = sip->sip_error != NULL;
+
+ if (errors ||
+ (sip->sip_flags & MSG_FLG_ERROR) /* Fatal error */ ||
+ (insane = (sip_sanity_check(sip) < 0))) {
+ sip_header_t const *h;
+ char const *badname = NULL, *phrase;
+
+ agent->sa_stats->as_bad_message++;
+ agent->sa_stats->as_bad_request++;
+
+ if (insane)
+ SU_DEBUG_5(("nta: %s (%u) %s\n", method_name, cseq,
+ "failed sanity check"));
+
+ for (h = (sip_header_t const *)sip->sip_error; h; h = h->sh_next) {
+ char const *bad;
+
+ if (h->sh_class == sip_error_class)
+ bad = h->sh_error->er_name;
+ else
+ bad = h->sh_class->hc_name;
+
+ if (bad)
+ SU_DEBUG_5(("nta: %s has bad %s header\n", method_name, bad));
+
+ if (!badname)
+ badname = bad;
+ }
+
+ if (sip->sip_via && method != sip_method_ack) {
+ msg_t *reply = nta_msg_create(agent, 0);
+
+ if (reply) {
+ agent_check_request_via(agent, msg, sip, sip->sip_via, tport);
+
+ if (badname)
+ phrase = su_sprintf(msg_home(reply), "Bad %s Header", badname);
+ else
+ phrase = sip_400_Bad_request;
+
+ SU_DEBUG_5(("nta: %s (%u) is %s\n", method_name, cseq, phrase));
+
+ nta_msg_mreply(agent, reply, sip_object(reply),
+ 400, phrase,
+ msg,
+ NTATAG_TPORT(tport),
+ NTATAG_INCOMPLETE(1),
+ TPTAG_SDWN_AFTER(stream),
+ TAG_END());
+ }
+ } else {
+ msg_destroy(msg);
+ if (stream) /* Send FIN */
+ tport_shutdown(tport, 1);
+ }
+
+ return;
+ }
+
+ if (str0casecmp(sip->sip_request->rq_version, sip_version_2_0) != 0) {
+ agent->sa_stats->as_bad_request++;
+ agent->sa_stats->as_bad_message++;
+
+ SU_DEBUG_5(("nta: bad version %s for %s (%u)\n",
+ sip->sip_request->rq_version, method_name, cseq));
+
+ nta_msg_treply(agent, msg, SIP_505_VERSION_NOT_SUPPORTED,
+ NTATAG_TPORT(tport),
+ TPTAG_SDWN_AFTER(stream),
+ TAG_END());
+
+ return;
+ }
+
+ if (agent_check_request_via(agent, msg, sip, sip->sip_via, tport) < 0) {
+ agent->sa_stats->as_bad_message++;
+ agent->sa_stats->as_bad_request++;
+ SU_DEBUG_5(("nta: %s (%u) %s\n", method_name, cseq, "has invalid Via"));
+ msg_destroy(msg);
+ return;
+ }
+
+ /* First, try existing incoming requests */
+ irq = incoming_find(agent, sip, sip->sip_via, &merge, &ack);
+ if (irq) {
+ /* Match - this is a retransmission */
+ SU_DEBUG_5(("nta: %s (%u) going to existing %s transaction\n",
+ method_name, cseq, irq->irq_rq->rq_method_name));
+ if (incoming_recv(irq, msg, sip, tport) >= 0)
+ return;
+ }
+ else if (ack) {
+ /* Match - this is an ACK or CANCEL or PRACK */
+ SU_DEBUG_5(("nta: %s (%u) is going to %s (%u)\n",
+ method_name, cseq,
+ ack->irq_rq->rq_method_name, ack->irq_cseq->cs_seq));
+ if (method == sip_method_ack) {
+ if (incoming_ack(ack, msg, sip, tport) >= 0)
+ return;
+ }
+ else if (method == sip_method_cancel) {
+ if (incoming_cancel(ack, msg, sip, tport) >= 0)
+ return;
+ }
+ else if (method == sip_method_prack) {
+ if (reliable_recv(ack, msg, sip, tport) >= 0)
+ return;
+ }
+ else {
+ assert(!method);
+ }
+ }
+ else if (merge) {
+ SU_DEBUG_5(("nta: %s (%u) %s\n",
+ method_name, cseq, "is a merged request"));
+ if (incoming_merge(merge, msg, sip, tport) >= 0)
+ return;
+ }
+
+ *url = *sip->sip_request->rq_url;
+ url->url_params = NULL;
+ agent_aliases(agent, url, tport); /* canonize urls */
+
+ if ((leg = leg_find(agent,
+ method_name, url,
+ sip->sip_call_id,
+ sip->sip_from->a_tag, sip->sip_from->a_url,
+ sip->sip_to->a_tag, sip->sip_to->a_url))) {
+ /* Try existing dialog */
+ SU_DEBUG_5(("nta: %s (%u) %s\n",
+ method_name, cseq, "going to existing leg"));
+ leg_recv(leg, msg, sip, tport);
+ return;
+ }
+ else if (!agent->sa_is_stateless &&
+ (leg = dst_find(agent, url, method_name))) {
+ /* Dialogless legs - let application process transactions statefully */
+ SU_DEBUG_5(("nta: %s (%u) %s\n",
+ method_name, cseq, "going to a dialogless leg"));
+ leg_recv(leg, msg, sip, tport);
+ }
+ else if (!agent->sa_is_stateless && (leg = agent->sa_default_leg)) {
+ SU_DEBUG_5(("nta: %s (%u) %s\n",
+ method_name, cseq, "going to a default leg"));
+ leg_recv(leg, msg, sip, tport);
+ }
+ else if (agent->sa_callback) {
+ /* Stateless processing for request */
+ agent->sa_stats->as_trless_request++;
+ SU_DEBUG_5(("nta: %s (%u) %s\n",
+ method_name, cseq, "to message callback"));
+ (void)agent->sa_callback(agent->sa_magic, agent, msg, sip);
+ }
+ else {
+ agent->sa_stats->as_trless_request++;
+ SU_DEBUG_5(("nta: %s (%u) no place to go: %d %s\n",
+ method_name, cseq, SIP_501_NOT_IMPLEMENTED));
+ if (method != sip_method_ack)
+ nta_msg_treply(agent, msg, SIP_501_NOT_IMPLEMENTED,
+ NTATAG_TPORT(tport),
+ TAG_END());
+ else
+ msg_destroy(msg);
+ }
+}
+
+/** Check @Via header.
+ *
+ */
+static
+int agent_check_request_via(nta_agent_t *agent,
+ msg_t *msg,
+ sip_t *sip,
+ sip_via_t *v,
+ tport_t *tport)
+{
+ enum { receivedlen = sizeof("received=") - 1 };
+ char received[receivedlen + TPORT_HOSTPORTSIZE];
+ char *hostport = received + receivedlen;
+ char const *rport;
+ su_sockaddr_t const *from;
+ sip_via_t const *tpv = agent_tport_via(tport);
+
+ assert(tport); assert(msg); assert(sip);
+ assert(sip->sip_request); assert(tpv);
+
+ from = msg_addr(msg);
+
+ if (v == NULL) {
+ /* Make up a via line */
+ v = sip_via_format(msg_home(msg), "SIP/2.0/%s %s",
+ tport_name(tport)->tpn_proto,
+ tport_hostport(hostport, TPORT_HOSTPORTSIZE, from, 1));
+ msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)v);
+
+ return v ? 0 : -1;
+ }
+
+ if (str0casecmp(v->v_protocol, tpv->v_protocol)) {
+ tport_hostport(hostport, TPORT_HOSTPORTSIZE, from, 1);
+ SU_DEBUG_1(("nta: Via check: invalid transport \"%s\" from %s\n",
+ v->v_protocol, hostport));
+ return -1;
+ }
+
+ if (v->v_received) {
+ /* Nasty, nasty */
+ tport_hostport(hostport, TPORT_HOSTPORTSIZE, from, 1);
+ SU_DEBUG_1(("nta: Via check: extra received=%s from %s\n",
+ v->v_received, hostport));
+ msg_header_remove_param(v->v_common, "received");
+ }
+
+ if (!tport_hostport(hostport, TPORT_HOSTPORTSIZE, from, 0))
+ return -1;
+
+ if (strcasecmp(hostport, v->v_host)) {
+ size_t rlen;
+ /* Add the "received" field */
+ memcpy(received, "received=", receivedlen);
+
+ if (hostport[0] == '[') {
+ rlen = strlen(hostport + 1) - 1;
+ memmove(hostport, hostport + 1, rlen);
+ hostport[rlen] = '\0';
+ }
+
+ msg_header_replace_param(msg_home(msg), v->v_common,
+ su_strdup(msg_home(msg), received));
+ SU_DEBUG_5(("nta: Via check: %s\n", received));
+ }
+
+ if (!agent->sa_server_rport) {
+ /*Xyzzy*/;
+ }
+ else if (v->v_rport) {
+ rport = su_sprintf(msg_home(msg), "rport=%u", ntohs(from->su_port));
+ msg_header_replace_param(msg_home(msg), v->v_common, rport);
+ }
+ else if (tport_is_tcp(tport)) {
+ rport = su_sprintf(msg_home(msg), "rport=%u", ntohs(from->su_port));
+ msg_header_replace_param(msg_home(msg), v->v_common, rport);
+ }
+
+ return 0;
+}
+
+/** @internal Handle aliases of local node.
+ *
+ * Return true if @a url is modified.
+ */
+static
+int agent_aliases(nta_agent_t const *agent, url_t url[], tport_t *tport)
+{
+ sip_contact_t *m;
+ sip_via_t const *lv;
+ char const *tport_port = "";
+
+ if (!url->url_host)
+ return 0;
+
+ if (tport)
+ tport_port = tport_name(tport)->tpn_port;
+
+ assert(tport_port);
+
+ for (m = agent->sa_aliases ? agent->sa_aliases : agent->sa_contact;
+ m;
+ m = m->m_next) {
+ if (url->url_type != m->m_url->url_type)
+ continue;
+
+ if (host_cmp(url->url_host, m->m_url->url_host))
+ continue;
+
+ if (url->url_port == NULL)
+ break;
+
+ if (m->m_url->url_port) {
+ if (strcmp(url->url_port, m->m_url->url_port))
+ continue;
+ } else {
+ if (strcmp(url->url_port, tport_port))
+ continue;
+ }
+
+ break;
+ }
+
+ if (!m)
+ return 0;
+
+ SU_DEBUG_7(("nta: canonizing " URL_PRINT_FORMAT " with %s\n",
+ URL_PRINT_ARGS(url),
+ agent->sa_aliases ? "aliases" : "contact"));
+
+ url->url_host = "%";
+
+ if (agent->sa_aliases) {
+ url->url_type = agent->sa_aliases->m_url->url_type;
+ url->url_scheme = agent->sa_aliases->m_url->url_scheme;
+ url->url_port = agent->sa_aliases->m_url->url_port;
+ return 1;
+ }
+ else {
+ /* Canonize the request URL port */
+ if (tport) {
+ lv = agent_tport_via(tport_parent(tport)); assert(lv);
+ if (lv->v_port)
+ /* Add non-default port */
+ url->url_port = lv->v_port;
+ return 1;
+ }
+ if (url->url_port &&
+ strcmp(url->url_port, url_port_default(url->url_type)) == 0)
+ /* Remove default port */
+ url->url_port = NULL;
+
+ return 0;
+ }
+}
+
+/** @internal Handle incoming responses. */
+static
+void agent_recv_response(nta_agent_t *agent,
+ msg_t *msg,
+ sip_t *sip,
+ sip_via_t *tport_via,
+ tport_t *tport)
+{
+ int status = sip->sip_status->st_status;
+ int errors;
+ char const *phrase = sip->sip_status->st_phrase;
+ char const *method =
+ sip->sip_cseq ? sip->sip_cseq->cs_method_name : "<UNKNOWN>";
+ uint32_t cseq = sip->sip_cseq ? sip->sip_cseq->cs_seq : 0;
+ nta_outgoing_t *orq;
+
+ agent->sa_stats->as_recv_msg++;
+ agent->sa_stats->as_recv_response++;
+
+ SU_DEBUG_5(("nta: received %03d %s for %s (%u)\n",
+ status, phrase, method, cseq));
+
+ if (agent->sa_bad_resp_mask)
+ errors = msg_extract_errors(msg) & agent->sa_bad_resp_mask;
+ else
+ errors = sip->sip_error != NULL;
+
+ if (errors ||
+ sip_sanity_check(sip) < 0) {
+ sip_header_t const *h;
+
+ agent->sa_stats->as_bad_response++;
+ agent->sa_stats->as_bad_message++;
+
+ SU_DEBUG_5(("nta: %03d %s failed sanity check\n", status, phrase));
+
+ for (h = (sip_header_t const *)sip->sip_error; h; h = h->sh_next) {
+ if (h->sh_class->hc_name) {
+ SU_DEBUG_5(("nta: %03d has bad %s header\n", status,
+ h->sh_class->hc_name));
+ }
+ }
+
+ msg_destroy(msg);
+ return;
+ }
+
+ if (str0casecmp(sip->sip_status->st_version, sip_version_2_0) != 0) {
+ agent->sa_stats->as_bad_response++;
+ agent->sa_stats->as_bad_message++;
+
+ SU_DEBUG_5(("nta: bad version %s %03d %s\n",
+ sip->sip_status->st_version, status, phrase));
+ msg_destroy(msg);
+ return;
+ }
+
+ if (sip->sip_cseq->cs_method == sip_method_ack) {
+ /* Drop response messages to ACK */
+ agent->sa_stats->as_bad_response++;
+ agent->sa_stats->as_bad_message++;
+ SU_DEBUG_5(("nta: %03d %s is response to ACK\n", status, phrase));
+ msg_destroy(msg);
+ return;
+ }
+
+ /* XXX - should check if msg should be discarded based on via? */
+
+ if ((orq = outgoing_find(agent, msg, sip, sip->sip_via))) {
+ SU_DEBUG_5(("nta: %03d %s going to a transaction\n", status, phrase));
+ if (outgoing_recv(orq, status, msg, sip) == 0)
+ return;
+ }
+
+ agent->sa_stats->as_trless_response++;
+
+ if ((orq = agent->sa_default_outgoing)) {
+ SU_DEBUG_5(("nta: %03d %s to the default transaction\n", status, phrase));
+ outgoing_default_recv(orq, status, msg, sip);
+ return;
+ }
+ else if (agent->sa_callback) {
+ SU_DEBUG_5(("nta: %03d %s to message callback\n", status, phrase));
+ /*
+ * Store message and transport to hook for the duration of the callback
+ * so that the transport can be obtained by nta_transport().
+ */
+ (void)agent->sa_callback(agent->sa_magic, agent, msg, sip);
+ return;
+ }
+
+ if (sip->sip_cseq->cs_method == sip_method_invite
+ && 200 <= sip->sip_status->st_status
+ && sip->sip_status->st_status < 300) {
+ agent->sa_stats->as_trless_200++;
+ /* Orphan 200 Ok to INVITE. ACK and BYE it */
+ SU_DEBUG_5(("nta: %03d %s must be ACK&BYE\n", status, phrase));
+ if (nta_msg_ackbye(agent, msg) != -1)
+ return;
+ }
+
+ SU_DEBUG_5(("nta: %03d %s was discarded\n", status, phrase));
+ msg_destroy(msg);
+}
+/** @internal Agent receives garbage */
+static
+void agent_recv_garbage(nta_agent_t *agent,
+ msg_t *msg,
+ tport_t *tport)
+{
+ agent->sa_stats->as_recv_msg++;
+ agent->sa_stats->as_bad_message++;
+
+#if SU_DEBUG >= 3
+ if (nta_log->log_level >= 3) {
+ tp_name_t tpn[1];
+
+ tport_delivered_from(tport, msg, tpn);
+
+ SU_DEBUG_3(("nta_agent: received garbage from " TPN_FORMAT "\n",
+ TPN_ARGS(tpn)));
+ }
+#endif
+
+ msg_destroy(msg);
+}
+
+/* ====================================================================== */
+/* 4) Message handling - create, complete, destroy */
+
+/** Create a new message belonging to the agent */
+msg_t *nta_msg_create(nta_agent_t *agent, int flags)
+{
+ msg_t *msg;
+
+ if (agent == NULL)
+ return su_seterrno(EINVAL), NULL;
+
+ msg = msg_create(agent->sa_mclass, agent->sa_flags | flags);
+
+ if (agent->sa_preload)
+ su_home_preload(msg_home(msg), 1, agent->sa_preload);
+
+ return msg;
+}
+
+/** Create a new message for transport */
+msg_t *nta_msg_create_for_transport(nta_agent_t *agent, int flags,
+ char const data[], usize_t dlen,
+ tport_t const *tport, tp_client_t *via)
+{
+ msg_t *msg = msg_create(agent->sa_mclass, agent->sa_flags | flags);
+
+ msg_maxsize(msg, agent->sa_maxsize);
+
+ if (agent->sa_preload)
+ su_home_preload(msg_home(msg), 1, dlen + agent->sa_preload);
+
+ return msg;
+}
+
+/** Complete a message. */
+int nta_msg_complete(msg_t *msg)
+{
+ return sip_complete_message(msg);
+}
+
+/** Discard a message */
+void nta_msg_discard(nta_agent_t *agent, msg_t *msg)
+{
+ msg_destroy(msg);
+}
+
+/** Check if the message is internally generated by NTA. */
+int nta_is_internal_msg(msg_t const *msg)
+{
+ return msg_get_flags(msg, NTA_INTERNAL_MSG) == NTA_INTERNAL_MSG;
+}
+
+/* ====================================================================== */
+/* 5) Stateless operation */
+
+/**Forward a request or response message.
+ *
+ * @note
+ * The ownership of @a msg is taken over by the function even if the
+ * function fails.
+ */
+int nta_msg_tsend(nta_agent_t *agent, msg_t *msg, url_string_t const *u,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ int retval = -1;
+ ta_list ta;
+ sip_t *sip = sip_object(msg);
+ tp_name_t tpn[1] = {{ NULL }};
+ char const *what;
+
+ if (!sip) {
+ msg_destroy(msg);
+ return -1;
+ }
+
+ what =
+ sip->sip_status ? "nta_msg_tsend(response)" :
+ sip->sip_request ? "nta_msg_tsend(request)" :
+ "nta_msg_tsend()";
+
+ ta_start(ta, tag, value);
+
+ if (sip_add_tl(msg, sip, ta_tags(ta)) < 0)
+ SU_DEBUG_3(("%s: cannot add headers\n", what));
+ else if (sip->sip_status) {
+ tport_t *tport = NULL;
+ int *use_rport = NULL;
+ int retry_without_rport = 0;
+
+ struct sigcomp_compartment *cc; cc = NONE;
+
+ if (agent->sa_server_rport)
+ use_rport = &retry_without_rport, retry_without_rport = 1;
+
+ tl_gets(ta_args(ta),
+ NTATAG_TPORT_REF(tport),
+ IF_SIGCOMP_TPTAG_COMPARTMENT_REF(cc)
+ /* NTATAG_INCOMPLETE_REF(incomplete), */
+ TAG_END());
+
+ if (!sip->sip_separator &&
+ !(sip->sip_separator = sip_separator_create(msg_home(msg))))
+ SU_DEBUG_3(("%s: cannot create sip_separator\n", what));
+ else if (msg_serialize(msg, (msg_pub_t *)sip) != 0)
+ SU_DEBUG_3(("%s: sip_serialize() failed\n", what));
+ else if (!sip_via_remove(msg, sip))
+ SU_DEBUG_3(("%s: cannot remove Via\n", what));
+ else if (nta_tpn_by_via(tpn, sip->sip_via, use_rport) < 0)
+ SU_DEBUG_3(("%s: bad via\n", what));
+ else {
+ if (!tport)
+ tport = tport_by_name(agent->sa_tports, tpn);
+ if (!tport)
+ tport = tport_by_protocol(agent->sa_tports, tpn->tpn_proto);
+
+ if (retry_without_rport)
+ tpn->tpn_port = sip_via_port(sip->sip_via, NULL);
+
+ if (tport && tpn->tpn_comp && cc == NONE)
+ cc = agent_compression_compartment(agent, tport, tpn, -1);
+
+ if (tport_tsend(tport, msg, tpn,
+ IF_SIGCOMP_TPTAG_COMPARTMENT(cc)
+ TPTAG_MTU(INT_MAX), ta_tags(ta), TAG_END())) {
+ agent->sa_stats->as_sent_msg++;
+ agent->sa_stats->as_sent_response++;
+ retval = 0;
+ }
+ else {
+ SU_DEBUG_3(("%s: send fails\n", what));
+ }
+ }
+ }
+ else {
+ /* Send request */
+ if (outgoing_create(agent, NULL, NULL, u, NULL, msg_ref_create(msg),
+ NTATAG_STATELESS(1),
+ ta_tags(ta)))
+ retval = 0;
+ }
+
+ if (retval == 0)
+ SU_DEBUG_5(("%s\n", what));
+
+ ta_end(ta);
+
+ msg_destroy(msg);
+
+ return retval;
+}
+
+/** Reply to a request message.
+ *
+ * @param agent nta agent object
+ * @param req_msg request message
+ * @param status status code
+ * @param phrase status phrase (may be NULL if status code is well-known)
+ * @param tag, value, ... optional additional headers terminated by TAG_END()
+ *
+ * @retval 0 when succesful
+ * @retval -1 upon an error
+ *
+ * @note
+ * The ownership of @a msg is taken over by the function even if the
+ * function fails.
+ */
+int nta_msg_treply(nta_agent_t *agent,
+ msg_t *req_msg,
+ int status, char const *phrase,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ int retval;
+ ta_list ta;
+
+ ta_start(ta, tag, value);
+
+ retval = nta_msg_mreply(agent, NULL, NULL, status, phrase, req_msg,
+ ta_tags(ta));
+ ta_end(ta);
+
+ return retval;
+}
+
+/**Reply to the request message.
+ *
+ * @note
+ * The ownership of @a msg is taken over by the function even if the
+ * function fails.
+ */
+int nta_msg_mreply(nta_agent_t *agent,
+ msg_t *reply, sip_t *sip,
+ int status, char const *phrase,
+ msg_t *req_msg,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ ta_list ta;
+ tp_name_t tpn[1];
+ int retval = -1;
+ tport_t *tport = NULL;
+ struct sigcomp_compartment *cc = NONE;
+ int *use_rport = NULL;
+ int retry_without_rport = 0, incomplete = 0;
+
+ if (!agent)
+ return -1;
+
+ if (agent->sa_server_rport)
+ use_rport = &retry_without_rport, retry_without_rport = 1;
+
+ ta_start(ta, tag, value);
+
+ tl_gets(ta_args(ta),
+ NTATAG_TPORT_REF(tport),
+ NTATAG_INCOMPLETE_REF(incomplete),
+ TPTAG_COMPARTMENT_REF(cc),
+ TAG_END());
+
+ if (reply == NULL) {
+ reply = nta_msg_create(agent, 0);
+ sip = sip_object(reply);
+ }
+
+ if (!sip) {
+ SU_DEBUG_3(("%s: no msg\n", __func__));
+ }
+ else if (sip_add_tl(reply, sip, ta_tags(ta)) < 0) {
+ SU_DEBUG_3(("%s: cannot add user headers\n", __func__));
+ }
+ else if (complete_response(reply, status, phrase, req_msg) < 0 &&
+ !incomplete) {
+ SU_DEBUG_3(("%s: cannot complete message\n", __func__));
+ }
+ else if (sip->sip_status && sip->sip_status->st_status > 100 &&
+ sip->sip_to && !sip->sip_to->a_tag &&
+ sip->sip_cseq && sip->sip_cseq->cs_method != sip_method_cancel &&
+ sip_to_tag(msg_home(reply), sip->sip_to,
+ nta_agent_newtag(msg_home(reply), "tag=%s", agent)) < 0) {
+ SU_DEBUG_3(("%s: cannot add To tag\n", __func__));
+ }
+ else if (nta_tpn_by_via(tpn, sip->sip_via, use_rport) < 0) {
+ SU_DEBUG_3(("%s: no Via\n", __func__));
+ }
+ else {
+ if (tport == NULL)
+ tport = tport_delivered_by(agent->sa_tports, req_msg);
+
+ if (!tport) {
+ tport_t *primary = tport_by_protocol(agent->sa_tports, tpn->tpn_proto);
+
+ tport = tport_by_name(primary, tpn);
+
+ if (!tport)
+ tport = primary;
+ }
+
+ if (retry_without_rport)
+ tpn->tpn_port = sip_via_port(sip->sip_via, NULL);
+
+ if (tport && tpn->tpn_comp) {
+ if (cc == NONE)
+ cc = agent_compression_compartment(agent, tport, tpn, -1);
+
+ if (cc != NULL && cc != NONE &&
+ tport_delivered_with_comp(tport, req_msg, NULL) != -1) {
+ agent_accept_compressed(agent, req_msg, cc);
+ }
+ }
+
+ if (tport_tsend(tport, reply, tpn,
+ IF_SIGCOMP_TPTAG_COMPARTMENT(cc)
+ TPTAG_MTU(INT_MAX), ta_tags(ta))) {
+ agent->sa_stats->as_sent_msg++;
+ agent->sa_stats->as_sent_response++;
+ retval = 0; /* Success! */
+ }
+ else {
+ SU_DEBUG_3(("%s: send fails\n", __func__));
+ }
+ }
+
+ msg_destroy(reply);
+ msg_destroy(req_msg);
+
+ ta_end(ta);
+
+ return retval;
+}
+
+/** Add headers from the request to the response message. */
+static
+int complete_response(msg_t *response,
+ int status, char const *phrase,
+ msg_t const *request)
+{
+ su_home_t *home = msg_home(response);
+ sip_t *response_sip = sip_object(response);
+ sip_t const *request_sip = sip_object(request);
+
+ int incomplete = 0;
+
+ if (!response_sip || !request_sip || !request_sip->sip_request)
+ return -1;
+
+ if (!response_sip->sip_status)
+ response_sip->sip_status = sip_status_create(home, status, phrase, NULL);
+ if (!response_sip->sip_via)
+ response_sip->sip_via = sip_via_dup(home, request_sip->sip_via);
+ if (!response_sip->sip_from)
+ response_sip->sip_from = sip_from_dup(home, request_sip->sip_from);
+ if (!response_sip->sip_to)
+ response_sip->sip_to = sip_to_dup(home, request_sip->sip_to);
+ if (!response_sip->sip_call_id)
+ response_sip->sip_call_id =
+ sip_call_id_dup(home, request_sip->sip_call_id);
+ if (!response_sip->sip_cseq)
+ response_sip->sip_cseq = sip_cseq_dup(home, request_sip->sip_cseq);
+
+ if (!response_sip->sip_record_route && request_sip->sip_record_route)
+ sip_add_dup(response, response_sip, (void*)request_sip->sip_record_route);
+
+ incomplete = sip_complete_message(response) < 0;
+
+ msg_serialize(response, (msg_pub_t *)response_sip);
+
+ if (incomplete ||
+ !response_sip->sip_status ||
+ !response_sip->sip_via ||
+ !response_sip->sip_from ||
+ !response_sip->sip_to ||
+ !response_sip->sip_call_id ||
+ !response_sip->sip_cseq ||
+ !response_sip->sip_content_length ||
+ !response_sip->sip_separator ||
+ (request_sip->sip_record_route && !response_sip->sip_record_route))
+ return -1;
+
+ return 0;
+}
+
+/** ACK and BYE an unknown 200 OK response to INVITE.
+ *
+ * A UAS may still return a 2XX series response to an INVITE request after
+ * the client transaction has been terminated. In that case, the UAC can not
+ * really accept the call, but it may send a ACK request to UAS followed
+ * immediately by BYE using nta_msg_ackbye(). The function does not create a
+ * transaction objects, but just sends the ACK and BYE request messages
+ * according to the @RecordRoute and @Contact headers in the @a msg.
+ */
+int nta_msg_ackbye(nta_agent_t *agent, msg_t *msg)
+{
+ sip_t *sip = sip_object(msg);
+ msg_t *amsg = nta_msg_create(agent, 0);
+ sip_t *asip = sip_object(amsg);
+ msg_t *bmsg = NULL;
+ sip_t *bsip;
+ url_string_t const *ruri;
+ nta_outgoing_t *ack = NULL, *bye = NULL;
+ sip_cseq_t *cseq;
+ sip_request_t *rq;
+ sip_route_t *route = NULL, *r, r0[1];
+ su_home_t *home = msg_home(amsg);
+
+ if (asip == NULL)
+ return -1;
+
+ sip_add_tl(amsg, asip,
+ SIPTAG_TO(sip->sip_to),
+ SIPTAG_FROM(sip->sip_from),
+ SIPTAG_CALL_ID(sip->sip_call_id),
+ TAG_END());
+
+ if (sip->sip_contact) {
+ ruri = (url_string_t const *)sip->sip_contact->m_url;
+ } else {
+ ruri = (url_string_t const *)sip->sip_to->a_url;
+ }
+
+ /* Reverse (and fix) record route */
+ route = sip_route_reverse(home, sip->sip_record_route);
+
+ if (route && !url_has_param(route->r_url, "lr")) {
+ for (r = route; r->r_next; r = r->r_next)
+ ;
+
+ /* Append r-uri */
+ *sip_route_init(r0)->r_url = *ruri->us_url;
+ r->r_next = sip_route_dup(home, r0);
+
+ /* Use topmost route as request-uri */
+ ruri = (url_string_t const *)route->r_url;
+ route = route->r_next;
+ }
+
+ msg_header_insert(amsg, (msg_pub_t *)asip, (msg_header_t *)route);
+
+ bmsg = msg_copy(amsg); bsip = sip_object(bmsg);
+
+ if (!(cseq = sip_cseq_create(home, sip->sip_cseq->cs_seq, SIP_METHOD_ACK)))
+ goto err;
+ else
+ msg_header_insert(amsg, (msg_pub_t *)asip, (msg_header_t *)cseq);
+
+ if (!(rq = sip_request_create(home, SIP_METHOD_ACK, ruri, NULL)))
+ goto err;
+ else
+ msg_header_insert(amsg, (msg_pub_t *)asip, (msg_header_t *)rq);
+
+ if (!(ack = nta_outgoing_mcreate(agent, NULL, NULL, NULL, amsg,
+ NTATAG_ACK_BRANCH(sip->sip_via->v_branch),
+ NTATAG_STATELESS(1),
+ TAG_END())))
+ goto err;
+ else
+ nta_outgoing_destroy(ack);
+
+ home = msg_home(bmsg);
+
+ if (!(cseq = sip_cseq_create(home, 0x7fffffff, SIP_METHOD_BYE)))
+ goto err;
+ else
+ msg_header_insert(bmsg, (msg_pub_t *)bsip, (msg_header_t *)cseq);
+
+ if (!(rq = sip_request_create(home, SIP_METHOD_BYE, ruri, NULL)))
+ goto err;
+ else
+ msg_header_insert(bmsg, (msg_pub_t *)bsip, (msg_header_t *)rq);
+
+ if (!(bye = nta_outgoing_mcreate(agent, NULL, NULL, NULL, bmsg,
+ NTATAG_STATELESS(1),
+ TAG_END())))
+ goto err;
+
+ msg_destroy(msg);
+ return 0;
+
+ err:
+ msg_destroy(amsg);
+ msg_destroy(bmsg);
+ return -1;
+}
+
+/**Complete a request with values from dialog.
+ *
+ * The function nta_msg_request_complete() completes a request message @a
+ * msg belonging to a dialog associated with @a leg. It increments the local
+ * @CSeq value, adds @CallID, @To, @From and @Route headers (if
+ * there is such headers present in @a leg), and creates a new request line
+ * object from @a method, @a method_name and @a request_uri.
+ *
+ * @param msg pointer to a request message object
+ * @param leg pointer to a #nta_leg_t object
+ * @param method request method number or #sip_method_unknown
+ * @param method_name method name (if @a method == #sip_method_unknown)
+ * @param request_uri request URI
+ *
+ * If @a request_uri contains query part, the query part is converted as SIP
+ * headers and added to the request.
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error
+ *
+ * @sa nta_outgoing_mcreate(), nta_outgoing_tcreate()
+ */
+int nta_msg_request_complete(msg_t *msg,
+ nta_leg_t *leg,
+ sip_method_t method,
+ char const *method_name,
+ url_string_t const *request_uri)
+{
+ su_home_t *home = msg_home(msg);
+ sip_t *sip = sip_object(msg);
+ sip_to_t const *to;
+ sip_cseq_t *cseq;
+ uint32_t seq;
+ url_t reg_url[1];
+ url_string_t const *original = request_uri;
+
+ if (!leg || !msg)
+ return -1;
+
+ if (!sip->sip_route && leg->leg_route) {
+ if (leg->leg_loose_route) {
+ if (leg->leg_target) {
+ request_uri = (url_string_t *)leg->leg_target->m_url;
+ }
+ sip->sip_route = sip_route_dup(home, leg->leg_route);
+ }
+ else {
+ sip_route_t **rr;
+
+ request_uri = (url_string_t *)leg->leg_route->r_url;
+ sip->sip_route = sip_route_dup(home, leg->leg_route->r_next);
+
+ for (rr = &sip->sip_route; *rr; rr = &(*rr)->r_next)
+ ;
+
+ if (leg->leg_target)
+ *rr = sip_route_dup(home, (sip_route_t *)leg->leg_target);
+ }
+ }
+ else if (leg->leg_target)
+ request_uri = (url_string_t *)leg->leg_target->m_url;
+
+ if (!request_uri && sip->sip_request)
+ request_uri = (url_string_t *)sip->sip_request->rq_url;
+
+ to = sip->sip_to ? sip->sip_to : leg->leg_remote;
+
+ if (!request_uri && to) {
+ if (method != sip_method_register)
+ request_uri = (url_string_t *)to->a_url;
+ else {
+ /* Remove user part from REGISTER requests */
+ *reg_url = *to->a_url;
+ reg_url->url_user = reg_url->url_password = NULL;
+ request_uri = (url_string_t *)reg_url;
+ }
+ }
+
+ if (!request_uri)
+ return -1;
+
+ if (method || method_name) {
+ sip_request_t *rq = sip->sip_request;
+ int use_headers =
+ request_uri == original || (url_t *)request_uri == rq->rq_url;
+
+ if (!rq
+ || request_uri != (url_string_t *)rq->rq_url
+ || method != rq->rq_method
+ || str0cmp(method_name, rq->rq_method_name))
+ rq = NULL;
+
+ if (rq == NULL) {
+ rq = sip_request_create(home, method, method_name, request_uri, NULL);
+ if (msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)rq) < 0)
+ return -1;
+ }
+
+ /* @RFC3261 table 1 (page 152):
+ * Req-URI cannot contain method parameter or headers
+ */
+ if (rq->rq_url->url_params) {
+ rq->rq_url->url_params =
+ url_strip_param_string((char *)rq->rq_url->url_params, "method");
+ sip_fragment_clear(rq->rq_common);
+ }
+
+ if (rq->rq_url->url_headers) {
+ if (use_headers) {
+ char *s = url_query_as_header_string(msg_home(msg),
+ rq->rq_url->url_headers);
+ if (!s)
+ return -1;
+ msg_header_parse_str(msg, (msg_pub_t*)sip, s);
+ }
+ rq->rq_url->url_headers = NULL, sip_fragment_clear(rq->rq_common);
+ }
+ }
+
+ if (!sip->sip_request)
+ return -1;
+
+ if (!sip->sip_max_forwards)
+ sip_add_dup(msg, sip, (sip_header_t *)leg->leg_agent->sa_max_forwards);
+
+ if (!sip->sip_call_id) {
+ if (leg->leg_id)
+ sip->sip_call_id = sip_call_id_dup(home, leg->leg_id);
+ else
+ sip->sip_call_id = sip_call_id_create(home, NULL);
+ }
+
+ if (!sip->sip_from)
+ sip->sip_from = sip_from_dup(home, leg->leg_local);
+ else if (leg->leg_local && leg->leg_local->a_tag &&
+ (!sip->sip_from->a_tag ||
+ strcasecmp(sip->sip_from->a_tag, leg->leg_local->a_tag)))
+ sip_from_tag(home, sip->sip_from, leg->leg_local->a_tag);
+
+ if (sip->sip_from && !sip->sip_from->a_tag) {
+ sip_fragment_clear(sip->sip_from->a_common);
+ sip_from_add_param(home, sip->sip_from,
+ nta_agent_newtag(home, "tag=%s", leg->leg_agent));
+ }
+
+ if (sip->sip_to) {
+ if (leg->leg_remote && leg->leg_remote->a_tag)
+ sip_to_tag(home, sip->sip_to, leg->leg_remote->a_tag);
+ }
+ else if (leg->leg_remote) {
+ sip->sip_to = sip_to_dup(home, leg->leg_remote);
+ }
+ else {
+ sip_to_t *to = sip_to_create(home, request_uri);
+ if (to) sip_aor_strip(to->a_url);
+ sip->sip_to = to;
+ }
+
+ if (!sip->sip_from || !sip->sip_from || !sip->sip_to)
+ return -1;
+
+ method = sip->sip_request->rq_method;
+ method_name = sip->sip_request->rq_method_name;
+
+ if (method == sip_method_ack || method == sip_method_cancel)
+ seq = sip->sip_cseq ? sip->sip_cseq->cs_seq : leg->leg_seq;
+ else if (leg->leg_seq)
+ seq = ++leg->leg_seq;
+ else if (sip->sip_cseq) /* Obtain initial value from existing CSeq header */
+ seq = leg->leg_seq = sip->sip_cseq->cs_seq;
+ else
+ seq = leg->leg_seq = (sip_now() >> 1) & 0x7ffffff;
+
+ if ((!sip->sip_cseq ||
+ seq != sip->sip_cseq->cs_seq ||
+ method != sip->sip_cseq->cs_method ||
+ (method == sip_method_unknown &&
+ strcmp(method_name, sip->sip_cseq->cs_method_name) != 0)) &&
+ (!(cseq = sip_cseq_create(home, seq, method, method_name)) ||
+ msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)cseq) < 0))
+ return -1;
+
+ return 0;
+}
+
+/* ====================================================================== */
+/* 6) Dialogs (legs) */
+
+static void leg_insert(nta_agent_t *agent, nta_leg_t *leg);
+static int leg_route(nta_leg_t *leg,
+ sip_record_route_t const *route,
+ sip_record_route_t const *reverse,
+ sip_contact_t const *contact);
+static int leg_callback_default(nta_leg_magic_t*, nta_leg_t*,
+ nta_incoming_t*, sip_t const *);
+#define HTABLE_HASH_LEG(leg) ((leg)->leg_hash)
+HTABLE_BODIES_WITH(leg_htable, lht, nta_leg_t, HTABLE_HASH_LEG, size_t, hash_value_t);
+static inline
+hash_value_t hash_istring(char const *, char const *, hash_value_t);
+
+/**@typedef nta_request_f
+ *
+ * Callback for incoming requests
+ *
+ * This is a callback function invoked by NTA for each incoming SIP request.
+ *
+ * @param lmagic call leg context
+ * @param leg call leg handle
+ * @param ireq incoming request
+ * @param sip incoming request contents
+ *
+ * @retval 100..699
+ * NTA constructs a reply message with given error code and corresponding
+ * standard phrase, then sends the reply.
+ *
+ * @retval 0
+ * The application takes care of sending (or not sending) the reply.
+ *
+ * @retval other
+ * All other return values will be interpreted as
+ * @e 500 @e Internal @e server @e error.
+ */
+
+
+/**
+ * Create a new leg object.
+ *
+ * The function nta_leg_tcreate() creates a leg object. A leg object is used
+ * to represent dialogs, partial dialogs (for example, in case of REGISTER),
+ * and destinations within a particular NTA object.
+ *
+ * When a leg is created, a callback pointer and a application context is
+ * provided. All other parameters are optional.
+ *
+ * @param agent agent object
+ * @param callback function which is called for each
+ * incoming request belonging to this leg
+ * @param magic call leg context
+ * @param tag,value,... optional extra headers in taglist
+ *
+ * When a leg representing dialog is created, the tags SIPTAG_CALL_ID(),
+ * SIPTAG_FROM(), SIPTAG_TO(), and SIPTAG_CSEQ() (for local @CSeq number) are used
+ * to establish dialog context. The SIPTAG_FROM() is used to pass local
+ * address (@From header when making a call, @To header when answering
+ * to a call) to the newly created leg. Respectively, the SIPTAG_TO() is
+ * used to pass remote address (@To header when making a call, @From
+ * header when answering to a call).
+ *
+ * If there is a (preloaded) route associated with the leg, SIPTAG_ROUTE()
+ * and NTATAG_TARGET() can be used. A client or server can also set the
+ * route using @RecordRoute and @Contact headers from a response or
+ * request message with the functions nta_leg_client_route() and
+ * nta_leg_server_route(), respectively.
+ *
+ * When a leg representing a local destination is created, the tags
+ * NTATAG_NO_DIALOG(1), NTATAG_METHOD(), and URLTAG_URL() are used. When a
+ * request with matching request-URI (URLTAG_URL()) and method
+ * (NTATAG_METHOD()) is received, it is passed to the callback function
+ * provided with the leg.
+ *
+ * @sa nta_leg_stateful(), nta_leg_bind(),
+ * nta_leg_tag(), nta_leg_rtag(),
+ * nta_leg_client_route(), nta_leg_server_route(),
+ * nta_leg_destroy(), nta_outgoing_tcreate(), and nta_request_f().
+ *
+ * @TAGS
+ * NTATAG_NO_DIALOG(), NTATAG_STATELESS(), NTATAG_METHOD(),
+ * URLTAG_URL(), SIPTAG_CALL_ID(), SIPTAG_CALL_ID_STR(), SIPTAG_FROM(),
+ * SIPTAG_FROM_STR(), SIPTAG_TO(), SIPTAG_TO_STR(), SIPTAG_ROUTE(),
+ * NTATAG_TARGET() and SIPTAG_CSEQ().
+ *
+ */
+nta_leg_t *nta_leg_tcreate(nta_agent_t *agent,
+ nta_request_f *callback,
+ nta_leg_magic_t *magic,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ sip_route_t const *route = NULL;
+ sip_contact_t const *contact = NULL;
+ sip_cseq_t const *cs = NULL;
+ sip_call_id_t const *i = NULL;
+ sip_from_t const *from = NULL;
+ sip_to_t const *to = NULL;
+ char const *method = NULL;
+ char const *i_str = NULL, *to_str = NULL, *from_str = NULL, *cs_str = NULL;
+ url_string_t const *url_string = NULL;
+ int no_dialog = 0;
+ unsigned rseq = 0;
+ /* RFC 3261 section 12.2.1.1 */
+ uint32_t seq = 0;
+ ta_list ta;
+ nta_leg_t *leg;
+ su_home_t *home;
+ url_t *url;
+
+ if (agent == NULL)
+ return su_seterrno(EINVAL), NULL;
+
+ ta_start(ta, tag, value);
+
+ tl_gets(ta_args(ta),
+ NTATAG_NO_DIALOG_REF(no_dialog),
+ NTATAG_METHOD_REF(method),
+ URLTAG_URL_REF(url_string),
+ SIPTAG_CALL_ID_REF(i),
+ SIPTAG_CALL_ID_STR_REF(i_str),
+ SIPTAG_FROM_REF(from),
+ SIPTAG_FROM_STR_REF(from_str),
+ SIPTAG_TO_REF(to),
+ SIPTAG_TO_STR_REF(to_str),
+ SIPTAG_ROUTE_REF(route),
+ NTATAG_TARGET_REF(contact),
+ NTATAG_REMOTE_CSEQ_REF(rseq),
+ SIPTAG_CSEQ_REF(cs),
+ SIPTAG_CSEQ_STR_REF(cs_str),
+ TAG_END());
+
+ ta_end(ta);
+
+ if (cs)
+ seq = cs->cs_seq;
+ else if (cs_str)
+ seq = strtoul(cs_str, (char **)&cs_str, 10);
+
+ if (i == NONE) /* Magic value, used for compatibility */
+ no_dialog = 1;
+
+ if (!(leg = su_home_clone(agent->sa_home, sizeof(*leg))))
+ return NULL;
+ home = leg->leg_home;
+
+ leg->leg_agent = agent;
+ nta_leg_bind(leg, callback, magic);
+
+ if (from) {
+ /* Now this is kludge */
+ leg->leg_local_is_to = sip_is_to((sip_header_t*)from);
+ leg->leg_local = sip_to_dup(home, from);
+ }
+ else if (from_str)
+ leg->leg_local = sip_to_make(home, from_str);
+
+ if (to && no_dialog) {
+ /* Remove tag, if any */
+ sip_to_t to0[1]; *to0 = *to; to0->a_params = NULL;
+ leg->leg_remote = sip_from_dup(home, to0);
+ }
+ else if (to)
+ leg->leg_remote = sip_from_dup(home, to);
+ else if (to_str)
+ leg->leg_remote = sip_from_make(home, to_str);
+
+ if (route && route != NONE)
+ leg->leg_route = sip_route_dup(home, route);
+
+ if (contact && contact != NONE) {
+ sip_contact_t m[1];
+ sip_contact_init(m);
+ *m->m_url = *contact->m_url;
+ m->m_url->url_headers = NULL;
+ leg->leg_target = sip_contact_dup(home, m);
+ }
+
+ url = url_hdup(home, url_string->us_url);
+
+ /* Match to local hosts */
+ if (url && agent_aliases(agent, url, NULL)) {
+ url_t *changed = url_hdup(home, url);
+ su_free(home, url);
+ url = changed;
+ }
+
+ leg->leg_rseq = rseq;
+ leg->leg_seq = seq;
+ leg->leg_url = url;
+
+ if (from && from != NONE && leg->leg_local == NULL) {
+ SU_DEBUG_3(("nta_leg_tcreate(): cannot duplicate local address\n"));
+ goto err;
+ }
+ else if (to && to != NONE && leg->leg_remote == NULL) {
+ SU_DEBUG_3(("nta_leg_tcreate(): cannot duplicate remote address\n"));
+ goto err;
+ }
+ else if (route && route != NONE && leg->leg_route == NULL) {
+ SU_DEBUG_3(("nta_leg_tcreate(): cannot duplicate route\n"));
+ goto err;
+ }
+ else if (contact && contact != NONE && leg->leg_target == NULL) {
+ SU_DEBUG_3(("nta_leg_tcreate(): cannot duplicate target\n"));
+ goto err;
+ }
+ else if (url_string && leg->leg_url == NULL) {
+ SU_DEBUG_3(("nta_leg_tcreate(): cannot duplicate local destination\n"));
+ goto err;
+ }
+
+ if (!no_dialog) {
+ if (!leg->leg_local || !leg->leg_remote) {
+ /* To and/or From header missing */
+ SU_DEBUG_3(("nta_leg_tcreate(): missing%s%s header\n",
+ !leg->leg_remote ? " To" : "",
+ !leg->leg_local ? " From" : ""));
+ goto err;
+ }
+
+ leg->leg_dialog = 1;
+
+ if (i != NULL)
+ leg->leg_id = sip_call_id_dup(home, i);
+ else if (i_str != NULL)
+ leg->leg_id = sip_call_id_make(home, i_str);
+ else
+ leg->leg_id = sip_call_id_create(home, NULL);
+
+ if (!leg->leg_id) {
+ SU_DEBUG_3(("nta_leg_tcreate(): cannot create Call-ID\n"));
+ goto err;
+ }
+
+ leg->leg_hash = leg->leg_id->i_hash;
+ }
+ else if (url) {
+ /* This is "default leg" with a destination URL. */
+ hash_value_t hash = 0;
+
+ if (method) {
+ leg->leg_method = su_strdup(home, method);
+ }
+#if 0
+ else if (url->url_params) {
+ int len = url_param(url->url_params, "method", NULL, 0);
+ if (len) {
+ char *tmp = su_alloc(home, len);
+ leg->leg_method = tmp;
+ url_param(url->url_params, "method", tmp, len);
+ }
+ }
+#endif
+
+ if (url->url_user && strcmp(url->url_user, "") == 0)
+ url->url_user = "%"; /* Match to any user */
+
+ hash = hash_istring(url->url_scheme, ":", 0);
+ hash = hash_istring(url->url_host, "", hash);
+ hash = hash_istring(url->url_user, "@", hash);
+
+ leg->leg_hash = hash;
+ }
+ else {
+ /* This is "default leg" without a destination URL. */
+ if (agent->sa_default_leg) {
+ SU_DEBUG_1(("leg_create(): tried to create second default leg\n"));
+ su_seterrno(EEXIST);
+ goto err;
+ }
+ else {
+ agent->sa_default_leg = leg;
+ }
+ return leg;
+ }
+
+ if (url) {
+ /* Parameters are ignored when comparing incoming URLs */
+ url->url_params = NULL;
+ }
+
+ leg_insert(agent, leg);
+
+ SU_DEBUG_9(("nta_leg_create(%p)\n", leg));
+
+ return leg;
+
+ err:
+ su_home_zap(leg->leg_home);
+
+ return NULL;
+}
+
+/** Return the default leg, if any */
+nta_leg_t *nta_default_leg(nta_agent_t const *agent)
+{
+ return agent ? agent->sa_default_leg : NULL;
+}
+
+
+/**
+ * Insert a call leg to agent.
+ */
+static
+void leg_insert(nta_agent_t *sa, nta_leg_t *leg)
+{
+ leg_htable_t *leg_hash;
+ assert(leg);
+ assert(sa);
+
+ if (leg->leg_dialog)
+ leg_hash = sa->sa_dialogs;
+ else
+ leg_hash = sa->sa_defaults;
+
+ if (leg_htable_is_full(leg_hash)) {
+ leg_htable_resize(sa->sa_home, leg_hash, 0);
+ assert(leg_hash->lht_table);
+ SU_DEBUG_7(("nta: resized%s leg hash to "MOD_ZU"\n",
+ leg->leg_dialog ? "" : " default", leg_hash->lht_size));
+ }
+
+ /* Insert entry into hash table (before other legs with same hash) */
+ leg_htable_insert(leg_hash, leg);
+}
+
+/**
+ * Destroy a leg.
+ *
+ * @param leg leg to be destroyed
+ */
+void nta_leg_destroy(nta_leg_t *leg)
+{
+ SU_DEBUG_9(("nta_leg_destroy(%p)\n", leg));
+
+ if (leg) {
+ leg_htable_t *leg_hash;
+ nta_agent_t *sa = leg->leg_agent;
+
+ assert(sa);
+
+ if (leg->leg_dialog) {
+ assert(sa->sa_dialogs);
+ leg_hash = sa->sa_dialogs;
+ }
+ else if (leg != sa->sa_default_leg) {
+ assert(sa->sa_defaults);
+ leg_hash = sa->sa_defaults;
+ }
+ else {
+ sa->sa_default_leg = NULL;
+ leg_hash = NULL;
+ }
+
+ if (leg_hash)
+ leg_htable_remove(leg_hash, leg);
+
+ leg_free(sa, leg);
+ }
+}
+
+static
+void leg_free(nta_agent_t *sa, nta_leg_t *leg)
+{
+ su_free(sa->sa_home, leg);
+}
+
+/** Return application context for the leg */
+nta_leg_magic_t *nta_leg_magic(nta_leg_t const *leg,
+ nta_request_f *callback)
+{
+ if (leg)
+ if (!callback || leg->leg_callback == callback)
+ return leg->leg_magic;
+
+ return NULL;
+}
+
+/**Bind a callback function and context to a leg object.
+ *
+ * The function nta_leg_bind() is used to change the callback
+ * and context pointer attached to a leg object.
+ *
+ * @param leg leg object to be bound
+ * @param callback new callback function (or NULL if no callback is desired)
+ * @param magic new context pointer
+ */
+void nta_leg_bind(nta_leg_t *leg,
+ nta_request_f *callback,
+ nta_leg_magic_t *magic)
+{
+ if (leg) {
+ if (callback)
+ leg->leg_callback = callback;
+ else
+ leg->leg_callback = leg_callback_default;
+ leg->leg_magic = magic;
+ }
+}
+
+/** Add a local tag to the leg.
+ *
+ * @param leg leg to be tagged
+ * @param tag tag to be added (if NULL, a tag generated by @b NTA is added)
+ *
+ * @return
+ * Pointer to tag if successful, NULL otherwise.
+ */
+char const *nta_leg_tag(nta_leg_t *leg, char const *tag)
+{
+ if (!leg || !leg->leg_local)
+ return su_seterrno(EINVAL), NULL;
+
+ if (tag && strchr(tag, '='))
+ tag = strchr(tag, '=') + 1;
+
+ /* If there already is a tag,
+ return NULL if it does not match with new one */
+ if (leg->leg_local->a_tag) {
+ if (!tag && str0casecmp(tag, leg->leg_local->a_tag))
+ return NULL;
+ else
+ return leg->leg_local->a_tag;
+ }
+
+ if (tag) {
+ if (sip_to_tag(leg->leg_home, leg->leg_local, tag) < 0)
+ return NULL;
+ return leg->leg_local->a_tag;
+ }
+
+ tag = nta_agent_newtag(leg->leg_home, "tag=%s", leg->leg_agent);
+
+ if (!tag || sip_to_add_param(leg->leg_home, leg->leg_local, tag) < 0)
+ return NULL;
+
+ return leg->leg_local->a_tag;
+}
+
+/** Get local tag. */
+char const *nta_leg_get_tag(nta_leg_t const *leg)
+{
+ if (leg && leg->leg_local)
+ return leg->leg_local->a_tag;
+ else
+ return NULL;
+}
+
+/** Add a remote tag to the leg.
+ *
+ * @note No remote tag is ever generated.
+ *
+ * @param leg leg to be tagged
+ * @param tag tag to be added (@b must be non-NULL)
+ *
+ * @return
+ * Pointer to tag if successful, NULL otherwise.
+ */
+char const *nta_leg_rtag(nta_leg_t *leg, char const *tag)
+{
+ /* Add a tag parameter, unless there already is a tag */
+ if (leg && leg->leg_remote && tag) {
+ if (sip_from_tag(leg->leg_home, leg->leg_remote, tag) < 0)
+ return NULL;
+ }
+
+ if (leg && leg->leg_remote)
+ return leg->leg_remote->a_tag;
+ else
+ return NULL;
+}
+
+/** Get remote tag. */
+char const *nta_leg_get_rtag(nta_leg_t const *leg)
+{
+ if (leg && leg->leg_remote)
+ return leg->leg_remote->a_tag;
+ else
+ return NULL;
+}
+
+/** Save target and route set at UAC side.
+ *
+ * @sa nta_leg_server_route(), @RFC3261 section 12.1.2
+ */
+int nta_leg_client_route(nta_leg_t *leg,
+ sip_record_route_t const *route,
+ sip_contact_t const *contact)
+{
+ return leg_route(leg, NULL, route, contact);
+}
+
+/** Save target and route set at UAS side.
+ *
+ * @sa nta_leg_client_route(), @RFC3261 section 12.1.1
+ */
+int nta_leg_server_route(nta_leg_t *leg,
+ sip_record_route_t const *route,
+ sip_contact_t const *contact)
+{
+ return leg_route(leg, route, NULL, contact);
+}
+
+/** Return route components. */
+int nta_leg_get_route(nta_leg_t *leg,
+ sip_route_t const **return_route,
+ sip_contact_t const **return_target)
+{
+ if (!leg)
+ return -1;
+
+ if (return_route)
+ *return_route = leg->leg_route;
+
+ if (return_target)
+ *return_target = leg->leg_target;
+
+ return 0;
+}
+
+/** Generate @Replaces header.
+ *
+ * @since New in @VERSION_1_12_2.
+ */
+SOFIAPUBFUN
+sip_replaces_t *nta_leg_make_replaces(nta_leg_t *leg,
+ su_home_t *home,
+ int early_only)
+{
+ char const *from_tag, *to_tag;
+
+ if (!leg)
+ return NULL;
+ if (!leg->leg_dialog || !leg->leg_local || !leg->leg_remote || !leg->leg_id)
+ return NULL;
+
+ from_tag = leg->leg_local->a_tag; if (!from_tag) from_tag = "0";
+ to_tag = leg->leg_remote->a_tag; if (!to_tag) to_tag = "0";
+
+ return sip_replaces_format(home, "%s;from-tag=%s;to-tag=%s%s",
+ leg->leg_id->i_id, from_tag, to_tag,
+ early_only ? ";early-only" : "");
+}
+
+/** Get dialog leg by @Replaces header.
+ *
+ * @since New in @VERSION_1_12_2.
+ */
+SOFIAPUBFUN
+nta_leg_t *nta_leg_by_replaces(nta_agent_t *sa, sip_replaces_t const *rp)
+{
+ nta_leg_t *leg = NULL;
+
+ if (sa && rp && rp->rp_call_id && rp->rp_from_tag && rp->rp_to_tag) {
+ char const *from_tag = rp->rp_from_tag, *to_tag = rp->rp_to_tag;
+ sip_call_id_t id[1];
+ sip_call_id_init(id);
+
+ id->i_hash = msg_hash_string(id->i_id = rp->rp_call_id);
+
+ leg = leg_find(sa, NULL, NULL, id, from_tag, NULL, to_tag, NULL);
+
+ if (leg == NULL && strcmp(from_tag, "0") == 0)
+ leg = leg_find(sa, NULL, NULL, id, NULL, NULL, to_tag, NULL);
+ if (leg == NULL && strcmp(to_tag, "0") == 0)
+ leg = leg_find(sa, NULL, NULL, id, from_tag, NULL, NULL, NULL);
+ }
+
+ return leg;
+}
+
+/** Calculate a simple case-insensitive hash over a string */
+static inline
+hash_value_t hash_istring(char const *s, char const *term, hash_value_t hash)
+{
+ if (s) {
+ for (; *s; s++) {
+ unsigned char c = *s;
+ if ('A' <= c && c <= 'Z')
+ c += 'a' - 'A';
+ hash = 38501U * (hash + c);
+ }
+ for (s = term; *s; s++) {
+ unsigned char c = *s;
+ hash = 38501U * (hash + c);
+ }
+ }
+
+ return hash;
+}
+
+/** @internal Handle requests intended for this leg. */
+static
+void leg_recv(nta_leg_t *leg, msg_t *msg, sip_t *sip, tport_t *tport)
+{
+ nta_agent_t *agent = leg->leg_agent;
+ nta_incoming_t *irq;
+ sip_method_t method = sip->sip_request->rq_method;
+ char const *method_name = sip->sip_request->rq_method_name;
+ char const *tag = NULL;
+ int status;
+
+ if (leg->leg_local)
+ tag = leg->leg_local->a_tag;
+
+ if (leg->leg_dialog)
+ agent->sa_stats->as_dialog_tr++;
+
+ /* RFC-3262 section 3 (page 4) */
+ if (agent->sa_is_a_uas && method == sip_method_prack) {
+ nta_msg_treply(agent, msg,
+ 481, "No such response",
+ NTATAG_TPORT(tport),
+ TAG_END());
+ return;
+ }
+
+ if (!(irq = incoming_create(agent, msg, sip, tport, tag))) {
+ SU_DEBUG_3(("nta: leg_recv(%p): cannot create transaction for %s\n",
+ leg, method_name));
+ nta_msg_treply(agent, msg,
+ SIP_500_INTERNAL_SERVER_ERROR,
+ NTATAG_TPORT(tport),
+ TAG_END());
+ return;
+ }
+
+ irq->irq_in_callback = 1;
+ status = incoming_callback(leg, irq, sip);
+ irq->irq_in_callback = 0;
+
+ if (irq->irq_destroyed) {
+ if (irq->irq_terminated) {
+ incoming_free(irq);
+ return;
+ }
+ if (status < 200)
+ status = 500;
+ }
+
+ if (status == 0)
+ return;
+
+ if (status < 100 || status > 699) {
+ SU_DEBUG_3(("nta_leg(%p): invalid status %03d from callback\n",
+ leg, status));
+ status = 500;
+ }
+ else if (method == sip_method_invite && status >= 200 && status < 300) {
+ SU_DEBUG_3(("nta_leg(%p): invalid INVITE status %03d from callback\n",
+ leg, status));
+ status = 500;
+ }
+
+ if (status >= 100 && irq->irq_status < 200)
+ nta_incoming_treply(irq, status, NULL, TAG_END());
+
+ if (status >= 200)
+ nta_incoming_destroy(irq);
+}
+
+/**Compare two SIP from/to fields.
+ *
+ * @retval nonzero if matching.
+ * @retval zero if not matching.
+ */
+static inline
+int addr_cmp(url_t const *a, url_t const *b)
+{
+ if (b == NULL)
+ return 0;
+ else
+ return
+ host_cmp(a->url_host, b->url_host)
+ || str0cmp(a->url_port, b->url_port)
+ || str0cmp(a->url_user, b->url_user);
+}
+
+/** Get a leg by dialog.
+ *
+ * The function nta_leg_by_dialog() searches for a dialog leg from agent's
+ * hash table. The matching rules based on parameters are as follows:
+ *
+ * @param agent pointer to agent object
+ * @param request_uri if non-NULL, and there is destination URI
+ * associated with the dialog, these URIs must match
+ * @param call_id if non-NULL, must match with @CallID header contents
+ * @param remote_tag if there is remote tag
+ * associated with dialog, @a remote_tag must match
+ * @param remote_uri if there is no remote tag, the remote URI must match
+ * @param local_tag if non-NULL and there is local tag associated with leg,
+ * it must math
+ * @param local_uri if there is no local tag, the local URI must match
+ *
+ */
+nta_leg_t *nta_leg_by_dialog(nta_agent_t const *agent,
+ url_t const *request_uri,
+ sip_call_id_t const *call_id,
+ char const *remote_tag,
+ url_t const *remote_uri,
+ char const *local_tag,
+ url_t const *local_uri)
+{
+ void *to_be_freed = NULL, *tbf2 = NULL, *tbf3 = NULL;
+ url_t *url;
+ url_t url0[1];
+ nta_leg_t *leg;
+
+ if (!agent || !call_id)
+ return su_seterrno(EINVAL), NULL;
+
+ if (request_uri == NULL) {
+ url = NULL;
+ }
+ else if (URL_IS_STRING(request_uri)) {
+ /* accept a string as URL */
+ to_be_freed = url = url_hdup(NULL, request_uri);
+ }
+ else {
+ *url0 = *request_uri, url = url0;
+ }
+
+ if (url) {
+ url->url_params = NULL;
+ agent_aliases(agent, url, NULL); /* canonize url */
+ }
+
+ if (remote_uri && URL_IS_STRING(remote_uri))
+ request_uri = tbf2 = url_hdup(NULL, remote_uri);
+
+ if (local_uri && URL_IS_STRING(local_uri))
+ local_uri = tbf3 = url_hdup(NULL, local_uri);
+
+ leg = leg_find(agent,
+ NULL, url,
+ call_id,
+ remote_tag, remote_uri,
+ local_tag, local_uri);
+
+ if (to_be_freed) su_free(NULL, to_be_freed);
+ if (tbf2) su_free(NULL, tbf2);
+ if (tbf3) su_free(NULL, tbf3);
+
+ return leg;
+}
+
+/**@internal
+ * Find a leg corresponding to the request message.
+ *
+ * A leg matches to message if leg_match_request() returns true ("Call-ID",
+ * "To", and "From" match).
+ */
+static
+nta_leg_t *leg_find(nta_agent_t const *sa,
+ char const *method_name,
+ url_t const *request_uri,
+ sip_call_id_t const *i,
+ char const *from_tag,
+ url_t const *from_uri,
+ char const *to_tag,
+ url_t const *to_uri)
+{
+ hash_value_t hash = i->i_hash;
+ leg_htable_t const *lht = sa->sa_dialogs;
+ nta_leg_t **ll, *leg, *loose_match = NULL;
+
+ for (ll = leg_htable_hash(lht, hash);
+ (leg = *ll);
+ ll = leg_htable_next(lht, ll)) {
+ sip_call_id_t const *leg_i = leg->leg_id;
+ url_t const *remote_uri = leg->leg_remote->a_url;
+ char const *remote_tag = leg->leg_remote->a_tag;
+ url_t const *local_uri = leg->leg_local->a_url;
+ char const *local_tag = leg->leg_local->a_tag;
+ url_t const *leg_url = leg->leg_url;
+ char const *leg_method = leg->leg_method;
+
+ if (leg->leg_hash != hash)
+ continue;
+ if (strcmp(leg_i->i_id, i->i_id) != 0)
+ continue;
+ /* Do not match if the incoming To has tag, but the local does not */
+ if (!local_tag && to_tag)
+ continue;
+ /* Do not match if incoming From has no tag but remote has a tag */
+ if (remote_tag && !from_tag)
+ continue;
+ /* Avoid matching with itself */
+ if (!remote_tag != !from_tag && !local_tag != !to_tag)
+ continue;
+
+ if (local_tag && to_tag ?
+ strcasecmp(local_tag, to_tag) : addr_cmp(local_uri, to_uri))
+ continue;
+ if (remote_tag && from_tag ?
+ strcasecmp(remote_tag, from_tag) : addr_cmp(remote_uri, from_uri))
+ continue;
+
+ if (leg_url && request_uri && url_cmp(leg_url, request_uri))
+ continue;
+ if (leg_method && method_name && strcasecmp(method_name, leg_method))
+ continue;
+
+ /* Perfect match if both local and To have tag
+ * or local does not have tag.
+ */
+ if ((!local_tag || to_tag))
+ return leg;
+
+ if (loose_match == NULL)
+ loose_match = leg;
+ }
+
+ return loose_match;
+}
+
+/** Get leg by destination */
+nta_leg_t *nta_leg_by_uri(nta_agent_t const *agent, url_string_t const *us)
+{
+ url_t *url;
+ nta_leg_t *leg;
+
+ if (!agent)
+ return NULL;
+
+ if (!us)
+ return agent->sa_default_leg;
+
+ url = url_hdup(NULL, us->us_url);
+
+ agent_aliases(agent, url, NULL);
+
+ leg = url ? dst_find(agent, url, NULL) : NULL;
+
+ su_free(NULL, url);
+
+ return leg;
+}
+
+/** Find a non-dialog leg corresponding to the request uri u0 */
+static
+nta_leg_t *dst_find(nta_agent_t const *sa,
+ url_t const *u0,
+ char const *method_name)
+{
+ hash_value_t hash, hash2;
+ leg_htable_t const *lht = sa->sa_defaults;
+ nta_leg_t **ll, *leg, *loose_match = NULL;
+ int again;
+ url_t url[1];
+
+ *url = *u0;
+ hash = hash_istring(url->url_scheme, ":", 0);
+ hash = hash_istring(url->url_host, "", hash);
+ hash2 = hash_istring("%", "@", hash);
+ hash = hash_istring(url->url_user, "@", hash);
+
+ /* First round, search with user name */
+ /* Second round, search without user name */
+ do {
+ for (ll = leg_htable_hash(lht, hash);
+ (leg = *ll);
+ ll = leg_htable_next(lht, ll)) {
+ if (leg->leg_hash != hash)
+ continue;
+ if (url_cmp(url, leg->leg_url))
+ continue;
+ if (!method_name) {
+ if (leg->leg_method)
+ continue;
+ return leg;
+ }
+ else if (leg->leg_method) {
+ if (strcasecmp(method_name, leg->leg_method))
+ continue;
+ return leg;
+ }
+ loose_match = leg;
+ }
+ if (loose_match)
+ return loose_match;
+
+ again = 0;
+
+ if (url->url_user && strcmp(url->url_user, "%")) {
+ url->url_user = "%";
+ hash = hash2;
+ again = 1;
+ }
+ } while (again);
+
+ return NULL;
+}
+
+/** Set leg route and target URL.
+ *
+ * The function leg_route() sets the leg route and contact using the
+ * @RecordRoute and @Contact headers.
+ */
+static
+int leg_route(nta_leg_t *leg,
+ sip_record_route_t const *route,
+ sip_record_route_t const *reverse,
+ sip_contact_t const *contact)
+{
+ su_home_t *home = leg->leg_home;
+ sip_route_t *r, r0[1];
+
+ if (!leg)
+ return -1;
+
+ if (route == NULL && reverse == NULL && contact == NULL)
+ return 0;
+
+ sip_route_init(r0);
+
+ if (leg->leg_route) {
+ r = leg->leg_route;
+ }
+ else if (route) {
+ r = sip_route_fixdup(home, route); if (!r) return -1;
+ }
+ else if (reverse) {
+ r = sip_route_reverse(home, reverse); if (!r) return -1;
+ }
+ else
+ r = NULL;
+
+#ifdef NTA_STRICT_ROUTING
+ /*
+ * Handle Contact according to the RFC2543bis04 sections 16.1, 16.2 and 16.4.
+ */
+ if (contact) {
+ *r0->r_url = *contact->m_url;
+
+ if (!(m_r = sip_route_dup(leg->leg_home, r0)))
+ return -1;
+
+ /* Append, but replace last entry if it was generated from contact */
+ for (rr = &r; *rr; rr = &(*rr)->r_next)
+ if (leg->leg_contact_set && (*rr)->r_next == NULL)
+ break;
+ }
+ else
+ rr = NULL;
+
+ if (rr) {
+ if (*rr)
+ su_free(leg->leg_home, *rr);
+ *rr = m_r;
+ }
+ if (m_r != NULL)
+ leg->leg_contact_set = 1;
+
+#else
+ if (r && r->r_url->url_params)
+ leg->leg_loose_route = url_has_param(r->r_url, "lr");
+
+ if (contact) {
+ sip_contact_t *target, m[1], *m0;
+
+ sip_contact_init(m);
+ *m->m_url = *contact->m_url;
+ m->m_url->url_headers = NULL;
+ target = sip_contact_dup(leg->leg_home, m);
+
+ if (target && target->m_url->url_params) {
+ /* Remove ttl, method. @RFC3261 table 1, page 152 */
+ char *p = (char *)target->m_url->url_params;
+ p = url_strip_param_string(p, "method");
+ p = url_strip_param_string(p, "ttl");
+ target->m_url->url_params = p;
+ }
+
+ m0 = leg->leg_target, leg->leg_target = target;
+
+ if (m0)
+ su_free(leg->leg_home, m0);
+ }
+#endif
+
+ leg->leg_route = r;
+
+ return 0;
+}
+
+/** @internal Default leg callback. */
+static int
+leg_callback_default(nta_leg_magic_t *magic,
+ nta_leg_t *leg,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ nta_incoming_treply(irq,
+ SIP_501_NOT_IMPLEMENTED,
+ TAG_END());
+ return 501;
+}
+
+/* ====================================================================== */
+/* 7) Server-side (incoming) transactions */
+
+#define HTABLE_HASH_IRQ(irq) ((irq)->irq_hash)
+HTABLE_BODIES_WITH(incoming_htable, iht, nta_incoming_t, HTABLE_HASH_IRQ,
+ size_t, hash_value_t);
+
+static void incoming_insert(nta_agent_t *agent,
+ incoming_queue_t *queue,
+ nta_incoming_t *irq);
+
+static inline int incoming_is_queued(nta_incoming_t const *irq);
+static inline void incoming_queue(incoming_queue_t *queue, nta_incoming_t *);
+static inline void incoming_remove(nta_incoming_t *irq);
+static inline void incoming_set_timer(nta_incoming_t *, unsigned interval);
+static inline void incoming_reset_timer(nta_incoming_t *);
+static inline int incoming_mass_destroy(nta_agent_t *sa, incoming_queue_t *q);
+
+static int incoming_set_params(nta_incoming_t *irq, tagi_t const *tags);
+static inline
+int incoming_set_compartment(nta_incoming_t *irq, tport_t *tport, msg_t *msg,
+ int create_if_needed);
+
+static inline nta_incoming_t
+ *incoming_call_callback(nta_incoming_t *, msg_t *, sip_t *);
+static inline int incoming_final_failed(nta_incoming_t *irq, msg_t *);
+static void incoming_retransmit_reply(nta_incoming_t *irq, tport_t *tport);
+
+/** Create a default server transaction.
+ *
+ * The default server transaction is used by a proxy to forward responses
+ * statelessly.
+ *
+ * @param agent pointer to agent object
+ *
+ * @retval pointer to default server transaction object
+ * @retval NULL if failed
+ */
+nta_incoming_t *nta_incoming_default(nta_agent_t *agent)
+{
+ msg_t *msg;
+ su_home_t *home;
+ nta_incoming_t *irq;
+
+ if (agent == NULL)
+ return su_seterrno(EFAULT), NULL;
+ if (agent->sa_default_incoming)
+ return su_seterrno(EEXIST), NULL;
+
+ msg = nta_msg_create(agent, 0);
+ if (!msg)
+ return NULL;
+
+ irq = su_zalloc(home = msg_home(msg), sizeof(*irq));
+ if (!irq)
+ return (void)msg_destroy(msg), NULL;
+
+ irq->irq_home = home;
+ irq->irq_request = NULL;
+ irq->irq_agent = agent;
+ irq->irq_received = agent_now(agent);
+ irq->irq_method = sip_method_invalid;
+
+ irq->irq_default = 1;
+ agent->sa_default_incoming = irq;
+
+ return irq;
+}
+
+/** Create a server transaction.
+ *
+ * The function nta_incoming_create() creates a server transaction for a
+ * request message. This function is used when an element processing
+ * requests statelessly wants to process a particular request statefully.
+ *
+ * @param agent pointer to agent object
+ * @param leg pointer to leg object (either @a agent or @a leg may be NULL)
+ * @param msg pointer to message object
+ * @param sip pointer to SIP structure (may be NULL)
+ * @param tag,value,... optional tagged parameters
+ *
+ * @note
+ * The ownership of @a msg is taken over by the function even if the
+ * function fails.
+ *
+ * @TAGS
+ * @TAG NTATAG_TPORT() specifies the transport used to receive the request
+ * and also default transport for sending the response.
+ *
+ * @retval nta_incoming_t pointer to the newly created server transaction
+ * @retval NULL if failed
+ */
+nta_incoming_t *nta_incoming_create(nta_agent_t *agent,
+ nta_leg_t *leg,
+ msg_t *msg,
+ sip_t *sip,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ char const *to_tag = NULL;
+ tport_t *tport = NULL;
+ ta_list ta;
+ nta_incoming_t *irq;
+
+ if (msg == NULL)
+ return NULL;
+
+ if (agent == NULL && leg != NULL)
+ agent = leg->leg_agent;
+
+ if (sip == NULL)
+ sip = sip_object(msg);
+
+ if (agent == NULL || sip == NULL || !sip->sip_request || !sip->sip_cseq)
+ return msg_destroy(msg), NULL;
+
+ ta_start(ta, tag, value);
+
+ tl_gets(ta_args(ta),
+ NTATAG_TPORT_REF(tport),
+ TAG_END());
+ ta_end(ta);
+
+ if (leg && leg->leg_local)
+ to_tag = leg->leg_local->a_tag;
+
+ if (tport == NULL)
+ tport = tport_delivered_by(agent->sa_tports, msg);
+
+ irq = incoming_create(agent, msg, sip, tport, to_tag);
+
+ if (!irq)
+ msg_destroy(msg);
+
+ return irq;
+}
+
+/** @internal Create a new incoming transaction object. */
+static
+nta_incoming_t *incoming_create(nta_agent_t *agent,
+ msg_t *msg,
+ sip_t *sip,
+ tport_t *tport,
+ char const *tag)
+{
+ nta_incoming_t *irq = su_zalloc(msg_home(msg), sizeof(*irq));
+
+ agent->sa_stats->as_server_tr++;
+
+ if (irq) {
+ su_home_t *home;
+ incoming_queue_t *queue;
+ sip_method_t method = sip->sip_request->rq_method;
+
+ irq->irq_request = msg;
+ irq->irq_home = home = msg_home(msg_ref_create(msg));
+ irq->irq_agent = agent;
+
+ irq->irq_received = agent_now(agent);
+
+ irq->irq_method = method;
+ irq->irq_rq = sip_request_copy(home, sip->sip_request);
+ irq->irq_from = sip_from_copy(home, sip->sip_from);
+ irq->irq_to = sip_to_copy(home, sip->sip_to);
+ irq->irq_call_id = sip_call_id_copy(home, sip->sip_call_id);
+ irq->irq_cseq = sip_cseq_copy(home, sip->sip_cseq);
+ irq->irq_via = sip_via_copy(home, sip->sip_via);
+ switch (method) {
+ case sip_method_ack:
+ case sip_method_cancel:
+ case sip_method_bye:
+ case sip_method_options:
+ case sip_method_register: /* Handling Path is up to application */
+ case sip_method_info:
+ case sip_method_prack:
+ case sip_method_publish:
+ break;
+ default:
+ irq->irq_record_route =
+ sip_record_route_copy(home, sip->sip_record_route);
+ }
+ irq->irq_branch = irq->irq_via->v_branch;
+ irq->irq_reliable_tp = tport_is_reliable(tport);
+
+ if (sip->sip_timestamp)
+ irq->irq_timestamp = sip_timestamp_copy(home, sip->sip_timestamp);
+
+ /* Tag transaction */
+ if (tag)
+ sip_to_tag(home, irq->irq_to, tag);
+
+ if (method != sip_method_ack) {
+ int *use_rport = NULL;
+ int retry_without_rport = 0;
+
+ if (agent->sa_server_rport)
+ use_rport = &retry_without_rport, retry_without_rport = 1;
+
+ if (nta_tpn_by_via(irq->irq_tpn, irq->irq_via, use_rport) < 0)
+ SU_DEBUG_1(("%s: bad via\n", __func__));
+ }
+
+ incoming_set_compartment(irq, tport, msg, 0);
+
+ if (method == sip_method_invite) {
+ irq->irq_must_100rel =
+ sip->sip_require && sip_has_feature(sip->sip_require, "100rel");
+
+ if (irq->irq_must_100rel ||
+ (sip->sip_supported &&
+ sip_has_feature(sip->sip_supported, "100rel"))) {
+ irq->irq_rseq = su_randint(1, 0x7fffffff); /* Initialize rseq */
+ }
+
+ queue = agent->sa_in.proceeding;
+
+ if (irq->irq_reliable_tp)
+ incoming_set_timer(irq, agent->sa_t2 / 2); /* N1 = T2 / 2 */
+ else
+ incoming_set_timer(irq, 200); /* N1 = 200 ms */
+
+ irq->irq_tport = tport_ref(tport);
+ }
+ else if (method == sip_method_ack) {
+ irq->irq_status = 700; /* Never send reply to ACK */
+ irq->irq_completed = 1;
+ if (irq->irq_reliable_tp || !agent->sa_is_a_uas) {
+ queue = agent->sa_in.terminated;
+ irq->irq_terminated = 1;
+ }
+ else {
+ queue = agent->sa_in.completed; /* Timer J */
+ }
+ }
+ else {
+ queue = agent->sa_in.proceeding;
+ /* draft-sparks-sip-nit-actions-03:
+
+ Blacklisting on a late response occurs even over reliable transports.
+ Thus, if an element processing a request received over a reliable
+ transport is delaying its final response at all, sending a 100 Trying
+ well in advance of the timeout will prevent blacklisting. Sending a
+ 100 Trying immediately will not harm the transaction as it would over
+ UDP, but a policy of always sending such a message results in
+ unneccessary traffic. A policy of sending a 100 Trying after the
+ period of time in which Timer E reaches T2 had this been a UDP hop is
+ one reasonable compromise.
+
+ */
+ if (agent->sa_extra_100 && irq->irq_reliable_tp)
+ incoming_set_timer(irq, agent->sa_t2 / 2); /* T2 / 2 */
+
+ irq->irq_tport = tport_ref(tport);
+ }
+
+ irq->irq_hash = NTA_HASH(irq->irq_call_id, irq->irq_cseq->cs_seq);
+
+ incoming_insert(agent, queue, irq);
+ }
+
+ return irq;
+}
+
+/** @internal
+ * Insert incoming transaction to hash table.
+ */
+static void
+incoming_insert(nta_agent_t *agent,
+ incoming_queue_t *queue,
+ nta_incoming_t *irq)
+{
+ incoming_queue(queue, irq);
+
+ if (incoming_htable_is_full(agent->sa_incoming))
+ incoming_htable_resize(agent->sa_home, agent->sa_incoming, 0);
+
+ if (irq->irq_method != sip_method_ack)
+ incoming_htable_insert(agent->sa_incoming, irq);
+ else
+ /* ACK is appended - final response with tags match with it,
+ * not with the original INVITE transaction */
+ /* XXX - what about rfc2543 servers, which do not add tag? */
+ incoming_htable_append(agent->sa_incoming, irq);
+}
+
+/** Call callback for incoming request */
+static
+int incoming_callback(nta_leg_t *leg, nta_incoming_t *irq, sip_t *sip)
+{
+ sip_method_t method = sip->sip_request->rq_method;
+ char const *method_name = sip->sip_request->rq_method_name;
+
+ /* RFC-3261 section 12.2.2 (page 76) */
+ if (leg->leg_dialog &&
+ irq->irq_agent->sa_is_a_uas &&
+ method != sip_method_ack) {
+ uint32_t seq = sip->sip_cseq->cs_seq;
+
+ if (leg->leg_rseq > sip->sip_cseq->cs_seq) {
+ SU_DEBUG_3(("nta_leg(%p): out-of-order %s (%u < %u)\n",
+ leg, method_name, seq, leg->leg_rseq));
+ return 500;
+ }
+
+ leg->leg_rseq = seq;
+ }
+
+ return leg->leg_callback(leg->leg_magic, leg, irq, sip);
+}
+
+/**
+ * Destroy an incoming transaction.
+ *
+ * This function does not actually free transaction object, but marks it as
+ * disposable. The object is freed after a timeout.
+ *
+ * @param irq incoming request object to be destroyed
+ */
+void nta_incoming_destroy(nta_incoming_t *irq)
+{
+ if (irq) {
+ irq->irq_callback = NULL;
+ irq->irq_magic = NULL;
+ irq->irq_destroyed = 1;
+ if (!irq->irq_in_callback) {
+ if (irq->irq_terminated || irq->irq_default)
+ incoming_free(irq);
+ else if (irq->irq_status < 200)
+ nta_incoming_treply(irq, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
+ }
+ }
+}
+
+/** @internal
+ * Initialize a queue for incoming transactions.
+ */
+static void
+incoming_queue_init(incoming_queue_t *queue, unsigned timeout)
+{
+ memset(queue, 0, sizeof *queue);
+ queue->q_tail = &queue->q_head;
+ queue->q_timeout = timeout;
+}
+
+/** Change the timeout value of a queue */
+static void
+incoming_queue_adjust(nta_agent_t *sa,
+ incoming_queue_t *queue,
+ unsigned timeout)
+{
+ nta_incoming_t *irq;
+ su_duration_t latest;
+
+ if (timeout >= queue->q_timeout || !queue->q_head) {
+ queue->q_timeout = timeout;
+ return;
+ }
+
+ latest = set_timeout(sa, queue->q_timeout = timeout);
+
+ for (irq = queue->q_head; irq; irq = irq->irq_next) {
+ if (irq->irq_timeout - latest > 0)
+ irq->irq_timeout = latest;
+ }
+}
+
+/** @internal
+ * Test if an incoming transaction is in a queue.
+ */
+static inline
+int incoming_is_queued(nta_incoming_t const *irq)
+{
+ return irq && irq->irq_queue;
+}
+
+/** @internal
+ * Insert an incoming transaction into a queue.
+ *
+ * The function incoming_queue() inserts a server transaction into a queue,
+ * and sets the corresponding timeout at the same time.
+ */
+static inline
+void incoming_queue(incoming_queue_t *queue,
+ nta_incoming_t *irq)
+{
+ if (irq->irq_queue == queue) {
+ assert(queue->q_timeout == 0);
+ return;
+ }
+
+ if (incoming_is_queued(irq))
+ incoming_remove(irq);
+
+ assert(*queue->q_tail == NULL);
+
+ if (queue->q_timeout)
+ irq->irq_timeout = set_timeout(irq->irq_agent, queue->q_timeout);
+ else
+ irq->irq_timeout = 0;
+
+ irq->irq_queue = queue;
+ irq->irq_prev = queue->q_tail;
+ *queue->q_tail = irq;
+ queue->q_tail = &irq->irq_next;
+ queue->q_length++;
+}
+
+/** @internal
+ * Remove an incoming transaction from a queue.
+ */
+static inline
+void incoming_remove(nta_incoming_t *irq)
+{
+ assert(incoming_is_queued(irq));
+ assert(irq->irq_queue->q_length > 0);
+
+ if ((*irq->irq_prev = irq->irq_next))
+ irq->irq_next->irq_prev = irq->irq_prev;
+ else
+ irq->irq_queue->q_tail = irq->irq_prev, assert(!*irq->irq_queue->q_tail);
+
+ irq->irq_queue->q_length--;
+ irq->irq_next = NULL;
+ irq->irq_prev = NULL;
+ irq->irq_queue = NULL;
+ irq->irq_timeout = 0;
+}
+
+static inline
+void incoming_set_timer(nta_incoming_t *irq, unsigned interval)
+{
+ nta_incoming_t **rq;
+
+ assert(irq);
+
+ if (interval == 0) {
+ incoming_reset_timer(irq);
+ return;
+ }
+
+ if (irq->irq_rprev) {
+ if ((*irq->irq_rprev = irq->irq_rnext))
+ irq->irq_rnext->irq_rprev = irq->irq_rprev;
+ if (irq->irq_agent->sa_in.re_t1 == &irq->irq_rnext)
+ irq->irq_agent->sa_in.re_t1 = irq->irq_rprev;
+ } else {
+ irq->irq_agent->sa_in.re_length++;
+ }
+
+ irq->irq_retry = set_timeout(irq->irq_agent, irq->irq_interval = interval);
+
+ rq = irq->irq_agent->sa_in.re_t1;
+
+ if (!(*rq) || (*rq)->irq_retry - irq->irq_retry > 0)
+ rq = &irq->irq_agent->sa_in.re_list;
+
+ while (*rq && (*rq)->irq_retry - irq->irq_retry <= 0)
+ rq = &(*rq)->irq_rnext;
+
+ if ((irq->irq_rnext = *rq))
+ irq->irq_rnext->irq_rprev = &irq->irq_rnext;
+ *rq = irq;
+ irq->irq_rprev = rq;
+
+ /* Optimization: keep special place for transactions with T1 interval */
+ if (interval == irq->irq_agent->sa_t1)
+ irq->irq_agent->sa_in.re_t1 = rq;
+}
+
+static inline
+void incoming_reset_timer(nta_incoming_t *irq)
+{
+ if (irq->irq_rprev) {
+ if ((*irq->irq_rprev = irq->irq_rnext))
+ irq->irq_rnext->irq_rprev = irq->irq_rprev;
+ if (irq->irq_agent->sa_in.re_t1 == &irq->irq_rnext)
+ irq->irq_agent->sa_in.re_t1 = irq->irq_rprev;
+ irq->irq_agent->sa_in.re_length--;
+ }
+
+ irq->irq_interval = 0, irq->irq_retry = 0;
+ irq->irq_rnext = NULL, irq->irq_rprev = NULL;
+}
+
+/** @internal
+ * Free an incoming transaction.
+ */
+static
+void incoming_free(nta_incoming_t *irq)
+{
+ SU_DEBUG_9(("nta: incoming_free(%p)\n", irq));
+
+ incoming_cut_off(irq);
+ incoming_reclaim(irq);
+}
+
+/** Remove references to the irq */
+static inline
+void incoming_cut_off(nta_incoming_t *irq)
+{
+ nta_agent_t *agent = irq->irq_agent;
+
+ assert(agent);
+
+ if (irq->irq_default) {
+ if (irq == agent->sa_default_incoming)
+ agent->sa_default_incoming = NULL;
+ irq->irq_default = 0;
+ return;
+ }
+
+ if (incoming_is_queued(irq))
+ incoming_remove(irq);
+
+ incoming_reset_timer(irq);
+
+ incoming_htable_remove(agent->sa_incoming, irq);
+
+ if (irq->irq_cc)
+ nta_compartment_decref(&irq->irq_cc);
+
+ if (irq->irq_tport)
+ tport_decref(&irq->irq_tport);
+}
+
+/** Reclaim the memory used by irq */
+static inline
+void incoming_reclaim(nta_incoming_t *irq)
+{
+ su_home_t *home = irq->irq_home;
+ nta_reliable_t *rel, *rel_next;
+
+ if (irq->irq_request)
+ msg_destroy(irq->irq_request), irq->irq_request = NULL;
+ if (irq->irq_request2)
+ msg_destroy(irq->irq_request2), irq->irq_request2 = NULL;
+ if (irq->irq_response)
+ msg_destroy(irq->irq_response), irq->irq_response = NULL;
+
+ for (rel = irq->irq_reliable; rel; rel = rel_next) {
+ rel_next = rel->rel_next;
+ if (rel->rel_unsent)
+ msg_destroy(rel->rel_unsent);
+ su_free(irq->irq_agent->sa_home, rel);
+ }
+
+ irq->irq_home = NULL;
+
+ su_free(home, irq);
+
+ msg_destroy((msg_t *)home);
+}
+
+/** Queue request to be freed */
+static inline
+void incoming_free_queue(incoming_queue_t *q, nta_incoming_t *irq)
+{
+ incoming_cut_off(irq);
+ incoming_queue(q, irq);
+}
+
+/** Reclaim memory used by queue of requests */
+static
+void incoming_reclaim_queued(su_root_magic_t *rm,
+ su_msg_r msg,
+ union sm_arg_u *u)
+{
+ incoming_queue_t *q = u->a_incoming_queue;
+ nta_incoming_t *irq, *irq_next;
+
+ SU_DEBUG_9(("incoming_reclaim_all(%p, %p, %p)\n", rm, msg, u));
+
+ for (irq = q->q_head; irq; irq = irq_next) {
+ irq_next = irq->irq_next;
+ incoming_reclaim(irq);
+ }
+}
+
+/**Bind a callback and context to an incoming transaction object
+ *
+ * The function nta_incoming_bind() is used to set the callback and
+ * context pointer attached to an incoming request object. The callback
+ * function will be invoked if the incoming request is cancelled, or if the
+ * final response to an incoming @b INVITE request has been acknowledged.
+ *
+ * If the callback is NULL, or no callback has been bound, NTA invokes the
+ * request callback of the call leg.
+ *
+ * @param irq incoming transaction
+ * @param callback callback function
+ * @param magic application context
+ */
+void nta_incoming_bind(nta_incoming_t *irq,
+ nta_ack_cancel_f *callback,
+ nta_incoming_magic_t *magic)
+{
+ if (irq) {
+ irq->irq_callback = callback;
+ irq->irq_magic = magic;
+ }
+}
+
+/** Add a @To tag to incoming request if needed.
+ *
+ * If @a tag is NULL, a new tag is generated.
+ */
+char const *nta_incoming_tag(nta_incoming_t *irq, char const *tag)
+{
+ if (!irq)
+ return su_seterrno(EFAULT), NULL;
+
+ if (irq->irq_default)
+ return su_seterrno(EINVAL), NULL;
+
+ if (tag && strchr(tag, '='))
+ tag = strchr(tag, '=') + 1;
+
+ if (tag && irq->irq_tag && strcasecmp(tag, irq->irq_tag))
+ return NULL;
+
+ if (!irq->irq_tag) {
+ if (tag)
+ tag = su_strdup(irq->irq_home, tag);
+ else
+ tag = nta_agent_newtag(irq->irq_home, NULL, irq->irq_agent);
+
+ if (!tag)
+ return tag;
+
+ irq->irq_tag = tag;
+ irq->irq_tag_set = 1;
+ }
+
+ return irq->irq_tag;
+}
+
+
+/**Get request message.
+ *
+ * Retrieve the incoming request message of the incoming transaction. Note
+ * that the message is not copied, but a new reference to it is created.
+ *
+ * @param irq incoming transaction handle
+ *
+ * @retval
+ * A pointer to request message is returned.
+ */
+msg_t *nta_incoming_getrequest(nta_incoming_t *irq)
+{
+ msg_t *msg = NULL;
+
+ if (irq && !irq->irq_default)
+ msg = msg_ref_create(irq->irq_request);
+
+ return msg;
+}
+
+/**Get ACK or CANCEL message.
+ *
+ * Retrieve the incoming ACK or CANCEL request message of the incoming
+ * transaction. Note that the ACK or CANCEL message is not copied, but a new
+ * reference to it is created.
+ *
+ * @param irq incoming transaction handle
+ *
+ * @retval A pointer to request message is returned, or NULL if there is no
+ * CANCEL or ACK received.
+ */
+msg_t *nta_incoming_getrequest_ackcancel(nta_incoming_t *irq)
+{
+ msg_t *msg = NULL;
+
+ if (irq && irq->irq_request2)
+ msg = msg_ref_create(irq->irq_request2);
+
+ return msg;
+}
+
+/**Get response message.
+ *
+ * Retrieve the response message latest sent by the server transaction. Note
+ * that the message is not copied, but a new reference to it is created. Use
+ * msg_dup() or msg_copy() to make a copy of it.
+ *
+ * @param irq incoming transaction handle
+ *
+ * @retval
+ * A pointer to a response message is returned.
+ */
+msg_t *nta_incoming_getresponse(nta_incoming_t *irq)
+{
+ msg_t *msg = NULL;
+
+ if (irq && irq->irq_response)
+ msg = msg_ref_create(irq->irq_response);
+
+ return msg;
+}
+
+/** Get method of a server transaction. */
+sip_method_t nta_incoming_method(nta_incoming_t const *irq)
+{
+ return irq ? irq->irq_method : sip_method_invalid;
+}
+
+/** Get method name of a server transaction. */
+char const *nta_incoming_method_name(nta_incoming_t const *irq)
+{
+ if (irq == NULL)
+ return NULL;
+ else if (irq->irq_rq)
+ return irq->irq_rq->rq_method_name;
+ else
+ return "*";
+}
+
+/** Get Request-URI of a server transaction */
+url_t const *nta_incoming_url(nta_incoming_t const *irq)
+{
+ return irq && irq->irq_rq ? irq->irq_rq->rq_url : NULL;
+}
+
+/** Get sequence number of a server transaction.
+ */
+uint32_t nta_incoming_cseq(nta_incoming_t const *irq)
+{
+ return irq && irq->irq_cseq ? irq->irq_cseq->cs_seq : 0;
+}
+
+/** Get local tag for incoming request */
+char const *nta_incoming_gettag(nta_incoming_t const *irq)
+{
+ return irq ? irq->irq_tag : 0;
+}
+
+/**
+ * Get status code of a server transaction.
+ */
+int nta_incoming_status(nta_incoming_t const *irq)
+{
+ return irq ? irq->irq_status : 400;
+}
+
+/** Get context pointer for an incoming transaction */
+nta_incoming_magic_t *nta_incoming_magic(nta_incoming_t *irq,
+ nta_ack_cancel_f *callback)
+{
+ return irq && irq->irq_callback == callback ? irq->irq_magic : NULL;
+}
+
+/** Find incoming transaction. */
+nta_incoming_t *nta_incoming_find(nta_agent_t const *agent,
+ sip_t const *sip,
+ sip_via_t const *v)
+{
+ if (agent && sip && v)
+ return incoming_find(agent, sip, v, NULL, NULL);
+ else
+ return NULL;
+}
+
+static inline
+int addr_match(sip_addr_t const *a, sip_addr_t const *b)
+{
+ if (a->a_tag && b->a_tag)
+ return strcasecmp(a->a_tag, b->a_tag) == 0;
+ else
+ return
+ str0casecmp(a->a_host, b->a_host) == 0 &&
+ str0cmp(a->a_user, b->a_user) == 0;
+}
+
+/** Find a matching server transaction object.
+ *
+ *
+ */
+static inline
+nta_incoming_t *incoming_find(nta_agent_t const *agent,
+ sip_t const *sip,
+ sip_via_t const *v,
+ nta_incoming_t **merge,
+ nta_incoming_t **ack)
+{
+ sip_cseq_t const *cseq = sip->sip_cseq;
+ sip_call_id_t const *i = sip->sip_call_id;
+ sip_to_t const *to = sip->sip_to;
+ sip_from_t const *from = sip->sip_from;
+ sip_request_t *rq = sip->sip_request;
+ int is_uas_ack = ack && agent->sa_is_a_uas && rq->rq_method == sip_method_ack;
+ incoming_htable_t const *iht = agent->sa_incoming;
+ hash_value_t hash = NTA_HASH(i, cseq->cs_seq);
+
+ nta_incoming_t **ii, *irq, *maybe;
+
+ for (ii = incoming_htable_hash(iht, hash), maybe = NULL;
+ (irq = *ii);
+ ii = incoming_htable_next(iht, ii)) {
+ if (hash != irq->irq_hash ||
+ irq->irq_call_id->i_hash != i->i_hash ||
+ strcmp(irq->irq_call_id->i_id, i->i_id))
+ continue;
+ if (irq->irq_cseq->cs_seq != cseq->cs_seq)
+ continue;
+ if (str0casecmp(irq->irq_from->a_tag, from->a_tag))
+ continue;
+ if (is_uas_ack) {
+ if (!addr_match(irq->irq_to, to))
+ continue;
+ }
+ else if (irq->irq_tag_set || !irq->irq_tag) {
+ if (str0casecmp(irq->irq_to->a_host, to->a_host) != 0 ||
+ str0cmp(irq->irq_to->a_user, to->a_user) != 0)
+ continue;
+ }
+ else if (str0casecmp(irq->irq_to->a_tag, to->a_tag))
+ continue;
+
+ if (str0casecmp(irq->irq_via->v_branch, v->v_branch) != 0) {
+ if (!agent->sa_is_a_uas)
+ continue;
+ if (is_uas_ack && irq->irq_status >= 200 && irq->irq_status < 300)
+ *ack = irq;
+ /* RFC3261 - section 8.2.2.2 Merged Requests */
+ else if (merge && !to->a_tag && agent->sa_merge_482)
+ *merge = irq;
+ continue;
+ }
+ if (!is_uas_ack && url_cmp(irq->irq_rq->rq_url, rq->rq_url))
+ continue;
+
+#if 0
+ if (irq->irq_terminated)
+ continue;
+#endif
+
+ if (irq->irq_method == rq->rq_method)
+ break; /* found */
+
+ if (ack && rq->rq_method == sip_method_cancel)
+ *ack = irq;
+ else if (ack && rq->rq_method == sip_method_ack &&
+ irq->irq_method == sip_method_invite)
+ *ack = irq;
+ }
+
+ if (irq)
+ return irq;
+
+ /* Check PRACKed requests */
+ if (ack && rq->rq_method == sip_method_prack && sip->sip_rack) {
+ sip_rack_t const *rack = sip->sip_rack;
+ hash = NTA_HASH(i, rack->ra_cseq);
+
+ for (ii = incoming_htable_hash(iht, hash);
+ (irq = *ii);
+ ii = incoming_htable_next(iht, ii)) {
+ if (hash != irq->irq_hash)
+ continue;
+ if (irq->irq_call_id->i_hash != i->i_hash)
+ continue;
+ if (strcmp(irq->irq_call_id->i_id, i->i_id))
+ continue;
+ if (irq->irq_cseq->cs_seq != rack->ra_cseq)
+ continue;
+ if (!addr_match(irq->irq_to, to) ||
+ !addr_match(irq->irq_from, from))
+ continue;
+ if (!irq->irq_from->a_tag != !from->a_tag)
+ continue;
+ *ack = irq;
+
+ return NULL;
+ }
+ }
+
+ return irq;
+}
+
+/** Process retransmitted requests. */
+static inline
+int
+incoming_recv(nta_incoming_t *irq, msg_t *msg, sip_t *sip, tport_t *tport)
+{
+ nta_agent_t *agent = irq->irq_agent;
+
+ agent->sa_stats->as_recv_retry++;
+
+ if (irq->irq_status >= 100) {
+ SU_DEBUG_5(("nta: re-received %s request, retransmitting %u reply\n",
+ sip->sip_request->rq_method_name, irq->irq_status));
+ incoming_retransmit_reply(irq, tport);
+ }
+ else if (irq->irq_agent->sa_extra_100) {
+ /* Answer automatically with 100 Trying */
+ if (irq->irq_method == sip_method_invite ||
+ /*
+ * Send 100 trying to non-invite if at least half of T2 has expired
+ * since the transaction was created.
+ */
+ su_duration(agent_now(irq->irq_agent), irq->irq_received) * 2U >
+ irq->irq_agent->sa_t2) {
+ SU_DEBUG_5(("nta: re-received %s request, sending 100 Trying\n",
+ sip->sip_request->rq_method_name));
+ nta_incoming_treply(irq, SIP_100_TRYING, NTATAG_TPORT(tport), TAG_END());
+ }
+ }
+
+ msg_destroy(msg);
+
+ return 0;
+}
+
+static inline
+int incoming_ack(nta_incoming_t *irq, msg_t *msg, sip_t *sip, tport_t *tport)
+{
+ nta_agent_t *agent = irq->irq_agent;
+
+ /* Process ACK separately? */
+ if (irq->irq_status >= 200 && irq->irq_status < 300 && !agent->sa_is_a_uas)
+ return -1;
+
+ if (irq->irq_queue == agent->sa_in.inv_completed) {
+ if (!irq->irq_confirmed)
+ agent->sa_stats->as_acked_tr++;
+
+ irq->irq_confirmed = 1;
+ incoming_reset_timer(irq); /* Reset timer G */
+
+ if (!irq->irq_reliable_tp) {
+ incoming_queue(agent->sa_in.inv_confirmed, irq); /* Timer I */
+ }
+ else {
+ irq->irq_terminated = 1;
+ incoming_queue(agent->sa_in.terminated, irq);
+ }
+
+ if (!irq->irq_destroyed) {
+ if (!irq->irq_callback) /* Process ACK normally */
+ return -1;
+
+ incoming_call_callback(irq, msg, sip); /* ACK callback */
+ }
+ } else if (irq->irq_queue == agent->sa_in.proceeding ||
+ irq->irq_queue == agent->sa_in.preliminary)
+ return -1;
+ else
+ assert(irq->irq_queue == agent->sa_in.inv_confirmed ||
+ irq->irq_queue == agent->sa_in.terminated);
+
+ msg_destroy(msg);
+
+ return 0;
+}
+
+static inline
+int incoming_cancel(nta_incoming_t *irq, msg_t *msg, sip_t *sip,
+ tport_t *tport)
+{
+ nta_agent_t *agent = irq->irq_agent;
+
+ /* Respond to the CANCEL */
+ nta_msg_treply(agent, msg_ref_create(msg), SIP_200_OK,
+ NTATAG_TPORT(tport),
+ TAG_END());
+
+ if (irq->irq_completed || irq->irq_method != sip_method_invite) {
+ msg_destroy(msg);
+ return 0;
+ }
+
+ if (!irq->irq_canceled) {
+ irq->irq_canceled = 1;
+ agent->sa_stats->as_canceled_tr++;
+ irq = incoming_call_callback(irq, msg, sip);
+ }
+
+ if (irq && !irq->irq_completed && agent->sa_cancel_487)
+ /* Respond to the cancelled request */
+ nta_incoming_treply(irq, SIP_487_REQUEST_CANCELLED, TAG_END());
+
+ msg_destroy(msg);
+
+ return 0;
+}
+
+/** Process merged requests */
+static inline
+int incoming_merge(nta_incoming_t *irq, msg_t *msg, sip_t *sip, tport_t *tport)
+{
+ nta_agent_t *agent = irq->irq_agent;
+
+ agent->sa_stats->as_merged_request++;
+
+ irq = incoming_create(irq->irq_agent, msg, sip, tport, irq->irq_tag);
+
+ if (!irq) {
+ SU_DEBUG_3(("nta: incoming_merge(): cannot create transaction for %s\n",
+ sip->sip_request->rq_method_name));
+ nta_msg_treply(agent, msg, 482, "Request merged",
+ NTATAG_TPORT(tport),
+ TAG_END());
+ return 0;
+ }
+
+ nta_incoming_treply(irq, 482, "Request merged", TAG_END());
+ nta_incoming_destroy(irq);
+
+ return 0;
+}
+
+/**@typedef nta_ack_cancel_f
+ *
+ * Callback function prototype for CANCELed/ACKed requests
+ *
+ * This is a callback function is invoked by NTA when an incoming request
+ * has been cancelled or an response to an incoming INVITE request has been
+ * acknowledged.
+ *
+ * @param magic incoming request context
+ * @param ireq incoming request
+ * @param sip ACK/CANCEL message
+ *
+ * @retval 0
+ * This callback function should return always 0.
+ */
+
+/** Call callback of incoming transaction */
+static inline
+nta_incoming_t *
+incoming_call_callback(nta_incoming_t *irq, msg_t *msg, sip_t *sip)
+{
+ if (irq->irq_callback) {
+ irq->irq_in_callback = 1;
+ irq->irq_request2 = msg;
+ irq->irq_callback(irq->irq_magic, irq, sip);
+ irq->irq_request2 = NULL;
+ irq->irq_in_callback = 0;
+
+ if (irq->irq_terminated && irq->irq_destroyed)
+ incoming_free(irq), irq = NULL;
+ }
+ return irq;
+}
+
+/**Set server transaction parameters.
+ *
+ * Sets the server transaction parameters. The parameters determine the way
+ * the SigComp compression is handled.
+ *
+ * @TAGS
+ * NTATAG_COMP(), and NTATAG_SIGCOMP_CLOSE().
+ *
+ * @retval number of set parameters when succesful
+ * @retval -1 upon an error
+ */
+int nta_incoming_set_params(nta_incoming_t *irq,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ int retval = -1;
+
+ if (irq) {
+ ta_list ta;
+ ta_start(ta, tag, value);
+ retval = incoming_set_params(irq, ta_args(ta));
+ ta_end(ta);
+ }
+ else {
+ su_seterrno(EINVAL);
+ }
+
+ return retval;
+}
+
+static
+int incoming_set_params(nta_incoming_t *irq, tagi_t const *tags)
+{
+ int retval = 0;
+
+ tagi_t const *t;
+ char const *comp = NONE;
+ struct sigcomp_compartment *cc = NONE;
+
+ if (irq->irq_default)
+ return retval;
+
+ for (t = tags; t; t = tl_next(t)) {
+ tag_type_t tt = t->t_tag;
+
+ if (ntatag_comp == tt)
+ comp = (char const *)t->t_value, retval++;
+
+ else if (ntatag_sigcomp_close == tt)
+ irq->irq_sigcomp_zap = t->t_value != 0, retval++;
+
+ else if (tptag_compartment == tt)
+ cc = (void *)t->t_value, retval++;
+ }
+
+ if (cc != NONE) {
+ if (cc)
+ agent_accept_compressed(irq->irq_agent, irq->irq_request, cc);
+ if (irq->irq_cc)
+ nta_compartment_decref(&irq->irq_cc);
+ irq->irq_cc = nta_compartment_ref(cc);
+ }
+ else if (comp != NULL && comp != NONE && irq->irq_cc == NULL) {
+ incoming_set_compartment(irq, irq->irq_tport, irq->irq_request, 1);
+ }
+
+ else if (comp == NULL) {
+ irq->irq_tpn->tpn_comp = NULL;
+ }
+
+ return retval;
+}
+
+static inline
+int incoming_set_compartment(nta_incoming_t *irq, tport_t *tport, msg_t *msg,
+ int create_if_needed)
+{
+ if (!nta_compressor_vtable)
+ return 0;
+
+ if (irq->irq_cc == NULL
+ || irq->irq_tpn->tpn_comp
+ || tport_delivered_with_comp(tport, msg, NULL) != -1) {
+ struct sigcomp_compartment *cc;
+
+ cc = agent_compression_compartment(irq->irq_agent, tport, irq->irq_tpn,
+ create_if_needed);
+
+ if (cc)
+ agent_accept_compressed(irq->irq_agent, msg, cc);
+
+ irq->irq_cc = cc;
+ }
+
+ return 0;
+}
+
+/** Complete a response message.
+ *
+ * @param irq server transaction object
+ * @param msg response message to be completed
+ * @param status status code (in range 100 - 699)
+ * @param phrase status phrase (may be NULL)
+ * @param tag,value,... taged argument list
+ *
+ * Generate status structure based on @a status and @a phrase.
+ * Add essential headers to the response message:
+ * @From, @To, @CallID, @CSeq, @Via, and optionally
+ * @RecordRoute.
+ */
+int nta_incoming_complete_response(nta_incoming_t *irq,
+ msg_t *msg,
+ int status,
+ char const *phrase,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ su_home_t *home = msg_home(msg);
+ sip_t *sip = sip_object(msg);
+ int clone = 0;
+ int retval;
+ ta_list ta;
+
+ if (irq == NULL || sip == NULL)
+ return su_seterrno(EFAULT), -1;
+
+ if (status != 0 && (status < 100 || status > 699))
+ return su_seterrno(EINVAL), -1;
+
+ if (!sip->sip_status)
+ sip->sip_status = sip_status_create(home, status, phrase, NULL);
+
+ ta_start(ta, tag, value);
+ retval = sip_add_tl(msg, sip, ta_tags(ta));
+ ta_end(ta);
+
+ if (retval < 0)
+ return -1;
+
+ if (irq->irq_default)
+ return sip_complete_message(msg);
+
+ if (!sip->sip_from)
+ clone = 1, sip->sip_from = sip_from_copy(home, irq->irq_from);
+ if (status > 100 && !irq->irq_tag) {
+ if (sip->sip_to)
+ nta_incoming_tag(irq, sip->sip_to->a_tag);
+ else
+ nta_incoming_tag(irq, NULL);
+ }
+ if (!sip->sip_to)
+ clone = 1, sip->sip_to = sip_to_copy(home, irq->irq_to);
+ if (sip->sip_status && sip->sip_status->st_status > 100 &&
+ irq->irq_tag && sip->sip_to && !sip->sip_to->a_tag)
+ sip_to_tag(home, sip->sip_to, irq->irq_tag);
+ if (!sip->sip_call_id)
+ clone = 1, sip->sip_call_id = sip_call_id_copy(home, irq->irq_call_id);
+ if (!sip->sip_cseq)
+ clone = 1, sip->sip_cseq = sip_cseq_copy(home, irq->irq_cseq);
+ if (!sip->sip_via)
+ clone = 1, sip->sip_via = sip_via_copy(home, irq->irq_via);
+ if (status < 300 &&
+ !sip->sip_record_route && irq->irq_record_route)
+ sip_add_dup(msg, sip, (sip_header_t *)irq->irq_record_route);
+
+ if (clone)
+ msg_set_parent(msg, (msg_t *)irq->irq_home);
+
+ if (retval < 0 || !sip->sip_from || !sip->sip_to || !sip->sip_call_id
+ || !sip->sip_cseq || !sip->sip_via
+ || (status < 300 && irq->irq_record_route && !sip->sip_record_route &&
+ sip->sip_cseq && sip->sip_cseq->cs_method != sip_method_register))
+ return -1;
+
+ return sip_complete_message(msg);
+}
+
+
+/**Reply to an incoming transaction request.
+ *
+ * This function creates a response message to an incoming request and sends
+ * it to the client.
+ *
+ * @note
+ * It is possible to send several non-final (1xx) responses, but only one
+ * final response.
+ *
+ * @param irq incoming request
+ * @param status status code
+ * @param phrase status phrase (may be NULL if status code is well-known)
+ * @param tag,value,... optional additional headers terminated by TAG_END()
+ *
+ * @retval 0 when succesful
+ * @retval -1 upon an error
+ */
+int nta_incoming_treply(nta_incoming_t *irq,
+ int status,
+ char const *phrase,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ int retval = -1;
+
+ if (irq &&
+ (irq->irq_status < 200 || status < 200 ||
+ (irq->irq_method == sip_method_invite && status < 300))) {
+ ta_list ta;
+ msg_t *msg = nta_msg_create(irq->irq_agent, 0);
+
+ ta_start(ta, tag, value);
+
+ if (!msg)
+ ;
+ else if (nta_incoming_complete_response(irq, msg, status, phrase,
+ ta_tags(ta)) < 0)
+ msg_destroy(msg);
+ else if (incoming_set_params(irq, ta_args(ta)) < 0)
+ msg_destroy(msg);
+ else
+ retval = nta_incoming_mreply(irq, msg);
+
+ ta_end(ta);
+
+ if (retval < 0 && status >= 200)
+ incoming_final_failed(irq, NULL);
+ }
+
+ return retval;
+}
+
+/**
+ * Return a response message to client.
+ *
+ * @note
+ * The ownership of @a msg is taken over by the function even if the
+ * function fails.
+ *
+ * @retval 0 when succesful
+ * @retval -1 upon an error
+ */
+int nta_incoming_mreply(nta_incoming_t *irq, msg_t *msg)
+{
+ sip_t *sip = sip_object(msg);
+
+ int status;
+
+ if (irq == NULL) {
+ msg_destroy(msg);
+ return -1;
+ }
+
+ if (msg == NULL)
+ return -1;
+
+ if (msg == irq->irq_response)
+ return 0;
+
+ if (!sip->sip_status || !sip->sip_via || !sip->sip_cseq)
+ return incoming_final_failed(irq, msg);
+
+ assert (sip->sip_cseq->cs_method == irq->irq_method || irq->irq_default);
+
+ status = sip->sip_status->st_status;
+
+ if (!irq->irq_tag && status > 100 && !irq->irq_default)
+ nta_incoming_tag(irq, NULL);
+
+ if (/* (irq->irq_confirmed && status >= 200) || */
+ (irq->irq_completed && status >= 300)) {
+ SU_DEBUG_3(("%s: already %s transaction\n", __func__,
+ irq->irq_confirmed ? "confirmed" : "completed"));
+ msg_destroy(msg);
+ return -1;
+ }
+
+ if (irq->irq_must_100rel && !sip->sip_rseq && status > 100 && status < 200) {
+ /* This nta_reliable_t object will be destroyed by PRACK or timeout */
+ if (nta_reliable_mreply(irq, NULL, NULL, msg))
+ return 0;
+
+ return -1;
+ }
+
+ if (status >= 200 && irq->irq_reliable && irq->irq_reliable->rel_unsent) {
+ if (reliable_final(irq, msg, sip) == 0)
+ return 0;
+ }
+
+ return incoming_reply(irq, msg, sip);
+}
+
+
+
+/** Send the response message.
+ *
+ * @note The ownership of msg is handled to incoming_reply().
+ */
+int incoming_reply(nta_incoming_t *irq, msg_t *msg, sip_t *sip)
+{
+ nta_agent_t *agent = irq->irq_agent;
+ int status = sip->sip_status->st_status;
+ int sending = 1;
+ int *use_rport = NULL;
+ int retry_without_rport = 0;
+ tp_name_t *tpn, default_tpn[1];
+
+ if (status == 408 &&
+ irq->irq_method != sip_method_invite &&
+ !agent->sa_pass_408 &&
+ !irq->irq_default) {
+ /* draft-sparks-sip-nit-actions-03 Action 2:
+
+ A transaction-stateful SIP element MUST NOT send a response with
+ Status-Code of 408 to a non-INVITE request. As a consequence, an
+ element that can not respond before the transaction expires will not
+ send a final response at all.
+ */
+ sending = 0;
+ }
+
+ if (irq->irq_status == 0 && irq->irq_timestamp && !sip->sip_timestamp)
+ incoming_timestamp(irq, msg, sip);
+
+ if (irq->irq_default) {
+ if (agent->sa_server_rport)
+ use_rport = &retry_without_rport, retry_without_rport = 1;
+ tpn = default_tpn;
+ if (nta_tpn_by_via(tpn, sip->sip_via, use_rport) < 0)
+ tpn = NULL;
+ }
+ else {
+ tpn = irq->irq_tpn;
+ }
+
+ if (sip_complete_message(msg) < 0)
+ SU_DEBUG_1(("%s: sip_complete_message() failed\n", __func__));
+ else if (msg_serialize(msg, (msg_pub_t *)sip) < 0)
+ SU_DEBUG_1(("%s: sip_serialize() failed\n", __func__));
+ else if (!(irq->irq_tport) &&
+ !(tport_decref(&irq->irq_tport),
+ irq->irq_tport = tpn ? tport_by_name(agent->sa_tports, tpn) : 0))
+ SU_DEBUG_1(("%s: no tport\n", __func__));
+ else {
+ int i, err = 0;
+ tport_t *tp = NULL;
+ incoming_queue_t *queue;
+
+ char const *method_name;
+ uint32_t cseq;
+
+ if (irq->irq_default) {
+ assert(sip->sip_cseq);
+ method_name = sip->sip_cseq->cs_method_name, cseq = sip->sip_cseq->cs_seq;
+ }
+ else {
+ method_name = irq->irq_rq->rq_method_name, cseq = irq->irq_cseq->cs_seq;
+ }
+
+ if (sending) {
+ for (i = 0; i < 3; i++) {
+ tp = tport_tsend(irq->irq_tport, msg, tpn,
+ IF_SIGCOMP_TPTAG_COMPARTMENT(irq->irq_cc)
+ TPTAG_MTU(INT_MAX),
+ TAG_END());
+ if (tp)
+ break;
+
+ err = msg_errno(msg);
+ SU_DEBUG_5(("%s: tport_tsend: %s%s\n",
+ __func__, su_strerror(err),
+ err == EPIPE ? "(retrying)" : ""));
+
+ if (err != EPIPE && err != ECONNREFUSED)
+ break;
+ tport_decref(&irq->irq_tport);
+ irq->irq_tport = tport_ref(tport_by_name(agent->sa_tports, tpn));
+ }
+
+ if (!tp) {
+ SU_DEBUG_3(("%s: tport_tsend: "
+ "error (%s) while sending %u %s for %s (%u)\n",
+ __func__, su_strerror(err),
+ status, sip->sip_status->st_phrase, method_name, cseq));
+ if (status < 200)
+ msg_destroy(msg);
+ else
+ incoming_final_failed(irq, msg);
+ return 0;
+ }
+
+ agent->sa_stats->as_sent_msg++;
+ agent->sa_stats->as_sent_response++;
+ }
+
+ SU_DEBUG_5(("nta: %s %u %s for %s (%u)\n",
+ sending ? "sent" : "not sending",
+ status, sip->sip_status->st_phrase, method_name, cseq));
+
+ if (irq->irq_default) {
+ msg_destroy(msg);
+ return 0;
+ }
+
+ incoming_reset_timer(irq);
+
+ if (status < 200) {
+ queue = agent->sa_in.proceeding;
+
+ if (irq->irq_method == sip_method_invite && status > 100 &&
+ agent->sa_progress != UINT_MAX && agent->sa_is_a_uas) {
+ /* Retransmit preliminary responses in regular intervals */
+ incoming_set_timer(irq, agent->sa_progress); /* N2 */
+ }
+ }
+ else {
+ irq->irq_completed = 1;
+
+ /* XXX - we should do this only after message has actually been sent! */
+ if (irq->irq_sigcomp_zap && irq->irq_cc)
+ agent_close_compressor(irq->irq_agent, irq->irq_cc);
+
+ if (irq->irq_method != sip_method_invite) {
+ irq->irq_confirmed = 1;
+
+ if (irq->irq_reliable_tp) {
+ irq->irq_terminated = 1;
+ queue = agent->sa_in.terminated ; /* J - set for 0 seconds */
+ } else {
+ queue = agent->sa_in.completed; /* J */
+ }
+
+ tport_decref(&irq->irq_tport);
+ }
+ else if (status >= 300 || agent->sa_is_a_uas) {
+ if (status < 300 || !irq->irq_reliable_tp)
+ incoming_set_timer(irq, agent->sa_t1); /* G */
+ queue = agent->sa_in.inv_completed; /* H */
+ }
+ else {
+#if 1
+ /* Avoid bug in @RFC3261:
+ Keep INVITE transaction around in order to catch
+ retransmitted INVITEs
+ */
+ irq->irq_confirmed = 1;
+ queue = agent->sa_in.inv_confirmed; /* H */
+#else
+ irq->irq_terminated = 1;
+ queue = agent->sa_in.terminated;
+#endif
+ }
+ }
+
+ if (irq->irq_queue != queue)
+ incoming_queue(queue, irq);
+
+ if (status >= 200 || irq->irq_status < 200) {
+ if (irq->irq_response)
+ msg_destroy(irq->irq_response);
+ assert(msg_home(msg) != irq->irq_home);
+ irq->irq_response = msg;
+ }
+ else {
+ msg_destroy(msg);
+ }
+
+ if (sip->sip_cseq->cs_method == irq->irq_method &&
+ irq->irq_status < 200 && status > irq->irq_status)
+ irq->irq_status = status;
+
+ return 0;
+ }
+
+ /*
+ * XXX - handling error is very problematic.
+ * Nobody checks return code from nta_incoming_*reply()
+ */
+ if (status < 200) {
+ msg_destroy(msg);
+ return -1;
+ }
+
+ /* We could not send final response. */
+ return incoming_final_failed(irq, msg);
+}
+
+
+/** @internal Sending final response has failed.
+ *
+ * Put transaction into its own queue, try later to send the response.
+ */
+static inline
+int incoming_final_failed(nta_incoming_t *irq, msg_t *msg)
+{
+ msg_destroy(msg);
+
+ if (!irq->irq_default) {
+ irq->irq_final_failed = 1;
+ incoming_queue(irq->irq_agent->sa_in.final_failed, irq);
+ }
+
+ return -1;
+}
+
+/** @internal Retransmit the reply */
+static
+void incoming_retransmit_reply(nta_incoming_t *irq, tport_t *tport)
+{
+ msg_t *msg = NULL;
+
+ if (irq->irq_final_failed)
+ return;
+
+ if (tport == NULL)
+ tport = irq->irq_tport;
+
+ /* Answer with existing reply */
+ if (irq->irq_reliable && !irq->irq_reliable->rel_pracked)
+ msg = reliable_response(irq);
+ else
+ msg = irq->irq_response;
+
+ if (msg && tport) {
+ irq->irq_retries++;
+
+ if (irq->irq_retries == 2 && irq->irq_tpn->tpn_comp) {
+ irq->irq_tpn->tpn_comp = NULL;
+
+ if (irq->irq_cc) {
+ agent_close_compressor(irq->irq_agent, irq->irq_cc);
+ nta_compartment_decref(&irq->irq_cc);
+ }
+ }
+
+ tport = tport_tsend(tport, msg, irq->irq_tpn,
+ IF_SIGCOMP_TPTAG_COMPARTMENT(irq->irq_cc)
+ TPTAG_MTU(INT_MAX), TAG_END());
+ irq->irq_agent->sa_stats->as_sent_msg++;
+ irq->irq_agent->sa_stats->as_sent_response++;
+ }
+}
+
+/** @internal Create timestamp header for response */
+static
+int incoming_timestamp(nta_incoming_t *irq, msg_t *msg, sip_t *sip)
+{
+ sip_timestamp_t ts[1];
+ su_time_t now = su_now();
+ char delay[32];
+ double diff = su_time_diff(now, irq->irq_received);
+
+ snprintf(delay, sizeof delay, "%.06f", diff);
+
+ *ts = *irq->irq_timestamp;
+ ts->ts_delay = delay;
+
+ return sip_add_dup(msg, sip, (sip_header_t *)ts);
+}
+
+enum {
+ timer_max_retransmit = 30,
+ timer_max_terminate = 100000,
+ timer_max_timeout = 100
+};
+
+/** @internal Timer routine for the incoming request. */
+static inline
+int incoming_timer(nta_agent_t *sa, su_duration_t now)
+{
+ nta_incoming_t *irq, *irq_next;
+ size_t retransmitted = 0, timeout = 0, terminated = 0, destroyed = 0;
+ size_t unconfirmed =
+ sa->sa_in.inv_completed->q_length +
+ sa->sa_in.preliminary->q_length;
+ size_t unterminated =
+ sa->sa_in.inv_confirmed->q_length +
+ sa->sa_in.completed->q_length;
+ size_t total = sa->sa_incoming->iht_used;
+
+ incoming_queue_t rq[1];
+
+ incoming_queue_init(rq, 0);
+
+ /* Handle retry queue */
+ while ((irq = sa->sa_in.re_list)) {
+ if ((irq->irq_retry && irq->irq_retry - now > 0) ||
+ retransmitted >= timer_max_retransmit)
+ break;
+
+ if (irq->irq_method == sip_method_invite && irq->irq_status >= 200) {
+ /* Timer G */
+ assert(irq->irq_queue == sa->sa_in.inv_completed);
+
+ retransmitted++;
+
+ SU_DEBUG_5(("nta: timer %s fired, retransmitting %u reply\n",
+ "G", irq->irq_status));
+
+ incoming_retransmit_reply(irq, irq->irq_tport);
+
+ if (2U * irq->irq_interval < sa->sa_t2)
+ incoming_set_timer(irq, 2U * irq->irq_interval); /* G */
+ else
+ incoming_set_timer(irq, sa->sa_t2); /* G */
+ }
+ else if (irq->irq_method == sip_method_invite && irq->irq_status >= 100) {
+ if (irq->irq_queue == sa->sa_in.preliminary) {
+ /* Timer P1 - PRACK timer */
+ retransmitted++;
+ SU_DEBUG_5(("nta: timer %s fired, retransmitting %u reply\n",
+ "P1", irq->irq_status));
+
+ incoming_retransmit_reply(irq, irq->irq_tport);
+
+ incoming_set_timer(irq, 2 * irq->irq_interval); /* P1 */
+ }
+ else {
+ /* Retransmitting provisional responses */
+ SU_DEBUG_5(("nta: timer %s fired, retransmitting %u reply\n",
+ "N2", irq->irq_status));
+ incoming_set_timer(irq, sa->sa_progress);
+ retransmitted++;
+ incoming_retransmit_reply(irq, irq->irq_tport);
+ }
+ } else {
+ /* Timer N1 */
+ SU_DEBUG_5(("nta: timer N1 fired, sending %u %s\n", SIP_100_TRYING));
+ incoming_reset_timer(irq);
+ nta_incoming_treply(irq, SIP_100_TRYING, TAG_END());
+ }
+ }
+
+ while ((irq = sa->sa_in.final_failed->q_head)) {
+ incoming_remove(irq);
+ irq->irq_final_failed = 0;
+
+ /* Report error to application */
+ SU_DEBUG_5(("nta: sending final response failed, timeout %u response\n",
+ irq->irq_status));
+ reliable_timeout(irq, 0);
+
+ nta_incoming_treply(irq, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
+
+ if (!irq->irq_final_failed) /* We have taken care of the error... */
+ continue;
+
+ if (irq->irq_destroyed) {
+ incoming_free_queue(rq, irq);
+ continue;
+ }
+
+ incoming_reset_timer(irq);
+ irq->irq_confirmed = 1;
+ irq->irq_terminated = 1;
+ incoming_queue(sa->sa_in.terminated, irq);
+ }
+
+ /* Timeouts.
+ * For each state the request is in, there is always a queue of its own
+ */
+ while ((irq = sa->sa_in.preliminary->q_head)) {
+ assert(irq->irq_status < 200);
+ assert(irq->irq_timeout);
+
+ if (irq->irq_timeout - now > 0
+ || timeout >= timer_max_timeout)
+ break;
+
+ timeout++;
+
+ /* Timer P2 - PRACK timer */
+ SU_DEBUG_5(("nta: timer %s fired, %s %u response\n",
+ "P2", "timeout", irq->irq_status));
+ incoming_reset_timer(irq);
+ irq->irq_timeout = 0;
+ reliable_timeout(irq, 1);
+ }
+
+ while ((irq = sa->sa_in.inv_completed->q_head)) {
+ assert(irq->irq_status >= 200);
+ assert(irq->irq_timeout);
+ assert(irq->irq_method == sip_method_invite);
+
+ if (irq->irq_timeout - now > 0 ||
+ timeout >= timer_max_timeout ||
+ terminated >= timer_max_terminate)
+ break;
+
+ /* Timer H */
+ SU_DEBUG_5(("nta: timer %s fired, %s %u response\n",
+ "H", "timeout and terminate", irq->irq_status));
+ irq->irq_confirmed = 1;
+ irq->irq_terminated = 1;
+ incoming_reset_timer(irq);
+ if (!irq->irq_destroyed) {
+ timeout++;
+ incoming_queue(sa->sa_in.terminated, irq);
+ /* report timeout error to user */
+ incoming_call_callback(irq, NULL, NULL);
+ } else {
+ timeout++;
+ terminated++;
+ incoming_free_queue(rq, irq);
+ }
+ }
+
+ while ((irq = sa->sa_in.inv_confirmed->q_head)) {
+ assert(irq->irq_timeout);
+ assert(irq->irq_status >= 200);
+ assert(irq->irq_method == sip_method_invite);
+
+ if (irq->irq_timeout - now > 0 ||
+ terminated >= timer_max_terminate)
+ break;
+
+ /* Timer I */
+ SU_DEBUG_5(("nta: timer %s fired, %s %u response\n",
+ "I", "terminate", irq->irq_status));
+
+ terminated++;
+ irq->irq_terminated = 1;
+
+ if (!irq->irq_destroyed)
+ incoming_queue(sa->sa_in.terminated, irq);
+ else
+ incoming_free_queue(rq, irq);
+ }
+
+ while ((irq = sa->sa_in.completed->q_head)) {
+ assert(irq->irq_status >= 200);
+ assert(irq->irq_timeout);
+ assert(irq->irq_method != sip_method_invite);
+
+ if (irq->irq_timeout - now > 0 ||
+ terminated >= timer_max_terminate)
+ break;
+
+ /* Timer J */
+
+ SU_DEBUG_5(("nta: timer %s fired, %s %u response\n",
+ "J", "terminate", irq->irq_status));
+
+ terminated++;
+ irq->irq_terminated = 1;
+
+ if (!irq->irq_destroyed)
+ incoming_queue(sa->sa_in.terminated, irq);
+ else
+ incoming_free_queue(rq, irq);
+ }
+
+ for (irq = sa->sa_in.terminated->q_head; irq; irq = irq_next) {
+ irq_next = irq->irq_next;
+ if (irq->irq_destroyed)
+ incoming_free_queue(rq, irq);
+ }
+
+ destroyed = incoming_mass_destroy(sa, rq);
+
+ if (retransmitted || timeout || terminated || destroyed)
+ SU_DEBUG_5(("nta_incoming_timer: "
+ MOD_ZU"/"MOD_ZU" resent, "
+ MOD_ZU"/"MOD_ZU" tout, "
+ MOD_ZU"/"MOD_ZU" term, "
+ MOD_ZU"/"MOD_ZU" free\n",
+ retransmitted, unconfirmed,
+ timeout, unconfirmed,
+ terminated, unterminated,
+ destroyed, total));
+
+ return
+ retransmitted >= timer_max_retransmit
+ || timeout >= timer_max_timeout
+ || terminated >= timer_max_terminate;
+}
+
+/** Mass destroy server transactions */
+static inline
+int incoming_mass_destroy(nta_agent_t *sa, incoming_queue_t *q)
+{
+ size_t destroyed = q->q_length;
+
+ if (destroyed > 2 && *sa->sa_terminator) {
+ su_msg_r m = SU_MSG_R_INIT;
+
+ if (su_msg_create(m,
+ su_clone_task(sa->sa_terminator),
+ su_root_task(sa->sa_root),
+ incoming_reclaim_queued,
+ sizeof(incoming_queue_t)) == SU_SUCCESS) {
+ incoming_queue_t *mq = su_msg_data(m)->a_incoming_queue;
+
+ *mq = *q;
+
+ if (su_msg_send(m) == SU_SUCCESS)
+ q->q_length = 0;
+ }
+ }
+
+ if (q->q_length > 0)
+ incoming_reclaim_queued(NULL, NULL, (void *)q);
+
+ return destroyed;
+}
+
+/* ====================================================================== */
+/* 8) Client-side (outgoing) transactions */
+
+#define HTABLE_HASH_ORQ(orq) ((orq)->orq_hash)
+
+HTABLE_BODIES_WITH(outgoing_htable, oht, nta_outgoing_t, HTABLE_HASH_ORQ,
+ size_t, hash_value_t);
+
+static nta_outgoing_t *outgoing_create(nta_agent_t *agent,
+ nta_response_f *callback,
+ nta_outgoing_magic_t *magic,
+ url_string_t const *route_url,
+ tp_name_t const *tpn,
+ msg_t *msg,
+ tag_type_t tag, tag_value_t value, ...);
+static int outgoing_features(nta_agent_t *agent, nta_outgoing_t *orq,
+ msg_t *msg, sip_t *sip,
+ tagi_t *tags);
+static void outgoing_prepare_send(nta_outgoing_t *orq);
+static void outgoing_send(nta_outgoing_t *orq, int retransmit);
+static void outgoing_try_tcp_instead(nta_outgoing_t *orq);
+static void outgoing_try_udp_instead(nta_outgoing_t *orq);
+static void outgoing_tport_error(nta_agent_t *agent, nta_outgoing_t *orq,
+ tport_t *tp, msg_t *msg, int error);
+static void outgoing_print_tport_error(nta_outgoing_t *orq,
+ int level, char *todo,
+ tp_name_t const *, msg_t *, int error);
+static void outgoing_insert(nta_agent_t *sa, nta_outgoing_t *orq);
+static void outgoing_destroy(nta_outgoing_t *orq);
+static inline int outgoing_is_queued(nta_outgoing_t const *orq);
+static inline void outgoing_queue(outgoing_queue_t *queue,
+ nta_outgoing_t *orq);
+static inline void outgoing_remove(nta_outgoing_t *orq);
+static inline void outgoing_set_timer(nta_outgoing_t *orq, unsigned interval);
+static inline void outgoing_reset_timer(nta_outgoing_t *orq);
+static size_t outgoing_timer_dk(outgoing_queue_t *q,
+ char const *timer,
+ su_duration_t now);
+static size_t outgoing_timer_bf(outgoing_queue_t *q,
+ char const *timer,
+ su_duration_t now);
+
+static void outgoing_ack(nta_outgoing_t *orq, msg_t *msg, sip_t *sip);
+static msg_t *outgoing_ackmsg(nta_outgoing_t *, sip_method_t, char const *,
+ tagi_t const *tags);
+static void outgoing_retransmit(nta_outgoing_t *orq);
+static void outgoing_trying(nta_outgoing_t *orq);
+static void outgoing_timeout(nta_outgoing_t *orq, su_duration_t now);
+static int outgoing_complete(nta_outgoing_t *orq);
+static int outgoing_terminate(nta_outgoing_t *orq);
+static size_t outgoing_mass_destroy(nta_agent_t *sa, outgoing_queue_t *q);
+static void outgoing_estimate_delay(nta_outgoing_t *orq, sip_t *sip);
+static int outgoing_duplicate(nta_outgoing_t *orq,
+ msg_t *msg,
+ sip_t *sip);
+static int outgoing_reply(nta_outgoing_t *orq,
+ int status, char const *phrase,
+ int delayed);
+
+static int outgoing_default_cb(nta_outgoing_magic_t *magic,
+ nta_outgoing_t *request,
+ sip_t const *sip);
+
+#if HAVE_SOFIA_SRESOLV
+static void outgoing_resolve(nta_outgoing_t *orq);
+static inline void outgoing_cancel_resolver(nta_outgoing_t *orq);
+static inline void outgoing_destroy_resolver(nta_outgoing_t *orq);
+static int outgoing_other_destinations(nta_outgoing_t const *orq);
+static int outgoing_try_another(nta_outgoing_t *orq);
+#else
+#define outgoing_other_destinations(orq) (0)
+#define outgoing_try_another(orq) (0)
+#endif
+
+/** Create a default outgoing transaction.
+ *
+ * The default outgoing transaction is used when agent receives responses
+ * not belonging to any transaction.
+ *
+ * @sa nta_leg_default(), nta_incoming_default().
+ */
+nta_outgoing_t *nta_outgoing_default(nta_agent_t *agent,
+ nta_response_f *callback,
+ nta_outgoing_magic_t *magic)
+{
+ nta_outgoing_t *orq;
+
+ if (agent == NULL)
+ return NULL;
+
+ if (agent->sa_default_outgoing)
+ return NULL;
+
+ orq = su_zalloc(agent->sa_home, sizeof *orq);
+ if (!orq)
+ return NULL;
+
+ orq->orq_agent = agent;
+ orq->orq_callback = callback;
+ orq->orq_magic = magic;
+ orq->orq_method = sip_method_invalid;
+ orq->orq_method_name = "*";
+ orq->orq_default = 1;
+ orq->orq_stateless = 1;
+ orq->orq_delay = UINT_MAX;
+
+ return agent->sa_default_outgoing = orq;
+}
+
+/**Create an outgoing request and client transaction belonging to the leg.
+ *
+ * The function nta_outgoing_tcreate() creates a request message and passes
+ * the request message to an outgoing client transaction object. The request
+ * is sent to the @a route_url (if non-NULL), default proxy (if defined by
+ * NTATAG_DEFAULT_PROXY()), or to the address specified by @a request_uri.
+ * If no @a request_uri is specified, it is taken from route-set target or
+ * from the @To header.
+ *
+ * When NTA receives response to the request, it invokes the @a callback
+ * function.
+ *
+ * @param leg call leg object
+ * @param callback callback function (may be @c NULL)
+ * @param magic application context pointer
+ * @param route_url optional URL used to route transaction requests
+ * @param method method type
+ * @param name method name
+ * @param request_uri Request-URI
+ * @param tag, value, ... list of tagged arguments
+ *
+ * @return
+ * A pointer to a newly created outgoing transaction object if successful,
+ * and NULL otherwise.
+ *
+ * @note If NTATAG_STATELESS(1) tag is given and the @a callback is NULL,
+ * the transaction object is marked as destroyed from the beginning. In that
+ * case, the function may return @code (nta_outgoing_t *)-1 @endcode if the
+ * transaction is freed before returning from the function.
+ *
+ * @sa
+ * nta_outgoing_mcreate(), nta_outgoing_tcancel(), nta_outgoing_destroy().
+ *
+ * @TAGS
+ * NTATAG_STATELESS(), NTATAG_DELAY_SENDING(), NTATAG_BRANCH_KEY(),
+ * NTATAG_ACK_BRANCH(), NTATAG_DEFAULT_PROXY(), NTATAG_PASS_100(),
+ * NTATAG_USE_TIMESTAMP(), NTATAG_USER_VIA(), TPTAG_IDENT(), NTATAG_TPORT(). All
+ * SIP tags from <sip_tag.h> can be used to manipulate the request message.
+ * SIP tags after SIPTAG_END() are ignored, however.
+ */
+nta_outgoing_t *nta_outgoing_tcreate(nta_leg_t *leg,
+ nta_response_f *callback,
+ nta_outgoing_magic_t *magic,
+ url_string_t const *route_url,
+ sip_method_t method,
+ char const *name,
+ url_string_t const *request_uri,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ nta_agent_t *agent;
+ msg_t *msg;
+ sip_t *sip;
+ nta_outgoing_t *orq = NULL;
+ ta_list ta;
+
+ if (leg == NULL)
+ return NULL;
+
+ agent = leg->leg_agent;
+ msg = nta_msg_create(agent, 0);
+ sip = sip_object(msg);
+
+ if (route_url == NULL)
+ route_url = (url_string_t *)agent->sa_default_proxy;
+
+ ta_start(ta, tag, value);
+
+ if (sip_add_tl(msg, sip, ta_tags(ta)) < 0)
+ ;
+ else if (route_url == NULL && leg->leg_route &&
+ leg->leg_loose_route &&
+ !(route_url = (url_string_t *)leg->leg_route->r_url))
+ ;
+ else if (nta_msg_request_complete(msg, leg, method, name, request_uri) < 0)
+ ;
+ else
+ orq = outgoing_create(agent, callback, magic, route_url, NULL, msg,
+ ta_tags(ta));
+
+ ta_end(ta);
+
+ if (!orq)
+ msg_destroy(msg);
+
+ return orq;
+}
+
+/**Create an outgoing client transaction.
+ *
+ * Create an outgoing transaction object. The request message is passed to
+ * the transaction object, which sends the request to the network. The
+ * request is sent to the @a route_url (if non-NULL), default proxy (if
+ * defined by NTATAG_DEFAULT_PROXY()), or to the address specified by @a
+ * request_uri. If no @a request_uri is specified, it is taken from
+ * route-set target or from the @To header.
+ *
+ * When NTA receives response to the request, it invokes the @a callback
+ * function.
+ *
+ * @param agent NTA agent object
+ * @param callback callback function (may be @c NULL)
+ * @param magic application context pointer
+ * @param route_url optional URL used to route transaction requests
+ * @param msg request message
+ * @param tag, value, ... tagged parameter list
+ *
+ * @return
+ * Returns a pointer to newly created outgoing transaction object if
+ * successful, and NULL otherwise.
+ *
+ * @note The caller is responsible for destroying the request message @a msg
+ * upon failure.
+ *
+ * @note If NTATAG_STATELESS(1) tag is given and the @a callback is NULL,
+ * the transaction object is marked as destroyed from the beginning. In that
+ * case, the function may return @code (nta_outgoing_t *)-1 @endcode if the
+ * transaction is freed before returning from the function.
+ *
+ * @sa
+ * nta_outgoing_tcreate(), nnta_outgoing_tcancel(), nta_outgoing_destroy().
+ *
+ * @TAGS
+ * NTATAG_STATELESS(), NTATAG_DELAY_SENDING(), NTATAG_BRANCH_KEY(),
+ * NTATAG_ACK_BRANCH(), NTATAG_DEFAULT_PROXY(), NTATAG_PASS_100(),
+ * NTATAG_USE_TIMESTAMP(), NTATAG_USER_VIA(), TPTAG_IDENT(), NTATAG_TPORT(). All
+ * SIP tags from <sip_tag.h> can be used to manipulate the request message.
+ * SIP tags after SIPTAG_END() are ignored, however.
+ */
+nta_outgoing_t *nta_outgoing_mcreate(nta_agent_t *agent,
+ nta_response_f *callback,
+ nta_outgoing_magic_t *magic,
+ url_string_t const *route_url,
+ msg_t *msg,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ nta_outgoing_t *orq = NULL;
+ int cleanup = 0;
+
+ if (msg == NONE)
+ msg = nta_msg_create(agent, 0), cleanup = 1;
+
+ if (msg && agent) {
+ ta_list ta;
+ ta_start(ta, tag, value);
+ if (sip_add_tl(msg, sip_object(msg), ta_tags(ta)) >= 0)
+ orq = outgoing_create(agent, callback, magic, route_url, NULL, msg,
+ ta_tags(ta));
+ ta_end(ta);
+ }
+
+ if (!orq && cleanup)
+ msg_destroy(msg);
+
+ return orq;
+}
+
+/** Cancel the request. */
+int nta_outgoing_cancel(nta_outgoing_t *orq)
+{
+ nta_outgoing_t *cancel =
+ nta_outgoing_tcancel(orq, NULL, NULL, TAG_NULL());
+
+ return (cancel != NULL) - 1;
+}
+
+/** Cancel the request.
+ *
+ * Initiate a cancel transaction for client transaction @a orq.
+ *
+ * @param orq client transaction to cancel
+ * @param callback callback function (may be @c NULL)
+ * @param magic application context pointer
+ * @param tag, value, ... list of extra arguments
+ *
+ * @note The function may return @code (nta_outgoing_t *)-1 @endcode (NONE)
+ * if callback is NULL.
+ *
+ * @TAGS
+ * NTATAG_CANCEL_2534(), NTATAG_CANCEL_408() and all the tags that are
+ * accepted by nta_outgoing_tcreate().
+ *
+ * If NTATAG_CANCEL_408(1) or NTATAG_CANCEL_2543(1) is given, the stack
+ * generates a 487 response to the request internally. If
+ * NTATAG_CANCEL_408(1) is given, no CANCEL request is actually sent.
+ *
+ * @note
+ * nta_outgoing_tcancel() refuses to send a CANCEL request for non-INVITE
+ * requests.
+ */
+nta_outgoing_t *nta_outgoing_tcancel(nta_outgoing_t *orq,
+ nta_response_f *callback,
+ nta_outgoing_magic_t *magic,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ msg_t *msg;
+ int cancel_2543, cancel_408;
+ ta_list ta;
+ int delay_sending;
+
+ if (orq == NULL || orq == NONE)
+ return NULL;
+
+ if (orq->orq_destroyed) {
+ SU_DEBUG_3(("%s: trying to cancel destroyed request\n", __func__));
+ return NULL;
+ }
+ if (orq->orq_method != sip_method_invite) {
+ SU_DEBUG_3(("%s: trying to cancel non-INVITE request\n", __func__));
+ return NULL;
+ }
+ if (orq->orq_status >= 200
+ /* && orq->orq_method != sip_method_invite ... !multicast */) {
+ SU_DEBUG_3(("%s: trying to cancel completed request\n", __func__));
+ return NULL;
+ }
+ if (orq->orq_canceled) {
+ SU_DEBUG_3(("%s: trying to cancel cancelled request\n", __func__));
+ return NULL;
+ }
+ orq->orq_canceled = 1;
+
+#if HAVE_SOFIA_SRESOLV
+ if (!orq->orq_resolved) {
+ if (orq->orq_resolver)
+ outgoing_cancel_resolver(orq);
+ outgoing_reply(orq, SIP_487_REQUEST_CANCELLED, 1);
+ return NULL; /* XXX - Does anyone care about reply? */
+ }
+#endif
+
+ cancel_408 = 0; /* Don't really CANCEL, this is timeout. */
+ cancel_2543 = orq->orq_agent->sa_cancel_2543;
+ /* CANCEL may be sent only after a provisional response has been received. */
+ delay_sending = orq->orq_status < 100;
+
+ ta_start(ta, tag, value);
+
+ tl_gets(ta_args(ta),
+ NTATAG_CANCEL_408_REF(cancel_408),
+ NTATAG_CANCEL_2543_REF(cancel_2543),
+ TAG_END());
+
+ if (!cancel_408)
+ msg = outgoing_ackmsg(orq, SIP_METHOD_CANCEL, ta_args(ta));
+ else
+ msg = NULL;
+
+ ta_end(ta);
+
+ if ((cancel_2543 || cancel_408) &&
+ !orq->orq_stateless && !orq->orq_destroyed)
+ outgoing_reply(orq, SIP_487_REQUEST_CANCELLED, 1);
+
+ if (msg) {
+ nta_outgoing_t *cancel;
+ if (cancel_2543) /* Follow RFC 2543 semantics for CANCEL */
+ delay_sending = 0;
+
+ cancel = outgoing_create(orq->orq_agent, callback, magic,
+ NULL, orq->orq_tpn, msg,
+ NTATAG_BRANCH_KEY(orq->orq_branch),
+ NTATAG_DELAY_SENDING(delay_sending),
+ NTATAG_USER_VIA(1),
+ TAG_END());
+
+ if (delay_sending)
+ orq->orq_cancel = cancel;
+
+ if (cancel)
+ return cancel;
+
+ msg_destroy(msg);
+ }
+
+ return NULL;
+}
+
+/**
+ * Destroy a request object.
+ *
+ * @note
+ * This function does not actually free the object, but marks it as
+ * disposable. The object is freed after a timeout.
+ */
+void nta_outgoing_destroy(nta_outgoing_t *orq)
+{
+ if (orq == NULL || orq == NONE)
+ return;
+
+ if (orq->orq_destroyed) {
+ SU_DEBUG_1(("nta_outgoing_destroy(%p): already destroyed\n", orq));
+ return;
+ }
+
+ outgoing_destroy(orq);
+}
+
+/** Return the request URI */
+url_t const *nta_outgoing_request_uri(nta_outgoing_t const *orq)
+{
+ return orq != NULL && orq != NONE ? orq->orq_url : NULL;
+}
+
+/** Return the URI used to route the request */
+url_t const *nta_outgoing_route_uri(nta_outgoing_t const *orq)
+{
+ return orq != NULL && orq != NONE ? orq->orq_route : NULL;
+}
+
+/** Return method of the client transaction */
+sip_method_t nta_outgoing_method(nta_outgoing_t const *orq)
+{
+ return orq != NULL && orq != NONE ? orq->orq_method : sip_method_invalid;
+}
+
+/** Return method name of the client transaction */
+char const *nta_outgoing_method_name(nta_outgoing_t const *orq)
+{
+ return orq != NULL && orq != NONE ? orq->orq_method_name : NULL;
+}
+
+/** Get sequence number of a client transaction.
+ */
+uint32_t nta_outgoing_cseq(nta_outgoing_t const *orq)
+{
+ return orq != NULL && orq != NONE && orq->orq_cseq
+ ? orq->orq_cseq->cs_seq : 0;
+}
+
+/**
+ * Get the status code of a client transaction.
+ */
+int nta_outgoing_status(nta_outgoing_t const *orq)
+{
+ /* Return 500 Internal server error for invalid handles. */
+ return orq != NULL && orq != NONE ? orq->orq_status : 500;
+}
+
+/** Get the RTT delay measured using @Timestamp header. */
+unsigned nta_outgoing_delay(nta_outgoing_t const *orq)
+{
+ return orq != NULL && orq != NONE ? orq->orq_delay : UINT_MAX;
+}
+
+/**Get reference to response message.
+ *
+ * Retrieve the latest incoming response message to the outgoing
+ * transaction. Note that the message is not copied, but a new reference to
+ * it is created instead.
+ *
+ * @param orq outgoing transaction handle
+ *
+ * @retval
+ * A pointer to response message is returned, or NULL if no response message
+ * has been received.
+ */
+msg_t *nta_outgoing_getresponse(nta_outgoing_t *orq)
+{
+ if (orq != NULL && orq != NONE)
+ return msg_ref_create(orq->orq_response);
+ else
+ return NULL;
+}
+
+/**Get request message.
+ *
+ * Retrieves the request message sent to the network. Note that the request
+ * message is @b not copied, but a new reference to it is created.
+ *
+ * @retval
+ * A pointer to the request message is returned, or NULL if an error
+ * occurred.
+ */
+msg_t *nta_outgoing_getrequest(nta_outgoing_t *orq)
+{
+ if (orq != NULL && orq != NONE)
+ return msg_ref_create(orq->orq_request);
+ else
+ return NULL;
+}
+
+/**Create an outgoing request.
+ *
+ * The function outgoing_create() creates an outgoing transaction object and
+ * sends the request to the network. The request is sent to the @a route_url
+ * (if non-NULL), default proxy (if defined by NTATAG_DEFAULT_PROXY()), or
+ * to the address specified by @a sip->sip_request->rq_url.
+ *
+ * When NTA receives response to the request, it invokes the @a callback
+ * function.
+ *
+ * @param agent nta agent object
+ * @param callback callback function (may be @c NULL)
+ * @param magic application context pointer
+ * @param route_url optional URL used to route transaction requests
+ * @param msg request message
+ * @param tpn (optional) transport name
+ * @param msg request message to
+ * @param tag, value, ... tagged arguments
+ *
+ * @return
+ * Returns a pointer to newly created outgoing transaction object if
+ * successful, and NULL otherwise.
+ *
+ * @note If NTATAG_STATELESS(1) tag is given and the @a callback is NULL,
+ * the transaction object is marked as destroyed from the beginning. In that
+ * case, the function may return @code (nta_outgoing_t *)-1 @endcode if the
+ * transaction is freed before returning from the function.
+ *
+ * @TAG NTATAG_TPORT must point to an existing transport object for
+ * 'agent' (the passed tport is otherwise ignored).
+ *
+ * @sa
+ * nta_outgoing_tcreate(), nta_outgoing_tcancel(), nta_outgoing_destroy().
+ */
+nta_outgoing_t *outgoing_create(nta_agent_t *agent,
+ nta_response_f *callback,
+ nta_outgoing_magic_t *magic,
+ url_string_t const *route_url,
+ tp_name_t const *tpn,
+ msg_t *msg,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ nta_outgoing_t *orq;
+ sip_t *sip;
+ su_home_t *home;
+ char const *comp = NONE;
+ char const *branch = NONE;
+ char const *ack_branch = NONE;
+ char const *tp_ident;
+ int delay_sending = 0, sigcomp_zap = 0;
+ int pass_100 = agent->sa_pass_100, use_timestamp = agent->sa_timestamp;
+ enum nta_res_order_e res_order = agent->sa_res_order;
+ struct sigcomp_compartment *cc = NULL;
+ ta_list ta;
+ char const *scheme = NULL;
+ char const *port = NULL;
+ int invalid, resolved, stateless = 0, user_via = agent->sa_user_via;
+ tagi_t const *t;
+ tport_t const *override_tport = NULL;
+
+ if (!agent->sa_tport_ip6)
+ res_order = nta_res_ip4_only;
+ else if (!agent->sa_tport_ip4)
+ res_order = nta_res_ip6_only;
+
+ if (!callback)
+ callback = outgoing_default_cb;
+ if (!route_url)
+ route_url = (url_string_t *)agent->sa_default_proxy;
+
+ sip = sip_object(msg);
+ home = msg_home(msg);
+
+ if (!sip->sip_request || sip_complete_message(msg) < 0) {
+ SU_DEBUG_3(("nta: outgoing_create: incomplete request\n"));
+ return NULL;
+ }
+
+ if (!route_url && !tpn && sip->sip_route &&
+ sip->sip_route->r_url->url_params &&
+ url_param(sip->sip_route->r_url->url_params, "lr", NULL, 0))
+ route_url = (url_string_t *)sip->sip_route->r_url;
+
+ if (!(orq = su_zalloc(agent->sa_home, sizeof(*orq))))
+ return NULL;
+
+ tp_ident = tpn ? tpn->tpn_ident : NULL;
+
+ ta_start(ta, tag, value);
+
+ /* tl_gets() is a bit too slow here... */
+ for (t = ta_args(ta); t; t = tl_next(t)) {
+ tag_type_t tt = t->t_tag;
+
+ if (ntatag_stateless == tt)
+ stateless = t->t_value != 0;
+ else if (ntatag_delay_sending == tt)
+ delay_sending = t->t_value != 0;
+ else if (ntatag_branch_key == tt)
+ branch = (void *)t->t_value;
+ else if (ntatag_pass_100 == tt)
+ pass_100 = t->t_value != 0;
+ else if (ntatag_use_timestamp == tt)
+ use_timestamp = t->t_value != 0;
+ else if (ntatag_user_via == tt)
+ user_via = t->t_value != 0;
+ else if (ntatag_ack_branch == tt)
+ ack_branch = (void *)t->t_value;
+ else if (ntatag_default_proxy == tt)
+ route_url = (void *)t->t_value;
+ else if (tptag_ident == tt)
+ tp_ident = (void *)t->t_value;
+ else if (ntatag_comp == tt)
+ comp = (char const *)t->t_value;
+ else if (ntatag_sigcomp_close == tt)
+ sigcomp_zap = t->t_value != 0;
+ else if (tptag_compartment == tt)
+ cc = (void *)t->t_value;
+ else if (ntatag_tport == tt) {
+ override_tport = (tport_t *)t->t_value;
+ }
+ }
+
+ orq->orq_agent = agent;
+ orq->orq_callback = callback;
+ orq->orq_magic = magic;
+ orq->orq_method = sip->sip_request->rq_method;
+ orq->orq_method_name = sip->sip_request->rq_method_name;
+ orq->orq_cseq = sip->sip_cseq;
+ orq->orq_to = sip->sip_to;
+ orq->orq_from = sip->sip_from;
+ orq->orq_call_id = sip->sip_call_id;
+ orq->orq_tags = tl_afilter(home, tport_tags, ta_args(ta));
+ orq->orq_delayed = delay_sending != 0;
+ orq->orq_pass_100 = pass_100 != 0;
+ orq->orq_sigcomp_zap = sigcomp_zap;
+ orq->orq_sigcomp_new = comp != NONE && comp != NULL;
+ orq->orq_res_order = res_order;
+ orq->orq_timestamp = use_timestamp;
+ orq->orq_delay = UINT_MAX;
+ orq->orq_stateless = stateless != 0;
+ orq->orq_user_via = user_via != 0 && sip->sip_via;
+ if (cc)
+ orq->orq_cc = nta_compartment_ref(cc);
+
+ /* Add supported features */
+ outgoing_features(agent, orq, msg, sip, ta_args(ta));
+
+ ta_end(ta);
+
+ /* select the tport to use for the outgoing message */
+ if (override_tport) {
+ /* note: no ref taken to the tport as its only used once here */
+ tpn = tport_name(override_tport);
+ }
+
+ if (route_url) {
+ invalid = nta_tpn_by_url(home, orq->orq_tpn, &scheme, &port, route_url);
+ resolved = tport_name_is_resolved(orq->orq_tpn);
+ orq->orq_url = url_hdup(home, sip->sip_request->rq_url);
+ if (route_url != (url_string_t *)agent->sa_default_proxy)
+ orq->orq_route = url_hdup(home, route_url->us_url);
+ }
+ else if (tpn) {
+ invalid = tport_name_dup(home, orq->orq_tpn, tpn);
+#if HAVE_SOFIA_SRESOLV
+ assert(tport_name_is_resolved(orq->orq_tpn));
+#endif
+ resolved = tport_name_is_resolved(orq->orq_tpn);
+ orq->orq_url = url_hdup(home, sip->sip_request->rq_url);
+ scheme = "sip"; /* XXX */
+ }
+ else {
+ invalid = nta_tpn_by_url(home, orq->orq_tpn, &scheme, &port,
+ (url_string_t *)sip->sip_request->rq_url);
+ resolved = tport_name_is_resolved(orq->orq_tpn);
+ orq->orq_url = url_hdup(home, sip->sip_request->rq_url);
+ sip_fragment_clear(sip->sip_request->rq_common);
+ }
+
+ orq->orq_tpn->tpn_ident = tp_ident;
+ if (comp == NULL)
+ orq->orq_tpn->tpn_comp = comp;
+
+ if (orq->orq_user_via && str0cmp(orq->orq_tpn->tpn_proto, "*") == 0) {
+ char const *proto = sip_via_transport(sip->sip_via);
+ if (proto) orq->orq_tpn->tpn_proto = proto;
+ }
+
+ if (branch && branch != NONE) {
+ if (strchr(branch, '='))
+ branch = su_strdup(home, branch);
+ else
+ branch = su_sprintf(home, "branch=%s", branch);
+ }
+ else if (orq->orq_user_via && sip->sip_via->v_branch)
+ branch = su_sprintf(home, "branch=%s", sip->sip_via->v_branch);
+ else if (stateless)
+ branch = stateless_branch(agent, msg, sip, orq->orq_tpn);
+ else
+ branch = stateful_branch(home, agent);
+
+ orq->orq_branch = branch;
+ orq->orq_via_branch = branch;
+
+ if (orq->orq_method == sip_method_ack) {
+ if (ack_branch != NULL && ack_branch != NONE) {
+ orq->orq_branch = su_strdup(home, ack_branch);
+ }
+ else if (!stateless && agent->sa_is_a_uas) {
+ /*
+ * ACK redirect further 2XX messages to it.
+ *
+ * Use orq_branch from INVITE, but put a different branch in topmost Via.
+ */
+ nta_outgoing_t *invite = outgoing_find(agent, msg, sip, NULL);
+
+ if (invite) {
+ sip_t const *inv = sip_object(invite->orq_request);
+
+ orq->orq_branch = su_strdup(home, invite->orq_branch);
+
+ /* @RFC3261 section 13.2.2.4 -
+ * The ACK MUST contain the same credentials as the INVITE.
+ */
+ if (!sip->sip_proxy_authorization && !sip->sip_authorization) {
+ if (inv->sip_proxy_authorization)
+ sip_add_dup(msg, sip, (void *)inv->sip_proxy_authorization);
+ if (inv->sip_authorization)
+ sip_add_dup(msg, sip, (void *)inv->sip_authorization);
+ }
+ }
+ else {
+ SU_DEBUG_1(("outgoing_create: ACK without INVITE\n"));
+ assert(!"INVITE found for ACK");
+ }
+ }
+ }
+
+#if HAVE_SOFIA_SRESOLV
+ if (!resolved)
+ orq->orq_tpn->tpn_port = port;
+ orq->orq_resolved = resolved;
+#else
+ orq->orq_resolved = resolved = 1;
+#endif
+ orq->orq_scheme = scheme;
+
+ if (invalid < 0 || !orq->orq_branch || msg_serialize(msg, (void *)sip) < 0) {
+ SU_DEBUG_3(("nta outgoing create: %s\n",
+ invalid < 0 ? "invalid URI" :
+ !orq->orq_branch ? "no branch" : "invalid message"));
+ outgoing_free(orq);
+ return NULL;
+ }
+
+ /* Now we are committed in sending the transaction */
+ orq->orq_request = msg;
+ agent->sa_stats->as_client_tr++;
+ orq->orq_hash = NTA_HASH(sip->sip_call_id, sip->sip_cseq->cs_seq);
+
+ if (resolved)
+ outgoing_prepare_send(orq);
+#if HAVE_SOFIA_SRESOLV
+ else
+ outgoing_resolve(orq);
+#endif
+
+ if (stateless &&
+ orq->orq_status >= 200 &&
+ callback == outgoing_default_cb) {
+ void *retval;
+
+ if (orq->orq_status < 300)
+ retval = (void *)-1; /* NONE */
+ else
+ retval = NULL, orq->orq_request = NULL;
+
+ outgoing_free(orq);
+
+ return retval;
+ }
+
+ assert(orq->orq_queue);
+
+ outgoing_insert(agent, orq);
+
+ return orq;
+}
+
+/** Prepare sending a request */
+static void
+outgoing_prepare_send(nta_outgoing_t *orq)
+{
+ nta_agent_t *sa = orq->orq_agent;
+ tport_t *tp;
+ tp_name_t *tpn = orq->orq_tpn;
+ int sips = strcasecmp(orq->orq_scheme, "sips") == 0;
+
+ /* Select transport by scheme */
+ if (sips && strcmp(tpn->tpn_proto, "*") == 0)
+ tpn->tpn_proto = "tls";
+
+ if (!tpn->tpn_port)
+ tpn->tpn_port = "";
+
+ tp = tport_by_name(sa->sa_tports, tpn);
+ orq->orq_tport = tport_ref(tp);
+
+ if (tpn->tpn_port[0] == '\0') {
+ if (sips || tport_has_tls(tp))
+ tpn->tpn_port = "5061";
+ else
+ tpn->tpn_port = "5060";
+ }
+
+ if (!orq->orq_tport) {
+ if (sips) {
+ SU_DEBUG_3(("nta outgoing create: no secure transport\n"));
+ outgoing_reply(orq, SIP_416_UNSUPPORTED_URI, 1);
+ }
+ else {
+ SU_DEBUG_3(("nta outgoing create: no transport protocol\n"));
+ outgoing_reply(orq, 503, "No transport", 1);
+ }
+ return;
+ }
+
+ if (outgoing_insert_via(orq, agent_tport_via(tp)) < 0) {
+ SU_DEBUG_3(("nta outgoing create: cannot insert Via line\n"));
+ outgoing_reply(orq, 503, "Cannot insert Via", 1);
+ return;
+ }
+
+ orq->orq_user_via = 1;
+
+#if HAVE_SOFIA_SMIME
+ {
+ sm_object_t *smime = sa->sa_smime;
+ sip_t *sip = sip_object(orq->orq_request);
+
+ if (sa->sa_smime &&
+ (sip->sip_request->rq_method == sip_method_invite ||
+ sip->sip_request->rq_method == sip_method_message)) {
+ msg_prepare(orq->orq_request);
+ if (sm_encode_message(smime, msg, sip, SM_ID_NULL) < 0) {
+ outgoing_tport_error(sa, orq, NULL,
+ orq->orq_request, su_errno());
+ return;
+ }
+ }
+ }
+#endif
+
+ orq->orq_prepared = 1;
+
+ if (orq->orq_delayed) {
+ SU_DEBUG_5(("nta: delayed sending %s (%u)\n",
+ orq->orq_method_name, orq->orq_cseq->cs_seq));
+ outgoing_queue(sa->sa_out.delayed, orq);
+ return;
+ }
+
+ outgoing_send(orq, 0);
+}
+
+/** Send a request */
+static void
+outgoing_send(nta_outgoing_t *orq, int retransmit)
+{
+ int err;
+ tp_name_t const *tpn = orq->orq_tpn;
+ msg_t *msg = orq->orq_request;
+ nta_agent_t *agent = orq->orq_agent;
+ tport_t *tp;
+ int once = 0;
+ su_time_t now = su_now();
+ tag_type_t tag = tag_skip;
+ tag_value_t value = 0;
+ struct sigcomp_compartment *cc; cc = NULL;
+
+ /* tport can be NULL if we are just switching network */
+ if (orq->orq_tport == NULL) {
+ outgoing_tport_error(agent, orq, NULL, orq->orq_request, ENETRESET);
+ return;
+ }
+
+ if (!retransmit)
+ orq->orq_sent = now;
+
+ if (orq->orq_timestamp) {
+ sip_t *sip = sip_object(msg);
+ sip_timestamp_t *ts =
+ sip_timestamp_format(msg_home(msg), "%lu.%06lu",
+ now.tv_sec, now.tv_usec);
+
+ if (ts) {
+ if (sip->sip_timestamp)
+ msg_header_remove(msg, (msg_pub_t *)sip, (msg_header_t *)sip->sip_timestamp);
+ msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)ts);
+ }
+ }
+
+ for (;;) {
+ if (tpn->tpn_comp == NULL) {
+ /* xyzzy */
+ }
+ else if (orq->orq_cc) {
+ cc = orq->orq_cc, orq->orq_cc = NULL;
+ }
+ else {
+ cc = agent_compression_compartment(agent, orq->orq_tport, tpn,
+ orq->orq_sigcomp_new);
+ }
+
+ if (orq->orq_try_udp_instead)
+ tag = tptag_mtu, value = 65535;
+
+ tp = tport_tsend(orq->orq_tport, msg, tpn,
+ tag, value,
+ IF_SIGCOMP_TPTAG_COMPARTMENT(cc)
+ TAG_NEXT(orq->orq_tags));
+ if (tp)
+ break;
+
+ err = msg_errno(orq->orq_request);
+
+ if (cc)
+ nta_compartment_decref(&cc);
+
+ /* RFC3261, 18.1.1 */
+ if (err == EMSGSIZE && !orq->orq_try_tcp_instead) {
+ if (strcasecmp(tpn->tpn_proto, "udp") == 0 ||
+ strcasecmp(tpn->tpn_proto, "*") == 0) {
+ outgoing_try_tcp_instead(orq);
+ continue;
+ }
+ }
+ else if (err == ECONNREFUSED && orq->orq_try_tcp_instead) {
+ if (strcasecmp(tpn->tpn_proto, "tcp") == 0 && msg_size(msg) <= 65535) {
+ outgoing_try_udp_instead(orq);
+ continue;
+ }
+ }
+ else if (err == EPIPE) {
+ /* Connection was closed */
+ if (!once++) {
+ orq->orq_retries++;
+ continue;
+ }
+ }
+
+ if (orq->orq_pending && orq->orq_tport)
+ tport_release(orq->orq_tport, orq->orq_pending, orq->orq_request,
+ NULL, orq, 0);
+
+ orq->orq_pending = 0;
+
+ outgoing_tport_error(agent, orq, NULL, orq->orq_request, err);
+
+ return;
+ }
+
+ agent->sa_stats->as_sent_msg++;
+ agent->sa_stats->as_sent_request++;
+ if (retransmit)
+ agent->sa_stats->as_retry_request++;
+
+ SU_DEBUG_5(("nta: %ssent %s (%u) to " TPN_FORMAT "\n",
+ retransmit ? "re" : "",
+ orq->orq_method_name, orq->orq_cseq->cs_seq,
+ TPN_ARGS(tpn)));
+
+ if (cc) {
+ if (orq->orq_cc)
+ nta_compartment_decref(&orq->orq_cc);
+ }
+
+ if (orq->orq_pending) {
+ assert(orq->orq_tport);
+ tport_release(orq->orq_tport, orq->orq_pending,
+ orq->orq_request, NULL, orq, 0);
+ orq->orq_pending = 0;
+ }
+
+ if (orq->orq_stateless) {
+ outgoing_reply(orq, 202, NULL, 202);
+ return;
+ }
+
+ if (orq->orq_method != sip_method_ack) {
+ orq->orq_pending = tport_pend(tp, orq->orq_request,
+ outgoing_tport_error, orq);
+ if (orq->orq_pending < 0)
+ orq->orq_pending = 0;
+ }
+
+ if (tp != orq->orq_tport) {
+ tport_decref(&orq->orq_tport);
+ orq->orq_tport = tport_ref(tp);
+ }
+
+ orq->orq_reliable = tport_is_reliable(tp);
+
+ if (retransmit)
+ return;
+
+ /* Set timers */
+ if (orq->orq_method == sip_method_ack) {
+ /* ACK */
+ outgoing_complete(orq); /* Timer K */
+ return;
+ }
+
+ outgoing_trying(orq); /* Timer B / F */
+
+ if (!orq->orq_reliable)
+ outgoing_set_timer(orq, agent->sa_t1); /* Timer A/E */
+ else if (orq->orq_try_tcp_instead && !tport_is_connected(tp))
+ outgoing_set_timer(orq, agent->sa_t4); /* Timer N3 */
+}
+
+static void
+outgoing_try_tcp_instead(nta_outgoing_t *orq)
+{
+ tport_t *tp;
+ tp_name_t tpn[1];
+
+ *tpn = *orq->orq_tpn;
+ tpn->tpn_proto = "tcp";
+ orq->orq_try_tcp_instead = 1;
+
+ tp = tport_by_name(orq->orq_agent->sa_tports, tpn);
+ if (tp && tp != orq->orq_tport) {
+ sip_t *sip = sip_object(orq->orq_request);
+ sip_fragment_clear(sip->sip_via->v_common);
+ sip->sip_via->v_protocol = sip_transport_tcp;
+
+ SU_DEBUG_5(("nta: %s (%u) too large for UDP, trying TCP\n",
+ orq->orq_method_name, orq->orq_cseq->cs_seq));
+
+ orq->orq_tpn->tpn_proto = "tcp";
+ tport_decref(&orq->orq_tport);
+ orq->orq_tport = tport_ref(tp);
+
+ return;
+ }
+
+ tpn->tpn_proto = "udp";
+ orq->orq_try_udp_instead = 1; /* Try again without SIP MTU limit */
+
+ tp = tport_by_name(orq->orq_agent->sa_tports, tpn);
+ if (tp && tp != orq->orq_tport) {
+ SU_DEBUG_5(("nta: %s (%u) exceed normal UDP size limit\n",
+ orq->orq_method_name, orq->orq_cseq->cs_seq));
+
+ tport_decref(&orq->orq_tport);
+ orq->orq_tport = tport_ref(tp);
+ }
+}
+
+static void
+outgoing_try_udp_instead(nta_outgoing_t *orq)
+{
+ tport_t *tp;
+ tp_name_t tpn[1];
+
+ *tpn = *orq->orq_tpn;
+ tpn->tpn_proto = "udp";
+ orq->orq_try_udp_instead = 1;
+
+ tp = tport_by_name(orq->orq_agent->sa_tports, tpn);
+ if (tp && tp != orq->orq_tport) {
+ sip_t *sip = sip_object(orq->orq_request);
+
+ sip_fragment_clear(sip->sip_via->v_common);
+ sip->sip_via->v_protocol = sip_transport_udp;
+
+ SU_DEBUG_5(("nta: %s (%u) TCP refused, trying UDP\n",
+ orq->orq_method_name, orq->orq_cseq->cs_seq));
+
+ orq->orq_tpn->tpn_proto = "udp";
+ tport_decref(&orq->orq_tport);
+ orq->orq_tport = tport_ref(tp);
+ }
+}
+
+
+/** @internal Report transport errors. */
+void
+outgoing_tport_error(nta_agent_t *agent, nta_outgoing_t *orq,
+ tport_t *tp, msg_t *msg, int error)
+{
+ tp_name_t const *tpn = tp ? tport_name(tp) : orq->orq_tpn;
+
+ if (orq->orq_pending) {
+ assert(orq->orq_tport);
+ tport_release(orq->orq_tport, orq->orq_pending, orq->orq_request,
+ NULL, orq, 0);
+ orq->orq_pending = 0;
+ }
+
+ if (error == EPIPE && orq->orq_retries++ == 0) {
+ /* XXX - we should retry only if the transport is not newly created */
+ outgoing_print_tport_error(orq, 5, "retrying once after ",
+ tpn, msg, error);
+ outgoing_send(orq, 1);
+ return;
+ }
+ else if (error == ECONNREFUSED && orq->orq_try_tcp_instead) {
+ /* RFC3261, 18.1.1 */
+ if (strcasecmp(tpn->tpn_proto, "tcp") == 0 && msg_size(msg) <= 65535) {
+ outgoing_print_tport_error(orq, 5, "retrying with UDP after ",
+ tpn, msg, error);
+ outgoing_try_udp_instead(orq);
+ outgoing_remove(orq); /* Reset state - this is no resend! */
+ outgoing_send(orq, 0); /* Send */
+ return;
+ }
+ }
+
+ if (outgoing_other_destinations(orq)) {
+ outgoing_print_tport_error(orq, 5, "trying alternative server after ",
+ tpn, msg, error);
+ outgoing_try_another(orq);
+ return;
+ }
+
+ outgoing_print_tport_error(orq, 3, "", tpn, msg, error);
+
+ outgoing_reply(orq, SIP_503_SERVICE_UNAVAILABLE, 0);
+}
+
+static
+void
+outgoing_print_tport_error(nta_outgoing_t *orq, int level, char *todo,
+ tp_name_t const *tpn, msg_t *msg, int error)
+{
+ su_sockaddr_t const *su = msg_addr(msg);
+ char addr[SU_ADDRSIZE];
+
+ su_llog(nta_log, level,
+ "nta: %s (%u): %s%s (%u) with %s/[%s]:%u\n",
+ orq->orq_method_name, orq->orq_cseq->cs_seq,
+ todo, su_strerror(error), error,
+ tpn->tpn_proto,
+ inet_ntop(su->su_family, SU_ADDR(su), addr, sizeof(addr)),
+ htons(su->su_port));
+}
+
+/**@internal
+ * Add features supported.
+ */
+static
+int outgoing_features(nta_agent_t *agent, nta_outgoing_t *orq,
+ msg_t *msg, sip_t *sip,
+ tagi_t *tags)
+{
+ char const *supported[8];
+ int i;
+
+ if (orq->orq_method != sip_method_invite) /* fast path for now */
+ return 0;
+
+ supported[i = 0] = NULL;
+
+ if (orq->orq_method == sip_method_invite) {
+ int add_100rel = agent->sa_invite_100rel;
+ int require_100rel = sip_has_feature(sip->sip_require, "100rel");
+
+ tl_gets(tags,
+ NTATAG_REL100_REF(add_100rel),
+ TAG_END());
+ if (add_100rel && !require_100rel &&
+ !sip_has_feature(sip->sip_supported, "100rel"))
+ supported[i++] = "100rel";
+
+ orq->orq_must_100rel = require_100rel;
+ }
+
+ if (i) {
+ supported[i] = NULL;
+
+ if (sip->sip_supported) {
+ su_home_t *home = msg_home(msg);
+ return msg_list_append_items(home, sip->sip_supported, supported);
+ }
+ else {
+ sip_supported_t s[1];
+ sip_supported_init(s);
+ s->k_items = supported;
+ return sip_add_dup(msg, sip, (sip_header_t *)s);
+ }
+ }
+
+ return 0;
+}
+
+
+/**@internal
+ * Insert outgoing request to agent hash table
+ */
+static
+void outgoing_insert(nta_agent_t *agent, nta_outgoing_t *orq)
+{
+ if (outgoing_htable_is_full(agent->sa_outgoing))
+ outgoing_htable_resize(agent->sa_home, agent->sa_outgoing, 0);
+ outgoing_htable_insert(agent->sa_outgoing, orq);
+ orq->orq_inserted = 1;
+}
+
+/** @internal
+ * Initialize a queue for outgoing transactions.
+ */
+static void
+outgoing_queue_init(outgoing_queue_t *queue, unsigned timeout)
+{
+ memset(queue, 0, sizeof *queue);
+ queue->q_tail = &queue->q_head;
+ queue->q_timeout = timeout;
+}
+
+/** Change the timeout value of a queue */
+static void
+outgoing_queue_adjust(nta_agent_t *sa,
+ outgoing_queue_t *queue,
+ unsigned timeout)
+{
+ nta_outgoing_t *orq;
+ su_duration_t latest;
+
+ if (timeout >= queue->q_timeout || !queue->q_head) {
+ queue->q_timeout = timeout;
+ return;
+ }
+
+ latest = set_timeout(sa, queue->q_timeout = timeout);
+
+ for (orq = queue->q_head; orq; orq = orq->orq_next) {
+ if (orq->orq_timeout - latest > 0)
+ orq->orq_timeout = latest;
+ }
+}
+
+/** @internal
+ * Test if an outgoing transaction is in a queue.
+ */
+static inline
+int outgoing_is_queued(nta_outgoing_t const *orq)
+{
+ return orq && orq->orq_queue;
+}
+
+/** @internal
+ * Insert an outgoing transaction into a queue.
+ *
+ * The function outgoing_queue() inserts a client transaction into a queue,
+ * and sets the corresponding timeout at the same time.
+ */
+static inline
+void outgoing_queue(outgoing_queue_t *queue,
+ nta_outgoing_t *orq)
+{
+ if (orq->orq_queue == queue) {
+ assert(queue->q_timeout == 0);
+ return;
+ }
+
+ if (outgoing_is_queued(orq))
+ outgoing_remove(orq);
+
+ assert(*queue->q_tail == NULL);
+
+ orq->orq_timeout = set_timeout(orq->orq_agent, queue->q_timeout);
+
+ orq->orq_queue = queue;
+ orq->orq_prev = queue->q_tail;
+ *queue->q_tail = orq;
+ queue->q_tail = &orq->orq_next;
+ queue->q_length++;
+}
+
+/** @internal
+ * Remove an outgoing transaction from a queue.
+ */
+static inline
+void outgoing_remove(nta_outgoing_t *orq)
+{
+ assert(outgoing_is_queued(orq));
+ assert(orq->orq_queue->q_length > 0);
+
+ if ((*orq->orq_prev = orq->orq_next))
+ orq->orq_next->orq_prev = orq->orq_prev;
+ else
+ orq->orq_queue->q_tail = orq->orq_prev, assert(!*orq->orq_queue->q_tail);
+
+ orq->orq_queue->q_length--;
+ orq->orq_next = NULL;
+ orq->orq_prev = NULL;
+ orq->orq_queue = NULL;
+ orq->orq_timeout = 0;
+}
+
+/** Set retransmit timer (orq_retry).
+ *
+ * The function outgoing_set_timer() will set the retry timer (B/D) on
+ * the outgoing request (client transaction).
+ */
+static inline
+void outgoing_set_timer(nta_outgoing_t *orq, unsigned interval)
+{
+ nta_outgoing_t **rq;
+
+ assert(orq);
+
+ if (interval == 0) {
+ outgoing_reset_timer(orq);
+ return;
+ }
+
+ if (orq->orq_rprev) {
+ /* Remove transaction from retry dequeue, re-insert it later. */
+ if ((*orq->orq_rprev = orq->orq_rnext))
+ orq->orq_rnext->orq_rprev = orq->orq_rprev;
+ if (orq->orq_agent->sa_out.re_t1 == &orq->orq_rnext)
+ orq->orq_agent->sa_out.re_t1 = orq->orq_rprev;
+ }
+ else {
+ orq->orq_agent->sa_out.re_length++;
+ }
+
+ orq->orq_retry = set_timeout(orq->orq_agent, orq->orq_interval = interval);
+
+ rq = orq->orq_agent->sa_out.re_t1;
+
+ if (!(*rq) || (*rq)->orq_retry - orq->orq_retry > 0)
+ rq = &orq->orq_agent->sa_out.re_list;
+
+ while (*rq && (*rq)->orq_retry - orq->orq_retry <= 0)
+ rq = &(*rq)->orq_rnext;
+
+ if ((orq->orq_rnext = *rq))
+ orq->orq_rnext->orq_rprev = &orq->orq_rnext;
+ *rq = orq;
+ orq->orq_rprev = rq;
+
+ if (interval == orq->orq_agent->sa_t1)
+ orq->orq_agent->sa_out.re_t1 = rq;
+}
+
+static inline
+void outgoing_reset_timer(nta_outgoing_t *orq)
+{
+ if (orq->orq_rprev) {
+ if ((*orq->orq_rprev = orq->orq_rnext))
+ orq->orq_rnext->orq_rprev = orq->orq_rprev;
+ if (orq->orq_agent->sa_out.re_t1 == &orq->orq_rnext)
+ orq->orq_agent->sa_out.re_t1 = orq->orq_rprev;
+ orq->orq_agent->sa_out.re_length--;
+ }
+
+ orq->orq_interval = 0, orq->orq_retry = 0;
+ orq->orq_rnext = NULL, orq->orq_rprev = NULL;
+}
+
+/** @internal
+ * Free resources associated with the request.
+ */
+static
+void outgoing_free(nta_outgoing_t *orq)
+{
+ SU_DEBUG_9(("nta: outgoing_free(%p)\n", orq));
+ outgoing_cut_off(orq);
+ outgoing_reclaim(orq);
+}
+
+/** Remove outgoing request from hash tables */
+static inline
+void outgoing_cut_off(nta_outgoing_t *orq)
+{
+ nta_agent_t *agent = orq->orq_agent;
+
+ if (orq->orq_default)
+ agent->sa_default_outgoing = NULL;
+
+ if (orq->orq_inserted)
+ outgoing_htable_remove(agent->sa_outgoing, orq), orq->orq_inserted = 0;
+
+ if (outgoing_is_queued(orq))
+ outgoing_remove(orq);
+
+ outgoing_reset_timer(orq);
+
+ if (orq->orq_pending) {
+ tport_release(orq->orq_tport, orq->orq_pending,
+ orq->orq_request, NULL, orq, 0);
+ }
+ orq->orq_pending = 0;
+
+ if (orq->orq_cc)
+ nta_compartment_decref(&orq->orq_cc);
+
+ if (orq->orq_tport)
+ tport_decref(&orq->orq_tport);
+}
+
+/** Reclaim outgoing request */
+static inline
+void outgoing_reclaim(nta_outgoing_t *orq)
+{
+ if (orq->orq_request)
+ msg_destroy(orq->orq_request), orq->orq_request = NULL;
+ if (orq->orq_response)
+ msg_destroy(orq->orq_response), orq->orq_response = NULL;
+#if HAVE_SOFIA_SRESOLV
+ if (orq->orq_resolver)
+ outgoing_destroy_resolver(orq);
+#endif
+ su_free(orq->orq_agent->sa_home, orq);
+}
+
+/** Queue request to be freed */
+static inline
+void outgoing_free_queue(outgoing_queue_t *q, nta_outgoing_t *orq)
+{
+ outgoing_cut_off(orq);
+ outgoing_queue(q, orq);
+}
+
+/** Reclaim memory used by queue of requests */
+static
+void outgoing_reclaim_queued(su_root_magic_t *rm,
+ su_msg_r msg,
+ union sm_arg_u *u)
+{
+ outgoing_queue_t *q = u->a_outgoing_queue;
+ nta_outgoing_t *orq, *orq_next;
+
+ SU_DEBUG_9(("outgoing_reclaim_all(%p, %p, %p)\n", rm, msg, u));
+
+ for (orq = q->q_head; orq; orq = orq_next) {
+ orq_next = orq->orq_next;
+ outgoing_reclaim(orq);
+ }
+}
+
+/** @internal Default callback for request */
+int outgoing_default_cb(nta_outgoing_magic_t *magic,
+ nta_outgoing_t *orq,
+ sip_t const *sip)
+{
+ if (sip == NULL || sip->sip_status->st_status >= 200)
+ outgoing_destroy(orq);
+ return 0;
+}
+
+/** @internal Destroy an outgoing transaction */
+void outgoing_destroy(nta_outgoing_t *orq)
+{
+ if (orq->orq_terminated || orq->orq_default) {
+ outgoing_free(orq);
+ }
+ else {
+ orq->orq_destroyed = 1;
+ orq->orq_callback = outgoing_default_cb;
+ orq->orq_magic = NULL;
+ }
+}
+
+/** @internal Outgoing transaction timer routine. */
+static
+int outgoing_timer(nta_agent_t *sa, su_duration_t now)
+{
+ nta_outgoing_t *orq;
+ outgoing_queue_t rq[1];
+ size_t retransmitted = 0, terminated = 0, timeout = 0, destroyed;
+ size_t total = sa->sa_outgoing->oht_used;
+ size_t trying = sa->sa_out.re_length;
+ size_t pending = sa->sa_out.trying->q_length + sa->sa_out.inv_calling->q_length;
+ size_t completed = sa->sa_out.completed->q_length +
+ sa->sa_out.inv_completed->q_length;
+
+ outgoing_queue_init(sa->sa_out.free = rq, 0);
+
+ while ((orq = sa->sa_out.re_list)) {
+ if ((orq->orq_retry && orq->orq_retry - now > 0)
+ || retransmitted >= timer_max_retransmit)
+ break;
+
+ if (orq->orq_reliable) {
+ outgoing_reset_timer(orq);
+
+ if (!tport_is_connected(orq->orq_tport)) {
+ /*
+ * Timer N3: try to use UDP if trying to send via TCP
+ * but no connection is established within SIP T4
+ */
+ SU_DEBUG_5(("nta: timer %s fired, %s %s (%u)\n", "N3",
+ "try UDP instead", orq->orq_method_name, orq->orq_cseq->cs_seq));
+ outgoing_try_udp_instead(orq);
+ }
+ continue;
+ }
+
+ assert(!orq->orq_reliable && orq->orq_interval != 0);
+
+ SU_DEBUG_5(("nta: timer %s fired, %s %s (%u)\n",
+ orq->orq_method == sip_method_invite ? "A" : "E",
+ "retransmit", orq->orq_method_name, orq->orq_cseq->cs_seq));
+
+ outgoing_retransmit(orq);
+
+ if (orq->orq_method == sip_method_invite ||
+ 2U * orq->orq_interval < sa->sa_t2)
+ outgoing_set_timer(orq, 2U * orq->orq_interval);
+ else
+ outgoing_set_timer(orq, sa->sa_t2);
+
+ if (++retransmitted % 5 == 0)
+ su_root_yield(sa->sa_root); /* Handle received packets */
+ }
+
+ terminated
+ = outgoing_timer_dk(sa->sa_out.inv_completed, "D", now)
+ + outgoing_timer_dk(sa->sa_out.completed, "K", now);
+
+ timeout
+ = outgoing_timer_bf(sa->sa_out.inv_calling, "B", now)
+ + outgoing_timer_bf(sa->sa_out.trying, "F", now);
+
+ destroyed = outgoing_mass_destroy(sa, rq);
+
+ sa->sa_out.free = NULL;
+
+ if (retransmitted || timeout || terminated || destroyed) {
+ SU_DEBUG_5(("nta_outgoing_timer: "
+ MOD_ZU"/"MOD_ZU" resent, "
+ MOD_ZU"/"MOD_ZU" tout, "
+ MOD_ZU"/"MOD_ZU" term, "
+ MOD_ZU"/"MOD_ZU" free\n",
+ retransmitted, trying,
+ timeout, pending,
+ terminated, completed,
+ destroyed, total));
+ }
+
+ return
+ retransmitted >= timer_max_retransmit ||
+ terminated >= timer_max_terminate ||
+ timeout >= timer_max_timeout;
+}
+
+/** @internal Retransmit the outgoing request. */
+void outgoing_retransmit(nta_outgoing_t *orq)
+{
+ if (orq->orq_prepared && !orq->orq_delayed) {
+ orq->orq_retries++;
+
+ if (orq->orq_retries >= 4 && orq->orq_cc) {
+ orq->orq_tpn->tpn_comp = NULL;
+ if (orq->orq_retries == 4) {
+ agent_close_compressor(orq->orq_agent, orq->orq_cc);
+ nta_compartment_decref(&orq->orq_cc);
+ }
+ }
+
+ outgoing_send(orq, 1);
+ }
+}
+
+/** Trying a client transaction. */
+static
+void outgoing_trying(nta_outgoing_t *orq)
+{
+ if (orq->orq_method == sip_method_invite)
+ outgoing_queue(orq->orq_agent->sa_out.inv_calling, orq);
+ else
+ outgoing_queue(orq->orq_agent->sa_out.trying, orq);
+}
+
+/** Handle timers B and F */
+static
+size_t outgoing_timer_bf(outgoing_queue_t *q,
+ char const *timer,
+ su_duration_t now)
+{
+ size_t timeout = 0;
+
+ for (;;) {
+ nta_outgoing_t *orq = q->q_head;
+
+ if (!orq
+ || !orq->orq_timeout
+ || orq->orq_timeout - now > 0
+ || timeout >= timer_max_timeout)
+ return timeout;
+
+ timeout++;
+
+ SU_DEBUG_5(("nta: timer %s fired, %s %s (%u)\n",
+ timer, "timeout",
+ orq->orq_method_name, orq->orq_cseq->cs_seq));
+
+ outgoing_timeout(orq, now);
+
+ assert(q->q_head != orq || orq->orq_timeout - now > 0);
+ }
+}
+
+/** @internal Signal transaction timeout to the application. */
+void outgoing_timeout(nta_outgoing_t *orq, su_duration_t now)
+{
+ nta_outgoing_t *cancel;
+
+ if (outgoing_other_destinations(orq)) {
+ SU_DEBUG_5(("nta(%p): try next after timeout\n", orq));
+ outgoing_try_another(orq);
+ return;
+ }
+
+ cancel = orq->orq_cancel; orq->orq_cancel = NULL;
+ orq->orq_agent->sa_stats->as_tout_request++;
+
+ outgoing_reply(orq, SIP_408_REQUEST_TIMEOUT, 0);
+
+ if (cancel)
+ outgoing_timeout(cancel, now);
+}
+
+/** Complete a client transaction.
+ *
+ * @return True if transaction was free()d.
+ */
+static
+int outgoing_complete(nta_outgoing_t *orq)
+{
+ orq->orq_completed = 1;
+
+ outgoing_reset_timer(orq); /* Timer A/E */
+
+ if (orq->orq_stateless)
+ return outgoing_terminate(orq);
+
+ if (orq->orq_reliable && orq->orq_method != sip_method_ack)
+ return outgoing_terminate(orq);
+
+ if (orq->orq_method == sip_method_invite) {
+ outgoing_queue(orq->orq_agent->sa_out.inv_completed, orq); /* Timer D */
+ }
+ else {
+ outgoing_queue(orq->orq_agent->sa_out.completed, orq); /* Timer K */
+ }
+
+ return 0;
+}
+
+/** Handle timers D and K */
+static
+size_t outgoing_timer_dk(outgoing_queue_t *q,
+ char const *timer,
+ su_duration_t now)
+{
+ size_t terminated = 0;
+
+ for (;;) {
+ nta_outgoing_t *orq = q->q_head;
+
+ if (!orq
+ || !orq->orq_timeout
+ || orq->orq_timeout - now > 0
+ || terminated >= timer_max_terminate)
+ return terminated;
+
+ terminated++;
+
+ SU_DEBUG_5(("nta: timer %s fired, %s %s (%u)\n", timer,
+ "terminate", orq->orq_method_name, orq->orq_cseq->cs_seq));
+
+ outgoing_terminate(orq);
+ }
+}
+
+/** Terminate a client transaction. */
+static
+int outgoing_terminate(nta_outgoing_t *orq)
+{
+ orq->orq_terminated = 1;
+
+ if (!orq->orq_destroyed) {
+ outgoing_queue(orq->orq_agent->sa_out.terminated, orq);
+ return 0;
+ }
+ else if (orq->orq_agent->sa_out.free) {
+ outgoing_free_queue(orq->orq_agent->sa_out.free, orq);
+ return 1;
+ }
+ else {
+ outgoing_free(orq);
+ return 1;
+ }
+}
+
+/** Mass destroy client transactions */
+static
+size_t outgoing_mass_destroy(nta_agent_t *sa, outgoing_queue_t *q)
+{
+ size_t destroyed = q->q_length;
+
+ if (destroyed > 2 && *sa->sa_terminator) {
+ su_msg_r m = SU_MSG_R_INIT;
+
+ if (su_msg_create(m,
+ su_clone_task(sa->sa_terminator),
+ su_root_task(sa->sa_root),
+ outgoing_reclaim_queued,
+ sizeof(outgoing_queue_t)) == SU_SUCCESS) {
+ outgoing_queue_t *mq = su_msg_data(m)->a_outgoing_queue;
+
+ *mq = *q;
+
+ if (su_msg_send(m) == SU_SUCCESS)
+ q->q_length = 0;
+ }
+ }
+
+ if (q->q_length)
+ outgoing_reclaim_queued(NULL, NULL, (void*)q);
+
+ return destroyed;
+}
+
+/** Find an outgoing request corresponging to a message and @Via line.
+ *
+ * Return an outgoing request object based on a message and the @Via line
+ * given as argument. This function is used when doing loop checking: if we
+ * have sent the request and it has been routed back to us.
+ *
+ * @param agent
+ * @param msg
+ * @param sip
+ * @param v
+ */
+nta_outgoing_t *nta_outgoing_find(nta_agent_t const *agent,
+ msg_t const *msg,
+ sip_t const *sip,
+ sip_via_t const *v)
+{
+ if (agent == NULL || msg == NULL || sip == NULL || v == NULL) {
+ su_seterrno(EFAULT);
+ return NULL;
+ }
+
+ return outgoing_find(agent, msg, sip, v);
+}
+
+/**@internal
+ *
+ * Find an outgoing request corresponging to a message and @Via line.
+ *
+ */
+nta_outgoing_t *outgoing_find(nta_agent_t const *sa,
+ msg_t const *msg,
+ sip_t const *sip,
+ sip_via_t const *v)
+{
+ nta_outgoing_t **oo, *orq;
+ outgoing_htable_t const *oht = sa->sa_outgoing;
+ sip_cseq_t const *cseq = sip->sip_cseq;
+ sip_call_id_t const *i = sip->sip_call_id;
+ hash_value_t hash;
+ sip_method_t method, method2;
+ unsigned short status = sip->sip_status ? sip->sip_status->st_status : 0;
+
+ if (cseq == NULL)
+ return NULL;
+
+ hash = NTA_HASH(i, cseq->cs_seq);
+
+ method = cseq->cs_method;
+
+ /* Get original invite when ACKing */
+ if (sip->sip_request && method == sip_method_ack && v == NULL)
+ method = sip_method_invite, method2 = sip_method_invalid;
+ else if (sa->sa_is_a_uas && status >= 200 && method == sip_method_invite)
+ method2 = sip_method_ack;
+ else
+ method2 = method;
+
+ for (oo = outgoing_htable_hash(oht, hash);
+ (orq = *oo);
+ oo = outgoing_htable_next(oht, oo)) {
+ if (orq->orq_stateless)
+ continue;
+ /* Accept terminated transactions when looking for original INVITE */
+ if (orq->orq_terminated && method2 != sip_method_invalid)
+ continue;
+ if (hash != orq->orq_hash)
+ continue;
+ if (orq->orq_call_id->i_hash != i->i_hash ||
+ strcmp(orq->orq_call_id->i_id, i->i_id))
+ continue;
+ if (orq->orq_cseq->cs_seq != cseq->cs_seq)
+ continue;
+ if (method == sip_method_unknown &&
+ strcmp(orq->orq_cseq->cs_method_name, cseq->cs_method_name))
+ continue;
+ if (orq->orq_method != method && orq->orq_method != method2)
+ continue;
+ if (str0casecmp(orq->orq_from->a_tag, sip->sip_from->a_tag))
+ continue;
+ if (orq->orq_to->a_tag && sip->sip_to->a_tag
+ ? strcasecmp(orq->orq_to->a_tag, sip->sip_to->a_tag)
+ : !addr_match(orq->orq_to, sip->sip_to))
+ continue;
+ if (orq->orq_method == method ?
+ /* Don't match if request To has a tag and response has no To tag */
+ orq->orq_to->a_tag && !sip->sip_to->a_tag :
+ /* Don't (with ACK) if request/response tag mismatch */
+ !orq->orq_to->a_tag != !sip->sip_to->a_tag)
+ continue;
+
+ if (orq->orq_method == sip_method_ack) {
+ if (orq->orq_ack_error ? status < 300 : status >= 300)
+ continue;
+ }
+
+ if (v && str0casecmp(orq->orq_branch + strlen("branch="), v->v_branch))
+ continue;
+
+ break; /* match */
+ }
+
+ return orq;
+}
+
+/** Process a response message. */
+int outgoing_recv(nta_outgoing_t *orq,
+ int status,
+ msg_t *msg,
+ sip_t *sip)
+{
+ nta_agent_t *sa = orq->orq_agent;
+ short orq_status = orq->orq_status;
+
+ if (status < 100) status = 100;
+
+ if (sip && orq->orq_delay == UINT_MAX)
+ outgoing_estimate_delay(orq, sip);
+
+ if (orq->orq_cc)
+ agent_accept_compressed(orq->orq_agent, msg, orq->orq_cc);
+
+ if (orq->orq_cancel) {
+ nta_outgoing_t *cancel;
+
+ cancel = orq->orq_cancel; orq->orq_cancel = NULL;
+
+ cancel->orq_delayed = 0;
+
+ if (status < 200)
+ outgoing_send(cancel, 0);
+ else
+ outgoing_reply(cancel, SIP_481_NO_TRANSACTION, 0);
+ }
+
+ if (orq->orq_pending) {
+ tport_release(orq->orq_tport, orq->orq_pending, orq->orq_request,
+ msg, orq, status < 200);
+ if (status >= 200)
+ orq->orq_pending = 0;
+ }
+
+ /* The state machines */
+ if (orq->orq_method == sip_method_invite) {
+ if (orq->orq_destroyed && status > 100 && status < 300)
+ return -1; /* Proxy statelessly (RFC3261 section 16.11) */
+
+ outgoing_reset_timer(orq);
+
+ if (status < 200) {
+ if (orq->orq_queue == sa->sa_out.inv_calling) {
+ orq->orq_status = status;
+ outgoing_queue(sa->sa_out.inv_proceeding, orq);
+ }
+
+ /* Handle 100rel */
+ if (sip && sip->sip_rseq)
+ if (outgoing_recv_reliable(orq, msg, sip) < 0) {
+ msg_destroy(msg);
+ return 0;
+ }
+ }
+ else {
+ /* Final response */
+ if (status >= 300)
+ outgoing_ack(orq, msg, sip);
+
+ if (!orq->orq_completed) {
+ if (outgoing_complete(orq))
+ return 0;
+
+ if (sip && sa->sa_is_a_uas) {
+ su_home_t *home = msg_home(orq->orq_request);
+ orq->orq_tag = su_strdup(home, sip->sip_to->a_tag);
+ }
+ }
+ /* Retransmission or response from another fork */
+ else {
+ /* Once 2xx has been received, non-2xx will not be forwarded */
+ if (status >= 300)
+ return outgoing_duplicate(orq, msg, sip);
+
+ if (sa->sa_is_a_uas) {
+ if (str0cmp(sip->sip_to->a_tag, orq->orq_tag) == 0)
+ /* Catch retransmission */
+ return outgoing_duplicate(orq, msg, sip);
+ }
+ }
+
+ orq->orq_status = status;
+ }
+ }
+ else if (orq->orq_method != sip_method_ack) {
+ /* Non-INVITE */
+ if (orq->orq_queue == sa->sa_out.trying) {
+ assert(orq_status < 200); (void)orq_status;
+
+ if (status < 200) {
+ if (!orq->orq_reliable)
+ outgoing_set_timer(orq, sa->sa_t2);
+ }
+ else if (!outgoing_complete(orq)) {
+ if (orq->orq_sigcomp_zap && orq->orq_tport && orq->orq_cc)
+ agent_zap_compressor(orq->orq_agent, orq->orq_cc);
+ }
+ else /* outgoing_complete */ {
+ msg_destroy(msg);
+ return 0;
+ }
+ } else {
+ /* Already completed or terminated */
+ assert(orq->orq_queue == sa->sa_out.completed ||
+ orq->orq_queue == sa->sa_out.terminated);
+ assert(orq->orq_status >= 200);
+ return outgoing_duplicate(orq, msg, sip);
+ }
+
+ orq->orq_status = status;
+ }
+ else {
+ /* ACK */
+ if (sip && (sip->sip_flags & NTA_INTERNAL_MSG) == 0)
+ /* Received re-transmitted final reply to INVITE, retransmit ACK */
+ outgoing_retransmit(orq);
+ msg_destroy(msg);
+ return 0;
+ }
+
+ if (status + orq->orq_pass_100 > 100 && !orq->orq_destroyed) {
+ if (orq->orq_response)
+ msg_destroy(orq->orq_response);
+ orq->orq_response = msg;
+ /* Call callback */
+ orq->orq_callback(orq->orq_magic, orq, sip);
+ }
+ else
+ msg_destroy(msg);
+
+ return 0;
+}
+
+static void outgoing_default_recv(nta_outgoing_t *orq,
+ int status,
+ msg_t *msg,
+ sip_t *sip)
+{
+ assert(sip->sip_cseq);
+
+ orq->orq_status = status;
+ orq->orq_response = msg;
+ orq->orq_callback(orq->orq_magic, orq, sip);
+ orq->orq_response = NULL;
+ orq->orq_status = 0;
+ msg_destroy(msg);
+}
+
+static void outgoing_estimate_delay(nta_outgoing_t *orq, sip_t *sip)
+{
+ su_time_t now = su_now();
+ double diff = 1000 * su_time_diff(now, orq->orq_sent);
+
+ if (orq->orq_timestamp && sip->sip_timestamp) {
+ double diff2, delay = 0.0;
+ su_time_t timestamp = { 0, 0 };
+ char const *bad;
+
+ sscanf(sip->sip_timestamp->ts_stamp, "%lu.%lu",
+ ×tamp.tv_sec, ×tamp.tv_usec);
+
+ diff2 = 1000 * su_time_diff(now, timestamp);
+
+ if (diff2 < 0)
+ bad = "negative";
+ else if (diff2 > diff + 1e-3)
+ bad = "too large";
+ else {
+ if (sip->sip_timestamp->ts_delay)
+ sscanf(sip->sip_timestamp->ts_delay, "%lg", &delay);
+
+ if (1000 * delay <= diff2) {
+ diff = diff2 - 1000 * delay;
+ orq->orq_delay = (unsigned)diff;
+ SU_DEBUG_7(("nta_outgoing: RTT is %g ms, now is %lu.%06lu, "
+ "Timestamp was %s %s\n",
+ diff, now.tv_sec, now.tv_usec,
+ sip->sip_timestamp->ts_stamp,
+ sip->sip_timestamp->ts_delay ?
+ sip->sip_timestamp->ts_delay : ""));
+ return;
+ }
+ bad = "delay";
+ }
+
+ SU_DEBUG_3(("nta_outgoing: %s Timestamp %lu.%06lu %g "
+ "(sent %lu.%06lu, now is %lu.%06lu)\n",
+ bad,
+ timestamp.tv_sec, timestamp.tv_usec,
+ delay,
+ orq->orq_sent.tv_sec, orq->orq_sent.tv_usec,
+ now.tv_sec, now.tv_usec));
+ }
+
+ if (diff >= 0 && diff < (double)UINT_MAX) {
+ orq->orq_delay = (unsigned)diff;
+ SU_DEBUG_7(("nta_outgoing: RTT is %g ms\n", diff));
+ }
+}
+
+/**@typedef nta_response_f
+ *
+ * Callback for replies to outgoing requests.
+ *
+ * This is a callback function invoked by NTA when it has received a new
+ * reply to an outgoing request.
+ *
+ * @param magic request context
+ * @param request request handle
+ * @param sip received status message
+ *
+ * @return
+ * This callback function should return always 0.
+ *
+ */
+
+/** Process duplicate responses */
+static int outgoing_duplicate(nta_outgoing_t *orq,
+ msg_t *msg,
+ sip_t *sip)
+{
+ sip_via_t *v;
+
+ if (sip && (sip->sip_flags & NTA_INTERNAL_MSG) == 0) {
+ v = sip->sip_via;
+
+ SU_DEBUG_5(("nta: %u %s is duplicate response to %d %s\n",
+ sip->sip_status->st_status, sip->sip_status->st_phrase,
+ orq->orq_cseq->cs_seq, orq->orq_cseq->cs_method_name));
+ if (v)
+ SU_DEBUG_5(("\tVia: %s %s%s%s%s%s%s%s%s%s\n",
+ v->v_protocol, v->v_host,
+ SIP_STRLOG(":", v->v_port),
+ SIP_STRLOG(" ;received=", v->v_received),
+ SIP_STRLOG(" ;maddr=", v->v_maddr),
+ SIP_STRLOG(" ;branch=", v->v_branch)));
+ }
+
+ msg_destroy(msg);
+ return 0;
+}
+
+/** @internal ACK to a final response (300..699).
+ * These messages are ACK'ed via the original URL (and tport)
+ */
+void outgoing_ack(nta_outgoing_t *orq, msg_t *msg, sip_t *sip)
+{
+ nta_outgoing_t *ack;
+ msg_t *ackmsg;
+ sip_t *acksip;
+
+ assert(orq);
+
+ /* Do not ack internally generated messages... */
+ if (sip == NULL || sip->sip_flags & NTA_INTERNAL_MSG)
+ return;
+
+ assert(sip); assert(sip->sip_status);
+ assert(sip->sip_status->st_status >= 300);
+ assert(orq->orq_tport);
+
+ ackmsg = outgoing_ackmsg(orq, SIP_METHOD_ACK, NULL);
+ acksip = sip_object(ackmsg);
+
+ if (acksip) {
+ if (sip->sip_to->a_tag && !acksip->sip_to->a_tag)
+ sip_to_tag(msg_home(ackmsg), acksip->sip_to, sip->sip_to->a_tag);
+
+ if ((ack = outgoing_create(orq->orq_agent, NULL, NULL,
+ NULL, orq->orq_tpn, ackmsg,
+ NTATAG_BRANCH_KEY(sip->sip_via->v_branch),
+ NTATAG_USER_VIA(1),
+ NTATAG_STATELESS(1),
+ TAG_END())))
+ ;
+ else
+ msg_destroy(msg);
+ }
+}
+
+/** Generate messages for hop-by-hop ACK or CANCEL.
+ */
+msg_t *outgoing_ackmsg(nta_outgoing_t *orq, sip_method_t m, char const *mname,
+ tagi_t const *tags)
+{
+ msg_t *msg = nta_msg_create(orq->orq_agent, 0);
+ su_home_t *home = msg_home(msg);
+ sip_t *sip = sip_object(msg);
+ sip_t *old = sip_object(orq->orq_request);
+ sip_via_t via[1];
+
+ if (!sip)
+ return NULL;
+
+ sip->sip_request =
+ sip_request_create(home, m, mname, (url_string_t *)orq->orq_url, NULL);
+
+ sip_add_dup(msg, sip, (sip_header_t *)old->sip_to);
+ sip_add_dup(msg, sip, (sip_header_t *)old->sip_from);
+ sip_add_dup(msg, sip, (sip_header_t *)old->sip_call_id);
+ sip_add_dup(msg, sip, (sip_header_t *)old->sip_route);
+ /* @RFC3841. Bug #1326727. */
+ sip_add_dup(msg, sip, (sip_header_t *)old->sip_accept_contact);
+ sip_add_dup(msg, sip, (sip_header_t *)old->sip_reject_contact);
+ sip_add_dup(msg, sip, (sip_header_t *)old->sip_request_disposition);
+
+ if (old->sip_via) {
+ /* Add only the topmost Via header */
+ *via = *old->sip_via; via->v_next = NULL;
+ sip_add_dup(msg, sip, (sip_header_t *)via);
+ }
+
+ sip->sip_cseq = sip_cseq_create(home, old->sip_cseq->cs_seq, m, mname);
+
+ if (tags)
+ sip_add_tl(msg, sip, TAG_NEXT(tags));
+
+ if (!sip->sip_max_forwards)
+ sip_add_dup(msg, sip, (sip_header_t *)orq->orq_agent->sa_max_forwards);
+
+ if (sip->sip_request &&
+ sip->sip_to &&
+ sip->sip_from &&
+ sip->sip_call_id &&
+ (!old->sip_route || sip->sip_route) &&
+ sip->sip_cseq)
+ return msg;
+
+ msg_destroy(msg);
+
+ return NULL;
+}
+
+static
+void outgoing_delayed_recv(su_root_magic_t *rm,
+ su_msg_r msg,
+ union sm_arg_u *u);
+
+/** Respond internally to a transaction. */
+int outgoing_reply(nta_outgoing_t *orq, int status, char const *phrase,
+ int delayed)
+{
+ nta_agent_t *agent = orq->orq_agent;
+ msg_t *msg = NULL;
+ sip_t *sip = NULL;
+
+ assert(status == 202 || status >= 400);
+
+ if (orq->orq_pending)
+ tport_release(orq->orq_tport, orq->orq_pending,
+ orq->orq_request, NULL, orq, 0);
+ orq->orq_pending = 0;
+
+ orq->orq_delayed = 0;
+
+ if (orq->orq_method == sip_method_ack) {
+ if (status != delayed)
+ SU_DEBUG_3(("nta(%p): responding %u %s to ACK!\n", orq, status, phrase));
+ orq->orq_status = status;
+ if (orq->orq_queue == NULL)
+ outgoing_complete(orq); /* Timer D/K */
+ return 0;
+ }
+
+ if (orq->orq_destroyed) {
+ if (orq->orq_status < 200)
+ orq->orq_status = status;
+ outgoing_complete(orq); /* Timer D/K */
+ return 0;
+ }
+
+ if (orq->orq_stateless)
+ ;
+ else if (orq->orq_queue == NULL ||
+ orq->orq_queue == orq->orq_agent->sa_out.resolving ||
+ orq->orq_queue == orq->orq_agent->sa_out.delayed)
+ outgoing_trying(orq);
+
+ /** Insert a dummy Via header */
+ if (!orq->orq_prepared) {
+ tport_t *tp = tport_primaries(orq->orq_agent->sa_tports);
+ outgoing_insert_via(orq, agent_tport_via(tp));
+ }
+
+ /* Create response message, if needed */
+ if (!orq->orq_stateless &&
+ !(orq->orq_callback == outgoing_default_cb) &&
+ !(status == 408 && !orq->orq_agent->sa_timeout_408)) {
+ char const *to_tag;
+
+ msg = nta_msg_create(agent, NTA_INTERNAL_MSG);
+
+ if (complete_response(msg, status, phrase, orq->orq_request) < 0) {
+ assert(!"complete message");
+ return -1;
+ }
+
+ sip = sip_object(msg); assert(sip->sip_flags & NTA_INTERNAL_MSG);
+ to_tag = nta_agent_newtag(msg_home(msg), "tag=%s", agent);
+
+ if (status > 100 &&
+ sip->sip_to && !sip->sip_to->a_tag &&
+ sip->sip_cseq->cs_method != sip_method_cancel &&
+ sip_to_tag(msg_home(msg), sip->sip_to, to_tag) < 0) {
+ assert(!"adding tag");
+ return -1;
+ }
+
+ if (status > 400 && agent->sa_blacklist) {
+ sip_retry_after_t af[1];
+ sip_retry_after_init(af)->af_delta = agent->sa_blacklist;
+
+ sip_add_dup(msg, sip, (sip_header_t *)af);
+ }
+ }
+
+ if (orq->orq_inserted && !delayed) {
+ outgoing_recv(orq, status, msg, sip);
+ return 0;
+ }
+ else if (orq->orq_stateless && orq->orq_callback == outgoing_default_cb) {
+ /* Xyzzy */
+ orq->orq_status = status;
+ outgoing_complete(orq);
+ }
+ else {
+ /*
+ * The thread creating outgoing transaction must return to application
+ * before transaction callback can be invoked. Therefore processing an
+ * internally generated response message must be delayed until
+ * transaction creation is completed.
+ *
+ * The internally generated message is transmitted using su_msg_send()
+ * and it is delivered back to NTA when the application next time
+ * executes the su_root_t event loop.
+ */
+ nta_agent_t *agent = orq->orq_agent;
+ su_root_t *root = agent->sa_root;
+ su_msg_r su_msg = SU_MSG_R_INIT;
+
+ if (su_msg_create(su_msg,
+ su_root_task(root),
+ su_root_task(root),
+ outgoing_delayed_recv,
+ sizeof(struct outgoing_recv_s)) == SU_SUCCESS) {
+ struct outgoing_recv_s *a = su_msg_data(su_msg)->a_outgoing_recv;
+
+ a->orq = orq;
+ a->msg = msg;
+ a->sip = sip;
+ a->status = status;
+
+ if (su_msg_send(su_msg) == SU_SUCCESS) {
+ return 0;
+ }
+ }
+ }
+
+ if (msg)
+ msg_destroy(msg);
+
+ return -1;
+}
+
+static
+void outgoing_delayed_recv(su_root_magic_t *rm,
+ su_msg_r msg,
+ union sm_arg_u *u)
+{
+ struct outgoing_recv_s *a = u->a_outgoing_recv;
+ if (outgoing_recv(a->orq, a->status, a->msg, a->sip) < 0 && a->msg)
+ msg_destroy(a->msg);
+}
+
+
+/* ====================================================================== */
+/* 9) Resolving (SIP) URL */
+
+#if HAVE_SOFIA_SRESOLV
+
+struct sipdns_query;
+
+/** DNS resolving for (SIP) URLs */
+struct sipdns_resolver
+{
+ tp_name_t sr_tpn[1]; /**< Copy of original transport name */
+ sres_query_t *sr_query; /**< Current DNS Query */
+ char const *sr_target; /**< Target for current query */
+
+ struct sipdns_query *sr_current; /**< Current query (with results) */
+ char **sr_results; /**< A/AAAA results to be used */
+
+ struct sipdns_query *sr_head; /**< List of intermediate results */
+ struct sipdns_query **sr_tail; /**< End of intermediate result list */
+
+ struct sipdns_query *sr_done; /**< Completed intermediate results */
+
+ /** Transports to consider for this request */
+ struct sipdns_tport const *sr_tports[SIPDNS_TRANSPORTS + 1];
+
+ uint16_t sr_a_aaaa1, sr_a_aaaa2; /**< Order of A and/or AAAA queries. */
+
+ unsigned
+ sr_use_naptr:1,
+ sr_use_srv:1,
+ sr_use_a_aaaa:1;
+};
+
+/** Intermediate queries */
+struct sipdns_query
+{
+ struct sipdns_query *sq_next;
+
+ char const *sq_proto;
+ char const *sq_domain;
+ char sq_port[6]; /* port number */
+
+ uint16_t sq_type;
+ uint16_t sq_priority; /* priority or preference */
+ uint16_t sq_weight; /* preference or weight */
+};
+
+static int outgoing_resolve_next(nta_outgoing_t *orq);
+static int outgoing_resolving(nta_outgoing_t *orq);
+static int outgoing_resolving_error(nta_outgoing_t *,
+ int status, char const *phrase);
+static int outgoing_query_naptr(nta_outgoing_t *orq, char const *domain);
+static void outgoing_answer_naptr(sres_context_t *orq, sres_query_t *q,
+ sres_record_t *answers[]);
+
+static int outgoing_make_srv_query(nta_outgoing_t *orq);
+static int outgoing_make_a_aaaa_query(nta_outgoing_t *orq);
+
+static void outgoing_query_all(nta_outgoing_t *orq);
+
+static int outgoing_query_srv(nta_outgoing_t *orq, struct sipdns_query *);
+static void outgoing_answer_srv(sres_context_t *orq, sres_query_t *q,
+ sres_record_t *answers[]);
+
+#if SU_HAVE_IN6
+static int outgoing_query_aaaa(nta_outgoing_t *orq, struct sipdns_query *);
+static void outgoing_answer_aaaa(sres_context_t *orq, sres_query_t *q,
+ sres_record_t *answers[]);
+#endif
+
+static int outgoing_query_a(nta_outgoing_t *orq, struct sipdns_query *);
+static void outgoing_answer_a(sres_context_t *orq, sres_query_t *q,
+ sres_record_t *answers[]);
+
+static void outgoing_query_results(nta_outgoing_t *orq,
+ struct sipdns_query *sq,
+ char *results[],
+ size_t rlen);
+
+
+#define SIPDNS_503_ERROR 503, "DNS Error"
+
+/** Resolve a request destination */
+static void
+outgoing_resolve(nta_outgoing_t *orq)
+{
+ struct sipdns_resolver *sr = NULL;
+ char const *tpname = orq->orq_tpn->tpn_proto;
+
+ if (orq->orq_agent->sa_resolver)
+ orq->orq_resolver = sr = su_zalloc(orq->orq_agent->sa_home, (sizeof *sr));
+
+ if (!sr) {
+ outgoing_resolving_error(orq, SIP_500_INTERNAL_SERVER_ERROR);
+ return;
+ }
+
+ *sr->sr_tpn = *orq->orq_tpn;
+ sr->sr_use_srv = orq->orq_agent->sa_use_srv;
+ sr->sr_use_naptr = orq->orq_agent->sa_use_naptr && sr->sr_use_srv;
+ sr->sr_use_a_aaaa = 1;
+ sr->sr_tail = &sr->sr_head;
+
+ /* RFC 3263:
+ If the TARGET was not a numeric IP address, but a port is present in
+ the URI, the client performs an A or AAAA record lookup of the domain
+ name. The result will be a list of IP addresses, each of which can
+ be contacted at the specific port from the URI and transport protocol
+ determined previously. The client SHOULD try the first record. If
+ an attempt should fail, based on the definition of failure in Section
+ 4.3, the next SHOULD be tried, and if that should fail, the next
+ SHOULD be tried, and so on.
+
+ This is a change from RFC 2543. Previously, if the port was
+ explicit, but with a value of 5060, SRV records were used. Now, A
+ or AAAA records will be used.
+ */
+ if (sr->sr_tpn->tpn_port)
+ sr->sr_use_naptr = 0, sr->sr_use_srv = 0;
+ /* RFC3263:
+ If [...] a transport was specified explicitly, the client performs an
+ SRV query for that specific transport,
+ */
+ else if (strcmp(tpname, "*") != 0)
+ sr->sr_use_naptr = 0;
+
+ if (sr->sr_use_srv || sr->sr_use_naptr) {
+ /* Initialize sr_tports */
+ tport_t *tport;
+ char const *ident = sr->sr_tpn->tpn_ident;
+ int i, j;
+
+ for (tport = tport_primary_by_name(orq->orq_agent->sa_tports, orq->orq_tpn);
+ tport;
+ tport = tport_next(tport)) {
+ tp_name_t const *tpn = tport_name(tport);
+ if (strcmp(tpname, "*") && strcasecmp(tpn->tpn_proto, tpname))
+ continue;
+ if (ident && (tpn->tpn_ident == NULL || strcmp(ident, tpn->tpn_ident)))
+ continue;
+
+ for (j = 0; j < SIPDNS_TRANSPORTS; j++)
+ if (strcasecmp(tpn->tpn_proto, sipdns_tports[j].name) == 0)
+ break;
+
+ assert(j < SIPDNS_TRANSPORTS);
+ if (j == SIPDNS_TRANSPORTS)
+ /* Someone added transport but did not update sipdns_tports */
+ continue;
+
+ for (i = 0; i < SIPDNS_TRANSPORTS; i++) {
+ if (sipdns_tports + j == sr->sr_tports[i] || sr->sr_tports[i] == NULL)
+ break;
+ }
+ sr->sr_tports[i] = sipdns_tports + j;
+
+ if (strcmp(tpname, "*")) /* Looking for only one transport */
+ break;
+ }
+
+ /* Nothing found */
+ if (!sr->sr_tports[0]) {
+ SU_DEBUG_3(("nta(%p): transport %s is not supported%s%s\n", orq, tpname,
+ ident ? " by interface " : "", ident ? ident : ""));
+ outgoing_resolving_error(orq, SIPDNS_503_ERROR);
+ return;
+ }
+ }
+
+ switch (orq->orq_res_order) {
+ default:
+ case nta_res_ip6_ip4:
+ sr->sr_a_aaaa1 = sres_type_aaaa, sr->sr_a_aaaa2 = sres_type_a;
+ break;
+ case nta_res_ip4_ip6:
+ sr->sr_a_aaaa1 = sres_type_a, sr->sr_a_aaaa2 = sres_type_aaaa;
+ break;
+ case nta_res_ip6_only:
+ sr->sr_a_aaaa1 = sres_type_aaaa, sr->sr_a_aaaa2 = sres_type_aaaa;
+ break;
+ case nta_res_ip4_only:
+ sr->sr_a_aaaa1 = sres_type_a, sr->sr_a_aaaa2 = sres_type_a;
+ break;
+ }
+
+ outgoing_resolve_next(orq);
+}
+
+/** Resolve next destination. */
+static int
+outgoing_resolve_next(nta_outgoing_t *orq)
+{
+ struct sipdns_resolver *sr = orq->orq_resolver;
+
+ if (sr == NULL) {
+ outgoing_resolving_error(orq, SIP_500_INTERNAL_SERVER_ERROR);
+ return 0;
+ }
+
+ if (sr->sr_results) {
+ /* Use existing A/AAAA results */
+ su_free(msg_home(orq->orq_request), sr->sr_results[0]);
+ sr->sr_results++;
+ if (sr->sr_results[0]) {
+ struct sipdns_query *sq = sr->sr_current; assert(sq);
+
+ if (sq->sq_proto)
+ orq->orq_tpn->tpn_proto = sq->sq_proto;
+ if (sq->sq_port[0])
+ orq->orq_tpn->tpn_port = sq->sq_port;
+
+ orq->orq_tpn->tpn_host = sr->sr_results[0];
+
+ outgoing_reset_timer(orq);
+ outgoing_queue(orq->orq_agent->sa_out.resolving, orq);
+ outgoing_prepare_send(orq);
+ return 1;
+ }
+ else {
+ sr->sr_current = NULL;
+ sr->sr_results = NULL;
+ }
+ }
+
+ if (sr->sr_head)
+ outgoing_query_all(orq);
+ else if (sr->sr_use_naptr)
+ outgoing_query_naptr(orq, sr->sr_tpn->tpn_host); /* NAPTR */
+ else if (sr->sr_use_srv)
+ outgoing_make_srv_query(orq); /* SRV */
+ else if (sr->sr_use_a_aaaa)
+ outgoing_make_a_aaaa_query(orq); /* A/AAAA */
+ else
+ return outgoing_resolving_error(orq, SIPDNS_503_ERROR);
+
+ return 1;
+}
+
+/** Check if can we retry other destinations? */
+static int
+outgoing_other_destinations(nta_outgoing_t const *orq)
+{
+ struct sipdns_resolver *sr = orq->orq_resolver;
+
+ if (!sr)
+ return 0;
+
+ if (sr->sr_use_a_aaaa || sr->sr_use_srv || sr->sr_use_naptr)
+ return 1;
+
+ if (sr->sr_results && sr->sr_results[1])
+ return 1;
+
+ if (sr->sr_head)
+ return 1;
+
+ return 0;
+}
+
+/** Resolve a request destination */
+static int
+outgoing_try_another(nta_outgoing_t *orq)
+{
+ struct sipdns_resolver *sr = orq->orq_resolver;
+
+ if (sr == NULL)
+ return 0;
+
+ *orq->orq_tpn = *sr->sr_tpn;
+ orq->orq_try_tcp_instead = 0, orq->orq_try_udp_instead = 0;
+ outgoing_reset_timer(orq);
+ outgoing_queue(orq->orq_agent->sa_out.resolving, orq);
+
+ return outgoing_resolve_next(orq);
+}
+
+/** Cancel resolver query */
+static inline void outgoing_cancel_resolver(nta_outgoing_t *orq)
+{
+ struct sipdns_resolver *sr = orq->orq_resolver;
+
+ assert(orq->orq_resolver);
+
+ if (sr->sr_query) /* Cancel resolver query */
+ sres_query_bind(sr->sr_query, NULL, NULL), sr->sr_query = NULL;
+}
+
+/** Destroy resolver */
+static inline void outgoing_destroy_resolver(nta_outgoing_t *orq)
+{
+ struct sipdns_resolver *sr = orq->orq_resolver;
+
+ assert(orq->orq_resolver);
+
+ if (sr->sr_query) /* Cancel resolver query */
+ sres_query_bind(sr->sr_query, NULL, NULL), sr->sr_query = NULL;
+
+ su_free(orq->orq_agent->sa_home, sr);
+
+ orq->orq_resolver = NULL;
+}
+
+/** Check if we are resolving. If not, return 503 response. */
+static
+int outgoing_resolving(nta_outgoing_t *orq)
+{
+ struct sipdns_resolver *sr = orq->orq_resolver;
+
+ assert(orq->orq_resolver);
+
+ if (!sr->sr_query) {
+ return outgoing_resolving_error(orq, SIPDNS_503_ERROR);
+ }
+ else {
+ outgoing_queue(orq->orq_agent->sa_out.resolving, orq);
+ return 0;
+ }
+}
+
+/** Return 503 response */
+static
+int outgoing_resolving_error(nta_outgoing_t *orq, int status, char const *phrase)
+{
+ orq->orq_resolved = 1;
+ outgoing_reply(orq, status, phrase, 0);
+ return -1;
+}
+
+/* Query SRV records (with the given tport). */
+static
+int outgoing_make_srv_query(nta_outgoing_t *orq)
+{
+ struct sipdns_resolver *sr = orq->orq_resolver;
+ su_home_t *home = msg_home(orq->orq_request);
+ struct sipdns_query *sq;
+ char const *host;
+ int i;
+ size_t hlen;
+
+ sr->sr_use_srv = 0;
+
+ host = sr->sr_tpn->tpn_host;
+ hlen = strlen(host) + 1;
+
+ for (i = 0; sr->sr_tports[i]; i++) {
+ char const *prefix = sr->sr_tports[i]->prefix;
+ size_t plen = strlen(prefix);
+
+ sq = su_zalloc(home, (sizeof *sq) + plen + hlen);
+ if (sq) {
+ *sr->sr_tail = sq, sr->sr_tail = &sq->sq_next;
+ sq->sq_domain = memcpy(sq + 1, prefix, plen);
+ memcpy((char *)sq->sq_domain + plen, host, hlen);
+ sq->sq_proto = sr->sr_tports[i]->name;
+ sq->sq_type = sres_type_srv;
+ sq->sq_priority = 1;
+ sq->sq_weight = 1;
+ }
+ }
+
+ outgoing_query_all(orq);
+
+ return 0;
+}
+
+/* Query A/AAAA records. */
+static
+int outgoing_make_a_aaaa_query(nta_outgoing_t *orq)
+{
+ struct sipdns_resolver *sr = orq->orq_resolver;
+ su_home_t *home = msg_home(orq->orq_request);
+ tp_name_t *tpn = orq->orq_tpn;
+ struct sipdns_query *sq;
+
+ assert(sr);
+
+ sr->sr_use_a_aaaa = 0;
+
+ sq = su_zalloc(home, 2 * (sizeof *sq));
+ if (!sq)
+ return outgoing_resolving(orq);
+
+ sq->sq_type = sr->sr_a_aaaa1;
+ sq->sq_domain = tpn->tpn_host;
+ sq->sq_priority = 1;
+
+ /* Append */
+ *sr->sr_tail = sq, sr->sr_tail = &sq->sq_next;
+
+ outgoing_query_all(orq);
+
+ return 0;
+}
+
+
+/** Start SRV/A/AAAA queries */
+static
+void outgoing_query_all(nta_outgoing_t *orq)
+{
+ struct sipdns_resolver *sr = orq->orq_resolver;
+ struct sipdns_query *sq = sr->sr_head;
+
+ if (sq == NULL) {
+ outgoing_resolving_error(orq, SIP_500_INTERNAL_SERVER_ERROR);
+ return;
+ }
+
+ /* Remove from intermediate list */
+ if (!(sr->sr_head = sq->sq_next))
+ sr->sr_tail = &sr->sr_head;
+
+ if (sq->sq_type == sres_type_srv)
+ outgoing_query_srv(orq, sq);
+#if SU_HAVE_IN6
+ else if (sq->sq_type == sres_type_aaaa)
+ outgoing_query_aaaa(orq, sq);
+#endif
+ else if (sq->sq_type == sres_type_a)
+ outgoing_query_a(orq, sq);
+ else
+ outgoing_resolving_error(orq, SIP_500_INTERNAL_SERVER_ERROR);
+}
+
+/** Query NAPTR record. */
+static
+int outgoing_query_naptr(nta_outgoing_t *orq, char const *domain)
+{
+ struct sipdns_resolver *sr = orq->orq_resolver;
+ sres_record_t **answers;
+
+ sr->sr_use_naptr = 0;
+
+ sr->sr_target = domain;
+
+ answers = sres_cached_answers(orq->orq_agent->sa_resolver,
+ sres_type_naptr, domain);
+
+ SU_DEBUG_5(("nta: for \"%s\" query \"%s\" %s%s\n",
+ orq->orq_tpn->tpn_host, domain, "NAPTR",
+ answers ? " (cached)" : ""));
+
+ if (answers) {
+ outgoing_answer_naptr(orq, NULL, answers);
+ return 0;
+ }
+ else {
+ sr->sr_query = sres_query(orq->orq_agent->sa_resolver,
+ outgoing_answer_naptr, orq,
+ sres_type_naptr, domain);
+ return outgoing_resolving(orq);
+ }
+}
+
+/* Process NAPTR records */
+static
+void outgoing_answer_naptr(sres_context_t *orq,
+ sres_query_t *q,
+ sres_record_t *answers[])
+{
+ int i, j, order = -1;
+ size_t rlen;
+ su_home_t *home = msg_home(orq->orq_request);
+ nta_agent_t *agent = orq->orq_agent;
+ struct sipdns_resolver *sr = orq->orq_resolver;
+ tp_name_t tpn[1];
+ struct sipdns_query *sq, *selected = NULL, **tail = &selected, **at;
+
+ assert(sr);
+
+ sr->sr_query = NULL;
+
+ *tpn = *sr->sr_tpn;
+
+ /* The NAPTR results are sorted first by Order then by Preference */
+ sres_sort_answers(orq->orq_agent->sa_resolver, answers);
+
+ for (i = 0; answers && answers[i]; i++) {
+ sres_naptr_record_t const *na = answers[i]->sr_naptr;
+ uint16_t type;
+
+ if (na->na_record->r_status)
+ continue;
+ if (na->na_record->r_type != sres_type_naptr)
+ continue;
+
+ /* RFC 2915 p 4:
+ * Order
+ * A 16-bit unsigned integer specifying the order in which the
+ * NAPTR records MUST be processed to ensure the correct ordering
+ * of rules. Low numbers are processed before high numbers, and
+ * once a NAPTR is found whose rule "matches" the target, the
+ * client MUST NOT consider any NAPTRs with a higher value for
+ * order (except as noted below for the Flags field).
+ */
+ if (order >= 0 && order != na->na_order)
+ break;
+
+ /* Check if NAPTR matches our target */
+ if (strncasecmp(na->na_services, "SIP+", 4) &&
+ strncasecmp(na->na_services, "SIPS+", 5))
+ /* Not a SIP/SIPS service */
+ continue;
+
+ /* Use NAPTR results, don't try extra SRV/A/AAAA records */
+ sr->sr_use_srv = 0, sr->sr_use_a_aaaa = 0;
+
+ /* Check if we have a transport mathing with service */
+ for (j = 0; sr->sr_tports[j]; j++) {
+ /*
+ * Syntax of services is actually more complicated
+ * but comparing the values in the transport list
+ * match with those values that make any sense
+ */
+ if (strcasecmp(na->na_services, sr->sr_tports[j]->service) != 0)
+ continue;
+
+ tpn->tpn_proto = sr->sr_tports[j]->name;
+
+ if (tport_primary_by_name(agent->sa_tports, tpn))
+ break;
+ }
+
+ SU_DEBUG_5(("nta: %s IN NAPTR %u %u \"%s\" \"%s\" \"%s\" %s%s\n",
+ na->na_record->r_name,
+ na->na_order, na->na_prefer,
+ na->na_flags, na->na_services,
+ na->na_regexp, na->na_replace,
+ !sr->sr_tports[j] ? " (not supported)" : ""));
+
+ if (!sr->sr_tports[j])
+ continue;
+
+ /* OK, we found matching NAPTR */
+ order = na->na_order;
+
+ /*
+ * The "S" flag means that the next lookup should be for SRV records
+ * ... "A" means that the next lookup should be for either an A, AAAA,
+ * or A6 record.
+ */
+ if (na->na_flags[0] == 's' || na->na_flags[0] == 'S')
+ type = sres_type_srv; /* SRV */
+ else if (na->na_flags[0] == 'a' || na->na_flags[0] == 'A')
+ type = sr->sr_a_aaaa1; /* A / AAAA */
+ else
+ continue;
+
+ rlen = strlen(na->na_replace) + 1;
+ sq = su_zalloc(home, (sizeof *sq) + rlen);
+
+ *tail = sq, tail = &sq->sq_next;
+ sq->sq_priority = na->na_prefer;
+ sq->sq_weight = j;
+ sq->sq_type = type;
+ sq->sq_domain = memcpy(sq + 1, na->na_replace, rlen);
+ sq->sq_proto = sr->sr_tports[j]->name;
+ }
+
+ sres_free_answers(orq->orq_agent->sa_resolver, answers);
+
+ /* RFC2915:
+ Preference [...] specifies the order in which NAPTR
+ records with equal "order" values SHOULD be processed, low
+ numbers being processed before high numbers. */
+ at = sr->sr_tail;
+ while (selected) {
+ sq = selected, selected = sq->sq_next;
+
+ for (tail = at; *tail; tail = &(*tail)->sq_next) {
+ if (sq->sq_priority < (*tail)->sq_priority)
+ break;
+ if (sq->sq_priority == (*tail)->sq_priority &&
+ sq->sq_weight < (*tail)->sq_weight)
+ break;
+ }
+ /* Insert */
+ sq->sq_next = *tail, *tail = sq;
+
+ if (!sq->sq_next) /* Last one */
+ sr->sr_tail = &sq->sq_next;
+ }
+
+ outgoing_resolve_next(orq);
+}
+
+/* Query SRV records */
+static
+int outgoing_query_srv(nta_outgoing_t *orq,
+ struct sipdns_query *sq)
+{
+ struct sipdns_resolver *sr = orq->orq_resolver;
+
+ sres_record_t **answers;
+
+ sr->sr_target = sq->sq_domain;
+ sr->sr_current = sq;
+
+ answers = sres_cached_answers(orq->orq_agent->sa_resolver,
+ sres_type_srv, sq->sq_domain);
+
+ SU_DEBUG_5(("nta: for \"%s\" query \"%s\" %s%s\n",
+ orq->orq_tpn->tpn_host, sq->sq_domain, "SRV",
+ answers ? " (cached)" : ""));
+
+ if (answers) {
+ outgoing_answer_srv(orq, NULL, answers);
+ return 0;
+ }
+ else {
+ sr->sr_query = sres_query(orq->orq_agent->sa_resolver,
+ outgoing_answer_srv, orq,
+ sres_type_srv, sq->sq_domain);
+ return outgoing_resolving(orq);
+ }
+}
+
+/* Process SRV records */
+static
+void
+outgoing_answer_srv(sres_context_t *orq, sres_query_t *q,
+ sres_record_t *answers[])
+{
+ struct sipdns_resolver *sr = orq->orq_resolver;
+ su_home_t *home = msg_home(orq->orq_request);
+ struct sipdns_query *sq0, *sq, *selected = NULL, **tail = &selected, **at;
+ int i;
+ size_t tlen;
+
+ sr->sr_query = NULL;
+
+ sq0 = sr->sr_current;
+ assert(sq0 && sq0->sq_type == sres_type_srv);
+ assert(sq0->sq_domain); assert(sq0->sq_proto);
+
+ /* Sort by priority, weight? */
+ sres_sort_answers(orq->orq_agent->sa_resolver, answers);
+
+ for (i = 0; answers && answers[i]; i++) {
+ sres_srv_record_t const *srv = answers[i]->sr_srv;
+
+ if (srv->srv_record->r_status /* There was an error */ ||
+ srv->srv_record->r_type != sres_type_srv)
+ continue;
+
+ tlen = strlen(srv->srv_target) + 1;
+
+ sq = su_zalloc(home, (sizeof *sq) + tlen);
+
+ if (sq) {
+ *tail = sq, tail = &sq->sq_next;
+
+ sq->sq_type = sr->sr_a_aaaa1;
+ sq->sq_proto = sq0->sq_proto;
+ sq->sq_domain = memcpy(sq + 1, srv->srv_target, tlen);
+ snprintf(sq->sq_port, sizeof(sq->sq_port), "%u", srv->srv_port);
+
+ sq->sq_priority = srv->srv_priority;
+ sq->sq_weight = srv->srv_weight;
+ }
+ }
+
+ sres_free_answers(orq->orq_agent->sa_resolver, answers);
+
+ at = &sr->sr_head;
+
+ /* Insert sorted by priority, randomly select by weigth */
+ while (selected) {
+ unsigned long weight = 0;
+ unsigned N = 0;
+ uint16_t priority = selected->sq_priority;
+
+ /* Total weight of entries with same priority */
+ for (sq = selected; sq && priority == sq->sq_priority; sq = sq->sq_next) {
+ weight += sq->sq_weight;
+ N ++;
+ }
+
+ tail = &selected;
+
+ /* Select by weighted random. Entries with weight 0 are kept in order */
+ if (N > 1 && weight > 0) {
+ unsigned rand = su_randint(0, weight - 1);
+
+ while (rand >= (*tail)->sq_weight) {
+ rand -= (*tail)->sq_weight;
+ tail = &(*tail)->sq_next;
+ }
+ }
+
+ /* Remove selected */
+ sq = *tail; *tail = sq->sq_next; assert(sq->sq_priority == priority);
+
+ /* Append at *at */
+ sq->sq_next = *at; *at = sq; at = &sq->sq_next; if (!*at) sr->sr_tail = at;
+
+ SU_DEBUG_5(("nta: %s IN SRV %u %u %s %s (%s)\n",
+ sq0->sq_domain,
+ (unsigned)sq->sq_priority, (unsigned)sq->sq_weight,
+ sq->sq_port, sq->sq_domain, sq->sq_proto));
+ }
+
+ /* This is not needed anymore (?) */
+ sr->sr_current = NULL;
+ sq0->sq_next = sr->sr_done; sr->sr_done = sq0;
+
+ outgoing_resolve_next(orq);
+}
+
+#if SU_HAVE_IN6
+/* Query AAAA records */
+static
+int outgoing_query_aaaa(nta_outgoing_t *orq, struct sipdns_query *sq)
+{
+ struct sipdns_resolver *sr = orq->orq_resolver;
+ sres_record_t **answers;
+
+ sr->sr_target = sq->sq_domain;
+ sr->sr_current = sq;
+
+ answers = sres_cached_answers(orq->orq_agent->sa_resolver,
+ sres_type_aaaa, sq->sq_domain);
+
+ SU_DEBUG_5(("nta: for \"%s\" query \"%s\" %s%s\n",
+ orq->orq_tpn->tpn_host, sq->sq_domain, "AAAA",
+ answers ? " (cached)" : ""));
+
+ if (answers) {
+ outgoing_answer_aaaa(orq, NULL, answers);
+ return 0;
+ }
+
+ sr->sr_query = sres_query(orq->orq_agent->sa_resolver,
+ outgoing_answer_aaaa, orq,
+ sres_type_aaaa, sq->sq_domain);
+
+ return outgoing_resolving(orq);
+}
+
+/* Process AAAA records */
+static
+void outgoing_answer_aaaa(sres_context_t *orq, sres_query_t *q,
+ sres_record_t *answers[])
+{
+ struct sipdns_resolver *sr = orq->orq_resolver;
+ su_home_t *home = msg_home(orq->orq_request);
+ struct sipdns_query *sq = sr->sr_current;
+
+ size_t i, j, found;
+ char *result, **results = NULL;
+
+ assert(sq); assert(sq->sq_type == sres_type_aaaa);
+
+ sr->sr_query = NULL;
+
+ for (i = 0, found = 0; answers && answers[i]; i++) {
+ sres_aaaa_record_t const *aaaa = answers[i]->sr_aaaa;
+ if (aaaa->aaaa_record->r_status == 0 &&
+ aaaa->aaaa_record->r_type == sres_type_aaaa)
+ found++;
+ }
+
+ if (found > 1)
+ results = su_zalloc(home, (found + 1) * (sizeof *results));
+ else if (found)
+ results = &result;
+
+ for (i = j = 0; results && answers && answers[i]; i++) {
+ char addr[SU_ADDRSIZE];
+ sres_aaaa_record_t const *aaaa = answers[i]->sr_aaaa;
+
+ if (aaaa->aaaa_record->r_status ||
+ aaaa->aaaa_record->r_type != sres_type_aaaa)
+ continue; /* There was an error */
+
+ inet_ntop(AF_INET6, &aaaa->aaaa_addr, addr, sizeof(addr));
+
+ if (j == 0)
+ SU_DEBUG_5(("nta(%p): %s IN AAAA %s\n", orq,
+ aaaa->aaaa_record->r_name, addr));
+ else
+ SU_DEBUG_5(("nta(%p): AAAA %s\n", orq, addr));
+
+ assert(j < found);
+ results[j++] = su_strdup(home, addr);
+ }
+
+ sres_free_answers(orq->orq_agent->sa_resolver, answers);
+
+ outgoing_query_results(orq, sq, results, found);
+}
+#endif /* SU_HAVE_IN6 */
+
+/* Query A records */
+static
+int outgoing_query_a(nta_outgoing_t *orq, struct sipdns_query *sq)
+{
+ struct sipdns_resolver *sr = orq->orq_resolver;
+ sres_record_t **answers;
+
+ sr->sr_target = sq->sq_domain;
+ sr->sr_current = sq;
+
+ answers = sres_cached_answers(orq->orq_agent->sa_resolver,
+ sres_type_a, sq->sq_domain);
+
+ SU_DEBUG_5(("nta: for \"%s\" query \"%s\" %s%s\n",
+ orq->orq_tpn->tpn_host, sq->sq_domain, "A",
+ answers ? " (cached)" : ""));
+
+ if (answers) {
+ outgoing_answer_a(orq, NULL, answers);
+ return 0;
+ }
+
+ sr->sr_query = sres_query(orq->orq_agent->sa_resolver,
+ outgoing_answer_a, orq,
+ sres_type_a, sq->sq_domain);
+
+ return outgoing_resolving(orq);
+}
+
+/* Process A records */
+static
+void outgoing_answer_a(sres_context_t *orq, sres_query_t *q,
+ sres_record_t *answers[])
+{
+ struct sipdns_resolver *sr = orq->orq_resolver;
+ su_home_t *home = msg_home(orq->orq_request);
+ struct sipdns_query *sq = sr->sr_current;
+
+ int i, j, found;
+ char *result, **results = NULL;
+
+ assert(sq); assert(sq->sq_type == sres_type_a);
+
+ sr->sr_query = NULL;
+
+ for (i = 0, found = 0; answers && answers[i]; i++) {
+ sres_a_record_t const *a = answers[i]->sr_a;
+ if (a->a_record->r_status == 0 &&
+ a->a_record->r_type == sres_type_a)
+ found++;
+ }
+
+ if (found > 1)
+ results = su_zalloc(home, (found + 1) * (sizeof *results));
+ else if (found)
+ results = &result;
+
+ for (i = j = 0; answers && answers[i]; i++) {
+ char addr[SU_ADDRSIZE];
+ sres_a_record_t const *a = answers[i]->sr_a;
+
+ if (a->a_record->r_status ||
+ a->a_record->r_type != sres_type_a)
+ continue; /* There was an error */
+
+ inet_ntop(AF_INET, &a->a_addr, addr, sizeof(addr));
+
+ if (j == 0)
+ SU_DEBUG_5(("nta: %s IN A %s\n", a->a_record->r_name, addr));
+ else
+ SU_DEBUG_5(("nta(%p): A %s\n", orq, addr));
+
+ assert(j < found);
+ results[j++] = su_strdup(home, addr);
+ }
+
+ sres_free_answers(orq->orq_agent->sa_resolver, answers);
+
+ outgoing_query_results(orq, sq, results, found);
+}
+
+/** Store A/AAAA query results */
+static void
+outgoing_query_results(nta_outgoing_t *orq,
+ struct sipdns_query *sq,
+ char *results[],
+ size_t rlen)
+{
+ struct sipdns_resolver *sr = orq->orq_resolver;
+
+ if (sq->sq_type == sr->sr_a_aaaa1 &&
+ sq->sq_type != sr->sr_a_aaaa2) {
+ sq->sq_type = sr->sr_a_aaaa2;
+
+ SU_DEBUG_7(("nta(%p): %s %s record still unresolved\n", orq,
+ sq->sq_domain, sq->sq_type == sres_type_a ? "A" : "AAAA"));
+
+ /*
+ * Three possible policies:
+ * 1) try each host for AAAA/A, then A/AAAA
+ * 2) try everything first for AAAA/A, then everything for A/AAAA
+ * 3) try one SRV record results for AAAA/A, then for A/AAAA,
+ * then next SRV record
+ */
+
+ /* We use now policy #1 */
+ if (!(sq->sq_next = sr->sr_head))
+ sr->sr_tail = &sq->sq_next;
+ sr->sr_head = sq;
+ }
+ else {
+ sq->sq_next = sr->sr_done, sr->sr_done = sq;
+ }
+
+ if (rlen > 1)
+ sr->sr_results = results;
+ else
+ sr->sr_current = NULL;
+
+ if (rlen > 0) {
+ orq->orq_resolved = 1;
+ orq->orq_tpn->tpn_host = results[0];
+ if (sq->sq_proto) orq->orq_tpn->tpn_proto = sq->sq_proto;
+ if (sq->sq_port[0]) orq->orq_tpn->tpn_port = sq->sq_port;
+ outgoing_prepare_send(orq);
+ } else {
+ outgoing_resolve_next(orq);
+ }
+}
+
+
+#endif
+
+/* ====================================================================== */
+/* 10) Reliable responses */
+
+static nta_prack_f nta_reliable_destroyed;
+
+/**
+ * Check that server transaction can be used to send reliable provisional
+ * responses.
+ */
+static inline
+int reliable_check(nta_incoming_t *irq)
+{
+ if (irq == NULL || irq->irq_status >= 200 || !irq->irq_agent)
+ return 0;
+
+ if (irq->irq_reliable && irq->irq_reliable->rel_status >= 200)
+ return 0;
+
+ /* @RSeq is initialized to nonzero when request requires/supports 100rel */
+ if (irq->irq_rseq == 0)
+ return 0;
+
+ if (irq->irq_rseq == 0xffffffffU) /* already sent >> 2**31 responses */
+ return 0;
+
+ return 1;
+}
+
+/** Respond reliably.
+ *
+ * @param irq
+ * @param callback
+ * @param rmagic
+ * @param status
+ * @param phrase
+ * @param tag, value, ..
+ */
+nta_reliable_t *nta_reliable_treply(nta_incoming_t *irq,
+ nta_prack_f *callback,
+ nta_reliable_magic_t *rmagic,
+ int status, char const *phrase,
+ tag_type_t tag,
+ tag_value_t value, ...)
+{
+ ta_list ta;
+ msg_t *msg;
+ sip_t *sip;
+ nta_reliable_t *retval = NULL;
+
+ if (!reliable_check(irq) || (status <= 100 || status >= 200))
+ return NULL;
+
+ msg = nta_msg_create(irq->irq_agent, 0);
+ sip = sip_object(msg);
+
+ if (!sip)
+ return NULL;
+
+ ta_start(ta, tag, value);
+
+ if (0 > nta_incoming_complete_response(irq, msg, status, phrase,
+ ta_tags(ta)))
+ msg_destroy(msg);
+ else if (!(retval = reliable_mreply(irq, callback, rmagic, msg, sip)))
+ msg_destroy(msg);
+
+ ta_end(ta);
+
+ return retval;
+}
+
+/** Respond reliably with @a msg.
+ *
+ * @note
+ * The stack takes over the ownership of @a msg. (It is destroyed even if
+ * sending the response fails.)
+ *
+ * @param irq
+ * @param callback
+ * @param rmagic
+ * @param msg
+ */
+nta_reliable_t *nta_reliable_mreply(nta_incoming_t *irq,
+ nta_prack_f *callback,
+ nta_reliable_magic_t *rmagic,
+ msg_t *msg)
+{
+ sip_t *sip = sip_object(msg);
+
+ if (!reliable_check(irq)) {
+ msg_destroy(msg);
+ return NULL;
+ }
+
+ if (sip == NULL || !sip->sip_status || sip->sip_status->st_status <= 100) {
+ msg_destroy(msg);
+ return NULL;
+ }
+
+ if (sip->sip_status->st_status >= 200) {
+ incoming_final_failed(irq, msg);
+ return NULL;
+ }
+
+ return reliable_mreply(irq, callback, rmagic, msg, sip);
+}
+
+static
+nta_reliable_t *reliable_mreply(nta_incoming_t *irq,
+ nta_prack_f *callback,
+ nta_reliable_magic_t *rmagic,
+ msg_t *msg,
+ sip_t *sip)
+{
+ nta_reliable_t *rel;
+ nta_agent_t *agent;
+
+ agent = irq->irq_agent;
+
+ if (callback == NULL)
+ callback = nta_reliable_destroyed;
+
+ rel = su_zalloc(agent->sa_home, sizeof(*rel));
+ if (rel) {
+ rel->rel_irq = irq;
+ rel->rel_callback = callback;
+ rel->rel_magic = rmagic;
+ rel->rel_unsent = msg;
+ rel->rel_status = sip->sip_status->st_status;
+ rel->rel_precious = sip->sip_payload != NULL;
+ rel->rel_next = irq->irq_reliable;
+
+ /*
+ * If there already is a un-pr-acknowledged response, queue this one
+ * until at least one response is pr-acknowledged.
+ */
+ if (irq->irq_reliable &&
+ (irq->irq_reliable->rel_next == NULL ||
+ irq->irq_reliable->rel_rseq == 0)) {
+ return irq->irq_reliable = rel;
+ }
+
+ if (reliable_send(irq, rel, msg_ref_create(msg), sip) < 0) {
+ msg_destroy(msg);
+ su_free(agent->sa_home, rel);
+ return NULL;
+ }
+
+ irq->irq_reliable = rel;
+
+ return callback ? rel : (nta_reliable_t *)-1;
+ }
+
+ msg_destroy(msg);
+ return NULL;
+}
+
+static
+int reliable_send(nta_incoming_t *irq,
+ nta_reliable_t *rel,
+ msg_t *msg,
+ sip_t *sip)
+{
+ nta_agent_t *sa = irq->irq_agent;
+ su_home_t *home = msg_home(msg);
+ sip_rseq_t rseq[1];
+ sip_rseq_init(rseq);
+
+ if (sip->sip_require)
+ msg_header_replace_param(home, sip->sip_require->k_common, "100rel");
+ else
+ sip_add_make(msg, sip, sip_require_class, "100rel");
+
+ rel->rel_rseq = rseq->rs_response = irq->irq_rseq;
+ sip_add_dup(msg, sip, (sip_header_t *)rseq);
+
+ if (!sip->sip_rseq || incoming_reply(irq, msg, sip) < 0) {
+ msg_destroy(msg);
+ return -1;
+ }
+
+ irq->irq_rseq++;
+
+ if (irq->irq_queue == sa->sa_in.preliminary)
+ /* Make sure we are moved to the tail */
+ incoming_remove(irq);
+
+ incoming_queue(sa->sa_in.preliminary, irq); /* P1 */
+ incoming_set_timer(irq, sa->sa_t1); /* P2 */
+
+ return 0;
+}
+
+/** Queue final response when there are unsent precious preliminary responses */
+static
+int reliable_final(nta_incoming_t *irq, msg_t *msg, sip_t *sip)
+{
+ nta_reliable_t *r;
+ unsigned already_in_callback;
+ /*
+ * We delay sending final response if it's 2XX and
+ * an unpracked reliable response contains session description
+ */
+ /* Get last unpracked response from queue */
+ if (sip->sip_status->st_status < 300)
+ for (r = irq->irq_reliable; r; r = r->rel_next)
+ if (r->rel_unsent && r->rel_precious) {
+ /* Delay sending 2XX */
+ reliable_mreply(irq, NULL, NULL, msg, sip);
+ return 0;
+ }
+
+ /* Flush unsent responses. */
+ already_in_callback = irq->irq_in_callback;
+ irq->irq_in_callback = 1;
+ reliable_flush(irq);
+ irq->irq_in_callback = already_in_callback;
+
+ if (!already_in_callback && irq->irq_terminated && irq->irq_destroyed) {
+ incoming_free(irq);
+ msg_destroy(msg);
+ return 0;
+ }
+
+ return 1;
+}
+
+/** Get latest reliably sent response */
+static
+msg_t *reliable_response(nta_incoming_t *irq)
+{
+ nta_reliable_t *r, *rel;
+
+ /* Get last unpracked response from queue */
+ for (rel = NULL, r = irq->irq_reliable; r; r = r->rel_next)
+ if (!r->rel_pracked)
+ rel = r;
+
+ assert(rel);
+
+ return rel->rel_unsent;
+}
+
+/** Process incoming PRACK with matching @RAck field */
+static
+int reliable_recv(nta_incoming_t *irq, msg_t *msg, sip_t *sip, tport_t *tp)
+{
+ sip_rack_t *rack = sip->sip_rack;
+ nta_reliable_t *rel;
+ nta_incoming_t *pr_irq;
+ int status;
+
+ for (rel = irq->irq_reliable; rel; rel = rel->rel_next)
+ if (rel->rel_pracked)
+ return -1;
+ else if (rel->rel_rseq == rack->ra_response)
+ break;
+
+ if (!rel)
+ return -1; /* Process normally */
+
+ rel->rel_pracked = 1;
+ msg_ref_destroy(rel->rel_unsent), rel->rel_unsent = NULL;
+
+ pr_irq = incoming_create(irq->irq_agent, msg, sip, tp, irq->irq_tag);
+ if (!pr_irq) {
+ nta_msg_treply(irq->irq_agent, msg,
+ SIP_500_INTERNAL_SERVER_ERROR,
+ NTATAG_TPORT(tp),
+ TAG_END());
+ return 0;
+ }
+
+ if (irq->irq_status < 200) {
+ incoming_queue(irq->irq_agent->sa_in.proceeding, irq); /* Reset P1 */
+ incoming_reset_timer(irq); /* Reset P2 */
+ }
+
+ irq->irq_in_callback = pr_irq->irq_in_callback = 1;
+ status = rel->rel_callback(rel->rel_magic, rel, pr_irq, sip); rel = NULL;
+ irq->irq_in_callback = pr_irq->irq_in_callback = 0;
+
+ if (pr_irq->irq_destroyed && pr_irq->irq_terminated) {
+ incoming_free(pr_irq);
+ }
+ else if (status != 0) {
+ if (status < 200 || status > 299) {
+ SU_DEBUG_3(("nta_reliable(): invalid status %03d from callback\n",
+ status));
+ status = 200;
+ }
+ nta_incoming_treply(pr_irq, status, "OK", TAG_END());
+ nta_incoming_destroy(pr_irq);
+ }
+
+ /* If there are queued unsent reliable responses, send them all. */
+ while (irq->irq_reliable && irq->irq_reliable->rel_rseq == 0) {
+ nta_reliable_t *r;
+
+ for (r = irq->irq_reliable; r; r = r->rel_next)
+ if (r->rel_rseq == 0)
+ rel = r;
+
+ msg = rel->rel_unsent, sip = sip_object(msg);
+
+ if (sip->sip_status->st_status < 200) {
+ if (reliable_send(irq, rel, msg_ref_create(msg), sip) < 0) {
+ assert(!"send reliable response");
+ }
+ }
+ else {
+ /*
+ * XXX
+ * Final response should be delayed until a reliable provisional
+ * response has been pracked
+ */
+ rel->rel_unsent = NULL, rel->rel_rseq = (uint32_t)-1;
+ if (incoming_reply(irq, msg, sip) < 0) {
+ assert(!"send delayed final response");
+ }
+ }
+ }
+
+ return 0;
+}
+
+/** Flush unacknowledged and unsent reliable responses */
+void reliable_flush(nta_incoming_t *irq)
+{
+ nta_reliable_t *r, *rel;
+
+ do {
+ for (r = irq->irq_reliable, rel = NULL; r; r = r->rel_next)
+ if (r->rel_unsent)
+ rel = r;
+
+ if (rel) {
+ rel->rel_pracked = 1;
+ msg_ref_destroy(rel->rel_unsent), rel->rel_unsent = NULL;
+ rel->rel_callback(rel->rel_magic, rel, NULL, NULL);
+ }
+ } while (rel);
+}
+
+void reliable_timeout(nta_incoming_t *irq, int timeout)
+{
+ if (timeout)
+ SU_DEBUG_5(("nta: response timeout with %u\n", irq->irq_status));
+
+ irq->irq_in_callback = 1;
+
+ reliable_flush(irq);
+
+ if (irq->irq_callback)
+ irq->irq_callback(irq->irq_magic, irq, NULL);
+
+ irq->irq_in_callback = 0;
+
+ if (irq->irq_completed && irq->irq_destroyed)
+ incoming_free(irq), irq = NULL;
+
+ if (timeout && irq && irq->irq_status < 200)
+ nta_incoming_treply(irq, 503, "Reliable Response Time-Out", TAG_END());
+}
+
+#if 0 /* Not needed, yet. */
+/** Use this callback when normal leg callback is supposed to
+ * process incoming PRACK requests
+ */
+int nta_reliable_leg_prack(nta_reliable_magic_t *magic,
+ nta_reliable_t *rel,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ nta_agent_t *agent;
+ nta_leg_t *leg;
+ char const *method_name;
+ url_t url[1];
+ int retval;
+
+ if (irq == NULL || sip == NULL || rel == NULL ||
+ sip_object(irq->irq_request) != sip)
+ return 500;
+
+ agent = irq->irq_agent;
+ method_name = sip->sip_request->rq_method_name;
+ *url = *sip->sip_request->rq_url; url->url_params = NULL;
+ agent_aliases(agent, url, irq->irq_tport); /* canonize urls */
+
+ if ((leg = leg_find(irq->irq_agent,
+ method_name, url,
+ sip->sip_call_id,
+ sip->sip_from->a_tag, sip->sip_from->a_url,
+ sip->sip_to->a_tag, sip->sip_to->a_url))) {
+ /* Use existing dialog */
+ SU_DEBUG_5(("nta: %s (%u) %s\n",
+ method_name, sip->sip_cseq->cs_seq,
+ "PRACK processed by default callback, too"));
+ retval = leg->leg_callback(leg->leg_magic, leg, irq, sip);
+ }
+ else {
+ retval = 500;
+ }
+
+ nta_reliable_destroy(rel);
+
+ return retval;
+}
+#endif
+
+/** Destroy a reliable response.
+ *
+ * The function nta_reliable_destroy() marks a reliable response object for
+ * destroyal, and frees it if possible.
+ */
+void nta_reliable_destroy(nta_reliable_t *rel)
+{
+ if (rel == NULL || rel == NONE)
+ return;
+
+ if (rel->rel_callback == nta_reliable_destroyed)
+ SU_DEBUG_1(("%s(%p): already destroyed\n", __func__, rel));
+
+ rel->rel_callback = nta_reliable_destroyed;
+
+ if (rel->rel_response)
+ return;
+
+ nta_reliable_destroyed(NULL, rel, NULL, NULL);
+}
+
+/** Free and unallocate the nta_reliable_t structure. */
+static
+int nta_reliable_destroyed(nta_reliable_magic_t *rmagic,
+ nta_reliable_t *rel,
+ nta_incoming_t *prack,
+ sip_t const *sip)
+{
+ nta_reliable_t **prev;
+
+ assert(rel); assert(rel->rel_irq);
+
+ for (prev = &rel->rel_irq->irq_reliable; *prev; prev = &(*prev)->rel_next)
+ if (*prev == rel)
+ break;
+
+ if (!*prev) {
+ assert(*prev);
+ SU_DEBUG_1(("%s(%p): not linked\n", __func__, rel));
+ return 200;
+ }
+
+ *prev = rel->rel_next;
+
+ if (rel->rel_unsent)
+ msg_destroy(rel->rel_unsent), rel->rel_unsent = NULL;
+
+ su_free(rel->rel_irq->irq_agent->sa_home, rel);
+
+ return 200;
+}
+
+/** Validate a reliable response. */
+int outgoing_recv_reliable(nta_outgoing_t *orq,
+ msg_t *msg,
+ sip_t *sip)
+{
+ short status = sip->sip_status->st_status;
+ char const *phrase = sip->sip_status->st_phrase;
+ uint32_t rseq = sip->sip_rseq->rs_response;
+
+ SU_DEBUG_7(("nta: %03u %s is reliably received with RSeq: %u\n",
+ status, phrase, rseq));
+
+ /* Cannot handle reliable responses unless we have a full dialog */
+ if (orq->orq_rseq == 0 && !orq->orq_to->a_tag) {
+ SU_DEBUG_5(("nta: %03u %s with initial RSeq: %u outside dialog\n",
+ status, phrase, rseq));
+ return 0;
+ }
+
+ if (rseq <= orq->orq_rseq) {
+ SU_DEBUG_3(("nta: %03u %s already received (RSeq: %u, expecting %u)\n",
+ status, phrase, rseq, orq->orq_rseq + 1));
+ return -1;
+ }
+
+ if (orq->orq_rseq && orq->orq_rseq + 1 != rseq) {
+ SU_DEBUG_3(("nta: %03d %s is not expected (RSeq: %u, expecting %u)\n",
+ status, sip->sip_status->st_phrase,
+ rseq, orq->orq_rseq + 1));
+ return -1;
+ }
+
+ return 0;
+}
+
+/** Create a tagged fork of outgoing request.
+ *
+ * When a dialog-creating INVITE request is forked, each response from
+ * diffent fork will create an early dialog with a distinct tag in @To
+ * header. When each fork should be handled separately, a tagged INVITE
+ * request can be used. It will only receive responses from the specified
+ * fork. Please note that the tagged transaction should be terminated with
+ * the final response from another fork, too.
+ *
+ * @param orq
+ * @param callback
+ * @param magic
+ * @param to_tag
+ * @param rseq
+ */
+nta_outgoing_t *nta_outgoing_tagged(nta_outgoing_t *orq,
+ nta_response_f *callback,
+ nta_outgoing_magic_t *magic,
+ char const *to_tag,
+ sip_rseq_t const *rseq)
+{
+ nta_agent_t *agent;
+ su_home_t *home;
+ nta_outgoing_t *tagged;
+ sip_to_t *to;
+
+ if (orq == NULL || to_tag == NULL)
+ return NULL;
+ if (orq->orq_to->a_tag) {
+ SU_DEBUG_1(("%s: transaction %p already in dialog\n", __func__, orq));
+ return NULL;
+ }
+
+ assert(orq->orq_agent); assert(orq->orq_request);
+
+ agent = orq->orq_agent;
+ tagged = su_alloc(agent->sa_home, sizeof(*tagged));
+ home = msg_home((msg_t *)orq->orq_request);
+
+ *tagged = *orq;
+ tagged->orq_callback = callback;
+ tagged->orq_magic = magic;
+
+ tagged->orq_prev = NULL, tagged->orq_next = NULL, tagged->orq_queue = NULL;
+ tagged->orq_rprev = NULL, tagged->orq_rnext = NULL;
+
+ if (tagged->orq_cc)
+ nta_compartment_ref(tagged->orq_cc);
+
+ sip_to_tag(home, to = sip_to_copy(home, orq->orq_to), to_tag);
+
+ tagged->orq_to = to;
+ tagged->orq_tport = tport_ref(orq->orq_tport);
+ tagged->orq_request = (msg_t *)msg_ref_create(orq->orq_request);
+ tagged->orq_response = NULL;
+ tagged->orq_cancel = NULL;
+
+ tagged->orq_pending = tport_pend(orq->orq_tport,
+ orq->orq_request,
+ outgoing_tport_error,
+ tagged);
+ if (tagged->orq_pending < 0)
+ tagged->orq_pending = 0;
+
+ tagged->orq_rseq = 0;
+
+ outgoing_queue(orq->orq_queue, tagged);
+ outgoing_insert(agent, tagged);
+
+ return tagged;
+}
+
+/**PRACK a provisional response.
+ *
+ * The function nta_outgoing_prack() creates and sends a PRACK request used
+ * to acknowledge a provisional response.
+ *
+ * The request is sent using the route of the original request @a oorq.
+ *
+ * When NTA receives response to the prack request, it invokes the @a
+ * callback function.
+ *
+ * @param leg dialog object
+ * @param oorq original transaction request
+ * @param callback callback function (may be @c NULL)
+ * @param magic application context pointer
+ * @param route_url optional URL used to route transaction requests
+ * @param resp (optional) response message to be acknowledged
+ * @param tag,value,... optional
+ *
+ * @return
+ * If successful, the function nta_outgoing_prack() returns a pointer
+ * to newly created client transaction object for PRACK request, NULL
+ * otherwise.
+ *
+ * @sa
+ * nta_outgoing_tcreate(), nta_outgoing_tcancel(), nta_outgoing_destroy().
+ */
+nta_outgoing_t *nta_outgoing_prack(nta_leg_t *leg,
+ nta_outgoing_t *oorq,
+ nta_response_f *callback,
+ nta_outgoing_magic_t *magic,
+ url_string_t const *route_url,
+ sip_t const *resp,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ ta_list ta;
+ msg_t *msg;
+ su_home_t *home;
+ sip_t *sip;
+ sip_to_t const *to = NULL;
+ sip_route_t *route = NULL, r0[1];
+ nta_outgoing_t *orq = NULL;
+ sip_rack_t *rack = NULL, rack0[1];
+
+ if (!leg || !oorq) {
+ SU_DEBUG_1(("%s: invalid arguments\n", __func__));
+ return NULL;
+ }
+
+ sip_rack_init(rack0);
+
+ if (resp) {
+ if (!resp->sip_status) {
+ SU_DEBUG_1(("%s: invalid arguments\n", __func__));
+ return NULL;
+ }
+
+ if (resp->sip_status->st_status <= 100 ||
+ resp->sip_status->st_status >= 200) {
+ SU_DEBUG_1(("%s: %u response cannot be PRACKed\n",
+ __func__, resp->sip_status->st_status));
+ return NULL;
+ }
+
+ if (!resp->sip_rseq) {
+ SU_DEBUG_1(("%s: %u response missing RSeq\n",
+ __func__, resp->sip_status->st_status));
+ return NULL;
+ }
+
+ if (resp->sip_rseq->rs_response <= oorq->orq_rseq) {
+ SU_DEBUG_1(("%s: %u response RSeq does not match received RSeq\n",
+ __func__, resp->sip_status->st_status));
+ return NULL;
+ }
+ if (!oorq->orq_must_100rel &&
+ !sip_has_feature(resp->sip_require, "100rel")) {
+ SU_DEBUG_1(("%s: %u response does not require 100rel\n",
+ __func__, resp->sip_status->st_status));
+ return NULL;
+ }
+
+ if (!resp->sip_to->a_tag) {
+ SU_DEBUG_1(("%s: %u response has no To tag\n",
+ __func__, resp->sip_status->st_status));
+ return NULL;
+ }
+ if (str0casecmp(resp->sip_to->a_tag, leg->leg_remote->a_tag) ||
+ str0casecmp(resp->sip_to->a_tag, oorq->orq_to->a_tag)) {
+ SU_DEBUG_1(("%s: %u response To tag does not agree with dialog tag\n",
+ __func__, resp->sip_status->st_status));
+ return NULL;
+ }
+
+ to = resp->sip_to;
+ rack = rack0;
+
+ rack->ra_response = resp->sip_rseq->rs_response;
+ rack->ra_cseq = resp->sip_cseq->cs_seq;
+ rack->ra_method = resp->sip_cseq->cs_method;
+ rack->ra_method_name = resp->sip_cseq->cs_method_name;
+ }
+
+ msg = nta_msg_create(leg->leg_agent, 0);
+ sip = sip_object(msg); home = msg_home(msg);
+
+ if (!sip)
+ return NULL;
+
+ if (!leg->leg_route && resp) {
+ /* Insert contact into route */
+ if (resp->sip_contact) {
+ sip_route_init(r0)->r_url[0] = resp->sip_contact->m_url[0];
+ route = sip_route_dup(home, r0);
+ }
+
+ /* Reverse record route */
+ if (resp->sip_record_route) {
+ sip_route_t *r, *r_next;
+ for (r = sip_route_dup(home, resp->sip_record_route); r; r = r_next) {
+ r_next = r->r_next, r->r_next = route, route = r;
+ }
+ }
+ }
+
+ ta_start(ta, tag, value);
+
+ if (!resp) {
+ tagi_t const *t;
+
+ if ((t = tl_find(ta_args(ta), ntatag_rseq)) && t->t_value) {
+ rack = rack0;
+ rack->ra_response = (uint32_t)t->t_value;
+ }
+
+ if (rack) {
+ rack->ra_cseq = orq->orq_cseq->cs_seq;
+ rack->ra_method = orq->orq_cseq->cs_method;
+ rack->ra_method_name = orq->orq_cseq->cs_method_name;
+ }
+ }
+
+ if (sip_add_tl(msg, sip,
+ TAG_IF(rack, SIPTAG_RACK(rack)),
+ TAG_IF(to, SIPTAG_TO(to)),
+ ta_tags(ta)) < 0)
+ ;
+ else if (route && sip_add_dup(msg, sip, (sip_header_t *)route) < 0)
+ ;
+ else if (!sip->sip_rack)
+ SU_DEBUG_1(("%s: RAck header missing\n", __func__));
+ else if (nta_msg_request_complete(msg, leg,
+ SIP_METHOD_PRACK,
+ (url_string_t *)oorq->orq_url) < 0)
+ ;
+ else
+ orq = outgoing_create(leg->leg_agent, callback, magic,
+ route_url, NULL, msg, ta_tags(ta));
+
+ ta_end(ta);
+
+ if (!orq)
+ msg_destroy(msg);
+ else if (rack)
+ oorq->orq_rseq = rack->ra_response;
+ else if (sip->sip_rack)
+ oorq->orq_rseq = sip->sip_rack->ra_response;
+
+ return orq;
+}
+
+/** Get @RSeq value stored with client transaction. */
+uint32_t nta_outgoing_rseq(nta_outgoing_t const *orq)
+{
+ return orq ? orq->orq_rseq : 0;
+}
+
+/** Set @RSeq value stored with client transaction.
+ *
+ * @return 0 if rseq was set successfully
+ * @return -1 if rseq is invalid or orq is NULL.
+ */
+int nta_outgoing_setrseq(nta_outgoing_t *orq, uint32_t rseq)
+{
+ if (orq && orq->orq_rseq <= rseq) {
+ orq->orq_rseq = rseq;
+ return 0;
+ }
+
+ return -1;
+}
+
+/* ------------------------------------------------------------------------ */
+/* 11) SigComp handling and public transport interface */
+
+#include <sofia-sip/nta_tport.h>
+
+static inline tport_t *
+nta_transport_(nta_agent_t *agent,
+ nta_incoming_t *irq,
+ msg_t *msg)
+{
+ if (irq)
+ return irq->irq_tport;
+ else if (agent && msg)
+ return tport_delivered_by(agent->sa_tports, msg);
+
+ errno = EINVAL;
+ return NULL;
+}
+
+
+tport_t *
+nta_incoming_transport(nta_agent_t *agent,
+ nta_incoming_t *irq,
+ msg_t *msg)
+{
+ return tport_ref(nta_transport_(agent, irq, msg));
+}
+
+nta_compressor_t *nta_agent_init_sigcomp(nta_agent_t *sa)
+{
+ if (!nta_compressor_vtable || !sa)
+ return NULL;
+
+ if (sa->sa_compressor == NULL) {
+ char const * const *l = sa->sa_sigcomp_option_list;
+ nta_compressor_t *comp;
+ comp = nta_compressor_vtable->ncv_init_agent(sa, l);
+ sa->sa_compressor = comp;
+ }
+
+ return sa->sa_compressor;
+}
+
+void nta_agent_deinit_sigcomp(nta_agent_t *sa)
+{
+ if (nta_compressor_vtable && sa && sa->sa_compressor) {
+ nta_compressor_vtable->ncv_deinit_agent(sa, sa->sa_compressor);
+ sa->sa_compressor = NULL;
+ }
+}
+
+struct sigcomp_compartment *
+nta_incoming_compartment(nta_incoming_t *irq)
+{
+ if (nta_compressor_vtable && irq && irq->irq_cc)
+ return nta_compressor_vtable->ncv_compartment_ref(irq->irq_cc);
+ else
+ return NULL;
+}
+
+tport_t *
+nta_outgoing_transport(nta_outgoing_t *orq)
+{
+ if (orq)
+ return tport_ref(orq->orq_tport);
+ else
+ return NULL;
+}
+
+
+struct sigcomp_compartment *
+nta_outgoing_compartment(nta_outgoing_t *orq)
+{
+ if (nta_compressor_vtable && orq && orq->orq_cc)
+ return nta_compressor_vtable->ncv_compartment_ref(orq->orq_cc);
+ else
+ return NULL;
+}
+
+
+struct sigcomp_compartment *
+nta_compartment_ref(struct sigcomp_compartment *cc)
+{
+ if (nta_compressor_vtable)
+ return nta_compressor_vtable->ncv_compartment_ref(cc);
+ else
+ return NULL;
+}
+
+void
+nta_compartment_decref(struct sigcomp_compartment **pcc)
+{
+ if (nta_compressor_vtable && pcc && *pcc)
+ nta_compressor_vtable->ncv_compartment_unref(*pcc), *pcc = NULL;
+}
+
+
+/** Get compartment for connection, create it when needed. */
+static
+struct sigcomp_compartment *
+agent_compression_compartment(nta_agent_t *sa,
+ tport_t *tp,
+ tp_name_t const *tpn,
+ int new_if_needed)
+{
+ if (nta_compressor_vtable) {
+ char const * const *l = sa->sa_sigcomp_option_list;
+ return nta_compressor_vtable->
+ ncv_compartment(sa, tp, sa->sa_compressor, tpn, l, new_if_needed);
+ }
+ else
+ return NULL;
+}
+
+static
+int agent_accept_compressed(nta_agent_t *sa, msg_t *msg,
+ struct sigcomp_compartment *cc)
+{
+ if (nta_compressor_vtable) {
+ nta_compressor_t *msc = sa->sa_compressor;
+ tport_compressor_t *sc = NULL;
+ if (tport_delivered_with_comp(sa->sa_tports, msg, &sc) < 0)
+ return 0;
+ return nta_compressor_vtable->ncv_accept_compressed(sa, msc, sc, msg, cc);
+ }
+ else
+ return 0;
+}
+
+/** Close compressor (lose its state). */
+static
+int agent_close_compressor(nta_agent_t *sa,
+ struct sigcomp_compartment *cc)
+{
+ if (nta_compressor_vtable)
+ return nta_compressor_vtable->ncv_close_compressor(sa, cc);
+ return 0;
+}
+
+/** Close both compressor and decompressor */
+static
+int agent_zap_compressor(nta_agent_t *sa,
+ struct sigcomp_compartment *cc)
+{
+ if (nta_compressor_vtable)
+ return nta_compressor_vtable->ncv_zap_compressor(sa, cc);
+ return 0;
+}
+
+/** Bind transport update callback */
+int nta_agent_bind_tport_update(nta_agent_t *agent,
+ nta_update_magic_t *magic,
+ nta_update_tport_f *callback)
+{
+ if (!agent)
+ return su_seterrno(EFAULT), -1;
+ agent->sa_update_magic = magic;
+ agent->sa_update_tport = callback;
+ return 0;
+}
+
+/** Check if public transport binding is in progress */
+int nta_agent_tport_is_updating(nta_agent_t *agent)
+{
+ return agent && tport_is_updating(agent->sa_tports);
+}
+
+/** Initiate STUN keepalive controller to TPORT */
+int nta_tport_keepalive(nta_outgoing_t *orq)
+{
+ tport_t *tp;
+
+ assert(orq); (void)tp;
+
+ return tport_keepalive(orq->orq_tport, msg_addrinfo(orq->orq_request),
+ TAG_END());
+}
+
+/** Close all transports. @since Experimental in @VERSION_1_12_2. */
+int nta_agent_close_tports(nta_agent_t *agent)
+{
+ int i;
+ outgoing_htable_t *oht = agent->sa_outgoing;
+ incoming_htable_t *iht = agent->sa_incoming;
+
+ for (i = oht->oht_size; i-- > 0;)
+ /* while */ if (oht->oht_table[i]) {
+ nta_outgoing_t *orq = oht->oht_table[i];
+
+ if (orq->orq_pending && orq->orq_tport)
+ tport_release(orq->orq_tport, orq->orq_pending, orq->orq_request,
+ NULL, orq, 0);
+
+ orq->orq_pending = 0;
+ tport_unref(orq->orq_tport), orq->orq_tport = NULL;
+ }
+
+
+ for (i = iht->iht_size; i-- > 0;)
+ /* while */ if (iht->iht_table[i]) {
+ nta_incoming_t *irq = iht->iht_table[i];
+ tport_unref(irq->irq_tport), irq->irq_tport = NULL;
+ }
+
+ tport_destroy(agent->sa_tports), agent->sa_tports = NULL;
+
+ msg_header_free(agent->sa_home, (void *)agent->sa_vias);
+ agent->sa_vias = NULL;
+ msg_header_free(agent->sa_home, (void *)agent->sa_public_vias);
+ agent->sa_public_vias = NULL;
+
+ return 0;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta.docs Thu Dec 21 01:30:28 2006
@@ -0,0 +1,572 @@
+/* -*- c -*- */
+
+/**@MODULEPAGE "nta" - SIP Transactions Module
+ *
+ * @section nta_meta Module Meta Information
+ *
+ * Sofia SIP Transaction API (nta) provides simple interface to the SIP
+ * transaction, transport and message handling. The @b nta interface is
+ * intended for both network and user elements. The public interface for @b
+ * nta is mostly defined in <sofia-sip/nta.h>, but tag parameters are
+ * defined in <sofia-sip/nta_tag.h>.
+ *
+ * @CONTACT Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @STATUS @SofiaSIP Core library
+ *
+ * @LICENSE LGPL
+ *
+ * @section nta_objects NTA Objects
+ *
+ * The NTA deals with a few kinds of objects: @e agent (#nta_agent_t), @e
+ * call @e legs (#nta_leg_t), @e outgoing @e client @e requests
+ * (#nta_outgoing_t), and @e incoming @e server @e requests
+ * (#nta_incoming_t).
+ *
+ * NTA also uses SIP message objects #msg_t and #sip_t for handling
+ * messages, as defined in <msg.h> and <sip.h>, respectively. The various
+ * SIP headers are also defined in <sip.h>.
+ *
+ * @section nta_agent_t Creating an NTA Agent
+ *
+ * Most of the SIP entities, like @e user @e agent or @e proxy, consist of a
+ * SIP server and a SIP client working together. The NTA provides a simple
+ * interface to SIP server and client with the #nta_agent_t objects.
+ *
+ * The #nta_agent_t object is created by calling nta_agent_create(). The
+ * object listens for incoming connections, receives messages, parses them,
+ * and pass them to the application. It also takes care of resolving the
+ * domain names and sending the messages.
+ *
+ * The agent needs a #su_root_t object to schedule its execution. A root
+ * object is used to wait for the network events, schedule the timer
+ * routines, and pass messages asyncronously. A root object can be created
+ * by, e.g., the function su_root_create(). The root object can be have its
+ * own thread, or its main loop can be executed by an application thread by
+ * calling the function su_root_run(). The main loop can be terminated by
+ * calling the function su_root_break().
+ *
+ * A simple agent could be created as follows:
+ * @code
+ * registrar->reg_root = su_root_create(NULL);
+ *
+ * if (registrar->reg_root) {
+ * registrar->reg_agent = nta_agent_create(registrar->reg_root,
+ * (url_string_t*)argv[1],
+ * NULL,
+ * NULL,
+ * NULL);
+ *
+ * if (registrar->reg_agent) {
+ * su_root_run(registrar->reg_root);
+ * nta_agent_destroy(registrar->reg_agent);
+ * }
+ *
+ * su_root_destroy(registrar->reg_root);
+ * }
+ * @endcode
+ *
+ * @section nta_server SIP Server Action
+ *
+ * A SIP server responds to the transactions sent by a client. The SIP
+ * server can operate in two modes; it can be stateless or stateful. This
+ * section describes how a stateful SIP server uses NTA.
+ *
+ * @subsection nta_leg_t The NTA Legs
+ *
+ * A leg is required for stateful transaction processing. A default
+ * leg is created like this:
+ * @code
+ * default_leg = nta_leg_tcreate(agent, process_requests, context,
+ * URLTAG_URL(url),
+ * NTATAG_NO_DIALOG(1),
+ * TAG_END());
+ * @endcode
+ *
+ * The @a url parameter is used to specify which URLs match to the leg. If
+ * it is given, only requests with requestURI matching are processed by the
+ * leg. The nta_leg_tcreate() is a @ref tagarg "tagarg" function, taking a
+ * tagged argument list as its arguments.
+ *
+ * Other, ordinary legs can be used to match incoming requests with existing
+ * dialogs, calls or transaction contexts, or to provide outgoing requests
+ * with consistent headers. When a call leg is created, it is provided with
+ * @From and @To headers, and optionally with other headers like
+ * @CallID, @Route, or @CSeq.
+ *
+ * A new call leg can be created as follows:
+ * @code
+ * call_leg = nta_leg_tcreate(agent,
+ * process_call_requests, call_context,
+ * SIPTAG_CALL_ID(sip->sip_call_id),
+ * SIPTAG_TO(sip->sip_from),
+ * SIPTAG_FROM(sip->sip_to),
+ * TAG_END());
+ * @endcode
+ *
+ * @note In the example above, the @From and @To are reversed. This
+ * happens if the headers are taken from an incoming request; the @From
+ * and @To headers change direction when an outgoing request is initiated.
+ *
+ * @note An existing leg can be used in any direction, however. If the leg
+ * was created for an incoming INVITE transaction, it is also possible to
+ * use the leg for an outgoing BYE transaction.
+ *
+ * @subsection nta_leg_tag Tagging the Call Leg
+ *
+ * All the SIP UAS elements are required to tag the @To header in their
+ * final responses. The function nta_leg_tag() adds a tag to the leg's local
+ * address. Local address is used as the @To header in the reply messages,
+ * and as the @From header in the requests. The function nta_incoming_tag()
+ * adds a tag to a incoming transaction. They are usually used in together,
+ * using the tag from initial response to the dialog, too:
+ * e.g.,
+ * @code
+ * if (!nta_leg_tag(leg, nta_incoming_tag(irq, NULL)))
+ * nta_incoming_treply(irq, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
+ * @endcode
+ *
+ * @subsection nta_incoming_t Incoming Transactions
+ *
+ * An incoming transaction object (nta_incoming_t) is created by NTA for
+ * each unique incoming request message. When NTA has created the incoming
+ * transaction object, it invokes the callback function provided with
+ * nta_leg_tcreate().
+ *
+ * The simplest way to reply to the request is to return a valid status code
+ * from the callback function. Valid status codes are in range of 100 to
+ * 699, inclusive. If no automatic response is desired, the callback
+ * function should return 0.
+ *
+ * @note If the status code is final, the incoming transaction object will
+ * be destroyed immediately after the callback function returns. It can not
+ * be used afterwards.
+ *
+ * @note It is not possible to respond with a 2xx status code to an incoming
+ * INVITE transaction by returning the status code from the callback.
+ *
+ * Valid return values for callback function are as follows:
+ * @li 0, 100 .. 699 for requests other than INVITE, and
+ * @li 0, 100 .. 199, 300..699 for INVITE requests.
+ *
+ * All other return codes are interpreted as 500, that is, a @e 500 @e
+ * Internal @e Server @e Error reply message is sent back to the client and
+ * the request is immediately destroyed.
+ *
+ * The simple registrar/redirect server may have a incoming request callback
+ * as follows:
+ * @code
+ * int process_request(server_t *server,
+ * nta_leg_t *leg,
+ * nta_incoming_t *irq,
+ * sip_t const *sip)
+ * {
+ * sip_contact_t *m;
+ *
+ * switch (sip->sip_request->rq_method) {
+ * case sip_method_register:
+ * return registrar_add(server, leg, reply, sip);
+ *
+ * case sip_method_ack:
+ * return 500;
+ *
+ * case sip_method_cancel:
+ * return 200;
+ *
+ * default:
+ * if (registrar_find(server, sip->sip_request->rq_url, &m) {
+ * nta_incoming_treply(irq, SIP_302_MOVED_TEMPORARILY,
+ * SIPTAG_CONTACT(m), TAG_END());
+ * return 302;
+ * }
+ * else {
+ * nta_incoming_treply(irq, SIP_404_NOT_FOUND, TAG_END());
+ * return 404;
+ * }
+ * }
+ * }
+ * @endcode
+ *
+ * The default reply message will contain the status line with default
+ * phrase, then @Via, @To, @From, @CallID, @CSeq, and @ContentLength headers.
+ * If a more complex response message is required, the application should
+ * respond using the function nta_incoming_treply():
+ * @code
+ * nta_incoming_treply(reply, SIP_200_OK,
+ * SIPTAG_CONTACT(contact),
+ * SIPTAG_CONTENT_TYPE_STR("application/sdp"),
+ * SIPTAG_PAYLOAD(sdp),
+ * TAG_END());
+ * @endcode
+ *
+ * The nta_incoming_treply() is a @ref tagarg "tagarg" function, taking a
+ * tagged argument list as its argument.
+ *
+ * @note It is possible to send provisional replies (containing 1xx status
+ * codes) several times with nta_incoming_treply(), but only one final
+ * reply (containing status codes 2xx..6xx) can be sent. However, with
+ * INVITE requests, a proxy can send a final 2xx reply even after an error
+ * reply (3xx..6xx).
+ *
+ * @section nta_100rel Reliable Provisional Responses - "100rel"
+ *
+ * The <A href="../specs/rfc3262.txt"><B>100rel</B></A> SIP extension
+ * provides reliable provisional responses, provisional responses that are
+ * retransmitted until a special acknowledgement request, PRACK, is
+ * received. In addition the PRACK method, the extension defines two
+ * headers, @RSeq and @RAck, that are used to identify different
+ * response messages. PRACK method is usable on INVITE requests only.
+ *
+ * Using reliable responses is negotiated using the "100rel" option tag. The
+ * UAC (party sending the INVITE) can include the option tag to the
+ * @Supported or @Require header. In the first case, the UAC just
+ * announces support for reliable responses, in the second case, the UAC
+ * requires that the UAS (party responding to the call) always sends
+ * provisional responses in reliable manner.
+ *
+ * When reliable responses are enabled with NTATAG_REL100() tag, the @b nta
+ * engine automatically inserts the "100rel" option tag to the @Supported
+ * header in the INVITE requests.
+ *
+ * @subsection nta_reliable_t Responding Reliably
+ *
+ * When a UAS wants to respond reliably to a INVITE request, instead of
+ * familiar nta_incoming_treply() or nta_incoming_mreply() it uses the
+ * functions nta_reliable_treply() or nta_reliable_mreply(). These functions
+ * return a pointer to a special object, nta_reliable_t, that is used to
+ * keep track of unacknowledged responses and respond to the the PRACK
+ * acknowledgement request.
+ *
+ * Both the functions nta_reliable_treply () and nta_reliable_mreply() take
+ * a callback funtion pointer and an application context pointer as their
+ * arguments. The callback function is similar to the leg callback function.
+ * The callback is invoked when a corresponding PRACK request is received,
+ * or when there is a timeout.
+ *
+ * The @b nta takes care of assigning a serial number to each reliable
+ * response and resending them if no PRACK request is received. It also
+ * automatically adds the 100rel option tag to the @Require header.
+ *
+ * Also, if a request with 100rel in @Require header is responded with usual
+ * nta_incoming_treply()/nta_incoming_mreply() functions, the @b nta creates
+ * a reliable response object for each provisional response in behalf of
+ * application. As the application can not provide a PRACK callback function
+ * to @b nta, the PRACK requests are not delivered to the application.
+ *
+ * @subsection early_dialog UAC Receives a Reliable Response
+ *
+ * When a UAC receives a provisional response with a @RSeq header, it is
+ * required to acknowledge it. In order to do that, it must establish an @e
+ * early @e dialog with the UAS. In another view, a reliable response is
+ * used to establish the early dialog. UAC establishes a leg object for the
+ * early dialog by calling nta_leg_tcreate() with the parameters derived
+ * from the response message.
+ *
+ * @code
+ * int invite_callback(call_t *call,
+ * nta_outgoing_t *orq,
+ * sip_t const *sip)
+ * {
+ * int status = sip->sip_status->st_status;
+ *
+ * if (!call->has_dialog &&
+ * (status >= 200 || (status > 100 && sip->sip_rseq))) {
+ * nta_leg_t *early =
+ * nta_leg_tcreate(call->nta_agent, mid_dialog_request, call,
+ * SIPTAG_TO(sip->sip_to),
+ * SIPTAG_FROM(sip->sip_from),
+ * SIPTAG_CALL_ID(sip->sip_call_id),
+ * SIPTAG_CSEQ(sip->sip_cseq),
+ * TAG_END());
+ *
+ * nta_leg_client_route(early,
+ * sip->sip_record_route,
+ * sip->sip_contact);
+ *
+ * fork = call_fork(call, leg = early);
+ *
+ * if (!fork) {
+ * handle error;
+ * }
+ * call = fork;
+ * }
+ * @endcode
+ *
+ * The original dialog object and client transaction object are used to
+ * process other call forks. For instance, if the early dialog is
+ * established with an announcement server it will never lead to an fully
+ * established call, but an another dialog will be used when the call is
+ * completed.
+ *
+ * @subsection nta_prack Acknowledging Reliable Response
+ *
+ * After an early dialog has been established, acknowledging the reliable
+ * response is trivial. The application can create a PRACK client
+ * transaction object by calling nta_outgoing_prack()
+ *
+ * @section nta_client SIP Client Action
+ *
+ * A SIP client initiates the transactions. In some cases, a SIP client is
+ * also required to invoke additional transactions, like @b ACK or @b
+ * CANCEL, to finalize the original transaction. This section describes how
+ * a SIP client uses NTA to make transactions.
+ *
+ * @subsection client_nta_leg_t Creating the Call Leg
+ *
+ * If the client does not have a suitable call leg, it must create it by
+ * calling the function nta_leg_tcreate():
+ * @code
+ * context->leg = nta_leg_tcreate(agent,
+ * callback, context,
+ * SIPTAG_CALL_ID(call_id),
+ * SIPTAG_FROM(from),
+ * SIPTAG_TO(to),
+ * TAG_END());
+ * @endcode
+ *
+ * The @p callback function and @p context pointer are used for incoming
+ * transactions, and they may be @c NULL if no such transactions are
+ * expected. If the callback is @c NULL, NTA responds to incoming
+ * transactions with status @e 403 @e Forbidden.
+ *
+ * The @a call_id may be @c NULL or left out. In that case, NTA generates a
+ * new call ID.
+ *
+ * The @a from and @a to are used in outgoing transactions. They are also
+ * used to select which incoming messages belong to this leg.
+ *
+ * The initial sequence number can be supplied with SIPTAG_CSEQ() (taking a
+ * @CSeq structure as parameter).
+ *
+ * The additional parameters (after @a to) are included in outgoing messages
+ * using this leg. Currently, only @c SIPTAG_ROUTE() is supported.
+ *
+ * @note Additional tagged parameters are ignored.
+ *
+ * @subsection nta_outgoing_t Outgoing requests
+ *
+ * The outgoing request is created and sent by nta_outgoing_tcreate(). It
+ * can be used as follows:
+ * @code
+ * oreq = nta_outgoing_tcreate(leg, response_to_register, reg,
+ * proxy_url,
+ * SIP_METHOD_REGISTER,
+ * registrar_url,
+ * SIPTAG_CONTACT(my_contact),
+ * TAG_END());
+ * @endcode
+ *
+ * NTA invokes the callback function response_to_register() each time a
+ * provisional answer is received, and when a final answer is received.
+ *
+ * @note There may be multiple final answers to the INVITE request.
+ *
+ * If NTA does not receive answer in timely manner, it will generate a
+ * @e 408 @e Timeout response and hand that back to the application.
+ *
+ * @note After a provisional answer to the INVITE request, no timeout will
+ * occur inside NTA. Application must itself timeout the INVITE
+ * transactions if any answer has been received.
+ *
+ * The request can be destroyed with NTA function nta_outgoing_destroy().
+ * If no final answer has been received, the request is cancelled when it is
+ * destroyed, too. The application can also cancel the outgoing request by
+ * calling nta_outgoing_cancel().
+ *
+ * @subsection nta_ack Acknowledging Answers to INVITE
+ *
+ * The final answers to the INVITE request must be acknowledged. NTA takes
+ * care of acknowledging automatically the 3xx..6xx answers; the appliction
+ * must explicitly create a separate acknowledge transaction to final 2xx
+ * answers.
+ *
+ * The final answer can be acknowledged like this:
+ * @code
+ * url = sip->sip_contact ? sip->sip_contact->m_url : original_url;
+ * ack = nta_outgoing_tcreate(leg, NULL, NULL,
+ * SIP_METHOD_ACK,
+ * (url_string_t*)url,
+ * SIPTAG_CSEQ(sip->sip_cseq),
+ * SIPTAG_PAYLOAD(sdp),
+ * TAG_END());
+ * @endcode
+ *
+ * @note The ACK transaction should be sent to the @Contact specified in the
+ * 2xx reply.
+ *
+ * <a name="nta_register_f"></a>
+ * @section nta_stateless_callback Stateless Processing of SIP Messages
+ *
+ * When an NTA agent is created, it is possible to provide it with a
+ * stateless callback function. The callback function will be called when an
+ * incoming SIP request or response message does not match with an existing
+ * transaction.
+ *
+ * Before invoking the stateless callback the agent will try to match the
+ * incoming request message with an existing dialog or dialog-less leg (or
+ * default leg). So, if you have created a default leg, all request messages
+ * are processed statefully by it instead of being passed to the stateless
+ * callback function.
+ *
+ * If you want to process request messages with stateless callback and still
+ * use dialog-less legs (for instance, in order to look up domains with
+ * nta_leg_by_uri()), you have to switch over to @em stateless @em mode by
+ * including NTATAG_STATELESS(1) in nta_agent_create() or
+ * nta_agent_set_params() arguments.
+ *
+ * Also, if a response message does not match with an existing client
+ * transaction, the agent will try to use the default outgoing (client)
+ * transaction. If you have created an default outgoing transaction, all
+ * stray response messages are passed to it instead of the stateless
+ * processing function.
+ *
+ * @section nta_message_f_example Stateless Callback Function
+ *
+ * In addition to the message (@a msg) and its
+ * parsed contents (@a sip) the callback function gets the
+ * application-specific context pointer (in this case, @a registrar) and a
+ * pointer to the NTA agent (@a agent) as its arguments:
+ *
+ * @code
+ * int process_message(nta_agent_context_t *registrar,
+ * nta_agent_t *agent,
+ * msg_t *msg,
+ * sip_t *sip);
+ * @endcode
+ *
+ * The application has three functions that can be used to process the
+ * messages in stateless manner:
+ * @li nta_msg_discard() ignores and destroys the message,
+ * @li nta_msg_tsend() forwards a request or response message, and
+ * @li nta_msg_treply() replies to a request message in a stateless way.
+ *
+ * Additionally, it is possible to process a request message statefully with
+ * nta_incoming_create().
+ *
+ * The functionality of the stateless callback function can vary greatly,
+ * depending the purpose of the application. An user-agent, a proxy or a
+ * registrar/redirect server each have very different callback functions.
+ *
+ * A simple redirect server could have a message callback function as
+ * follows.
+ *
+ * @code
+ * int process_message(redirect_t *r,
+ * nta_agent_t *agent,
+ * msg_t *msg,
+ * sip_t *sip)
+ * {
+ * sip_contact_t *m;
+ * sip_unsupported_t *u;
+ *
+ * @endcode
+ *
+ * The incoming response messages are simply ignored. The @b ACK requests can
+ * safely be discarded, too, because the redirect server keeps no state.
+ *
+ * @code
+ * if (!sip->sip_request || sip->sip_request->rq_method == sip_method_ack) {
+ * nta_msg_discard(agent, msg);
+ * return 0;
+ * }
+ * @endcode
+ *
+ * Next, the redirect server first checks if processing the request requires
+ * a feature that is not supported by it:
+ * @code
+ * u = sip_unsupported(msg_home(msg), sip->sip_require, r->r_supported);
+ * if (u) {
+ * nta_msg_treply(agent, msg, SIP_420_BAD_EXTENSION,
+ * SIPTAG_SUPPORTED(r->r_supported),
+ * SIPTAG_UNSUPPORTED(u),
+ * TAG_END());
+ * return 0;
+ * }
+ * @endcode
+ *
+ * The @b CANCEL requests terminate a transacton. A stateless redirect
+ * server does not have transactions, so it redirect replies with a @e 481
+ * @e Call @e Leg/Transaction @e Does @e Not @e Exist message:
+ * @code
+ * if (sip->sip_request->rq_method == sip_method_cancel) {
+ * nta_msg_treply(agent, msg, SIP_481_NO_TRANSACTION, TAG_END());
+ * return 0;
+ * }
+ * @endcode
+ *
+ * All other requests are answered normally with a 302 response.
+ * The location service is
+ * searched for the request uri, and if a matching address was found, a
+ * list of active bindings is returned to the client.
+ * @code
+ * m = location_find(redirect, sip->sip_request->rq_url);
+ * if (m) {
+ * nta_msg_treply(agent, msg, SIP_302_MOVED_TEMPORARILY,
+ * SIPTAG_CONTACT(m),
+ * TAG_END());
+ * }
+ * @endcode
+ *
+ * Otherwise, @e 404 @e Not @e Found is sent:
+ * @code
+ * else {
+ * nta_msg_treply(agent, msg, SIP_404_NOT_FOUND, TAG_END());
+ * }
+ *
+ * return 0;
+ * }
+ * @endcode
+ *
+ */
+
+/**@page internal NTA Semantics and Internal Data Flows
+ *
+ * NTA implements simple state machines at transaction level. The figure
+ * below illustrates how a message is processed by NTA.
+ *
+ * @image html nta-receiving-message.gif "NTA processing incoming messages."
+ * @image latex nta-receiving-message.eps "NTA processing incoming messages."
+ *
+ *
+ */
+
+int invite_callback(call_t *call,
+ nta_outgoing_t *orq,
+ sip_t const *sip)
+{
+ int status = sip->sip_status->st_status;
+ nta_leg_t *leg = call->leg;
+
+ if (!call->has_dialog &&
+ (status >= 200 || (status > 100 && sip->sip_rseq))) {
+ nta_leg_t *early =
+ nta_leg_tcreate(call->nta_agent, mid_dialog_request, call,
+ SIPTAG_TO(sip->sip_to),
+ SIPTAG_FROM(sip->sip_from),
+ SIPTAG_CALL_ID(sip->sip_call_id),
+ SIPTAG_CSEQ(sip->sip_cseq),
+ TAG_END());
+
+ nta_leg_client_route(early,
+ sip->sip_record_route,
+ sip->sip_contact);
+
+ fork = call_fork(call, leg = early);
+
+ if (!fork) {
+ handle error;
+ }
+ call = fork;
+ }
+
+ if (status > 100 && status < 200 && sip->sip_rseq) {
+ nta_outgoing_t *prack =
+ nta_outgoing_prack(leg, orq, NULL, NULL, NULL,
+ sip,
+ TAG_END());
+ nta_outgoing_destroy(prack);
+ return 0;
+ }
+
+ ...
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta_check.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta_check.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,384 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nta_check.c
+ * @brief Checks for features, MIME types, session timer.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Mar 8 16:35:05 EET 2006 ppessi
+ */
+
+#include "config.h"
+
+#include <sofia-sip/su_tagarg.h>
+#include <sofia-sip/sip_header.h>
+#include <sofia-sip/sip_status.h>
+#include <sofia-sip/sip_util.h>
+#include <sofia-sip/nta.h>
+
+/* ======================================================================== */
+/* Request validation */
+
+/**Check that we support all features which UAC requires.
+ *
+ * The list of supported features is compared with the list of features
+ * required by the UAC. If some features are not listed as supported, return
+ * 420. If @a irq is non-NULL, the 420 response message is sent to the
+ * client along with list of unsupported features in the @Unsupported
+ * header, too.
+ *
+ * @param irq incoming transaction object (may be NULL).
+ * @param sip contents of the SIP message
+ * @param supported list of protocol features supported
+ * @param tag, value, ... optional list of tagged arguments used
+ * when responding to the transaction
+ *
+ * @return 0 if successful.
+ * 420 if any of the required features is not supported.
+ */
+int nta_check_required(nta_incoming_t *irq,
+ sip_t const *sip,
+ sip_supported_t const *supported,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ int status = 0;
+
+ if (sip->sip_require) {
+ su_home_t home[SU_HOME_AUTO_SIZE(512)];
+ sip_unsupported_t *us;
+
+ su_home_auto(home, sizeof home);
+
+ us = sip_has_unsupported(home, supported, sip->sip_require);
+
+ if (us) {
+ status = 420;
+ if (irq) {
+ ta_list ta;
+ ta_start(ta, tag, value);
+ nta_incoming_treply(irq,
+ SIP_420_BAD_EXTENSION,
+ SIPTAG_UNSUPPORTED(us),
+ SIPTAG_SUPPORTED(supported),
+ ta_tags(ta));
+ ta_end(ta);
+ }
+ }
+
+ su_home_deinit(home);
+ }
+
+ return status;
+}
+
+/** Check that UAC supports all the required features.
+ *
+ * The list of required features is compared with the features supported by
+ * the UAC. If some features are not supported, return 421. If @a irq is
+ * non-NULL, the 421 response message is sent to the client, too.
+ *
+ * @param irq incoming transaction object (may be NULL).
+ * @param sip contents of the SIP message
+ * @param require list of required protocol features
+ * @param tag, value, ... optional list of tagged arguments used
+ * when responding to the transaction
+ *
+ * @return 0 if successful.
+ * 421 if any of the required features is not supported.
+ */
+int nta_check_supported(nta_incoming_t *irq,
+ sip_t const *sip,
+ sip_require_t *require,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ if (!sip_has_unsupported(NULL, sip->sip_supported, require))
+ return 0;
+
+ if (irq) {
+ ta_list ta;
+ ta_start(ta, tag, value);
+ nta_incoming_treply(irq,
+ SIP_421_EXTENSION_REQUIRED,
+ SIPTAG_REQUIRE(require),
+ ta_tags(ta));
+ ta_end(ta);
+ }
+
+ return 421;
+}
+
+/** Check that we allow the request method.
+ *
+ * The request-method is compared with the list of supported methods in @a
+ * allow. If match is found, 0 is is returned. Otherwise, if the
+ * request-method is well-known, 405 is returned. If the request-method is
+ * unknown, 501 is returned. If @a irq is non-NULL, the 405 or 501 response
+ * message is sent to the client, too.
+ *
+ * @param irq incoming transaction object (may be NULL).
+ * @param sip contents of the SIP message
+ * @param allow list of allowed methods
+ * @param tag, value, ... optional list of tagged arguments used
+ * when responding to the transaction
+ *
+ * @return 0 if successful, 405 is request-method is not allowed, 501 if
+ * request-method is unknown.
+ */
+int nta_check_method(nta_incoming_t *irq,
+ sip_t const *sip,
+ sip_allow_t const *allow,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ /* Check extensions */
+ sip_method_t method = sip->sip_request->rq_method;
+ char const *name = sip->sip_request->rq_method_name;
+
+ if (sip_is_allowed(allow, method, name))
+ return 0;
+
+ if (irq) {
+ ta_list ta;
+ ta_start(ta, tag, value);
+
+ if (method != sip_method_unknown)
+ /* Well-known method */
+ nta_incoming_treply(irq,
+ SIP_405_METHOD_NOT_ALLOWED,
+ SIPTAG_ALLOW(allow),
+ ta_tags(ta));
+ else
+ /* Completeley unknown method */
+ nta_incoming_treply(irq,
+ SIP_501_NOT_IMPLEMENTED,
+ SIPTAG_ALLOW(allow),
+ ta_tags(ta));
+ ta_end(ta);
+ }
+
+ return method != sip_method_unknown ? 405 : 501;
+}
+
+static char const application_sdp[] = "application/sdp";
+
+/** Check that we understand session content in the request.
+ *
+ * If there is no @ContentDisposition header or the @ContentDisposition
+ * header indicated "session", the message body and content-type is compared
+ * with the acceptable session content-types listed in @a session_accepts.
+ * (typically, @c "application/sdp"). If no match is found, a 415 is
+ * returned. If @a irq is non-NULL, the 415 response message is sent to the
+ * client, too.
+ *
+ * If the @ContentDisposition header indicates something else but "session",
+ * and it does not contain "handling=optional" parameter, a 415 response is
+ * returned, too.
+ *
+ * Also, the @ContentEncoding header is checked. If it is not empty
+ * (indicating no content-encoding), a 415 response is returned, too.
+ *
+ * @param irq incoming (server) transaction object (may be NULL).
+ * @param sip contents of the SIP message
+ * @param session_accepts list of acceptable content-types for "session"
+ * content disposition
+ * @param tag, value, ... optional list of tagged arguments used
+ * when responding to the transaction
+ *
+ * @return 0 if successful, 415 if content-type is not acceptable.
+ */
+int nta_check_session_content(nta_incoming_t *irq,
+ sip_t const *sip,
+ sip_accept_t const *session_accepts,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ sip_content_type_t const *c = sip->sip_content_type;
+ sip_content_disposition_t const *cd = sip->sip_content_disposition;
+ int acceptable_type = 0, acceptable_encoding = 0;
+
+ if (sip->sip_payload == NULL)
+ return 0;
+
+ if (cd == NULL || strcasecmp(cd->cd_type, "session") == 0) {
+ sip_accept_t const *ab = session_accepts;
+ char const *c_type;
+
+ if (c)
+ c_type = c->c_type;
+ else if (sip->sip_payload->pl_len > 3 &&
+ strncasecmp(sip->sip_payload->pl_data, "v=0", 3) == 0)
+ /* Missing Content-Type, but it looks like SDP */
+ c_type = application_sdp;
+ else
+ /* No chance */
+ ab = NULL, c_type = NULL;
+
+ for (; ab; ab = ab->ac_next) {
+ if (strcasecmp(c_type, ab->ac_type) == 0)
+ break;
+ }
+
+ if (ab)
+ acceptable_type = 1;
+ }
+ else if (cd->cd_optional)
+ acceptable_type = 1;
+
+ /* Empty or missing Content-Encoding */
+ if (!sip->sip_content_encoding ||
+ !sip->sip_content_encoding->k_items ||
+ !sip->sip_content_encoding->k_items[0] ||
+ !sip->sip_content_encoding->k_items[0][0])
+ acceptable_encoding = 1;
+
+ if (acceptable_type && acceptable_encoding)
+ return 0;
+
+ if (irq) {
+ ta_list ta;
+ ta_start(ta, tag, value);
+ nta_incoming_treply(irq,
+ SIP_415_UNSUPPORTED_MEDIA,
+ SIPTAG_ACCEPT(session_accepts),
+ ta_tags(ta));
+ ta_end(ta);
+ }
+
+ return 415;
+}
+
+
+/**Check that UAC accepts one of listed MIME content-types.
+ *
+ * The list of acceptable content-types are compared with the acceptable
+ * content-types. If match is found, it is returned in @a return_acceptable.
+ * If no match is found, a 406 is returned. If @a irq is non-NULL, the 406
+ * response message is sent to the client, too.
+ *
+ * @param irq incoming transaction object (may be NULL).
+ * @param sip contents of the SIP message
+ * @param acceptable list of acceptable content types
+ * @param return_acceptable optional return-value parameter for
+ * matched content-type
+ * @param tag, value, ... optional list of tagged arguments used
+ * when responding to the transaction
+ *
+ * @return 406 if no content-type is acceptable by client, 0 if successful.
+ */
+int nta_check_accept(nta_incoming_t *irq,
+ sip_t const *sip,
+ sip_accept_t const *acceptable,
+ sip_accept_t const **return_acceptable,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ ta_list ta;
+ sip_accept_t const *ac, *ab;
+ sip_method_t method;
+
+ if (!acceptable)
+ return 0;
+
+ if (sip->sip_request)
+ method = sip->sip_request->rq_method;
+ else /* if (sip->sip_cseq) */
+ method = sip->sip_cseq->cs_method;
+
+ /* Missing Accept header implies support for SDP in INVITE and OPTIONS
+ * (and PRACK and UPDATE?)
+ */
+ if (!sip->sip_accept && (method == sip_method_invite ||
+ method == sip_method_options ||
+ method == sip_method_prack ||
+ method == sip_method_update)) {
+ for (ab = acceptable; ab; ab = ab->ac_next)
+ if (strcasecmp(application_sdp, ab->ac_type) == 0) {
+ if (return_acceptable) *return_acceptable = ab;
+ return 0;
+ }
+ }
+
+ for (ac = sip->sip_accept; ac; ac = ac->ac_next) {
+ if (sip_q_value(ac->ac_q) == 0 || !ac->ac_type)
+ continue;
+
+ for (ab = acceptable; ab; ab = ab->ac_next)
+ if (strcasecmp(ac->ac_type, ab->ac_type) == 0) {
+ if (return_acceptable) *return_acceptable = ab;
+ return 0;
+ }
+ }
+
+ if (irq) {
+ ta_start(ta, tag, value);
+ nta_incoming_treply(irq,
+ SIP_406_NOT_ACCEPTABLE,
+ SIPTAG_ACCEPT(acceptable),
+ ta_tags(ta));
+ ta_end(ta);
+ }
+
+ return 406;
+}
+
+/**Check @SessionExpires header.
+ *
+ * If the proposed session-expiration time is smaller than @MinSE or our
+ * minimal session expiration time, respond with 422 containing our minimal
+ * session expiration time in @MinSE header.
+ *
+ * @param irq incoming transaction object (may be NULL).
+ * @param sip contents of the SIP message
+ * @param my_min_se minimal session expiration time in seconds
+ * @param tag, value, ... optional list of tagged arguments used
+ * when responding to the transaction
+ *
+ * @return 422 if session expiration time is too small, 0 when successful.
+ */
+int nta_check_session_expires(nta_incoming_t *irq,
+ sip_t const *sip,
+ sip_time_t my_min_se,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ if ((sip->sip_min_se &&
+ sip->sip_session_expires->x_delta < sip->sip_min_se->min_delta)
+ || sip->sip_session_expires->x_delta < my_min_se) {
+ ta_list ta;
+
+ sip_min_se_t min_se[1];
+
+ sip_min_se_init(min_se)->min_delta = my_min_se;
+
+ if (irq) {
+ ta_start(ta, tag, value);
+ nta_incoming_treply(irq,
+ SIP_422_SESSION_TIMER_TOO_SMALL,
+ SIPTAG_MIN_SE(min_se),
+ ta_tags(ta));
+ ta_end(ta);
+ }
+
+ return 422;
+ }
+
+ return 0;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta_compat.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta_compat.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,951 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nta_compat.c
+ * @brief Compatibility functions for Nokia SIP Transaction API
+ *
+ * These functions are deprecated and should not be used anymore.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Jul 24 22:28:34 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <stdarg.h>
+#include <string.h>
+#include <assert.h>
+
+#include <sofia-sip/su_tagarg.h>
+
+#include "sofia-sip/nta.h"
+#include "nta_compat.h"
+#include "nta_internal.h"
+
+#include <sofia-sip/sip_header.h>
+#include <sofia-sip/sip_util.h>
+
+/** Set UAS flag value.
+ *
+ * The function nta_agent_set_uas() is used to set or clear User Agent
+ * Server flag.
+ *
+ * Currently, the flag determines how the agent handles 2XX replies to an
+ * incoming INVITE request. If flag is set, the agent resends the 2XX final
+ * responses to an INVITE.
+ *
+ * @deprecated Use nta_agent_set_params() and NTATAG_UA() instead.
+ */
+int nta_agent_set_uas(nta_agent_t *agent, int value)
+{
+ int retval = 1;
+
+ nta_agent_set_params(agent, NTATAG_UA(value != 0), TAG_END());
+ nta_agent_get_params(agent, NTATAG_UA_REF(retval), TAG_END());
+
+ return retval;
+}
+
+/** Set branch key.
+ *
+ * @deprecated Use nta_agent_set_params() and NTATAG_BRANCH_KEY() instead.
+ */
+msg_param_t nta_agent_set_branch(nta_agent_t *agent,
+ msg_param_t branch)
+{
+ msg_param_t retval = "";
+
+ nta_agent_set_params(agent, NTATAG_BRANCH_KEY(branch), TAG_END());
+ nta_agent_get_params(agent, NTATAG_BRANCH_KEY_REF(retval), TAG_END());
+
+ return retval;
+}
+
+/** Set default proxy.
+ *
+ * @deprecated Use nta_agent_set_params() and NTATAG_DEFAULT_PROXY() instead.
+ */
+int nta_agent_set_proxy(nta_agent_t *agent, url_string_t const *u)
+{
+ if (agent)
+ nta_agent_set_params(agent, NTATAG_DEFAULT_PROXY(u), TAG_END());
+ return 0;
+}
+
+/**Return default @b Tag.
+ *
+ * The function nta_agent_tag() returns the default @To @b tag
+ * which is used by NTA agent.
+ *
+ * @param agent NTA agent object
+ *
+ * @return The default tag used by NTA agent.
+ *
+ * @deprecated Use nta_agent_newtag() to generate a new, unique tag value.
+ *
+ * @sa NTATAG_TAG_3261().
+ */
+msg_param_t nta_agent_tag(nta_agent_t const *agent)
+{
+ return
+ (agent && agent->sa_2543_tag)
+ ? agent->sa_2543_tag + strlen("tag=")
+ : NULL;
+}
+
+/** Reply to the request message. */
+int nta_msg_reply(nta_agent_t *agent,
+ msg_t *msg,
+ int status, char const *phrase,
+ void *extra, ...)
+{
+ int retval;
+ va_list(headers);
+ va_start(headers, extra);
+ retval = nta_msg_vreply(agent, msg, status, phrase, extra, headers);
+ va_end(headers);
+ return retval;
+}
+
+/** Reply to the request message (stdarg version of nta_msg_reply()). */
+int nta_msg_vreply(nta_agent_t *agent,
+ msg_t *req_msg,
+ int status, char const *phrase,
+ void *extra, va_list headers)
+{
+ msg_t *reply = nta_msg_create(agent, 0);
+ sip_t *sip = sip_object(reply);
+
+ if (sip_add_headers(reply, sip, extra, headers) < 0)
+ sip = NULL;
+
+ return nta_msg_mreply(agent, reply, sip,
+ status, phrase, req_msg, TAG_END());
+}
+
+/** Send the message (stdarg version of nta_msg_send()). */
+int nta_msg_vsend(nta_agent_t *agent, msg_t *msg, url_string_t const *u,
+ void *extra, va_list headers)
+{
+ sip_t *sip = sip_object(msg);
+
+ if (extra && sip_add_headers(msg, sip, extra, headers) < 0) {
+ msg_destroy(msg);
+ return -1;
+ }
+
+ return nta_msg_tsend(agent, msg, u, TAG_END());
+}
+
+/** Send the message. */
+int nta_msg_send(nta_agent_t *agent, msg_t *msg, url_string_t const *u,
+ void *extra, ...)
+{
+ int retval;
+ va_list headers;
+ va_start(headers, extra);
+ retval = nta_msg_vsend(agent, msg, u, extra, headers);
+ va_end(headers);
+
+ return retval;
+}
+
+/**
+ * Create a new leg object for incoming request message.
+ *
+ * @param agent agent object
+ * @param callback function which is called for each
+ * incoming request belonging to this leg
+ * @param magic call leg context
+ * @param msg a request message
+ *
+ * @note The ownership of @a msg will pass back to NTA upon successful call
+ * to the function nta_msg_leg(). In other words, if the call to @a
+ * nta_msg_leg() is successful, the application may not do anything with @a
+ * msg anymore. Instead of that, NTA will create of a new incoming request
+ * object for the @a msg and eventually return the request to application by
+ * calling the @a callback function.
+ *
+ * @deprecated Use nta_leg_stateful() instead.
+ */
+nta_leg_t *nta_msg_leg(nta_agent_t *agent,
+ msg_t *msg,
+ nta_request_f *callback,
+ nta_leg_magic_t *magic,
+ ...)
+{
+ nta_leg_t *leg;
+ sip_t *sip = sip_object(msg);
+
+ SU_DEBUG_9(("\tnta_msg_leg(): called\n"));
+
+ assert(msg && sip && sip->sip_request);
+
+ if (!msg || !sip || !sip->sip_request || !callback)
+ return NULL;
+
+ leg = nta_leg_tcreate(agent, callback, magic,
+ SIPTAG_CALL_ID(sip->sip_call_id),
+ SIPTAG_FROM(sip->sip_to), /* local address */
+ SIPTAG_TO(sip->sip_from), /* remote address */
+ TAG_END());
+ if (!leg)
+ /* xyzzy */;
+ else if (nta_leg_server_route(leg, sip->sip_record_route,
+ sip->sip_contact) < 0)
+ nta_leg_destroy(leg), leg = NULL;
+ else if (nta_leg_stateful(leg, msg) < 0)
+ nta_leg_destroy(leg), leg = NULL;
+
+ SU_DEBUG_9(("\tnta_msg_leg(): returns %p\n", leg));
+
+ return leg;
+}
+
+static void sm_leg_recv(su_root_magic_t *rm,
+ su_msg_r msg,
+ union sm_arg_u *u);
+
+/** Process msg statefully using the leg. */
+int nta_leg_stateful(nta_leg_t *leg, msg_t *msg)
+{
+ su_msg_r su_msg = SU_MSG_RINITIALIZER;
+ nta_agent_t *agent = leg->leg_agent;
+ su_root_t *root = agent->sa_root;
+ struct leg_recv_s *a;
+
+ /* Create a su message that is passed to NTA network thread */
+ if (su_msg_create(su_msg,
+ su_root_task(root),
+ su_root_task(root),
+ sm_leg_recv, /* Function to call */
+ sizeof(struct leg_recv_s)) == SU_FAILURE)
+ return -1;
+
+ agent->sa_stats->as_trless_to_tr++;
+
+ a = su_msg_data(su_msg)->a_leg_recv;
+
+ a->leg = leg;
+ a->msg = msg;
+
+ a->tport = tport_incref(tport_delivered_by(agent->sa_tports, msg));
+
+ return su_msg_send(su_msg);
+}
+
+/** @internal Delayed leg_recv(). */
+static
+void sm_leg_recv(su_root_magic_t *rm,
+ su_msg_r msg,
+ union sm_arg_u *u)
+{
+ struct leg_recv_s *a = u->a_leg_recv;
+ leg_recv(a->leg, a->msg, sip_object(a->msg), a->tport);
+ tport_decref(&a->tport);
+}
+
+/**Create a new leg object
+ *
+ * @param agent agent object
+ * @param callback function which is called for each
+ * incoming request belonging to this leg
+ * @param magic call leg context
+ * @param i optional @CallID
+ * (if @c NULL, an ID generated by @b NTA is used)
+ * @param from optional @From (local address)
+ * @param to optional @To (remote address)
+ * @param extra, ... optional extra headers, terminated with a @c NULL
+ *
+ * @deprecated Use nta_leg_tcreate() instead.
+ */
+nta_leg_t *nta_leg_create(nta_agent_t *agent,
+ nta_request_f *callback,
+ nta_leg_magic_t *magic,
+ sip_call_id_t const *i,
+ sip_from_t const *from,
+ sip_to_t const *to,
+ void const *extra, ...)
+{
+ nta_leg_t *leg;
+ va_list headers;
+ va_start(headers, extra);
+ leg = nta_leg_vcreate(agent, callback, magic,
+ i, from, to,
+ extra, headers);
+ va_end(headers);
+ return leg;
+}
+
+/**
+ * Create a new leg object
+ *
+ * @param agent agent object
+ * @param callback function which is called for each
+ * incoming request belonging to this leg
+ * @param magic call leg context
+ * @param i optional @CallID
+ * (if @c NULL, an ID generated by @b NTA is used)
+ * @param from optional @From (local address)
+ * @param to optional @To (remote address)
+ * @param extra optional extra header
+ * @param headers va_list of optional extra headers
+ *
+ * @deprecated Use nta_leg_tcreate() instead.
+ */
+nta_leg_t *nta_leg_vcreate(nta_agent_t *agent,
+ nta_request_f *callback,
+ nta_leg_magic_t *magic,
+ sip_call_id_t const *i,
+ sip_from_t const *from,
+ sip_to_t const *to,
+ void const *extra, va_list headers)
+{
+ sip_route_t const *route = NULL;
+ sip_cseq_t const *cseq = NULL;
+
+ for (; extra ; extra = va_arg(headers, void *)) {
+ sip_header_t const *h = (sip_header_t const *)extra;
+
+ if (h == SIP_NONE)
+ continue;
+ else if (sip_call_id_p(h)) {
+ if (i == NULL) i = h->sh_call_id;
+ }
+ else if (sip_from_p(h)) {
+ if (from == NULL) from = h->sh_from;
+ }
+ else if (sip_to_p(h)) {
+ if (to == NULL) to = h->sh_to;
+ }
+ else if (sip_route_p(h)) {
+ route = h->sh_route;
+ }
+ else if (sip_cseq_p(h)) {
+ cseq = h->sh_cseq;
+ }
+ else {
+ SU_DEBUG_3(("nta_leg_create: extra header %s\n",
+ sip_header_name(h, 0)));
+ }
+ }
+
+ return nta_leg_tcreate(agent, callback, magic,
+ NTATAG_NO_DIALOG(i == SIP_NONE->sh_call_id),
+ TAG_IF(i != SIP_NONE->sh_call_id, SIPTAG_CALL_ID(i)),
+ TAG_IF(from != SIP_NONE->sh_from, SIPTAG_FROM(from)),
+ TAG_IF(to != SIP_NONE->sh_to, SIPTAG_TO(to)),
+ SIPTAG_ROUTE(route),
+ SIPTAG_CSEQ(cseq),
+ TAG_END());
+}
+
+/**Mark leg as branchable.
+ *
+ * This function does currently absolutely nothing.
+ *
+ * @param leg leg to be marked branchable.
+ *
+ * @note Currently, all legs @b are branchable.
+ *
+ * @deprecated Do not use.
+ */
+int nta_leg_branch(nta_leg_t *leg)
+{
+ return 0;
+}
+
+/** Add route from final response
+ *
+ * @deprecated Use nta_leg_client_route().
+ */
+int nta_leg_route(nta_leg_t *leg,
+ sip_record_route_t const *route,
+ sip_contact_t const *contact,
+ url_string_t const *url)
+{
+ return nta_leg_client_route(leg, route, contact);
+}
+
+#if 0
+/**Get response message.
+ *
+ * The function nta_incoming_getresponse() retrieves a copy of the latest
+ * outgoing response message. The response message is copied; the original
+ * copy is kept by the transaction.
+ *
+ * @param irq incoming (server) transaction handle
+ *
+ * @retval
+ * A pointer to the copy of the response message is returned, or NULL if an
+ * error occurred.
+ */
+msg_t *nta_incoming_getresponse(nta_incoming_t *irq)
+{
+ if (irq && irq->irq_response) {
+ msg_t *msg = nta_msg_create(irq->irq_agent, 0);
+ sip_t *sip = sip_object(msg);
+
+ msg_clone(msg, irq->irq_response);
+
+ /* Copy the SIP headers from the old message */
+ if (msg_copy_all(msg, sip, sip_object(irq->irq_response)) >= 0)
+ return msg;
+
+ msg_destroy(msg);
+ }
+
+ return NULL;
+}
+
+/**Get request message.
+ *
+ * The function nta_outgoing_getrequest() retrieves the request message sent
+ * to the network. The request message is copied; the original copy is kept
+ * by the transaction.
+ *
+ * @param orq outgoing transaction handle
+ *
+ * @retval
+ * A pointer to the copy of the request message is returned, or NULL if an
+ * error occurred.
+ */
+msg_t *nta_outgoing_getrequest(nta_outgoing_t *orq)
+{
+ if (orq && orq->orq_request) {
+ msg_t *msg = nta_msg_create(orq->orq_agent, 0);
+ sip_t *sip = sip_object(msg);
+
+ msg_clone(msg, orq->orq_request);
+
+ /* Copy the SIP headers from the old message */
+ if (sip_copy_all(msg, sip, sip_object(orq->orq_request)) >= 0)
+ return msg;
+
+ msg_destroy(msg);
+ }
+
+ return NULL;
+}
+
+/**Get latest response message.
+ *
+ * The function nta_outgoing_getresponse() retrieves the latest incoming
+ * response message to the outgoing transaction. Note that the message is
+ * not copied, but removed from the transaction.
+ *
+ * @param orq outgoing transaction handle
+ *
+ * @retval
+ * A pointer to response message is returned, or NULL if no response message
+ * has been received or the response message has already been retrieved.
+ */
+msg_t *nta_outgoing_getresponse(nta_outgoing_t *orq)
+{
+ msg_t *msg = NULL;
+
+ if (orq && orq->orq_response)
+ msg = orq->orq_response, orq->orq_response = NULL;
+
+ return msg;
+}
+#endif
+
+/** Create an outgoing request belonging to the leg.
+ *
+ * The function nta_outgoing_create() creates an outgoing transaction and
+ * sends the request. The request is sent to the @a route_url (if
+ * non-NULL), default proxy (as specified by nta_agent_set_proxy()), or to
+ * the address specified by @a request_uri. In the latest case, all the
+ * tranport parameters are stripped from the request_uri. If no @a
+ * request_uri is specified, it is taken from the @To header.
+ *
+ * When NTA receives response to the request, it invokes the @c callback
+ * function.
+ *
+ * @param leg call leg object
+ * @param callback callback function (may be @c NULL)
+ * @param magic application context pointer
+ * @param route_url URL used to route transaction requests
+ * @param method method type
+ * @param name method name
+ * @param request_uri Request-URI
+ * @param extra, ... list of extra headers
+ *
+ * @return
+ * The function nta_outgoing_create() returns a pointer to newly created
+ * outgoing transaction object if successful, and NULL otherwise.
+ *
+ * @deprecated
+ * Use nta_outgoing_tcreate() or nta_outgoing_mcreate() instead.
+ */
+nta_outgoing_t *nta_outgoing_create(nta_leg_t *leg,
+ nta_response_f *callback,
+ nta_outgoing_magic_t *magic,
+ url_string_t const *route_url,
+ sip_method_t method,
+ char const *name,
+ url_string_t const *request_uri,
+ void const *extra, ...)
+{
+ nta_outgoing_t *orq;
+ va_list headers;
+
+ va_start(headers, extra);
+ orq = nta_outgoing_vcreate(leg, callback, magic,
+ route_url, method, name, request_uri,
+ extra, headers);
+ va_end(headers);
+ return orq;
+}
+
+/**Create a request belonging to the leg
+ * (stdarg version of nta_outgoing_create()).
+ *
+ * @deprecated
+ * Use nta_outgoing_tcreate() or nta_outgoing_mcreate() instead.
+ */
+nta_outgoing_t *nta_outgoing_vcreate(nta_leg_t *leg,
+ nta_response_f *callback,
+ nta_outgoing_magic_t *magic,
+ url_string_t const *route_url,
+ sip_method_t method,
+ char const *name,
+ url_string_t const *request_uri,
+ void const *extra,
+ va_list headers)
+{
+ nta_agent_t *agent = leg->leg_agent;
+ msg_t *msg = nta_msg_create(agent, 0);
+ sip_t *sip = sip_object(msg);
+ nta_outgoing_t *orq;
+
+ if (extra &&
+ sip_add_headers(msg, sip, extra, headers) < 0)
+ orq = NULL;
+ else if (route_url && leg->leg_route && !sip->sip_route &&
+ sip_add_dup(msg, sip, (sip_header_t *)leg->leg_route) < 0)
+ orq = NULL;
+ else if (nta_msg_request_complete(msg, leg, method, name, request_uri) < 0)
+ orq = NULL;
+ else
+ orq = nta_outgoing_mcreate(agent, callback, magic, route_url, msg);
+
+ if (!orq)
+ msg_destroy(msg);
+
+ return orq;
+}
+
+/**Forward a request.
+ *
+ * @deprecated
+ * Use nta_outgoing_mcreate() instead.
+ */
+nta_outgoing_t *nta_outgoing_tclone(nta_agent_t *agent,
+ nta_response_f *callback,
+ nta_outgoing_magic_t *magic,
+ url_string_t const *route_url,
+ msg_t *parent,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ ta_list ta;
+ msg_t *msg;
+ nta_outgoing_t *orq = NULL;
+
+ if (parent == NULL)
+ return NULL;
+ if ((msg = nta_msg_create(agent, 0)) == NULL)
+ return NULL;
+
+ ta_start(ta, tag, value);
+
+ msg_clone(msg, parent);
+
+ if (parent && sip_copy_all(msg, sip_object(msg), sip_object(parent)) < 0)
+ ;
+ else if (sip_add_tl(msg, sip_object(msg), ta_tags(ta)) < 0)
+ ;
+ else
+ orq = nta_outgoing_mcreate(agent, callback, magic, route_url, msg);
+
+ ta_end(ta);
+
+ if (!orq)
+ msg_destroy(msg);
+
+ return orq;
+
+}
+
+/** Forward a request belonging to the leg.
+ *
+ * The function nta_outgoing_forward() will create an outgoing transaction
+ * based on the incoming transaction. The forwarded message is specified by
+ * @a isip parameter. The caller rewrite the URL by giving non-NULL @a
+ * request_url.
+ *
+ * The request is sent to the server specified by @a route_url if it is
+ * non-NULL.
+ *
+ * @deprecated
+ * Use nta_outgoing_mcreate() instead.
+ */
+nta_outgoing_t *nta_outgoing_forward(nta_leg_t *leg,
+ nta_response_f *callback,
+ nta_outgoing_magic_t *magic,
+ url_string_t const *route_url,
+ url_string_t const *request_uri,
+ nta_incoming_t *ireq,
+ sip_t const *isip,
+ void const *extra, ...)
+{
+ nta_outgoing_t *orq;
+ va_list headers;
+
+ va_start(headers, extra);
+ orq = nta_outgoing_vforward(leg, callback, magic, route_url, request_uri,
+ ireq, isip, extra, headers);
+ va_end(headers);
+ return orq;
+}
+
+/**Forward a request belonging to the leg
+ * (stdarg version of nta_outgoing_forward()).
+ *
+ * @deprecated
+ * Use nta_outgoing_mcreate() instead.
+ */
+nta_outgoing_t *nta_outgoing_vforward(nta_leg_t *leg,
+ nta_response_f *callback,
+ nta_outgoing_magic_t *magic,
+ url_string_t const *route_url,
+ url_string_t const *request_uri,
+ nta_incoming_t const *ireq,
+ sip_t const *isip,
+ void const *extra,
+ va_list headers)
+{
+ nta_agent_t *agent = leg->leg_agent;
+ nta_outgoing_t *orq = NULL;
+ msg_t *msg, *imsg;
+ sip_t *sip;
+ su_home_t *home;
+
+ assert(leg); assert(ireq);
+
+ if (isip == NULL)
+ imsg = ireq->irq_request, isip = sip_object(ireq->irq_request);
+ else if (isip == sip_object(ireq->irq_request))
+ imsg = ireq->irq_request;
+ else if (isip == sip_object(ireq->irq_request2))
+ imsg = ireq->irq_request2;
+ else {
+ SU_DEBUG_3(("nta_outgoing_forward: invalid arguments\n"));
+ return NULL;
+ }
+
+ assert(isip); assert(isip->sip_request);
+
+ if (!route_url)
+ route_url = (url_string_t *)agent->sa_default_proxy;
+
+ if (!(msg = nta_msg_create(agent, 0)))
+ return NULL;
+
+ msg_clone(msg, imsg);
+
+ sip = sip_object(msg);
+ home = msg_home(msg);
+
+ /* Copy the SIP headers from the @c imsg message */
+ do {
+ if (sip_copy_all(msg, sip, isip) < 0)
+ break;
+ if (sip_add_headers(msg, sip, extra, headers) < 0)
+ break;
+ if (!route_url && sip->sip_route) {
+ request_uri = (url_string_t *)sip->sip_route->r_url;
+ if (!sip_route_remove(msg, sip))
+ break;
+ }
+ if (request_uri) {
+ sip_request_t *rq;
+
+ rq = sip_request_create(home,
+ sip->sip_request->rq_method,
+ sip->sip_request->rq_method_name,
+ request_uri,
+ NULL);
+
+ if (!rq || sip_header_insert(msg, sip, (sip_header_t *)rq) < 0)
+ break;
+ }
+
+ if ((orq = nta_outgoing_mcreate(agent, callback, magic, route_url, msg)))
+ return orq;
+
+ } while (0);
+
+ msg_destroy(msg);
+ return NULL;
+}
+
+
+/** Fork an outgoing request toward another destination.
+ *
+ * @deprecated
+ * Use nta_outgoing_mcreate() instead.
+ */
+nta_outgoing_t *nta_outgoing_fork(nta_outgoing_t *old_orq,
+ nta_response_f *callback,
+ nta_outgoing_magic_t *magic,
+ url_string_t const *route_url,
+ url_string_t const *request_uri,
+ void const *extra, ...)
+{
+ nta_outgoing_t *orq;
+ va_list headers;
+
+ va_start(headers, extra);
+ orq = nta_outgoing_vfork(old_orq, callback, magic, route_url,
+ request_uri, extra, headers);
+ va_end(headers);
+ return orq;
+}
+
+/** Fork an outgoing request (stdarg version of nta_outgoing_fork()).
+ *
+ * @deprecated
+ * Use nta_outgoing_mcreate() instead.
+ */
+nta_outgoing_t *nta_outgoing_vfork(nta_outgoing_t *old_orq,
+ nta_response_f *callback,
+ nta_outgoing_magic_t *magic,
+ url_string_t const *route_url,
+ url_string_t const *request_uri,
+ void const *extra,
+ va_list headers)
+{
+ nta_outgoing_t * orq;
+ msg_t *msg, *imsg;
+ sip_t *sip, *isip;
+ nta_agent_t *agent;
+ su_home_t *home;
+
+ if (!old_orq || !old_orq->orq_request || !request_uri)
+ return NULL;
+
+ agent = old_orq->orq_agent;
+ imsg = old_orq->orq_request;
+
+ if (!(msg = nta_msg_create(agent, 0)))
+ return NULL;
+
+ msg_clone(msg, imsg);
+
+ sip = sip_object(msg); isip = sip_object(imsg);
+ home = msg_home(msg);
+
+ /* Copy the SIP headers from the imsg message */
+ if (sip_copy_all(msg, sip, isip) < 0)
+ orq = NULL;
+ else if (sip_via_remove(msg, sip) == NULL)
+ orq = NULL;
+ else if (sip_add_dup(msg, sip_object(msg),
+ (sip_header_t const *)
+ sip_request_create(home,
+ sip->sip_request->rq_method,
+ sip->sip_request->rq_method_name,
+ request_uri,
+ NULL)) < 0)
+ orq = NULL;
+ else if (sip_add_headers(msg, sip, extra, headers) < 0)
+ orq = NULL;
+ else
+ orq = nta_outgoing_mcreate(agent, callback, magic, route_url, msg);
+
+ if (!orq)
+ msg_destroy(msg);
+
+ return orq;
+}
+
+/**
+ * Reply to an incoming transaction request.
+ *
+ * This function creates and sends a response message to an incoming request.
+ * It is possible to send several non-final (1xx) responses, but only one
+ * final response.
+ *
+ * @param irq incoming request
+ * @param status status code
+ * @param phrase status phrase (may be NULL if status code is well-known)
+ * @param extra, ... optional additional headers terminated by NULL
+ *
+ * @deprecated
+ * Use nta_incoming_treply() instead.
+ */
+int nta_incoming_reply(nta_incoming_t *irq,
+ int status,
+ char const *phrase,
+ void const *extra,
+ ...)
+{
+ int retval;
+ va_list headers;
+ va_start(headers, extra);
+ retval = nta_incoming_vreply(irq, status, phrase, extra, headers);
+ va_end(headers);
+ return retval;
+}
+
+/**Reply to an incoming transaction request (stdarg version).
+ *
+ * @deprecated
+ * Use nta_incoming_treply() instead.
+ */
+int nta_incoming_vreply(nta_incoming_t *irq,
+ int status,
+ char const *phrase,
+ void const *extra, va_list headers)
+{
+ if (irq->irq_status < 200 || status < 200 ||
+ (irq->irq_method == sip_method_invite && status < 300)) {
+ msg_t *msg = nta_msg_create(irq->irq_agent, 0);
+ sip_t *sip = sip_object(msg);
+
+ if (!msg)
+ return -1;
+ else if (nta_msg_response_complete(msg, irq, status, phrase) < 0)
+ msg_destroy(msg);
+ else if (sip_add_headers(msg, sip, extra, headers) < 0 )
+ msg_destroy(msg);
+ else if (sip_message_complete(msg) < 0)
+ msg_destroy(msg);
+ else if (nta_incoming_mreply(irq, msg) < 0)
+ msg_destroy(msg);
+ else
+ return 0;
+ }
+
+ return -1;
+}
+
+
+/**
+ * Forward a response to incoming transaction.
+ *
+ * This function forwards a response message from outgoing request to an
+ * incoming request. It copies the message save the first via field, and
+ * send the response message to the address specified in the second via.
+ *
+ * It is possible to send several non-final (1xx) responses, but only one
+ * final response.
+ *
+ * @param irq incoming request
+ * @param orq
+ * @param sip message structure for outgoing transaction
+ * @param extra, ... list of optional additional headers terminated by NULL
+ *
+ * @bug Adding extra headers is unimplemented.
+ *
+ * @deprecated Use nta_incoming_mreply() instead.
+ */
+int nta_incoming_forward(nta_incoming_t *irq,
+ nta_outgoing_t *orq,
+ sip_t const *sip,
+ void const *extra, ...)
+{
+ msg_t *msg = nta_outgoing_response(orq);
+ int status;
+
+ if (irq == NULL || sip == NULL || msg == NULL || sip != sip_object(msg))
+ return -1;
+
+ status = sip->sip_status->st_status;
+
+ sip_via_remove(msg, (sip_t *)sip); /* Remove topmost via */
+
+ if (sip_message_complete(msg) < 0)
+ msg_destroy(msg);
+ if (nta_incoming_mreply(irq, msg) < 0)
+ msg_destroy(msg);
+ else
+ return 0;
+
+ return -1;
+}
+
+/** Send a BYE to an INVITE.
+ *
+ * @deprecated
+ * This function should used only if application requires
+ * RFC2543 compatibility.
+ */
+nta_outgoing_t *nta_outgoing_tbye(nta_outgoing_t *orq,
+ nta_response_f *callback,
+ nta_outgoing_magic_t *magic,
+ url_string_t const *route_url,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ msg_t *msg;
+ sip_t *sip, *inv;
+ sip_cseq_t *cs;
+ sip_request_t *rq;
+ su_home_t *home;
+ url_string_t *url;
+
+ if (orq == NULL || orq->orq_method != sip_method_invite)
+ return NULL;
+
+ inv = sip_object(orq->orq_request);
+ msg = nta_msg_create(orq->orq_agent, 0);
+ home = msg_home(msg);
+ sip = sip_object(msg);
+
+ if (inv == NULL || sip == NULL) {
+ msg_destroy(msg);
+ return NULL;
+ }
+
+ sip_add_tl(msg, sip,
+ SIPTAG_TO(inv->sip_to),
+ SIPTAG_FROM(inv->sip_from),
+ SIPTAG_CALL_ID(inv->sip_call_id),
+ SIPTAG_ROUTE(inv->sip_route),
+ TAG_END());
+
+ url = (url_string_t *)inv->sip_request->rq_url;
+
+ rq = sip_request_create(home, SIP_METHOD_BYE, url, NULL);
+ sip_header_insert(msg, sip, (sip_header_t*)rq);
+
+ cs = sip_cseq_create(home, inv->sip_cseq->cs_seq + 1, SIP_METHOD_BYE);
+ sip_header_insert(msg, sip, (sip_header_t*)cs);
+
+ return nta_outgoing_mcreate(orq->orq_agent, callback, magic,
+ route_url, msg);
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta_compat.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta_compat.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,214 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef NTA_COMPAT_H
+/** Defined when <nta_compat.h> has been included. */
+#define NTA_COMPAT_H;
+
+/**@file nta_compat.h
+ * @brief Deprecated NTA functions and types.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Sep 4 15:54:57 2001 ppessi
+ */
+
+#ifndef NTA_H
+#include <sofia-sip/nta.h>
+#endif
+
+typedef msg_t nta_msg_t;
+
+sip_param_t nta_agent_set_branch(nta_agent_t *agent, sip_param_t branch);
+
+sip_param_t nta_agent_tag(nta_agent_t const *a);
+
+int nta_agent_set_uas(nta_agent_t *agent, int value);
+
+int nta_agent_set_proxy(nta_agent_t *agent, url_string_t const *u);
+
+int nta_msg_send(nta_agent_t *agent, msg_t *msg,
+ url_string_t const *route_url,
+ void *extra, ...);
+
+int nta_msg_reply(nta_agent_t *self,
+ msg_t *request_msg,
+ int status, char const *phrase,
+ void *extra, ...);
+
+nta_leg_t *nta_msg_leg(nta_agent_t *agent,
+ msg_t *msg,
+ nta_request_f *req_callback,
+ nta_leg_magic_t *magic, ...);
+
+nta_leg_t *nta_leg_create(nta_agent_t *agent,
+ nta_request_f *req_callback,
+ nta_leg_magic_t *magic,
+ sip_call_id_t const *i,
+ sip_from_t const *from,
+ sip_to_t const *to,
+ void const *extra, ...);
+
+int nta_leg_branch(nta_leg_t *leg);
+
+int nta_leg_route(nta_leg_t *, sip_record_route_t const *,
+ sip_contact_t const *, url_string_t const *);
+
+int nta_incoming_reply(nta_incoming_t *irq,
+ int status, char const *phrase,
+ void const *extra, ...);
+
+int nta_incoming_forward(nta_incoming_t *ireq,
+ nta_outgoing_t *request,
+ sip_t const *sip,
+ void const *extra, ...);
+
+int nta_incoming_tforward(nta_incoming_t *ireq,
+ nta_outgoing_t *request,
+ sip_t const *sip,
+ tag_type_t tag, tag_value_t value, ...);
+
+nta_outgoing_t *nta_outgoing_create(nta_leg_t *leg,
+ nta_response_f *callback,
+ nta_outgoing_magic_t *magic,
+ url_string_t const *route_url,
+ sip_method_t method,
+ char const *method_name,
+ url_string_t const *req_url,
+ void const *extra_headers, ...);
+
+/** Create a new outgoing request with old contents, but new url */
+nta_outgoing_t *nta_outgoing_fork(nta_outgoing_t *,
+ nta_response_f *callback,
+ nta_outgoing_magic_t *magic,
+ url_string_t const *route_url,
+ url_string_t const *request_url,
+ void const *extra, ...);
+
+nta_outgoing_t *nta_outgoing_forward(nta_leg_t *leg,
+ nta_response_f *callback,
+ nta_outgoing_magic_t *magic,
+ url_string_t const *route_url,
+ url_string_t const *request_url,
+ nta_incoming_t *ireq,
+ sip_t const *sip,
+ void const *extra, ...);
+
+nta_outgoing_t *nta_outgoing_tclone(nta_agent_t *agent,
+ nta_response_f *callback,
+ nta_outgoing_magic_t *magic,
+ url_string_t const *route_url,
+ msg_t *parent,
+ tag_type_t tag, tag_value_t value, ...);
+
+nta_outgoing_t *nta_outgoing_tbye(nta_outgoing_t *orq,
+ nta_response_f *callback,
+ nta_outgoing_magic_t *magic,
+ url_string_t const *route_url,
+ tag_type_t tag, tag_value_t value, ...);
+
+/** Process message statefully using @a leg. */
+int nta_leg_stateful(nta_leg_t *leg, msg_t *msg);
+
+typedef nta_ack_cancel_f nta_incoming_f;
+
+#define nta_incoming_request nta_incoming_getrequest
+#define nta_outgoing_response nta_outgoing_getresponse
+
+#define nta_get_params nta_agent_get_params
+#define nta_set_params nta_agent_set_params
+
+int nta_msg_vsend(nta_agent_t *agent, msg_t *msg, url_string_t const *u,
+ void *extra, va_list headers);
+
+int nta_msg_vreply(nta_agent_t *self,
+ msg_t *msg,
+ int status, char const *phrase,
+ void *extra, va_list headers);
+
+nta_leg_t *nta_leg_vcreate(nta_agent_t *agent,
+ nta_request_f *req_callback,
+ nta_leg_magic_t *magic,
+ sip_call_id_t const *i,
+ sip_from_t const *from,
+ sip_to_t const *to,
+ void const *extra, va_list header);
+
+int nta_incoming_vreply(nta_incoming_t *irq,
+ int status, char const *phrase,
+ void const *extra, va_list header);
+
+int nta_incoming_vforward(nta_incoming_t *ireq,
+ nta_outgoing_t *request,
+ sip_t const *sip,
+ void const *extra, va_list header);
+
+nta_outgoing_t *nta_outgoing_vcreate(nta_leg_t *leg,
+ nta_response_f *callback,
+ nta_outgoing_magic_t *magic,
+ url_string_t const *route_url,
+ sip_method_t method,
+ char const *method_name,
+ url_string_t const *request_uri,
+ void const *extra,
+ va_list headers);
+
+nta_outgoing_t *nta_outgoing_vforward(nta_leg_t *leg,
+ nta_response_f *callback,
+ nta_outgoing_magic_t *magic,
+ url_string_t const *route_url,
+ url_string_t const *request_url,
+ nta_incoming_t const *ireq,
+ sip_t const *isip,
+ void const *extra,
+ va_list headers);
+nta_outgoing_t *nta_outgoing_vfork(nta_outgoing_t *old_orq,
+ nta_response_f *callback,
+ nta_outgoing_magic_t *magic,
+ url_string_t const *route_url,
+ url_string_t const *request_url,
+ void const *extra, va_list headers);
+
+enum {
+ NTA_RETRY_TIMER_INI = NTA_SIP_T1,
+ NTA_RETRY_TIMER_MAX = NTA_SIP_T2,
+ NTA_LINGER_TIMER = NTA_SIP_T4,
+ NTA_RETRY_COUNT = 11,
+ NTA_INVITE_COUNT = 7,
+};
+
+#define NTATAG_RETRY_TIMER_INI NTATAG_SIP_T1
+#define NTATAG_RETRY_TIMER_INI_REF NTATAG_SIP_T1_REF
+#define NTATAG_RETRY_TIMER_MAX NTATAG_SIP_T2
+#define NTATAG_RETRY_TIMER_MAX_REF NTATAG_SIP_T2_REF
+#define NTATAG_LINGER_TIMER NTATAG_SIP_T4
+#define NTATAG_LINGER_TIMER_REF NTATAG_SIP_T4_REF
+
+#define NTATAG_RETRY_COUNT(x) tag_skip, (tag_value_t)0
+#define NTATAG_RETRY_COUNT_REF(x) tag_skip, (tag_value_t)0
+
+#define NTATAG_INVITE_COUNT(x) tag_skip, (tag_value_t)0
+#define NTATAG_INVITE_COUNT_REF(x) tag_skip, (tag_value_t)0
+
+#endif /* !defined(NTA_COMPAT_H) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta_internal.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta_internal.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,587 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef NTA_INTERNAL_H
+/** Defined when <nta_internal.h> has been included. */
+#define NTA_INTERNAL_H
+
+/**@IFILE nta_internal.h
+ * @brief Internals of NTA objects.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Jul 18 09:18:32 2000 ppessi
+ */
+
+/* Resolver context type */
+#define SRES_CONTEXT_T nta_outgoing_t
+
+/* We are customer of tport_t */
+#define TP_AGENT_T nta_agent_t
+#define TP_MAGIC_T sip_via_t
+#define TP_CLIENT_T nta_outgoing_t
+
+#include <sofia-sip/nta.h>
+#include <sofia-sip/nta_tport.h>
+#include <sofia-sip/tport.h>
+
+#if HAVE_SOFIA_SRESOLV
+#include <sofia-sip/sresolv.h>
+#endif
+
+#include <sofia-sip/htable.h>
+
+#if HAVE_SMIME
+#include "smimec.h"
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** A sip_flag telling that this message is internally generated. */
+#define NTA_INTERNAL_MSG (1<<15)
+
+/** Resolving order */
+enum nta_res_order_e
+{
+ nta_res_ip6_ip4,
+ nta_res_ip4_ip6,
+ nta_res_ip6_only,
+ nta_res_ip4_only
+};
+
+HTABLE_DECLARE_WITH(leg_htable, lht, nta_leg_t, size_t, hash_value_t);
+HTABLE_DECLARE_WITH(outgoing_htable, oht, nta_outgoing_t, size_t, hash_value_t);
+HTABLE_DECLARE_WITH(incoming_htable, iht, nta_incoming_t, size_t, hash_value_t);
+
+typedef struct outgoing_queue_t {
+ nta_outgoing_t **q_tail;
+ nta_outgoing_t *q_head;
+ size_t q_length;
+ unsigned q_timeout;
+} outgoing_queue_t;
+
+typedef struct incoming_queue_t {
+ nta_incoming_t **q_tail;
+ nta_incoming_t *q_head;
+ size_t q_length;
+ unsigned q_timeout;
+} incoming_queue_t;
+
+typedef struct nta_compressor nta_compressor_t;
+
+struct nta_agent_s
+{
+ su_home_t sa_home[1];
+ su_root_t *sa_root;
+ su_timer_t *sa_timer;
+ nta_agent_magic_t *sa_magic;
+ nta_message_f *sa_callback;
+
+ uint32_t sa_nw_updates; /* Shall we enable network detector? */
+
+ nta_update_magic_t *sa_update_magic;
+ nta_update_tport_f *sa_update_tport;
+
+ su_time_t sa_now; /**< Timestamp in microsecond resolution. */
+ uint32_t sa_millisec; /**< Timestamp in milliseconds resolution. */
+
+ uint32_t sa_flags; /**< Message flags */
+ msg_mclass_t *sa_mclass;
+
+ sip_contact_t *sa_contact;
+ sip_via_t *sa_vias; /**< @Via headers for all transports */
+ sip_via_t *sa_public_vias; /**< @Vias for public transports */
+ sip_contact_t *sa_aliases;/**< List of aliases for agent */
+
+ uint64_t sa_branch; /**< Counter for generating branch parameter */
+ uint64_t sa_tags; /**< Counter for generating tag parameters */
+
+ char const *sa_2543_tag; /**< Fixed tag added to @To when responding */
+
+#if HAVE_SOFIA_SRESOLV
+ sres_resolver_t *sa_resolver; /**< DNS resolver */
+#endif
+
+ tport_t *sa_tports;
+
+ /* Default outbound proxy */
+ url_t *sa_default_proxy;
+
+#if HAVE_SMIME
+ sm_object_t *sa_smime;
+#else
+ void *sa_smime;
+#endif
+
+
+ /** Request error mask */
+ unsigned sa_bad_req_mask;
+ /** Response error mask */
+ unsigned sa_bad_resp_mask;
+
+ /** Maximum size of incoming messages */
+ size_t sa_maxsize;
+
+ /** Maximum size of outgoing UDP requests */
+ size_t sa_udp_mtu;
+
+ /** SIP T1 - initial interval of retransmissions (500 ms) */
+ unsigned sa_t1;
+ /** SIP T2 - maximum interval of retransmissions (4000 ms) */
+ unsigned sa_t2;
+ /** SIP T4 - clear message time (5000 ms) */
+ unsigned sa_t4;
+
+ /** SIP T1X64 - transaction lifetime (32 s) */
+ unsigned sa_t1x64;
+
+ /** Progress timer - interval between provisional responses sent */
+ unsigned sa_progress;
+
+ /** Blacklisting period */
+ unsigned sa_blacklist;
+
+ /** NTA is used to test packet drop */
+ unsigned sa_drop_prob : 10;
+ /** NTA is acting as an User Agent server */
+ unsigned sa_is_a_uas : 1;
+ /** Process requests outside dialog statelessly */
+ unsigned sa_is_stateless : 1;
+ /** Let application provide @Via headers */
+ unsigned sa_user_via:1;
+ /** Respond with "100 Trying" if application has not responded. */
+ unsigned sa_extra_100:1;
+ /** The "100 Trying" provisional answers are passed to the application */
+ unsigned sa_pass_100:1;
+ /** If true, a "408 Request Timeout" message is generated when outgoing
+ request expires. */
+ unsigned sa_timeout_408:1;
+ /** If true, a "408 Request Timeout" responses are passed to client. */
+ unsigned sa_pass_408:1;
+ /** If true, a "482 Request Merged" response is sent to merged requests. */
+ unsigned sa_merge_482 : 1;
+ /** If true, send a CANCEL to an INVITE without an provisional response. */
+ unsigned sa_cancel_2543 : 1;
+ /** If true, reply with 487 response when a CANCEL is received. */
+ unsigned sa_cancel_487 : 1;
+ /** If true, use unique tags. */
+ unsigned sa_tag_3261 : 1;
+ /** If true, include 100rel in INVITE requests. */
+ unsigned sa_invite_100rel : 1;
+ /** If true, insert @Timestamp in requests. */
+ unsigned sa_timestamp : 1;
+
+ /** If true, transports support IPv4. */
+ unsigned sa_tport_ip4 : 1;
+ /** If true, transports support IPv6. */
+ unsigned sa_tport_ip6 : 1;
+ /** If true, transports support UDP. */
+ unsigned sa_tport_udp : 1;
+ /** If true, transports support TCP. */
+ unsigned sa_tport_tcp : 1;
+ /** If true, transports support SCTP. */
+ unsigned sa_tport_sctp : 1;
+ /** If true, transports support TLS. */
+ unsigned sa_tport_tls : 1;
+
+ /** If true, use NAPTR lookup */
+ unsigned sa_use_naptr : 1;
+ /** If true, use SRV lookup */
+ unsigned sa_use_srv : 1;
+
+ /** If true, transports use threadpool */
+ unsigned sa_tport_threadpool : 1;
+
+ /** If true, use rport at client */
+ unsigned sa_rport:1;
+ /** If true, use rport at server */
+ unsigned sa_server_rport:1;
+ /** If true, use rport with tcp, too */
+ unsigned sa_tcp_rport:1;
+
+ /** If true, automatically create compartments */
+ unsigned sa_auto_comp:1;
+
+ unsigned :0;
+
+ /** Messages memory preload. */
+ unsigned sa_preload;
+
+ /** Name of SigComp algorithm */
+ char const *sa_algorithm;
+ /** Options for SigComp. */
+ char const *sa_sigcomp_options;
+ char const* const *sa_sigcomp_option_list;
+ char const *sa_sigcomp_option_free;
+
+ nta_compressor_t *sa_compressor;
+
+ /** Resolving order (AAAA/A) */
+ enum nta_res_order_e sa_res_order;
+
+ /** @MaxForwards */
+
+ sip_max_forwards_t sa_max_forwards[1];
+
+ /* Statistics */
+ struct {
+ uint32_t as_recv_msg;
+ uint32_t as_recv_request;
+ uint32_t as_recv_response;
+ uint32_t as_bad_message;
+ uint32_t as_bad_request;
+ uint32_t as_bad_response;
+ uint32_t as_drop_request;
+ uint32_t as_drop_response;
+ uint32_t as_client_tr;
+ uint32_t as_server_tr;
+ uint32_t as_dialog_tr;
+ uint32_t as_acked_tr;
+ uint32_t as_canceled_tr;
+ uint32_t as_trless_request;
+ uint32_t as_trless_to_tr;
+ uint32_t as_trless_response;
+ uint32_t as_trless_200;
+ uint32_t as_merged_request;
+ uint32_t as_sent_msg;
+ uint32_t as_sent_request;
+ uint32_t as_sent_response;
+ uint32_t as_retry_request;
+ uint32_t as_retry_response;
+ uint32_t as_recv_retry;
+ uint32_t as_tout_request;
+ uint32_t as_tout_response;
+ } sa_stats[1];
+
+ /** Hash of dialogs. */
+ leg_htable_t sa_dialogs[1];
+ /** Default leg */
+ nta_leg_t *sa_default_leg;
+ /** Hash of legs without dialogs. */
+ leg_htable_t sa_defaults[1];
+ /** Hash table for outgoing transactions */
+ outgoing_htable_t sa_outgoing[1];
+ nta_outgoing_t *sa_default_outgoing;
+ /** Hash table for incoming transactions */
+ incoming_htable_t sa_incoming[1];
+ nta_incoming_t *sa_default_incoming;
+
+ /* Queues (states) for outgoing client transactions */
+ struct {
+ /** Queue for retrying client transactions */
+ nta_outgoing_t *re_list;
+ nta_outgoing_t **re_t1; /**< Special place for T1 timer */
+ size_t re_length; /**< Length of sa_out.re_list */
+
+ outgoing_queue_t delayed[1];
+ outgoing_queue_t resolving[1];
+
+ outgoing_queue_t trying[1]; /* Timer F/E */
+ outgoing_queue_t completed[1]; /* Timer K */
+ outgoing_queue_t terminated[1];
+
+ /* Special queues (states) for outgoing INVITE transactions */
+ outgoing_queue_t inv_calling[1]; /* Timer B/A */
+ outgoing_queue_t inv_proceeding[1];
+ outgoing_queue_t inv_completed[1]; /* Timer D */
+
+ /* Temporary queue for transactions waiting to be freed */
+ outgoing_queue_t *free;
+ } sa_out;
+
+ /* Queues (states) for incoming server transactions */
+ struct {
+ /** Queue for retransmitting response of server transactions */
+ nta_incoming_t *re_list;
+ nta_incoming_t **re_t1; /**< Special place for T1 timer */
+ size_t re_length;
+
+ incoming_queue_t proceeding[1]; /**< Request received */
+ incoming_queue_t preliminary[1]; /**< 100rel sent */
+ incoming_queue_t completed[1]; /**< Final answer sent (non-invite). */
+ incoming_queue_t inv_completed[1]; /**< Final answer sent (INVITE). */
+ incoming_queue_t inv_confirmed[1]; /**< Final answer sent, ACK recvd. */
+ incoming_queue_t terminated[1]; /**< Terminated, ready to free. */
+ incoming_queue_t final_failed[1];
+ } sa_in;
+
+ /* Special task for freeing memory */
+ su_clone_r sa_terminator;
+};
+
+struct nta_leg_s
+{
+ su_home_t leg_home[1];
+ hash_value_t leg_hash;
+ unsigned leg_dialog : 1;
+ unsigned leg_stateless : 1; /**< Process requests statelessly */
+#ifdef NTA_STRICT_ROUTING
+ unsigned leg_contact_set : 1;
+#else
+ unsigned leg_loose_route : 1; /**< Topmost route in set is LR */
+#endif
+ unsigned leg_local_is_to : 1; /**< Backwards-compatibility. */
+ unsigned:0;
+ nta_request_f *leg_callback;
+ nta_leg_magic_t *leg_magic;
+ nta_agent_t *leg_agent;
+ /** Leg URL.
+ *
+ * This is the URL used to match incoming requests.
+ */
+ url_t const *leg_url;
+ char const *leg_method; /**< Method for this dialog. */
+
+ uint32_t leg_seq; /**< Sequence number for next transaction */
+ uint32_t leg_rseq; /**< Remote sequence number */
+ sip_call_id_t *leg_id; /**< Call ID */
+ sip_from_t *leg_remote; /**< Remote address (@To/@From) */
+ sip_to_t *leg_local; /**< Local address (@From/@To) */
+
+ sip_route_t *leg_route; /**< @Route for outgoing requests. */
+ sip_contact_t *leg_target; /**< Remote destination (from @Contact). */
+};
+
+#define leg_has_id(leg) ((leg)->leg_id != NULL)
+
+struct nta_incoming_s
+{
+ su_home_t *irq_home;
+ hash_value_t irq_hash;
+ nta_agent_t *irq_agent;
+ nta_ack_cancel_f *irq_callback;
+ nta_incoming_magic_t *irq_magic;
+
+ /* Timeout/state queue */
+ nta_incoming_t **irq_prev;
+ nta_incoming_t *irq_next;
+ incoming_queue_t *irq_queue;
+
+ /* Retry queue */
+ nta_incoming_t **irq_rprev;
+ nta_incoming_t *irq_rnext;
+
+ sip_method_t irq_method;
+ sip_request_t *irq_rq;
+ sip_from_t *irq_from;
+ sip_to_t *irq_to;
+ char const *irq_tag;
+ sip_cseq_t *irq_cseq;
+ sip_call_id_t *irq_call_id;
+ sip_via_t *irq_via;
+ sip_record_route_t *irq_record_route;
+ char const *irq_branch;
+
+ uint32_t irq_rseq;
+
+ sip_timestamp_t *irq_timestamp;
+ su_time_t irq_received;
+
+ su_duration_t irq_timeout; /**< Timer H, I, J */
+ su_duration_t irq_retry; /**< Timer G */
+ unsigned short irq_interval; /**< Next timer */
+
+ short irq_status;
+
+ unsigned irq_retries : 8;
+ unsigned irq_default : 1; /**< Default transaction */
+ unsigned irq_canceled : 1; /**< Transaction is canceled */
+ unsigned irq_completed : 1; /**< Transaction is completed */
+ unsigned irq_confirmed : 1; /**< Response has been acked */
+ unsigned irq_terminated :1; /**< Transaction is terminated */
+ unsigned irq_final_failed:1; /**< Sending final response failed */
+ unsigned irq_destroyed :1; /**< Transaction is destroyed */
+ unsigned irq_in_callback:1; /**< Callback is being invoked */
+ unsigned irq_reliable_tp:1; /**< Transport is reliable */
+ unsigned irq_sigcomp_zap:1; /**< Reset SigComp */
+ unsigned irq_must_100rel:1; /**< 100rel is required */
+ unsigned irq_tag_set:1; /**< Tag is not from request */
+ unsigned :0;
+
+ tp_name_t irq_tpn[1];
+ tport_t *irq_tport;
+ struct sigcomp_compartment *irq_cc;
+ msg_t *irq_request;
+ msg_t *irq_request2; /**< ACK/CANCEL */
+ msg_t *irq_response;
+
+ nta_reliable_t *irq_reliable; /**< List of reliable responses */
+};
+
+struct nta_reliable_s
+{
+ nta_reliable_t *rel_next;
+ nta_incoming_t *rel_irq;
+ nta_prack_f *rel_callback;
+ nta_reliable_magic_t *rel_magic;
+ uint32_t rel_rseq;
+ unsigned short rel_status;
+ unsigned rel_pracked : 1;
+ unsigned rel_precious : 1;
+ msg_t *rel_response;
+ msg_t *rel_unsent;
+};
+
+typedef struct sipdns_resolver sipdns_resolver_t;
+
+struct nta_outgoing_s
+{
+ hash_value_t orq_hash; /**< Hash value */
+ nta_agent_t *orq_agent;
+ nta_response_f *orq_callback;
+ nta_outgoing_magic_t *orq_magic;
+
+ /* Timeout/state queue */
+ nta_outgoing_t **orq_prev;
+ nta_outgoing_t *orq_next;
+ outgoing_queue_t *orq_queue;
+
+ /* Retry queue */
+ nta_outgoing_t **orq_rprev;
+ nta_outgoing_t *orq_rnext;
+
+ sip_method_t orq_method;
+ char const *orq_method_name;
+ sip_from_t const *orq_from;
+ sip_to_t const *orq_to;
+ sip_cseq_t const *orq_cseq;
+ sip_call_id_t const *orq_call_id;
+
+ char const *orq_tag; /**< Tag from final response. */
+
+ su_time_t orq_sent; /**< When request was sent? */
+ unsigned orq_delay; /**< RTT estimate */
+
+ su_duration_t orq_retry; /**< Timer A, E */
+ su_duration_t orq_timeout; /**< Timer B, D, F, K */
+
+ unsigned short orq_interval; /**< Next timer A/E */
+
+ unsigned short orq_status;
+ unsigned char orq_retries; /**< Number of tries this far */
+ unsigned orq_default : 1; /**< This is default transaction */
+ unsigned orq_inserted : 1;
+ unsigned orq_resolved : 1;
+ unsigned orq_prepared : 1; /**< outgoing_prepare() called */
+ unsigned orq_canceled : 1;
+ unsigned orq_terminated : 1;
+ unsigned orq_destroyed : 1;
+ unsigned orq_completed : 1;
+ unsigned orq_delayed : 1;
+ unsigned orq_stripped_uri : 1;
+ unsigned orq_try_tcp_instead : 1;
+ unsigned orq_try_udp_instead : 1;
+ unsigned orq_reliable : 1; /**< Transport is reliable */
+ unsigned orq_ack_error : 1; /**< ACK is sent by NTA */
+ /* Attributes */
+ unsigned orq_user_via : 1;
+ unsigned orq_stateless : 1;
+ unsigned orq_pass_100 : 1;
+ unsigned orq_sigcomp_new:1; /**< Create compartment if needed */
+ unsigned orq_sigcomp_zap:1; /**< Reset SigComp after completing */
+ unsigned orq_must_100rel : 1;
+ unsigned orq_timestamp : 1; /**< insert @Timestamp header. */
+ unsigned : 0; /* pad */
+
+ uint32_t orq_rseq; /**< Latest incoming rseq */
+
+#if HAVE_SOFIA_SRESOLV
+ sipdns_resolver_t *orq_resolver;
+#endif
+ enum nta_res_order_e orq_res_order; /**< AAAA/A first? */
+
+ url_t *orq_route; /**< Route URL */
+ tp_name_t orq_tpn[1]; /**< Where to send request */
+ char const *orq_scheme; /**< Transport URL type */
+
+ tport_t *orq_tport;
+ struct sigcomp_compartment *orq_cc;
+ tagi_t *orq_tags; /**< Tport tag items */
+ int orq_pending; /**< Request is pending in tport */
+
+ char const *orq_branch; /**< Transaction branch */
+ char const *orq_via_branch; /**< @Via branch */
+ url_t const *orq_url; /**< Original RequestURI */
+
+ msg_t *orq_request;
+ msg_t *orq_response;
+
+ nta_outgoing_t *orq_cancel; /**< CANCEL transaction */
+};
+
+/* Virtual function table for plugging in SigComp */
+typedef struct
+{
+ int ncv_size;
+ char const *ncv_name;
+
+ nta_compressor_t *(*ncv_init_agent)(nta_agent_t *sa,
+ char const * const *options);
+
+ void (*ncv_deinit_agent)(nta_agent_t *sa, nta_compressor_t *);
+
+ struct sigcomp_compartment *(*ncv_compartment)(nta_agent_t *sa,
+ tport_t *tport,
+ nta_compressor_t *msc,
+ tp_name_t const *tpn,
+ char const * const *options,
+ int new_if_needed);
+
+ int (*ncv_accept_compressed)(nta_agent_t *sa,
+ nta_compressor_t *msc,
+ tport_compressor_t *sc,
+ msg_t *msg,
+ struct sigcomp_compartment *cc);
+
+ int (*ncv_close_compressor)(nta_agent_t *sa,
+ struct sigcomp_compartment *cc);
+ int (*ncv_zap_compressor)(nta_agent_t *sa,
+ struct sigcomp_compartment *cc);
+
+ struct sigcomp_compartment *(*ncv_compartment_ref)
+ (struct sigcomp_compartment *);
+
+ void (*ncv_compartment_unref)(struct sigcomp_compartment *);
+
+} nta_compressor_vtable_t;
+
+extern nta_compressor_vtable_t *nta_compressor_vtable;
+
+SOFIAPUBFUN nta_compressor_t *nta_agent_init_sigcomp(nta_agent_t *sa);
+SOFIAPUBFUN void nta_agent_deinit_sigcomp(nta_agent_t *sa);
+
+/* ====================================================================== */
+/* Debug log settings */
+
+#define SU_LOG nta_log
+
+#ifdef SU_DEBUG_H
+#error <su_debug.h> included directly.
+#endif
+#include <sofia-sip/su_debug.h>
+SOFIAPUBVAR su_log_t nta_log[];
+
+SOFIA_END_DECLS
+
+#endif /* NTA_INTERNAL_H */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta_tag.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta_tag.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,148 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nta_tag.c
+ * @brief Tags for Nokia SIP Transaction API
+ *
+ * @note This file is used to automatically generate
+ * nta_tag_ref.c and nta_tag_dll.c
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Jul 24 22:28:34 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <assert.h>
+
+#define TAG_NAMESPACE "nta"
+
+#include "sofia-sip/nta_tag.h"
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/sip_tag_class.h>
+#include <sofia-sip/url_tag_class.h>
+
+#include <sofia-sip/sip_protos.h>
+
+tag_typedef_t ntatag_any = NSTAG_TYPEDEF(*);
+
+tag_typedef_t ntatag_mclass = PTRTAG_TYPEDEF(mclass);
+
+tag_typedef_t ntatag_bad_req_mask = UINTTAG_TYPEDEF(bad_req_mask);
+tag_typedef_t ntatag_bad_resp_mask = UINTTAG_TYPEDEF(bad_resp_mask);
+
+tag_typedef_t ntatag_default_proxy = URLTAG_TYPEDEF(default_proxy);
+tag_typedef_t ntatag_contact = SIPHDRTAG_NAMED_TYPEDEF(contact, contact);
+tag_typedef_t ntatag_target = SIPHDRTAG_NAMED_TYPEDEF(target, contact);
+tag_typedef_t ntatag_aliases = SIPHDRTAG_NAMED_TYPEDEF(aliases, contact);
+
+tag_typedef_t ntatag_method = STRTAG_TYPEDEF(method);
+tag_typedef_t ntatag_branch_key = STRTAG_TYPEDEF(branch_key);
+tag_typedef_t ntatag_ack_branch = STRTAG_TYPEDEF(ack_branch);
+tag_typedef_t ntatag_comp = CSTRTAG_TYPEDEF(comp);
+tag_typedef_t ntatag_msg = PTRTAG_TYPEDEF(msg);
+tag_typedef_t ntatag_tport = PTRTAG_TYPEDEF(tport);
+tag_typedef_t ntatag_smime = PTRTAG_TYPEDEF(smime);
+tag_typedef_t ntatag_remote_cseq = UINTTAG_TYPEDEF(remote_cseq);
+
+tag_typedef_t ntatag_maxsize = USIZETAG_TYPEDEF(maxsize);
+tag_typedef_t ntatag_udp_mtu = UINTTAG_TYPEDEF(udp_mtu);
+tag_typedef_t ntatag_max_forwards = UINTTAG_TYPEDEF(max_forwards);
+tag_typedef_t ntatag_sip_t1 = UINTTAG_TYPEDEF(sip_t1);
+tag_typedef_t ntatag_sip_t1x64 = UINTTAG_TYPEDEF(sip_t1x64);
+tag_typedef_t ntatag_sip_t2 = UINTTAG_TYPEDEF(sip_t2);
+tag_typedef_t ntatag_sip_t4 = UINTTAG_TYPEDEF(sip_t4);
+tag_typedef_t ntatag_progress = UINTTAG_TYPEDEF(progress);
+tag_typedef_t ntatag_blacklist = UINTTAG_TYPEDEF(blacklist);
+tag_typedef_t ntatag_debug_drop_prob = UINTTAG_TYPEDEF(debug_drop_prob);
+
+tag_typedef_t ntatag_sigcomp_options = STRTAG_TYPEDEF(sigcomp_options);
+tag_typedef_t ntatag_sigcomp_close = BOOLTAG_TYPEDEF(sigcomp_close);
+tag_typedef_t ntatag_sigcomp_aware = BOOLTAG_TYPEDEF(sigcomp_aware);
+tag_typedef_t ntatag_sigcomp_algorithm = STRTAG_TYPEDEF(sigcomp_algorithm);
+
+tag_typedef_t ntatag_ua = BOOLTAG_TYPEDEF(ua);
+tag_typedef_t ntatag_stateless = BOOLTAG_TYPEDEF(stateless);
+tag_typedef_t ntatag_user_via = BOOLTAG_TYPEDEF(user_via);
+tag_typedef_t ntatag_pass_100 = BOOLTAG_TYPEDEF(pass_100);
+tag_typedef_t ntatag_extra_100 = BOOLTAG_TYPEDEF(extra_100);
+tag_typedef_t ntatag_timeout_408 = BOOLTAG_TYPEDEF(timeout_408);
+tag_typedef_t ntatag_pass_408 = BOOLTAG_TYPEDEF(pass_408);
+tag_typedef_t ntatag_merge_482 = BOOLTAG_TYPEDEF(merge_482);
+tag_typedef_t ntatag_cancel_2543 = BOOLTAG_TYPEDEF(cancel_2543);
+tag_typedef_t ntatag_cancel_408 = BOOLTAG_TYPEDEF(cancel_408);
+tag_typedef_t ntatag_cancel_487 = BOOLTAG_TYPEDEF(cancel_487);
+tag_typedef_t ntatag_tag_3261 = BOOLTAG_TYPEDEF(tag_3261);
+tag_typedef_t ntatag_rel100 = BOOLTAG_TYPEDEF(rel100);
+tag_typedef_t ntatag_no_dialog = BOOLTAG_TYPEDEF(no_dialog);
+tag_typedef_t ntatag_use_timestamp = BOOLTAG_TYPEDEF(use_timestamp);
+tag_typedef_t ntatag_sipflags = UINTTAG_TYPEDEF(sipflags);
+tag_typedef_t ntatag_client_rport = BOOLTAG_TYPEDEF(client_rport);
+tag_typedef_t ntatag_server_rport = BOOLTAG_TYPEDEF(server_rport);
+tag_typedef_t ntatag_tcp_rport = BOOLTAG_TYPEDEF(tcp_rport);
+tag_typedef_t ntatag_preload = UINTTAG_TYPEDEF(preload);
+tag_typedef_t ntatag_use_naptr = BOOLTAG_TYPEDEF(naptr);
+tag_typedef_t ntatag_use_srv = BOOLTAG_TYPEDEF(srv);
+tag_typedef_t ntatag_rseq = UINTTAG_TYPEDEF(rseq);
+
+/* Status */
+
+tag_typedef_t ntatag_s_irq_hash = UINTTAG_TYPEDEF(s_irq_hash);
+tag_typedef_t ntatag_s_orq_hash = UINTTAG_TYPEDEF(s_orq_hash);
+tag_typedef_t ntatag_s_leg_hash = UINTTAG_TYPEDEF(s_leg_hash);
+tag_typedef_t ntatag_s_irq_hash_used = UINTTAG_TYPEDEF(s_irq_hash_used);
+tag_typedef_t ntatag_s_orq_hash_used = UINTTAG_TYPEDEF(s_orq_hash_used);
+tag_typedef_t ntatag_s_leg_hash_used = UINTTAG_TYPEDEF(s_leg_hash_used);
+tag_typedef_t ntatag_s_recv_msg = UINTTAG_TYPEDEF(s_recv_msg);
+tag_typedef_t ntatag_s_recv_request = UINTTAG_TYPEDEF(s_recv_request);
+tag_typedef_t ntatag_s_recv_response = UINTTAG_TYPEDEF(s_recv_response);
+tag_typedef_t ntatag_s_bad_message = UINTTAG_TYPEDEF(s_bad_message);
+tag_typedef_t ntatag_s_bad_request = UINTTAG_TYPEDEF(s_bad_request);
+tag_typedef_t ntatag_s_bad_response = UINTTAG_TYPEDEF(s_bad_response);
+tag_typedef_t ntatag_s_drop_request = UINTTAG_TYPEDEF(s_drop_request);
+tag_typedef_t ntatag_s_drop_response = UINTTAG_TYPEDEF(s_drop_response);
+tag_typedef_t ntatag_s_client_tr = UINTTAG_TYPEDEF(s_client_tr);
+tag_typedef_t ntatag_s_server_tr = UINTTAG_TYPEDEF(s_server_tr);
+tag_typedef_t ntatag_s_dialog_tr = UINTTAG_TYPEDEF(s_dialog_tr);
+tag_typedef_t ntatag_s_acked_tr = UINTTAG_TYPEDEF(s_acked_tr);
+tag_typedef_t ntatag_s_canceled_tr = UINTTAG_TYPEDEF(s_canceled_tr);
+tag_typedef_t ntatag_s_trless_request = UINTTAG_TYPEDEF(s_trless_request);
+tag_typedef_t ntatag_s_trless_to_tr = UINTTAG_TYPEDEF(s_trless_to_tr);
+tag_typedef_t ntatag_s_trless_response = UINTTAG_TYPEDEF(s_trless_response);
+tag_typedef_t ntatag_s_trless_200 = UINTTAG_TYPEDEF(s_trless_200);
+tag_typedef_t ntatag_s_merged_request = UINTTAG_TYPEDEF(s_merged_request);
+tag_typedef_t ntatag_s_sent_msg = UINTTAG_TYPEDEF(s_sent_msg);
+tag_typedef_t ntatag_s_sent_request = UINTTAG_TYPEDEF(s_sent_request);
+tag_typedef_t ntatag_s_sent_response = UINTTAG_TYPEDEF(s_sent_response);
+tag_typedef_t ntatag_s_retry_request = UINTTAG_TYPEDEF(s_retry_request);
+tag_typedef_t ntatag_s_retry_response = UINTTAG_TYPEDEF(s_retry_response);
+tag_typedef_t ntatag_s_recv_retry = UINTTAG_TYPEDEF(s_recv_retry);
+tag_typedef_t ntatag_s_tout_request = UINTTAG_TYPEDEF(s_tout_request);
+tag_typedef_t ntatag_s_tout_response = UINTTAG_TYPEDEF(s_tout_response);
+
+/* Internal */
+tag_typedef_t ntatag_delay_sending = BOOLTAG_TYPEDEF(delay_sending);
+tag_typedef_t ntatag_incomplete = BOOLTAG_TYPEDEF(incomplete);
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/portbind.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/portbind.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,243 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@file portbind.c
+ * @brief bind a socket to an UDP/TCP port and return the port number
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Mar 25 12:12:25 2004 ppessi
+ */
+
+#include "config.h"
+
+char const name[] = "portbind";
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <assert.h>
+#include <unistd.h>
+
+#if HAVE_SYS_SOCKET_T
+#include <sys/socket.h>
+#endif
+
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+#if HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+#include "sofia-sip/su.h"
+
+#if !defined(IPPROTO_SCTP)
+#define IPPROTO_SCTP (132)
+#endif
+
+static
+char const helptext[] =
+ "usage: portbind OPTIONS [port]\n"
+ " where OPTIONS are\n"
+ " [-t] bind to TCP\n"
+ " [-u] bind to UDP\n"
+ " [-s] bind to SCTP\n"
+#if HAVE_SIN6
+ " [-6] bind to IPv6 only\n"
+ " [-4] bind to IPv4 only\n"
+ " By default, portbind binds to UDP and TCP on IPv6 and IPv4.\n"
+#else
+ " By default, portbind binds to UDP and TCP.\n"
+#endif
+;
+
+void usage(int returncode)
+{
+ fprintf(returncode ? stderr : stdout, helptext);
+ exit(returncode);
+}
+
+int main(int argc, char *argv[])
+{
+ char *o_port = "0", *o_protocol = NULL;
+ int o_tcp = 0, o_udp = 0, o_sctp = 0;
+ char *names[5] = { NULL };
+ int protos[5] = { 0 };
+ int types[5] = { 0 };
+ int n, N = 0;
+ unsigned long portno;
+ unsigned short port;
+ int af;
+ su_socket_t s;
+ socklen_t salen;
+ struct sockaddr_storage ss[1];
+ struct sockaddr *sa = (void *)ss;
+ struct sockaddr_in *sin = (void *)ss;
+#if HAVE_SIN6
+ int o_ip6 = 0, o_ip4 = 0;
+ struct sockaddr_in6 *sin6 = (void *)ss;
+#endif
+
+ for (argv++; *argv && **argv == '-';) {
+ char *opt = *argv++ + 1;
+ if (strcmp(opt, "-") == 0)
+ break;
+ else if (strcmp(opt, "P") == 0 && *argv)
+ o_protocol = *argv++;
+ else if (strcmp(opt, "u") == 0)
+ o_udp = 1;
+ else if (strcmp(opt, "t") == 0)
+ o_tcp = 1;
+ else if (strcmp(opt, "s") == 0)
+ o_sctp = 1;
+ else if (strcmp(opt, "h") == 0)
+ usage(0);
+ else if (strcmp(opt, "-help") == 0)
+ usage(0);
+#if HAVE_SIN6
+ else if (strcmp(opt, "6") == 0)
+ o_ip6 = AF_INET6;
+ else if (strcmp(opt, "4") == 0)
+ o_ip4 = 0;
+#endif
+ else
+ usage(1);
+ }
+
+ if (argv[0]) {
+ char *s = NULL;
+
+ portno = strtoul(argv[0], &s, 10);
+
+ if (portno != (portno & 65535) || s == argv[0] || *s) {
+ fprintf(stderr, "%s: invalid port %s\n", name, argv[0]);
+ exit(1);
+ }
+ } else {
+ portno = 0;
+ }
+
+#if HAVE_SIN6
+ if (o_ip6)
+ af = AF_INET6;
+ else if (o_ip4)
+ af = AF_INET;
+ else
+ af = AF_INET6;
+#else
+ af = AF_INET;
+#endif
+
+ memset(ss, 0, sizeof ss);
+
+ if (!o_tcp || !o_udp || !o_sctp || !o_protocol)
+ o_tcp = o_udp = 1;
+
+ if (o_protocol) {
+ struct protoent *pent = getprotobyname(o_protocol);
+
+ if (!pent) {
+ fprintf(stderr, "%s: %s\n", o_protocol, "unknown protocol");
+ exit(1);
+ }
+ names[N] = pent->p_name, protos[N] = pent->p_proto, types[N++] = SOCK_RAW;
+ }
+
+ if (o_tcp)
+ names[N] = "TCP", protos[N] = IPPROTO_TCP, types[N++] = SOCK_STREAM;
+ if (o_udp)
+ names[N] = "UDP", protos[N] = IPPROTO_UDP, types[N++] = SOCK_DGRAM;
+ if (o_sctp)
+ names[N] = "SCTP", protos[N] = IPPROTO_SCTP, types[N++] = SOCK_SEQPACKET;
+
+ assert(N != 0);
+
+ port = portno;
+
+ for (n = 0; n < N;) {
+ s = su_socket(sa->sa_family = af, types[n], protos[n]);
+
+#if HAVE_SIN6
+ if (s == INVALID_SOCKET && af == AF_INET6 && !o_ip6)
+ s = su_socket(sa->sa_family = af = AF_INET, types[n], protos[n]);
+#endif
+
+ if (s == INVALID_SOCKET) {
+ fprintf(stderr, "%s: socket(AF_INET%s, 0, %s): %s\n",
+ name, af == AF_INET ? "" : "6", names[n], strerror(errno));
+ exit(1);
+ }
+
+#if HAVE_SIN6
+ if (af == AF_INET6 && !o_ip6 && !o_ip4)
+ o_ip6 = o_ip4;
+ if (af == AF_INET6)
+ salen = sizeof *sin6;
+ else
+#endif
+ salen = sizeof *sin;
+
+ sin->sin_port = htons(port);
+
+ if (bind(s, sa, salen) == -1) {
+ if (errno == EADDRINUSE) {
+ if (++port == 0)
+ port = 1024;
+ if (port != portno) {
+ close(s);
+ n = 0;
+ continue;
+ }
+ }
+
+ fprintf(stderr, "%s: bind(%s): %s\n", name, o_port, strerror(errno));
+ exit(1);
+ }
+
+ if (portno == 0) {
+ struct sockaddr_storage ss[1];
+ struct sockaddr *sa = (void *)ss;
+ struct sockaddr_in *sin = (void *)ss;
+
+ salen = sizeof *ss;
+ if (getsockname(s, sa, &salen) == -1) {
+ fprintf(stderr, "%s: getsockname(): %s\n", name, strerror(errno));
+ exit(1);
+ }
+
+ portno = port = ntohs(sin->sin_port);
+ }
+
+ close(s);
+
+ n++;
+ }
+
+ printf("%u\n", ntohs(sin->sin_port));
+
+ return 0;
+}
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/run_test_nta
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/run_test_nta Thu Dec 21 01:30:28 2006
@@ -0,0 +1,214 @@
+#! /bin/bash
+#
+# Run nta_test with our own name server
+#
+# --------------------------------------------------------------------
+#
+# This file is part of the Sofia-SIP package
+#
+# Copyright (C) 2005 Nokia Corporation.
+#
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+#
+# --------------------------------------------------------------------
+#
+# Author: Pekka Pessi <Pekka.Pessi at nokia.com>.
+#
+
+#set -x
+
+s=${0%/*}
+
+resolvfile=.test$$.resolv.conf
+namedfile=.test$$.named.conf
+pidfile=.test$$.named.pid
+zonefile=.test$$.example.zone
+
+test x$s = x$0 && s=`pwd`
+
+test -z "$srcdir" && srcdir=$s
+export srcdir
+
+PATH=/usr/sbin:/usr/local/sbin:/sbin:$PATH
+
+export PATH
+
+me6="::1"
+
+if ../su/localinfo -6 -n -g -s >& /dev/null ; then
+ ipv6=true aaaa=aaaa v6flag=-6
+ me6=$(../su/localinfo -6 -n -s -g | awk '{print $1; exit(0); }')
+else
+ if ! ../su/localinfo '--help' >& /dev/null ; then
+ echo "warning: $0: missing 'localinfo', cannot test IPv6"
+ else
+ echo "warning: $0: no valid IPv6 addresses available"
+ fi
+ ipv6=false aaaa=a
+fi
+
+if type named >& /dev/null && ./portbind --help >& /dev/null
+then
+
+port=$(./portbind $v6flag) sink=$port
+port=$(./portbind $v6flag $((port + 1))) down=$port
+port=$(./portbind $v6flag $((port + 1))) bind=$port
+port=$(./portbind $v6flag $((port + 1))) contact=$port
+
+# Disable IPv6 resolver for now
+if false && eval $ipv6 ; then
+ listen="listen-on-v6 port $bind { any; };"
+ ns=$me6
+else
+ listen="listen-on port $bind { 127.0.0.1; };"
+ ns="127.0.0.1"
+fi
+
+cat > $resolvfile <<EOF
+nameserver $ns
+domain example.com
+port $bind
+EOF
+
+cat > $namedfile <<EOF
+options {
+ pid-file "$pidfile";
+ $listen
+};
+
+zone "example.org" in {
+ type master;
+ file "$zonefile";
+};
+EOF
+
+cat > $zonefile << EOF
+;
+; Zone file for example.org
+; SIP targets: example.org
+; srv.example.org
+; down.example.org
+; na.example.org
+; ipv6-20-80.example.org
+; ipv.example.org
+;
+\$TTL 60
+@ IN SOA ns root (
+ 2002042901 ; SERIAL
+ 7200 ; REFRESH
+ 600 ; RETRY
+ 36000000 ; EXPIRE
+ 60 ; MINIMUM
+ )
+ NS ns
+ ;; order pref flags service regexp replacement
+ NAPTR 20 15 "s" "SIP+D2U" "" _sip._udp
+ NAPTR 40 25 "s" "SIPS+D2T" "" _sips._tcp
+ NAPTR 40 50 "s" "SIP+D2T" "" _sip._tcp
+
+ns AAAA $me6
+ A 127.0.0.1
+
+_sip._udp SRV 1 100 $contact me
+_sips._tcp SRV 3 100 $contact me
+_sip._tcp SRV 2 100 $contact me
+
+_sip._udp.srv SRV 1 100 $contact a
+_sips._tcp.srv SRV 3 100 $contact a
+_sip._tcp.srv SRV 2 100 $contact $aaaa
+
+_sip._udp.srv2 SRV 1 200 $contact c
+ SRV 1 100 $contact b
+ SRV 1 50 $contact a
+
+me AAAA $me6
+ A 127.0.0.1
+
+a A 127.0.0.1
+b A 0.0.0.2
+c A 0.0.0.3
+
+aaaa AAAA $me6
+
+; Directly from NAPTR to A/AAAA (Test 1.6c)
+na NAPTR 20 15 "a" "SIP+D2T" "" a2
+
+; No sensible NAPTR match (and we get 503)
+na503 NAPTR 20 15 "S" "SIP+D2F" "" a2
+
+; No SIP NAPTR match
+nona NAPTR 20 15 "S" "ZIP+D2U" "" a2
+_sip._udp.nona SRV 1 10 $contact ip4
+
+; No SIP SRV match
+nosrv NAPTR 20 1 "s" "SIP+D2U" "" _sip._udp.nosrv
+ NAPTR 20 2 "s" "SIP+D2U" "" _sip._udp.srv
+
+; This fails (and we get 503)
+a2 A 127.0.0.2
+
+; IP6 should get 80%, IP4 20%
+ipv6-20-80 NAPTR 20 15 "s" "SIP+D2U" "" _sip._udp.ipv6-20-80
+
+_sip._udp.ipv6-20-80 SRV 1 80 $contact ip6
+ SRV 1 20 $contact ip4
+
+_sip._udp.ipv SRV 1 100 $contact ip6
+_sip._udp.ipv SRV 1 100 $contact ip4
+
+ip6 AAAA $me6
+ip4 A 127.0.0.1
+
+; SRV failover to me...
+down NAPTR 20 15 "s" "SIP+D2U" "" _sip._udp.down
+_sip._udp.down SRV 1 100 $down me
+_sip._udp.down SRV 2 100 $contact me
+
+; A failover
+down2 A 0.0.0.2
+ A 0.0.0.3
+ A 127.0.0.1
+EOF
+
+# -g is also very nice option for named
+named -f -c $namedfile &
+pid=$!
+while ! test -r $pidfile && kill -0 $!
+do
+ sleep 1
+done
+
+if test -r $pidfile ; then
+# export SOFIA_DEBUG=9
+ sink=$sink down=$down \
+ ipv6=$ipv6 \
+ SIPCONTACT="sip:*:$contact;comp=sigcomp" \
+ $VALGRIND ./test_nta "$@" - $resolvfile
+ exit=$?
+ kill $(cat $pidfile)
+ rm $pidfile $zonefile $resolvfile $namedfile 2>/dev/null
+ exit $exit
+fi
+exit $?
+
+else # not having BIND and portbind
+
+ipv6=$ipv6 $VALGRIND ./test_nta "$@"
+exit $?
+fi
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/run_test_nta_api
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/run_test_nta_api Thu Dec 21 01:30:28 2006
@@ -0,0 +1,39 @@
+#! /bin/bash
+#
+# Run test_nta_api
+#
+# --------------------------------------------------------------------
+#
+# This file is part of the Sofia-SIP package
+#
+# Copyright (C) 2005 Nokia Corporation.
+#
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+#
+# --------------------------------------------------------------------
+#
+# Author: Pekka Pessi <Pekka.Pessi at nokia.com>.
+#
+
+#set -x
+
+s=${0%/*}
+
+exec $VALGRIND ./test_nta_api "$@"
+
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sl_read_payload.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sl_read_payload.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,126 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup sl_utils
+ * @CFILE sl_read_payload.c
+ *
+ * @brief Functions for reading SIP message payload from a file.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Sep 5 00:44:34 2002 ppessi
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sofia-sip/sip_header.h>
+
+#include <sofia-sip/sl_utils.h>
+
+/** Read payload from named file.
+ *
+ * The function sl_read_payload() reads the contents to a SIP payload
+ * structure from a the named file. If @a fname is NULL, the payload
+ * contents are read from standard input.
+ */
+sip_payload_t *sl_read_payload(su_home_t *home, char const *fname)
+{
+ FILE *f;
+ sip_payload_t *pl;
+
+ if (fname == NULL || strcmp(fname, "-") == 0)
+ f = stdin, fname = "<stdin>";
+ else
+ f = fopen(fname, "rb");
+
+ if (f == NULL)
+ return NULL;
+
+ pl = sl_fread_payload(home, f);
+ if (f != stdin)
+ fclose(f);
+
+ return pl;
+}
+
+sip_payload_t *sl_fread_payload(su_home_t *home, FILE *f)
+{
+ sip_payload_t *pl;
+ size_t n;
+ char *buf;
+ char const *who;
+ size_t used, size;
+
+ if (f == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ pl = sip_payload_create(home, NULL, 0);
+
+ if (pl == NULL)
+ return NULL;
+
+ /* Read block by block */
+ used = 0;
+ size = 4096;
+ buf = malloc(size);
+ who = "sl_fread_payload: malloc";
+
+ while (buf) {
+ n = fread(buf + used, 1, size - used, f);
+ used += n;
+ if (n < size - used) {
+ if (feof(f))
+ ;
+ else if (ferror(f)) {
+ free(buf); buf = NULL;
+ who = "sl_fread_payload: fread";
+ }
+ break;
+ }
+ buf = realloc(buf, size = 2 * size);
+ if (buf == NULL)
+ who = "sl_fread_payload: realloc";
+ }
+
+ if (buf == NULL) {
+ perror(who);
+ su_free(home, pl);
+ return NULL;
+ }
+
+ if (used < size)
+ buf[used] = '\0';
+
+ pl->pl_common->h_data = pl->pl_data = buf;
+ pl->pl_common->h_len = pl->pl_len = used;
+
+ return pl;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sl_utils.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sl_utils.docs Thu Dec 21 01:30:28 2006
@@ -0,0 +1,9 @@
+/* -*- c -*- */
+
+/**@defgroup sl_utils SIP Library Utilities - "sl_utils"
+ *
+ * SIP library utilities provide some simple utility functions for printing
+ * and managing SIP headers or messages.
+ *
+ */
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sl_utils_log.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sl_utils_log.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,287 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup sl_utils
+ *
+ * @CFILE sl_utils_log.c
+ * @brief Implementation of SIP library utility logging functions.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Oct 5 15:38:39 2000 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include <sofia-sip/su_log.h>
+
+#include <sofia-sip/sip_header.h>
+#include "sofia-sip/sl_utils.h"
+
+/**Log a SIP message.
+ *
+ * The function sl_message_log() logs shorthand information identifying
+ * the SIP message to the given @a log at level @a level. The shorthand
+ * information include the method and URL by default. If @a details is
+ * nonzero, topmost @Via, @CSeq, @To @b and @@From is included, too.
+ *
+ * @param log output log (if @c NULL, su_default_log() is used).
+ * @param level log level
+ * @param prefix string logged before the first line.
+ * @param sip message to be logged.
+ * @param details flag specifying if detailed output is desired.
+ */
+void sl_sip_log(su_log_t *log,
+ int level,
+ char const *prefix,
+ sip_t const *sip,
+ int details)
+{
+ sip_cseq_t const *cs = sip->sip_cseq;
+
+ if (log == NULL)
+ log = su_log_default;
+
+ assert(cs);
+
+ if (sip->sip_request) {
+ su_llog(log, level,
+ "%s%s "URL_FORMAT_STRING" (CSeq %d %s)\n",
+ prefix,
+ sip->sip_request->rq_method_name,
+ URL_PRINT_ARGS(sip->sip_request->rq_url),
+ cs->cs_seq,
+ cs->cs_method_name);
+
+ if (!details)
+ return;
+
+ if (sip->sip_via) {
+ char const *received = sip->sip_via->v_received;
+ char const *port = sip->sip_via->v_port;
+
+ su_llog(log, level,
+ "\tvia %s%s%s%s%s%s\n",
+ sip->sip_via->v_host,
+ port ? ":" : "", port ? port : "",
+ received ? " (" : "", received ? received : "",
+ received ? ")" : "");
+ }
+ }
+ else {
+ su_llog(log, level,
+ "%s%03u %s (CSeq %d %s)\n",
+ prefix,
+ sip->sip_status->st_status,
+ sip->sip_status->st_phrase,
+ cs->cs_seq,
+ cs->cs_method_name);
+ if (!details)
+ return;
+ }
+
+ if (sip->sip_from)
+ sl_from_log(log, level, "\tFrom: %s\n", sip->sip_from);
+
+ if (sip->sip_to)
+ sl_to_log(log, level, "\tTo: %s\n", sip->sip_to);
+}
+
+/**Log a @From header.
+ *
+ * The function sl_from_log() logs the contents of @a from header to
+ * the output @a log. The @a fmt specifies the output format, where %s
+ * is replaced with header contents. If @a fmt is @c NULL, only the header
+ * contents are logged.
+ *
+ * @param log output log
+ * @param level logging level of output
+ * @param fmt output format
+ * @param from @From header
+ */
+void sl_from_log(su_log_t *log, int level,
+ char const *fmt, sip_from_t const *from)
+{
+ sip_addr_t a[1];
+
+ if (from == NULL)
+ return;
+
+ memcpy(a, from, sizeof a);
+ a->a_params = NULL;
+ if (!a->a_display) a->a_display = "";
+
+ return sl_header_log(log, level, fmt, (sip_header_t *)a);
+}
+
+/**Log a @To header.
+ *
+ * The function sl_to_log() logs the contents of @a to header to the
+ * log @a log with given @a level. The @a fmt specifies the output format,
+ * where %s is replaced with header contents. If @a fmt is @c NULL, only the
+ * header contents are logged.
+ *
+ * @param log output log
+ * @param level logging level of output
+ * @param fmt output format
+ * @param to @To header
+ */
+void sl_to_log(su_log_t *log, int level, char const *fmt, sip_to_t const *to)
+{
+ sl_from_log(log, level, fmt, (sip_from_t const *)to);
+}
+
+/**Log a @Contact header.
+ *
+ * The function sl_contact_log() logs the contents of @a contact header
+ * to the log @a log with given @a level. The @a fmt specifies the output
+ * format, where %s is replaced with header contents. If @a fmt is @c NULL,
+ * only the header contents are logged.
+ *
+ * @param log output log
+ * @param level logging level of output
+ * @param fmt output format
+ * @param contact @Contact header
+ */
+void sl_contact_log(su_log_t *log, int level,
+ char const *fmt, sip_contact_t const *m)
+{
+ sl_from_log(log, level, fmt, (sip_from_t const *)m);
+}
+
+/**Log an @Allow header(s).
+ *
+ * The function sl_allow_log() logs the contents of @a allow header to
+ * the log @a log with given @a level. The @a fmt specifies the output
+ * format, where %s is replaced with header contents. If @a fmt is @c NULL,
+ * only the header contents are logged.
+ *
+ * @param log output log
+ * @param level logging level of output
+ * @param fmt output format
+ * @param allow @Allow header
+ *
+ */
+void sl_allow_log(su_log_t *log, int level,
+ char const *fmt, sip_allow_t const *allow)
+{
+ sl_header_log(log, level, fmt, (sip_header_t *)allow);
+}
+
+
+/**Log a @Via header.
+ *
+ * The function sl_via_log() logs the contents of @a via header to
+ * the @a log. The @a fmt specifies the output format, where %s
+ * is replaced with header contents. If @a fmt is @c NULL, only the header
+ * contents are logged.
+ *
+ * @param log output log
+ * @param fmt format used when logging
+ * @param v via header
+ */
+void sl_via_log(su_log_t *log, int level, char const *fmt, sip_via_t const *v)
+{
+ sl_header_log(log, level, fmt, (sip_header_t *)v);
+}
+
+
+/**Log message payload.
+ *
+ * The function sl_payload_log() logs the contents of @a payload object
+ * to the output @a log. Each line in the payload is prepended with the
+ * @a prefix. If @a prefix is @c NULL, only the header contents are logged.
+ * For each line in payload, only first 70 charactes are logged, rest is
+ * replaced with "...".
+ *
+ * @param log output log
+ * @param level logging level of output
+ * @param prefix prefix appended to each payload line
+ * @param pl payload object
+ */
+void sl_payload_log(su_log_t *log, int level,
+ char const *prefix,
+ sip_payload_t const *pl)
+{
+ char *s = pl->pl_data, *end = pl->pl_data + pl->pl_len;
+ char line[74];
+
+ if (log == NULL)
+ log = su_log_default;
+
+ while (s < end && *s != '\0') {
+ size_t n = strncspn(s, end - s, "\r\n");
+ size_t crlf = strnspn(s + n, end - s - n, "\r\n");
+ if (n < 70) {
+ memcpy(line, s, n);
+ line[n] = '\0';
+ }
+ else {
+ memcpy(line, s, 70);
+ strcpy(line + 70, "...");
+ }
+ su_llog(log, level, "%s%s\n", prefix, line);
+ s += n + crlf;
+ }
+}
+
+/** Log a header.
+ *
+ * Logs the contents of an header to the output @a stream. The @a fmt
+ * specifies the output format, where %s is replaced with header contents.
+ * If @a fmt is @c NULL, only the header contents are logged.
+ *
+ * @param stream output stream
+ * @param fmt output format
+ * @param h a SIP header object
+ */
+void sl_header_log(su_log_t *log, int level, char const *fmt,
+ sip_header_t const *h)
+{
+ char *s, b[1024];
+ issize_t len;
+
+ len = sip_header_field_e(s = b, sizeof b, h, 0);
+ if (len == -1)
+ return;
+
+ if ((size_t)len >= sizeof b) {
+ s = malloc(len + 1); if (!s) return;
+ sip_header_field_e(s, len + 1, h, 0);
+ }
+ s[len] = '\0';
+
+ if (fmt == NULL)
+ fmt = "%s\n";
+ su_llog(log, level, fmt, s);
+
+ if (s != b)
+ free(s);
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sl_utils_print.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sl_utils_print.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,297 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup sl_utils
+ *
+ * @CFILE sl_utils_print.c
+ * @brief Implementation of SIP library utility print functions.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Oct 5 15:38:39 2000 ppessi
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+#include <sofia-sip/sip_header.h>
+#include "sofia-sip/sl_utils.h"
+
+/**Print a SIP message.
+ *
+ * The function sl_message_log() prints shorthand information identifying
+ * the SIP message to the given output @a stream. The shorthand information
+ * include the method and URL by default. If @a details is nonzero, topmost
+ * @Via, @CSeq, @To and @From is included, too.
+ *
+ * @param stream output stream (if @c NULL, @c stdout is used).
+ * @param prefix string printed before the first line.
+ * @param sip message to be logged.
+ * @param details flag specifying if detailed output is desired.
+ */
+void sl_message_log(FILE *stream,
+ char const *prefix, sip_t const *sip, int details)
+{
+ sip_cseq_t const *cs = sip->sip_cseq;
+
+ if (stream == NULL)
+ stream = stdout;
+
+ assert(cs);
+
+ if (sip->sip_request) {
+ fprintf(stream,
+ "%s%s "URL_FORMAT_STRING" (CSeq %d %s)\n",
+ prefix,
+ sip->sip_request->rq_method_name,
+ URL_PRINT_ARGS(sip->sip_request->rq_url),
+ cs->cs_seq,
+ cs->cs_method_name);
+
+ if (!details)
+ return;
+
+ if (sip->sip_via) {
+ fputs(prefix, stream);
+ sl_via_print(stream, "Via: %s\n", sip->sip_via);
+ }
+ }
+ else {
+ fprintf(stream,
+ "%s%03u %s (CSeq %d %s)\n",
+ prefix,
+ sip->sip_status->st_status,
+ sip->sip_status->st_phrase,
+ cs->cs_seq,
+ cs->cs_method_name);
+ if (!details)
+ return;
+ }
+
+ if (sip->sip_from)
+ sl_from_print(stream, "\tFrom: %s\n", sip->sip_from);
+
+ if (sip->sip_to)
+ sl_to_print(stream, "\tTo: %s\n", sip->sip_to);
+}
+
+/** Print @From header.
+ *
+ * The function sl_from_print() prints the contents of @a from header to
+ * the output @a stream. The @a fmt specifies the output format, where %s
+ * is replaced with header contents. If @a fmt is @c NULL, only the header
+ * contents are printed.
+ *
+ * @param stream output stream
+ * @param fmt output format
+ * @param from header object
+ *
+ * @return
+ * The function sl_from_print() returns number of bytes printed,
+ * or -1 upon an error.
+ */
+issize_t sl_from_print(FILE *stream, char const *fmt, sip_from_t const *from)
+{
+ sip_addr_t a[1];
+
+ if (from == NULL)
+ return -1;
+
+ memcpy(a, from, sizeof a);
+ a->a_params = NULL;
+ if (!a->a_display) a->a_display = "";
+
+ return sl_header_print(stream, fmt, (sip_header_t *)a);
+}
+
+/** Print @To header.
+ *
+ * The function sl_to_print() prints the contents of @a to header to
+ * the output @a stream. The @a fmt specifies the output format, where %s
+ * is replaced with header contents. If @a fmt is @c NULL, only the header
+ * contents are printed.
+ *
+ * @param stream output stream
+ * @param fmt output format
+ * @param to header object
+ *
+ * @return
+ * The function sl_to_print() returns number of bytes printed,
+ * or -1 upon an error.
+ */
+issize_t sl_to_print(FILE *stream, char const *fmt, sip_to_t const *to)
+{
+ return sl_from_print(stream, fmt, (sip_from_t const *)to);
+}
+
+/** Print @Contact header.
+ *
+ * The function sl_contact_print() prints the contents of @a contact
+ * header to the output @a stream. The @a fmt specifies the output format,
+ * where %s is replaced with header contents. If @a fmt is @c NULL, only the
+ * header contents are printed.
+ *
+ * @param stream output stream
+ * @param fmt output format
+ * @param contact header object
+ *
+ * @return
+ * The function sl_contact_print() returns number of bytes printed,
+ * or -1 upon an error.
+*/
+issize_t sl_contact_print(FILE *stream, char const *fmt,
+ sip_contact_t const *m)
+{
+ return sl_from_print(stream, fmt, (sip_from_t const *)m);
+}
+
+/** Print @Allow header(s).
+ *
+ * The function sl_allow_print() prints the contents of @a allow header to
+ * the output @a stream. The @a fmt specifies the output format, where %s
+ * is replaced with header contents. If @a fmt is @c NULL, only the header
+ * contents are printed.
+ *
+ * @param stream output stream
+ * @param fmt output format
+ * @param allow header object
+ *
+ * @return
+ * The function sl_allow_print() returns number of bytes printed,
+ * or -1 upon an error.
+*/
+issize_t sl_allow_print(FILE *stream,
+ char const *fmt,
+ sip_allow_t const *allow)
+{
+ return sl_header_print(stream, fmt, (sip_header_t *)allow);
+}
+
+
+/** Print message payload.
+ *
+ * The function sl_payload_print() prints the contents of @a payload
+ * object to the output @a stream. The @a fmt specifies the output format,
+ * where %s is replaced with header contents. If @a fmt is @c NULL, only the
+ * header contents are printed.
+ *
+ * @param stream output stream
+ * @param prefix prefix appended to each payload line
+ * @param pl payload object
+ *
+ * @return
+ * The function sl_payload_print() returns number of bytes printed,
+ * or -1 upon an error.
+*/
+issize_t sl_payload_print(FILE *stream, char const *prefix, sip_payload_t const *pl)
+{
+ char *s = pl->pl_data, *end = pl->pl_data + pl->pl_len;
+ size_t n, total = 0, crlf = 1;
+
+ while (s < end && *s != '\0') {
+ n = strncspn(s, end - s, "\r\n");
+ crlf = strnspn(s + n, end - s - n, "\r\n");
+ if (prefix)
+ fputs(prefix, stream), total += strlen(prefix);
+ fwrite(s, 1, n + crlf, stream);
+ s += n + crlf;
+ total += n + crlf;
+ }
+ if (crlf == 0)
+ fputs("\n", stream), total++;
+
+ return (issize_t)total;
+}
+
+/** Print @Via header.
+ *
+ * The function sl_via_print() prints the contents of @a via header to
+ * the output @a stream. The @a fmt specifies the output format, where %s
+ * is replaced with header contents. If @a fmt is @c NULL, only the header
+ * contents are printed.
+ *
+ * @param stream output stream
+ * @param fmt output format
+ * @param v header object
+ *
+ * @return
+ * The function sl_via_print() returns number of bytes printed,
+ * or -1 upon an error.
+ */
+issize_t sl_via_print(FILE *stream, char const *fmt, sip_via_t const *v)
+{
+ char s[1024];
+
+ sip_header_field_e(s, sizeof(s), (sip_header_t const *)v, 0);
+ s[sizeof(s) - 1] = '\0';
+
+ if (fmt && strcmp(fmt, "%s"))
+ return fprintf(stream, fmt, s);
+ if (fputs(s, stream) >= 0)
+ return (issize_t)strlen(s);
+ return -1;
+}
+
+/** Print a header.
+ *
+ * Prints the contents of an header to the output @a stream. The @a fmt
+ * specifies the output format, where %s is replaced with header contents.
+ * If @a fmt is @c NULL, only the header contents are printed.
+ *
+ * @param stream output stream
+ * @param fmt output format
+ * @param v header object
+ *
+ * @return
+ * Number of bytes logged, or -1 upon an error.
+ */
+issize_t sl_header_print(FILE *stream, char const *fmt, sip_header_t const *h)
+{
+ char *s, b[1024];
+ issize_t len;
+
+ len = sip_header_field_e(s = b, sizeof b, h, 0);
+ if (len == -1)
+ return len;
+
+ if ((size_t)len >= sizeof b) {
+ s = malloc(len + 1); if (!s) return -1;
+ sip_header_field_e(s, len + 1, h, 0);
+ }
+ s[len] = '\0';
+
+ if (fmt != NULL && strcmp(fmt, "%s") != 0)
+ len = fprintf(stream, fmt, s);
+ else if (fputs(s, stream) < 0)
+ len = -1;
+
+ if (s != b)
+ free(s);
+
+ return len;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/nta.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/nta.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,479 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef NTA_H
+/** Defined when <sofia-sip/nta.h> has been included. */
+#define NTA_H
+
+/**@file sofia-sip/nta.h @brief Nokia Transaction API for SIP
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Jul 18 09:18:32 2000 ppessi
+ */
+
+#ifndef SU_WAIT_H
+#include <sofia-sip/su_wait.h>
+#endif
+
+#ifndef SIP_H
+#include <sofia-sip/sip.h>
+#endif
+
+#ifndef NTA_TAG_H
+#include <sofia-sip/nta_tag.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/* ----------------------------------------------------------------------
+ * 1) Types
+ */
+
+/** NTA agent */
+typedef struct nta_agent_s nta_agent_t;
+/** NTA call leg */
+typedef struct nta_leg_s nta_leg_t;
+/** NTA outgoing request */
+typedef struct nta_outgoing_s nta_outgoing_t;
+/** NTA incoming request */
+typedef struct nta_incoming_s nta_incoming_t;
+
+#ifndef NTA_AGENT_MAGIC_T
+/** Default type of application context for NTA agents.
+ * Application may define this to appropriate type before including
+ * <nta.h>. */
+#define NTA_AGENT_MAGIC_T struct nta_agent_magic_s
+#endif
+#ifndef NTA_LEG_MAGIC_T
+/** Default type of application context for NTA call legs.
+ * Application may define this to appropriate type before including
+ * <nta.h>. */
+#define NTA_LEG_MAGIC_T struct nta_leg_magic_s
+#endif
+#ifndef NTA_OUTGOING_MAGIC_T
+/** Default type of application context for outgoing NTA requests.
+ * Application may define this to appropriate type before including
+ * <nta.h>. */
+#define NTA_OUTGOING_MAGIC_T struct nta_outgoing_magic_s
+#endif
+#ifndef NTA_INCOMING_MAGIC_T
+/** Default type of application context for incoming NTA requests.
+ * Application may define this to appropriate type before including
+ * <nta.h>. */
+#define NTA_INCOMING_MAGIC_T struct nta_incoming_magic_s
+#endif
+
+/** Application context for NTA agents */
+typedef NTA_AGENT_MAGIC_T nta_agent_magic_t;
+/** Application context for NTA call legs */
+typedef NTA_LEG_MAGIC_T nta_leg_magic_t;
+/** Application context for outgoing NTA requests */
+typedef NTA_OUTGOING_MAGIC_T nta_outgoing_magic_t;
+/** Application context for incoming NTA requests */
+typedef NTA_INCOMING_MAGIC_T nta_incoming_magic_t;
+
+/* ----------------------------------------------------------------------
+ * 2) Constants
+ */
+
+/** NTA API version number */
+#define NTA_VERSION "2.0"
+
+/** NTA module version */
+SOFIAPUBVAR char const nta_version[];
+
+enum {
+ /* Stack parameters */
+ NTA_SIP_T1 = 500, /**< SIP T1, 500 milliseconds. */
+ NTA_SIP_T2 = 4000, /**< SIP T2, 4 seconds. */
+ NTA_SIP_T4 = 5000, /**< SIP T4, 5 seconds. */
+ NTA_TIME_MAX = 15 * 24 * 3600 * 1000
+ /**< Maximum value for timers. */
+};
+
+/* ----------------------------------------------------------------------
+ * 3) Agent-level prototypes
+ */
+
+typedef int nta_message_f(nta_agent_magic_t *context,
+ nta_agent_t *agent,
+ msg_t *msg,
+ sip_t *sip);
+
+SOFIAPUBFUN
+nta_agent_t *nta_agent_create(su_root_t *root,
+ url_string_t const *name,
+ nta_message_f *callback,
+ nta_agent_magic_t *magic,
+ tag_type_t tag, tag_value_t value, ...);
+
+SOFIAPUBFUN void nta_agent_destroy(nta_agent_t *agent);
+
+SOFIAPUBFUN char const *nta_agent_version(nta_agent_t const *a);
+SOFIAPUBFUN nta_agent_magic_t *nta_agent_magic(nta_agent_t const *a);
+
+SOFIAPUBFUN
+int nta_agent_add_tport(nta_agent_t *agent,
+ url_string_t const *url,
+ tag_type_t tag, tag_value_t value, ...);
+
+SOFIAPUBFUN int nta_agent_close_tports(nta_agent_t *agent);
+
+SOFIAPUBFUN sip_contact_t *nta_agent_contact(nta_agent_t const *a);
+SOFIAPUBFUN sip_via_t *nta_agent_via(nta_agent_t const *a);
+SOFIAPUBFUN sip_via_t *nta_agent_public_via(nta_agent_t const *a);
+
+SOFIAPUBFUN char const *nta_agent_newtag(su_home_t *,
+ char const *fmt, nta_agent_t *);
+
+SOFIAPUBFUN int nta_agent_set_params(nta_agent_t *agent,
+ tag_type_t tag, tag_value_t value, ...);
+SOFIAPUBFUN int nta_agent_get_params(nta_agent_t *agent,
+ tag_type_t tag, tag_value_t value, ...);
+
+SOFIAPUBFUN int nta_agent_get_stats(nta_agent_t *agent,
+ tag_type_t tag, tag_value_t value, ...);
+
+/* ----------------------------------------------------------------------
+ * 4) Message-level prototypes
+ */
+
+SOFIAPUBFUN msg_t *nta_msg_create(nta_agent_t *self, int flags);
+
+SOFIAPUBFUN int nta_msg_complete(msg_t *msg);
+
+SOFIAPUBFUN int nta_msg_request_complete(msg_t *msg,
+ nta_leg_t *leg,
+ sip_method_t method,
+ char const *method_name,
+ url_string_t const *req_url);
+
+SOFIAPUBFUN int nta_is_internal_msg(msg_t const *msg);
+
+/* ----------------------------------------------------------------------
+ * 5) Leg-level prototypes
+ */
+typedef int nta_request_f(nta_leg_magic_t *lmagic,
+ nta_leg_t *leg,
+ nta_incoming_t *irq,
+ sip_t const *sip);
+
+SOFIAPUBFUN
+nta_leg_t *nta_leg_tcreate(nta_agent_t *agent,
+ nta_request_f *req_callback,
+ nta_leg_magic_t *magic,
+ tag_type_t tag, tag_value_t value, ...);
+
+SOFIAPUBFUN void nta_leg_destroy(nta_leg_t *leg);
+
+SOFIAPUBFUN nta_leg_t *nta_default_leg(nta_agent_t const *agent);
+
+SOFIAPUBFUN nta_leg_magic_t *nta_leg_magic(nta_leg_t const *leg,
+ nta_request_f *callback);
+
+SOFIAPUBFUN void nta_leg_bind(nta_leg_t *leg,
+ nta_request_f *callback,
+ nta_leg_magic_t *);
+
+/** Add local tag. */
+SOFIAPUBFUN char const *nta_leg_tag(nta_leg_t *leg, char const *tag);
+
+/** Get local tag. */
+SOFIAPUBFUN char const *nta_leg_get_tag(nta_leg_t const *leg);
+
+/** Add remote tag. */
+SOFIAPUBFUN char const *nta_leg_rtag(nta_leg_t *leg, char const *tag);
+
+/** Get remote tag. */
+SOFIAPUBFUN char const *nta_leg_get_rtag(nta_leg_t const *leg);
+
+/** Set UAC route. */
+SOFIAPUBFUN int nta_leg_client_route(nta_leg_t *leg,
+ sip_record_route_t const *route,
+ sip_contact_t const *contact);
+
+/** Set UAS route */
+SOFIAPUBFUN int nta_leg_server_route(nta_leg_t *leg,
+ sip_record_route_t const *route,
+ sip_contact_t const *contact);
+
+/** Get route */
+SOFIAPUBFUN int nta_leg_get_route(nta_leg_t *leg,
+ sip_route_t const **return_route,
+ sip_contact_t const **return_target);
+
+/** Get leg by destination */
+SOFIAPUBFUN nta_leg_t *nta_leg_by_uri(nta_agent_t const *,
+ url_string_t const *);
+
+/** Get leg by dialog */
+SOFIAPUBFUN
+nta_leg_t *nta_leg_by_dialog(nta_agent_t const *agent,
+ url_t const *request_uri,
+ sip_call_id_t const *call_id,
+ char const *from_tag,
+ url_t const *from_url,
+ char const *to_tag,
+ url_t const *to_url);
+
+/** Generate Replaces header */
+SOFIAPUBFUN sip_replaces_t *nta_leg_make_replaces(nta_leg_t *leg,
+ su_home_t *home,
+ int early_only);
+/** Get dialog leg by Replaces header */
+SOFIAPUBFUN
+nta_leg_t *nta_leg_by_replaces(nta_agent_t *, sip_replaces_t const *);
+
+/* ----------------------------------------------------------------------
+ * 6) Prototypes for incoming transactions
+ */
+
+SOFIAPUBFUN
+nta_incoming_t *nta_incoming_create(nta_agent_t *agent,
+ nta_leg_t *leg,
+ msg_t *msg,
+ sip_t *sip,
+ tag_type_t tag, tag_value_t value, ...);
+
+SOFIAPUBFUN nta_incoming_t *nta_incoming_default(nta_agent_t *agent);
+
+typedef int nta_ack_cancel_f(nta_incoming_magic_t *imagic,
+ nta_incoming_t *irq,
+ sip_t const *sip);
+
+SOFIAPUBFUN void nta_incoming_bind(nta_incoming_t *irq,
+ nta_ack_cancel_f *callback,
+ nta_incoming_magic_t *imagic);
+
+SOFIAPUBFUN
+nta_incoming_magic_t *nta_incoming_magic(nta_incoming_t *irq,
+ nta_ack_cancel_f *callback);
+
+SOFIAPUBFUN
+nta_incoming_t *nta_incoming_find(nta_agent_t const *agent,
+ sip_t const *sip,
+ sip_via_t const *v);
+
+SOFIAPUBFUN char const *nta_incoming_tag(nta_incoming_t *irq, char const *tag);
+SOFIAPUBFUN char const *nta_incoming_gettag(nta_incoming_t const *irq);
+
+SOFIAPUBFUN int nta_incoming_status(nta_incoming_t const *irq);
+SOFIAPUBFUN sip_method_t nta_incoming_method(nta_incoming_t const *irq);
+SOFIAPUBFUN char const *nta_incoming_method_name(nta_incoming_t const *irq);
+SOFIAPUBFUN url_t const *nta_incoming_url(nta_incoming_t const *irq);
+SOFIAPUBFUN uint32_t nta_incoming_cseq(nta_incoming_t const *irq);
+
+SOFIAPUBFUN int nta_incoming_set_params(nta_incoming_t *irq,
+ tag_type_t tag, tag_value_t value, ...);
+
+SOFIAPUBFUN msg_t *nta_incoming_getrequest(nta_incoming_t *irq);
+SOFIAPUBFUN msg_t *nta_incoming_getrequest_ackcancel(nta_incoming_t *irq);
+SOFIAPUBFUN msg_t *nta_incoming_getresponse(nta_incoming_t *irq);
+
+SOFIAPUBFUN
+int nta_incoming_complete_response(nta_incoming_t *irq,
+ msg_t *msg,
+ int status,
+ char const *phrase,
+ tag_type_t tag, tag_value_t value, ...);
+
+SOFIAPUBFUN
+int nta_incoming_treply(nta_incoming_t *ireq,
+ int status, char const *phrase,
+ tag_type_t tag, tag_value_t value, ...);
+
+SOFIAPUBFUN int nta_incoming_mreply(nta_incoming_t *irq, msg_t *msg);
+
+SOFIAPUBFUN void nta_incoming_destroy(nta_incoming_t *irq);
+
+/* Functions for feature, method, mime, session-timer negotation */
+
+SOFIAPUBFUN
+int nta_check_required(nta_incoming_t *irq,
+ sip_t const *sip,
+ sip_supported_t const *supported,
+ tag_type_t tag, tag_value_t value, ...);
+SOFIAPUBFUN
+int nta_check_supported(nta_incoming_t *irq,
+ sip_t const *sip,
+ sip_require_t *require,
+ tag_type_t tag, tag_value_t value, ...);
+SOFIAPUBFUN
+int nta_check_method(nta_incoming_t *irq,
+ sip_t const *sip,
+ sip_allow_t const *allow,
+ tag_type_t tag, tag_value_t value, ...);
+SOFIAPUBFUN
+int nta_check_session_content(nta_incoming_t *irq, sip_t const *sip,
+ sip_accept_t const *session_accepts,
+ tag_type_t tag, tag_value_t value, ...);
+SOFIAPUBFUN
+int nta_check_accept(nta_incoming_t *irq,
+ sip_t const *sip,
+ sip_accept_t const *acceptable,
+ sip_accept_t const **return_acceptable,
+ tag_type_t tag, tag_value_t value, ...);
+
+SOFIAPUBFUN
+int nta_check_session_expires(nta_incoming_t *irq,
+ sip_t const *sip,
+ sip_time_t my_min_se,
+ tag_type_t tag, tag_value_t value, ...);
+
+/* ----------------------------------------------------------------------
+ * 7) Prototypes for outgoing transactions
+ */
+typedef int nta_response_f(nta_outgoing_magic_t *magic,
+ nta_outgoing_t *request,
+ sip_t const *sip);
+
+SOFIAPUBFUN
+nta_outgoing_t *nta_outgoing_tcreate(nta_leg_t *leg,
+ nta_response_f *callback,
+ nta_outgoing_magic_t *magic,
+ url_string_t const *route_url,
+ sip_method_t method,
+ char const *method_name,
+ url_string_t const *request_uri,
+ tag_type_t tag, tag_value_t value, ...);
+
+SOFIAPUBFUN
+nta_outgoing_t *nta_outgoing_mcreate(nta_agent_t *agent,
+ nta_response_f *callback,
+ nta_outgoing_magic_t *magic,
+ url_string_t const *route_url,
+ msg_t *msg,
+ tag_type_t tag, tag_value_t value, ...);
+
+SOFIAPUBFUN
+nta_outgoing_t *nta_outgoing_default(nta_agent_t *agent,
+ nta_response_f *callback,
+ nta_outgoing_magic_t *magic);
+
+SOFIAPUBFUN int nta_outgoing_status(nta_outgoing_t const *orq);
+SOFIAPUBFUN sip_method_t nta_outgoing_method(nta_outgoing_t const *orq);
+SOFIAPUBFUN char const *nta_outgoing_method_name(nta_outgoing_t const *orq);
+SOFIAPUBFUN uint32_t nta_outgoing_cseq(nta_outgoing_t const *orq);
+
+SOFIAPUBFUN unsigned nta_outgoing_delay(nta_outgoing_t const *orq);
+
+SOFIAPUBFUN url_t const *nta_outgoing_request_uri(nta_outgoing_t const *orq);
+SOFIAPUBFUN url_t const *nta_outgoing_route_uri(nta_outgoing_t const *orq);
+
+SOFIAPUBFUN msg_t *nta_outgoing_getresponse(nta_outgoing_t *orq);
+SOFIAPUBFUN msg_t *nta_outgoing_getrequest(nta_outgoing_t *orq);
+
+SOFIAPUBFUN
+nta_outgoing_t *nta_outgoing_tagged(nta_outgoing_t *orq,
+ nta_response_f *callback,
+ nta_outgoing_magic_t *magic,
+ char const *to_tag,
+ sip_rseq_t const *rseq);
+
+SOFIAPUBFUN int nta_outgoing_cancel(nta_outgoing_t *);
+
+SOFIAPUBFUN
+nta_outgoing_t *nta_outgoing_tcancel(nta_outgoing_t *orq,
+ nta_response_f *callback,
+ nta_outgoing_magic_t *magic,
+ tag_type_t, tag_value_t, ...);
+
+SOFIAPUBFUN void nta_outgoing_destroy(nta_outgoing_t *);
+
+SOFIAPUBFUN
+nta_outgoing_t *nta_outgoing_find(nta_agent_t const *sa,
+ msg_t const *msg,
+ sip_t const *sip,
+ sip_via_t const *v);
+
+SOFIAPUBFUN int nta_tport_keepalive(nta_outgoing_t *orq);
+
+/* ----------------------------------------------------------------------
+ * 8) Reliable provisional responses (100rel)
+ */
+
+/* UAC side */
+
+SOFIAPUBFUN
+nta_outgoing_t *nta_outgoing_prack(nta_leg_t *leg,
+ nta_outgoing_t *oorq,
+ nta_response_f *callback,
+ nta_outgoing_magic_t *magic,
+ url_string_t const *route_url,
+ sip_t const *response_to_prack,
+ tag_type_t, tag_value_t, ...);
+
+SOFIAPUBFUN uint32_t nta_outgoing_rseq(nta_outgoing_t const *orq);
+SOFIAPUBFUN int nta_outgoing_setrseq(nta_outgoing_t *orq, uint32_t rseq);
+
+/* UAS side */
+
+/** NTA reliable response */
+typedef struct nta_reliable_s nta_reliable_t;
+
+#ifndef NTA_RELIABLE_MAGIC_T
+/** Default type of application context for reliable NTA responses.
+ * Application may define this to appropriate type before including
+ * <nta.h>. */
+#define NTA_RELIABLE_MAGIC_T struct nta_reliable_magic_s
+#endif
+
+/** Application context for reliable NTA requests */
+typedef NTA_RELIABLE_MAGIC_T nta_reliable_magic_t;
+
+typedef int nta_prack_f(nta_reliable_magic_t *rmagic,
+ nta_reliable_t *rel,
+ nta_incoming_t *prack,
+ sip_t const *sip);
+
+SOFIAPUBFUN
+nta_reliable_t *nta_reliable_treply(nta_incoming_t *ireq,
+ nta_prack_f *callback,
+ nta_reliable_magic_t *rmagic,
+ int status, char const *phrase,
+ tag_type_t tag,
+ tag_value_t value, ...);
+
+SOFIAPUBFUN
+nta_reliable_t *nta_reliable_mreply(nta_incoming_t *irq,
+ nta_prack_f *callback,
+ nta_reliable_magic_t *rmagic,
+ msg_t *msg);
+
+SOFIAPUBFUN void nta_reliable_destroy(nta_reliable_t *);
+
+/* ----------------------------------------------------------------------
+ * Backward-compatibility stuff - going away soon
+ */
+
+#define nta_outgoing_tmcreate nta_outgoing_mcreate
+#define nta_msg_response_complete(msg, irq, status, phrase) \
+ nta_incoming_complete_response((irq), (msg), (status), (phrase), TAG_END())
+
+SOFIAPUBFUN void nta_msg_discard(nta_agent_t *agent, msg_t *msg);
+
+SOFIA_END_DECLS
+
+#endif
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/nta_stateless.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/nta_stateless.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,103 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef NTA_STATELESS_H
+/** Defined when <sofia-sip/nta_stateless.h> has been included. */
+#define NTA_STATELESS_H
+
+/**@file sofia-sip/nta_stateless.h
+ * @brief NTA functions for stateless SIP processing.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Sep 4 15:54:57 2001 ppessi
+ */
+
+#ifndef NTA_H
+#include <sofia-sip/nta.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/**@typedef int nta_message_f(nta_agent_magic_t *context,
+ * nta_agent_t *agent,
+ * msg_t *msg,
+ * sip_t *sip);
+ *
+ * Callback for incoming messages.
+ *
+ * The typedef nta_message_f() defines prototype for the callback functions
+ * invoked by NTA when it has received an incoming message that will be
+ * processed statelessly.
+ *
+ * The application can either discard the message by calling
+ * nta_msg_discard(), forward it by calling nta_msg_tsend() or reply to the
+ * message by calling nta_msg_treply(). When application wants to process a
+ * request statefully, it passes the message to a leg with the function
+ * nta_leg_stateful(). A new leg can be created by calling the function
+ * nta_leg_tcreate().
+ *
+ * @par Prototype
+ * @code
+ * int message_callback(nta_agent_magic_t *context,
+ * nta_agent_t *agent,
+ * msg_t *msg,
+ * sip_t *sip);
+ * @endcode
+ *
+ * @param context agent context
+ * @param agent agent handle
+ * @param msg received message
+ * @param sip contents of message
+ *
+ * @return
+ * This callback function should always return 0.
+ */
+
+/** Forward a request or response message. */
+SOFIAPUBFUN
+int nta_msg_tsend(nta_agent_t *agent, msg_t *msg, url_string_t const *u,
+ tag_type_t tag, tag_value_t value, ...);
+
+/** Reply to a request message. */
+SOFIAPUBFUN
+int nta_msg_mreply(nta_agent_t *agent,
+ msg_t *reply, sip_t *sip,
+ int status, char const *phrase,
+ msg_t *req_msg,
+ tag_type_t tag, tag_value_t value, ...);
+
+/** Reply to a request message. */
+SOFIAPUBFUN
+int nta_msg_treply(nta_agent_t *self,
+ msg_t *msg,
+ int status, char const *phrase,
+ tag_type_t tag, tag_value_t value, ...);
+
+/** ACK and BYE an unknown 200 OK response to INVITE. */
+SOFIAPUBFUN int nta_msg_ackbye(nta_agent_t *a, msg_t *msg);
+
+SOFIA_END_DECLS
+
+#endif /* !defined(NTA_STATELESS_H) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/nta_tag.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/nta_tag.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,687 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef NTA_TAG_H
+/** Defined when <sofia-sip/nta_tag.h> has been included. */
+#define NTA_TAG_H
+
+/**@file sofia-sip/nta_tag.h
+ * @brief NTA tags
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Sep 4 15:54:57 2001 ppessi
+ */
+
+#ifndef SU_TAG_H
+#include <sofia-sip/su_tag.h>
+#endif
+
+#ifndef SIP_TAG_H
+#include <sofia-sip/sip_tag.h>
+#endif
+
+#ifndef URL_TAG_H
+#include <sofia-sip/url_tag.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** List of all nta tags. */
+NTA_DLL extern tag_type_t nta_tag_list[];
+
+/** Filter tag matching any nta tag. */
+#define NTATAG_ANY() ntatag_any, ((tag_value_t)0)
+NTA_DLL extern tag_typedef_t ntatag_any;
+
+/* Tags for parameters */
+
+NTA_DLL extern tag_typedef_t ntatag_mclass;
+/** Message class used by NTA. @HI */
+#define NTATAG_MCLASS(x) ntatag_mclass, tag_ptr_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_mclass_ref;
+#define NTATAG_MCLASS_REF(x) ntatag_mclass_ref, tag_ptr_vr(&(x), (x))
+
+NTA_DLL extern tag_typedef_t ntatag_bad_req_mask;
+/** Mask for bad request messages.
+ *
+ * If an incoming request has erroneous headers matching with the mask, nta
+ * automatically returns a 400 Bad Message response to them. If no mask is
+ * specified, all requests with any bad header are dropped.
+ *
+ */
+#define NTATAG_BAD_REQ_MASK(x) ntatag_bad_req_mask, tag_uint_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_bad_req_mask_ref;
+#define NTATAG_BAD_REQ_MASK_REF(x) ntatag_bad_req_mask_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_bad_resp_mask;
+/** Mask for bad response messages.
+ *
+ * If an incoming response has erroneous headers matching with the mask, nta
+ * drops the response message. If no mask is specified, all responses with
+ * any bad header are dropped.
+ */
+#define NTATAG_BAD_RESP_MASK(x) ntatag_bad_resp_mask, tag_uint_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_bad_resp_mask_ref;
+#define NTATAG_BAD_RESP_MASK_REF(x) ntatag_bad_resp_mask_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_default_proxy;
+/** URL for (default) proxy. @HI */
+#define NTATAG_DEFAULT_PROXY(x) \
+ntatag_default_proxy, urltag_url_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_default_proxy_ref;
+#define NTATAG_DEFAULT_PROXY_REF(x) \
+ntatag_default_proxy_ref, urltag_url_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_contact;
+/** Contact used by NTA. @HI */
+#define NTATAG_CONTACT(x) \
+ntatag_contact, siptag_contact_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_contact_ref;
+#define NTATAG_CONTACT_REF(x) \
+ntatag_contact_ref, siptag_contact_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_target;
+/** Dialog target (contact) used by NTA. @HI */
+#define NTATAG_TARGET(x) \
+ntatag_target, siptag_contact_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_target_ref;
+#define NTATAG_TARGET_REF(x) \
+ntatag_target_ref, siptag_contact_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_aliases;
+/** Aliases used by NTA. @HI @deprecated */
+#define NTATAG_ALIASES(x) \
+ntatag_aliases, siptag_contact_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_aliases_ref;
+#define NTATAG_ALIASES_REF(x) \
+ntatag_aliases_ref, siptag_contact_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_branch_key;
+/** Branch key. @HI */
+#define NTATAG_BRANCH_KEY(x) \
+ntatag_branch_key, tag_str_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_branch_key_ref;
+#define NTATAG_BRANCH_KEY_REF(x) \
+ntatag_branch_key_ref, tag_str_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_ack_branch;
+/** Branch for ACKed transaction. @HI */
+#define NTATAG_ACK_BRANCH(x) \
+ntatag_ack_branch, tag_str_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_ack_branch_ref;
+#define NTATAG_ACK_BRANCH_REF(x) \
+ntatag_ack_branch_ref, tag_str_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_comp;
+/** Compression algorithm. @HI */
+#define NTATAG_COMP(x) \
+ntatag_comp, tag_str_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_comp_ref;
+#define NTATAG_COMP_REF(x) \
+ntatag_comp_ref, tag_str_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_msg;
+/** Pass a SIP message to treply()/tcreate() functions. @HI */
+#define NTATAG_MSG(x) ntatag_msg, tag_ptr_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_msg_ref;
+#define NTATAG_MSG_REF(x) ntatag_msg_ref, tag_ptr_vr(&(x), (x))
+
+NTA_DLL extern tag_typedef_t ntatag_tport;
+/** Pass a transport object to msg_tsend/msg_treply. @HI */
+#define NTATAG_TPORT(x) ntatag_tport, tag_ptr_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_tport_ref;
+#define NTATAG_TPORT_REF(x) ntatag_tport_ref, tag_ptr_vr(&(x), (x))
+
+NTA_DLL extern tag_typedef_t ntatag_remote_cseq;
+/** Remote CSeq number. @HI */
+#define NTATAG_REMOTE_CSEQ(x) ntatag_remote_cseq, tag_uint_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_remote_cseq_ref;
+#define NTATAG_REMOTE_CSEQ_REF(x) ntatag_remote_cseq_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_smime;
+/** Provide S/MIME context to NTA. @HI */
+#define NTATAG_SMIME(x) ntatag_smime, tag_ptr_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_smime_ref;
+#define NTATAG_SMIME_REF(x) ntatag_smime_ref, tag_ptr_vr(&(x), (x))
+
+NTA_DLL extern tag_typedef_t ntatag_maxsize;
+/** Maximum size of incoming message. @HI */
+#define NTATAG_MAXSIZE(x) ntatag_maxsize, tag_usize_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_maxsize_ref;
+#define NTATAG_MAXSIZE_REF(x) ntatag_maxsize_ref, tag_usize_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_udp_mtu;
+/** Maximum size of outgoing UDP request. @HI */
+#define NTATAG_UDP_MTU(x) ntatag_udp_mtu, tag_usize_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_udp_mtu_ref;
+#define NTATAG_UDP_MTU_REF(x) ntatag_udp_mtu_ref, tag_usize_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_max_forwards;
+/** Default value for @MaxForwards header.
+ *
+ * @since New in @VERSION_1_12_2.
+ * @hideinitializer
+ */
+#define NTATAG_MAX_FORWARDS(x) ntatag_max_forwards, tag_uint_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_max_forwards_ref;
+#define NTATAG_MAX_FORWARDS_REF(x) ntatag_max_forwards_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_sip_t1;
+/** Initial retransmission interval (in milliseconds) @HI */
+#define NTATAG_SIP_T1(x) ntatag_sip_t1, tag_uint_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_sip_t1_ref;
+#define NTATAG_SIP_T1_REF(x) ntatag_sip_t1_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_sip_t1x64;
+/** Transaction timeout (defaults to T1 * 64). @HI */
+#define NTATAG_SIP_T1X64(x) ntatag_sip_t1x64, tag_uint_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_sip_t1x64_ref;
+#define NTATAG_SIP_T1X64_REF(x) ntatag_sip_t1x64_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_sip_t2;
+/** Maximum retransmission interval (in milliseconds) @HI */
+#define NTATAG_SIP_T2(x) ntatag_sip_t2, tag_uint_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_sip_t2_ref;
+#define NTATAG_SIP_T2_REF(x) ntatag_sip_t2_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_sip_t4;
+/** Transaction lifetime (in milliseconds) @HI */
+#define NTATAG_SIP_T4(x) ntatag_sip_t4, tag_uint_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_sip_t4_ref;
+#define NTATAG_SIP_T4_REF(x) ntatag_sip_t4_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_progress;
+/** Progress timer for User-Agents (interval for retranmitting 1XXs) @HI */
+#define NTATAG_PROGRESS(x) ntatag_progress, tag_uint_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_progress_ref;
+#define NTATAG_PROGRESS_REF(x) ntatag_progress_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_blacklist;
+/** Add Retry-After header to internally-generated error messages. @HI */
+#define NTATAG_BLACKLIST(x) ntatag_blacklist, tag_uint_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_blacklist_ref;
+#define NTATAG_BLACKLIST_REF(x) ntatag_blacklist_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_debug_drop_prob;
+/** Packet drop probability for debugging.
+ *
+ * The packet drop probability parameter is useful mainly in proxies for
+ * debugging purposes. The stack drops an incoming message with the given
+ * probability. The range is in 0 .. 1000, 500 means p=0.5.
+ @HI */
+#define NTATAG_DEBUG_DROP_PROB(x) ntatag_debug_drop_prob, tag_uint_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_debug_drop_prob_ref;
+#define NTATAG_DEBUG_DROP_PROB_REF(x) ntatag_debug_drop_prob_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_sigcomp_options;
+/** Semicolon-separate SigComp options. @HI */
+#define NTATAG_SIGCOMP_OPTIONS(x) ntatag_sigcomp_options, tag_str_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_sigcomp_options_ref;
+#define NTATAG_SIGCOMP_OPTIONS_REF(x) ntatag_sigcomp_options_ref, tag_str_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_sigcomp_close;
+/** Close SigComp compartment after completing transaction. @HI */
+#define NTATAG_SIGCOMP_CLOSE(x) ntatag_sigcomp_close, tag_bool_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_sigcomp_close_ref;
+#define NTATAG_SIGCOMP_CLOSE_REF(x) ntatag_sigcomp_close_ref, tag_bool_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_sigcomp_aware;
+/** Indicate that the application is SigComp-aware. */
+#define NTATAG_SIGCOMP_AWARE(x) ntatag_sigcomp_aware, tag_bool_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_sigcomp_aware_ref;
+#define NTATAG_SIGCOMP_AWARE_REF(x) ntatag_sigcomp_aware_ref, tag_bool_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_sigcomp_algorithm;
+/** Specify SigComp algorithm. For example, NULL, LZSS, or LZSS-POC.
+ */
+#define NTATAG_SIGCOMP_ALGORITHM(x) ntatag_sigcomp_algorithm, tag_str_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_sigcomp_algorithm_ref;
+#define NTATAG_SIGCOMP_ALGORITHM_REF(x) \
+ntatag_sigcomp_algorithm_ref, tag_str_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_ua;
+/** If true, NTA acts as User Agent Server or Client by default. @HI */
+#define NTATAG_UA(x) ntatag_ua, tag_bool_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_ua_ref;
+#define NTATAG_UA_REF(x) ntatag_ua_ref, tag_bool_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_stateless;
+/** If true, agent processes incoming requests statelessly by default. @HI */
+#define NTATAG_STATELESS(x) ntatag_stateless, tag_bool_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_stateless_ref;
+#define NTATAG_STATELESS_REF(x) ntatag_stateless_ref, tag_bool_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_user_via;
+/** Allow application to insert Via headers. @HI */
+#define NTATAG_USER_VIA(x) ntatag_user_via, tag_bool_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_user_via_ref;
+#define NTATAG_USER_VIA_REF(x) ntatag_user_via_ref, tag_bool_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_extra_100;
+/** Respond with "100 Trying" if application has not responded. @HI */
+#define NTATAG_EXTRA_100(x) ntatag_extra_100, tag_bool_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_extra_100_ref;
+#define NTATAG_EXTRA_100_REF(x) ntatag_extra_100_ref, tag_bool_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_pass_100;
+/** Pass "100 Trying" provisional answers to the application. @HI */
+#define NTATAG_PASS_100(x) ntatag_pass_100, tag_bool_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_pass_100_ref;
+#define NTATAG_PASS_100_REF(x) ntatag_pass_100_ref, tag_bool_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_timeout_408;
+/** Generate "408 Request Timeout" response when request times out. @HI */
+#define NTATAG_TIMEOUT_408(x) ntatag_timeout_408, tag_bool_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_timeout_408_ref;
+#define NTATAG_TIMEOUT_408_REF(x) ntatag_timeout_408_ref, tag_bool_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_pass_408;
+/** Pass "408 Request Timeout" responses to client. @HI */
+#define NTATAG_PASS_408(x) ntatag_pass_408, tag_bool_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_pass_408_ref;
+#define NTATAG_PASS_408_REF(x) ntatag_pass_408_ref, tag_bool_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_no_dialog;
+/** Create a leg without dialog. @HI */
+#define NTATAG_NO_DIALOG(x) ntatag_no_dialog, tag_bool_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_no_dialog_ref;
+#define NTATAG_NO_DIALOG_REF(x) ntatag_no_dialog_ref, tag_bool_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_merge_482;
+/** Merge requests, send 482 to other requests. @HI */
+#define NTATAG_MERGE_482(x) ntatag_merge_482, tag_bool_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_merge_482_ref;
+#define NTATAG_MERGE_482_REF(x) ntatag_merge_482_ref, tag_bool_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_cancel_2543;
+/** Send a CANCEL to an INVITE without an provisional response. @HI */
+#define NTATAG_CANCEL_2543(x) ntatag_cancel_2543, tag_bool_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_cancel_2543_ref;
+#define NTATAG_CANCEL_2543_REF(x) ntatag_cancel_2543_ref, tag_bool_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_cancel_408;
+/** Do not send a CANCEL but just timeout the request. @HI */
+#define NTATAG_CANCEL_408(x) ntatag_cancel_408, tag_bool_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_cancel_408_ref;
+#define NTATAG_CANCEL_408_REF(x) ntatag_cancel_408_ref, tag_bool_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_tag_3261;
+/** When responding to requests, use unique tags. @HI */
+#define NTATAG_TAG_3261(x) ntatag_tag_3261, tag_bool_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_tag_3261_ref;
+#define NTATAG_TAG_3261_REF(x) ntatag_tag_3261_ref, tag_bool_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_use_timestamp;
+/** Use Timestamp header. @HI */
+#define NTATAG_USE_TIMESTAMP(x) ntatag_use_timestamp, tag_bool_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_use_timestamp_ref;
+#define NTATAG_USE_TIMESTAMP_REF(x) ntatag_use_timestamp_ref, tag_bool_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_method;
+/** Method name. @HI */
+#define NTATAG_METHOD(x) ntatag_method, tag_str_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_method_ref;
+#define NTATAG_METHOD_REF(x) ntatag_method_ref, tag_str_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_cancel_487;
+/** When a CANCEL is received, reply with 487 response. True by default. @HI */
+#define NTATAG_CANCEL_487(x) ntatag_cancel_487, tag_bool_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_cancel_487_ref;
+#define NTATAG_CANCEL_487_REF(x) ntatag_cancel_487_ref, tag_bool_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_rel100;
+/** Include rel100 in INVITE requests. @HI */
+#define NTATAG_REL100(x) ntatag_rel100, tag_bool_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_rel100_ref;
+#define NTATAG_REL100_REF(x) ntatag_rel100_ref, tag_bool_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_sipflags;
+/** Set SIP parser flags. @HI */
+#define NTATAG_SIPFLAGS(x) ntatag_sipflags, tag_uint_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_sipflags_ref;
+#define NTATAG_SIPFLAGS_REF(x) ntatag_sipflags_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_client_rport;
+/** Add rport at client. @HI */
+#define NTATAG_CLIENT_RPORT(x) ntatag_client_rport, tag_bool_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_client_rport_ref;
+#define NTATAG_CLIENT_RPORT_REF(x) ntatag_client_rport_ref, tag_bool_vr(&(x))
+
+#define NTATAG_RPORT(x) ntatag_client_rport, tag_bool_v((x))
+#define NTATAG_RPORT_REF(x) ntatag_client_rport_ref, tag_bool_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_server_rport;
+/** Use rport at server. @HI */
+#define NTATAG_SERVER_RPORT(x) ntatag_server_rport, tag_bool_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_server_rport_ref;
+#define NTATAG_SERVER_RPORT_REF(x) ntatag_server_rport_ref, tag_bool_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_tcp_rport;
+/** Use rport with TCP, too. @HI */
+#define NTATAG_TCP_RPORT(x) ntatag_tcp_rport, tag_bool_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_tcp_rport_ref;
+#define NTATAG_TCP_RPORT_REF(x) ntatag_tcp_rport_ref, tag_bool_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_preload;
+/** Preload by N bytes. @HI */
+#define NTATAG_PRELOAD(x) ntatag_preload, tag_uint_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_preload_ref;
+#define NTATAG_PRELOAD_REF(x) ntatag_preload_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_use_naptr;
+/** If true, try to use NAPTR records when resolving. @HI */
+#define NTATAG_USE_NAPTR(x) ntatag_use_naptr, tag_bool_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_use_naptr_ref;
+#define NTATAG_USE_NAPTR_REF(x) ntatag_use_naptr_ref, tag_bool_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_use_srv;
+/** If true, try to use SRV records when resolving. @HI */
+#define NTATAG_USE_SRV(x) ntatag_use_srv, tag_bool_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_use_srv_ref;
+#define NTATAG_USE_SRV_REF(x) ntatag_use_srv_ref, tag_bool_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_rseq;
+/** RSeq value for nta_outgoing_prack(), @HI */
+#define NTATAG_RSEQ(x) ntatag_rseq, tag_uint_v((x))
+
+NTA_DLL extern tag_typedef_t ntatag_rseq_ref;
+#define NTATAG_RSEQ_REF(x) ntatag_rseq_ref, tag_uint_vr(&(x))
+
+/* ====================================================================== */
+/* Tags for statistics. */
+
+NTA_DLL extern tag_typedef_t ntatag_s_irq_hash;
+#define NTATAG_S_IRQ_HASH(x) ntatag_s_irq_hash, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_irq_hash_ref;
+#define NTATAG_S_IRQ_HASH_REF(x) ntatag_s_irq_hash_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_orq_hash;
+#define NTATAG_S_ORQ_HASH(x) ntatag_s_orq_hash, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_orq_hash_ref;
+#define NTATAG_S_ORQ_HASH_REF(x) ntatag_s_orq_hash_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_leg_hash;
+#define NTATAG_S_LEG_HASH(x) ntatag_s_leg_hash, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_leg_hash_ref;
+#define NTATAG_S_LEG_HASH_REF(x) ntatag_s_leg_hash_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_irq_hash_used;
+#define NTATAG_S_IRQ_HASH_USED(x) ntatag_s_irq_hash_used, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_irq_hash_used_ref;
+#define NTATAG_S_IRQ_HASH_USED_REF(x) \
+ntatag_s_irq_hash_used_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_orq_hash_used;
+#define NTATAG_S_ORQ_HASH_USED(x) ntatag_s_orq_hash_used, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_orq_hash_used_ref;
+#define NTATAG_S_ORQ_HASH_USED_REF(x) \
+ntatag_s_orq_hash_used_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_leg_hash_used;
+#define NTATAG_S_LEG_HASH_USED(x) ntatag_s_leg_hash_used, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_leg_hash_used_ref;
+#define NTATAG_S_LEG_HASH_USED_REF(x) \
+ntatag_s_leg_hash_used_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_recv_msg;
+#define NTATAG_S_RECV_MSG(x) ntatag_s_recv_msg, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_recv_msg_ref;
+#define NTATAG_S_RECV_MSG_REF(x) ntatag_s_recv_msg_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_recv_request;
+#define NTATAG_S_RECV_REQUEST(x) ntatag_s_recv_request, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_recv_request_ref;
+#define NTATAG_S_RECV_REQUEST_REF(x)\
+ ntatag_s_recv_request_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_recv_response;
+#define NTATAG_S_RECV_RESPONSE(x) ntatag_s_recv_response, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_recv_response_ref;
+#define NTATAG_S_RECV_RESPONSE_REF(x)\
+ ntatag_s_recv_response_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_bad_message;
+#define NTATAG_S_BAD_MESSAGE(x) ntatag_s_bad_message, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_bad_message_ref;
+#define NTATAG_S_BAD_MESSAGE_REF(x)\
+ ntatag_s_bad_message_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_bad_request;
+#define NTATAG_S_BAD_REQUEST(x) ntatag_s_bad_request, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_bad_request_ref;
+#define NTATAG_S_BAD_REQUEST_REF(x)\
+ ntatag_s_bad_request_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_bad_response;
+#define NTATAG_S_BAD_RESPONSE(x) ntatag_s_bad_response, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_bad_response_ref;
+#define NTATAG_S_BAD_RESPONSE_REF(x)\
+ ntatag_s_bad_response_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_drop_request;
+#define NTATAG_S_DROP_REQUEST(x) ntatag_s_drop_request, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_drop_request_ref;
+#define NTATAG_S_DROP_REQUEST_REF(x)\
+ ntatag_s_drop_request_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_drop_response;
+#define NTATAG_S_DROP_RESPONSE(x) ntatag_s_drop_response, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_drop_response_ref;
+#define NTATAG_S_DROP_RESPONSE_REF(x)\
+ ntatag_s_drop_response_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_client_tr;
+#define NTATAG_S_CLIENT_TR(x) ntatag_s_client_tr, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_client_tr_ref;
+#define NTATAG_S_CLIENT_TR_REF(x)\
+ ntatag_s_client_tr_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_server_tr;
+#define NTATAG_S_SERVER_TR(x) ntatag_s_server_tr, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_server_tr_ref;
+#define NTATAG_S_SERVER_TR_REF(x)\
+ ntatag_s_server_tr_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_dialog_tr;
+#define NTATAG_S_DIALOG_TR(x) ntatag_s_dialog_tr, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_dialog_tr_ref;
+#define NTATAG_S_DIALOG_TR_REF(x)\
+ ntatag_s_dialog_tr_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_acked_tr;
+#define NTATAG_S_ACKED_TR(x) ntatag_s_acked_tr, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_acked_tr_ref;
+#define NTATAG_S_ACKED_TR_REF(x) ntatag_s_acked_tr_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_canceled_tr;
+#define NTATAG_S_CANCELED_TR(x) ntatag_s_canceled_tr, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_canceled_tr_ref;
+#define NTATAG_S_CANCELED_TR_REF(x) \
+ ntatag_s_canceled_tr_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_trless_request;
+#define NTATAG_S_TRLESS_REQUEST(x) ntatag_s_trless_request, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_trless_request_ref;
+#define NTATAG_S_TRLESS_REQUEST_REF(x)\
+ ntatag_s_trless_request_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_trless_to_tr;
+#define NTATAG_S_TRLESS_TO_TR(x) ntatag_s_trless_to_tr, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_trless_to_tr_ref;
+#define NTATAG_S_TRLESS_TO_TR_REF(x)\
+ ntatag_s_trless_to_tr_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_trless_response;
+#define NTATAG_S_TRLESS_RESPONSE(x) ntatag_s_trless_response, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_trless_response_ref;
+#define NTATAG_S_TRLESS_RESPONSE_REF(x)\
+ ntatag_s_trless_response_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_trless_200;
+#define NTATAG_S_TRLESS_200(x) ntatag_s_trless_200, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_trless_200_ref;
+#define NTATAG_S_TRLESS_200_REF(x)\
+ ntatag_s_trless_200_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_merged_request;
+#define NTATAG_S_MERGED_REQUEST(x) ntatag_s_merged_request, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_merged_request_ref;
+#define NTATAG_S_MERGED_REQUEST_REF(x)\
+ ntatag_s_merged_request_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_sent_msg;
+#define NTATAG_S_SENT_MSG(x) ntatag_s_sent_msg, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_sent_msg_ref;
+#define NTATAG_S_SENT_MSG_REF(x)\
+ ntatag_s_sent_msg_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_sent_request;
+#define NTATAG_S_SENT_REQUEST(x) ntatag_s_sent_request, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_sent_request_ref;
+#define NTATAG_S_SENT_REQUEST_REF(x)\
+ ntatag_s_sent_request_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_sent_response;
+#define NTATAG_S_SENT_RESPONSE(x) ntatag_s_sent_response, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_sent_response_ref;
+#define NTATAG_S_SENT_RESPONSE_REF(x)\
+ ntatag_s_sent_response_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_retry_request;
+#define NTATAG_S_RETRY_REQUEST(x) ntatag_s_retry_request, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_retry_request_ref;
+#define NTATAG_S_RETRY_REQUEST_REF(x)\
+ ntatag_s_retry_request_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_retry_response;
+#define NTATAG_S_RETRY_RESPONSE(x) ntatag_s_retry_response, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_retry_response_ref;
+#define NTATAG_S_RETRY_RESPONSE_REF(x)\
+ ntatag_s_retry_response_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_recv_retry;
+#define NTATAG_S_RECV_RETRY(x) ntatag_s_recv_retry, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_recv_retry_ref;
+#define NTATAG_S_RECV_RETRY_REF(x)\
+ ntatag_s_recv_retry_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_tout_request;
+#define NTATAG_S_TOUT_REQUEST(x) ntatag_s_tout_request, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_tout_request_ref;
+#define NTATAG_S_TOUT_REQUEST_REF(x)\
+ ntatag_s_tout_request_ref, tag_uint_vr(&(x))
+
+NTA_DLL extern tag_typedef_t ntatag_s_tout_response;
+#define NTATAG_S_TOUT_RESPONSE(x) ntatag_s_tout_response, tag_uint_v(x)
+
+NTA_DLL extern tag_typedef_t ntatag_s_tout_response_ref;
+#define NTATAG_S_TOUT_RESPONSE_REF(x)\
+ ntatag_s_tout_response_ref, tag_uint_vr(&(x))
+
+SOFIA_END_DECLS
+
+#endif /* !defined(nta_tag_h) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/nta_tport.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/nta_tport.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,85 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef NTA_TPORT_H
+/** Defined when <sofia-sip/nta_tport.h> has been included. */
+#define NTA_TPORT_H
+
+/**
+ * @file sofia-sip/nta_tport.h
+ * @brief Transport and SigComp handling
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Oct 7 20:04:39 2004 ppessi
+ *
+ */
+
+#ifndef NTA_H
+#include <sofia-sip/nta.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+struct tport_s;
+
+#ifndef TPORT_T
+#define TPORT_T struct tport_s
+typedef TPORT_T tport_t;
+#endif
+
+#ifndef NTA_UPDATE_MAGIC_T
+#define NTA_UPDATE_MAGIC_T void
+#endif
+typedef NTA_UPDATE_MAGIC_T nta_update_magic_t;
+
+struct sigcomp_compartment;
+struct sigcomp_udvm;
+
+#define nta_transport nta_incoming_transport
+
+SOFIAPUBFUN
+tport_t *nta_incoming_transport(nta_agent_t *, nta_incoming_t *, msg_t *msg);
+
+SOFIAPUBFUN
+struct sigcomp_compartment *nta_incoming_compartment(nta_incoming_t *irq);
+
+SOFIAPUBFUN tport_t *nta_outgoing_transport(nta_outgoing_t *orq);
+
+SOFIAPUBFUN
+struct sigcomp_compartment *
+nta_outgoing_compartment(nta_outgoing_t *orq);
+
+SOFIAPUBFUN void nta_compartment_decref(struct sigcomp_compartment **);
+
+typedef void nta_update_tport_f(nta_update_magic_t *, nta_agent_t *);
+
+SOFIAPUBFUN
+int nta_agent_bind_tport_update(nta_agent_t *agent,
+ nta_update_magic_t *magic,
+ nta_update_tport_f *);
+
+SOFIA_END_DECLS
+
+#endif /* !defined NTA_TPORT_H */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/sl_utils.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/sl_utils.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,84 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SL_UTILS_H
+/** Defined when <sofia-sip/sl_utils.h> has been included. */
+#define SL_UTILS_H
+
+/**@ingroup sl_utils
+ *
+ * @file sofia-sip/sl_utils.h @brief Prototypes for SIP helper functions.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Oct 5 15:38:39 2000 ppessi
+ */
+
+#include <stdio.h>
+
+#ifndef STRING0_H
+#include <sofia-sip/string0.h>
+#endif
+
+#ifndef SIP_H
+#include <sofia-sip/sip.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+#ifndef SU_LOG_T
+#define SU_LOG_T
+typedef struct su_log_s su_log_t;
+#endif
+
+/* Read from file */
+SOFIAPUBFUN sip_payload_t *sl_read_payload(su_home_t *home, char const *fname);
+SOFIAPUBFUN sip_payload_t *sl_fread_payload(su_home_t *home, FILE *);
+
+/* Printing functions */
+SOFIAPUBFUN void
+sl_message_log(FILE *, char const *prefix, sip_t const *, int details);
+SOFIAPUBFUN issize_t
+sl_header_print(FILE *, char const *fmt, sip_header_t const *h),
+sl_from_print(FILE *, char const *fmt, sip_from_t const *from),
+sl_to_print(FILE *, char const *fmt, sip_to_t const *to),
+sl_contact_print(FILE *, char const *fmt, sip_contact_t const *m),
+sl_allow_print(FILE *, char const *fmt, sip_allow_t const *g),
+sl_payload_print(FILE *, char const *prefix, sip_payload_t const *pl),
+sl_via_print(FILE *, char const *fmt, sip_via_t const *v);
+
+/* Logging functions */
+SOFIAPUBFUN void
+sl_sip_log(su_log_t*, int lvl, char const *, sip_t const *, int details),
+sl_header_log(su_log_t *, int lvl, char const *, sip_header_t const *h),
+sl_from_log(su_log_t *, int lvl, char const *, sip_from_t const *from),
+sl_to_log(su_log_t *, int lvl, char const *, sip_to_t const *to),
+sl_contact_log(su_log_t *, int lvl, char const *, sip_contact_t const *m),
+sl_allow_log(su_log_t *, int, char const *, sip_allow_t const *g),
+sl_via_log(su_log_t *, int, char const *, sip_via_t const *v),
+sl_payload_log(su_log_t *, int, char const *, sip_payload_t const *pl);
+
+SOFIA_END_DECLS
+
+#endif
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/test_nta.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/test_nta.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,3485 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@internal
+ * @CFILE test_nta.c
+ *
+ * Test functions for NTA.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Aug 21 15:18:26 2001 ppessi
+ */
+
+#include "config.h"
+
+typedef struct agent_t agent_t;
+
+#define SU_ROOT_MAGIC_T agent_t
+
+#include <sofia-sip/su_wait.h>
+
+#include <msg_internal.h>
+
+#define NTA_AGENT_MAGIC_T agent_t
+#define NTA_LEG_MAGIC_T agent_t
+#define NTA_OUTGOING_MAGIC_T agent_t
+#define NTA_INCOMING_MAGIC_T agent_t
+#define NTA_RELIABLE_MAGIC_T agent_t
+
+#include "sofia-sip/nta.h"
+#include "nta_internal.h"
+#include <sofia-sip/sip_header.h>
+#include <sofia-sip/sip_tag.h>
+#include <sofia-sip/sip_status.h>
+#include <sofia-sip/tport.h>
+#include <sofia-sip/htable.h>
+#include <sofia-sip/sresolv.h>
+#include <sofia-sip/su_log.h>
+#include <sofia-sip/sofia_features.h>
+#include <sofia-sip/hostdomain.h>
+
+#include <sofia-sip/string0.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <stdio.h>
+#include <assert.h>
+#include <unistd.h>
+
+SOFIAPUBVAR su_log_t nta_log[];
+SOFIAPUBVAR su_log_t tport_log[];
+
+int tstflags = 0;
+#define TSTFLAGS tstflags
+
+#include <sofia-sip/tstdef.h>
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+#define __func__ name
+#endif
+
+#define NONE ((void *)-1)
+
+struct sigcomp_compartment;
+
+char const name[] = "test_nta";
+
+struct agent_t {
+ su_home_t ag_home[1];
+ int ag_flags;
+ su_root_t *ag_root;
+ msg_mclass_t *ag_mclass;
+ nta_agent_t *ag_agent;
+
+ url_string_t *ag_obp; /**< Outbound proxy. */
+
+ nta_leg_t *ag_server_leg; /**< Leg for sip:%@% */
+ nta_leg_t *ag_default_leg; /**< Leg for rest */
+
+ unsigned ag_drop;
+
+ nta_outgoing_t *ag_orq;
+ int ag_status;
+
+ char const *ag_comp;
+ struct sigcomp_compartment *ag_client_compartment;
+
+ /* Server side */
+ int ag_response; /**< What we answer by default */
+ nta_incoming_t *ag_irq;
+
+ struct sigcomp_compartment *ag_server_compartment;
+
+ char const *ag_m;
+
+ sip_contact_t const *ag_contact;
+ sip_from_t *ag_alice;
+ sip_to_t *ag_bob;
+
+ sip_contact_t *ag_m_alice;
+ sip_contact_t *ag_m_bob;
+ sip_contact_t *ag_aliases;
+
+ nta_leg_t *ag_alice_leg;
+ nta_leg_t *ag_bob_leg;
+
+ msg_t *ag_request;
+
+ nta_leg_t *ag_expect_leg;
+ nta_leg_t *ag_latest_leg;
+ nta_leg_t *ag_call_leg;
+ nta_leg_t *ag_tag_remote; /**< If this is set, outgoing_callback()
+ * tags it with the tag from remote.
+ */
+ int ag_tag_status; /**< Which response established dialog */
+ msg_param_t ag_call_tag; /**< Tag used to establish dialog */
+
+ nta_reliable_t *ag_reliable;
+
+ sip_via_t *ag_out_via; /**< Outgoing via */
+ sip_via_t *ag_in_via; /**< Incoming via */
+
+ sip_content_type_t *ag_content_type;
+ sip_payload_t *ag_payload;
+
+ msg_t *ag_probe_msg;
+
+ /* Dummy servers */
+ char const *ag_sink_port;
+ su_socket_t ag_sink_socket, ag_down_socket;
+};
+
+static int test_init(agent_t *ag, char const *resolv_conf);
+static int test_deinit(agent_t *ag);
+static int test_bad_messages(agent_t *ag);
+static int test_routing(agent_t *ag);
+static int test_tports(agent_t *ag);
+static int test_resolv(agent_t *ag, char const *resolv_conf);
+static int test_dialog(agent_t *ag);
+static int test_call(agent_t *ag);
+static int test_prack(agent_t *ag);
+static int test_fix_467(agent_t *ag);
+
+static int test_for_ack(agent_t *ag,
+ nta_incoming_t *irq,
+ sip_t const *sip);
+static int test_for_ack_or_timeout(agent_t *ag,
+ nta_incoming_t *irq,
+ sip_t const *sip);
+
+int agent_callback(agent_t *ag,
+ nta_agent_t *nta,
+ msg_t *msg,
+ sip_t *sip)
+{
+ if (tstflags & tst_verbatim) {
+ if (sip->sip_request) {
+ printf("%s: %s: %s " URL_PRINT_FORMAT " %s\n",
+ name, __func__, sip->sip_request->rq_method_name,
+ URL_PRINT_ARGS(sip->sip_request->rq_url),
+ sip->sip_request->rq_version);
+ }
+ else {
+ printf("%s: %s: %s %03d %s\n", name, __func__,
+ sip->sip_status->st_version,
+ sip->sip_status->st_status,
+ sip->sip_status->st_phrase);
+ }
+ }
+
+ msg_destroy(msg);
+
+ return 0;
+}
+
+static
+void leg_match(agent_t *ag, nta_leg_t *leg, int always, char const *func)
+{
+ char const *match = "unknown leg";
+
+ if (!always && (tstflags & tst_verbatim) != tst_verbatim)
+ return;
+
+ if (leg == ag->ag_default_leg)
+ match = "ag_default_leg";
+ else if (leg == ag->ag_server_leg)
+ match = "ag_server_leg";
+ else if (leg == ag->ag_alice_leg)
+ match = "ag_alice_leg";
+ else if (leg == ag->ag_bob_leg)
+ match = "ag_bob_leg";
+
+ printf("%s: %s: %smatched with %s\n", name, func,
+ always ? "mis" : "", match);
+}
+
+static
+void leg_zap(agent_t *ag, nta_leg_t *leg)
+{
+ if (leg == ag->ag_default_leg)
+ ag->ag_default_leg = NULL;
+ else if (leg == ag->ag_server_leg)
+ ag->ag_server_leg = NULL;
+ else if (leg == ag->ag_alice_leg)
+ ag->ag_alice_leg = NULL;
+ else if (leg == ag->ag_bob_leg)
+ ag->ag_bob_leg = NULL;
+ else
+ printf("%s:%u: %s: did not exist\n",
+ __FILE__, __LINE__, __func__);
+
+ nta_leg_destroy(leg);
+}
+
+
+int leg_callback_200(agent_t *ag,
+ nta_leg_t *leg,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ if (tstflags & tst_verbatim) {
+ printf("%s: %s: %s " URL_PRINT_FORMAT " %s\n",
+ name, __func__, sip->sip_request->rq_method_name,
+ URL_PRINT_ARGS(sip->sip_request->rq_url),
+ sip->sip_request->rq_version);
+ }
+
+ if (!sip->sip_content_length ||
+ !sip->sip_via ||
+ !sip->sip_from || !sip->sip_from->a_tag)
+ return 500;
+
+ if (ag->ag_in_via == NULL)
+ ag->ag_in_via = sip_via_dup(ag->ag_home, sip->sip_via);
+
+ if (ag->ag_request == NULL)
+ ag->ag_request = nta_incoming_getrequest(irq);
+
+ ag->ag_latest_leg = leg;
+
+ if (ag->ag_expect_leg && leg != ag->ag_expect_leg) {
+ leg_match(ag, leg, 1, __func__);
+ return 500;
+ }
+ leg_match(ag, leg, 0, __func__);
+
+ if (sip->sip_request->rq_method == sip_method_bye) {
+ leg_zap(ag, leg);
+ }
+
+ return 200;
+}
+
+int leg_callback_500(agent_t *ag,
+ nta_leg_t *leg,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ if (tstflags & tst_verbatim) {
+ printf("%s: %s: %s " URL_PRINT_FORMAT " %s\n",
+ name, __func__, sip->sip_request->rq_method_name,
+ URL_PRINT_ARGS(sip->sip_request->rq_url),
+ sip->sip_request->rq_version);
+ }
+
+ return 500;
+}
+
+int new_leg_callback_200(agent_t *ag,
+ nta_leg_t *leg,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ if (tstflags & tst_verbatim) {
+ printf("%s: %s: %s " URL_PRINT_FORMAT " %s\n",
+ name, __func__, sip->sip_request->rq_method_name,
+ URL_PRINT_ARGS(sip->sip_request->rq_url),
+ sip->sip_request->rq_version);
+ }
+
+ if (!sip->sip_content_length ||
+ !sip->sip_via ||
+ !sip->sip_from || !sip->sip_from->a_tag)
+ return 500;
+
+ ag->ag_latest_leg = leg;
+
+ if (ag->ag_expect_leg && leg != ag->ag_expect_leg) {
+ leg_match(ag, leg, 1, __func__);
+ return 500;
+ }
+ leg_match(ag, leg, 0, __func__);
+
+ ag->ag_bob_leg = nta_leg_tcreate(ag->ag_agent,
+ leg_callback_200,
+ ag,
+ URLTAG_URL(sip->sip_request->rq_url),
+ SIPTAG_CALL_ID(sip->sip_call_id),
+ SIPTAG_FROM(sip->sip_to),
+ SIPTAG_TO(sip->sip_from),
+ TAG_END());
+ if (!ag->ag_bob_leg ||
+ !nta_leg_tag(ag->ag_bob_leg, NULL) ||
+ !nta_leg_get_tag(ag->ag_bob_leg) ||
+ !nta_incoming_tag(irq, nta_leg_get_tag(ag->ag_bob_leg)))
+ return 500;
+
+ return 200;
+}
+
+
+int outgoing_callback(agent_t *ag,
+ nta_outgoing_t *orq,
+ sip_t const *sip)
+{
+ BEGIN();
+
+ int status = sip->sip_status->st_status;
+
+ if (tstflags & tst_verbatim) {
+ printf("%s: %s: %s %03d %s\n", name, __func__,
+ sip->sip_status->st_version,
+ sip->sip_status->st_status,
+ sip->sip_status->st_phrase);
+ }
+
+ TEST_P(orq, ag->ag_orq);
+
+ ag->ag_status = status;
+
+ if (status < 200)
+ return 0;
+
+ if (ag->ag_comp) {
+ nta_compartment_decref(&ag->ag_client_compartment);
+ ag->ag_client_compartment = nta_outgoing_compartment(orq);
+ }
+
+ if (ag->ag_out_via == NULL)
+ ag->ag_out_via = sip_via_dup(ag->ag_home, sip->sip_via);
+
+ if (ag->ag_tag_remote) {
+ TEST_S(nta_leg_rtag(ag->ag_tag_remote, sip->sip_to->a_tag),
+ sip->sip_to->a_tag);
+ ag->ag_tag_remote = NULL;
+ }
+
+ TEST_1(sip->sip_to && sip->sip_to->a_tag);
+
+ nta_outgoing_destroy(orq);
+ ag->ag_orq = NULL;
+
+ END();
+}
+
+static
+int test_magic_branch(agent_t *ag, sip_t const *sip)
+{
+ BEGIN();
+
+ if (sip) {
+ TEST_1(sip->sip_via);
+ TEST_S(sip->sip_via->v_branch, "MagicalBranch");
+ }
+
+ END();
+}
+
+static
+int magic_callback(agent_t *ag,
+ nta_outgoing_t *orq,
+ sip_t const *sip)
+{
+ test_magic_branch(ag, sip);
+ return outgoing_callback(ag, orq, sip);
+}
+
+void
+nta_test_run(agent_t *ag)
+{
+ for (ag->ag_status = 0; ag->ag_status < 200;) {
+ if (tstflags & tst_verbatim) {
+ fputs(".", stdout); fflush(stdout);
+ }
+ su_root_step(ag->ag_root, 500L);
+ }
+}
+
+#include <sofia-sip/msg_mclass.h>
+
+int test_init(agent_t *ag, char const *resolv_conf)
+{
+ char const *contact = "sip:*:*;comp=sigcomp";
+ su_sockaddr_t su;
+ socklen_t sulen, sulen0;
+ su_socket_t s;
+ int af;
+
+ BEGIN();
+
+ TEST_1(ag->ag_root = su_root_create(ag));
+
+ TEST_1(ag->ag_mclass = msg_mclass_clone(sip_default_mclass(), 0, 0));
+
+#if SU_HAVE_IN6
+ if (str0cmp(getenv("ipv6"), "true") == 0) {
+ contact = "sip:[::]:*;comp=sigcomp";
+ af = AF_INET6, sulen0 = sizeof (struct sockaddr_in6);
+ }
+ else {
+ af = AF_INET, sulen0 = sizeof (struct sockaddr_in);
+ contact = "sip:0.0.0.0:*;comp=sigcomp";
+ }
+#else
+ af = AF_INET, sulen0 = sizeof (struct sockaddr_in);
+ contact = "sip:0.0.0.0:*;comp=sigcomp";
+#endif
+
+ if (ag->ag_m)
+ contact = ag->ag_m;
+ else if (getenv("SIPCONTACT"))
+ contact = getenv("SIPCONTACT");
+
+ /* Sink server */
+ s = socket(af, SOCK_DGRAM, 0); TEST_1(s != INVALID_SOCKET);
+ memset(&su, 0, sulen = sulen0);
+ su.su_family = af;
+ if (getenv("sink")) {
+ su.su_port = htons(atoi(getenv("sink")));
+ }
+ TEST_1(bind(s, &su.su_sa, sulen) < 0 ? (perror("bind"), 0) : 1);
+ TEST_1(getsockname(s, &su.su_sa, &sulen) == 0);
+
+ ag->ag_sink_port = su_sprintf(ag->ag_home, "%u", ntohs(su.su_sin.sin_port));
+ ag->ag_sink_socket = s;
+
+ /* Down server */
+ s = socket(af, SOCK_STREAM, 0); TEST_1(s != INVALID_SOCKET);
+ memset(&su, 0, sulen = sulen0);
+ su.su_family = af;
+ if (getenv("down")) {
+ su.su_port = htons(atoi(getenv("down")));
+ }
+ TEST_1(bind(s, &su.su_sa, sulen) < 0 ? (perror("bind"), 0) : 1);
+ ag->ag_down_socket = s;
+
+ /* Create agent */
+ TEST_1(ag->ag_agent = nta_agent_create(ag->ag_root,
+ (url_string_t *)contact,
+ NULL,
+ NULL,
+ NTATAG_MCLASS(ag->ag_mclass),
+ NTATAG_USE_TIMESTAMP(1),
+ SRESTAG_RESOLV_CONF(resolv_conf),
+ NTATAG_USE_NAPTR(0),
+ NTATAG_USE_SRV(0),
+ NTATAG_PRELOAD(2048),
+ TAG_END()));
+
+ {
+ /* Initialize our headers */
+ sip_from_t from[1];
+ sip_to_t to[1];
+ sip_contact_t m[1];
+
+ sip_from_init(from);
+ sip_to_init(to);
+ sip_contact_init(m);
+
+ TEST_1(ag->ag_contact = nta_agent_contact(ag->ag_agent));
+
+ *m->m_url = *ag->ag_contact->m_url;
+ m->m_url->url_user = "bob";
+ TEST_1(ag->ag_m_bob = sip_contact_dup(ag->ag_home, m));
+
+ to->a_display = "Bob";
+ *to->a_url = *ag->ag_contact->m_url;
+ to->a_url->url_user = "bob";
+ to->a_url->url_port = NULL;
+ TEST_1(ag->ag_bob = sip_to_dup(ag->ag_home, to));
+
+ *m->m_url = *ag->ag_contact->m_url;
+ m->m_url->url_user = "alice";
+ TEST_1(ag->ag_m_alice = sip_contact_dup(ag->ag_home, m));
+
+ from->a_display = "Alice";
+ *from->a_url = *ag->ag_contact->m_url;
+ from->a_url->url_user = "alice";
+ from->a_url->url_port = NULL;
+ TEST_1(ag->ag_alice = sip_from_dup(ag->ag_home, from));
+ }
+ {
+ char const data[] =
+ "v=0\r\n"
+ "o=- 425432 423412 IN IP4 127.0.0.1\r\n"
+ "s= \r\n"
+ "c=IN IP4 127.0.0.1\r\n"
+ "m=5004 audio 8 0\r\n";
+
+ ag->ag_content_type = sip_content_type_make(ag->ag_home, "application/sdp");
+ ag->ag_payload = sip_payload_make(ag->ag_home, data);
+ }
+
+ {
+ sip_contact_t *m;
+
+ ag->ag_aliases =
+ sip_contact_make(ag->ag_home, "sip:127.0.0.1, sip:localhost, sip:[::1]");
+ TEST_1(ag->ag_aliases);
+ TEST_1(ag->ag_aliases->m_next);
+ TEST_1(ag->ag_aliases->m_next->m_next);
+ TEST_P(ag->ag_aliases->m_next->m_next->m_next, NULL);
+
+ for (m = ag->ag_aliases; m; m = m->m_next)
+ m->m_url->url_port = ag->ag_contact->m_url->url_port;
+
+ TEST_1(m = sip_contact_dup(ag->ag_home, ag->ag_contact));
+
+ m->m_next = ag->ag_aliases;
+ ag->ag_aliases = m;
+
+ TEST(nta_agent_set_params(ag->ag_agent,
+ NTATAG_ALIASES(ag->ag_aliases),
+ NTATAG_REL100(1),
+ NTATAG_UA(1),
+ NTATAG_USE_NAPTR(1),
+ NTATAG_USE_SRV(1),
+ NTATAG_MAX_FORWARDS(20),
+ TAG_END()),
+ 6);
+
+ TEST(nta_agent_set_params(ag->ag_agent,
+ NTATAG_ALIASES(ag->ag_aliases),
+ NTATAG_DEFAULT_PROXY("sip:127.0.0.1"),
+ TAG_END()), 2);
+
+ TEST(nta_agent_set_params(ag->ag_agent,
+ NTATAG_ALIASES(ag->ag_aliases),
+ NTATAG_DEFAULT_PROXY(NULL),
+ TAG_END()), 2);
+
+ TEST(nta_agent_set_params(ag->ag_agent,
+ NTATAG_DEFAULT_PROXY("tel:+35878008000"),
+ TAG_END()), -1);
+
+ }
+
+ {
+ url_t url[1];
+
+ /* Create the server leg */
+ *url = *ag->ag_aliases->m_url;
+ url->url_user = "%";
+ TEST_1(ag->ag_server_leg = nta_leg_tcreate(ag->ag_agent,
+ leg_callback_200,
+ ag,
+ NTATAG_NO_DIALOG(1),
+ URLTAG_URL(url),
+ TAG_END()));
+ }
+
+ END();
+}
+
+int test_reinit(agent_t *ag)
+{
+ BEGIN();
+ /* Create a new default leg */
+ nta_leg_destroy(ag->ag_default_leg), ag->ag_default_leg = NULL;
+ TEST_1(ag->ag_default_leg = nta_leg_tcreate(ag->ag_agent,
+ leg_callback_200,
+ ag,
+ NTATAG_NO_DIALOG(1),
+ TAG_END()));
+ END();
+}
+
+int test_deinit(agent_t *ag)
+{
+ BEGIN();
+
+ if (ag->ag_request) msg_destroy(ag->ag_request), ag->ag_request = NULL;
+
+ su_free(ag->ag_home, ag->ag_in_via), ag->ag_in_via = NULL;
+
+ nta_leg_destroy(ag->ag_alice_leg);
+ nta_leg_destroy(ag->ag_bob_leg);
+ nta_leg_destroy(ag->ag_default_leg);
+ nta_leg_destroy(ag->ag_server_leg);
+
+ nta_agent_destroy(ag->ag_agent);
+ su_root_destroy(ag->ag_root);
+
+ su_free(ag->ag_home, (void *)ag->ag_sink_port), ag->ag_sink_port = NULL;
+
+ free(ag->ag_mclass), ag->ag_mclass = NULL;
+
+ END();
+}
+
+static
+int readfile(FILE *f, void **contents)
+{
+ /* Read in whole (binary!) file */
+ char *buffer = NULL;
+ long size;
+ size_t len;
+
+ /* Read whole file in */
+ if (fseek(f, 0, SEEK_END) < 0 ||
+ (size = ftell(f)) < 0 ||
+ fseek(f, 0, SEEK_SET) < 0 ||
+ (long)(len = (size_t)size) != size) {
+ fprintf(stderr, "%s: unable to determine file size (%s)\n",
+ __func__, strerror(errno));
+ return -1;
+ }
+
+ if (!(buffer = malloc(len + 2)) ||
+ fread(buffer, 1, len, f) != len) {
+ fprintf(stderr, "%s: unable to read file (%s)\n", __func__, strerror(errno));
+ if (buffer)
+ free(buffer);
+ return -1;
+ }
+
+ buffer[len] = '\0';
+
+ *contents = buffer;
+
+ return len;
+}
+
+#if HAVE_DIRENT_H
+#include <dirent.h>
+#endif
+
+static int test_bad_messages(agent_t *ag)
+{
+#if HAVE_DIRENT_H
+ DIR *dir;
+ struct dirent *d;
+ char name[PATH_MAX + 1] = "../sip/tests/";
+ size_t offset;
+ char const *host, *port;
+ su_addrinfo_t *ai, hints[1];
+ su_socket_t s;
+ su_sockaddr_t su[1];
+ socklen_t sulen;
+ char via[64];
+ size_t vlen;
+ int i;
+
+ dir = opendir(name);
+ if (dir == NULL && getenv("srcdir")) {
+ strncpy(name, getenv("srcdir"), PATH_MAX);
+ strncat(name, "/../sip/tests/", PATH_MAX);
+ dir = opendir(name);
+ }
+
+ if (dir == NULL) {
+ fprintf(stderr, "test_nta: cannot find sip torture messages\n");
+ fprintf(stderr, "test_nta: tried %s\n", name);
+ return 0;
+ }
+
+ offset = strlen(name);
+
+ BEGIN();
+
+ TEST_1(ag->ag_default_leg = nta_leg_tcreate(ag->ag_agent,
+ leg_callback_500,
+ ag,
+ NTATAG_NO_DIALOG(1),
+ TAG_END()));
+
+ host = ag->ag_contact->m_url->url_host;
+ if (host_is_ip6_reference(host)) {
+ host = strcpy(via, host + 1);
+ via[strlen(via) - 1] = '\0';
+ }
+ port = url_port(ag->ag_contact->m_url);
+
+ memset(hints, 0, sizeof hints);
+ hints->ai_socktype = SOCK_DGRAM;
+ hints->ai_protocol = IPPROTO_UDP;
+
+ TEST(su_getaddrinfo(host, port, hints, &ai), 0); TEST_1(ai);
+ s = su_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); TEST_1(s != -1);
+ memset(su, 0, sulen = sizeof su);
+ su->su_len = sizeof su; su->su_family = ai->ai_family;
+ TEST_1(bind(s, &su->su_sa, sulen) == 0);
+ TEST_1(getsockname(s, &su->su_sa, &sulen) == 0);
+ sprintf(via, "v: SIP/2.0/UDP is.invalid:%u\r\n", ntohs(su->su_port));
+ vlen = strlen(via);
+
+ for (d = readdir(dir); d; d = readdir(dir)) {
+ size_t len = strlen(d->d_name);
+ FILE *f;
+ int blen, n;
+ void *buffer; char *r;
+
+ if (len < strlen(".txt"))
+ continue;
+ if (strcmp(d->d_name + len - strlen(".txt"), ".txt"))
+ continue;
+ strncpy(name + offset, d->d_name, PATH_MAX - offset);
+ TEST_1(f = fopen(name, "rb"));
+ TEST_1((blen = readfile(f, &buffer)) > 0);
+ r = buffer;
+
+ if (strncmp(r, "JUNK ", 5) == 0) {
+ TEST_SIZE(su_sendto(s, r, blen, 0, ai->ai_addr, ai->ai_addrlen), blen);
+ }
+ else if (strncmp(r, "INVITE ", 7) != 0) {
+ su_iovec_t vec[3];
+ n = strcspn(r, "\r\n"); n += strspn(r + n, "\r\n");
+ vec[0].siv_base = r, vec[0].siv_len = n;
+ vec[1].siv_base = via, vec[1].siv_len = vlen;
+ vec[2].siv_base = r + n, vec[2].siv_len = blen - n;
+ TEST_SIZE(su_vsend(s, vec, 3, 0, (void *)ai->ai_addr, ai->ai_addrlen),
+ blen + vlen);
+ }
+ free(buffer);
+ su_root_step(ag->ag_root, 1);
+ }
+
+ su_close(s);
+
+ for (i = 0; i < 20; i++)
+ su_root_step(ag->ag_root, 1);
+
+ nta_leg_destroy(ag->ag_default_leg), ag->ag_default_leg = NULL;
+
+ closedir(dir);
+
+ END();
+#else
+ return 0;
+#endif /* HAVE_DIRENT_H */
+}
+
+static unsigned char const code[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+#include <sofia-sip/su_uniqueid.h>
+
+sip_payload_t *test_payload(su_home_t *home, size_t size)
+{
+ sip_payload_t *pl = sip_payload_create(home, NULL, (isize_t)size);
+
+ if (pl) {
+ size_t i;
+ char *data = (char *)pl->pl_data;
+
+ for (i = 0; i < size; i++) {
+ if ((i & 63) != 63)
+ data[i] = code[su_randint(0, 63)];
+ else
+ data[i] = '\n';
+ }
+ }
+
+ return pl;
+}
+
+/* Test transports */
+
+int test_tports(agent_t *ag)
+{
+ int udp = 0, tcp = 0, sctp = 0, tls = 0;
+ sip_via_t const *v, *v_udp_only = NULL;
+ char const *udp_comp = NULL;
+ char const *tcp_comp = NULL;
+
+ url_t url[1];
+
+ BEGIN();
+
+ *url = *ag->ag_contact->m_url;
+ url->url_port = "*";
+ url->url_params = "transport=tcp";
+
+ url->url_params = "transport=udp";
+
+ TEST_1(nta_agent_add_tport(ag->ag_agent, (url_string_t *)url,
+ TAG_END()) == 0);
+
+ TEST_1(v = nta_agent_via(ag->ag_agent));
+
+ for (; v; v = v->v_next) {
+ if (strcasecmp(v->v_protocol, sip_transport_udp) == 0) {
+ if (udp)
+ v_udp_only = v;
+ udp = 1;
+ if (udp_comp == NULL)
+ udp_comp = v->v_comp;
+ }
+ else if (strcasecmp(v->v_protocol, sip_transport_tcp) == 0) {
+ tcp = 1;
+ if (tcp_comp == NULL)
+ tcp_comp = v->v_comp;
+ }
+ else if (strcasecmp(v->v_protocol, sip_transport_sctp) == 0) {
+ sctp = 1;
+ }
+ else if (strcasecmp(v->v_protocol, sip_transport_tls) == 0) {
+ tls = 1;
+ }
+ }
+
+ *url = *ag->ag_aliases->m_url;
+ url->url_user = "bob";
+
+ if (udp_comp || tcp_comp)
+ ag->ag_comp = "sigcomp";
+
+ {
+ /* Test 0.1
+ * Send a message from default leg to default leg
+ */
+ char const p_acid[] = "P-Access-Network-Info: IEEE-802.11g\n";
+ url_t url[1];
+
+ *url = *ag->ag_contact->m_url;
+ url->url_params = NULL;
+ ag->ag_expect_leg = ag->ag_default_leg;
+ su_free(ag->ag_home, (void *)ag->ag_out_via), ag->ag_out_via = NULL;
+
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_default_leg,
+ outgoing_callback, ag,
+ ag->ag_obp,
+ SIP_METHOD_MESSAGE,
+ (url_string_t *)url,
+ SIPTAG_SUBJECT_STR("Test 0.1"),
+ SIPTAG_FROM(ag->ag_alice),
+ SIPTAG_TO(ag->ag_bob),
+ SIPTAG_CONTACT(ag->ag_m_alice),
+ SIPTAG_HEADER_STR(p_acid),
+ TAG_END()));
+
+ nta_test_run(ag);
+ TEST(ag->ag_status, 200);
+ TEST_P(ag->ag_orq, NULL);
+ TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
+ TEST_1(ag->ag_request);
+
+ msg_destroy(ag->ag_request), ag->ag_request = NULL;
+
+ TEST_1(ag->ag_out_via->v_comp == NULL);
+
+ nta_leg_bind(ag->ag_default_leg, leg_callback_200, ag);
+ }
+
+ {
+ /* Test 0.1.2: test url_headers
+ *
+ * Send a message from default leg to default leg.
+ */
+ url_t url[1];
+ sip_t *sip;
+
+ *url = *ag->ag_contact->m_url;
+ /* Test that method parameter is stripped and headers in query are used */
+ url->url_params = "method=MESSAGE;user=IP";
+ url->url_headers = "organization=United%20Testers";
+ ag->ag_expect_leg = ag->ag_default_leg;
+ su_free(ag->ag_home, (void *)ag->ag_out_via), ag->ag_out_via = NULL;
+
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_default_leg,
+ outgoing_callback, ag,
+ ag->ag_obp,
+ SIP_METHOD_MESSAGE,
+ (url_string_t *)url,
+ SIPTAG_SUBJECT_STR("Test 0.1.2"),
+ SIPTAG_FROM(ag->ag_alice),
+ SIPTAG_TO(ag->ag_bob),
+ SIPTAG_CONTACT(ag->ag_m_alice),
+ TAG_END()));
+
+ nta_test_run(ag);
+ TEST(ag->ag_status, 200);
+ TEST_P(ag->ag_orq, NULL);
+ TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
+ TEST_1(ag->ag_request);
+ TEST_1(sip = sip_object(ag->ag_request));
+
+ TEST_1(sip->sip_organization);
+ TEST_S(sip->sip_organization->g_string, "United Testers");
+ TEST_S(sip->sip_request->rq_url->url_params, "user=IP");
+
+ TEST_1(ag->ag_out_via->v_comp == NULL);
+
+ nta_leg_bind(ag->ag_default_leg, leg_callback_200, ag);
+ }
+
+ /* Test 0.1.3
+ * Send a message from Bob to Alice using SIGCOMP and TCP
+ */
+ if (tcp_comp) {
+ url_t url[1];
+ sip_payload_t *pl;
+ size_t size = 1024;
+
+ *url = *ag->ag_aliases->m_url;
+ url->url_user = "alice";
+ if (url->url_params)
+ url->url_params = su_sprintf(NULL, "%s;transport=tcp", url->url_params);
+ else
+ url->url_params = "transport=tcp";
+
+ TEST_1(pl = test_payload(ag->ag_home, size));
+
+ ag->ag_expect_leg = ag->ag_server_leg;
+ su_free(ag->ag_home, (void *)ag->ag_out_via), ag->ag_out_via = NULL;
+
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+ ag->ag_obp,
+ SIP_METHOD_MESSAGE,
+ (url_string_t *)url,
+ NTATAG_COMP("sigcomp"),
+ SIPTAG_SUBJECT_STR("Test 0.1.3"),
+ SIPTAG_FROM(ag->ag_bob),
+ SIPTAG_TO(ag->ag_alice),
+ SIPTAG_CONTACT(ag->ag_m_bob),
+ SIPTAG_PAYLOAD(pl),
+ TAG_END()));
+ su_free(ag->ag_home, pl);
+
+ nta_test_run(ag);
+ TEST(ag->ag_status, 200);
+ TEST_1(ag->ag_client_compartment);
+ nta_compartment_decref(&ag->ag_client_compartment);
+ TEST_P(ag->ag_orq, NULL);
+ TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
+ TEST_S(ag->ag_out_via->v_comp, "sigcomp");
+ }
+
+ /* Test 0.2
+ * Send a message from Bob to Alice
+ * This time specify a TCP URI, and include a large payload
+ * of 512 kB
+ */
+ if (tcp) {
+ url_t url[1];
+ sip_payload_t *pl;
+ usize_t size = 512 * 1024;
+
+ *url = *ag->ag_aliases->m_url;
+ url->url_user = "alice";
+ url->url_params = "transport=tcp";
+
+ TEST_1(pl = test_payload(ag->ag_home, size));
+
+ ag->ag_expect_leg = ag->ag_server_leg;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+ NULL,
+ SIP_METHOD_MESSAGE,
+ (url_string_t *)url,
+ SIPTAG_SUBJECT_STR("Test 0.2"),
+ SIPTAG_FROM(ag->ag_bob),
+ SIPTAG_TO(ag->ag_alice),
+ SIPTAG_CONTACT(ag->ag_m_bob),
+ SIPTAG_PAYLOAD(pl),
+ NTATAG_DEFAULT_PROXY(ag->ag_obp),
+ TAG_END()));
+ su_free(ag->ag_home, pl);
+
+ nta_test_run(ag);
+ TEST(ag->ag_status, 200);
+ TEST_P(ag->ag_orq, NULL);
+ TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
+ }
+
+ /* Test 0.3
+ * Send a message from Bob to Alice
+ * This time include a large payload of 512 kB, let NTA choose transport.
+ */
+ if (tcp) {
+ url_t url[1];
+ sip_payload_t *pl;
+ usize_t size = 512 * 1024;
+
+ *url = *ag->ag_aliases->m_url;
+ url->url_user = "alice";
+
+ TEST_1(pl = test_payload(ag->ag_home, size));
+
+ ag->ag_expect_leg = ag->ag_server_leg;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+ ag->ag_obp,
+ SIP_METHOD_MESSAGE,
+ (url_string_t *)url,
+ SIPTAG_SUBJECT_STR("Test 0.3"),
+ SIPTAG_FROM(ag->ag_bob),
+ SIPTAG_TO(ag->ag_alice),
+ SIPTAG_CONTACT(ag->ag_m_bob),
+ SIPTAG_PAYLOAD(pl),
+ TAG_END()));
+ su_free(ag->ag_home, pl);
+
+ nta_test_run(ag);
+ TEST(ag->ag_status, 200);
+ TEST_P(ag->ag_orq, NULL);
+ TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
+ }
+
+ /* Test 0.4.1:
+ * Send a message from Bob to Alice
+ * This time include a payload of 2 kB, let NTA choose transport.
+ */
+ {
+ url_t url[1];
+ sip_payload_t *pl;
+ usize_t size = 2 * 1024;
+
+ *url = *ag->ag_aliases->m_url;
+ url->url_user = "alice";
+
+ TEST_1(pl = test_payload(ag->ag_home, size));
+ su_free(ag->ag_home, (void *)ag->ag_out_via), ag->ag_out_via = NULL;
+
+ ag->ag_expect_leg = ag->ag_server_leg;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+ ag->ag_obp,
+ SIP_METHOD_MESSAGE,
+ (url_string_t *)url,
+ SIPTAG_SUBJECT_STR("Test 0.4.1"),
+ SIPTAG_FROM(ag->ag_bob),
+ SIPTAG_TO(ag->ag_alice),
+ SIPTAG_CONTACT(ag->ag_m_bob),
+ SIPTAG_PAYLOAD(pl),
+ TAG_END()));
+ su_free(ag->ag_home, pl);
+
+ nta_test_run(ag);
+ TEST(ag->ag_status, 200);
+ TEST_P(ag->ag_orq, NULL);
+ TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
+ TEST_1(ag->ag_out_via);
+ TEST_1(strcasecmp(ag->ag_out_via->v_protocol, "SIP/2.0/TCP") == 0 ||
+ strcasecmp(ag->ag_out_via->v_protocol, "SIP/2.0/SCTP") == 0);
+ su_free(ag->ag_home, ag->ag_in_via), ag->ag_in_via = NULL;
+ }
+
+ /* Test 0.4.2:
+ * Send a message from Bob to Alices UDP-only address
+ * This time include a payload of 2 kB, let NTA choose transport.
+ */
+ if (v_udp_only) {
+ url_t url[1];
+ sip_payload_t *pl;
+ usize_t size = 2 * 1024;
+
+ *url = *ag->ag_aliases->m_url;
+ url->url_user = "alice";
+ url->url_host = v_udp_only->v_host;
+ url->url_port = v_udp_only->v_port;
+ url->url_params = NULL; /* No sigcomp */
+
+ TEST_1(pl = test_payload(ag->ag_home, size));
+
+ ag->ag_expect_leg = ag->ag_default_leg;
+
+ su_free(ag->ag_home, ag->ag_in_via), ag->ag_in_via = NULL;
+
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+ ag->ag_obp,
+ SIP_METHOD_MESSAGE,
+ (url_string_t *)url,
+ SIPTAG_SUBJECT_STR("Test 0.4.2"),
+ SIPTAG_FROM(ag->ag_bob),
+ SIPTAG_TO(ag->ag_alice),
+ SIPTAG_CONTACT(ag->ag_m_bob),
+ SIPTAG_PAYLOAD(pl),
+ TAG_END()));
+ su_free(ag->ag_home, pl);
+
+ nta_test_run(ag);
+ TEST(ag->ag_status, 200);
+ TEST_P(ag->ag_orq, NULL);
+ TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
+ TEST_1(ag->ag_in_via);
+ TEST_1(strcasecmp(ag->ag_in_via->v_protocol, "SIP/2.0/UDP") == 0);
+ su_free(ag->ag_home, ag->ag_in_via), ag->ag_in_via = NULL;
+ }
+
+ /* Test 0.5:
+ * Send a message from Bob to Alice
+ * This time include a payload of 2 kB, try to use UDP.
+ */
+ if (udp) {
+ url_t url[1];
+ sip_payload_t *pl;
+ usize_t size = 2 * 1024;
+
+ *url = *ag->ag_aliases->m_url;
+ url->url_user = "alice";
+
+ TEST_1(pl = test_payload(ag->ag_home, size));
+
+ su_free(ag->ag_home, (void *)ag->ag_out_via), ag->ag_out_via = NULL;
+
+ ag->ag_expect_leg = ag->ag_server_leg;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+ ag->ag_obp,
+ SIP_METHOD_MESSAGE,
+ (url_string_t *)url,
+ SIPTAG_SUBJECT_STR("Test 0.5"),
+ SIPTAG_FROM(ag->ag_bob),
+ SIPTAG_TO(ag->ag_alice),
+ SIPTAG_CONTACT(ag->ag_m_bob),
+ SIPTAG_PAYLOAD(pl),
+ TPTAG_MTU(0xffffffff),
+ TAG_END()));
+ su_free(ag->ag_home, pl);
+
+ nta_test_run(ag);
+ TEST(ag->ag_status, 200);
+ TEST_P(ag->ag_orq, NULL);
+ TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
+ TEST_1(ag->ag_out_via);
+ TEST_S(ag->ag_out_via->v_protocol, "SIP/2.0/UDP");
+ }
+
+ if (udp) {
+ /* Send a message from default leg to server leg
+ * using a prefilled Via header
+ */
+ sip_via_t via[1];
+
+ sip_via_init(via);
+
+ via->v_protocol = sip_transport_udp;
+
+ via->v_host = ag->ag_contact->m_url->url_host;
+ via->v_port = ag->ag_contact->m_url->url_port;
+
+ sip_via_add_param(ag->ag_home, via, "branch=MagicalBranch");
+
+ nta_agent_set_params(ag->ag_agent,
+ NTATAG_ALIASES(ag->ag_aliases),
+ NTATAG_USER_VIA(1),
+ TAG_END());
+
+ ag->ag_expect_leg = ag->ag_server_leg;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_default_leg,
+ magic_callback, ag,
+ ag->ag_obp,
+ SIP_METHOD_MESSAGE,
+ (url_string_t *)url,
+ SIPTAG_SUBJECT_STR("Test 0.6"),
+ SIPTAG_FROM(ag->ag_alice),
+ SIPTAG_TO(ag->ag_bob),
+ SIPTAG_CONTACT(ag->ag_m_alice),
+ SIPTAG_VIA(via),
+ TAG_END()));
+ nta_test_run(ag);
+ TEST(ag->ag_status, 200);
+ TEST_P(ag->ag_orq, NULL);
+ TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
+
+ nta_agent_set_params(ag->ag_agent,
+ NTATAG_USER_VIA(0),
+ TAG_END());
+ }
+
+ /* Test 0.7
+ * Send a message from Bob to Alice using SCTP
+ */
+ if (sctp) {
+ url_t url[1];
+ sip_payload_t *pl;
+ usize_t size = 16 * 1024;
+
+ *url = *ag->ag_aliases->m_url;
+ url->url_user = "alice";
+#if 0
+ if (url->url_params)
+ url->url_params = su_sprintf(NULL, "%s;transport=sctp", url->url_params);
+ else
+#endif
+ url->url_params = "transport=sctp";
+
+ TEST_1(pl = test_payload(ag->ag_home, size));
+
+ ag->ag_expect_leg = ag->ag_server_leg;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+ ag->ag_obp,
+ SIP_METHOD_MESSAGE,
+ (url_string_t *)url,
+ SIPTAG_SUBJECT_STR("Test 0.7"),
+ SIPTAG_FROM(ag->ag_bob),
+ SIPTAG_TO(ag->ag_alice),
+ SIPTAG_CONTACT(ag->ag_m_bob),
+ SIPTAG_PAYLOAD(pl),
+ TAG_END()));
+ su_free(ag->ag_home, pl);
+
+ nta_test_run(ag);
+ TEST(ag->ag_status, 200);
+ TEST_P(ag->ag_orq, NULL);
+ TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
+ }
+
+ /* Test 0.8: Send a too large message */
+ if (tcp) {
+ url_t url[1];
+ sip_payload_t *pl;
+ usize_t size = 128 * 1024;
+
+ nta_agent_set_params(ag->ag_agent,
+ NTATAG_MAXSIZE(65536),
+ TAG_END());
+
+ *url = *ag->ag_aliases->m_url;
+ url->url_user = "alice";
+
+ TEST_1(pl = test_payload(ag->ag_home, size));
+
+ ag->ag_expect_leg = ag->ag_server_leg;
+ ag->ag_latest_leg = NULL;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+ ag->ag_obp,
+ SIP_METHOD_MESSAGE,
+ (url_string_t *)url,
+ SIPTAG_SUBJECT_STR("Test 0.8"),
+ SIPTAG_FROM(ag->ag_bob),
+ SIPTAG_TO(ag->ag_alice),
+ SIPTAG_CONTACT(ag->ag_m_bob),
+ SIPTAG_PAYLOAD(pl),
+ TAG_END()));
+ su_free(ag->ag_home, pl);
+
+ nta_test_run(ag);
+ TEST(ag->ag_status, 413);
+ TEST_P(ag->ag_orq, NULL);
+ TEST_P(ag->ag_latest_leg, NULL);
+
+ nta_agent_set_params(ag->ag_agent,
+ NTATAG_MAXSIZE(2 * 1024 * 1024),
+ TAG_END());
+ }
+
+ /* Test 0.9: Timeout */
+ {
+ url_t url[1];
+
+ printf("%s: starting MESSAGE timeout test, completing in 4 seconds\n",
+ name);
+
+ nta_agent_set_params(ag->ag_agent,
+ NTATAG_TIMEOUT_408(1),
+ NTATAG_SIP_T1(25),
+ NTATAG_SIP_T1X64(64 * 25),
+ NTATAG_SIP_T2(8 * 25),
+ NTATAG_SIP_T4(10 * 25),
+ TAG_END());
+
+ *url = *ag->ag_aliases->m_url;
+ url->url_user = "timeout";
+ url->url_port = ag->ag_sink_port;
+
+ ag->ag_expect_leg = ag->ag_server_leg;
+ ag->ag_latest_leg = NULL;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+ ag->ag_obp,
+ SIP_METHOD_MESSAGE,
+ (url_string_t *)url,
+ SIPTAG_SUBJECT_STR("Test 0.9"),
+ SIPTAG_FROM(ag->ag_bob),
+ SIPTAG_TO(ag->ag_alice),
+ SIPTAG_CONTACT(ag->ag_m_bob),
+ TAG_END()));
+
+ nta_test_run(ag);
+ TEST(ag->ag_status, 408);
+ TEST_P(ag->ag_orq, NULL);
+ TEST_P(ag->ag_latest_leg, NULL);
+
+ nta_agent_set_params(ag->ag_agent,
+ NTATAG_SIP_T1(500),
+ NTATAG_SIP_T1X64(64 * 500),
+ NTATAG_SIP_T2(NTA_SIP_T2),
+ NTATAG_SIP_T4(NTA_SIP_T4),
+ TAG_END());
+ }
+
+
+ END();
+}
+
+int leg_callback_destroy(agent_t *ag,
+ nta_leg_t *leg,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ if (tstflags & tst_verbatim) {
+ printf("%s: %s: %s " URL_PRINT_FORMAT " %s\n",
+ name, __func__, sip->sip_request->rq_method_name,
+ URL_PRINT_ARGS(sip->sip_request->rq_url),
+ sip->sip_request->rq_version);
+ }
+
+ ag->ag_latest_leg = leg;
+
+ nta_incoming_destroy(irq);
+
+ return 0;
+}
+
+int leg_callback_save(agent_t *ag,
+ nta_leg_t *leg,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ if (tstflags & tst_verbatim) {
+ printf("%s: %s: %s " URL_PRINT_FORMAT " %s\n",
+ name, __func__, sip->sip_request->rq_method_name,
+ URL_PRINT_ARGS(sip->sip_request->rq_url),
+ sip->sip_request->rq_version);
+ }
+
+ ag->ag_latest_leg = leg;
+ ag->ag_irq = irq;
+ ag->ag_status = 1000;
+
+ return 0;
+}
+
+
+int test_destroy_incoming(agent_t *ag)
+{
+ BEGIN();
+
+ url_t url[1];
+
+ *url = *ag->ag_contact->m_url;
+
+ /* Test 3.1
+ * Check that when a incoming request is destroyed in callback,
+ * a 500 response is sent
+ */
+ ag->ag_expect_leg = ag->ag_default_leg;
+ nta_leg_bind(ag->ag_default_leg, leg_callback_destroy, ag);
+
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_default_leg,
+ outgoing_callback, ag,
+ ag->ag_obp,
+ SIP_METHOD_MESSAGE,
+ (url_string_t *)url,
+ SIPTAG_SUBJECT_STR("Test 3.1"),
+ SIPTAG_FROM(ag->ag_alice),
+ SIPTAG_TO(ag->ag_bob),
+ TAG_END()));
+
+ nta_test_run(ag);
+ TEST(ag->ag_status, 500);
+ TEST_P(ag->ag_orq, NULL);
+ TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
+
+ /* Test 3.1
+ * Check that when a incoming request is destroyed, a 500 response is sent
+ */
+ nta_leg_bind(ag->ag_default_leg, leg_callback_save, ag);
+
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_default_leg,
+ outgoing_callback, ag,
+ ag->ag_obp,
+ SIP_METHOD_MESSAGE,
+ (url_string_t *)url,
+ SIPTAG_SUBJECT_STR("Test 3.1"),
+ SIPTAG_FROM(ag->ag_alice),
+ SIPTAG_TO(ag->ag_bob),
+ TAG_END()));
+
+ nta_test_run(ag);
+ TEST(ag->ag_status, 1000);
+ TEST_1(ag->ag_irq);
+ TEST_1(ag->ag_orq);
+ TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
+ nta_incoming_destroy(ag->ag_irq), ag->ag_irq = NULL;
+ nta_test_run(ag);
+ TEST(ag->ag_status, 500);
+ TEST_P(ag->ag_orq, NULL);
+
+ END();
+}
+
+int test_resolv(agent_t *ag, char const *resolv_conf)
+{
+ int udp = 0, tcp = 0, sctp = 0, tls = 0;
+ sip_via_t const *v;
+
+ url_t *url;
+
+ if (!resolv_conf)
+ return 0;
+
+ BEGIN();
+
+ nta_leg_bind(ag->ag_default_leg, leg_callback_200, ag);
+
+ nta_agent_set_params(ag->ag_agent,
+ NTATAG_SIP_T1(8 * 25),
+ NTATAG_SIP_T1X64(64 * 25),
+ NTATAG_SIP_T4(10 * 25),
+ TAG_END());
+
+
+ TEST_1(v = nta_agent_via(ag->ag_agent));
+ for (; v; v = v->v_next) {
+ if (strcasecmp(v->v_protocol, sip_transport_udp) == 0)
+ udp = 1;
+ else if (strcasecmp(v->v_protocol, sip_transport_tcp) == 0)
+ tcp = 1;
+ else if (strcasecmp(v->v_protocol, sip_transport_sctp) == 0)
+ sctp = 1;
+ else if (strcasecmp(v->v_protocol, sip_transport_tls) == 0)
+ tls = 1;
+ }
+
+ url = url_hdup(ag->ag_home, (void *)"sip:example.org"); TEST_1(url);
+
+ {
+ /* Test 1.1
+ * Send a message to sip:example.org
+ */
+ ag->ag_expect_leg = ag->ag_default_leg;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+ ag->ag_obp,
+ SIP_METHOD_MESSAGE,
+ (url_string_t *)url,
+ SIPTAG_SUBJECT_STR("Test 1.1"),
+ SIPTAG_FROM(ag->ag_alice),
+ SIPTAG_TO(ag->ag_bob),
+ SIPTAG_CONTACT(ag->ag_m_alice),
+ TAG_END()));
+ nta_test_run(ag);
+ TEST(ag->ag_status, 200);
+ TEST_P(ag->ag_orq, NULL);
+ TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
+ }
+
+ {
+ /* Test 1.2
+ * Send a message to sip:srv.example.org
+ */
+ url->url_host = "srv.example.org";
+ ag->ag_expect_leg = ag->ag_default_leg;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+ ag->ag_obp,
+ SIP_METHOD_MESSAGE,
+ (url_string_t *)url,
+ SIPTAG_SUBJECT_STR("Test 1.2"),
+ SIPTAG_FROM(ag->ag_alice),
+ SIPTAG_TO(ag->ag_bob),
+ SIPTAG_CONTACT(ag->ag_m_alice),
+ TAG_END()));
+ nta_test_run(ag);
+ TEST(ag->ag_status, 200);
+ TEST_P(ag->ag_orq, NULL);
+ TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
+ }
+
+ {
+ /* Test 1.3
+ * Send a message to sip:ipv.example.org
+ */
+ url->url_host = "ipv.example.org";
+ ag->ag_expect_leg = ag->ag_default_leg;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+ ag->ag_obp,
+ SIP_METHOD_MESSAGE,
+ (url_string_t *)url,
+ SIPTAG_SUBJECT_STR("Test 1.3"),
+ SIPTAG_FROM(ag->ag_alice),
+ SIPTAG_TO(ag->ag_bob),
+ SIPTAG_CONTACT(ag->ag_m_alice),
+ TAG_END()));
+ nta_test_run(ag);
+ TEST(ag->ag_status, 200);
+ TEST_P(ag->ag_orq, NULL);
+ TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
+ }
+
+ {
+ /* Test 1.4.1
+ * Send a message to sip:down.example.org
+ */
+ url->url_host = "down.example.org";
+ ag->ag_expect_leg = ag->ag_default_leg;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+ ag->ag_obp,
+ SIP_METHOD_MESSAGE,
+ (url_string_t *)url,
+ SIPTAG_SUBJECT_STR("Test 1.4.1"),
+ SIPTAG_FROM(ag->ag_alice),
+ SIPTAG_TO(ag->ag_bob),
+ SIPTAG_CONTACT(ag->ag_m_alice),
+ TAG_END()));
+ nta_test_run(ag);
+ TEST(ag->ag_status, 200);
+ TEST_P(ag->ag_orq, NULL);
+ TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
+
+ }
+
+ {
+ /* Test 1.4.2
+ * Send a message to sip:na503.example.org
+ */
+ url->url_host = "na503.example.org";
+ ag->ag_expect_leg = ag->ag_default_leg;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+ ag->ag_obp,
+ SIP_METHOD_MESSAGE,
+ (url_string_t *)url,
+ SIPTAG_SUBJECT_STR("Test 1.4.2"),
+ SIPTAG_FROM(ag->ag_alice),
+ SIPTAG_TO(ag->ag_bob),
+ SIPTAG_CONTACT(ag->ag_m_alice),
+ TAG_END()));
+ nta_test_run(ag);
+ TEST(ag->ag_status, 503);
+ TEST_P(ag->ag_orq, NULL);
+ TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
+ }
+
+ {
+ /* Test 1.4.3
+ * Send a message to sip:nona.example.org
+ */
+ url->url_host = "nona.example.org";
+ ag->ag_expect_leg = ag->ag_default_leg;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+ ag->ag_obp,
+ SIP_METHOD_MESSAGE,
+ (url_string_t *)url,
+ SIPTAG_SUBJECT_STR("Test 1.4.3"),
+ SIPTAG_FROM(ag->ag_alice),
+ SIPTAG_TO(ag->ag_bob),
+ SIPTAG_CONTACT(ag->ag_m_alice),
+ TAG_END()));
+ nta_test_run(ag);
+ TEST(ag->ag_status, 200);
+ TEST_P(ag->ag_orq, NULL);
+ TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
+ }
+
+ {
+ /* Test 1.4.4
+ * Send a message to sip:nosrv.example.org
+ * After failing to find _sip._udp.nosrv.example.org,
+ * second SRV with _sip._udp.srv.example.org succeeds
+ */
+ url->url_host = "nosrv.example.org";
+ ag->ag_expect_leg = ag->ag_default_leg;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+ ag->ag_obp,
+ SIP_METHOD_MESSAGE,
+ (url_string_t *)url,
+ SIPTAG_SUBJECT_STR("Test 1.4.4"),
+ SIPTAG_FROM(ag->ag_alice),
+ SIPTAG_TO(ag->ag_bob),
+ SIPTAG_CONTACT(ag->ag_m_alice),
+ TAG_END()));
+ nta_test_run(ag);
+ TEST(ag->ag_status, 200);
+ TEST_P(ag->ag_orq, NULL);
+ TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
+ }
+
+ {
+ /* Test 1.5.1
+ * Send a message to sip:srv.example.org;transport=tcp
+ * Test outgoing_make_srv_query()
+ */
+ url->url_host = "srv.example.org";
+ url->url_params = "transport=tcp";
+ ag->ag_expect_leg = ag->ag_default_leg;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+ ag->ag_obp,
+ SIP_METHOD_MESSAGE,
+ (url_string_t *)url,
+ SIPTAG_SUBJECT_STR("Test 1.5.1: outgoing_make_srv_query()"),
+ SIPTAG_FROM(ag->ag_alice),
+ SIPTAG_TO(ag->ag_bob),
+ SIPTAG_CONTACT(ag->ag_m_alice),
+ TAG_END()));
+ nta_test_run(ag);
+ TEST(ag->ag_status, 200);
+ TEST_P(ag->ag_orq, NULL);
+ TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
+ url->url_params = NULL;
+ }
+
+ {
+ /* Test 1.5.2
+ * Send a message to sip:srv.example.org;transport=udp
+ * Test outgoing_make_srv_query()
+ */
+ url->url_host = "srv.example.org";
+ url->url_params = "transport=udp";
+ ag->ag_expect_leg = ag->ag_default_leg;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+ ag->ag_obp,
+ SIP_METHOD_MESSAGE,
+ (url_string_t *)url,
+ SIPTAG_SUBJECT_STR("Test 1.5.2: outgoing_make_srv_query()"),
+ SIPTAG_FROM(ag->ag_alice),
+ SIPTAG_TO(ag->ag_bob),
+ SIPTAG_CONTACT(ag->ag_m_alice),
+ TAG_END()));
+ nta_test_run(ag);
+ TEST(ag->ag_status, 200);
+ TEST_P(ag->ag_orq, NULL);
+ TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
+ url->url_params = NULL;
+ }
+
+ {
+ /* Test 1.5.3
+ * Send a message to sip:srv2.example.org;transport=udp
+ * Test outgoing_query_srv_a()
+ */
+ url->url_host = "srv2.example.org";
+ url->url_params = "transport=udp";
+ ag->ag_expect_leg = ag->ag_default_leg;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+ ag->ag_obp,
+ SIP_METHOD_MESSAGE,
+ (url_string_t *)url,
+ SIPTAG_SUBJECT_STR("Test 1.5: outgoing_query_srv_a()"),
+ SIPTAG_FROM(ag->ag_alice),
+ SIPTAG_TO(ag->ag_bob),
+ SIPTAG_CONTACT(ag->ag_m_alice),
+ TAG_END()));
+ nta_test_run(ag);
+ TEST(ag->ag_status, 200);
+ TEST_P(ag->ag_orq, NULL);
+ TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
+ url->url_params = NULL;
+ }
+
+ {
+ /* Test 1.6.1
+ * Send a message to sip:srv.example.org:$port
+ * Test outgoing_make_a_aaaa_query()
+ */
+ url->url_host = "srv.example.org";
+ url->url_port = ag->ag_contact->m_url->url_port;
+ ag->ag_expect_leg = ag->ag_default_leg;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+ ag->ag_obp,
+ SIP_METHOD_MESSAGE,
+ (url_string_t *)url,
+ SIPTAG_SUBJECT_STR("Test 1.6.1: outgoing_make_a_aaaa_query()"),
+ SIPTAG_FROM(ag->ag_alice),
+ SIPTAG_TO(ag->ag_bob),
+ SIPTAG_CONTACT(ag->ag_m_alice),
+ TAG_END()));
+ nta_test_run(ag);
+ TEST(ag->ag_status, 503);
+ TEST_P(ag->ag_orq, NULL);
+ TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
+ }
+
+ {
+ /* Test 1.6.2
+ * Send a message to sip:a.example.org:$port
+ * Test outgoing_make_a_aaaa_query()
+ */
+ url->url_host = "a.example.org";
+ url->url_port = ag->ag_contact->m_url->url_port;
+ ag->ag_expect_leg = ag->ag_default_leg;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+ ag->ag_obp,
+ SIP_METHOD_MESSAGE,
+ (url_string_t *)url,
+ SIPTAG_SUBJECT_STR("Test 1.6.2: outgoing_make_a_aaaa_query()"),
+ SIPTAG_FROM(ag->ag_alice),
+ SIPTAG_TO(ag->ag_bob),
+ SIPTAG_CONTACT(ag->ag_m_alice),
+ TAG_END()));
+ nta_test_run(ag);
+ TEST(ag->ag_status, 200);
+ TEST_P(ag->ag_orq, NULL);
+ TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
+ url->url_port = NULL;
+ }
+
+#if 0 /* This must be run on host *without* proxy */
+ {
+ /* Test 1.6c
+ * Send a message to sip:na.example.org
+ * Test outgoing_query_all() with NAPTR "A" flag
+ */
+ url->url_host = "na.example.org";
+ ag->ag_expect_leg = ag->ag_default_leg;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+ ag->ag_obp,
+ SIP_METHOD_MESSAGE,
+ (url_string_t *)url,
+ SIPTAG_SUBJECT_STR("Test 1.6c"),
+ SIPTAG_FROM(ag->ag_alice),
+ SIPTAG_TO(ag->ag_bob),
+ SIPTAG_CONTACT(ag->ag_m_alice),
+ TAG_END()));
+ nta_test_run(ag);
+ TEST(ag->ag_status, 503);
+ TEST(ag->ag_orq, NULL);
+ TEST(ag->ag_latest_leg, ag->ag_default_leg);
+ }
+#endif
+
+ {
+ /* Test 1.7
+ * Send a message to sip:down2.example.org:$port
+ * Test A record failover.
+ */
+ url->url_host = "down2.example.org";
+ url->url_port = ag->ag_contact->m_url->url_port;
+ ag->ag_expect_leg = ag->ag_default_leg;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+ ag->ag_obp,
+ SIP_METHOD_MESSAGE,
+ (url_string_t *)url,
+ SIPTAG_SUBJECT_STR("Test 1.7: outgoing_make_a_aaaa_query()"),
+ SIPTAG_FROM(ag->ag_alice),
+ SIPTAG_TO(ag->ag_bob),
+ SIPTAG_CONTACT(ag->ag_m_alice),
+ TAG_END()));
+ nta_test_run(ag);
+ TEST(ag->ag_status, 200);
+ TEST_P(ag->ag_orq, NULL);
+ TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
+ url->url_params = NULL;
+ }
+
+#if 0
+ /* Test 0.1.1
+ * Send a message from Bob to Alice using SIGCOMP and TCP
+ */
+ if (tcp_comp) {
+ url_t url[1];
+ sip_payload_t *pl;
+ usize_t size = 1024;
+
+ *url = *ag->ag_aliases->m_url;
+ url->url_user = "alice";
+ if (url->url_params)
+ url->url_params = su_sprintf(NULL, "%s;transport=tcp", url->url_params);
+ else
+ url->url_params = "transport=tcp";
+
+ TEST_1(pl = test_payload(ag->ag_home, size));
+ ag->ag_expect_leg = ag->ag_server_leg;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+ ag->ag_obp,
+ SIP_METHOD_MESSAGE,
+ (url_string_t *)url,
+ SIPTAG_SUBJECT_STR("Test 0.1.1"),
+ SIPTAG_FROM(ag->ag_bob),
+ SIPTAG_TO(ag->ag_alice),
+ SIPTAG_CONTACT(ag->ag_m_bob),
+ SIPTAG_PAYLOAD(pl),
+ TAG_END()));
+ su_free(ag->ag_home, pl);
+
+ nta_test_run(ag);
+ TEST(ag->ag_status, 200);
+ TEST(ag->ag_orq, NULL);
+ TEST(ag->ag_latest_leg, ag->ag_server_leg);
+ }
+
+ /* Test 0.2
+ * Send a message from Bob to Alice
+ * This time specify a TCP URI, and include a large payload
+ * of 512 kB
+ */
+ if (tcp) {
+ url_t url[1];
+ sip_payload_t *pl;
+ usize_t size = 512 * 1024;
+
+ *url = *ag->ag_aliases->m_url;
+ url->url_user = "alice";
+#if 0
+ if (url->url_params)
+ url->url_params = su_sprintf(NULL, "%s;transport=tcp", url->url_params);
+ else
+#endif
+ url->url_params = "transport=tcp";
+
+
+ TEST_1(pl = test_payload(ag->ag_home, size));
+
+ ag->ag_expect_leg = ag->ag_server_leg;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+ ag->ag_obp,
+ SIP_METHOD_MESSAGE,
+ (url_string_t *)url,
+ SIPTAG_SUBJECT_STR("Test 0.2"),
+ SIPTAG_FROM(ag->ag_bob),
+ SIPTAG_TO(ag->ag_alice),
+ SIPTAG_CONTACT(ag->ag_m_bob),
+ SIPTAG_PAYLOAD(pl),
+ TAG_END()));
+ su_free(ag->ag_home, pl);
+
+ nta_test_run(ag);
+ TEST(ag->ag_status, 200);
+ TEST(ag->ag_orq, NULL);
+ TEST(ag->ag_latest_leg, ag->ag_server_leg);
+ }
+
+ /* Test 0.3
+ * Send a message from Bob to Alice
+ * This time include a large payload of 512 kB, let NTA choose transport.
+ */
+ if (tcp) {
+ url_t url[1];
+ sip_payload_t *pl;
+ usize_t size = 512 * 1024;
+
+ *url = *ag->ag_aliases->m_url;
+ url->url_user = "alice";
+
+ TEST_1(pl = test_payload(ag->ag_home, size));
+
+ ag->ag_expect_leg = ag->ag_server_leg;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+ ag->ag_obp,
+ SIP_METHOD_MESSAGE,
+ (url_string_t *)url,
+ SIPTAG_SUBJECT_STR("Test 0.3"),
+ SIPTAG_FROM(ag->ag_bob),
+ SIPTAG_TO(ag->ag_alice),
+ SIPTAG_CONTACT(ag->ag_m_bob),
+ SIPTAG_PAYLOAD(pl),
+ TAG_END()));
+ su_free(ag->ag_home, pl);
+
+ nta_test_run(ag);
+ TEST(ag->ag_status, 200);
+ TEST(ag->ag_orq, NULL);
+ TEST(ag->ag_latest_leg, ag->ag_server_leg);
+ }
+
+ /* Test 0.4:
+ * Send a message from Bob to Alice
+ * This time include a payload of 2 kB, let NTA choose transport.
+ */
+ {
+ url_t url[1];
+ sip_payload_t *pl;
+ usize_t size = 2 * 1024;
+
+ *url = *ag->ag_aliases->m_url;
+ url->url_user = "alice";
+
+ TEST_1(pl = test_payload(ag->ag_home, size));
+
+ su_free(ag->ag_home, (void *)ag->ag_out_via), ag->ag_out_via = NULL;
+
+ ag->ag_expect_leg = ag->ag_server_leg;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+ ag->ag_obp,
+ SIP_METHOD_MESSAGE,
+ (url_string_t *)url,
+ SIPTAG_SUBJECT_STR("Test 0.4"),
+ SIPTAG_FROM(ag->ag_bob),
+ SIPTAG_TO(ag->ag_alice),
+ SIPTAG_CONTACT(ag->ag_m_bob),
+ SIPTAG_PAYLOAD(pl),
+ TAG_END()));
+ su_free(ag->ag_home, pl);
+
+ nta_test_run(ag);
+ TEST(ag->ag_status, 200);
+ TEST(ag->ag_orq, NULL);
+ TEST(ag->ag_latest_leg, ag->ag_server_leg);
+ TEST_1(ag->ag_out_via);
+ TEST_1(strcasecmp(ag->ag_out_via->v_protocol, "SIP/2.0/TCP") == 0 ||
+ strcasecmp(ag->ag_out_via->v_protocol, "SIP/2.0/SCTP") == 0);
+ }
+
+ /* Test 0.5:
+ * Send a message from Bob to Alice
+ * This time include a payload of 2 kB, try to use UDP.
+ */
+ if (udp) {
+ url_t url[1];
+ sip_payload_t *pl;
+ usize_t size = 2 * 1024;
+
+ *url = *ag->ag_aliases->m_url;
+ url->url_user = "alice";
+
+ TEST_1(pl = test_payload(ag->ag_home, size));
+
+ su_free(ag->ag_home, (void *)ag->ag_out_via), ag->ag_out_via = NULL;
+
+ ag->ag_expect_leg = ag->ag_server_leg;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+ ag->ag_obp,
+ SIP_METHOD_MESSAGE,
+ (url_string_t *)url,
+ SIPTAG_SUBJECT_STR("Test 0.5"),
+ SIPTAG_FROM(ag->ag_bob),
+ SIPTAG_TO(ag->ag_alice),
+ SIPTAG_CONTACT(ag->ag_m_bob),
+ SIPTAG_PAYLOAD(pl),
+ TPTAG_MTU(0xffffffff),
+ TAG_END()));
+ su_free(ag->ag_home, pl);
+
+ nta_test_run(ag);
+ TEST(ag->ag_status, 200);
+ TEST(ag->ag_orq, NULL);
+ TEST(ag->ag_latest_leg, ag->ag_server_leg);
+ TEST_1(ag->ag_out_via);
+ TEST_S(ag->ag_out_via->v_protocol, "SIP/2.0/UDP");
+ }
+
+ if (udp) {
+ /* Send a message from default leg to server leg
+ * using a prefilled Via header
+ */
+ sip_via_t via[1];
+
+ sip_via_init(via);
+
+ via->v_protocol = sip_transport_udp;
+
+ via->v_host = ag->ag_contact->m_url->url_host;
+ via->v_port = ag->ag_contact->m_url->url_port;
+
+ sip_via_add_param(ag->ag_home, via, "branch=MagicalBranch");
+
+ nta_agent_set_params(ag->ag_agent,
+ NTATAG_USER_VIA(1),
+ TAG_END());
+
+ ag->ag_expect_leg = ag->ag_server_leg;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_default_leg,
+ magic_callback, ag,
+ ag->ag_obp,
+ SIP_METHOD_MESSAGE,
+ (url_string_t *)url,
+ SIPTAG_SUBJECT_STR("Test 0.6"),
+ SIPTAG_FROM(ag->ag_alice),
+ SIPTAG_TO(ag->ag_bob),
+ SIPTAG_CONTACT(ag->ag_m_alice),
+ SIPTAG_VIA(via),
+ TAG_END()));
+ nta_test_run(ag);
+ TEST(ag->ag_status, 200);
+ TEST(ag->ag_orq, NULL);
+ TEST(ag->ag_latest_leg, ag->ag_server_leg);
+
+ nta_agent_set_params(ag->ag_agent,
+ NTATAG_USER_VIA(0),
+ TAG_END());
+ }
+
+ /* Test 0.7
+ * Send a message from Bob to Alice using SCTP
+ */
+ if (sctp) {
+ url_t url[1];
+ sip_payload_t *pl;
+ usize_t size = 16 * 1024;
+
+ *url = *ag->ag_aliases->m_url;
+ url->url_user = "alice";
+#if 0
+ if (url->url_params)
+ url->url_params = su_sprintf(NULL, "%s;transport=sctp", url->url_params);
+ else
+#endif
+ url->url_params = "transport=sctp";
+
+ TEST_1(pl = test_payload(ag->ag_home, size));
+
+ ag->ag_expect_leg = ag->ag_server_leg;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+ ag->ag_obp,
+ SIP_METHOD_MESSAGE,
+ (url_string_t *)url,
+ SIPTAG_SUBJECT_STR("Test 0.7"),
+ SIPTAG_FROM(ag->ag_bob),
+ SIPTAG_TO(ag->ag_alice),
+ SIPTAG_CONTACT(ag->ag_m_bob),
+ SIPTAG_PAYLOAD(pl),
+ TAG_END()));
+ su_free(ag->ag_home, pl);
+
+ nta_test_run(ag);
+ TEST(ag->ag_status, 200);
+ TEST(ag->ag_orq, NULL);
+ TEST(ag->ag_latest_leg, ag->ag_server_leg);
+ }
+
+ /* Test 0.8: Send a too large message */
+ if (tcp) {
+ url_t url[1];
+ sip_payload_t *pl;
+ usize_t size = 128 * 1024;
+
+ nta_agent_set_params(ag->ag_agent,
+ NTATAG_MAXSIZE(65536),
+ TAG_END());
+
+ *url = *ag->ag_aliases->m_url;
+ url->url_user = "alice";
+
+ TEST_1(pl = test_payload(ag->ag_home, size));
+
+ ag->ag_expect_leg = ag->ag_server_leg;
+ ag->ag_latest_leg = NULL;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+ ag->ag_obp,
+ SIP_METHOD_MESSAGE,
+ (url_string_t *)url,
+ SIPTAG_SUBJECT_STR("Test 0.8"),
+ SIPTAG_FROM(ag->ag_bob),
+ SIPTAG_TO(ag->ag_alice),
+ SIPTAG_CONTACT(ag->ag_m_bob),
+ SIPTAG_PAYLOAD(pl),
+ TAG_END()));
+ su_free(ag->ag_home, pl);
+
+ nta_test_run(ag);
+ TEST(ag->ag_status, 413);
+ TEST(ag->ag_orq, NULL);
+ TEST(ag->ag_latest_leg, NULL);
+
+ nta_agent_set_params(ag->ag_agent,
+ NTATAG_MAXSIZE(2 * 1024 * 1024),
+ TAG_END());
+ }
+
+ /* Test 0.9: Timeout */
+ {
+ url_t url[1];
+
+ printf("%s: starting MESSAGE timeout test, test will complete in 4 seconds\n",
+ name);
+
+ nta_agent_set_params(ag->ag_agent,
+ NTATAG_TIMEOUT_408(1),
+ NTATAG_SIP_T1(25),
+ NTATAG_SIP_T1X64(64 * 25),
+ TAG_END());
+
+ *url = *ag->ag_aliases->m_url;
+ url->url_user = "timeout";
+ url->url_port = ag->ag_sink_port;
+
+ ag->ag_expect_leg = ag->ag_server_leg;
+ ag->ag_latest_leg = NULL;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+ ag->ag_obp,
+ SIP_METHOD_MESSAGE,
+ (url_string_t *)url,
+ SIPTAG_SUBJECT_STR("Test 0.9"),
+ SIPTAG_FROM(ag->ag_bob),
+ SIPTAG_TO(ag->ag_alice),
+ SIPTAG_CONTACT(ag->ag_m_bob),
+ TAG_END()));
+
+ nta_test_run(ag);
+ TEST(ag->ag_status, 408);
+ TEST(ag->ag_orq, NULL);
+ TEST(ag->ag_latest_leg, NULL);
+
+ nta_agent_set_params(ag->ag_agent,
+ NTATAG_SIP_T1(500),
+ NTATAG_SIP_T1X64(64 * 500),
+ TAG_END());
+ }
+#endif
+
+ nta_agent_set_params(ag->ag_agent,
+ NTATAG_SIP_T1(500),
+ NTATAG_SIP_T1X64(64 * 500),
+ NTATAG_SIP_T2(NTA_SIP_T2),
+ NTATAG_SIP_T4(NTA_SIP_T4),
+ TAG_END());
+
+ END();
+}
+
+/* Test default routing */
+
+int test_routing(agent_t *ag)
+{
+ url_t url[1];
+
+ *url = *ag->ag_aliases->m_url;
+ url->url_user = "bob";
+
+ nta_leg_bind(ag->ag_default_leg, leg_callback_200, ag);
+
+ nta_agent_set_params(ag->ag_agent,
+ NTATAG_MAXSIZE(2 * 1024 * 1024),
+ TAG_END());
+
+ BEGIN();
+
+ {
+ /*
+ * Send a message from default leg to default leg
+ *
+ * We are now using url with an explicit port that does not match with
+ * our own port number.
+ */
+ url_t url2[1];
+
+ *url2 = *url;
+ url2->url_port = "9"; /* discard service */
+
+ ag->ag_expect_leg = ag->ag_default_leg;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+ (url_string_t *)url,
+ SIP_METHOD_MESSAGE,
+ (url_string_t *)url2,
+ SIPTAG_SUBJECT_STR("Test 1.2"),
+ SIPTAG_FROM(ag->ag_alice),
+ SIPTAG_TO(ag->ag_bob),
+ SIPTAG_CONTACT(ag->ag_m_alice),
+ TAG_END()));
+ nta_test_run(ag);
+ TEST(ag->ag_status, 200);
+ TEST_P(ag->ag_orq, NULL);
+ TEST_P(ag->ag_latest_leg, ag->ag_default_leg);
+ }
+
+ END();
+}
+
+/* Test dialogs and the tag handling */
+
+int test_dialog(agent_t *ag)
+{
+ BEGIN();
+
+ /*
+ * Test establishing a dialog
+ *
+ * Alice sends a message to Bob, then Bob back to the Alice, and again
+ * Alice to Bob.
+ */
+ TEST_1(ag->ag_alice_leg = nta_leg_tcreate(ag->ag_agent,
+ leg_callback_200,
+ ag,
+ SIPTAG_FROM(ag->ag_alice),
+ SIPTAG_TO(ag->ag_bob),
+ TAG_END()));
+ TEST_1(nta_leg_tag(ag->ag_alice_leg, NULL));
+ nta_leg_bind(ag->ag_server_leg, new_leg_callback_200, ag);
+
+ /* Send message from Alice to Bob establishing the dialog */
+ ag->ag_expect_leg = ag->ag_server_leg;
+ ag->ag_tag_remote = ag->ag_alice_leg;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_alice_leg, outgoing_callback, ag,
+ ag->ag_obp,
+ SIP_METHOD_MESSAGE,
+ (url_string_t *)ag->ag_m_bob->m_url,
+ SIPTAG_SUBJECT_STR("Test 2.1"),
+ SIPTAG_FROM(ag->ag_alice),
+ SIPTAG_TO(ag->ag_bob),
+ SIPTAG_CONTACT(ag->ag_m_alice),
+ TAG_END()));
+ nta_test_run(ag);
+ TEST(ag->ag_status, 200);
+ TEST_P(ag->ag_orq, NULL);
+ TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
+ TEST_1(ag->ag_bob_leg != NULL);
+
+ nta_leg_bind(ag->ag_server_leg, leg_callback_200, ag);
+
+ /* Send message from Bob to Alice */
+ ag->ag_expect_leg = ag->ag_alice_leg;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_bob_leg, outgoing_callback, ag,
+ NULL,
+ SIP_METHOD_MESSAGE,
+ (url_string_t *)ag->ag_m_alice->m_url,
+ SIPTAG_SUBJECT_STR("Test 2.2"),
+ TAG_END()));
+ nta_test_run(ag);
+ TEST(ag->ag_status, 200);
+ TEST_P(ag->ag_orq, NULL);
+ TEST_P(ag->ag_latest_leg, ag->ag_alice_leg);
+
+ /* Send again message from Alice to Bob */
+ ag->ag_expect_leg = ag->ag_bob_leg;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_alice_leg, outgoing_callback, ag,
+ NULL,
+ SIP_METHOD_MESSAGE,
+ (url_string_t *)ag->ag_m_bob->m_url,
+ SIPTAG_SUBJECT_STR("Test 2.3"),
+ TAG_END()));
+ nta_test_run(ag);
+ TEST(ag->ag_status, 200);
+ TEST_P(ag->ag_orq, NULL);
+ TEST_P(ag->ag_latest_leg, ag->ag_bob_leg);
+
+ /* Send message from Bob to Alice
+ * This time, however, specify request URI
+ */
+ {
+ ag->ag_expect_leg = ag->ag_alice_leg;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_bob_leg, outgoing_callback, ag,
+ NULL,
+ SIP_METHOD_MESSAGE,
+ (url_string_t *)ag->ag_m_alice->m_url,
+ SIPTAG_SUBJECT_STR("Test 2.4"),
+ TAG_END()));
+ nta_test_run(ag);
+ TEST(ag->ag_status, 200);
+ TEST_P(ag->ag_orq, NULL);
+ TEST_P(ag->ag_latest_leg, ag->ag_alice_leg);
+ }
+
+ nta_leg_destroy(ag->ag_alice_leg), ag->ag_alice_leg = NULL;
+ nta_leg_destroy(ag->ag_bob_leg), ag->ag_bob_leg = NULL;
+
+ END();
+}
+
+/* ---------------------------------------------------------------------- */
+/* Test INVITE, dialogs */
+
+static
+int test_for_ack(agent_t *ag,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ sip_method_t method;
+
+ BEGIN();
+
+ method = sip ? sip->sip_request->rq_method : sip_method_unknown;
+
+ nta_incoming_destroy(irq);
+ TEST_P(irq, ag->ag_irq);
+ ag->ag_irq = NULL;
+
+ TEST(method, sip_method_ack);
+
+ ag->ag_status = 200;
+
+ END();
+}
+
+static
+int test_for_prack(agent_t *ag,
+ nta_reliable_t *rel,
+ nta_incoming_t *prack,
+ sip_t const *sip)
+{
+ sip_method_t method = sip ? sip->sip_request->rq_method : sip_method_unknown;
+
+ nta_incoming_treply(ag->ag_irq,
+ SIP_200_OK,
+ SIPTAG_CONTACT(ag->ag_m_alice),
+ TAG_END());
+
+ TEST(method, sip_method_prack);
+
+ return 200;
+}
+
+int alice_leg_callback(agent_t *ag,
+ nta_leg_t *leg,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ BEGIN();
+
+ if (tstflags & tst_verbatim) {
+ printf("%s: %s: %s " URL_PRINT_FORMAT " %s\n",
+ name, __func__, sip->sip_request->rq_method_name,
+ URL_PRINT_ARGS(sip->sip_request->rq_url),
+ sip->sip_request->rq_version);
+ }
+
+ TEST_1(sip->sip_content_length);
+ TEST_1(sip->sip_via);
+ TEST_1(sip->sip_from && sip->sip_from->a_tag);
+
+ if (sip->sip_request->rq_method == sip_method_prack)
+ return 481;
+
+ ag->ag_latest_leg = leg;
+
+ if (leg != ag->ag_alice_leg) {
+ leg_match(ag, leg, 1, __func__);
+ return 500;
+ }
+
+ if (sip->sip_request->rq_method == sip_method_invite) {
+ TEST_1(sip_has_feature(sip->sip_supported, "100rel"));
+ nta_incoming_bind(irq, test_for_ack, ag);
+ nta_incoming_treply(irq, SIP_100_TRYING, TAG_END());
+
+ nta_agent_set_params(ag->ag_agent,
+ NTATAG_DEBUG_DROP_PROB(ag->ag_drop),
+ TAG_END());
+
+ ag->ag_reliable =
+ nta_reliable_treply(irq,
+ NULL, NULL,
+ SIP_183_SESSION_PROGRESS,
+ SIPTAG_CONTENT_TYPE(ag->ag_content_type),
+ SIPTAG_PAYLOAD(ag->ag_payload),
+ SIPTAG_CONTACT(ag->ag_m_alice),
+ TAG_END());
+ TEST_1(ag->ag_reliable);
+ ag->ag_reliable =
+ nta_reliable_treply(irq,
+ NULL, NULL,
+ 184, "Next",
+ SIPTAG_CONTACT(ag->ag_m_alice),
+ TAG_END());
+ TEST_1(ag->ag_reliable);
+ ag->ag_reliable =
+ nta_reliable_treply(irq,
+ test_for_prack, ag,
+ 185, "Last",
+ SIPTAG_CONTACT(ag->ag_m_alice),
+ TAG_END());
+ TEST_1(ag->ag_reliable);
+ ag->ag_irq = irq;
+ return 0;
+ }
+
+ if (sip->sip_request->rq_method == sip_method_bye) {
+ leg_zap(ag, leg);
+ }
+ if (sip)
+ return 200;
+
+ END();
+}
+
+
+int bob_leg_callback(agent_t *ag,
+ nta_leg_t *leg,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ BEGIN();
+
+ if (tstflags & tst_verbatim) {
+ printf("%s: %s: %s " URL_PRINT_FORMAT " %s\n",
+ name, __func__, sip->sip_request->rq_method_name,
+ URL_PRINT_ARGS(sip->sip_request->rq_url),
+ sip->sip_request->rq_version);
+ }
+
+ TEST_1(sip->sip_content_length);
+ TEST_1(sip->sip_via);
+ TEST_1(sip->sip_from && sip->sip_from->a_tag);
+
+ if (sip->sip_request->rq_method == sip_method_prack)
+ return 481;
+
+ ag->ag_latest_leg = leg;
+
+ if (ag->ag_bob_leg && leg != ag->ag_bob_leg) {
+ leg_match(ag, leg, 1, __func__);
+ return 500;
+ }
+
+ if (ag->ag_bob_leg == NULL) {
+ nta_leg_bind(leg, leg_callback_500, ag);
+ ag->ag_bob_leg = nta_leg_tcreate(ag->ag_agent,
+ bob_leg_callback,
+ ag,
+ SIPTAG_CALL_ID(sip->sip_call_id),
+ SIPTAG_FROM(sip->sip_to),
+ SIPTAG_TO(sip->sip_from),
+ TAG_END());
+ TEST_1(ag->ag_bob_leg);
+ TEST_1(nta_leg_tag(ag->ag_bob_leg, NULL));
+ TEST_1(nta_leg_get_tag(ag->ag_bob_leg));
+ TEST_1(nta_incoming_tag(irq, nta_leg_get_tag(ag->ag_bob_leg)));
+ TEST(nta_leg_server_route(ag->ag_bob_leg,
+ sip->sip_record_route,
+ sip->sip_contact), 0);
+ }
+
+ if (sip->sip_request->rq_method != sip_method_invite) {
+ return 200;
+ } else {
+ nta_incoming_bind(irq, test_for_ack, ag);
+#if 1
+ nta_incoming_treply(irq,
+ SIP_180_RINGING,
+ SIPTAG_CONTACT(ag->ag_m_bob),
+ TAG_END());
+ nta_incoming_treply(irq,
+ SIP_180_RINGING,
+ SIPTAG_CONTACT(ag->ag_m_bob),
+ TAG_END());
+#endif
+ nta_incoming_treply(irq,
+ SIP_200_OK,
+ SIPTAG_CONTENT_TYPE(ag->ag_content_type),
+ SIPTAG_PAYLOAD(ag->ag_payload),
+ SIPTAG_CONTACT(ag->ag_m_bob),
+ TAG_END());
+ ag->ag_irq = irq;
+ }
+
+ END();
+}
+
+int outgoing_invite_callback(agent_t *ag,
+ nta_outgoing_t *orq,
+ sip_t const *sip)
+{
+ BEGIN();
+
+ int status = sip->sip_status->st_status;
+
+ if (tstflags & tst_verbatim) {
+ printf("%s: %s: %s %03d %s\n", name, __func__,
+ sip->sip_status->st_version,
+ sip->sip_status->st_status,
+ sip->sip_status->st_phrase);
+ }
+
+ {
+ msg_t *msg;
+
+ TEST_1(msg = nta_outgoing_getresponse(orq));
+ TEST_1(msg->m_refs == 2);
+ TEST_1(sip_object(msg) == sip);
+ if (ag->ag_probe_msg == NULL)
+ ag->ag_probe_msg = msg;
+ msg_destroy(msg);
+ }
+
+ if (status < 200) {
+ if (sip->sip_require && sip_has_feature(sip->sip_require, "100rel")) {
+ TEST_1(sip->sip_rseq);
+ orq = nta_outgoing_prack(ag->ag_call_leg, orq, NULL, NULL,
+ NULL,
+ sip,
+ TAG_END());
+ TEST_1(orq);
+ nta_outgoing_destroy(orq);
+ }
+ return 0;
+ }
+
+ if (status < 300) {
+ nta_outgoing_t *ack;
+
+ TEST_1(nta_leg_rtag(ag->ag_call_leg, sip->sip_to->a_tag));
+
+ TEST(nta_leg_client_route(ag->ag_call_leg,
+ sip->sip_record_route,
+ sip->sip_contact), 0);
+
+ ack = nta_outgoing_tcreate(ag->ag_call_leg, NULL, NULL,
+ NULL,
+ SIP_METHOD_ACK,
+ NULL,
+ SIPTAG_CSEQ(sip->sip_cseq),
+ TAG_END());
+ TEST_1(ack);
+ nta_outgoing_destroy(ack);
+ }
+ else {
+ ag->ag_status = status;
+ }
+
+ TEST_1(sip->sip_to && sip->sip_to->a_tag);
+
+ nta_outgoing_destroy(orq);
+ ag->ag_orq = NULL;
+ ag->ag_call_leg = NULL;
+ END();
+}
+
+
+int test_call(agent_t *ag)
+{
+ sip_content_type_t *c = ag->ag_content_type;
+ sip_payload_t *sdp = ag->ag_payload;
+ nta_leg_t *old_leg;
+ sip_replaces_t *r1, *r2;
+
+ BEGIN();
+
+ /*
+ * Test establishing a call
+ *
+ * Alice sends a INVITE to Bob, then Bob sends 200 Ok.
+ */
+ TEST_1(ag->ag_alice_leg = nta_leg_tcreate(ag->ag_agent,
+ alice_leg_callback,
+ ag,
+ SIPTAG_FROM(ag->ag_alice),
+ SIPTAG_TO(ag->ag_bob),
+ TAG_END()));
+ TEST_1(nta_leg_tag(ag->ag_alice_leg, NULL));
+ nta_leg_bind(ag->ag_server_leg, bob_leg_callback, ag);
+
+ /* Send INVITE */
+ ag->ag_expect_leg = ag->ag_server_leg;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_call_leg = ag->ag_alice_leg,
+ outgoing_invite_callback, ag,
+ ag->ag_obp,
+ SIP_METHOD_INVITE,
+ (url_string_t *)ag->ag_m_bob->m_url,
+ SIPTAG_SUBJECT_STR("Call 1"),
+ SIPTAG_CONTACT(ag->ag_m_alice),
+ SIPTAG_CONTENT_TYPE(c),
+ SIPTAG_ACCEPT_CONTACT_STR("*;audio"),
+ SIPTAG_PAYLOAD(sdp),
+ NTATAG_USE_TIMESTAMP(1),
+ NTATAG_PASS_100(1),
+ TAG_END()));
+
+ /* Try to CANCEL it immediately */
+ TEST_1(nta_outgoing_cancel(ag->ag_orq) == 0);
+ /* As Bob immediately answers INVITE with 200 Ok,
+ cancel should be answered with 487. */
+
+ nta_test_run(ag);
+ TEST(ag->ag_status, 200);
+ TEST_P(ag->ag_orq, NULL);
+ TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
+ TEST_1(ag->ag_bob_leg != NULL);
+
+ TEST_1(r1 = nta_leg_make_replaces(ag->ag_alice_leg, ag->ag_home, 0));
+ TEST_1(r2 = sip_replaces_format(ag->ag_home, "%s;from-tag=%s;to-tag=%s",
+ r1->rp_call_id, r1->rp_to_tag, r1->rp_from_tag));
+
+ TEST_P(ag->ag_alice_leg, nta_leg_by_replaces(ag->ag_agent, r2));
+ TEST_P(ag->ag_bob_leg, nta_leg_by_replaces(ag->ag_agent, r1));
+
+ /* Re-INVITE from Bob to Alice.
+ *
+ * Alice first sends 183, waits for PRACK, then sends 184 and 185,
+ * waits for PRACKs, then sends 200, waits for ACK.
+ */
+ ag->ag_expect_leg = ag->ag_alice_leg;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_call_leg = ag->ag_bob_leg,
+ outgoing_invite_callback, ag,
+ NULL,
+ SIP_METHOD_INVITE,
+ NULL,
+ SIPTAG_SUBJECT_STR("Re-INVITE"),
+ SIPTAG_CONTACT(ag->ag_m_bob),
+ SIPTAG_SUPPORTED_STR("foo"),
+ SIPTAG_CONTENT_TYPE(c),
+ SIPTAG_PAYLOAD(sdp),
+ TAG_END()));
+ nta_test_run(ag);
+ TEST(ag->ag_status, 200);
+ TEST_P(ag->ag_orq, NULL);
+ TEST_P(ag->ag_latest_leg, ag->ag_alice_leg);
+
+ nta_agent_set_params(ag->ag_agent,
+ NTATAG_DEBUG_DROP_PROB(0),
+ TAG_END());
+
+ /* Send BYE from Bob to Alice */
+ old_leg = ag->ag_expect_leg = ag->ag_alice_leg;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_bob_leg, outgoing_callback, ag,
+ NULL,
+ SIP_METHOD_BYE,
+ NULL,
+ SIPTAG_SUBJECT_STR("Hangup"),
+ SIPTAG_FROM(ag->ag_alice),
+ SIPTAG_TO(ag->ag_bob),
+ SIPTAG_CONTACT(ag->ag_m_alice),
+ SIPTAG_CONTENT_TYPE(c),
+ SIPTAG_PAYLOAD(sdp),
+ TAG_END()));
+
+ nta_test_run(ag);
+ TEST(ag->ag_status, 200);
+ TEST_P(ag->ag_orq, NULL);
+ TEST_P(ag->ag_latest_leg, old_leg);
+ TEST_P(ag->ag_alice_leg, NULL);
+
+ nta_leg_destroy(ag->ag_bob_leg), ag->ag_bob_leg = NULL;
+ ag->ag_latest_leg = NULL;
+ ag->ag_call_leg = NULL;
+
+ END();
+}
+
+/* ============================================================================ */
+/* Test early dialogs, PRACK */
+
+int test_for_ack_or_timeout(agent_t *ag,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ BEGIN();
+
+ sip_method_t method = sip ? sip->sip_request->rq_method : sip_method_unknown;
+
+ if (method == sip_method_ack) {
+ TEST(method, sip_method_ack);
+
+ ag->ag_status = 200;
+ }
+ else if (method == sip_method_cancel) {
+ nta_incoming_treply(irq, SIP_487_REQUEST_CANCELLED, TAG_END());
+ }
+ else {
+ if (ag->ag_bob_leg) {
+ nta_leg_destroy(ag->ag_bob_leg), ag->ag_bob_leg = NULL;
+ }
+ }
+
+ nta_incoming_destroy(irq);
+ TEST_P(irq, ag->ag_irq);
+ ag->ag_irq = NULL;
+
+ END();
+}
+
+/* */
+int bob_leg_callback2(agent_t *ag,
+ nta_leg_t *leg,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ BEGIN();
+
+ if (tstflags & tst_verbatim) {
+ printf("%s: %s: %s " URL_PRINT_FORMAT " %s\n",
+ name, __func__, sip->sip_request->rq_method_name,
+ URL_PRINT_ARGS(sip->sip_request->rq_url),
+ sip->sip_request->rq_version);
+ }
+
+ TEST_1(sip->sip_content_length);
+ TEST_1(sip->sip_via);
+ TEST_1(sip->sip_from && sip->sip_from->a_tag);
+
+ ag->ag_latest_leg = leg;
+
+ if (ag->ag_bob_leg && leg != ag->ag_bob_leg) {
+ leg_match(ag, leg, 1, __func__);
+ return 500;
+ }
+
+ if (ag->ag_bob_leg == NULL) {
+ nta_leg_bind(leg, leg_callback_500, ag);
+ ag->ag_bob_leg = nta_leg_tcreate(ag->ag_agent,
+ bob_leg_callback,
+ ag,
+ SIPTAG_CALL_ID(sip->sip_call_id),
+ SIPTAG_FROM(sip->sip_to),
+ SIPTAG_TO(sip->sip_from),
+ TAG_END());
+ TEST_1(ag->ag_bob_leg);
+ TEST_1(nta_leg_tag(ag->ag_bob_leg, NULL));
+ TEST_1(nta_leg_get_tag(ag->ag_bob_leg));
+ TEST_1(nta_incoming_tag(irq, nta_leg_get_tag(ag->ag_bob_leg)));
+ TEST(nta_leg_server_route(ag->ag_bob_leg,
+ sip->sip_record_route,
+ sip->sip_contact), 0);
+ }
+
+ if (sip->sip_request->rq_method != sip_method_invite) {
+ return 200;
+ } else {
+ nta_incoming_bind(irq, test_for_ack_or_timeout, ag);
+ nta_incoming_treply(irq,
+ SIP_183_SESSION_PROGRESS,
+ SIPTAG_CONTENT_TYPE(ag->ag_content_type),
+ SIPTAG_PAYLOAD(ag->ag_payload),
+ SIPTAG_CONTACT(ag->ag_m_bob),
+ TAG_END());
+ if (0)
+ nta_incoming_treply(irq,
+ SIP_180_RINGING,
+ SIPTAG_CONTENT_TYPE(ag->ag_content_type),
+ SIPTAG_PAYLOAD(ag->ag_payload),
+ SIPTAG_CONTACT(ag->ag_m_bob),
+ TAG_END());
+ nta_incoming_treply(irq,
+ SIP_200_OK,
+ SIPTAG_CONTACT(ag->ag_m_bob),
+ TAG_END());
+ ag->ag_irq = irq;
+ }
+
+ END();
+}
+
+
+int invite_prack_callback(agent_t *ag,
+ nta_outgoing_t *orq,
+ sip_t const *sip)
+{
+ BEGIN();
+
+ int status = sip->sip_status->st_status;
+
+ if (tstflags & tst_verbatim) {
+ printf("%s: %s: %s %03d %s\n", name, __func__,
+ sip->sip_status->st_version,
+ sip->sip_status->st_status,
+ sip->sip_status->st_phrase);
+ }
+
+ if (!ag->ag_call_tag && (status >= 200 || (status > 100 && sip->sip_rseq))) {
+ nta_outgoing_t *tagged;
+ TEST_1(sip->sip_to->a_tag);
+ ag->ag_tag_status = status;
+ ag->ag_call_tag = su_strdup(ag->ag_home, sip->sip_to->a_tag);
+ TEST_S(ag->ag_call_tag, sip->sip_to->a_tag);
+ TEST_S(nta_leg_rtag(ag->ag_call_leg, ag->ag_call_tag), ag->ag_call_tag);
+ TEST(nta_leg_client_route(ag->ag_call_leg,
+ sip->sip_record_route,
+ sip->sip_contact), 0);
+ tagged = nta_outgoing_tagged(orq,
+ invite_prack_callback,
+ ag,
+ ag->ag_call_tag,
+ sip->sip_rseq);
+ TEST_1(tagged);
+ nta_outgoing_destroy(orq);
+ if (ag->ag_orq == orq)
+ ag->ag_orq = tagged;
+ orq = tagged;
+ }
+
+ if (status > 100 && status < 200 && sip->sip_rseq) {
+ nta_outgoing_t *prack;
+ prack = nta_outgoing_prack(ag->ag_call_leg, orq, NULL, NULL,
+ NULL,
+ sip,
+ TAG_END());
+ TEST_1(prack);
+ nta_outgoing_destroy(prack);
+ return 0;
+ }
+
+ if (status < 200)
+ return 0;
+
+ if (status < 300) {
+ nta_outgoing_t *ack;
+ msg_t *msg;
+ sip_t *osip;
+
+ TEST_1(msg = nta_outgoing_getrequest(orq));
+ TEST_1(osip = sip_object(msg));
+
+ TEST_1(nta_leg_rtag(ag->ag_call_leg, sip->sip_to->a_tag));
+
+ TEST(nta_leg_client_route(ag->ag_call_leg,
+ sip->sip_record_route,
+ sip->sip_contact), 0);
+
+ ack = nta_outgoing_tcreate(ag->ag_call_leg, NULL, NULL,
+ NULL,
+ SIP_METHOD_ACK,
+ NULL,
+ SIPTAG_CSEQ(sip->sip_cseq),
+ NTATAG_ACK_BRANCH(osip->sip_via->v_branch),
+ TAG_END());
+ TEST_1(ack);
+ nta_outgoing_destroy(ack);
+ msg_destroy(msg);
+ }
+ else {
+ ag->ag_status = status;
+ }
+
+ TEST_1(sip->sip_to && sip->sip_to->a_tag);
+
+ nta_outgoing_destroy(orq);
+ ag->ag_orq = NULL;
+ ag->ag_call_leg = NULL;
+
+ END();
+}
+
+static int process_prack(nta_reliable_magic_t *arg,
+ nta_reliable_t *rel,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ agent_t *ag = (agent_t *)arg;
+ if (ag->ag_irq) {
+ nta_incoming_treply(ag->ag_irq,
+ 504, "Reliable Response Timeout",
+ TAG_END());
+ nta_incoming_destroy(ag->ag_irq);
+ }
+ return 504;
+}
+
+/* send invite, wait for 183, send CANCEL */
+int bob_leg_callback3(agent_t *ag,
+ nta_leg_t *leg,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ BEGIN();
+
+ if (tstflags & tst_verbatim) {
+ printf("%s: %s: %s " URL_PRINT_FORMAT " %s\n",
+ name, __func__, sip->sip_request->rq_method_name,
+ URL_PRINT_ARGS(sip->sip_request->rq_url),
+ sip->sip_request->rq_version);
+ }
+
+ TEST_1(sip->sip_content_length);
+ TEST_1(sip->sip_via);
+ TEST_1(sip->sip_from && sip->sip_from->a_tag);
+
+ ag->ag_latest_leg = leg;
+
+ if (ag->ag_bob_leg && leg != ag->ag_bob_leg) {
+ leg_match(ag, leg, 1, __func__);
+ return 500;
+ }
+
+ if (ag->ag_bob_leg == NULL) {
+ nta_leg_bind(leg, leg_callback_500, ag);
+ ag->ag_bob_leg = nta_leg_tcreate(ag->ag_agent,
+ bob_leg_callback,
+ ag,
+ SIPTAG_CALL_ID(sip->sip_call_id),
+ SIPTAG_FROM(sip->sip_to),
+ SIPTAG_TO(sip->sip_from),
+ TAG_END());
+ TEST_1(ag->ag_bob_leg);
+ TEST_1(nta_leg_tag(ag->ag_bob_leg, NULL));
+ TEST_1(nta_leg_get_tag(ag->ag_bob_leg));
+ TEST_1(nta_incoming_tag(irq, nta_leg_get_tag(ag->ag_bob_leg)));
+ TEST(nta_leg_server_route(ag->ag_bob_leg,
+ sip->sip_record_route,
+ sip->sip_contact), 0);
+ }
+
+ if (sip->sip_request->rq_method != sip_method_invite) {
+ return 200;
+ } else {
+ nta_reliable_t *rel;
+ nta_incoming_bind(irq, test_for_ack_or_timeout, ag);
+ rel = nta_reliable_treply(irq, process_prack, ag,
+ SIP_183_SESSION_PROGRESS,
+ SIPTAG_CONTENT_TYPE(ag->ag_content_type),
+ SIPTAG_PAYLOAD(ag->ag_payload),
+ SIPTAG_CONTACT(ag->ag_m_bob),
+ TAG_END());
+ ag->ag_irq = irq;
+ }
+
+ END();
+}
+
+
+int invite_183_cancel_callback(agent_t *ag,
+ nta_outgoing_t *orq,
+ sip_t const *sip)
+{
+ BEGIN();
+
+ int status = sip->sip_status->st_status;
+
+ if (tstflags & tst_verbatim) {
+ printf("%s: %s: %s %03d %s\n", name, __func__,
+ sip->sip_status->st_version,
+ sip->sip_status->st_status,
+ sip->sip_status->st_phrase);
+ }
+
+ if (status > 100 && status < 200) {
+ nta_outgoing_cancel(orq);
+ return 0;
+ }
+
+ if (status < 200)
+ return 0;
+
+ if (status < 300) {
+ nta_outgoing_t *ack;
+ msg_t *msg;
+ sip_t *osip;
+
+ TEST_1(msg = nta_outgoing_getrequest(orq));
+ TEST_1(osip = sip_object(msg));
+
+ TEST_1(nta_leg_rtag(ag->ag_call_leg, sip->sip_to->a_tag));
+
+ TEST(nta_leg_client_route(ag->ag_call_leg,
+ sip->sip_record_route,
+ sip->sip_contact), 0);
+
+ ack = nta_outgoing_tcreate(ag->ag_call_leg, NULL, NULL,
+ NULL,
+ SIP_METHOD_ACK,
+ NULL,
+ SIPTAG_CSEQ(sip->sip_cseq),
+ NTATAG_ACK_BRANCH(osip->sip_via->v_branch),
+ TAG_END());
+ TEST_1(ack);
+ nta_outgoing_destroy(ack);
+ msg_destroy(msg);
+ }
+ else {
+ ag->ag_status = status;
+ }
+
+ TEST_1(sip->sip_to && sip->sip_to->a_tag);
+
+ nta_outgoing_destroy(orq);
+ ag->ag_orq = NULL;
+ ag->ag_call_leg = NULL;
+
+ END();
+}
+
+/*
+ * Test establishing a call with an early dialog / 100 rel / timeout
+ *
+ * Alice sends a INVITE to Bob, then Bob sends 183, Alice sends PRACK,
+ * Bob sends 200 to PRACK, Bob sends 200 to INVITE.
+ * Bob sends BYE, Alice 200.
+ */
+
+int test_prack(agent_t *ag)
+{
+ sip_content_type_t *c = ag->ag_content_type;
+ sip_payload_t *sdp = ag->ag_payload;
+ nta_leg_t *old_leg;
+
+ BEGIN();
+
+ {
+ /* Send a PRACK from default leg, NTA responds to it with error */
+ url_t url[1];
+
+ *url = *ag->ag_aliases->m_url;
+ url->url_user = "bob";
+
+ ag->ag_expect_leg = ag->ag_server_leg;
+ ag->ag_latest_leg = NULL;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ag,
+ ag->ag_obp,
+ SIP_METHOD_PRACK,
+ (url_string_t *)url,
+ SIPTAG_SUBJECT_STR("Test 1.1"),
+ SIPTAG_FROM(ag->ag_alice),
+ SIPTAG_TO(ag->ag_bob),
+ SIPTAG_CONTACT(ag->ag_m_alice),
+ SIPTAG_RACK_STR("1432432 42332432 INVITE"),
+ TAG_END()));
+ nta_test_run(ag);
+ TEST(ag->ag_status, 481);
+ TEST_P(ag->ag_orq, NULL);
+ TEST_P(ag->ag_latest_leg, NULL);
+ }
+
+ TEST_1(ag->ag_alice_leg = nta_leg_tcreate(ag->ag_agent,
+ alice_leg_callback,
+ ag,
+ SIPTAG_FROM(ag->ag_alice),
+ SIPTAG_TO(ag->ag_bob),
+ TAG_END()));
+ TEST_1(nta_leg_tag(ag->ag_alice_leg, NULL));
+
+ /* Send INVITE */
+ nta_leg_bind(ag->ag_server_leg, bob_leg_callback2, ag);
+ ag->ag_expect_leg = ag->ag_server_leg;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_call_leg = ag->ag_alice_leg,
+ invite_prack_callback, ag,
+ ag->ag_obp,
+ SIP_METHOD_INVITE,
+ (url_string_t *)ag->ag_m_bob->m_url,
+ SIPTAG_SUBJECT_STR("Call 2"),
+ SIPTAG_CONTACT(ag->ag_m_alice),
+ SIPTAG_REQUIRE_STR("100rel"),
+ SIPTAG_CONTENT_TYPE(c),
+ SIPTAG_PAYLOAD(sdp),
+ TAG_END()));
+ nta_test_run(ag);
+ TEST(ag->ag_status, 200);
+ /*TEST(ag->ag_tag_status, 183);*/
+ TEST_P(ag->ag_orq, NULL);
+ TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
+ TEST_1(ag->ag_bob_leg != NULL);
+
+ /* Send BYE from Bob to Alice */
+ old_leg = ag->ag_expect_leg = ag->ag_alice_leg;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_bob_leg, outgoing_callback, ag,
+ NULL,
+ SIP_METHOD_BYE,
+ NULL,
+ SIPTAG_SUBJECT_STR("Hangup"),
+ SIPTAG_FROM(ag->ag_alice),
+ SIPTAG_TO(ag->ag_bob),
+ SIPTAG_CONTACT(ag->ag_m_alice),
+ SIPTAG_CONTENT_TYPE(c),
+ SIPTAG_PAYLOAD(sdp),
+ TAG_END()));
+
+ nta_test_run(ag);
+ TEST(ag->ag_status, 200);
+ TEST_P(ag->ag_orq, NULL);
+ TEST_P(ag->ag_latest_leg, old_leg);
+ TEST_P(ag->ag_alice_leg, NULL);
+
+ nta_leg_destroy(ag->ag_bob_leg), ag->ag_bob_leg = NULL;
+ ag->ag_latest_leg = NULL;
+ ag->ag_call_leg = NULL;
+
+ /* Test CANCELing a call after received PRACK */
+ TEST_1(ag->ag_alice_leg = nta_leg_tcreate(ag->ag_agent,
+ alice_leg_callback,
+ ag,
+ SIPTAG_FROM(ag->ag_alice),
+ SIPTAG_TO(ag->ag_bob),
+ TAG_END()));
+ TEST_1(nta_leg_tag(ag->ag_alice_leg, NULL));
+
+ /* Send INVITE */
+ nta_leg_bind(ag->ag_server_leg, bob_leg_callback3, ag);
+ ag->ag_expect_leg = ag->ag_server_leg;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_call_leg = ag->ag_alice_leg,
+ invite_183_cancel_callback, ag,
+ ag->ag_obp,
+ SIP_METHOD_INVITE,
+ (url_string_t *)ag->ag_m_bob->m_url,
+ SIPTAG_SUBJECT_STR("Call 2b"),
+ SIPTAG_CONTACT(ag->ag_m_alice),
+ SIPTAG_REQUIRE_STR("100rel"),
+ SIPTAG_CONTENT_TYPE(c),
+ SIPTAG_PAYLOAD(sdp),
+ TAG_END()));
+ nta_test_run(ag);
+ TEST_1(ag->ag_status == 487 || ag->ag_status == 504);
+ TEST_P(ag->ag_orq, NULL);
+ TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
+ TEST_1(ag->ag_bob_leg != NULL);
+
+ nta_leg_destroy(ag->ag_bob_leg), ag->ag_bob_leg = NULL;
+ ag->ag_latest_leg = NULL;
+ ag->ag_call_leg = NULL;
+
+ if (getenv("EXPENSIVE_CHECKS")) {
+ printf("%s: starting 100rel timeout test, test will complete in 4 seconds\n",
+ name);
+
+ TEST(nta_agent_set_params(ag->ag_agent,
+ NTATAG_SIP_T1(25),
+ NTATAG_SIP_T1X64(64 * 25),
+ TAG_END()), 2);
+
+ TEST_1(ag->ag_alice_leg = nta_leg_tcreate(ag->ag_agent,
+ alice_leg_callback,
+ ag,
+ SIPTAG_FROM(ag->ag_alice),
+ SIPTAG_TO(ag->ag_bob),
+ TAG_END()));
+ TEST_1(nta_leg_tag(ag->ag_alice_leg, NULL));
+
+ /* Send INVITE,
+ * send precious provisional response
+ * do not send PRACK,
+ * timeout (after 64 * t1 ~ 3.2 seconds),
+ */
+ nta_leg_bind(ag->ag_server_leg, bob_leg_callback2, ag);
+ ag->ag_expect_leg = ag->ag_server_leg;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_call_leg = ag->ag_alice_leg,
+ outgoing_callback, ag,
+ ag->ag_obp,
+ SIP_METHOD_INVITE,
+ (url_string_t *)ag->ag_m_bob->m_url,
+ SIPTAG_SUBJECT_STR("Call 3"),
+ SIPTAG_CONTACT(ag->ag_m_alice),
+ SIPTAG_REQUIRE_STR("100rel"),
+ SIPTAG_CONTENT_TYPE(c),
+ SIPTAG_PAYLOAD(sdp),
+ TAG_END()));
+ nta_test_run(ag);
+ TEST(ag->ag_status, 503);
+ TEST_P(ag->ag_orq, NULL);
+ TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
+ TEST_1(ag->ag_bob_leg == NULL);
+
+ TEST(nta_agent_set_params(ag->ag_agent,
+ NTATAG_SIP_T1(500),
+ NTATAG_SIP_T1X64(64 * 500),
+ TAG_END()), 2);
+ }
+ END();
+/*
+ nta_leg_destroy(ag->ag_bob_leg), ag->ag_bob_leg = NULL;
+ ag->ag_latest_leg = NULL;
+ ag->ag_call_leg = NULL;
+ if (ag->ag_call_tag)
+ su_free(ag->ag_home, (void *)ag->ag_call_tag), ag->ag_call_tag = NULL;
+*/
+}
+
+int alice_leg_callback2(agent_t *ag,
+ nta_leg_t *leg,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ BEGIN();
+
+ if (tstflags & tst_verbatim) {
+ printf("%s: %s: %s " URL_PRINT_FORMAT " %s\n",
+ name, __func__, sip->sip_request->rq_method_name,
+ URL_PRINT_ARGS(sip->sip_request->rq_url),
+ sip->sip_request->rq_version);
+ }
+
+ TEST_1(sip->sip_content_length);
+ TEST_1(sip->sip_via);
+ TEST_1(sip->sip_from && sip->sip_from->a_tag);
+
+ if (sip->sip_request->rq_method == sip_method_prack)
+ return 481;
+
+ ag->ag_latest_leg = leg;
+
+ if (leg != ag->ag_alice_leg) {
+ leg_match(ag, leg, 1, __func__);
+ return 500;
+ }
+
+ if (sip->sip_request->rq_method == sip_method_invite) {
+ TEST_1(sip_has_feature(sip->sip_supported, "100rel"));
+ nta_incoming_bind(irq, test_for_ack, ag);
+ nta_incoming_treply(irq, SIP_100_TRYING, TAG_END());
+
+ nta_agent_set_params(ag->ag_agent,
+ NTATAG_DEBUG_DROP_PROB(ag->ag_drop),
+ TAG_END());
+ ag->ag_reliable =
+ nta_reliable_treply(irq,
+ NULL, NULL,
+ SIP_183_SESSION_PROGRESS,
+ SIPTAG_CONTENT_TYPE(ag->ag_content_type),
+ SIPTAG_PAYLOAD(ag->ag_payload),
+ SIPTAG_CONTACT(ag->ag_m_alice),
+ TAG_END());
+ TEST_1(ag->ag_reliable);
+ ag->ag_reliable =
+ nta_reliable_treply(irq,
+ NULL, NULL,
+ 184, "Next",
+ SIPTAG_CONTACT(ag->ag_m_alice),
+ TAG_END());
+ TEST_1(ag->ag_reliable);
+ ag->ag_reliable =
+ nta_reliable_treply(irq,
+ NULL, NULL,
+ 185, "Last",
+ SIPTAG_CONTACT(ag->ag_m_alice),
+ TAG_END());
+ TEST_1(ag->ag_reliable);
+ TEST(nta_incoming_treply(irq, SIP_200_OK, TAG_END()), 0);
+ ag->ag_irq = irq;
+ return 0;
+ }
+
+ if (sip->sip_request->rq_method == sip_method_bye) {
+ leg_zap(ag, leg);
+ }
+
+ if(sip)
+ return 200;
+
+ END();
+}
+/*
+ * Test establishing a call with an early dialog / 100 rel / timeout
+ *
+ * Alice sends a INVITE to Bob, then Bob sends 183, 184, 185, and 200.
+ * Bob sends BYE, Alice 200.
+ *
+ * See bug #467.
+ */
+int test_fix_467(agent_t *ag)
+{
+ sip_content_type_t *c = ag->ag_content_type;
+ sip_payload_t *sdp = ag->ag_payload;
+ nta_leg_t *old_leg;
+
+ BEGIN();
+
+ TEST_1(ag->ag_alice_leg = nta_leg_tcreate(ag->ag_agent,
+ alice_leg_callback2,
+ ag,
+ SIPTAG_FROM(ag->ag_alice),
+ SIPTAG_TO(ag->ag_bob),
+ TAG_END()));
+ TEST_1(nta_leg_tag(ag->ag_alice_leg, NULL));
+ ag->ag_bob_leg = NULL;
+ ag->ag_call_tag = NULL;
+
+ /* Send INVITE */
+ nta_leg_bind(ag->ag_server_leg, bob_leg_callback2, ag);
+ ag->ag_expect_leg = ag->ag_server_leg;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_call_leg = ag->ag_alice_leg,
+ invite_prack_callback, ag,
+ ag->ag_obp,
+ SIP_METHOD_INVITE,
+ (url_string_t *)ag->ag_m_bob->m_url,
+ SIPTAG_SUBJECT_STR("Call 5"),
+ SIPTAG_CONTACT(ag->ag_m_alice),
+ SIPTAG_REQUIRE_STR("100rel"),
+ SIPTAG_CONTENT_TYPE(c),
+ SIPTAG_PAYLOAD(sdp),
+ TAG_END()));
+ nta_test_run(ag);
+ TEST(ag->ag_status, 200);
+ /*TEST(ag->ag_tag_status, 183);*/
+ TEST_P(ag->ag_orq, NULL);
+ TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
+ TEST_1(ag->ag_bob_leg != NULL);
+
+ /* Send BYE from Bob to Alice */
+ old_leg = ag->ag_expect_leg = ag->ag_alice_leg;
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_bob_leg, outgoing_callback, ag,
+ NULL,
+ SIP_METHOD_BYE,
+ NULL,
+ SIPTAG_SUBJECT_STR("Hangup"),
+ SIPTAG_FROM(ag->ag_alice),
+ SIPTAG_TO(ag->ag_bob),
+ SIPTAG_CONTACT(ag->ag_m_alice),
+ SIPTAG_CONTENT_TYPE(c),
+ SIPTAG_PAYLOAD(sdp),
+ TAG_END()));
+
+
+ nta_test_run(ag);
+ TEST(ag->ag_status, 200);
+ TEST_P(ag->ag_orq, NULL);
+ TEST_P(ag->ag_latest_leg, old_leg);
+ TEST_P(ag->ag_alice_leg, NULL);
+
+ END();
+/*
+ nta_leg_destroy(ag->ag_bob_leg), ag->ag_bob_leg = NULL;
+ ag->ag_latest_leg = NULL;
+ ag->ag_call_leg = NULL;
+*/
+}
+
+#if HAVE_ALARM
+#include <unistd.h>
+#include <signal.h>
+
+static RETSIGTYPE sig_alarm(int s)
+{
+ fprintf(stderr, "%s: FAIL! test timeout!\n", name);
+ exit(1);
+}
+#endif
+
+static
+char const nta_test_usage[] =
+ "usage: %s OPTIONS\n"
+ "where OPTIONS are\n"
+ " -v | --verbose be verbose\n"
+ " -q | --quiet be quiet\n"
+ " -1 quit on first error\n"
+ " -l level set logging level (0 by default)\n"
+ " -p uri specify uri of outbound proxy\n"
+ " -m uri bind to local uri\n"
+ " --attach print pid, wait for a debugger to be attached\n"
+#if HAVE_ALARM
+ " --no-alarm don't ask for guard ALARM\n"
+#endif
+ ;
+
+void usage(void)
+{
+ fprintf(stderr, nta_test_usage, name);
+ exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+ int retval = 0, quit_on_single_failure = 0;
+ int i, o_attach = 0, o_alarm = 1;
+
+ agent_t ag[1] = {{ { SU_HOME_INIT(ag) }, 0, NULL }};
+
+ for (i = 1; argv[i]; i++) {
+ if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--verbose") == 0)
+ tstflags |= tst_verbatim;
+ else if (strcmp(argv[i], "-q") == 0 || strcmp(argv[i], "--quiet") == 0)
+ tstflags &= ~tst_verbatim;
+ else if (strcmp(argv[i], "-1") == 0)
+ quit_on_single_failure = 1;
+ else if (strncmp(argv[i], "-l", 2) == 0) {
+ int level = 3;
+ char *rest = NULL;
+
+ if (argv[i][2])
+ level = strtol(argv[i] + 2, &rest, 10);
+ else if (argv[i + 1])
+ level = strtol(argv[i + 1], &rest, 10), i++;
+ else
+ level = 3, rest = "";
+
+ if (rest == NULL || *rest)
+ usage();
+
+ su_log_set_level(nta_log, level);
+ su_log_set_level(tport_log, level);
+ }
+ else if (strncmp(argv[i], "-p", 2) == 0) {
+ if (argv[i][2])
+ ag->ag_obp = (url_string_t *)(argv[i] + 2);
+ else if (argv[i + 1])
+ ag->ag_obp = (url_string_t *)(argv[++i]);
+ else
+ usage();
+ }
+ else if (strncmp(argv[i], "-m", 2) == 0) {
+ if (argv[i][2])
+ ag->ag_m = argv[i] + 2;
+ else if (argv[i + 1])
+ ag->ag_m = argv[++i];
+ else
+ usage();
+ }
+ else if (strcmp(argv[i], "--attach") == 0) {
+ o_attach = 1;
+ }
+ else if (strcmp(argv[i], "--no-alarm") == 0) {
+ o_alarm = 0;
+ }
+ else if (strcmp(argv[i], "-") == 0) {
+ i++; break;
+ }
+ else if (argv[i][0] != '-') {
+ break;
+ }
+ else
+ usage();
+ }
+
+ if (o_attach) {
+ char line[10], *got;
+ printf("nua_test: pid %u\n", getpid());
+ printf("<Press RETURN to continue>\n");
+ got = fgets(line, sizeof line, stdin); (void)got;
+ }
+#if HAVE_ALARM
+ else if (o_alarm) {
+ alarm(60);
+ signal(SIGALRM, sig_alarm);
+ }
+#endif
+
+ su_init();
+
+ if (!(TSTFLAGS & tst_verbatim)) {
+ su_log_soft_set_level(nta_log, 0);
+ su_log_soft_set_level(tport_log, 0);
+ }
+
+#define SINGLE_FAILURE_CHECK() \
+ do { fflush(stdout); \
+ if (retval && quit_on_single_failure) { su_deinit(); return retval; } \
+ } while(0)
+
+ retval |= test_init(ag, argv[i]); SINGLE_FAILURE_CHECK();
+ if (retval == 0) {
+ retval |= test_bad_messages(ag); SINGLE_FAILURE_CHECK();
+ retval |= test_reinit(ag); SINGLE_FAILURE_CHECK();
+ retval |= test_tports(ag); SINGLE_FAILURE_CHECK();
+ retval |= test_destroy_incoming(ag); SINGLE_FAILURE_CHECK();
+ retval |= test_resolv(ag, argv[i]); SINGLE_FAILURE_CHECK();
+ retval |= test_routing(ag); SINGLE_FAILURE_CHECK();
+ retval |= test_dialog(ag); SINGLE_FAILURE_CHECK();
+ retval |= test_call(ag); SINGLE_FAILURE_CHECK();
+ retval |= test_prack(ag); SINGLE_FAILURE_CHECK();
+ retval |= test_fix_467(ag); SINGLE_FAILURE_CHECK();
+ }
+ retval |= test_deinit(ag); fflush(stdout);
+
+ su_home_deinit(ag->ag_home);
+
+ su_deinit();
+
+ return retval;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/test_nta_api.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/test_nta_api.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1345 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@internal
+ * @CFILE test_nta_api.c
+ *
+ * Test functions for NTA.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Aug 21 15:18:26 2001 ppessi
+ */
+
+#include "config.h"
+
+typedef struct agent_t agent_t;
+#define SU_ROOT_MAGIC_T agent_t
+
+#include <sofia-sip/su_wait.h>
+
+#include <msg_internal.h>
+
+#define NTA_AGENT_MAGIC_T agent_t
+#define NTA_LEG_MAGIC_T agent_t
+#define NTA_OUTGOING_MAGIC_T agent_t
+#define NTA_INCOMING_MAGIC_T agent_t
+#define NTA_RELIABLE_MAGIC_T agent_t
+
+#include "sofia-sip/nta.h"
+#include "nta_internal.h"
+#include <sofia-sip/sip_header.h>
+#include <sofia-sip/sip_tag.h>
+#include <sofia-sip/sip_status.h>
+#include <sofia-sip/tport.h>
+#include <sofia-sip/htable.h>
+#include <sofia-sip/sresolv.h>
+#include <sofia-sip/su_log.h>
+#include <sofia-sip/msg_mclass.h>
+#include <sofia-sip/sofia_features.h>
+#include <sofia-sip/hostdomain.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <stdio.h>
+#include <assert.h>
+#include <time.h>
+#include "sofia-sip/string0.h"
+
+extern su_log_t nta_log[];
+extern su_log_t tport_log[];
+
+int tstflags = 0;
+#define TSTFLAGS tstflags
+char const name[] = "test_nta_api";
+
+#include <sofia-sip/tstdef.h>
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+#define __func__ name
+#endif
+
+#define NONE ((void *)-1)
+
+struct sigcomp_compartment;
+
+struct agent_t {
+ su_home_t ag_home[1];
+ int ag_flags;
+ su_root_t *ag_root;
+ msg_mclass_t *ag_mclass;
+ nta_agent_t *ag_agent;
+
+ nta_leg_t *ag_default_leg; /**< Leg for rest */
+ nta_leg_t *ag_server_leg; /**< Leg for <sip:%@%>;methods=<PUBLISH>;events=<presence> */
+
+ unsigned ag_drop;
+
+ nta_outgoing_t *ag_orq;
+ int ag_status;
+ msg_t *ag_response;
+
+ /* Server side */
+ nta_incoming_t *ag_irq;
+
+ sip_contact_t const *ag_contact;
+ sip_from_t *ag_alice;
+ sip_to_t *ag_bob;
+
+ sip_contact_t *ag_m_alice;
+ sip_contact_t *ag_m_bob;
+ sip_contact_t *ag_aliases;
+
+ nta_leg_t *ag_alice_leg;
+ nta_leg_t *ag_bob_leg;
+
+ msg_t *ag_request;
+
+ nta_leg_t *ag_expect_leg;
+ nta_leg_t *ag_latest_leg;
+ nta_leg_t *ag_call_leg;
+ nta_leg_t *ag_tag_remote; /**< If this is set, outgoing_callback()
+ * tags it with the tag from remote.
+ */
+ int ag_tag_status; /**< Which response established dialog */
+ msg_param_t ag_call_tag; /**< Tag used to establish dialog */
+
+ nta_reliable_t *ag_reliable;
+
+ sip_via_t *ag_out_via; /**< Outgoing via */
+ sip_via_t *ag_in_via; /**< Incoming via */
+
+ sip_content_type_t *ag_content_type;
+ sip_payload_t *ag_payload;
+
+ msg_t *ag_probe_msg;
+};
+
+
+static int incoming_callback_1(agent_t *ag,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ return 0;
+}
+
+static int incoming_callback_2(agent_t *ag,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ return 0;
+}
+
+int agent_callback(agent_t *ag,
+ nta_agent_t *nta,
+ msg_t *msg,
+ sip_t *sip)
+{
+ msg_destroy(msg);
+ return 0;
+}
+
+int leg_callback(agent_t *ag,
+ nta_leg_t *leg,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ BEGIN();
+ msg_t *msg;
+ char const *tag;
+
+ if (tstflags & tst_verbatim) {
+ printf("%s: %s: %s " URL_PRINT_FORMAT " %s\n",
+ name, __func__, sip->sip_request->rq_method_name,
+ URL_PRINT_ARGS(sip->sip_request->rq_url),
+ sip->sip_request->rq_version);
+ }
+
+ TEST_1(sip->sip_content_length);
+ TEST_1(sip->sip_via);
+ TEST_1(sip->sip_from && sip->sip_from->a_tag);
+
+ TEST_VOID(nta_incoming_bind(irq, incoming_callback_1, ag));
+ TEST_P(nta_incoming_magic(irq, incoming_callback_1), ag);
+ TEST_P(nta_incoming_magic(irq, incoming_callback_2), 0);
+
+ TEST_1(tag = nta_incoming_tag(irq, "tag=foofaa"));
+ TEST_S(nta_incoming_gettag(irq), tag);
+ TEST_S(tag, "foofaa");
+ TEST_1(tag = nta_incoming_tag(irq, "foofaa"));
+
+ TEST(nta_incoming_status(irq), 0);
+ TEST(nta_incoming_method(irq), sip_method_message);
+ TEST_S(nta_incoming_method_name(irq), "MESSAGE");
+ TEST_1(nta_incoming_url(irq) != NULL);
+ TEST_1(nta_incoming_cseq(irq) != 0);
+
+ TEST(nta_incoming_set_params(irq, TAG_END()), 0);
+
+ TEST_1(msg = nta_incoming_getrequest(irq)); msg_destroy(msg);
+ TEST_P(nta_incoming_getrequest_ackcancel(irq), NULL);
+ TEST_P(nta_incoming_getresponse(irq), NULL);
+
+ TEST(nta_incoming_treply(irq, SIP_100_TRYING, TAG_END()), 0);
+ TEST_1(msg = nta_incoming_getresponse(irq)); msg_destroy(msg);
+ msg = nta_msg_create(ag->ag_agent, 0);
+ TEST(nta_incoming_complete_response(irq, msg, SIP_200_OK, TAG_END()), 0);
+ TEST(nta_incoming_mreply(irq, msg), 0);
+
+ END();
+}
+
+int outgoing_callback(agent_t *ag,
+ nta_outgoing_t *orq,
+ sip_t const *sip)
+{
+ BEGIN();
+ msg_t *msg;
+
+ int status = sip->sip_status->st_status;
+
+ if (tstflags & tst_verbatim) {
+ printf("%s: %s: %s %03d %s\n", name, __func__,
+ sip->sip_status->st_version,
+ sip->sip_status->st_status,
+ sip->sip_status->st_phrase);
+ }
+
+ ag->ag_status = status;
+
+ if (status < 200)
+ return 0;
+
+ TEST_1(sip->sip_to && sip->sip_to->a_tag);
+
+ /* Test API functions */
+ TEST(nta_outgoing_status(orq), status);
+ TEST_1(nta_outgoing_request_uri(orq));
+ TEST_1(!nta_outgoing_route_uri(orq));
+ TEST(nta_outgoing_method(orq), sip_method_message);
+ TEST_S(nta_outgoing_method_name(orq), "MESSAGE");
+ TEST(nta_outgoing_cseq(orq), sip->sip_cseq->cs_seq);
+ TEST_1(nta_outgoing_delay(orq) < UINT_MAX);
+
+ TEST_1(msg = nta_outgoing_getresponse(orq));
+ msg_destroy(msg);
+
+ TEST_1(msg = nta_outgoing_getrequest(orq));
+ msg_destroy(msg);
+
+ nta_outgoing_destroy(orq);
+ /* Call it twice */
+ nta_outgoing_destroy(orq);
+
+ ag->ag_orq = NULL;
+
+ END();
+}
+
+void
+nta_test_run(agent_t *ag)
+{
+ time_t now = time(NULL);
+
+ for (ag->ag_status = 0; ag->ag_status < 200;) {
+ if (tstflags & tst_verbatim) {
+ fputs(".", stdout); fflush(stdout);
+ }
+ su_root_step(ag->ag_root, 500L);
+
+ if (!getenv("NTA_TEST_DEBUG") && time(NULL) > now + 5) {
+ fprintf(stderr, "nta_test_run: timeout\n");
+ return;
+ }
+ }
+}
+
+int api_test_init(agent_t *ag)
+{
+ BEGIN();
+
+ char const *contact = NULL;
+
+ if (getenv("SIPCONTACT"))
+ contact = getenv("SIPCONTACT");
+
+ if (contact == NULL || contact[0] == '\0')
+ contact = "sip:0.0.0.0:*;comp=sigcomp";
+
+ TEST_1(ag->ag_root = su_root_create(ag));
+ TEST_1(ag->ag_mclass = msg_mclass_clone(sip_default_mclass(), 0, 0));
+
+ /* Create agent */
+ TEST_1(ag->ag_agent = nta_agent_create(ag->ag_root,
+ (url_string_t *)contact,
+ NULL,
+ NULL,
+ NTATAG_MCLASS(ag->ag_mclass),
+ NTATAG_USE_TIMESTAMP(1),
+ NTATAG_USE_NAPTR(0),
+ NTATAG_USE_SRV(0),
+ NTATAG_PRELOAD(2048),
+ TAG_END()));
+ /* Create a default leg */
+ TEST_1(ag->ag_default_leg = nta_leg_tcreate(ag->ag_agent,
+ leg_callback,
+ ag,
+ NTATAG_NO_DIALOG(1),
+ TAG_END()));
+
+ {
+ /* Initialize our headers */
+ sip_from_t from[1];
+ sip_to_t to[1];
+ sip_contact_t m[1];
+
+ sip_from_init(from);
+ sip_to_init(to);
+ sip_contact_init(m);
+
+ TEST_1(ag->ag_contact = nta_agent_contact(ag->ag_agent));
+
+ *m->m_url = *ag->ag_contact->m_url;
+ m->m_url->url_user = "bob";
+ TEST_1(ag->ag_m_bob = sip_contact_dup(ag->ag_home, m));
+
+ to->a_display = "Bob";
+ *to->a_url = *ag->ag_contact->m_url;
+ to->a_url->url_user = "bob";
+ to->a_url->url_port = NULL;
+ TEST_1(ag->ag_bob = sip_to_dup(ag->ag_home, to));
+
+ url_strip_transport(ag->ag_bob->a_url);
+
+ *m->m_url = *ag->ag_contact->m_url;
+ m->m_url->url_user = "alice";
+ TEST_1(ag->ag_m_alice = sip_contact_dup(ag->ag_home, m));
+
+ from->a_display = "Alice";
+ *from->a_url = *ag->ag_contact->m_url;
+ from->a_url->url_user = "alice";
+ from->a_url->url_port = NULL;
+
+ TEST_1(ag->ag_alice = sip_from_dup(ag->ag_home, from));
+
+ url_strip_transport(ag->ag_alice->a_url);
+ }
+
+ {
+ char const data[] =
+ "v=0\r\n"
+ "o=- 425432 423412 IN IP4 127.0.0.1\r\n"
+ "s= \r\n"
+ "c=IN IP4 127.0.0.1\r\n"
+ "m=5004 audio 8 0\r\n";
+
+ ag->ag_content_type = sip_content_type_make(ag->ag_home, "application/sdp");
+ ag->ag_payload = sip_payload_make(ag->ag_home, data);
+ }
+
+ {
+ sip_contact_t *m;
+
+ ag->ag_aliases =
+ sip_contact_make(ag->ag_home, "sip:127.0.0.1, sip:localhost, sip:[::1]");
+ TEST_1(ag->ag_aliases);
+ TEST_1(ag->ag_aliases->m_next);
+ TEST_1(ag->ag_aliases->m_next->m_next);
+ TEST_P(ag->ag_aliases->m_next->m_next->m_next, NULL);
+
+ for (m = ag->ag_aliases; m; m = m->m_next)
+ m->m_url->url_port = ag->ag_contact->m_url->url_port;
+
+ TEST_1(m = sip_contact_dup(ag->ag_home, ag->ag_contact));
+
+ m->m_next = ag->ag_aliases;
+ ag->ag_aliases = m;
+
+ TEST(nta_agent_set_params(ag->ag_agent,
+ NTATAG_ALIASES(ag->ag_aliases),
+ NTATAG_REL100(1),
+ NTATAG_UA(1),
+ NTATAG_USE_NAPTR(1),
+ NTATAG_USE_SRV(1),
+ TAG_END()),
+ 5);
+
+ TEST(nta_agent_set_params(ag->ag_agent,
+ NTATAG_ALIASES(ag->ag_aliases),
+ NTATAG_DEFAULT_PROXY("sip:127.0.0.1"),
+ TAG_END()), 2);
+
+ TEST(nta_agent_set_params(ag->ag_agent,
+ NTATAG_ALIASES(ag->ag_aliases),
+ NTATAG_DEFAULT_PROXY(NULL),
+ TAG_END()), 2);
+
+ TEST(nta_agent_set_params(ag->ag_agent,
+ NTATAG_DEFAULT_PROXY("tel:+35878008000"),
+ TAG_END()), -1);
+
+ }
+
+ {
+ url_t url[1];
+
+ /* Create the server leg */
+ *url = *ag->ag_aliases->m_url;
+ url->url_user = "%";
+ TEST_1(ag->ag_server_leg = nta_leg_tcreate(ag->ag_agent,
+ leg_callback,
+ ag,
+ NTATAG_NO_DIALOG(1),
+ URLTAG_URL(url),
+ TAG_END()));
+ }
+
+ END();
+}
+
+int api_test_deinit(agent_t *ag)
+{
+ BEGIN();
+
+ if (ag->ag_request) msg_destroy(ag->ag_request), ag->ag_request = NULL;
+ if (ag->ag_response) msg_destroy(ag->ag_response), ag->ag_response = NULL;
+
+ su_free(ag->ag_home, ag->ag_in_via), ag->ag_in_via = NULL;
+
+ nta_leg_destroy(ag->ag_alice_leg);
+ nta_leg_destroy(ag->ag_bob_leg);
+ nta_leg_destroy(ag->ag_default_leg);
+ nta_leg_destroy(ag->ag_server_leg);
+
+ nta_agent_destroy(ag->ag_agent);
+ su_root_destroy(ag->ag_root);
+
+ free(ag->ag_mclass), ag->ag_mclass = NULL;
+
+ END();
+}
+
+/* Get and check parameters */
+int api_test_params(agent_t *ag)
+{
+ BEGIN();
+ nta_agent_t *nta;
+
+ sip_contact_t const *aliases = (void *)-1;
+ msg_mclass_t *mclass = (void *)-1;
+ unsigned sip_t1 = -1;
+ unsigned sip_t2 = -1;
+ unsigned sip_t4 = -1;
+ unsigned debug_drop_prob = -1;
+ int ua = -1;
+ int user_via = -1;
+ int extra_100 = -1;
+ int pass_100 = -1;
+ int timeout_408 = -1;
+ int pass_408 = -1;
+ int merge_482 = -1;
+ int cancel_2543 = -1;
+ int cancel_487 = -1;
+ int rel100 = -1;
+ int use_timestamp = -1;
+ int use_naptr = -1;
+ int use_srv = -1;
+ unsigned preload = (unsigned)-1;
+ char const *s = NONE;
+
+ TEST_1(nta = nta_agent_create(ag->ag_root, (url_string_t *)"sip:*:*",
+ NULL, NULL, TAG_END()));
+ TEST(nta_agent_get_params(nta,
+ NTATAG_MCLASS_REF(mclass),
+ NTATAG_ALIASES_REF(aliases),
+ NTATAG_SIP_T1_REF(sip_t1),
+ NTATAG_SIP_T2_REF(sip_t2),
+ NTATAG_SIP_T4_REF(sip_t4),
+ NTATAG_DEBUG_DROP_PROB_REF(debug_drop_prob),
+ NTATAG_UA_REF(ua),
+ NTATAG_USER_VIA_REF(user_via),
+ NTATAG_EXTRA_100_REF(extra_100),
+ NTATAG_PASS_100_REF(pass_100),
+ NTATAG_TIMEOUT_408_REF(timeout_408),
+ NTATAG_PASS_408_REF(pass_408),
+ NTATAG_MERGE_482_REF(merge_482),
+ NTATAG_CANCEL_2543_REF(cancel_2543),
+ NTATAG_CANCEL_487_REF(cancel_487),
+ NTATAG_REL100_REF(rel100),
+ NTATAG_USE_TIMESTAMP_REF(use_timestamp),
+ NTATAG_USE_NAPTR_REF(use_naptr),
+ NTATAG_USE_SRV_REF(use_srv),
+ TAG_END()),
+ /* Number of parameters */ 19);
+
+ TEST_P(mclass, sip_default_mclass());
+ TEST_P(aliases, NULL);
+ TEST(sip_t1, NTA_SIP_T1);
+ TEST(sip_t2, NTA_SIP_T2);
+ TEST(sip_t4, NTA_SIP_T4);
+ TEST(debug_drop_prob, 0);
+ TEST(ua, 0);
+ TEST(user_via, 0);
+ TEST(extra_100, 0);
+ TEST(pass_100, 0);
+ TEST(timeout_408, 1);
+ TEST(pass_408, 0);
+ TEST(merge_482, 0);
+ TEST(cancel_2543, 0);
+ TEST(cancel_487, 1);
+ TEST(rel100, 0);
+ TEST(use_timestamp, 0);
+ TEST(use_naptr, 1);
+ TEST(use_srv, 1);
+
+ TEST(nta_agent_set_params(NULL,
+ NTATAG_PRELOAD(2048),
+ TAG_END()), -1);
+ TEST(nta_agent_get_params(NULL,
+ NTATAG_PRELOAD_REF(preload),
+ TAG_END()), -1);
+
+ TEST(nta_agent_set_params(nta,
+ NTATAG_PRELOAD(2048),
+ TAG_END()), 1);
+ TEST(nta_agent_get_params(nta,
+ NTATAG_PRELOAD_REF(preload),
+ TAG_END()), 1);
+ TEST(preload, 2048);
+
+ TEST(nta_agent_set_params(nta,
+ NTATAG_SIGCOMP_OPTIONS("sip"),
+ TAG_END()), 1);
+ TEST(nta_agent_set_params(nta,
+ NTATAG_SIGCOMP_OPTIONS(","),
+ TAG_END()), -1);
+ TEST(nta_agent_set_params(nta,
+ NTATAG_SIGCOMP_OPTIONS("sip;dms=16384"),
+ TAG_END()), 1);
+ s = NONE;
+ TEST(nta_agent_get_params(nta,
+ NTATAG_SIGCOMP_OPTIONS_REF(s),
+ TAG_END()), 1);
+ TEST_S(s, "sip;dms=16384");
+
+ TEST_VOID(nta_agent_destroy(nta));
+
+ END();
+}
+
+int api_test_stats(agent_t *ag)
+{
+ BEGIN();
+
+ nta_agent_t *nta;
+
+ uint32_t irq_hash = -1, orq_hash = -1, leg_hash = -1;
+ uint32_t recv_msg = -1, sent_msg = -1;
+ uint32_t recv_request = -1, recv_response = -1;
+ uint32_t bad_message = -1, bad_request = -1, bad_response = -1;
+ uint32_t drop_request = -1, drop_response = -1;
+ uint32_t client_tr = -1, server_tr = -1, dialog_tr = -1;
+ uint32_t acked_tr = -1, canceled_tr = -1;
+ uint32_t trless_request = -1, trless_to_tr = -1, trless_response = -1;
+ uint32_t trless_200 = -1, merged_request = -1;
+ uint32_t sent_request = -1, sent_response = -1;
+ uint32_t retry_request = -1, retry_response = -1, recv_retry = -1;
+ uint32_t tout_request = -1, tout_response = -1;
+
+ TEST_1(nta = nta_agent_create(ag->ag_root, (url_string_t *)"sip:*:*",
+ NULL, NULL, TAG_END()));
+
+ TEST(nta_agent_get_stats(NULL,
+ NTATAG_S_TOUT_REQUEST_REF(tout_request),
+ NTATAG_S_TOUT_RESPONSE_REF(tout_response),
+ TAG_END()), -1);
+
+ TEST(nta_agent_get_stats(nta,
+ NTATAG_S_IRQ_HASH_REF(irq_hash),
+ NTATAG_S_ORQ_HASH_REF(orq_hash),
+ NTATAG_S_LEG_HASH_REF(leg_hash),
+ NTATAG_S_RECV_MSG_REF(recv_msg),
+ NTATAG_S_SENT_MSG_REF(sent_msg),
+ NTATAG_S_RECV_REQUEST_REF(recv_request),
+ NTATAG_S_RECV_RESPONSE_REF(recv_response),
+ NTATAG_S_BAD_MESSAGE_REF(bad_message),
+ NTATAG_S_BAD_REQUEST_REF(bad_request),
+ NTATAG_S_BAD_RESPONSE_REF(bad_response),
+ NTATAG_S_DROP_REQUEST_REF(drop_request),
+ NTATAG_S_DROP_RESPONSE_REF(drop_response),
+ NTATAG_S_CLIENT_TR_REF(client_tr),
+ NTATAG_S_SERVER_TR_REF(server_tr),
+ NTATAG_S_DIALOG_TR_REF(dialog_tr),
+ NTATAG_S_ACKED_TR_REF(acked_tr),
+ NTATAG_S_CANCELED_TR_REF(canceled_tr),
+ NTATAG_S_TRLESS_REQUEST_REF(trless_request),
+ NTATAG_S_TRLESS_TO_TR_REF(trless_to_tr),
+ NTATAG_S_TRLESS_RESPONSE_REF(trless_response),
+ NTATAG_S_TRLESS_200_REF(trless_200),
+ NTATAG_S_MERGED_REQUEST_REF(merged_request),
+ NTATAG_S_SENT_REQUEST_REF(sent_request),
+ NTATAG_S_SENT_RESPONSE_REF(sent_response),
+ NTATAG_S_RETRY_REQUEST_REF(retry_request),
+ NTATAG_S_RETRY_RESPONSE_REF(retry_response),
+ NTATAG_S_RECV_RETRY_REF(recv_retry),
+ NTATAG_S_TOUT_REQUEST_REF(tout_request),
+ NTATAG_S_TOUT_RESPONSE_REF(tout_response),
+ TAG_END()), 29);
+
+ TEST_1(irq_hash == HTABLE_MIN_SIZE);
+ TEST_1(orq_hash == HTABLE_MIN_SIZE);
+ TEST_1(leg_hash == HTABLE_MIN_SIZE);
+ TEST_1(recv_msg == 0);
+ TEST_1(sent_msg == 0);
+ TEST_1(recv_request == 0);
+ TEST_1(recv_response == 0);
+ TEST_1(bad_message == 0);
+ TEST_1(bad_request == 0);
+ TEST_1(bad_response == 0);
+ TEST_1(drop_request == 0);
+ TEST_1(drop_response == 0);
+ TEST_1(client_tr == 0);
+ TEST_1(server_tr == 0);
+ TEST_1(dialog_tr == 0);
+ TEST_1(acked_tr == 0);
+ TEST_1(canceled_tr == 0);
+ TEST_1(trless_request == 0);
+ TEST_1(trless_to_tr == 0);
+ TEST_1(trless_response == 0);
+ TEST_1(trless_200 == 0);
+ TEST_1(merged_request == 0);
+ TEST_1(sent_request == 0);
+ TEST_1(sent_response == 0);
+ TEST_1(retry_request == 0);
+ TEST_1(retry_response == 0);
+ TEST_1(recv_retry == 0);
+ TEST_1(tout_request == 0);
+ TEST_1(tout_response == 0);
+
+ TEST_VOID(nta_agent_destroy(nta));
+
+ END();
+}
+
+/* Test handling transports */
+int api_test_tport(agent_t *ag)
+{
+ sip_via_t const *v;
+
+ url_t url[1];
+
+ BEGIN();
+
+ nta_agent_t *agent;
+ sip_contact_t const *m;
+
+ *url = *ag->ag_contact->m_url;
+ url->url_port = "*";
+ url->url_params = "transport=tcp";
+
+ TEST_1(agent = nta_agent_create(ag->ag_root, NONE, NULL, NULL, TAG_END()));
+ TEST_1(!nta_agent_via(agent));
+ TEST_1(!nta_agent_public_via(agent));
+ TEST_1(!nta_agent_contact(agent));
+
+ TEST_1(nta_agent_add_tport(agent, (url_string_t *)url, TAG_END()) == 0);
+ TEST_1(v = nta_agent_via(agent)); TEST_1(!v->v_next);
+ TEST(strcasecmp(v->v_protocol, sip_transport_tcp), 0);
+ TEST_1(m = nta_agent_contact(agent));
+ TEST_S(m->m_url->url_params, "transport=tcp");
+
+ TEST_1(nta_agent_add_tport(agent, (url_string_t *)url,
+ TPTAG_SERVER(0), TAG_END()) == 0);
+ TEST_1(v = nta_agent_public_via(agent)); TEST_1(!v->v_next);
+ TEST(strcasecmp(v->v_protocol, sip_transport_tcp), 0);
+ TEST_1(host_has_domain_invalid(v->v_host));
+ TEST_1(m = nta_agent_contact(agent));
+ TEST_S(m->m_url->url_params, "transport=tcp");
+
+ url->url_params = "transport=udp";
+ TEST_1(nta_agent_add_tport(agent, (url_string_t *)url, TAG_END()) == 0);
+ TEST_1(v = nta_agent_via(agent)); TEST_1(v = v->v_next);
+ TEST(strcasecmp(v->v_protocol, sip_transport_udp), 0);
+
+ TEST_VOID(nta_agent_destroy(agent));
+
+ TEST_1(agent = nta_agent_create(ag->ag_root, NONE, NULL, NULL, TAG_END()));
+ TEST_1(nta_agent_add_tport(agent, (url_string_t *)url, TAG_END()) == 0);
+ TEST_1(v = nta_agent_via(agent)); TEST_1(!v->v_next);
+ TEST(strcasecmp(v->v_protocol, sip_transport_udp), 0);
+ TEST_1(m = nta_agent_contact(agent));
+ TEST_S(m->m_url->url_params, "transport=udp");
+ TEST_VOID(nta_agent_destroy(agent));
+
+ url->url_params = "transport=tcp,udp";
+
+ TEST_1(agent = nta_agent_create(ag->ag_root, NONE, NULL, NULL, TAG_END()));
+ TEST_1(nta_agent_add_tport(agent, (url_string_t *)url, TAG_END()) == 0);
+ TEST_1(v = nta_agent_via(agent));
+ TEST(strcasecmp(v->v_protocol, sip_transport_tcp), 0);
+ TEST_1(v = v->v_next);
+ TEST(strcasecmp(v->v_protocol, sip_transport_udp), 0);
+ TEST_1(m = nta_agent_contact(agent));
+ TEST_1(!m->m_url->url_params);
+ TEST_VOID(nta_agent_destroy(agent));
+
+ url->url_params = NULL;
+
+ TEST_1(agent = nta_agent_create(ag->ag_root, NONE, NULL, NULL, TAG_END()));
+ TEST_1(nta_agent_add_tport(agent, (url_string_t *)url, TAG_END()) == 0);
+ TEST_1(v = nta_agent_via(agent));
+ TEST(strcasecmp(v->v_protocol, sip_transport_udp), 0);
+ TEST_1(v = v->v_next);
+ TEST(strcasecmp(v->v_protocol, sip_transport_tcp), 0);
+ TEST_1(m = nta_agent_contact(agent));
+ TEST_1(!m->m_url->url_params);
+ TEST_VOID(nta_agent_destroy(agent));
+
+
+ END();
+}
+
+static int api_test_dialogs(agent_t *ag)
+{
+ BEGIN();
+#if 0
+ {
+ /* Test 0.1
+ * Send a message from default leg to default leg
+ */
+ char const p_acid[] = "P-Access-Network-Info: IEEE-802.11g\n";
+ msg_t *msg;
+
+ ag->ag_expect_leg = ag->ag_default_leg;
+
+ TEST_1(ag->ag_orq =
+ nta_outgoing_tcreate(ag->ag_default_leg,
+ outgoing_callback, ag,
+ ag->ag_obp,
+ SIP_METHOD_MESSAGE,
+ (url_string_t *)ag->ag_contact->m_url,
+ SIPTAG_SUBJECT_STR("Test 0.1"),
+ SIPTAG_FROM(ag->ag_alice),
+ SIPTAG_TO(ag->ag_bob),
+ SIPTAG_CONTACT(ag->ag_m_alice),
+ SIPTAG_HEADER_STR(p_acid),
+ TAG_END()));
+
+ TEST(nta_outgoing_getresponse(ag->ag_orq), NULL);
+ TEST_1(msg = nta_outgoing_getrequest(ag->ag_orq));
+ TEST(nta_outgoing_method(ag->ag_orq), sip_method_message);
+ TEST_S(nta_outgoing_method_name(ag->ag_orq), "MESSAGE");
+ msg_destroy(msg);
+
+ TEST(nta_outgoing_delay(ag->ag_orq), UINT_MAX);
+ nta_test_run(ag);
+ TEST(ag->ag_status, 200);
+ TEST(ag->ag_orq, NULL);
+ TEST(ag->ag_latest_leg, ag->ag_default_leg);
+ TEST_1(ag->ag_request);
+
+ nta_leg_bind(ag->ag_default_leg, leg_callback_200, ag);
+ }
+#endif
+
+ END();
+}
+
+
+int outgoing_default(agent_t *ag,
+ nta_outgoing_t *orq,
+ sip_t const *sip)
+{
+ BEGIN();
+ msg_t *msg;
+
+ int status = sip->sip_status->st_status;
+
+ ag->ag_status = status;
+
+ if (status < 200)
+ return 0;
+
+ /* Test API functions */
+ TEST(nta_outgoing_status(orq), status);
+ TEST_1(!nta_outgoing_request_uri(orq));
+ TEST_1(!nta_outgoing_route_uri(orq));
+ TEST(nta_outgoing_method(orq), sip_method_invalid);
+ TEST_S(nta_outgoing_method_name(orq), "*");
+ TEST(nta_outgoing_cseq(orq), 0);
+ TEST_1(nta_outgoing_delay(orq) == UINT_MAX);
+
+ TEST_1(msg = nta_outgoing_getresponse(orq));
+ if (ag->ag_response == NULL)
+ ag->ag_response = msg;
+ else
+ msg_destroy(msg);
+
+ TEST_1(!nta_outgoing_getrequest(orq));
+
+ END();
+}
+
+/* Test default incoming and outgoing */
+static int api_test_default(agent_t *ag)
+{
+ BEGIN();
+ nta_agent_t *nta;
+ nta_incoming_t *irq;
+ nta_outgoing_t *orq;
+ sip_via_t via[1];
+
+ TEST_1(nta = ag->ag_agent);
+
+ TEST_1(irq = nta_incoming_default(nta));
+
+ TEST_VOID(nta_incoming_bind(irq, incoming_callback_1, ag));
+ TEST_P(nta_incoming_magic(irq, incoming_callback_1), ag);
+ TEST_P(nta_incoming_magic(irq, incoming_callback_2), 0);
+
+ TEST_P(nta_incoming_tag(irq, NULL), NULL);
+ TEST_P(nta_incoming_gettag(irq), NULL);
+
+ TEST(nta_incoming_status(irq), 0);
+ TEST(nta_incoming_method(irq), sip_method_invalid);
+ TEST_S(nta_incoming_method_name(irq), "*");
+ TEST_P(nta_incoming_url(irq), NULL);
+ TEST(nta_incoming_cseq(irq), 0);
+
+ TEST(nta_incoming_set_params(irq, TAG_END()), 0);
+
+ TEST_P(nta_incoming_getrequest(irq), NULL);
+ TEST_P(nta_incoming_getrequest_ackcancel(irq), NULL);
+ TEST_P(nta_incoming_getresponse(irq), NULL);
+
+ TEST(nta_incoming_complete_response(irq, NULL, SIP_200_OK, TAG_END()), -1);
+
+ TEST(nta_incoming_treply(irq, SIP_200_OK, TAG_END()), -1);
+ TEST(nta_incoming_mreply(irq, NULL), -1);
+
+ TEST_VOID(nta_incoming_destroy(irq));
+
+ TEST_1(orq = nta_outgoing_default(nta, outgoing_default, ag));
+
+ TEST(nta_outgoing_status(orq), 0);
+ TEST(nta_outgoing_method(orq), sip_method_invalid);
+ TEST_S(nta_outgoing_method_name(orq), "*");
+ TEST(nta_outgoing_cseq(orq), 0);
+
+ TEST(nta_outgoing_delay(orq), UINT_MAX);
+ TEST_P(nta_outgoing_request_uri(orq), NULL);
+ TEST_P(nta_outgoing_route_uri(orq), NULL);
+
+ TEST_P(nta_outgoing_getresponse(orq), NULL);
+ TEST_P(nta_outgoing_getrequest(orq), NULL);
+
+ TEST_P(nta_outgoing_tagged(orq, NULL, NULL, NULL, NULL), NULL);
+ TEST(nta_outgoing_cancel(orq), -1);
+ TEST_P(nta_outgoing_tcancel(orq, NULL, NULL, TAG_END()), NULL);
+
+ TEST_VOID(nta_outgoing_destroy(orq));
+
+ TEST_1(irq = nta_incoming_default(nta));
+ TEST_1(orq = nta_outgoing_default(nta, outgoing_default, ag));
+
+ via[0] = nta_agent_via(nta)[0];
+ via->v_next = NULL;
+
+ TEST_1(nta_incoming_treply
+ (irq,
+ SIP_200_OK,
+ SIPTAG_VIA(via),
+ SIPTAG_CALL_ID_STR("oishciucnkrcoihciunskcisj"),
+ SIPTAG_CSEQ_STR("1 MESSAGE"),
+ SIPTAG_FROM_STR("Arska <sip:arska at example.com>;tag=aiojcidscd0i"),
+ SIPTAG_TO_STR("Jaska <sip:jaska at example.net>;tag=iajf8wru"),
+ TAG_END()) == 0);
+
+ for (ag->ag_status = 0; ag->ag_status < 200; ) {
+ su_root_step(ag->ag_root, 200);
+ }
+
+ TEST(nta_outgoing_status(orq), 0);
+
+ TEST_VOID(nta_outgoing_destroy(orq));
+ TEST_VOID(nta_incoming_destroy(irq));
+
+ END();
+}
+
+/** Test API for errors */
+static int api_test_errors(agent_t *ag)
+{
+ nta_agent_t *nta;
+ su_root_t *root;
+ su_home_t home[1];
+
+ BEGIN();
+
+ memset(home, 0, sizeof home);
+ home->suh_size = sizeof home;
+ su_home_init(home);
+
+ TEST_P(nta_agent_create(NULL,
+ (url_string_t *)"sip:*:*",
+ NULL,
+ NULL,
+ TAG_END()), NULL);
+
+ TEST_1(root = su_root_create(NULL));
+
+ TEST_P(nta_agent_create(root,
+ (url_string_t *)"http://localhost:*/invalid/bind/url",
+ NULL,
+ NULL,
+ TAG_END()), NULL);
+
+ TEST_P(nta_agent_create(root,
+ (url_string_t *)"sip:*:*;transport=XXX",
+ NULL,
+ NULL,
+ TAG_END()), NULL);
+
+ TEST_1(nta = nta_agent_create(root,
+ (url_string_t *)"sip:*:*",
+ NULL,
+ NULL,
+ TAG_END()));
+
+ TEST_VOID(nta_agent_destroy(NULL));
+ TEST_VOID(nta_agent_destroy(nta));
+
+ TEST_1(nta = nta_agent_create(root,
+ (url_string_t *)"sip:*:*",
+ agent_callback,
+ ag,
+ TAG_END()));
+
+ TEST_P(nta_agent_contact(NULL), NULL);
+ TEST_P(nta_agent_via(NULL), NULL);
+ TEST_S(nta_agent_version(nta), nta_agent_version(NULL));
+ TEST_P(nta_agent_magic(NULL), NULL);
+ TEST_P(nta_agent_magic(nta), (void *)ag);
+ TEST(nta_agent_add_tport(NULL, NULL, TAG_END()), -1);
+ TEST_P(nta_agent_newtag(home, "tag=%s", NULL), NULL);
+ TEST_1(nta_agent_newtag(home, "tag=%s", nta));
+
+ {
+ msg_t *msg;
+ TEST_1(nta_msg_create(NULL, 0) == NULL);
+ TEST(nta_msg_complete(NULL), -1);
+
+ TEST_1(msg = nta_msg_create(nta, 0));
+ TEST(nta_msg_complete(msg), -1);
+ TEST(nta_msg_request_complete(msg, NULL,
+ sip_method_unknown, "FOO", NULL), -1);
+ TEST(nta_is_internal_msg(NULL), 0);
+ TEST(nta_is_internal_msg(msg), 0);
+ TEST_1(msg_set_flags(msg, NTA_INTERNAL_MSG));
+ TEST(nta_is_internal_msg(msg), 1);
+ TEST_VOID(msg_destroy(msg));
+ }
+
+ TEST_P(nta_leg_tcreate(NULL, NULL, NULL, TAG_END()), NULL);
+ TEST_VOID(nta_leg_destroy(NULL));
+ TEST_P(nta_leg_magic(NULL, NULL), NULL);
+ TEST_VOID(nta_leg_bind(NULL, NULL, NULL));
+ TEST_P(nta_leg_tag(NULL, "fidsafsa"), NULL);
+ TEST_P(nta_leg_rtag(NULL, "fidsafsa"), NULL);
+ TEST_P(nta_leg_get_tag(NULL), NULL);
+ TEST(nta_leg_client_route(NULL, NULL, NULL), -1);
+ TEST(nta_leg_server_route(NULL, NULL, NULL), -1);
+ TEST_P(nta_leg_by_uri(NULL, NULL), NULL);
+ TEST_P(nta_leg_by_dialog(NULL, NULL, NULL, NULL, NULL, NULL, NULL), NULL);
+ TEST_P(nta_leg_by_dialog(nta, NULL, NULL, NULL, NULL, NULL, NULL), NULL);
+
+ TEST_P(nta_leg_make_replaces(NULL, NULL, 1), NULL);
+ TEST_P(nta_leg_by_replaces(NULL, NULL), NULL);
+
+ TEST_P(nta_incoming_create(NULL, NULL, NULL, NULL, TAG_END()), NULL);
+ TEST_P(nta_incoming_create(nta, NULL, NULL, NULL, TAG_END()), NULL);
+
+ TEST_VOID(nta_incoming_bind(NULL, NULL, NULL));
+ TEST_P(nta_incoming_magic(NULL, NULL), NULL);
+
+ TEST_P(nta_incoming_find(NULL, NULL, NULL), NULL);
+ TEST_P(nta_incoming_find(nta, NULL, NULL), NULL);
+
+ TEST_P(nta_incoming_tag(NULL, NULL), NULL);
+ TEST_P(nta_incoming_gettag(NULL), NULL);
+
+ TEST(nta_incoming_status(NULL), 400);
+ TEST(nta_incoming_method(NULL), sip_method_invalid);
+ TEST_P(nta_incoming_method_name(NULL), NULL);
+ TEST_P(nta_incoming_url(NULL), NULL);
+ TEST(nta_incoming_cseq(NULL), 0);
+
+ TEST(nta_incoming_set_params(NULL, TAG_END()), -1);
+
+ TEST_P(nta_incoming_getrequest(NULL), NULL);
+ TEST_P(nta_incoming_getrequest_ackcancel(NULL), NULL);
+ TEST_P(nta_incoming_getresponse(NULL), NULL);
+
+ TEST(nta_incoming_complete_response(NULL, NULL, 800, "foo", TAG_END()), -1);
+
+ TEST(nta_incoming_treply(NULL, SIP_200_OK, TAG_END()), -1);
+ TEST(nta_incoming_mreply(NULL, NULL), -1);
+
+ TEST_VOID(nta_incoming_destroy(NULL));
+
+ TEST_P(nta_outgoing_tcreate(NULL, outgoing_callback, ag,
+ URL_STRING_MAKE("sip:localhost"),
+ SIP_METHOD_MESSAGE,
+ URL_STRING_MAKE("sip:localhost"),
+ TAG_END()), NULL);
+
+ TEST_P(nta_outgoing_mcreate(NULL, outgoing_callback, ag,
+ URL_STRING_MAKE("sip:localhost"),
+ NULL,
+ TAG_END()), NULL);
+
+ TEST_P(nta_outgoing_default(NULL, NULL, NULL), NULL);
+
+ TEST(nta_outgoing_status(NULL), 500);
+ TEST(nta_outgoing_method(NULL), sip_method_invalid);
+ TEST_P(nta_outgoing_method_name(NULL), NULL);
+ TEST(nta_outgoing_cseq(NULL), 0);
+
+ TEST(nta_outgoing_delay(NULL), UINT_MAX);
+ TEST_P(nta_outgoing_request_uri(NULL), NULL);
+ TEST_P(nta_outgoing_route_uri(NULL), NULL);
+
+ TEST_P(nta_outgoing_getresponse(NULL), NULL);
+ TEST_P(nta_outgoing_getrequest(NULL), NULL);
+
+ TEST_P(nta_outgoing_tagged(NULL, NULL, NULL, NULL, NULL), NULL);
+ TEST(nta_outgoing_cancel(NULL), -1);
+ TEST_P(nta_outgoing_tcancel(NULL, NULL, NULL, TAG_END()), NULL);
+ TEST_VOID(nta_outgoing_destroy(NULL));
+
+ TEST_P(nta_outgoing_find(NULL, NULL, NULL, NULL), NULL);
+ TEST_P(nta_outgoing_find(nta, NULL, NULL, NULL), NULL);
+
+ TEST(nta_outgoing_status(NONE), 500);
+ TEST(nta_outgoing_method(NONE), sip_method_invalid);
+ TEST_P(nta_outgoing_method_name(NONE), NULL);
+ TEST(nta_outgoing_cseq(NONE), 0);
+
+ TEST(nta_outgoing_delay(NONE), UINT_MAX);
+ TEST_P(nta_outgoing_request_uri(NONE), NULL);
+ TEST_P(nta_outgoing_route_uri(NONE), NULL);
+
+ TEST_P(nta_outgoing_getresponse(NONE), NULL);
+ TEST_P(nta_outgoing_getrequest(NONE), NULL);
+
+ TEST_P(nta_outgoing_tagged(NONE, NULL, NULL, NULL, NULL), NULL);
+ TEST(nta_outgoing_cancel(NONE), -1);
+ TEST_P(nta_outgoing_tcancel(NONE, NULL, NULL, TAG_END()), NULL);
+ TEST_VOID(nta_outgoing_destroy(NONE));
+
+#if 0
+nta_reliable_t *nta_reliable_treply(nta_incoming_t *ireq,
+ nta_prack_f *callback,
+ nta_reliable_magic_t *rmagic,
+ int status, char const *phrase,
+ tag_type_t tag,
+ tag_value_t value, ...);
+
+nta_reliable_t *nta_reliable_mreply(nta_incoming_t *irq,
+ nta_prack_f *callback,
+ nta_reliable_magic_t *rmagic,
+ msg_t *msg);
+
+void nta_reliable_destroy(nta_reliable_t *);
+
+#endif
+
+ TEST_VOID(nta_agent_destroy(nta));
+ TEST_VOID(su_root_destroy(root));
+ TEST_VOID(su_home_deinit(home));
+
+ END();
+}
+
+static int api_test_dialog_matching(agent_t *ag)
+{
+ nta_agent_t *nta;
+ su_root_t *root;
+ su_home_t home[1];
+ nta_leg_t *leg, *dialog1, *dialog2, *dst, *defdst;
+ sip_from_t *a1, *a2;
+ sip_call_id_t *i;
+
+ BEGIN();
+
+ memset(home, 0, sizeof home);
+ home->suh_size = sizeof home;
+ su_home_init(home);
+
+ TEST_1(root = su_root_create(NULL));
+
+ TEST_1(nta = nta_agent_create(root,
+ (url_string_t *)"sip:*:*",
+ NULL,
+ NULL,
+ TAG_END()));
+
+ TEST_1(dst = nta_leg_tcreate(nta, NULL, NULL,
+ NTATAG_NO_DIALOG(1),
+ URLTAG_URL("sip:joe at localhost"),
+ TAG_END()));
+
+ TEST_1(defdst = nta_leg_tcreate(nta, NULL, NULL,
+ NTATAG_NO_DIALOG(1),
+ TAG_END()));
+
+ TEST_1(dialog1 =
+ nta_leg_tcreate(nta, NULL, NULL,
+ URLTAG_URL("sip:pc.al.us"),
+ SIPTAG_CALL_ID_STR("foobarbaz"),
+ /* local */
+ SIPTAG_FROM_STR("<sip:me.myself.i at foo.com>;tag=foo"),
+ /* remote */
+ SIPTAG_TO_STR("<sip:joe.boy at al.us>"),
+ TAG_END()));
+
+ TEST_1(a1 = sip_from_make(home, "<sip:me.myself.i at foo.com>;tag=foo"));
+ TEST_1(a2 = sip_from_make(home, "<sip:joe.boy at al.us>;tag=al"));
+ TEST_1(i = sip_call_id_make(home, "foobarbaz"));
+
+ TEST_1(dialog2 =
+ nta_leg_tcreate(nta, NULL, NULL,
+ SIPTAG_CALL_ID(i),
+ /* local */
+ SIPTAG_FROM(a2),
+ /* remote */
+ SIPTAG_TO(a1),
+ TAG_END()));
+
+ TEST_1(!nta_leg_by_dialog(nta, NULL, NULL,
+ a1->a_tag, a1->a_url, a2->a_tag, a2->a_url));
+ TEST_1(!nta_leg_by_dialog(NULL, NULL, i,
+ a1->a_tag, a1->a_url, a2->a_tag, a2->a_url));
+ TEST_1(!nta_leg_by_dialog(nta, (void *)"sip:no.such.url", i,
+ a2->a_tag, a2->a_url, a1->a_tag, a1->a_url));
+ TEST_1(!nta_leg_by_dialog(nta, a2->a_url, i,
+ a2->a_tag, a2->a_url, a1->a_tag, a1->a_url));
+
+ TEST_P(leg = nta_leg_by_dialog(nta, NULL, i,
+ /* local */ a1->a_tag, a1->a_url,
+ /* remote */ a2->a_tag, a2->a_url),
+ dialog2);
+ TEST_P(leg = nta_leg_by_dialog(nta, (void *)"sip:no.such.url", i,
+ /* local */ a1->a_tag, a1->a_url,
+ /* remote */ a2->a_tag, a2->a_url),
+ dialog2);
+ TEST_P(leg = nta_leg_by_dialog(nta, a2->a_url, i,
+ a1->a_tag, a1->a_url, a2->a_tag, a2->a_url),
+ dialog2);
+
+ TEST_P(leg = nta_leg_by_dialog(nta, NULL, i,
+ a2->a_tag, a2->a_url, a1->a_tag, a1->a_url),
+ dialog1);
+ TEST_P(leg = nta_leg_by_dialog(nta, (url_t *)"sip:pc.al.us", i,
+ a2->a_tag, a2->a_url, a1->a_tag, a1->a_url),
+ dialog1);
+ /* local tag is required because there is tag */
+ TEST_P(leg = nta_leg_by_dialog(nta, (url_t *)"sip:pc.al.us", i,
+ a2->a_tag, a2->a_url, "xyzzy", a1->a_url),
+ NULL);
+ /* local URI is ignored because we have tag */
+ TEST_P(leg = nta_leg_by_dialog(nta, (url_t *)"sip:pc.al.us", i,
+ a2->a_tag, a2->a_url, a1->a_tag, a2->a_url),
+ dialog1);
+
+ /* remote tag is ignored because there is no tag */
+ TEST_P(leg = nta_leg_by_dialog(nta, (url_t *)"sip:pc.al.us", i,
+ "xyzzy", a2->a_url, a1->a_tag, a1->a_url),
+ dialog1);
+ /* remote url is required */
+ TEST_P(leg = nta_leg_by_dialog(nta, (url_t *)"sip:pc.al.us", i,
+ a2->a_tag, a1->a_url, a1->a_tag, a1->a_url),
+ NULL);
+ TEST_P(leg = nta_leg_by_dialog(nta, (url_t *)"sip:pc.al.us", i,
+ a2->a_tag, NULL, a1->a_tag, a1->a_url),
+ dialog1);
+
+ /* local url is used if there is no local tag */
+ TEST_P(leg = nta_leg_by_dialog(nta, (url_t *)"sip:pc.al.us", i,
+ a2->a_tag, a2->a_url, NULL, NULL),
+ NULL);
+
+ nta_leg_tag(dialog1, "al");
+ TEST_P(leg = nta_leg_by_dialog(nta, (url_t *)"sip:pc.al.us", i,
+ a2->a_tag, a2->a_url, a1->a_tag, a1->a_url),
+ dialog1);
+ TEST_P(leg = nta_leg_by_dialog(nta, (url_t *)"sip:pc.al.us", i,
+ a2->a_tag, a2->a_url, "xyzzy", a1->a_url),
+ NULL);
+ TEST_P(leg = nta_leg_by_dialog(nta, (url_t *)"sip:pc.al.us", i,
+ a2->a_tag, a2->a_url, a1->a_tag, a1->a_url),
+ dialog1);
+ TEST_P(leg = nta_leg_by_dialog(nta, (url_t *)"sip:pc.al.us", i,
+ a2->a_tag, a2->a_url, NULL, a1->a_url),
+ NULL);
+
+ nta_leg_destroy(defdst);
+ nta_leg_destroy(dst);
+ nta_leg_destroy(dialog1);
+ nta_leg_destroy(dialog2);
+
+ TEST_VOID(nta_agent_destroy(nta));
+ TEST_VOID(su_root_destroy(root));
+ TEST_VOID(su_home_deinit(home));
+
+ END();
+
+}
+
+#if HAVE_ALARM
+#include <unistd.h>
+#include <signal.h>
+
+static RETSIGTYPE sig_alarm(int s)
+{
+ fprintf(stderr, "%s: FAIL! test timeout!\n", name);
+ exit(1);
+}
+#endif
+
+static
+char const nta_test_api_usage[] =
+ "usage: %s OPTIONS\n"
+ "where OPTIONS are\n"
+ " -v | --verbose be verbose\n"
+ " -q | --quiet be quiet\n"
+ " -1 quit on first error\n"
+ " -l level set logging level (0 by default)\n"
+ " --attach print pid, wait for a debugger to be attached\n"
+#if HAVE_ALARM
+ " --no-alarm don't ask for guard ALARM\n"
+#endif
+ ;
+
+void usage(void)
+{
+ fprintf(stderr, nta_test_api_usage, name);
+ exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+ int retval = 0, quit_on_single_failure = 0;
+ int i, o_attach = 0, o_alarm = 1;
+
+ agent_t ag[1] = {{ { SU_HOME_INIT(ag) }, 0, NULL }};
+
+ for (i = 1; argv[i]; i++) {
+ if (strcmp(argv[i], "-v") == 0)
+ tstflags |= tst_verbatim;
+ else if (strcmp(argv[i], "-q") == 0)
+ tstflags &= ~tst_verbatim;
+ else if (strcmp(argv[i], "-1") == 0)
+ quit_on_single_failure = 1;
+ else if (strncmp(argv[i], "-l", 2) == 0) {
+ int level = 3;
+ char *rest = NULL;
+
+ if (argv[i][2])
+ level = strtol(argv[i] + 2, &rest, 10);
+ else if (argv[i + 1])
+ level = strtol(argv[i + 1], &rest, 10), i++;
+ else
+ level = 3, rest = "";
+
+ if (rest == NULL || *rest)
+ usage();
+
+ su_log_set_level(nta_log, level);
+ su_log_set_level(tport_log, level);
+ }
+ else if (strcmp(argv[i], "--attach") == 0) {
+ o_attach = 1;
+ }
+ else if (strcmp(argv[i], "--no-alarm") == 0) {
+ o_alarm = 0;
+ }
+ else if (strcmp(argv[i], "-") == 0) {
+ i++; break;
+ }
+ else if (argv[i][0] != '-') {
+ break;
+ }
+ else
+ usage();
+ }
+
+ if (o_attach) {
+ char line[10];
+ printf("nua_test: pid %lu\n", (unsigned long)getpid());
+ printf("<Press RETURN to continue>\n");
+ fgets(line, sizeof line, stdin);
+ }
+#if HAVE_ALARM
+ else if (o_alarm) {
+ alarm(60);
+ signal(SIGALRM, sig_alarm);
+ }
+#endif
+
+ su_init();
+
+ if (!(TSTFLAGS & tst_verbatim)) {
+ su_log_soft_set_level(nta_log, 0);
+ su_log_soft_set_level(tport_log, 0);
+ }
+
+#define SINGLE_FAILURE_CHECK() \
+ do { fflush(stderr); fflush(stdout); \
+ if (retval && quit_on_single_failure) { su_deinit(); return retval; } \
+ } while(0)
+
+ retval |= api_test_init(ag); fflush(stdout); SINGLE_FAILURE_CHECK();
+ if (retval == 0) {
+ retval |= api_test_errors(ag); SINGLE_FAILURE_CHECK();
+ retval |= api_test_params(ag); SINGLE_FAILURE_CHECK();
+ retval |= api_test_stats(ag); SINGLE_FAILURE_CHECK();
+ retval |= api_test_dialog_matching(ag); SINGLE_FAILURE_CHECK();
+ retval |= api_test_tport(ag); SINGLE_FAILURE_CHECK();
+ retval |= api_test_dialogs(ag); SINGLE_FAILURE_CHECK();
+ retval |= api_test_default(ag); SINGLE_FAILURE_CHECK();
+ }
+ retval |= api_test_deinit(ag); fflush(stdout);
+
+ su_home_deinit(ag->ag_home);
+
+ su_deinit();
+
+ return retval;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/ChangeLog Thu Dec 21 01:30:28 2006
@@ -0,0 +1,7 @@
+2005-08-10 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Added agent.pem and cafile.pem.
+
+2005-07-18 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * Initial import of the module to Sofia-SIP tree.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/Doxyfile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/Doxyfile Thu Dec 21 01:30:28 2006
@@ -0,0 +1,18 @@
+PROJECT_NAME = "nth"
+OUTPUT_DIRECTORY = ../docs/html/nth
+
+INPUT = nth.docs sofia-sip .
+
+ at INCLUDE = ../docs/Doxyfile.conf
+
+TAGFILES += \
+ "../docs/su.doxytags=../su" \
+ "../docs/ipt.doxytags=../ipt" \
+ "../docs/bnf.doxytags=../bnf" \
+ "../docs/url.doxytags=../url" \
+ "../docs/msg.doxytags=../msg" \
+ "../docs/http.doxytags=../http" \
+
+GENERATE_TAGFILE = ../docs/nth.doxytags
+
+ALIASES +=
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/Makefile.am Thu Dec 21 01:30:28 2006
@@ -0,0 +1,66 @@
+#
+# Makefile.am for nth module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+INCLUDES = -I$(srcdir)/../ipt -I../ipt \
+ -I$(srcdir)/../iptsec -I../iptsec \
+ -I$(srcdir)/../msg -I../msg \
+ -I$(srcdir)/../bnf -I../bnf \
+ -I$(srcdir)/../http -I../http \
+ -I$(srcdir)/../sresolv -I../sresolv \
+ -I$(srcdir)/../tport -I../tport \
+ -I$(srcdir)/../url -I../url \
+ -I$(srcdir)/../su -I../su
+
+# ----------------------------------------------------------------------
+# Build targets
+
+noinst_LTLIBRARIES = libnth.la
+
+check_PROGRAMS = test_nth http-client http-server
+
+TESTS = test_nth
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+
+BUILT_SOURCES = nth_tag_ref.c
+
+nobase_include_sofia_HEADERS = \
+ sofia-sip/nth.h sofia-sip/nth_tag.h
+
+libnth_la_SOURCES = nth_client.c nth_server.c nth_tag.c nth_tag_ref.c
+
+COVERAGE_INPUT = $(libnth_la_SOURCES) $(include_sofia_HEADERS)
+
+LDADD = libnth.la \
+ ../iptsec/libiptsec.la \
+ ../ipt/libipt.la \
+ ../http/libhttp.la \
+ ../sresolv/libsresolv.la \
+ ../tport/libtport.la \
+ ../stun/libstun.la \
+ ../sresolv/libsresolv.la \
+ ../url/liburl.la \
+ ../msg/libmsg.la \
+ ../bnf/libbnf.la \
+ ../su/libsu.la
+
+test_nth_LDFLAGS = -static
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+
+EXTRA_DIST = Doxyfile nth.docs $(BUILT_SOURCES) \
+ agent.pem cafile.pem
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+
+include ../sofia.am
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/Makefile.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1,746 @@
+# 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.
+
+ at SET_MAKE@
+
+#
+# Makefile.am for nth module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+# common Makefile targets for libsofia-sip-ua modules
+# ---------------------------------------------------
+
+
+SOURCES = $(libnth_la_SOURCES) http-client.c http-server.c test_nth.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 = test_nth$(EXEEXT) http-client$(EXEEXT) \
+ http-server$(EXEEXT)
+DIST_COMMON = $(nobase_include_sofia_HEADERS) $(srcdir)/../sofia.am \
+ $(srcdir)/Makefile.am $(srcdir)/Makefile.in ChangeLog
+subdir = libsofia-sip-ua/nth
+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 =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libnth_la_LIBADD =
+am_libnth_la_OBJECTS = nth_client.lo nth_server.lo nth_tag.lo \
+ nth_tag_ref.lo
+libnth_la_OBJECTS = $(am_libnth_la_OBJECTS)
+http_client_SOURCES = http-client.c
+http_client_OBJECTS = http-client.$(OBJEXT)
+http_client_LDADD = $(LDADD)
+http_client_DEPENDENCIES = libnth.la ../iptsec/libiptsec.la \
+ ../ipt/libipt.la ../http/libhttp.la ../sresolv/libsresolv.la \
+ ../tport/libtport.la ../stun/libstun.la \
+ ../sresolv/libsresolv.la ../url/liburl.la ../msg/libmsg.la \
+ ../bnf/libbnf.la ../su/libsu.la
+http_server_SOURCES = http-server.c
+http_server_OBJECTS = http-server.$(OBJEXT)
+http_server_LDADD = $(LDADD)
+http_server_DEPENDENCIES = libnth.la ../iptsec/libiptsec.la \
+ ../ipt/libipt.la ../http/libhttp.la ../sresolv/libsresolv.la \
+ ../tport/libtport.la ../stun/libstun.la \
+ ../sresolv/libsresolv.la ../url/liburl.la ../msg/libmsg.la \
+ ../bnf/libbnf.la ../su/libsu.la
+test_nth_SOURCES = test_nth.c
+test_nth_OBJECTS = test_nth.$(OBJEXT)
+test_nth_LDADD = $(LDADD)
+test_nth_DEPENDENCIES = libnth.la ../iptsec/libiptsec.la \
+ ../ipt/libipt.la ../http/libhttp.la ../sresolv/libsresolv.la \
+ ../tport/libtport.la ../stun/libstun.la \
+ ../sresolv/libsresolv.la ../url/liburl.la ../msg/libmsg.la \
+ ../bnf/libbnf.la ../su/libsu.la
+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 = $(libnth_la_SOURCES) http-client.c http-server.c test_nth.c
+DIST_SOURCES = $(libnth_la_SOURCES) http-client.c http-server.c \
+ test_nth.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|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(include_sofiadir)"
+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)/../ipt -I../ipt \
+ -I$(srcdir)/../iptsec -I../iptsec \
+ -I$(srcdir)/../msg -I../msg \
+ -I$(srcdir)/../bnf -I../bnf \
+ -I$(srcdir)/../http -I../http \
+ -I$(srcdir)/../sresolv -I../sresolv \
+ -I$(srcdir)/../tport -I../tport \
+ -I$(srcdir)/../url -I../url \
+ -I$(srcdir)/../su -I../su
+
+
+# ----------------------------------------------------------------------
+# Build targets
+noinst_LTLIBRARIES = libnth.la
+TESTS = test_nth
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+BUILT_SOURCES = nth_tag_ref.c
+nobase_include_sofia_HEADERS = \
+ sofia-sip/nth.h sofia-sip/nth_tag.h
+
+libnth_la_SOURCES = nth_client.c nth_server.c nth_tag.c nth_tag_ref.c
+COVERAGE_INPUT = $(libnth_la_SOURCES) $(include_sofia_HEADERS)
+LDADD = libnth.la \
+ ../iptsec/libiptsec.la \
+ ../ipt/libipt.la \
+ ../http/libhttp.la \
+ ../sresolv/libsresolv.la \
+ ../tport/libtport.la \
+ ../stun/libstun.la \
+ ../sresolv/libsresolv.la \
+ ../url/liburl.la \
+ ../msg/libmsg.la \
+ ../bnf/libbnf.la \
+ ../su/libsu.la
+
+test_nth_LDFLAGS = -static
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+EXTRA_DIST = Doxyfile nth.docs $(BUILT_SOURCES) \
+ agent.pem cafile.pem
+
+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
+
+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/nth/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu libsofia-sip-ua/nth/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-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
+libnth.la: $(libnth_la_OBJECTS) $(libnth_la_DEPENDENCIES)
+ $(LINK) $(libnth_la_LDFLAGS) $(libnth_la_OBJECTS) $(libnth_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
+http-client$(EXEEXT): $(http_client_OBJECTS) $(http_client_DEPENDENCIES)
+ @rm -f http-client$(EXEEXT)
+ $(LINK) $(http_client_LDFLAGS) $(http_client_OBJECTS) $(http_client_LDADD) $(LIBS)
+http-server$(EXEEXT): $(http_server_OBJECTS) $(http_server_DEPENDENCIES)
+ @rm -f http-server$(EXEEXT)
+ $(LINK) $(http_server_LDFLAGS) $(http_server_OBJECTS) $(http_server_LDADD) $(LIBS)
+test_nth$(EXEEXT): $(test_nth_OBJECTS) $(test_nth_DEPENDENCIES)
+ @rm -f test_nth$(EXEEXT)
+ $(LINK) $(test_nth_LDFLAGS) $(test_nth_OBJECTS) $(test_nth_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/http-client.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/http-server.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nth_client.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nth_server.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nth_tag.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nth_tag_ref.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_nth.Po at am__quote@
+
+.c.o:
+ at am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+ at am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ at am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at 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 $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(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-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-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-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-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-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-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) $<
+
+ at ENABLE_COVERAGE_TRUE@coverage:
+ at 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)
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+# 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:
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/agent.pem
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/agent.pem Thu Dec 21 01:30:28 2006
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIDPjCCAqegAwIBAgIHJQIBAZACBjANBgkqhkiG9w0BAQUFADBwMQswCQYDVQQG
+EwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTERMA8GA1UEBxMIU2FuIEpvc2UxDjAM
+BgNVBAoTBXNpcGl0MSkwJwYDVQQLEyBTaXBpdCBUZXN0IENlcnRpZmljYXRlIEF1
+dGhvcml0eTAeFw0wMzEyMDMxODMwMjJaFw0wNjEyMDIxODMwMjJaMGUxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMREwDwYDVQQHEwhTYW4gSm9zZTEO
+MAwGA1UEChMFc2lwaXQxHjAcBgNVBAMTFXBla2thLm5va2lhLnNpcGl0Lm5ldDCB
+nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAsdJn/O6JoIC1I2iXOVJLQypmt9sN
+HmvB84853Qx9KS+xqP3U2nqNMnDQby6ZmTsRHNGAK5QuGugU11wocmYNP0/TQFaz
+KNLhNt0pMBOfpAV9vG6pCSkocObsUo2XFULPTEB/SzGcvE1G1em3XmwRfPA178y9
+L2+sVNT5Vtt5KfMCAwEAAaOB7DCB6TAgBgNVHREEGTAXghVwZWtrYS5ub2tpYS5z
+aXBpdC5uZXQwCQYDVR0TBAIwADAdBgNVHQ4EFgQU1OjdL9cdA0NNbxPDQ9xZUZG6
+NnIwgZoGA1UdIwSBkjCBj4AUa0YXFOqUdiWAVG4TVNqh41QUobahdKRyMHAxCzAJ
+BgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMREwDwYDVQQHEwhTYW4gSm9z
+ZTEOMAwGA1UEChMFc2lwaXQxKTAnBgNVBAsTIFNpcGl0IFRlc3QgQ2VydGlmaWNh
+dGUgQXV0aG9yaXR5ggEAMA0GCSqGSIb3DQEBBQUAA4GBADCO35LJqgiK5OUR+DuT
+N4CfUhsn9T5kDSf2rikna4ZFbuS7smc/oVu4g26HHjt6DKs4UEx9OmyXFslSENZ+
+tFNeVClpHJrPsNwjk/uyjhfeW1NezhXMIi6q8DYcwE5I7r+Uz2XST+jWCTb4obPY
+10ysI7e7/rgCoITe+qO2U35D
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQCx0mf87omggLUjaJc5UktDKma32w0ea8HzjzndDH0pL7Go/dTa
+eo0ycNBvLpmZOxEc0YArlC4a6BTXXChyZg0/T9NAVrMo0uE23SkwE5+kBX28bqkJ
+KShw5uxSjZcVQs9MQH9LMZy8TUbV6bdebBF88DXvzL0vb6xU1PlW23kp8wIDAQAB
+AoGAVtICT64vqBvvVPB2FVimwo5rRI1BJH88XSyq9dBpM7jDp1z3lgyL7/rA6ef4
+uqXqPwXS7HQW5rA1rMikPuawxE5UG31OG3U0+H/OGl0xwAq57mEtRDR8464jSUPY
+l9bzkRpjnEgdUtkLnogm8F4mALexdc3KxIgg3uo/OOg0N5ECQQDZon1JBNEYWxEF
+GBNbEvQthPy7rRLmxontgcsfhRvm5lSbuC+VP1uRHibwwIrXOUZD8uuEVdVZNzfV
+bGPdh70HAkEA0Ss6HyAWczRBzrvC8eVvPmkI9XihdLqUFLTDL0R1sMCISwW/FEeH
+X9yFqOY+y6EJAitzhxtol+0k+UsIJl5ctQJAXU0L6QHnokloQobPxXuasukQcGUC
+dW0oNGowapLmI1cbbqbHv3QqDUyf5Rambx5ewUKjNViW3miNxzFwnshSgQJAINuQ
+gskwnaJM4CPgqM0o333yeVUcz9BraKFItAkmD8D+6AIcFRxzaJykpnac0LIYTy3y
+NPwaPxtynnKp8hUKrQJBAM1i5051UzJVFuRedwtPdGDrfkNwoJm27fwWozSQcBC6
+G5VnTrQ6V8VCJglNzVhy9b2WqlqfWV3D5BCgxyuH984=
+-----END RSA PRIVATE KEY-----
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/cafile.pem
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/cafile.pem Thu Dec 21 01:30:28 2006
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDJDCCAo2gAwIBAgIBADANBgkqhkiG9w0BAQUFADBwMQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTERMA8GA1UEBxMIU2FuIEpvc2UxDjAMBgNVBAoT
+BXNpcGl0MSkwJwYDVQQLEyBTaXBpdCBUZXN0IENlcnRpZmljYXRlIEF1dGhvcml0
+eTAeFw0wMzA3MTgxMjIxNTJaFw0xMzA3MTUxMjIxNTJaMHAxCzAJBgNVBAYTAlVT
+MRMwEQYDVQQIEwpDYWxpZm9ybmlhMREwDwYDVQQHEwhTYW4gSm9zZTEOMAwGA1UE
+ChMFc2lwaXQxKTAnBgNVBAsTIFNpcGl0IFRlc3QgQ2VydGlmaWNhdGUgQXV0aG9y
+aXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDIh6DkcUDLDyK9BEUxkud
++nJ4xrCVGKfgjHm6XaSuHiEtnfELHM+9WymzkBNzZpJu30yzsxwfKoIKugdNUrD4
+N3viCicwcN35LgP/KnbN34cavXHr4ZlqxH+OdKB3hQTpQa38A7YXdaoz6goW2ft5
+Mi74z03GNKP/G9BoKOGd5QIDAQABo4HNMIHKMB0GA1UdDgQWBBRrRhcU6pR2JYBU
+bhNU2qHjVBShtjCBmgYDVR0jBIGSMIGPgBRrRhcU6pR2JYBUbhNU2qHjVBShtqF0
+pHIwcDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExETAPBgNVBAcT
+CFNhbiBKb3NlMQ4wDAYDVQQKEwVzaXBpdDEpMCcGA1UECxMgU2lwaXQgVGVzdCBD
+ZXJ0aWZpY2F0ZSBBdXRob3JpdHmCAQAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0B
+AQUFAAOBgQCWbRvv1ZGTRXxbH8/EqkdSCzSoUPrs+rQqR0xdQac9wNY/nlZbkR3O
+qAezG6Sfmklvf+DOg5RxQq/+Y6I03LRepc7KeVDpaplMFGnpfKsibETMipwzayNQ
+QgUf4cKBiF+65Ue7hZuDJa2EMv8qW4twEhGDYclpFU9YozyS1OhvUg==
+-----END CERTIFICATE-----
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/http-client.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/http-client.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,407 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@file http-client.c Simple HTTP tool.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Fri Mar 30 12:05:21 2001 ppessi
+ */
+
+#include "config.h"
+
+/**@page http_client Make HTTP request
+ *
+ * @par Name
+ * http-client - HTTP request tool
+ *
+ * @par Synopsis
+ *
+ * <tt>http-client [OPTIONS] url</tt>
+ *
+ * @par Description
+ *
+ * The @em http-client utility sends a HTTP request to an HTTP server or proxy.
+ *
+ * @par
+ *
+ * The @em http-client tool will print out status line and interesting
+ * headers from the response. The message body is also printed.
+ *
+ * @par Options
+ *
+ * The @e http-client utility accepts following command line options:
+ * <dl>
+ * <dt>--method=name</dt>
+ * <dd>Specify the request method name (GET by default).
+ * </dd>
+ * <dt>--proxy=url</dt>
+ * <dd>Specifies the proxy via which the request will be sent.
+ * </dd>
+ * <dt>--ua=value</dt>
+ * <dd>Specifies the User-Agent header field.
+ * </dd>
+ * <dt>--mf=n</dt>
+ * <dd>Specify the initial Max-Forwards count.
+ * </dd>
+ * <dt>--pipe</dt>
+ * <dd>Use pipelining (do not shutdown client connection after request).
+ * </dd>
+ * <dt>--extra</dt>
+ * <dd>Insert standard input to the requests.
+ * </dd>
+ * </dl>
+ *
+ * @par Examples
+ *
+ * You want to query supported features of http://connecting.nokia.com:
+ * @code
+ * $ http-client --method OPTIONS http://connecting.nokia.com
+ * @endcode
+ *
+ * @par Environment
+ * @c NTH_DEBUG, @c TPORT_DEBUG, @c TPORT_LOG.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * <hr>
+ */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+
+typedef struct context_s context_t;
+#define NTH_CLIENT_MAGIC_T context_t
+
+#include <sofia-sip/nth.h>
+#include <sofia-sip/http_header.h>
+#include <sofia-sip/http_tag.h>
+#include <sofia-sip/tport_tag.h>
+#include <sofia-sip/auth_client.h>
+
+struct context_s {
+ su_home_t c_home[1];
+ su_root_t *c_root;
+ nth_engine_t *c_engine;
+ nth_client_t *c_clnt;
+ char const *c_user;
+ char const *c_pass;
+ auth_client_t *c_auth;
+ int c_pre;
+ int c_pending;
+};
+
+static
+char const name[] = "http-client";
+
+static
+int header_print(FILE *stream, char const *fmt, http_header_t const *h)
+{
+ char s[1024];
+
+ msg_header_field_e(s, sizeof(s), (msg_header_t*)h, 0);
+ s[sizeof(s) - 1] = '\0';
+
+ if (fmt && strcmp(fmt, "%s"))
+ return fprintf(stream, fmt, s);
+ if (fputs(s, stream) >= 0)
+ return strlen(s);
+ return -1;
+}
+
+static
+int payload_print(FILE *stream, msg_payload_t const *pl)
+{
+ for (; pl; pl = pl->pl_next) {
+ fprintf(stream, "%.*s", (int)pl->pl_len, pl->pl_data);
+ }
+ return 0;
+}
+
+static
+char *read_file(FILE *stream)
+{
+ int n;
+ char *buf;
+ off_t used, size;
+
+ if (stream == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ /* Read block by block */
+ used = 0;
+ size = 512;
+ buf = malloc(size);
+
+ while (buf) {
+ n = fread(buf + used, 1, size - used - 1, stream);
+ used += n;
+ if (n < size - used - 1) {
+ if (feof(stream))
+ ;
+ else if (ferror(stream))
+ free(buf), buf = NULL;
+ break;
+ }
+ buf = realloc(buf, 2 * size);
+ }
+
+ if (buf)
+ if (used < size)
+ buf[used] = '\0';
+
+ return buf;
+}
+
+char const _usage[] =
+"usage: %s [OPTIONS] url\n"
+" where OPTIONS are as follows\n"
+" --method=name\n"
+" --proxy=url\n"
+" --user=user:password\n"
+" --ua=value\n"
+" --mf=n\n"
+" --pipe\n"
+" --extra\n";
+
+static
+void usage(int rc)
+{
+ fprintf(stderr, _usage, name);
+ exit(rc);
+}
+
+static int response(context_t *context,
+ nth_client_t *oreq,
+ http_t const *http);
+
+int main(int argc, char *argv[])
+{
+ su_home_t *home;
+ context_t context[1] = {{{SU_HOME_INIT(context)}}};
+ http_method_t method;
+ char
+ *o_proxy = NULL,
+ *o_user = NULL,
+ *o_max_forwards = NULL,
+ *o_method_name = "GET",
+ *o_user_agent = "http-client/1.0 " "nth/" NTH_VERSION;
+ int
+ o_pipe = 0, o_extra = 0;
+
+ char *extra = NULL;
+ char *v;
+
+#define MATCH(s, o) \
+ ((strcmp(s, o) == 0))
+#define MATCH1(s, o) \
+ ((strncmp(s, o, strlen(o)) == 0) && \
+ (v = (s[strlen(o)] ? s + strlen(o) : argv++[1])))
+#define MATCH2(s, o) \
+ ((strncmp(s, o, strlen(o)) == 0) && \
+ (s[strlen(o)] == '=' || s[strlen(o)] == '\0') && \
+ (v = s[strlen(o)] ? s + strlen(o) + 1 : argv++[1]))
+
+ while ((v = argv++[1])) {
+ if (v[0] != '-') { argv--; break; }
+ else if (MATCH(v, "-")) { break; }
+ else if (MATCH2(v, "--method")) { o_method_name = v; continue; }
+ else if (MATCH2(v, "--mf")) { o_max_forwards = v; continue; }
+ else if (MATCH2(v, "--proxy")) { o_proxy = v; continue; }
+ else if (MATCH2(v, "--user")) { o_user = v; continue; }
+ else if (MATCH2(v, "--ua")) { o_user_agent = v; continue; }
+ else if (MATCH(v, "--pipe")) { o_pipe = 1; continue; }
+ else if (MATCH(v, "--extra")) { o_extra = 1; continue; }
+ else if (MATCH(v, "--help")) { usage(0); continue; }
+ else
+ usage(1);
+ }
+
+ if (!argv[1])
+ usage(1);
+
+ method = http_method_code(o_method_name);
+
+ if (o_user) {
+ char *pass = strchr(o_user, ':');
+ if (pass) *pass++ = '\0';
+ context->c_user = o_user, context->c_pass = pass;
+ }
+
+ su_init();
+
+ su_home_init(home = context->c_home);
+
+ if (o_extra) {
+ if (isatty(0))
+ fprintf(stderr,
+ "Type extra HTTP headers, empty line then HTTP message body "
+ "(^D when complete):\n");
+ fflush(stderr);
+
+ extra = read_file(stdin);
+ }
+
+ context->c_root = su_root_create(context);
+
+ if (context->c_root) {
+ context->c_engine =
+ nth_engine_create(context->c_root,
+ NTHTAG_ERROR_MSG(0),
+ TAG_END());
+
+ if (context->c_engine) {
+ while ((v = argv++[1])) {
+ nth_client_t *clnt;
+ clnt = nth_client_tcreate(context->c_engine,
+ response, context,
+ method, o_method_name,
+ URL_STRING_MAKE(v),
+ NTHTAG_PROXY(o_proxy),
+ HTTPTAG_USER_AGENT_STR(o_user_agent),
+ HTTPTAG_MAX_FORWARDS_STR(o_max_forwards),
+ TPTAG_REUSE(o_pipe),
+ HTTPTAG_HEADER_STR(extra),
+ TAG_END());
+ if (clnt)
+ context->c_pending++;
+ }
+
+ if (context->c_pending)
+ su_root_run(context->c_root);
+
+ nth_engine_destroy(context->c_engine), context->c_engine = NULL;
+ }
+ su_root_destroy(context->c_root);
+ }
+
+ su_deinit();
+
+ return 0;
+}
+
+/** Handle responses to request */
+static
+int response(context_t *c,
+ nth_client_t *clnt,
+ http_t const *http)
+{
+ nth_client_t *newclnt = NULL;
+ int status;
+
+ if (http) {
+ status = http->http_status->st_status;
+ } else {
+ status = nth_client_status(clnt);
+ fprintf(stderr, "HTTP/1.1 %u Error\n", status);
+ }
+
+ if (http && (c->c_pre || status >= 200)) {
+ http_header_t *h = (http_header_t *)http->http_status;
+ char hname[64];
+
+ for (; h; h = (http_header_t *)h->sh_succ) {
+ if (h == (http_header_t *)http->http_payload)
+ continue;
+ else if (h == (http_header_t *)http->http_separator)
+ continue;
+ else if (!h->sh_class->hc_name)
+ header_print(stdout, NULL, h);
+ else if (h->sh_class->hc_name[0]) {
+ snprintf(hname, sizeof hname, "%s: %%s\n", h->sh_class->hc_name);
+ header_print(stdout, hname, h);
+ } else {
+ header_print(stdout, "%s\n", h);
+ }
+ }
+
+ printf("\n");
+ if (http->http_payload)
+ payload_print(stdout, http->http_payload);
+
+ fflush(stdout);
+ }
+
+ if (status < 200)
+ return 0;
+
+ if (status == 401 && http->http_www_authenticate) {
+ char const *user = c->c_user;
+ char const *pass = c->c_pass;
+
+ if (!user || !pass) {
+ url_t const *url = nth_client_url(clnt);
+ if (url) {
+ user = url->url_user, pass = url->url_password;
+ }
+ }
+
+ //if (user && pass &&
+ if (
+ auc_challenge(&c->c_auth, c->c_home,
+ http->http_www_authenticate,
+ http_authorization_class) > 0) {
+ char const *scheme = NULL;
+ char const *realm = NULL;
+
+ scheme = http->http_www_authenticate->au_scheme;
+ realm = msg_params_find(http->http_www_authenticate->au_params,
+ "realm=");
+ if (auc_all_credentials(&c->c_auth, scheme, realm, user, pass)
+ >= 0)
+ newclnt = nth_client_tcreate(c->c_engine,
+ NULL, NULL, HTTP_NO_METHOD, NULL,
+ NTHTAG_AUTHENTICATION(&c->c_auth),
+ NTHTAG_TEMPLATE(clnt),
+ TAG_END());
+ }
+ }
+
+ if (status == 302 && http->http_location) {
+ url_t loc[1];
+
+ *loc = *http->http_location->loc_url;
+
+ newclnt = nth_client_tcreate(c->c_engine, NULL, NULL,
+ HTTP_NO_METHOD,
+ (url_string_t *)loc,
+ NTHTAG_TEMPLATE(clnt),
+ TAG_END());
+ }
+
+
+ if (newclnt)
+ c->c_pending++;
+
+ nth_client_destroy(clnt);
+ if (c->c_pending-- == 1)
+ su_root_break(c->c_root);
+
+ return 0;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/http-server.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/http-server.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,287 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@nofile http-server.c
+ * @brief Test HTTP server
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Sat Oct 19 02:56:23 2002 ppessi
+ *
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <signal.h>
+
+typedef struct context_s context_t;
+#define NTH_SITE_MAGIC_T context_t
+#define SU_ROOT_MAGIC_T context_t
+
+#include <sofia-sip/nth.h>
+#include <sofia-sip/tport_tag.h>
+#include <sofia-sip/http_header.h>
+
+struct context_s {
+ su_home_t c_home[1];
+ su_root_t *c_root;
+ nth_site_t *c_site;
+ char const *c_server;
+ char const *c_expires;
+ char const *c_content_type;
+ http_content_length_t *c_content_length;
+ msg_payload_t *c_body;
+};
+
+char const name[] = "http-server";
+
+static
+void usage(int rc)
+{
+ fprintf(rc ? stderr : stdout,
+ "usage: %s OPTIONS url [content]\n",
+ name
+ );
+ exit(rc);
+}
+
+static int request(context_t *context,
+ nth_site_t *site,
+ nth_request_t *req,
+ http_t const *http,
+ char const *path);
+su_msg_r server_intr_msg = SU_MSG_R_INIT;
+static RETSIGTYPE server_intr_handler(int signum);
+static void server_break(context_t *c, su_msg_r msg, su_msg_arg_t *arg);
+
+static msg_payload_t *read_payload(su_home_t *home, char const *fname);
+static msg_payload_t *fread_payload(su_home_t *home, FILE *f);
+
+int main(int argc, char *argv[])
+{
+ su_home_t *home;
+ context_t *c, context[1] = {{{SU_HOME_INIT(context)}}};
+ char *o_url = NULL, *o_body = NULL;
+ int o_extra = 0;
+ int o_timeout = 300;
+ char *s;
+
+ c = context;
+ su_init();
+ su_home_init(home = context->c_home);
+
+#define MATCH(s, v) \
+ ((strncmp(s, v, strlen(v)) == 0))
+#define MATCH1(s, v) \
+ ((strncmp(s, v, strlen(v)) == 0) && \
+ (s = (s[strlen(v)] ? s + strlen(v) : argv++[1])))
+#define MATCH2(s, v) \
+ ((strncmp(s, v, strlen(v)) == 0) && \
+ (s[strlen(v)] == '=' ? (s = s + strlen(v) + 1) : (s = argv++[1])))
+
+ while ((s = argv++[1])) {
+ if (*s != '-') break;
+ s++;
+ if (MATCH2(s, "-expires")) { c->c_expires = s; continue; }
+ else if (MATCH2(s, "-tcp-timeout")) { o_timeout = strtoul(s, &s, 0); continue; }
+ else if (MATCH2(s, "-ct")) { c->c_content_type = s; continue; }
+ else if (MATCH2(s, "-content-type")) { c->c_content_type = s; continue; }
+ else if (MATCH2(s, "-server")) { c->c_server = s; continue; }
+ else if (MATCH(s, "-help")) { usage(0); continue; }
+ else if (MATCH(s, "x")||MATCH(s, "-extra")) { o_extra = 1; continue; }
+ else
+ usage(2);
+ }
+
+ if (!(o_url = s))
+ usage(1);
+ else
+ o_body = argv++[1];
+
+ context->c_root = su_root_create(context);
+
+ context->c_body = read_payload(context->c_home, o_body);
+ if (!context->c_body) {
+ perror("contents");
+ exit(1);
+ }
+
+ context->c_content_length =
+ msg_content_length_create(context->c_home, context->c_body->pl_len);
+
+ su_msg_create(server_intr_msg,
+ su_root_task(context->c_root),
+ su_root_task(context->c_root),
+ server_break, 0);
+
+ signal(SIGINT, server_intr_handler);
+
+#ifndef _WIN32
+ signal(SIGPIPE, server_intr_handler);
+ signal(SIGQUIT, server_intr_handler);
+ signal(SIGHUP, server_intr_handler);
+#endif
+
+ if (context->c_root) {
+ context->c_site =
+ nth_site_create(NULL, /* This is a top-level site */
+ request, context,
+ (url_string_t *)o_url,
+ NTHTAG_ROOT(context->c_root),
+ TPTAG_TIMEOUT(o_timeout * 1000),
+ TAG_END());
+
+ if (context->c_site) {
+ su_root_run(context->c_root);
+ nth_site_destroy(context->c_site);
+ }
+
+ su_root_destroy(context->c_root);
+ }
+
+ su_deinit();
+
+ return 0;
+}
+
+static void server_break(context_t *c, su_msg_r msg, su_msg_arg_t *arg)
+{
+ fprintf(stderr, "%s: received signal, exiting\n", name);
+
+ su_root_break(c->c_root);
+}
+
+static RETSIGTYPE server_intr_handler(int signum)
+{
+ su_msg_send(server_intr_msg);
+}
+
+
+static int request(context_t *c,
+ nth_site_t *site,
+ nth_request_t *req,
+ http_t const *http,
+ char const *path)
+{
+ fprintf(stderr, "request to /%s\n", path);
+
+ if (path && strlen(path))
+ return 404;
+
+ if (http->http_request->rq_method != http_method_get) {
+ nth_request_treply(req, HTTP_405_NOT_ALLOWED,
+ HTTPTAG_ALLOW_STR("GET"),
+ TAG_END());
+ return 405;
+ }
+
+ nth_request_treply(req, HTTP_200_OK,
+ HTTPTAG_SERVER_STR(c->c_server),
+ HTTPTAG_EXPIRES_STR(c->c_expires),
+ HTTPTAG_CONTENT_TYPE_STR(c->c_content_type),
+ HTTPTAG_CONTENT_LENGTH(c->c_content_length),
+ HTTPTAG_PAYLOAD(c->c_body),
+ TAG_END());
+ return 200;
+}
+
+/** Read message body from named file.
+ *
+ * The function read_payload() reads the contents to a SIP payload
+ * structure from a the named file. If @a fname is NULL, the payload
+ * contents are read from standard input.
+ */
+msg_payload_t *read_payload(su_home_t *home, char const *fname)
+{
+ FILE *f;
+ msg_payload_t *pl;
+
+ if (fname == NULL || strcmp(fname, "-") == 0)
+ f = stdin, fname = "<stdin>";
+ else
+ f = fopen(fname, "rb");
+
+ if (f == NULL)
+ return NULL;
+
+ pl = fread_payload(home, f);
+ if (f != stdin)
+ fclose(f);
+
+ return pl;
+}
+
+msg_payload_t *fread_payload(su_home_t *home, FILE *f)
+{
+ msg_payload_t *pl;
+ int n;
+ char *buf;
+ off_t used, size;
+
+
+ if (f == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ pl = msg_payload_create(home, NULL, 0);
+
+ if (pl == NULL)
+ return NULL;
+
+ /* Read block by block */
+ used = 0;
+ size = 4096;
+ buf = malloc(size);
+
+ while (buf) {
+ n = fread(buf + used, 1, size - used, f);
+ used += n;
+ if (n < size - used) {
+ if (feof(f))
+ ;
+ else if (ferror(f))
+ buf = NULL;
+ break;
+ }
+ buf = realloc(buf, size = 2 * size);
+ }
+ if (buf == NULL) {
+ perror("fread_payload: realloc");
+ return NULL;
+ }
+
+ if (used < size)
+ buf[used] = '\0';
+
+ pl->pl_common->h_data = pl->pl_data = buf;
+ pl->pl_common->h_len = pl->pl_len = used;
+
+ return pl;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/nth.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/nth.docs Thu Dec 21 01:30:28 2006
@@ -0,0 +1,21 @@
+/* -*- c -*- */
+
+/**@MODULEPAGE "nth" - HTTP Transactions Module
+ *
+ * @section nth_meta Module Meta Information
+ *
+ * NTH provides interface to simple HTTP transaction engines for both HTTP
+ * servers and clients. The transaction interface for both client and server
+ * is available through <nth.h>, tags controlling the options in
+ * <nth_tag.h>.
+ *
+ * @CONTACT Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @STATUS @SofiaSIP Core library
+ *
+ * @LICENSE LGPL
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ */
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/nth_client.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/nth_client.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1268 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nth_client.c
+ * @brief HTTP Client implementhtion
+ *
+ * Copyright (c) 2002 Nokia Research Center. All rights reserved.
+ *
+ * This source file has been divided into following sections:
+ * 1) engine
+ * 2) tport handling
+ * 3) client transactions
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Jun 13 02:57:51 2000 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <sofia-sip/string0.h>
+
+/** @internal SU message argument structure type */
+#define SU_MSG_ARG_T union sm_arg_u
+/** @internal SU timer argument pointer type */
+#define SU_TIMER_ARG_T struct nth_engine_s
+
+#define MSG_HDR_T union http_header_u
+#define MSG_PUB_T struct http_s
+
+#include "sofia-sip/nth.h"
+#include <sofia-sip/http_header.h>
+#include <sofia-sip/http_tag.h>
+#include <sofia-sip/http_status.h>
+
+#include <sofia-sip/hostdomain.h>
+
+#include <sofia-sip/msg_addr.h>
+#include <sofia-sip/su_tagarg.h>
+
+#include <sofia-sip/auth_client.h>
+
+/* We are customer of tport_t */
+#define TP_STACK_T nth_engine_t
+#define TP_MAGIC_T void
+#define TP_CLIENT_T nth_client_t
+
+#ifndef TPORT_H
+#include <sofia-sip/tport.h>
+#endif
+#include <sofia-sip/htable.h>
+
+#define HE_TIMER HE_TIMER
+enum { HE_TIMER = 1000 };
+
+/** @c http_flag telling that this message is internally generated. */
+#define NTH_INTERNAL_MSG (1<<16)
+
+HTABLE_DECLARE_WITH(hc_htable, hct, nth_client_t, uintptr_t, size_t);
+
+struct nth_engine_s {
+ su_home_t he_home[1];
+ su_root_t *he_root;
+ su_timer_t *he_timer;
+ int he_mflags; /**< Message flags */
+ msg_mclass_t const *he_mclass;
+
+ tport_t *he_tports;
+
+ url_t *he_default_proxy;
+
+ unsigned he_now;
+ unsigned he_expires;
+
+ /* Attributes */
+ unsigned he_streaming:1; /**< Enable streaming */
+ unsigned he_error_msg:1;
+ unsigned:0;
+
+ /* Statistics */
+ struct {
+ uint32_t st_requests; /**< Sent requests */
+ uint32_t st_1xxresponses; /**< Received 1XX responses */
+ uint32_t st_responses; /**< Received responses */
+ uint32_t st_tp_errors; /**< Transport errors */
+ uint32_t st_timeouts; /**< Timeouts */
+ uint32_t st_bad; /**< Bad responses*/
+ } he_stats[1];
+
+ /** Table for client transactions */
+ hc_htable_t he_clients[1];
+};
+
+struct nth_client_s {
+ nth_engine_t *hc_engine;
+ nth_response_f *hc_callback;
+ nth_client_magic_t *hc_magic;
+
+ http_method_t hc_method;
+ char const *hc_method_name;
+ url_t const *hc_url; /**< Original RequestURI */
+
+ unsigned hc_timeout; /**< Client timeout */
+ unsigned hc_expires; /**< Client expires */
+
+ /* Request state */
+ unsigned short hc_status;
+ unsigned hc_destroyed:1;
+ unsigned hc_completed:1;
+ unsigned hc_inserted:1;
+ unsigned hc_is_streaming:1; /**< Currently streaming response */
+
+ /* Attributes */
+ unsigned hc_streaming:1; /**< Enable streaming */
+ unsigned hc_error_msg:1;
+ unsigned /* pad */:0;
+
+ url_string_t const *hc_route_url;
+ tp_name_t hc_tpn[1]; /**< Where to send requests */
+ tport_t *hc_tport;
+ int hc_pending; /**< Request is pending in tport */
+ tagi_t *hc_tags; /**< Transport tags */
+
+ auth_client_t **hc_auc; /**< List of authenticators */
+
+ msg_t *hc_request;
+ msg_t *hc_response;
+};
+
+
+/* ====================================================================== */
+/* Debug log settings */
+
+#define SU_LOG nth_client_log
+
+#ifdef SU_DEBUG_H
+#error <su_debug.h> included directly.
+#endif
+#include <sofia-sip/su_debug.h>
+
+/**@var NTH_DEBUG
+ *
+ * Environment variable determining the debug log level for @b nth
+ * module.
+ *
+ * The NTH_DEBUG environment variable is used to determine the debug
+ * logging level for @b nth module. The default level is 1.
+ *
+ * @sa <su_debug.h>, nth_client_log, #SOFIA_DEBUG
+ */
+extern char const NTH_DEBUG[];
+
+#ifndef SU_DEBUG
+#define SU_DEBUG 1
+#endif
+
+/**Debug log for @b nth module.
+ *
+ * The nth_client_log is the log object used by @b nth client. The level of
+ * #nth_client_log is set using #NTH_DEBUG environment variable.
+ */
+su_log_t nth_client_log[] = { SU_LOG_INIT("nth", "NTH_DEBUG", SU_DEBUG) };
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+static char const __func__[] = "nth";
+#endif
+
+/* ====================================================================== */
+/* Internal message passing */
+
+union sm_arg_u {
+ struct hc_recv_s {
+ nth_client_t *hc;
+ msg_t *msg;
+ http_t *http;
+ } hc_recv[1];
+};
+
+/* ====================================================================== */
+/* Internal prototypes */
+
+tagi_t nth_client_tags[] = {
+ {nthtag_mclass, 0},
+ {nthtag_message, 0},
+ {nthtag_mflags, 0},
+
+ {nthtag_proxy, 0},
+ {nthtag_error_msg, 0},
+ {nthtag_template, 0},
+ {nthtag_authentication, 0},
+
+ {TAG_NEXT(tport_tags)}
+};
+
+/* ====================================================================== */
+/* Internal prototypes */
+
+static int he_create_tports(nth_engine_t * he, tagi_t *tags);
+static int he_timer_init(nth_engine_t * he);
+static void he_timer(su_root_magic_t *, su_timer_t *, nth_engine_t * he);
+static void hc_timer(nth_engine_t * he, nth_client_t * hc, uint32_t now);
+static uint32_t he_now(nth_engine_t const *he);
+static void he_recv_message(nth_engine_t * he, tport_t * tport,
+ msg_t *msg, void *arg, su_time_t now);
+static msg_t *he_msg_create(nth_engine_t * he, int flags,
+ char const data[], usize_t dlen,
+ tport_t const *tport, nth_client_t * hc);
+static void he_tp_error(nth_engine_t * he,
+ tport_t * tport, int errcode, char const *remote);
+static int hc_recv(nth_client_t * hc, msg_t *msg, http_t * http);
+
+HTABLE_PROTOS_WITH(hc_htable, hct, nth_client_t, uintptr_t, size_t);
+
+#define HTABLE_HASH_CLIENT(hc) ((uintptr_t)(hc)->hc_tport)
+HTABLE_BODIES_WITH(hc_htable, hct, nth_client_t, HTABLE_HASH_CLIENT,
+ uintptr_t, size_t);
+
+static url_string_t const *hc_request_complete(nth_client_t * hc,
+ msg_t *msg, http_t * http,
+ http_method_t method,
+ char const *name,
+ url_string_t const *url,
+ char const *version,
+ url_t const *parent);
+static
+int hc_request_authenticate(nth_client_t * hc,
+ msg_t *msg, http_t * http,
+ url_string_t const *uri, auth_client_t **auc);
+static
+nth_client_t *hc_create(nth_engine_t * he,
+ nth_response_f * callback,
+ nth_client_magic_t * magic,
+ msg_t *msg, tag_type_t tag, tag_value_t value, ...);
+static int hc_resolve_and_send(nth_client_t * hc);
+static nth_client_t *hc_send(nth_client_t * hc);
+static void hc_insert(nth_engine_t * he, nth_client_t * hc);
+static void hc_free(nth_client_t * hc);
+static void hc_tport_error(nth_engine_t *, nth_client_t * hc,
+ tport_t * tp, msg_t *msg, int error);
+static int hc_reply(nth_client_t * hc, int status, char const *phrase);
+static int hc_default_cb(nth_client_magic_t * magic,
+ nth_client_t * request, http_t const *http);
+
+/* ---------------------------------------------------------------------- */
+
+char const *nth_engine_version(void)
+{
+ return "sofia-http-client/" NTH_CLIENT_VERSION;
+}
+
+/* ---------------------------------------------------------------------- */
+
+nth_engine_t *nth_engine_create(su_root_t *root,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ nth_engine_t *he;
+ ta_list ta;
+
+ if ((he = su_home_new(sizeof(*he)))) {
+ he->he_root = root;
+ he->he_mflags = MSG_DO_CANONIC;
+ he->he_mclass = http_default_mclass();
+ he->he_expires = 32000;
+
+ ta_start(ta, tag, value);
+
+ if (hc_htable_resize(he->he_home, he->he_clients, 0) < 0 ||
+ he_create_tports(he, ta_args(ta)) < 0 ||
+ he_timer_init(he) < 0 || nth_engine_set_params(he, ta_tags(ta)) < 0) {
+ nth_engine_destroy(he), he = NULL;
+ }
+
+ ta_end(ta);
+ }
+
+ return he;
+}
+
+void nth_engine_destroy(nth_engine_t * he)
+{
+ if (he) {
+ size_t i;
+ hc_htable_t *hct = he->he_clients;
+
+ for (i = 0; i < hct->hct_size; i++)
+ hc_free(hct->hct_table[i]);
+
+ tport_destroy(he->he_tports);
+
+ su_timer_destroy(he->he_timer), he->he_timer = NULL;
+
+ su_home_unref(he->he_home);
+ }
+}
+
+int nth_engine_set_params(nth_engine_t * he,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ int n;
+ ta_list ta;
+ unsigned expires;
+ int error_msg;
+ msg_mclass_t const *mclass;
+ int mflags;
+ int streaming;
+ url_string_t const *proxy;
+
+ if (he == NULL)
+ return (errno = EINVAL), -1;
+
+ ta_start(ta, tag, value);
+
+ expires = he->he_expires;
+ error_msg = he->he_error_msg;
+ mclass = he->he_mclass;
+ mflags = he->he_mflags;
+ streaming = he->he_streaming;
+ proxy = (void *) he->he_default_proxy;
+
+ n = tl_gets(ta_args(ta),
+ NTHTAG_EXPIRES_REF(expires),
+ NTHTAG_ERROR_MSG_REF(error_msg),
+ NTHTAG_MCLASS_REF(mclass),
+ NTHTAG_MFLAGS_REF(mflags),
+ NTHTAG_STREAMING_REF(streaming),
+ NTHTAG_PROXY_REF(proxy), TAG_END());
+
+ if (n > 0) {
+ if (proxy->us_url != he->he_default_proxy) {
+ url_t *copy = url_hdup(he->he_home, proxy->us_url);
+
+ if (proxy && !copy) {
+ n = -1;
+ } else {
+ su_free(he->he_home, (void *) he->he_default_proxy);
+ he->he_default_proxy = copy;
+ }
+ }
+ }
+
+ if (n > 0) {
+ he->he_expires = expires;
+ he->he_error_msg = error_msg != 0;
+ if (mclass)
+ he->he_mclass = mclass;
+ else
+ he->he_mclass = http_default_mclass();
+ he->he_mflags = mflags;
+ he->he_streaming = streaming != 0;
+ }
+
+ ta_end(ta);
+
+ return n;
+}
+
+int nth_engine_get_params(nth_engine_t const *he,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ int n;
+ ta_list ta;
+ msg_mclass_t const *mclass;
+
+ if (he == NULL)
+ return (errno = EINVAL), -1;
+
+ if (he->he_mclass != http_default_mclass())
+ mclass = he->he_mclass;
+ else
+ mclass = NULL;
+
+ ta_start(ta, tag, value);
+
+ n = tl_tgets(ta_args(ta),
+ NTHTAG_ERROR_MSG(he->he_error_msg),
+ NTHTAG_MCLASS(mclass),
+ NTHTAG_MFLAGS(he->he_mflags),
+ NTHTAG_EXPIRES(he->he_expires),
+ NTHTAG_STREAMING(he->he_streaming),
+ NTHTAG_PROXY((url_string_t *) he->he_default_proxy),
+ TAG_END());
+
+ ta_end(ta);
+
+ return n;
+}
+
+int nth_engine_get_stats(nth_engine_t const *he,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ int n;
+ ta_list ta;
+
+ if (he == NULL)
+ return (errno = EINVAL), -1;
+
+ ta_start(ta, tag, value);
+
+ n = tl_tgets(ta_args(ta), TAG_END());
+
+ ta_end(ta);
+
+ return n;
+}
+
+static tp_name_t he_name[1] = { {"*", "*", "*", "*"} };
+
+static char const *const he_tports[] = {
+ "tcp", "tls", NULL
+};
+
+static tp_stack_class_t http_client_class[1] = { {
+ sizeof(http_client_class),
+ he_recv_message,
+ he_tp_error,
+ he_msg_create}
+};
+
+/** Create transports for client engine */
+static
+int he_create_tports(nth_engine_t * he, tagi_t *tags)
+{
+ he->he_tports = tport_tcreate(he, http_client_class, he->he_root, TAG_END());
+
+ if (!he->he_tports)
+ return -1;
+
+ return tport_tbind(he->he_tports, he_name, he_tports,
+ TPTAG_SERVER(0), TAG_NEXT(tags));
+}
+
+/** Initialize engine timer. */
+static
+int he_timer_init(nth_engine_t * he)
+{
+ he->he_timer = su_timer_create(su_root_task(he->he_root), HE_TIMER);
+ return su_timer_set(he->he_timer, he_timer, he);
+}
+
+/**
+ * Engine timer routine.
+ */
+static
+void he_timer(su_root_magic_t *rm, su_timer_t *timer, nth_engine_t * he)
+{
+ unsigned i;
+ uint32_t now;
+ hc_htable_t *hct = he->he_clients;
+
+ now = su_time_ms(su_now());
+ now += now == 0;
+ he->he_now = now;
+
+ if (hct)
+ for (i = hct->hct_size; i > 0;)
+ if (hct->hct_table[--i])
+ hc_timer(he, hct->hct_table[i], now);
+
+ su_timer_set(timer, he_timer, he);
+
+ he->he_now = 0;
+}
+
+/** Get current timestamp in milliseconds */
+static
+uint32_t he_now(nth_engine_t const *he)
+{
+ if (he->he_now)
+ return he->he_now;
+ else
+ return su_time_ms(su_now());
+}
+
+static
+void he_recv_message(nth_engine_t * he,
+ tport_t * tport, msg_t *msg, void *arg, su_time_t now)
+{
+ nth_client_t *hc, **hcp;
+ tp_name_t const *tpn;
+
+ for (hcp = hc_htable_hash(he->he_clients, (hash_value_t)(uintptr_t) tport);
+ (hc = *hcp); hcp = hc_htable_next(he->he_clients, hcp)) {
+ if (hc->hc_tport == tport) {
+ if (hc_recv(hc, msg, http_object(msg)) < 0)
+ msg_destroy(msg);
+ return;
+ }
+ }
+
+ /* Extra response? Framing error? */
+
+ tpn = tport_name(tport);
+
+ if (msg_size(msg))
+ SU_DEBUG_3(("nth client: received extra data ("MOD_ZU" bytes) "
+ "from %s/%s:%s\n",
+ (size_t)msg_size(msg),
+ tpn->tpn_proto, tpn->tpn_host, tpn->tpn_port));
+ else
+ SU_DEBUG_3(("nth client: received extra data from %s/%s:%s\n",
+ tpn->tpn_proto, tpn->tpn_host, tpn->tpn_port));
+
+ msg_destroy(msg);
+ tport_shutdown(tport, 2);
+}
+
+/** Report error from transport */
+static void he_tp_error(nth_engine_t * he,
+ tport_t * tport, int errcode, char const *remote)
+{
+ su_log("\nth: tport: %s%s%s\n",
+ remote ? remote : "", remote ? ": " : "", su_strerror(errcode));
+}
+
+/** Create a new message. */
+msg_t *nth_engine_msg_create(nth_engine_t * he, int flags)
+{
+ if (he == NULL) {
+ errno = EINVAL;
+ return NULL;
+
+ }
+
+ flags |= he->he_mflags;
+
+ if (he->he_streaming)
+ flags |= MSG_FLG_STREAMING;
+ else
+ flags &= ~MSG_FLG_STREAMING;
+
+ return msg_create(he->he_mclass, flags);
+}
+
+
+/** Create a new message for transport */
+static
+msg_t *he_msg_create(nth_engine_t * he, int flags,
+ char const data[], usize_t dlen,
+ tport_t const *tport, nth_client_t * hc)
+{
+
+ flags |= he->he_mflags;
+
+ if (he->he_streaming)
+ flags |= MSG_FLG_STREAMING;
+ else
+ flags &= ~MSG_FLG_STREAMING;
+
+ if (hc == NULL) {
+ nth_client_t **slot;
+ for (slot = hc_htable_hash(he->he_clients, (hash_value_t)(uintptr_t) tport);
+ (hc = *slot); slot = hc_htable_next(he->he_clients, slot))
+ if (hc->hc_tport == tport)
+ break;
+ }
+
+ if (hc) {
+ if (hc->hc_method == http_method_head) {
+ flags &= ~MSG_FLG_STREAMING;
+ flags |= HTTP_FLG_NO_BODY;
+ }
+ }
+
+ return msg_create(he->he_mclass, flags);
+}
+
+/** Get destination name from Host header and request URI. */
+static
+int tpn_by_host(tp_name_t * tpn, http_host_t const *h, url_t const *url)
+{
+ if (!h || !url)
+ return -1;
+
+ tpn->tpn_proto = url_tport_default(url->url_type);
+ tpn->tpn_canon = h->h_host;
+ tpn->tpn_host = h->h_host;
+ if (h->h_port)
+ tpn->tpn_port = h->h_port;
+ else
+ tpn->tpn_port = url_port_default(url->url_type);
+
+ return 0;
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+nth_client_t *nth_client_tcreate(nth_engine_t * engine,
+ nth_response_f * callback,
+ nth_client_magic_t * magic,
+ http_method_t method, char const *name,
+ url_string_t const *uri,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ nth_client_t *hc = NULL;
+ ta_list ta;
+
+ if (engine) {
+ void *none = &none;
+ msg_t *msg = none;
+ http_t *http;
+ char const *version = http_version_1_1;
+ nth_client_t const *template = NULL;
+ auth_client_t **auc = none;
+ unsigned expires = engine->he_expires;
+ int ok = 0;
+
+ ta_start(ta, tag, value);
+
+ tl_gets(ta_args(ta),
+ NTHTAG_TEMPLATE_REF(template),
+ NTHTAG_AUTHENTICATION_REF(auc),
+ NTHTAG_MESSAGE_REF(msg),
+ NTHTAG_EXPIRES_REF(expires),
+ HTTPTAG_VERSION_REF(version),
+ TAG_END());
+
+ if (msg == none) {
+ if (template && template->hc_request)
+ msg = msg_copy(template->hc_request);
+ else
+ msg = msg_create(engine->he_mclass, engine->he_mflags);
+ }
+ http = http_object(msg);
+
+ if (template) {
+ if (callback == NULL)
+ callback = template->hc_callback;
+ if (magic == NULL)
+ magic = template->hc_magic;
+ if (name == NULL)
+ method = template->hc_method, name = template->hc_method_name;
+ if (uri == NULL)
+ uri = (url_string_t *) template->hc_url;
+
+ if (auc == none)
+ auc = template->hc_auc;
+ } else if (auc == none) {
+ auc = NULL;
+ }
+
+ hc = hc_create(engine, callback, magic, msg, ta_tags(ta));
+
+ if (hc)
+ hc->hc_expires = expires;
+
+ if (hc == NULL)
+ ;
+ else if (http_add_tl(msg, http, ta_tags(ta)) < 0)
+ ;
+ else if (!(uri = hc_request_complete(hc, msg, http,
+ method, name, uri, version,
+ nth_client_url(template))))
+ ;
+ else if (auc && hc_request_authenticate(hc, msg, http, uri, auc) <= 0)
+ ;
+ else if (hc_resolve_and_send(hc) < 0)
+ ;
+ else
+ ok = 1;
+
+ if (!ok) {
+ if (hc)
+ hc_free(hc);
+ else
+ msg_destroy(msg);
+ hc = NULL;
+ }
+
+ ta_end(ta);
+ }
+
+ return hc;
+}
+
+static
+url_string_t const *hc_request_complete(nth_client_t * hc,
+ msg_t *msg, http_t * http,
+ http_method_t method,
+ char const *name,
+ url_string_t const *uri,
+ char const *version,
+ url_t const *parent)
+{
+ su_home_t *home = msg_home(msg);
+ http_host_t *host = http->http_host;
+ void *tbf = NULL;
+ url_t const *url;
+ url_t u[1];
+
+ if (uri == NULL && http->http_request)
+ uri = (url_string_t *) http->http_request->rq_url;
+
+ if (uri == NULL)
+ uri = (url_string_t *) parent;
+
+ url = url_string_p(uri) ? (tbf = url_hdup(NULL, uri->us_url)) : uri->us_url;
+
+ if (!url)
+ return NULL;
+
+ *u = *url;
+
+ if (u->url_type == url_unknown && u->url_path && !u->url_host) {
+ if (parent) {
+ *u = *parent;
+ u->url_path = url->url_path; /* XXX - relative URLs! */
+ u->url_params = url->url_params;
+ u->url_headers = url->url_headers; /* Query */
+ }
+ }
+
+ if (!hc->hc_route_url && u->url_type != url_http
+ && u->url_type != url_https)
+ hc->hc_route_url = (url_string_t *) u;
+
+ if (host &&
+ (host_cmp(host->h_host, u->url_host) ||
+ str0cmp(host->h_port, u->url_port)))
+ host = NULL;
+
+ if (host == NULL && u->url_host) {
+ host = http_host_create(home, u->url_host, u->url_port);
+ msg_header_insert(msg, http, (http_header_t *) host);
+ }
+
+ if (u->url_host || hc->hc_route_url || host)
+ hc->hc_url = url_hdup(home, u);
+
+ if (hc->hc_route_url == (url_string_t *) u)
+ hc->hc_route_url = (url_string_t *) hc->hc_url;
+
+ if (hc->hc_url) {
+ http_request_t *rq = http->http_request;
+
+ if (rq && !method && !name)
+ method = rq->rq_method, name = rq->rq_method_name;
+ else if (rq && method && method != rq->rq_method)
+ rq = NULL;
+ else if (rq && name && strcmp(name, rq->rq_method_name))
+ rq = NULL;
+
+ if (rq && version && strcasecmp(version, rq->rq_version))
+ rq = NULL;
+
+ if (!hc->hc_route_url) {
+ u->url_type = url_unknown, u->url_scheme = NULL;
+ u->url_user = NULL, u->url_password = NULL;
+ u->url_host = NULL, u->url_port = NULL;
+ u->url_root = '/';
+ if (!u->url_path)
+ u->url_path = "";
+ u->url_fragment = NULL;
+ }
+
+ if (rq && http_url_cmp(u, rq->rq_url))
+ rq = NULL;
+
+ if (!rq) {
+ if (http->http_request)
+ msg_header_remove(msg, http, (msg_header_t *) http->http_request);
+
+ http->http_request =
+ http_request_create(home, method, name, (url_string_t *) u, version);
+
+ if (!http->http_request)
+ uri = NULL;
+ }
+ } else {
+ uri = NULL;
+ }
+
+ if (http_message_complete(msg, http) < 0)
+ uri = NULL;
+
+ if (tbf)
+ su_free(NULL, tbf);
+
+ if (uri) {
+ hc->hc_method = http->http_request->rq_method;
+ hc->hc_method_name = http->http_request->rq_method_name;
+ }
+
+ return uri;
+}
+
+static
+int hc_request_authenticate(nth_client_t * hc,
+ msg_t *msg,
+ http_t * http,
+ url_string_t const *uri, auth_client_t **auc)
+{
+ return auc_authorization(auc, msg, http,
+ http->http_request->rq_method_name,
+ uri->us_url, http->http_payload);
+}
+
+static
+nth_client_t *hc_create(nth_engine_t * he,
+ nth_response_f * callback,
+ nth_client_magic_t * magic,
+ msg_t *msg, tag_type_t tag, tag_value_t value, ...)
+{
+ nth_client_t *hc;
+ su_home_t *home = msg_home(msg);
+
+ if (!(hc = su_zalloc(he->he_home, sizeof(*hc))))
+ return NULL;
+
+ if (!callback)
+ callback = hc_default_cb;
+
+ {
+ int error_msg = he->he_error_msg;
+ int streaming = he->he_streaming;
+ url_string_t const *route_url = NULL;
+
+ ta_list ta;
+ ta_start(ta, tag, value);
+
+ route_url = (url_string_t *) he->he_default_proxy;
+
+ tl_gets(ta_args(ta),
+ NTHTAG_PROXY_REF(route_url),
+ NTHTAG_ERROR_MSG_REF(error_msg),
+ NTHTAG_STREAMING_REF(streaming), TAG_END());
+
+ hc->hc_engine = he;
+ hc->hc_callback = callback;
+ hc->hc_magic = magic;
+ hc->hc_tags = tl_afilter(home, tport_tags, ta_args(ta));
+ hc->hc_error_msg = error_msg;
+ hc->hc_streaming = streaming;
+ hc->hc_route_url = route_url;
+
+ ta_end(ta);
+ }
+
+ hc->hc_request = msg;
+
+ return hc;
+}
+
+
+static
+int hc_resolve_and_send(nth_client_t * hc)
+{
+ msg_t *msg = hc->hc_request;
+ http_t *http = http_object(msg);
+ su_home_t *home = msg_home(msg);
+ int resolved = -1;
+
+ if (hc->hc_route_url) {
+ resolved = tport_name_by_url(home, hc->hc_tpn, hc->hc_route_url);
+ } else {
+ resolved = tpn_by_host(hc->hc_tpn, http->http_host, hc->hc_url);
+ }
+
+ if (resolved < 0) {
+ SU_DEBUG_3(("nth client resolve: %s\n", "cannot resolve URL"));
+ return -1;
+ }
+
+ hc->hc_route_url = NULL;
+
+ hc->hc_tport = tport_by_name(hc->hc_engine->he_tports, hc->hc_tpn);
+
+ if (!hc->hc_tport) {
+ assert(hc->hc_tport);
+ SU_DEBUG_3(("nth client create: %s\n",
+ !hc->hc_tport ? "no transport" : "invalid message"));
+ return -1;
+ }
+
+ if (msg_serialize(msg, http) < 0) {
+ assert(hc->hc_tport);
+ SU_DEBUG_3(("nth client create: invalid message"));
+ return -1;
+ }
+
+ hc_send(hc);
+
+ hc_insert(hc->hc_engine, hc);
+
+ return 0;
+}
+
+/**@internal
+ * Insert client request to the hash table
+ */
+static
+void hc_insert(nth_engine_t * he, nth_client_t * hc)
+{
+ if (hc_htable_is_full(he->he_clients))
+ hc_htable_resize(he->he_home, he->he_clients, 0);
+ hc_htable_insert(he->he_clients, hc);
+ hc->hc_inserted = 1;
+}
+
+/**@internal
+ * Remove client request from the hash table
+ */
+static
+void hc_remove(nth_engine_t * he, nth_client_t * hc)
+{
+ if (hc->hc_inserted)
+ hc_htable_remove(he->he_clients, hc);
+ hc->hc_inserted = 0;
+}
+
+/** Destroy client request. */
+void nth_client_destroy(nth_client_t * hc)
+{
+ if (hc == NULL)
+ ;
+ else if (hc->hc_completed)
+ hc_free(hc);
+ else
+ hc->hc_callback = hc_default_cb;
+}
+
+/**@internal Free client request. */
+void hc_free(nth_client_t * hc)
+{
+ if (hc) {
+ if (hc->hc_pending)
+ tport_release(hc->hc_tport, hc->hc_pending, hc->hc_request, NULL, hc,
+ 0);
+ tport_decref(&hc->hc_tport);
+ msg_destroy(hc->hc_request);
+ msg_destroy(hc->hc_response);
+ su_free(hc->hc_engine->he_home, hc);
+ }
+}
+
+/**
+ * Gets client status.
+ *
+ * @param hc pointer to a nth client object
+ *
+ * @return
+ * Returns the status code from the response message if it has been
+ * received. A status code below 100 indicates that no response has been
+ * received. If request timeouts, the connection is closed and the status
+ * code is set to 408. If @a hc is NULL, returns 400 (Bad Request).
+ */
+int nth_client_status(nth_client_t const *hc)
+{
+ return hc ? hc->hc_status : 400;
+}
+
+/**
+ * Gets client method.
+ *
+ * @param hc pointer to a nth client object
+ *
+ * @return
+ * Returns the HTTP method from the request.
+ * If @a hc is NULL, returns #http_method_invalid.
+ */
+http_method_t nth_client_method(nth_client_t const *hc)
+{
+ return hc ? hc->hc_method : http_method_invalid;
+}
+
+/** Get original Request-URI */
+url_t const *nth_client_url(nth_client_t const *hc)
+{
+ return hc ? hc->hc_url : NULL;
+}
+
+/** Get request message. */
+msg_t *nth_client_request(nth_client_t * hc)
+{
+ msg_t *request = NULL;
+
+ if (hc)
+ request = hc->hc_request, hc->hc_request = NULL;
+
+ return request;
+}
+
+/** Get response message. */
+msg_t *nth_client_response(nth_client_t const *hc)
+{
+ if (hc)
+ return msg_ref_create(hc->hc_response);
+ else
+ return NULL;
+}
+
+/** Is client streaming response? */
+int nth_client_is_streaming(nth_client_t const *hc)
+{
+ return hc && hc->hc_is_streaming;
+}
+
+/** Send request. */
+static nth_client_t *hc_send(nth_client_t * hc)
+{
+ nth_engine_t *he = hc->hc_engine;
+ tport_t *tp;
+
+ he->he_stats->st_requests++;
+
+ tp = tport_tsend(hc->hc_tport, hc->hc_request, hc->hc_tpn,
+ TAG_NEXT(hc->hc_tags));
+
+ if (tp == NULL) {
+ he->he_stats->st_tp_errors++;
+ hc_reply(hc, HTTP_503_NO_SERVICE);
+ return hc;
+ }
+
+ hc->hc_tport = tport_incref(tp);
+
+ hc->hc_pending = tport_pend(tp, hc->hc_request, hc_tport_error, hc);
+ if (hc->hc_pending == -1)
+ hc->hc_pending = 0;
+
+ if (hc->hc_expires) {
+ hc->hc_timeout = he_now(he) + hc->hc_expires; /* XXX */
+ if (hc->hc_timeout == 0)
+ hc->hc_timeout++;
+ }
+
+ return hc;
+}
+
+/** @internal Report transport errors. */
+void hc_tport_error(nth_engine_t * he, nth_client_t * hc,
+ tport_t * tp, msg_t *msg, int error)
+{
+ su_sockaddr_t const *su = msg_addr(msg);
+ tp_name_t const *tpn = tp ? tport_name(tp) : hc->hc_tpn;
+ char addr[SU_ADDRSIZE];
+ char const *errmsg;
+
+ if (error)
+ errmsg = su_strerror(error);
+ else
+ errmsg = "Remote end closed connection";
+ su_log("nth: %s: %s (%u) with %s@%s:%u\n",
+ hc->hc_method_name,
+ errmsg, error,
+ tpn->tpn_proto,
+ inet_ntop(su->su_family, SU_ADDR(su), addr, sizeof(addr)),
+ htons(su->su_port));
+
+ he->he_stats->st_tp_errors++;
+ hc_reply(hc, HTTP_503_NO_SERVICE);
+}
+
+static
+void hc_delayed_recv(su_root_magic_t *rm, su_msg_r msg, union sm_arg_u *u);
+
+/** Respond internally to a transaction. */
+int hc_reply(nth_client_t * hc, int status, char const *phrase)
+{
+ nth_engine_t *he = hc->hc_engine;
+ msg_t *msg = NULL;
+ http_t *http = NULL;
+
+ assert(status >= 400);
+
+ SU_DEBUG_5(("nth: hc_reply(%p, %u, %s)\n", hc, status, phrase));
+
+ if (hc->hc_pending) {
+ tport_release(hc->hc_tport, hc->hc_pending, hc->hc_request, NULL, hc,
+ status < 200);
+ if (status >= 200)
+ hc->hc_pending = 0;
+ }
+
+ tport_shutdown(hc->hc_tport, 2);
+
+ hc->hc_completed = 1;
+ hc->hc_timeout = 0;
+
+ if (hc->hc_callback == hc_default_cb) {
+ hc_free(hc);
+ return 0;
+ }
+
+ /* Create response message, if needed */
+ if (hc->hc_error_msg) {
+ msg = he_msg_create(he, NTH_INTERNAL_MSG, NULL, 0, NULL, hc);
+ http = http_object(msg);
+ http_complete_response(msg, status, phrase, http_object(hc->hc_request));
+ } else
+ hc->hc_status = status;
+
+ if (hc->hc_inserted) {
+ hc_recv(hc, msg, http);
+ return 0;
+ } else {
+ /*
+ * The thread creating outgoing transaction must return to application
+ * before transaction callback can be invoked. Processing an internally
+ * generated response message must be delayed until transaction creation
+ * is completed.
+ *
+ * The internally generated message is transmitted using su_msg_send()
+ * and it is delivered back to NTA when the application next time
+ * executes the su_root_t event loop.
+ */
+ su_root_t *root = he->he_root;
+ su_msg_r su_msg = SU_MSG_R_INIT;
+
+ if (su_msg_create(su_msg,
+ su_root_task(root),
+ su_root_task(root),
+ hc_delayed_recv,
+ sizeof(struct hc_recv_s)) == SU_SUCCESS) {
+ struct hc_recv_s *a = su_msg_data(su_msg)->hc_recv;
+
+ a->hc = hc;
+ a->msg = msg;
+ a->http = http;
+
+ if (su_msg_send(su_msg) == SU_SUCCESS)
+ return 0;
+ }
+ }
+
+ if (msg)
+ msg_destroy(msg);
+
+ return -1;
+}
+
+static
+void hc_delayed_recv(su_root_magic_t *rm, su_msg_r msg, union sm_arg_u *u)
+{
+ struct hc_recv_s *a = u->hc_recv;
+
+ if (hc_recv(a->hc, a->msg, a->http) < 0 && a->msg)
+ msg_destroy(a->msg);
+}
+
+/** Receive response to transaction. */
+int hc_recv(nth_client_t * hc, msg_t *msg, http_t * http)
+{
+ short status;
+ int streaming = msg_is_streaming(msg);
+ int shutdown = 0;
+
+ if (http && http->http_status) {
+ status = http->http_status->st_status;
+ if (status < 100)
+ status = 100;
+
+ if (streaming && !hc->hc_streaming) {
+ /* Disable streaming for this msg */
+ msg_set_streaming(msg, 0);
+
+ return 0; /* Wait for complete message */
+ }
+
+ hc->hc_status = status;
+ } else if (http)
+ status = hc->hc_status = 500, streaming = 0, http = NULL;
+ else
+ status = hc->hc_status, streaming = 0;
+
+ if (status == 400 || (http && (http->http_flags & MSG_FLG_ERROR)))
+ shutdown = 2;
+
+ if (!streaming || shutdown)
+ msg_set_streaming(msg, 0);
+
+ if (hc->hc_pending) {
+ tport_release(hc->hc_tport, hc->hc_pending, hc->hc_request, msg, hc,
+ streaming || status < 200);
+ if (!streaming && status >= 200)
+ hc->hc_pending = 0;
+ }
+
+ if (!streaming && status >= 200) {
+ /* Completed. */
+ hc->hc_completed = 1;
+ hc_remove(hc->hc_engine, hc);
+
+ if (shutdown ||
+ !http ||
+ (http->http_status->st_version == http_version_1_1 &&
+ http->http_connection &&
+ msg_params_find(http->http_connection->k_items, "close")) ||
+ (http->http_status->st_version == http_version_1_0))
+ shutdown = 2;
+ }
+
+ if (shutdown) {
+ if (status < 200)
+ status = 400;
+ tport_shutdown(hc->hc_tport, shutdown);
+ }
+
+ if (msg_is_complete(msg)) {
+ if (status < 200)
+ hc->hc_engine->he_stats->st_1xxresponses++;
+ else
+ hc->hc_engine->he_stats->st_responses++;
+ }
+
+ if (hc->hc_response)
+ msg_destroy(hc->hc_response);
+ hc->hc_response = msg;
+ hc->hc_is_streaming = streaming;
+
+ /* Call callback */
+ hc->hc_callback(hc->hc_magic, hc, http);
+
+ return 0;
+}
+
+/** @internal Default callback for request */
+int hc_default_cb(nth_client_magic_t * magic,
+ nth_client_t * hc, http_t const *http)
+{
+ if (http == NULL || http->http_status->st_status >= 200)
+ hc_free(hc);
+ return 0;
+}
+
+/** @internal Client transaction timer routine. */
+static
+void hc_timer(nth_engine_t * he, nth_client_t * hc, uint32_t now)
+{
+ if (hc->hc_timeout == 0)
+ return;
+
+ if ((int)hc->hc_timeout - (int)now > 0)
+ return;
+
+ hc_reply(hc, HTTP_408_TIMEOUT);
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/nth_server.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/nth_server.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1328 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@file nth_server.c
+ * @brief HTTP server.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Sat Oct 19 01:37:36 2002 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <assert.h>
+
+#include <sofia-sip/string0.h>
+#include <sofia-sip/hostdomain.h>
+
+#if !defined(EALREADY) && defined(_WIN32)
+#define EALREADY WSAEALREADY
+#endif
+
+typedef struct server_s server_t;
+
+/** @internal SU timer argument pointer type */
+#define SU_TIMER_ARG_T server_t
+
+#include <sofia-sip/http_header.h>
+#include <sofia-sip/http_status.h>
+#include <sofia-sip/http_tag.h>
+
+#include "sofia-sip/nth.h"
+
+#include <sofia-sip/msg_date.h>
+#include <sofia-sip/msg_addr.h>
+#include <sofia-sip/su_tagarg.h>
+
+#include <sofia-sip/hostdomain.h>
+
+/* We are customer of tport_t */
+#define TP_STACK_T server_t
+#define TP_MAGIC_T void
+
+#include <sofia-sip/tport.h>
+#include <sofia-sip/htable.h>
+
+#include <sofia-sip/auth_module.h>
+
+#ifndef UINT32_MAX
+#define UINT32_MAX (0xffffffffU)
+#endif
+
+enum { SERVER_TICK = 1000 };
+
+#define SERVER_VERSION "nth/" NTH_VERSION
+
+HTABLE_DECLARE(hc_htable, hct, nth_client_t);
+
+struct server_s
+{
+ su_home_t srv_home[1];
+ su_root_t *srv_root;
+
+ su_timer_t *srv_timer;
+ unsigned srv_now;
+
+ msg_mclass_t const*srv_mclass;
+ int srv_mflags; /**< Message flags */
+
+ tport_t *srv_tports;
+ unsigned srv_queuesize; /**< Maximum number of queued responses */
+
+ size_t srv_max_bodylen; /**< Maximum accepted length */
+
+ unsigned srv_persistent:1; /**< Allow persistent connections */
+
+ /** Sites */
+ nth_site_t *srv_sites;
+
+ /* Statistics */
+ struct {
+ uint32_t st_requests; /**< Received requests */
+ uint32_t st_responses; /**< Sent responses */
+ uint32_t st_bad; /**< Bad requests */
+ } srv_stats[1];
+
+ http_server_t *srv_server; /**< Server header */
+};
+
+struct nth_site_s
+{
+ nth_site_t *site_next, **site_prev;
+
+ nth_site_t *site_kids;
+
+ server_t *site_server;
+ auth_mod_t *site_auth;
+
+ url_t *site_url;
+ char const *site_path;
+ size_t site_path_len;
+
+ nth_request_f *site_callback;
+ nth_site_magic_t *site_magic;
+
+ su_time_t site_access; /**< Last request served */
+
+ /** Host header must match with server name */
+ unsigned site_strict : 1;
+ /** Site can have kids */
+ unsigned site_isdir : 1;
+ /** Site does not have domain name */
+ unsigned site_wildcard : 1;
+};
+
+struct nth_request_s
+{
+ server_t *req_server;
+
+ http_method_t req_method;
+ char const *req_method_name;
+ url_t const *req_url; /**< RequestURI */
+ char const *req_version;
+
+ tport_t *req_tport;
+ msg_t *req_request;
+ msg_t *req_response;
+
+ auth_status_t *req_as;
+
+ unsigned short req_status;
+ unsigned req_close : 1; /**< Client asked for close */
+ unsigned req_in_callback : 1;
+ unsigned req_destroyed : 1;
+};
+
+/* ====================================================================== */
+/* Debug log settings */
+
+#define SU_LOG nth_server_log
+
+#ifdef SU_DEBUG_H
+#error <su_debug.h> included directly.
+#endif
+#include <sofia-sip/su_debug.h>
+
+/**Environment variable determining the debug log level for @b nth
+ * module.
+ *
+ * The NTH_DEBUG environment variable is used to determine the debug
+ * logging level for @b nth module. The default level is 1.
+ *
+ * @sa <su_debug.h>, nth_server_log, SOFIA_DEBUG
+ */
+extern char const NTH_DEBUG[];
+
+#ifndef SU_DEBUG
+#define SU_DEBUG 1
+#endif
+
+/**Debug log for @b nth module.
+ *
+ * The nth_server_log is the log object used by @b nth module. The level of
+ * #nth_server_log is set using #NTH_DEBUG environment variable.
+ */
+su_log_t nth_server_log[] = { SU_LOG_INIT("nth", "NTH_DEBUG", SU_DEBUG) };
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+static char const __func__[] = "nth";
+#endif
+
+/* ====================================================================== */
+/** Server side
+ */
+static server_t *server_create(url_t const *url,
+ tag_type_t tag, tag_value_t value, ...);
+void server_destroy(server_t *srv);
+static inline int server_timer_init(server_t *srv);
+static void server_timer(su_root_magic_t *rm, su_timer_t *timer, server_t *srv);
+static inline uint32_t server_now(server_t const *srv);
+static void server_request(server_t *srv, tport_t *tport, msg_t *msg,
+ void *arg, su_time_t now);
+static nth_site_t **site_get_host(nth_site_t **, char const *host, char const *port);
+static nth_site_t **site_get_rslot(nth_site_t *parent, char *path,
+ char **return_rest);
+static nth_site_t *site_get_subdir(nth_site_t *parent, char const *path, char const **res);
+static void server_tport_error(server_t *srv, tport_t *tport,
+ int errcode, char const *remote);
+static msg_t *server_msg_create(server_t *srv, int flags,
+ char const data[], usize_t dlen,
+ tport_t const *tp, tp_client_t *tpc);
+
+static void server_reply(server_t *srv, tport_t *tport,
+ msg_t *request, msg_t *response,
+ int status, char const *phrase);
+
+static
+void nth_site_request(server_t *srv,
+ nth_site_t *site,
+ tport_t *tport,
+ msg_t *request,
+ http_t *http,
+ char const *path,
+ msg_t *response);
+
+/* ----------------------------------------------------------------------
+ * 5) Site functions
+ */
+
+/** Create a http site object.
+ *
+ * The function nth_site_create() allocates and initializes a web site
+ * object. A web site object can be either
+ * - a primary http server (@a parent is NULL),
+ * - a virtual http server (@a address contains hostpart), or
+ * - a site within a server
+ * (@a address does not have hostpart, only path part).
+ *
+ * @param parent pointer to parent site
+ * (NULL when creating a primary server object)
+ * @param callback pointer to callback function called when
+ * a request is received
+ * @param magic application context included in callback parameters
+ * @param address absolute or relative URI specifying the address of
+ * site
+ * @param tag, value, ... list of tagged parameters
+ *
+ * @TAGS
+ * If the @a parent is NULL, the list of tagged parameters must contain
+ * NTHTAG_ROOT() used to create the server engine. Tags supported when @a
+ * parent is NULL are NTHTAG_ROOT(), NTHTAG_MCLASS(), TPTAG_REUSE(),
+ * HTTPTAG_SERVER(), and HTTPTAG_SERVER_STR(). All the tags are passed to
+ * tport_tcreate() and tport_tbind(), too.
+ *
+ * @since Support for multiple sites was added to @VERSION_1_12_4
+ */
+nth_site_t *nth_site_create(nth_site_t *parent,
+ nth_request_f *callback,
+ nth_site_magic_t *magic,
+ url_string_t const *address,
+ tag_type_t tag, tag_value_t value,
+ ...)
+{
+ nth_site_t *site = NULL, **prev = NULL;
+ su_home_t home[SU_HOME_AUTO_SIZE(256)];
+ url_t *url, url0[1];
+ server_t *srv = NULL;
+ ta_list ta;
+ char *path = NULL;
+ size_t usize;
+ int is_host, is_path, wildcard = 0;
+
+ su_home_auto(home, sizeof home);
+
+ if (parent && url_is_string(address)) {
+ char const *s = (char const *)address;
+ size_t sep = strcspn(s, "/:");
+
+ if (parent->site_path) {
+ /* subpath */
+ url_init(url0, parent->site_url->url_type);
+ url0->url_path = s;
+ address = (url_string_t*)url0;
+ }
+ else if (s[sep] == ':')
+ /* absolute URL with scheme */;
+ else if (s[sep] == '\0' && strchr(s, '.') && host_is_valid(s)) {
+ /* looks like a domain name */;
+ url_init(url0, parent->site_url->url_type);
+ url0->url_host = s;
+ address = (url_string_t*)url0;
+ }
+ else {
+ /* looks like a path */
+ url_init(url0, parent->site_url->url_type);
+ url0->url_path = s;
+ address = (url_string_t*)url0;
+ }
+ }
+
+ url = url_hdup(home, address->us_url);
+
+ if (!url || !callback)
+ return NULL;
+
+ is_host = url->url_host != NULL;
+ is_path = url->url_path != NULL;
+
+ if (is_host && is_path) {
+ SU_DEBUG_3(("nth_site_create(): virtual host and path simultanously\n"));
+ errno = EINVAL;
+ goto error;
+ }
+
+ if (!parent && !is_host) {
+ SU_DEBUG_3(("nth_site_create(): host is required\n"));
+ errno = EINVAL;
+ goto error;
+ }
+
+ if (parent) {
+ if (!parent->site_isdir) {
+ SU_DEBUG_3(("nth_site_create(): invalid parent resource \n"));
+ errno = EINVAL;
+ goto error;
+ }
+
+ srv = parent->site_server; assert(srv);
+ if (is_host) {
+ prev = site_get_host(&srv->srv_sites, url->url_host, url->url_port);
+
+ if (prev == NULL) {
+ SU_DEBUG_3(("nth_site_create(): host %s:%s already exists\n",
+ url->url_host, url->url_port ? url->url_port : ""));
+ errno = EEXIST;
+ goto error;
+ }
+ }
+ else {
+ size_t i, j;
+
+ path = (char *)url->url_path;
+ while (path[0] == '/')
+ path++;
+
+ /* Remove duplicate // */
+ for (i = j = 0; path[i];) {
+ while (path[i] == '/' && path[i + 1] == '/')
+ i++;
+ path[j++] = path[i++];
+ }
+ path[j] = path[i];
+
+ url = url0, *url = *parent->site_url;
+
+ if (url->url_path) {
+ url->url_path = su_strcat(home, url->url_path, path);
+ if (!url->url_path)
+ goto error;
+ path = (char *)url->url_path + strlen(parent->site_url->url_path);
+ }
+ else
+ url->url_path = path;
+
+ prev = site_get_rslot(parent, path, &path);
+
+ if (!prev || path[0] == '\0') {
+ SU_DEBUG_3(("nth_site_create(): directory \"%s\" already exists\n",
+ url->url_path));
+ errno = EEXIST;
+ goto error;
+ }
+ }
+ }
+
+ if (!parent) {
+ if (strcmp(url->url_host, "*") == 0 ||
+ host_cmp(url->url_host, "0.0.0.0") == 0 ||
+ host_cmp(url->url_host, "::") == 0)
+ wildcard = 1, url->url_host = "*";
+ }
+
+ usize = sizeof(*url) + url_xtra(url);
+
+ ta_start(ta, tag, value);
+
+ if (!parent) {
+ srv = server_create(url, ta_tags(ta));
+ prev = &srv->srv_sites;
+ }
+
+ if (srv && (site = su_zalloc(srv->srv_home, (sizeof *site) + usize))) {
+ site->site_url = (url_t *)(site + 1);
+ url_dup((void *)(site->site_url + 1), usize - sizeof(*url),
+ site->site_url, url);
+
+ assert(prev);
+ if ((site->site_next = *prev))
+ site->site_next->site_prev = &site->site_next;
+ *prev = site, site->site_prev = prev;
+ site->site_server = srv;
+
+ if (path) {
+ size_t path_len;
+
+ site->site_path = site->site_url->url_path + (path - url->url_path);
+ path_len = strlen(site->site_path); assert(path_len > 0);
+ if (path_len > 0 && site->site_path[path_len - 1] == '/')
+ path_len--, site->site_isdir = 1;
+ site->site_path_len = path_len;
+ }
+ else {
+ site->site_isdir = is_host;
+ site->site_path = "";
+ site->site_path_len = 0;
+ }
+
+ site->site_wildcard = wildcard;
+ site->site_callback = callback;
+ site->site_magic = magic;
+
+ if (parent)
+ site->site_auth = parent->site_auth;
+
+ nth_site_set_params(site, ta_tags(ta));
+ }
+
+ ta_end(ta);
+
+ error:
+ su_home_deinit(home);
+ return site;
+}
+
+void nth_site_destroy(nth_site_t *site)
+{
+ if (site == NULL)
+ return;
+
+ if (site->site_auth)
+ auth_mod_unref(site->site_auth), site->site_auth = NULL;
+
+ if (site->site_server->srv_sites == site) {
+ server_destroy(site->site_server);
+ }
+}
+
+
+nth_site_magic_t *nth_site_magic(nth_site_t const *site)
+{
+ return site ? site->site_magic : NULL;
+}
+
+
+void nth_site_bind(nth_site_t *site,
+ nth_request_f *callback,
+ nth_site_magic_t *magic)
+{
+ if (site) {
+ site->site_callback = callback;
+ site->site_magic = magic;
+ }
+}
+
+
+/** Get the site URL. @NEW_1_12_4. */
+url_t const *nth_site_url(nth_site_t const *site)
+{
+ return site ? site->site_url : NULL;
+}
+
+/** Return server name and version */
+char const *nth_site_server_version(void)
+{
+ return "nth/" NTH_VERSION;
+}
+
+/** Get the time last time served. @NEW_1_12_4. */
+su_time_t nth_site_access_time(nth_site_t const *site)
+{
+ su_time_t const never = { 0, 0 };
+
+ return site ? site->site_access : never;
+}
+
+int nth_site_set_params(nth_site_t *site,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ int n;
+ ta_list ta;
+
+ server_t *server;
+ int master;
+ msg_mclass_t const *mclass;
+ int mflags;
+ auth_mod_t *am;
+
+ if (site == NULL)
+ return (errno = EINVAL), -1;
+
+ server = site->site_server;
+ master = site == server->srv_sites;
+ am = site->site_auth;
+
+ mclass = server->srv_mclass;
+ mflags = server->srv_mflags;
+
+ ta_start(ta, tag, value);
+
+ n = tl_gets(ta_args(ta),
+ TAG_IF(master, NTHTAG_MCLASS_REF(mclass)),
+ TAG_IF(master, NTHTAG_MFLAGS_REF(mflags)),
+ NTHTAG_AUTH_MODULE_REF(am),
+ TAG_END());
+
+ if (n > 0) {
+ if (mclass)
+ server->srv_mclass = mclass;
+ else
+ server->srv_mclass = http_default_mclass();
+ server->srv_mflags = mflags;
+ auth_mod_ref(am), auth_mod_unref(site->site_auth), site->site_auth = am;
+ }
+
+ ta_end(ta);
+
+ return n;
+}
+
+int nth_site_get_params(nth_site_t const *site,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ int n;
+ ta_list ta;
+ server_t *server;
+ int master;
+ msg_mclass_t const *mclass;
+
+ if (site == NULL)
+ return (errno = EINVAL), -1;
+
+ server = site->site_server;
+ master = site == server->srv_sites;
+
+ if (master && server->srv_mclass != http_default_mclass())
+ mclass = server->srv_mclass;
+ else
+ mclass = NULL;
+
+ ta_start(ta, tag, value);
+
+ n = tl_tgets(ta_args(ta),
+ TAG_IF(master, NTHTAG_MCLASS(mclass)),
+ TAG_IF(master, NTHTAG_MFLAGS(server->srv_mflags)),
+ TAG_END());
+
+ ta_end(ta);
+
+ return n;
+}
+
+int nth_site_get_stats(nth_site_t const *site,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ int n;
+ ta_list ta;
+
+ if (site == NULL)
+ return (errno = EINVAL), -1;
+
+ ta_start(ta, tag, value);
+
+ n = tl_tgets(ta_args(ta),
+ TAG_END());
+
+ ta_end(ta);
+
+ return n;
+}
+
+static
+nth_site_t **site_get_host(nth_site_t **list, char const *host, char const *port)
+{
+ nth_site_t *site;
+
+ assert(host);
+
+ for (; (site = *list); list = &site->site_next) {
+ if (host_cmp(host, site->site_url->url_host) == 0 &&
+ str0cmp(port, site->site_url->url_port) == 0) {
+ break;
+ }
+ }
+
+ return list;
+}
+
+/** Find a place to insert site from the hierarchy.
+ *
+ * A resource can be either a 'dir' (name ends with '/') or 'file'.
+ * When a resource
+ */
+static
+nth_site_t **site_get_rslot(nth_site_t *parent, char *path,
+ char **return_rest)
+{
+ nth_site_t *site, **prev;
+ size_t len;
+ int cmp;
+
+ assert(path);
+
+ if (path[0] == '\0')
+ return errno = EEXIST, NULL;
+
+ for (prev = &parent->site_kids; (site = *prev); prev = &site->site_next) {
+ cmp = strncmp(path, site->site_path, len = site->site_path_len);
+ if (cmp > 0)
+ break;
+ if (cmp < 0)
+ continue;
+ if (path[len] == '\0') {
+ if (site->site_isdir)
+ return *return_rest = path, prev;
+ return errno = EEXIST, NULL;
+ }
+ if (path[len] != '/' || site->site_path[len] != '/')
+ continue;
+
+ while (path[++len] == '/')
+ ;
+
+ return site_get_rslot(site, path + len, return_rest);
+ }
+
+ *return_rest = path;
+
+ return prev;
+}
+
+static char const site_nodir_match[] = "";
+
+/** Find a subdir from site hierarchy */
+static
+nth_site_t *site_get_subdir(nth_site_t *parent,
+ char const *path,
+ char const **return_rest)
+{
+ nth_site_t *site;
+ size_t len;
+ int cmp;
+
+ assert(path);
+
+ while (path[0] == '/') /* Skip multiple slashes */
+ path++;
+
+ if (path[0] == '\0')
+ return *return_rest = path, parent;
+
+ for (site = parent->site_kids; site; site = site->site_next) {
+ cmp = strncmp(path, site->site_path, len = site->site_path_len);
+ if (cmp > 0)
+ break;
+ if (cmp < 0)
+ continue;
+ if (path[len] == '\0')
+ return *return_rest = site_nodir_match, site;
+ if (site->site_path[len] == '/' && path[len] == '/')
+ return site_get_subdir(site, path + len + 1, return_rest);
+ }
+
+ return *return_rest = path, parent;
+}
+
+
+/* ----------------------------------------------------------------------
+ * Server functions
+ */
+
+static char const * const http_tports[] =
+ {
+ "tcp", "tls", NULL
+ };
+
+static tp_stack_class_t nth_server_class[1] =
+ {{
+ sizeof(nth_server_class),
+ server_request,
+ server_tport_error,
+ server_msg_create
+ }};
+
+server_t *server_create(url_t const *url,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ server_t *srv;
+ msg_mclass_t *mclass = NULL;
+ tp_name_t tpn[1] = {{ NULL }};
+ su_root_t *root = NULL;
+ http_server_t const *server = NULL;
+ int persistent = 0;
+ char const *server_str = SERVER_VERSION;
+ ta_list ta;
+
+ ta_start(ta, tag, value);
+ tl_gets(ta_args(ta),
+ NTHTAG_ROOT_REF(root),
+ NTHTAG_MCLASS_REF(mclass),
+ TPTAG_REUSE_REF(persistent),
+ HTTPTAG_SERVER_REF(server),
+ HTTPTAG_SERVER_STR_REF(server_str),
+ TAG_END());
+
+ if (!root || !url ||
+ (url->url_type != url_http && url->url_type != url_https)
+ || !(srv = su_home_new(sizeof(*srv)))) {
+ ta_end(ta);
+ return NULL;
+ }
+
+ tpn->tpn_proto = url_tport_default(url->url_type);
+ tpn->tpn_canon = url->url_host;
+ tpn->tpn_host = url->url_host;
+ tpn->tpn_port = url_port(url);
+
+ srv->srv_tports = tport_tcreate(srv, nth_server_class, root,
+ TPTAG_IDLE(600000),
+ TPTAG_TIMEOUT(300000),
+ ta_tags(ta));
+
+ srv->srv_persistent = persistent;
+ srv->srv_max_bodylen = 1 << 30; /* 1 GB */
+
+ if (tport_tbind(srv->srv_tports, tpn, http_tports,
+ TAG_END()) >= 0) {
+ srv->srv_root = root;
+ srv->srv_mclass = mclass ? mclass : http_default_mclass();
+ srv->srv_mflags = MSG_DO_CANONIC;
+
+ if (server)
+ srv->srv_server = http_server_dup(srv->srv_home, server);
+ else
+ srv->srv_server = http_server_make(srv->srv_home, server_str);
+
+ tport_get_params(srv->srv_tports,
+ TPTAG_QUEUESIZE_REF(srv->srv_queuesize),
+ TAG_END());
+ }
+ else {
+ SU_DEBUG_1(("nth_server_create: cannot bind transports "
+ URL_FORMAT_STRING "\n",
+ URL_PRINT_ARGS(url)));
+ server_destroy(srv), srv = NULL;
+ }
+
+ ta_end(ta);
+
+ return srv;
+}
+
+void server_destroy(server_t *srv)
+{
+ tport_destroy(srv->srv_tports);
+ su_timer_destroy(srv->srv_timer);
+ su_home_unref(srv->srv_home);
+}
+
+/** Initialize server timer. */
+static inline
+int server_timer_init(server_t *srv)
+{
+ if (0) {
+ srv->srv_timer = su_timer_create(su_root_task(srv->srv_root), SERVER_TICK);
+ return su_timer_set(srv->srv_timer, server_timer, srv);
+ }
+ return 0;
+}
+
+/**
+ * Server timer routine.
+ */
+static
+void server_timer(su_root_magic_t *rm, su_timer_t *timer, server_t *srv)
+{
+ uint32_t now;
+
+ su_timer_set(timer, server_timer, srv);
+
+ now = su_time_ms(su_now()); now += now == 0; srv->srv_now = now;
+
+ /* Xyzzy */
+
+ srv->srv_now = 0;
+}
+
+/** Get current timestamp in milliseconds */
+static inline
+uint32_t server_now(server_t const *srv)
+{
+ if (srv->srv_now)
+ return srv->srv_now;
+ else
+ return su_time_ms(su_now());
+}
+
+/** Process incoming request message */
+static
+void server_request(server_t *srv,
+ tport_t *tport,
+ msg_t *request,
+ void *arg,
+ su_time_t now)
+{
+ nth_site_t *site = NULL, *subsite = NULL;
+ msg_t *response;
+ http_t *http = http_object(request);
+ http_host_t *h;
+ char const *host, *port, *path, *subpath = NULL;
+
+ /* Disable streaming */
+ if (msg_is_streaming(request)) {
+ msg_set_streaming(request, 0);
+ return;
+ }
+
+ /* Create a response message */
+ response = server_msg_create(srv, 0, NULL, 0, NULL, NULL);
+ tport_tqueue(tport, response, TAG_END());
+
+ if (http && http->http_flags & MSG_FLG_TIMEOUT) {
+ server_reply(srv, tport, request, response, 400, "Request timeout");
+ return;
+ } else if (http && http->http_flags & MSG_FLG_TOOLARGE) {
+ server_reply(srv, tport, request, response, HTTP_413_ENTITY_TOO_LARGE);
+ return;
+ } else if (!http || !http->http_request ||
+ (http->http_flags & MSG_FLG_ERROR)) {
+ server_reply(srv, tport, request, response, HTTP_400_BAD_REQUEST);
+ return;
+ }
+
+ if (http->http_request->rq_version != http_version_1_0 &&
+ http->http_request->rq_version != http_version_1_1) {
+ server_reply(srv, tport, request, response, HTTP_505_HTTP_VERSION);
+ return;
+ }
+
+ h = http->http_host;
+
+ if (h) {
+ host = h->h_host, port = h->h_port;
+ }
+ else if (http->http_request->rq_url->url_host) {
+ host = http->http_request->rq_url->url_host;
+ port = http->http_request->rq_url->url_port;
+ }
+ else
+ host = NULL, port = NULL;
+
+ path = http->http_request->rq_url->url_path;
+
+ if (host)
+ site = *site_get_host(&srv->srv_sites, host, port);
+
+ if (site == NULL && !srv->srv_sites->site_strict)
+ site = srv->srv_sites;
+
+ if (path == NULL)
+ path = "";
+
+ if (path[0])
+ subsite = site_get_subdir(site, path, &subpath);
+
+ if (subsite)
+ subsite->site_access = now;
+ else
+ site->site_access = now;
+
+ if (subsite && subsite->site_isdir && subpath == site_nodir_match) {
+ /* Answer with 301 */
+ http_location_t loc[1];
+ http_location_init(loc);
+
+ *loc->loc_url = *site->site_url;
+
+ if (site->site_wildcard) {
+ if (http->http_host) {
+ loc->loc_url->url_host = http->http_host->h_host;
+ loc->loc_url->url_port = http->http_host->h_port;
+ }
+ else {
+ tp_name_t const *tpn = tport_name(tport); assert(tpn);
+ loc->loc_url->url_host = tpn->tpn_canon;
+ if (strcmp(url_port_default(loc->loc_url->url_type), tpn->tpn_port))
+ loc->loc_url->url_port = tpn->tpn_port;
+ }
+ }
+
+ loc->loc_url->url_root = 1;
+ loc->loc_url->url_path = subsite->site_url->url_path;
+
+ msg_header_add_dup(response, NULL, (msg_header_t *)loc);
+
+ server_reply(srv, tport, request, response, HTTP_301_MOVED_PERMANENTLY);
+ }
+ else if (subsite)
+ nth_site_request(srv, subsite, tport, request, http, subpath, response);
+ else if (site)
+ nth_site_request(srv, site, tport, request, http, path, response);
+ else
+ /* Answer with 404 */
+ server_reply(srv, tport, request, response, HTTP_404_NOT_FOUND);
+}
+
+static void server_tport_error(server_t *srv,
+ tport_t *tport,
+ int errcode,
+ char const *remote)
+{
+ su_log("\nth: tport: %s%s%s\n",
+ remote ? remote : "", remote ? ": " : "",
+ su_strerror(errcode));
+}
+
+/** Respond without creating a request structure */
+static void server_reply(server_t *srv, tport_t *tport,
+ msg_t *request, msg_t *response,
+ int status, char const *phrase)
+{
+ http_t *http;
+ http_payload_t *pl;
+ int close;
+ http_status_t st[1];
+ char const *req_version = NULL;
+
+ if (status < 200 || status >= 600)
+ status = 500, phrase = http_500_internal_server;
+
+ http = http_object(request);
+
+ if (http && http->http_request)
+ req_version = http->http_request->rq_version;
+
+ close = status >= 200 &&
+ (!srv->srv_persistent
+ || status == 400
+ || (http && http->http_request &&
+ http->http_request->rq_version != http_version_1_1)
+ || (http && http->http_connection &&
+ msg_params_find(http->http_connection->k_items, "close")));
+
+ msg_destroy(request);
+
+ http = http_object(response);
+
+ pl = http_payload_format(msg_home(response),
+ "<html>\n"
+ "<head><title>%u %s</title></head>\n"
+ "<body><h2>%u %s</h2></body>\n"
+ "</html>\n", status, phrase, status, phrase);
+
+ msg_header_insert(response, (msg_pub_t *)http, (msg_header_t *)pl);
+
+ if (req_version != http_version_0_9) {
+ http_status_init(st);
+ st->st_version = http_version_1_1;
+ st->st_status = status;
+ st->st_phrase = phrase;
+
+ http_add_tl(response, http,
+ HTTPTAG_STATUS(st),
+ HTTPTAG_SERVER(srv->srv_server),
+ HTTPTAG_CONTENT_TYPE_STR("text/html"),
+ HTTPTAG_SEPARATOR_STR("\r\n"),
+ TAG_IF(close, HTTPTAG_CONNECTION_STR("close")),
+ TAG_END());
+
+ msg_serialize(response, (msg_pub_t *)http);
+ } else {
+ /* Just send the response */
+ *msg_chain_head(response) = (msg_header_t *)pl;
+ close = 1;
+ }
+
+ if (tport_tqsend(tport, response, NULL,
+ TPTAG_CLOSE_AFTER(close),
+ TAG_END()) == -1) {
+ SU_DEBUG_3(("server_reply(): cannot queue response\n"));
+ tport_shutdown(tport, 2);
+ }
+
+ msg_destroy(response);
+}
+
+/** Create a new message for transport */
+static
+msg_t *server_msg_create(server_t *srv, int flags,
+ char const data[], usize_t dlen,
+ tport_t const *tp, tp_client_t *tpc)
+{
+ msg_t *msg = msg_create(srv->srv_mclass, srv->srv_mflags | flags);
+
+ return msg;
+}
+
+/* ----------------------------------------------------------------------
+ * 6) Server transactions
+ */
+
+struct auth_info
+{
+ nth_site_t *site;
+ nth_request_t *req;
+ http_t const *http;
+ char const *path;
+};
+
+static void nth_authentication_result(void *ai0, auth_status_t *as);
+
+static
+void nth_site_request(server_t *srv,
+ nth_site_t *site,
+ tport_t *tport,
+ msg_t *request,
+ http_t *http,
+ char const *path,
+ msg_t *response)
+{
+ auth_mod_t *am = site->site_auth;
+ nth_request_t *req;
+ auth_status_t *as;
+ struct auth_info *ai;
+ size_t size = (am ? (sizeof *as) + (sizeof *ai) : 0) + (sizeof *req);
+ int status;
+
+ req = su_zalloc(srv->srv_home, size);
+
+ if (req == NULL) {
+ server_reply(srv, tport, request, response, HTTP_500_INTERNAL_SERVER);
+ return;
+ }
+
+ if (am)
+ as = auth_status_init(req + 1, sizeof *as), ai = (void *)(as + 1);
+ else
+ as = NULL, ai = NULL;
+
+ req->req_server = srv;
+ req->req_method = http->http_request->rq_method;
+ req->req_method_name = http->http_request->rq_method_name;
+ req->req_url = http->http_request->rq_url;
+ req->req_version = http->http_request->rq_version;
+
+ req->req_tport = tport_incref(tport);
+ req->req_request = request;
+ req->req_response = response;
+
+ req->req_status = 100;
+ req->req_close =
+ !srv->srv_persistent
+ || http->http_request->rq_version != http_version_1_1
+ || (http->http_connection &&
+ msg_params_find(http->http_connection->k_items, "close"));
+
+ if (am) {
+ static auth_challenger_t const http_server_challenger[] =
+ {{ HTTP_401_UNAUTHORIZED, http_www_authenticate_class }};
+
+ req->req_as = as;
+
+ as->as_method = http->http_request->rq_method_name;
+ as->as_uri = path;
+
+ if (http->http_payload) {
+ as->as_body = http->http_payload->pl_data;
+ as->as_bodylen = http->http_payload->pl_len;
+ }
+
+ auth_mod_check_client(am, as,
+ http->http_authorization,
+ http_server_challenger);
+
+ if (as->as_status == 100) {
+ /* Stall transport - do not read more requests */
+ if (tport_queuelen(tport) * 2 >= srv->srv_queuesize)
+ tport_stall(tport);
+
+ as->as_callback = nth_authentication_result;
+ as->as_magic = ai;
+ ai->site = site;
+ ai->req = req;
+ ai->http = http;
+ ai->path = path;
+ return;
+ }
+ else if (as->as_status) {
+ assert(as->as_status >= 200);
+ nth_request_treply(req, as->as_status, as->as_phrase,
+ HTTPTAG_HEADER((http_header_t *)as->as_response),
+ HTTPTAG_HEADER((http_header_t *)as->as_info),
+ TAG_END());
+ nth_request_destroy(req);
+ return;
+ }
+ }
+
+ req->req_in_callback = 1;
+ status = site->site_callback(site->site_magic, site, req, http, path);
+ req->req_in_callback = 0;
+
+ if (status != 0 && (status < 100 || status >= 600))
+ status = 500;
+
+ if (status != 0 && req->req_status < 200) {
+ nth_request_treply(req, status, NULL, TAG_END());
+ }
+
+ if (req->req_status < 100) {
+ /* Stall transport - do not read more requests */
+ if (tport_queuelen(tport) * 2 >= srv->srv_queuesize)
+ tport_stall(tport);
+ }
+
+ if (status >= 200 || req->req_destroyed)
+ nth_request_destroy(req);
+}
+
+static void nth_authentication_result(void *ai0, auth_status_t *as)
+{
+ struct auth_info *ai = ai0;
+ nth_request_t *req = ai->req;
+ int status;
+
+ if (as->as_status != 0) {
+ assert(as->as_status >= 300);
+ nth_request_treply(req, status = as->as_status, as->as_phrase,
+ HTTPTAG_HEADER((http_header_t *)as->as_response),
+ TAG_END());
+ }
+ else {
+ req->req_in_callback = 1;
+ status = ai->site->site_callback(ai->site->site_magic,
+ ai->site,
+ ai->req,
+ ai->http,
+ ai->path);
+ req->req_in_callback = 0;
+
+ if (status != 0 && (status < 100 || status >= 600))
+ status = 500;
+
+ if (status != 0 && req->req_status < 200) {
+ nth_request_treply(req, status, NULL, TAG_END());
+ }
+ }
+
+ if (status >= 200 || req->req_destroyed)
+ nth_request_destroy(req);
+}
+
+void nth_request_destroy(nth_request_t *req)
+{
+ if (req == NULL)
+ return;
+
+ if (req->req_status < 200)
+ nth_request_treply(req, HTTP_500_INTERNAL_SERVER, TAG_END());
+
+ req->req_destroyed = 1;
+
+ if (req->req_in_callback)
+ return;
+
+ if (req->req_as)
+ su_home_deinit(req->req_as->as_home);
+
+ tport_decref(&req->req_tport), req->req_tport = NULL;
+ msg_destroy(req->req_request), req->req_request = NULL;
+ msg_destroy(req->req_response), req->req_response = NULL;
+ su_free(req->req_server->srv_home, req);
+}
+
+/** Return request authentication status.
+ *
+ * @param req pointer to HTTP request object
+ *
+ * @retval Status code
+ *
+ * @since New in @VERSION_1_12_4
+ */
+int nth_request_status(nth_request_t const *req)
+{
+ return req ? req->req_status : 400;
+}
+
+/** Return request authentication status.
+ *
+ * @param req pointer to HTTP request object
+ *
+ * @retval Pointer to authentication status struct
+ *
+ * @note The authentication status struct is freed when the #nth_request_t
+ * object is destroyed.
+ *
+ * @since New in @VERSION_1_12_4
+ *
+ * @sa AUTH
+ */
+auth_status_t *nth_request_auth(nth_request_t const *req)
+{
+ return req ? req->req_as : NULL;
+}
+
+http_method_t nth_request_method(nth_request_t const *req)
+{
+ return req ? req->req_method : http_method_invalid;
+}
+
+msg_t *nth_request_message(nth_request_t *req)
+{
+ msg_t *retval = NULL;
+
+ if (req)
+ retval = msg_ref_create(req->req_request);
+
+ return retval;
+}
+
+int nth_request_treply(nth_request_t *req,
+ int status, char const *phrase,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ msg_t *response, *next = NULL;
+ http_t *http;
+ int retval = -1;
+ int req_close, close;
+ ta_list ta;
+ http_header_t const *as_info = NULL;
+
+ if (req == NULL || status < 100 || status >= 600) {
+ return -1;
+ }
+
+ response = req->req_response;
+ http = http_object(response);
+
+ if (status >= 200 && req->req_as)
+ as_info = (http_header_t const *)req->req_as->as_info;
+
+ ta_start(ta, tag, value);
+
+ http_add_tl(response, http,
+ HTTPTAG_SERVER(req->req_server->srv_server),
+ HTTPTAG_HEADER(as_info),
+ ta_tags(ta));
+
+ if (http->http_payload && !http->http_content_length) {
+ http_content_length_t *l;
+ http_payload_t *pl;
+ size_t len = 0;
+
+ for (pl = http->http_payload; pl; pl = pl->pl_next)
+ len += pl->pl_len;
+
+ if (len > UINT32_MAX)
+ goto fail;
+
+ l = http_content_length_create(msg_home(response), (uint32_t)len);
+
+ msg_header_insert(response, (msg_pub_t *)http, (msg_header_t *)l);
+ }
+
+ if (req->req_method == http_method_head && http->http_payload) {
+ http_payload_t *pl;
+
+ for (pl = http->http_payload; pl; pl = pl->pl_next)
+ msg_header_remove(response, (msg_pub_t *)http, (msg_header_t *)pl);
+ }
+
+ http_complete_response(response, status, phrase,
+ http_object(req->req_request));
+
+ if (!http->http_date) {
+ http_date_t date[1];
+ http_date_init(date)->d_time = msg_now();
+ msg_header_add_dup(response, (msg_pub_t *)http, (msg_header_t*)date);
+ }
+
+ if (status < 200) {
+ close = 0;
+ next = server_msg_create(req->req_server, 0, NULL, 0, NULL, NULL);
+ }
+ else {
+ req_close = req->req_close;
+
+ close = (http->http_connection &&
+ msg_params_find(http->http_connection->k_items, "close"));
+
+ if (req_close && !close && status >= 200) {
+ close = 1;
+ http_add_tl(response, http, HTTPTAG_CONNECTION_STR("close"), TAG_END());
+ }
+ }
+
+ msg_serialize(response, (msg_pub_t *)http);
+
+ retval = tport_tqsend(req->req_tport, response, next,
+ TAG_IF(close, TPTAG_CLOSE_AFTER(1)),
+ ta_tags(ta));
+
+ fail:
+ ta_end(ta);
+
+ if (retval == 0)
+ req->req_status = status;
+
+ return retval;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/nth_tag.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/nth_tag.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,82 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nth_tag.c
+ * @brief Tags for HTTP Transaction API
+ *
+ * @note This file is used to automatically generate
+ * nth_tag_ref.c and nth_tag_dll.c
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Jul 24 22:28:34 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <assert.h>
+
+#define TAG_NAMESPACE "nth"
+
+#include "sofia-sip/nth_tag.h"
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/http_tag_class.h>
+#include <sofia-sip/url_tag_class.h>
+
+#include <sofia-sip/http_protos.h>
+
+tag_typedef_t nthtag_any = NSTAG_TYPEDEF(*);
+
+/* Common */
+tag_typedef_t nthtag_mclass = PTRTAG_TYPEDEF(mclass);
+tag_typedef_t nthtag_message = PTRTAG_TYPEDEF(message);
+tag_typedef_t nthtag_mflags = INTTAG_TYPEDEF(mflags);
+tag_typedef_t nthtag_streaming = BOOLTAG_TYPEDEF(streaming);
+
+/* Client */
+tag_typedef_t nthtag_proxy = URLTAG_TYPEDEF(proxy);
+tag_typedef_t nthtag_expires = UINTTAG_TYPEDEF(expires);
+tag_typedef_t nthtag_error_msg = BOOLTAG_TYPEDEF(error_msg);
+tag_typedef_t nthtag_template = PTRTAG_TYPEDEF(template);
+tag_typedef_t nthtag_authentication = PTRTAG_TYPEDEF(authentication);
+
+/* Server */
+tag_typedef_t nthtag_root = PTRTAG_TYPEDEF(root);
+tag_typedef_t nthtag_strict_host = BOOLTAG_TYPEDEF(scrict_host);
+
+/**@def NTHTAG_AUTH_MODULE()
+ *
+ * Pointer to authentication module.
+ *
+ * A site requires authentication from the clients if passed an
+ * authentication module pointer with NTHTAG_AUTH_MODULE(). Incoming client
+ * request is challenged with 401, upon successful authentication the
+ * authenticated username is stored in the #auth_status_t structure
+ * associated with the #nth_request_t object. It is up to application to
+ * authorize the user.
+ *
+ * @sa nth_site_create(), nth_site_set_params(), nth_request_auth().
+ */
+tag_typedef_t nthtag_auth_module = PTRTAG_TYPEDEF(auth_module);
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/sofia-sip/nth.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/sofia-sip/nth.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,202 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@file sofia-sip/nth.h
+ * @brief Transaction API for HTTP
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Wed Jun 5 19:25:18 2002 ppessi
+ */
+
+/* ----------------------------------------------------------------------
+ * 1) Types
+ */
+
+#ifndef NTH_H_TYPES
+#define NTH_H_TYPES
+
+/** NTH engine */
+typedef struct nth_engine_s nth_engine_t;
+/** NTH client request */
+typedef struct nth_client_s nth_client_t;
+
+/** NTH (virtual) hosts or site(s) */
+typedef struct nth_site_s nth_site_t;
+/** Server transaction */
+typedef struct nth_request_s nth_request_t;
+
+#ifndef NTH_CLIENT_MAGIC_T
+/** Default type of application context for client NTH requests.
+ * Application may define this to appropriate type before including
+ * <nth.h>. */
+#define NTH_CLIENT_MAGIC_T struct nth_client_magic_s
+#endif
+
+/** Application context for client requests */
+typedef NTH_CLIENT_MAGIC_T nth_client_magic_t;
+
+#ifndef NTH_SITE_MAGIC_T
+/** Default type of application context for NTH servers.
+ * Application may define this to appropriate type before including
+ * <nth.h>. */
+#define NTH_SITE_MAGIC_T struct nth_site_magic_s
+#endif
+
+/** Application context for NTH servers */
+typedef NTH_SITE_MAGIC_T nth_site_magic_t;
+
+#endif
+
+#ifndef NTH_H
+/** Defined when <sofia-sip/nth.h> has been included. */
+#define NTH_H
+
+/* ----------------------------------------------------------------------
+ * 2) Constants
+ */
+
+/** Version number */
+#define NTH_VERSION "1.0"
+
+#define NTH_CLIENT_VERSION NTH_VERSION
+#define NTH_SERVER_VERSION NTH_VERSION
+
+/* ----------------------------------------------------------------------
+ * 3) Other include files
+ */
+
+#include <sofia-sip/su_wait.h>
+#include <sofia-sip/su_tag.h>
+#include <sofia-sip/http.h>
+#include <sofia-sip/http_status.h>
+
+#ifndef NTH_TAG_H
+#include <sofia-sip/nth_tag.h>
+#endif
+
+/* ----------------------------------------------------------------------
+ * 3) Engine prototypes
+ */
+
+SOFIA_BEGIN_DECLS
+
+NTH_DLL char const *nth_engine_version(void);
+
+NTH_DLL nth_engine_t *nth_engine_create(su_root_t *root,
+ tag_type_t tag, tag_value_t value, ...);
+NTH_DLL void nth_engine_destroy(nth_engine_t *engine);
+
+NTH_DLL int nth_engine_set_params(nth_engine_t *engine,
+ tag_type_t tag, tag_value_t value, ...);
+NTH_DLL int nth_engine_get_params(nth_engine_t const *engine,
+ tag_type_t tag, tag_value_t value, ...);
+NTH_DLL int nth_engine_get_stats(nth_engine_t const *engine,
+ tag_type_t tag, tag_value_t value, ...);
+
+NTH_DLL msg_t *nth_engine_msg_create(nth_engine_t *he, int flags);
+
+/* ----------------------------------------------------------------------
+ * 4) Prototypes for client transactions
+ */
+typedef int nth_response_f(nth_client_magic_t *magic,
+ nth_client_t *request,
+ http_t const *http);
+
+NTH_DLL nth_client_t *nth_client_tcreate(nth_engine_t *engine,
+ nth_response_f *callback,
+ nth_client_magic_t *magic,
+ http_method_t method,
+ char const *method_name,
+ url_string_t const *request_uri,
+ tag_type_t tag, tag_value_t value,
+ ...);
+
+NTH_DLL int nth_client_status(nth_client_t const *clnt);
+NTH_DLL http_method_t nth_client_method(nth_client_t const *cnlt);
+NTH_DLL int nth_client_is_streaming(nth_client_t const *hc);
+
+NTH_DLL url_t const *nth_client_url(nth_client_t const *clnt);
+
+NTH_DLL msg_t *nth_client_request(nth_client_t *clnt);
+NTH_DLL msg_t *nth_client_response(nth_client_t const *clnt);
+NTH_DLL void nth_client_destroy(nth_client_t *clnt);
+
+/* ----------------------------------------------------------------------
+ * 5) Server side prototypes
+ */
+
+typedef int nth_request_f(nth_site_magic_t *lmagic,
+ nth_site_t *server,
+ nth_request_t *req,
+ http_t const *http,
+ char const *path);
+
+char const *nth_site_server_version(void);
+
+NTH_DLL nth_site_t *nth_site_create(nth_site_t *parent,
+ nth_request_f *req_callback,
+ nth_site_magic_t *magic,
+ url_string_t const *address,
+ tag_type_t tag, tag_value_t value,
+ ...);
+
+NTH_DLL void nth_site_destroy(nth_site_t *site);
+
+NTH_DLL nth_site_magic_t *nth_site_magic(nth_site_t const *site);
+
+NTH_DLL void nth_site_bind(nth_site_t *site,
+ nth_request_f *callback,
+ nth_site_magic_t *);
+
+NTH_DLL su_time_t nth_site_access_time(nth_site_t const *site);
+
+NTH_DLL int nth_site_set_params(nth_site_t *site,
+ tag_type_t tag, tag_value_t value, ...);
+NTH_DLL int nth_site_get_params(nth_site_t const *site,
+ tag_type_t tag, tag_value_t value, ...);
+NTH_DLL int nth_site_get_stats(nth_site_t const *site,
+ tag_type_t tag, tag_value_t value, ...);
+
+NTH_DLL url_t const *nth_site_url(nth_site_t const *site);
+
+/* ----------------------------------------------------------------------
+ * 6) Prototypes for server transactions
+ */
+
+NTH_DLL int nth_request_status(nth_request_t const *req);
+NTH_DLL http_method_t nth_request_method(nth_request_t const *req);
+NTH_DLL msg_t *nth_request_message(nth_request_t *req);
+
+NTH_DLL int nth_request_treply(nth_request_t *ireq,
+ int status, char const *phrase,
+ tag_type_t tag, tag_value_t value, ...);
+
+NTH_DLL void nth_request_destroy(nth_request_t *req);
+
+NTH_DLL struct auth_status_t *nth_request_auth(nth_request_t const *req);
+
+SOFIA_END_DECLS
+
+#endif
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/sofia-sip/nth_tag.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/sofia-sip/nth_tag.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,190 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef NTH_TAG_H
+/** Defined when <sofia-sip/nth_tag.h> has been included. */
+#define NTH_TAG_H
+
+/**@file sofia-sip/nth_tag.h
+ * @brief Tags for @b nth, HTTP engine module.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Sun Oct 13 22:23:48 2002 ppessi
+ */
+
+#ifndef SU_TAG_H
+#include <sofia-sip/su_tag.h>
+#endif
+
+#ifndef URL_TAG_H
+#include <sofia-sip/url_tag.h>
+#endif
+
+#ifndef HTTP_TAG_H
+#include <sofia-sip/http_tag.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** List of all nth tags */
+NTH_DLL extern tagi_t nth_client_tags[];
+
+/** Filter tag matching any nth tag. */
+#define NTHTAG_ANY() nthtag_any, ((tag_value_t)0)
+NTH_DLL extern tag_typedef_t nthtag_any;
+
+/* Common tags */
+
+NTH_DLL extern tag_typedef_t nthtag_mclass;
+/** Pointer to a mclass, message factory object. @HI */
+#define NTHTAG_MCLASS(x) nthtag_mclass, tag_cptr_v((x))
+
+NTH_DLL extern tag_typedef_t nthtag_mclass_ref;
+#define NTHTAG_MCLASS_REF(x) nthtag_mclass_ref, tag_cptr_vr(&(x), (x))
+
+NTH_DLL extern tag_typedef_t nthtag_mflags;
+/** Message flags used by nth_engine_msg_create()/nth_site_msg(). @HI */
+#define NTHTAG_MFLAGS(x) nthtag_mflags, tag_int_v((x))
+
+NTH_DLL extern tag_typedef_t nthtag_mflags_ref;
+#define NTHTAG_MFLAGS_REF(x) nthtag_mflags_ref, tag_int_vr(&(x))
+
+NTH_DLL extern tag_typedef_t nthtag_streaming;
+/** Enable streaming. @HI */
+#define NTHTAG_STREAMING(x) nthtag_streaming, tag_bool_v((x))
+
+NTH_DLL extern tag_typedef_t nthtag_streaming_ref;
+#define NTHTAG_STREAMING_REF(x) nthtag_streaming_ref, tag_bool_vr(&(x))
+
+/* Client-only tags */
+
+NTH_DLL extern tag_typedef_t nthtag_proxy;
+/** URL for (default) proxy. @HI */
+#define NTHTAG_PROXY(x) nthtag_proxy, urltag_url_v((x))
+
+NTH_DLL extern tag_typedef_t nthtag_proxy_ref;
+#define NTHTAG_PROXY_REF(x) nthtag_proxy_ref, urltag_url_vr(&(x))
+
+NTH_DLL extern tag_typedef_t nthtag_expires;
+/** Expires in milliseconds for client transactions. @HI */
+#define NTHTAG_EXPIRES(x) nthtag_expires, tag_uint_v((x))
+
+NTH_DLL extern tag_typedef_t nthtag_expires_ref;
+#define NTHTAG_EXPIRES_REF(x) nthtag_expires_ref, tag_uint_vr(&(x))
+
+NTH_DLL extern tag_typedef_t nthtag_error_msg;
+/** If true, nth engine generates complete error messages. @HI */
+#define NTHTAG_ERROR_MSG(x) nthtag_error_msg, tag_bool_v((x))
+
+NTH_DLL extern tag_typedef_t nthtag_error_msg_ref;
+#define NTHTAG_ERROR_MSG_REF(x) nthtag_error_msg_ref, tag_bool_vr(&(x))
+
+#if SU_HAVE_INLINE
+struct nth_client_s;
+su_inline tag_value_t nthtag_template_v(struct nth_client_s const *v)
+{ return (tag_value_t)v; }
+su_inline tag_value_t nthtag_template_vr(struct nth_client_s const **vp)
+{return(tag_value_t)vp;}
+#else
+#define nthtag_template_v(v) ((tag_value_t)(v))
+#define nthtag_template_vr(vp) ((tag_value_t)&(vp))
+#endif
+
+NTH_DLL extern tag_typedef_t nthtag_template;
+/** Use existing client request as template. @HI */
+#define NTHTAG_TEMPLATE(x) nthtag_template, nthtag_template_v((x))
+
+NTH_DLL extern tag_typedef_t nthtag_template_ref;
+#define NTHTAG_TEMPLATE_REF(x) nthtag_template_ref, nthtag_template_vr(&(x))
+
+#if SU_HAVE_INLINE
+su_inline tag_value_t nthtag_message_v(struct msg_s *v)
+{ return (tag_value_t)v; }
+su_inline tag_value_t nthtag_message_vr(struct msg_s **vp)
+{ return(tag_value_t)vp; }
+#else
+#define nthtag_message_v(v) ((tag_value_t)(v))
+#define nthtag_message_vr(vp) ((tag_value_t)&(vp))
+#endif
+
+NTH_DLL extern tag_typedef_t nthtag_message;
+/** Use existing request message. @HI */
+#define NTHTAG_MESSAGE(x) nthtag_message, nthtag_message_v((x))
+
+NTH_DLL extern tag_typedef_t nthtag_message_ref;
+#define NTHTAG_MESSAGE_REF(x) nthtag_message_ref, nthtag_message_vr(&(x))
+
+#if SU_HAVE_INLINE
+struct auth_client_s;
+su_inline tag_value_t nthtag_authentication_v(struct auth_client_s **v) { return (tag_value_t)v; }
+su_inline tag_value_t nthtag_authentication_vr(struct auth_client_s ***vp) {return(tag_value_t)vp;}
+#else
+#define nthtag_authentication_v(v) ((tag_value_t)(v))
+#define nthtag_authentication_vr(vp) ((tag_value_t)&(vp))
+#endif
+
+NTH_DLL extern tag_typedef_t nthtag_authentication;
+/** Use stack of authenticators. @HI */
+#define NTHTAG_AUTHENTICATION(x) \
+nthtag_authentication, nthtag_authentication_v((x))
+
+NTH_DLL extern tag_typedef_t nthtag_authentication_ref;
+#define NTHTAG_AUTHENTICATION_REF(x) \
+nthtag_authentication_ref, nthtag_authentication_vr(&(x))
+
+NTH_DLL extern tag_typedef_t nthtag_max_retry_after;
+/** Maximum value for retry interval. @HI */
+#define NTHTAG_MAX_RETRY_AFTER(x) nthtag_max_retry_after, tag_int_v((x))
+
+NTH_DLL extern tag_typedef_t nthtag_max_retry_after_ref;
+#define NTHTAG_MAX_RETRY_AFTER_REF(x) \
+nthtag_max_retry_after_ref, tag_int_vr(&(x))
+
+/* Server-side tags */
+
+NTH_DLL extern tag_typedef_t nthtag_root;
+/** Pointer to root reactor object. @HI */
+#define NTHTAG_ROOT(x) nthtag_root, tag_ptr_v((x))
+
+NTH_DLL extern tag_typedef_t nthtag_root_ref;
+#define NTHTAG_ROOT_REF(x) nthtag_root_ref, tag_ptr_vr(&(x), (x))
+
+NTH_DLL extern tag_typedef_t nthtag_strict_host;
+/** Do not serve requests to mismatching hosts by default host. @HI */
+#define NTHTAG_STRICT_HOST(x) nthtag_strict_host, tag_bool_v((x))
+
+NTH_DLL extern tag_typedef_t nthtag_strict_host_ref;
+#define NTHTAG_STRICT_HOST_REF(x) nthtag_strict_host_ref, tag_bool_vr(&(x))
+
+NTH_DLL extern tag_typedef_t nthtag_auth_module;
+/** Pointer to authentication module. @HI. @NEW_1_12_4. */
+#define NTHTAG_AUTH_MODULE(x) nthtag_auth_module, tag_ptr_v((x))
+
+NTH_DLL extern tag_typedef_t nthtag_auth_module_ref;
+#define NTHTAG_AUTH_MODULE_REF(x) nthtag_auth_module_ref, tag_ptr_vr(&(x), (x))
+
+SOFIA_END_DECLS
+
+#endif /* !defined NTH_TAG_H */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/test_nth.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/test_nth.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,960 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@file test_nth.c
+ * @brief Tests for nth module
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Oct 22 20:52:37 2002 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <assert.h>
+
+#if HAVE_ALARM
+#include <unistd.h>
+#include <signal.h>
+#endif
+
+typedef struct tester tester_t;
+typedef struct site site_t;
+typedef struct client client_t;
+
+#define SU_ROOT_MAGIC_T tester_t
+
+#include <sofia-sip/su_tagarg.h>
+#include <sofia-sip/su_wait.h>
+
+#define NTH_CLIENT_MAGIC_T client_t
+#define NTH_SITE_MAGIC_T site_t
+
+#include "sofia-sip/nth.h"
+#include <sofia-sip/http_header.h>
+#include <sofia-sip/msg_mclass.h>
+#include <sofia-sip/tport_tag.h>
+#include <sofia-sip/auth_module.h>
+
+int tstflags = 0;
+
+#define TSTFLAGS tstflags
+
+#include <sofia-sip/tstdef.h>
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+#define __func__ name
+#endif
+
+char const name[] = "test_nth";
+
+static int init_test(tester_t *t);
+static int deinit_test(tester_t *t);
+static int test_nth_client_api(tester_t *t);
+static int test_nth_server_api(tester_t *t);
+static int init_server(tester_t *t);
+static int test_requests(tester_t *t);
+static int init_engine(tester_t *t);
+
+struct site
+{
+ site_t *s_next, *s_parent;
+ tester_t *s_tester;
+ url_string_t *s_url;
+ nth_site_t *s_ns;
+ int s_called;
+ int s_status;
+ char const *s_phrase;
+ tagi_t *s_tags;
+};
+
+struct client
+{
+ unsigned c_status;
+};
+
+struct tester
+{
+ su_home_t t_home[1];
+ su_root_t *t_root;
+ msg_mclass_t *t_mclass;
+ url_string_t *t_proxy;
+ nth_engine_t *t_engine;
+
+ char const *t_srcdir;
+ char const *t_pem;
+
+ su_sockaddr_t t_addr[1];
+ socklen_t t_addrlen;
+
+ su_socket_t t_sink;
+ url_string_t *t_sinkuri;
+ su_sockaddr_t t_sinkaddr[1];
+ socklen_t t_sinkaddrlen;
+
+ site_t *t_sites;
+ site_t *t_master;
+};
+
+static int test_site(site_t *t,
+ nth_site_t *server,
+ nth_request_t *req,
+ http_t const *http,
+ char const *path);
+
+static site_t *site_create(tester_t *t, site_t *parent,
+ char const *url,
+ int status, char const *phrase,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ nth_site_t *pns = parent ? parent->s_ns : NULL;
+ site_t *s;
+ ta_list ta;
+
+ if (url == NULL)
+ return NULL;
+
+ s = su_zalloc(t->t_home, sizeof *s);
+ if (s == NULL)
+ return NULL;
+
+ s->s_url = URL_STRING_MAKE(url);
+ s->s_tester = t;
+ s->s_next = t->t_sites;
+ s->s_status = status;
+ s->s_phrase = phrase;
+
+ ta_start(ta, tag, value);
+
+ s->s_tags = tl_adup(t->t_home, ta_args(ta));
+ if (s->s_tags)
+ s->s_ns = nth_site_create(pns, test_site, s,
+ (url_string_t *)s->s_url,
+ NTHTAG_ROOT(t->t_root),
+ ta_tags(ta));
+
+ ta_end(ta);
+
+ if (s->s_ns == NULL)
+ return NULL;
+
+ t->t_sites = s;
+
+ return s;
+}
+
+static int init_test(tester_t *t)
+{
+ su_socket_t s;
+
+ BEGIN();
+
+ t->t_root = su_root_create(t); TEST_1(t->t_root);
+ t->t_mclass = msg_mclass_clone(http_default_mclass(), 0, 0);
+ TEST_1(t->t_mclass);
+
+ t->t_addr->su_len = (sizeof t->t_addr->su_sin);
+ s = su_socket(t->t_addr->su_family = AF_INET, SOCK_STREAM, 0);
+ TEST_1(s != INVALID_SOCKET);
+ TEST_1(inet_pton(AF_INET, "127.0.0.1", &t->t_addr->su_sin.sin_addr) >= 0);
+ TEST_1(bind(s, &t->t_addr->su_sa,
+ t->t_addrlen = (sizeof t->t_addr->su_sin)) != -1);
+ TEST_1(getsockname(s, &t->t_addr->su_sa, &t->t_addrlen) != -1);
+ TEST_1(t->t_addr->su_port != 0);
+ TEST_1(su_close(s) != -1);
+
+ t->t_pem = su_sprintf(t->t_home, "%s/agent.pem", t->t_srcdir);
+
+ END();
+}
+
+static int deinit_test(tester_t *t)
+{
+ site_t *s, *s_next;
+
+ BEGIN();
+
+ nth_engine_destroy(t->t_engine);
+
+ for (s = t->t_sites; s; s = s_next) {
+ s_next = s->s_next;
+ nth_site_destroy(s->s_ns), s->s_ns = NULL;
+ su_free(t->t_home, s);
+ }
+
+ su_root_destroy(t->t_root);
+
+ su_home_deinit(t->t_home);
+
+ memset(t, 0, sizeof t);
+
+ END();
+}
+
+
+static int test_nth_client_api(tester_t *t)
+{
+ char const *s;
+
+ BEGIN();
+
+ s = nth_engine_version();
+ TEST_1(s); TEST_1(strlen(s)); TEST_S(s, "sofia-http-client/" NTH_CLIENT_VERSION);
+
+ TEST_1(nth_engine_create(NULL, TAG_END()) == NULL);
+ TEST(errno, EINVAL);
+ TEST_VOID(nth_engine_destroy(NULL));
+ TEST_1(nth_engine_get_params(NULL, TAG_END()) == -1);
+ TEST_1(nth_engine_set_params(NULL, TAG_END()) == -1);
+ TEST_1(!nth_client_tcreate(NULL, NULL, NULL,
+ HTTP_METHOD_OPTIONS,
+ URL_STRING_MAKE("*"),
+ TAG_END()));
+ TEST(nth_client_status(NULL), 400);
+ TEST(nth_client_method(NULL), http_method_invalid);
+ TEST(nth_client_is_streaming(NULL), 0);
+ TEST_P(nth_client_url(NULL), NULL);
+ TEST_P(nth_client_request(NULL), NULL);
+ TEST_P(nth_client_response(NULL), NULL);
+ TEST_VOID(nth_client_destroy(NULL));
+
+ t->t_engine = nth_engine_create(t->t_root,
+ NTHTAG_ERROR_MSG(2),
+ NTHTAG_MCLASS(t->t_mclass),
+ NTHTAG_MFLAGS(MSG_DO_CANONIC|MSG_DO_COMPACT),
+ NTHTAG_STREAMING(0),
+ NTHTAG_PROXY("http://localhost:8888"),
+ TAG_END());
+ TEST_1(t->t_engine);
+
+ {
+ int error_msg = -1;
+ msg_mclass_t const *mclass = (void *)-1;
+ int mflags = -1;
+ unsigned expires = -1;
+ int streaming = -1;
+ url_string_t const *proxy = (void *)-1;
+
+ char *proxy_str;
+
+ TEST(nth_engine_get_params(t->t_engine,
+ NTHTAG_ERROR_MSG_REF(error_msg),
+ NTHTAG_MCLASS_REF(mclass),
+ NTHTAG_MFLAGS_REF(mflags),
+ NTHTAG_EXPIRES_REF(expires),
+ NTHTAG_STREAMING_REF(streaming),
+ NTHTAG_PROXY_REF(proxy),
+ TAG_END()),
+ 6);
+
+ TEST(error_msg, 1);
+ TEST_P(mclass, t->t_mclass);
+ TEST(mflags, MSG_DO_CANONIC|MSG_DO_COMPACT);
+ TEST(expires, 32000);
+ TEST(streaming, 0);
+ TEST_1(proxy != NULL);
+ TEST_1(proxy_str = url_as_string(t->t_home, proxy->us_url));
+ TEST_S(proxy_str, "http://localhost:8888");
+
+ proxy = URL_STRING_MAKE("http://127.0.0.1:80");
+
+ TEST(nth_engine_set_params(t->t_engine,
+ NTHTAG_ERROR_MSG(0),
+ NTHTAG_MCLASS(http_default_mclass()),
+ NTHTAG_MFLAGS(0),
+ NTHTAG_EXPIRES(10000),
+ NTHTAG_STREAMING(2),
+ NTHTAG_PROXY(proxy),
+ TAG_END()),
+ 6);
+
+ error_msg = -1;
+ mclass = (void *)-1;
+ mflags = -1;
+ expires = (unsigned)-1;
+ streaming = -1;
+ proxy = (void *)-1;
+
+ TEST(nth_engine_get_params(t->t_engine,
+ NTHTAG_ERROR_MSG_REF(error_msg),
+ NTHTAG_MCLASS_REF(mclass),
+ NTHTAG_MFLAGS_REF(mflags),
+ NTHTAG_EXPIRES_REF(expires),
+ NTHTAG_STREAMING_REF(streaming),
+ NTHTAG_PROXY_REF(proxy),
+ TAG_END()),
+ 6);
+
+ TEST(error_msg, 0);
+ TEST_P(mclass, NULL);
+ TEST(mflags, 0);
+ TEST(expires, 10000);
+ TEST(streaming, 1);
+ TEST_1(proxy != NULL);
+ TEST_1(proxy_str = url_as_string(t->t_home, proxy->us_url));
+ TEST_S(proxy_str, "http://127.0.0.1:80");
+ }
+
+ TEST_1(nth_engine_get_stats(NULL, TAG_END()) == -1);
+
+ {
+ msg_t *msg;
+ http_t *http;
+
+ TEST_1(nth_engine_msg_create(NULL, -1) == NULL);
+ TEST_1(msg = nth_engine_msg_create(t->t_engine, -1));
+ TEST_1(http = http_object(msg));
+ TEST(http->http_flags, MSG_FLG_USERMASK);
+ msg_destroy(msg);
+
+ /* Use mflags set by set_params (+ streaming flag) */
+ TEST_1(msg = nth_engine_msg_create(t->t_engine, 0));
+ TEST_1(http = http_object(msg));
+ TEST(http->http_flags, MSG_FLG_STREAMING | t->t_mclass->mc_flags);
+ msg_destroy(msg);
+ }
+
+ TEST_VOID(nth_engine_destroy(t->t_engine));
+ t->t_engine = NULL;
+
+ END();
+}
+
+static int site_check_all(site_t *t,
+ nth_site_t *server,
+ nth_request_t *req,
+ http_t const *http,
+ char const *path);
+
+static int test_nth_server_api(tester_t *t)
+
+{
+ char const *v;
+ site_t s[1];
+
+ BEGIN();
+
+ memset(s, 0, sizeof s);
+
+ v = nth_site_server_version();
+ TEST_1(v); TEST_1(strlen(v)); TEST_S(v, "nth/" NTH_SERVER_VERSION);
+
+ /* Fails because no parent site, no root */
+ TEST_1(!nth_site_create(NULL, test_site, s,
+ URL_STRING_MAKE("http://127.0.0.1:8888"),
+ TAG_END()));
+
+ /* Fails because url specifies both host and path */
+ TEST_1(!nth_site_create(NULL, site_check_all, s,
+ URL_STRING_MAKE("http://127.0.0.1:8888/foo/"),
+ NTHTAG_ROOT(t->t_root), TAG_END()));
+
+ TEST_VOID(nth_site_destroy(NULL));
+ TEST_P(nth_site_magic(NULL), NULL);
+ TEST_VOID(nth_site_bind(NULL, test_site, s));
+ TEST_1(nth_site_set_params(NULL, TAG_END()) == -1);
+ TEST_1(nth_site_get_params(NULL, TAG_END()) == -1);
+ TEST_1(nth_site_get_stats(NULL, TAG_END()) == -1);
+ TEST(nth_request_status(NULL), 400);
+ TEST(nth_request_method(NULL), http_method_invalid);
+ TEST_P(nth_request_message(NULL), NULL);
+ TEST_1(nth_request_treply(NULL, HTTP_200_OK, TAG_END()) == -1);
+ TEST_VOID(nth_request_destroy(NULL));
+
+ END();
+}
+
+static int test_site(site_t *s,
+ nth_site_t *ns,
+ nth_request_t *req,
+ http_t const *http,
+ char const *path)
+{
+ if (s == NULL || ns == NULL || req == NULL)
+ return 500;
+
+ TEST_1(nth_request_treply(req, s->s_status, s->s_phrase,
+ TAG_NEXT(s->s_tags)) != -1);
+
+ TEST_VOID(nth_request_destroy(req));
+
+ return s->s_status;
+}
+
+
+static int site_check_all(site_t *s,
+ nth_site_t *ns,
+ nth_request_t *req,
+ http_t const *http,
+ char const *path)
+{
+ msg_t *msg;
+ auth_status_t *as;
+
+ TEST_1(s); TEST_1(ns); TEST_1(req); TEST_1(http); TEST_1(path);
+
+ if (s == NULL || ns == NULL || req == NULL)
+ return 500;
+
+ TEST(nth_request_status(req), 0);
+ TEST(nth_request_method(req), http_method_get);
+ TEST_1(msg = nth_request_message(req));
+
+ msg_destroy(msg);
+
+ as = nth_request_auth(req);
+
+ TEST_1(nth_request_treply(req, s->s_status, s->s_phrase,
+ TAG_NEXT(s->s_tags)) != -1);
+
+ TEST_VOID(nth_request_destroy(req));
+
+ return s->s_status;
+}
+
+static char passwd_name[] = "tmp_sippasswd.XXXXXX";
+
+static void remove_tmp(void)
+{
+ if (passwd_name[0])
+ unlink(passwd_name);
+}
+
+static char const passwd[] =
+ "alice:secret:\n"
+ "bob:secret:\n"
+ "charlie:secret:\n";
+
+static int init_server(tester_t *t)
+{
+ BEGIN();
+
+ site_t *m = t->t_master, *sub2;
+ auth_mod_t *am;
+ int temp;
+
+ TEST_1(t->t_master = m =
+ site_create(t, NULL,
+ su_sprintf(t->t_home, "HTTP://127.0.0.1:%u",
+ htons(t->t_addr->su_port)),
+ HTTP_200_OK,
+ HTTPTAG_CONTENT_TYPE_STR("text/html"),
+ HTTPTAG_PAYLOAD_STR("<html><body>Hello</body></html>\n"),
+ TPTAG_CERTIFICATE(t->t_pem),
+ TAG_END()));
+
+ TEST_1(site_create(t, m, "/sub/sub",
+ HTTP_200_OK,
+ HTTPTAG_CONTENT_TYPE_STR("text/html"),
+ HTTPTAG_PAYLOAD_STR
+ ("<html><body>sub/sub</body></html>\n"),
+ TAG_END()));
+
+ TEST_1(site_create(t, m, "/sub/",
+ HTTP_200_OK,
+ HTTPTAG_CONTENT_TYPE_STR("text/html"),
+ HTTPTAG_PAYLOAD_STR("<html><body>sub/</body></html>\n"),
+ TAG_END()));
+
+ TEST_1(site_create(t, m, "/sub/sub/",
+ HTTP_200_OK,
+ HTTPTAG_CONTENT_TYPE_STR("text/html"),
+ HTTPTAG_PAYLOAD_STR
+ ("<html><body>sub/sub/</body></html>\n"),
+ TAG_END()));
+
+ TEST_1(sub2 =
+ site_create(t, m, "/sub2/",
+ HTTP_200_OK,
+ HTTPTAG_CONTENT_TYPE_STR("text/html"),
+ HTTPTAG_PAYLOAD_STR("<html><body>sub2/</body></html>\n"),
+ TAG_END()));
+
+ TEST_1(site_create(t, sub2, "sub/",
+ HTTP_200_OK,
+ HTTPTAG_CONTENT_TYPE_STR("text/html"),
+ HTTPTAG_PAYLOAD_STR
+ ("<html><body>sub2/sub/</body></html>\n"),
+ TAG_END()));
+
+
+#ifndef _WIN32
+ temp = mkstemp(passwd_name);
+#else
+ temp = open(passwd_name, O_WRONLY|O_CREAT|O_TRUNC, 666);
+#endif
+ TEST_1(temp != -1);
+ atexit(remove_tmp); /* Make sure temp file is unlinked */
+
+ TEST_SIZE(write(temp, passwd, strlen(passwd)), strlen(passwd));
+
+ TEST_1(close(temp) == 0);
+
+ am = auth_mod_create(t->t_root,
+ AUTHTAG_METHOD("Digest"),
+ AUTHTAG_REALM("auth"),
+ AUTHTAG_DB(passwd_name),
+ TAG_END());
+ TEST_1(am);
+
+ TEST_1(site_create(t, m, "auth/",
+ HTTP_200_OK,
+ HTTPTAG_CONTENT_TYPE_STR("text/html"),
+ HTTPTAG_PAYLOAD_STR
+ ("<html><body>auth/</body></html>\n"),
+ NTHTAG_AUTH_MODULE(am),
+ TAG_END()));
+
+ auth_mod_unref(am);
+
+
+ am = auth_mod_create(t->t_root,
+ AUTHTAG_METHOD("Delayed+Basic"),
+ AUTHTAG_REALM("auth2"),
+ AUTHTAG_DB(passwd_name),
+ TAG_END());
+ TEST_1(am);
+
+ TEST_1(site_create(t, m, "auth2/",
+ HTTP_200_OK,
+ HTTPTAG_CONTENT_TYPE_STR("text/html"),
+ HTTPTAG_PAYLOAD_STR
+ ("<html><body>auth/</body></html>\n"),
+ NTHTAG_AUTH_MODULE(am),
+ TAG_END()));
+
+ auth_mod_unref(am);
+
+ END();
+}
+
+static int send_request(tester_t *t, char const *req, size_t reqlen,
+ int close_socket,
+ char reply[], int rlen,
+ int *return_len)
+{
+ static su_socket_t c = INVALID_SOCKET;
+ int m, r;
+ su_wait_t w[1];
+
+ BEGIN();
+
+ if (c == INVALID_SOCKET) {
+ c = su_socket(t->t_addr->su_family, SOCK_STREAM, 0); TEST_1(c != SOCK_STREAM);
+ TEST_1(connect(c, &t->t_addr->su_sa, t->t_addrlen) != -1);
+
+ while (su_root_step(t->t_root, 1) == 0);
+ }
+
+ if (reqlen == (size_t)-1)
+ reqlen = strlen(req);
+
+ TEST_SIZE(su_send(c, req, reqlen, 0), reqlen);
+
+ if (close_socket == 1)
+ shutdown(c, 1);
+
+ TEST(su_wait_create(w, c, SU_WAIT_IN), 0);
+
+ while (su_root_step(t->t_root, 1) == 0 || su_wait(w, 1, 0) < 0);
+
+ for (r = 0;;) {
+ TEST_1((m = recv(c, reply, rlen - r - 1, 0)) != -1);
+ r += m;
+ if (m == 0 || r == rlen - 1)
+ break;
+ }
+ reply[r] = '\0';
+
+ if (close_socket != -1)
+ su_close(c), c = -1;
+
+ *return_len = r;
+
+ END();
+}
+
+int sspace(char const *buffer)
+{
+ int m = strcspn(buffer, " ");
+
+ if (buffer[m])
+ m += 1 + strcspn(buffer + m + 1, " ");
+
+ return m;
+}
+
+#define CRLF "\r\n"
+
+static int test_requests(tester_t *t)
+{
+ char buffer[4096 + 1];
+ int m;
+
+ BEGIN();
+
+ {
+ static char const get[] =
+ "GET / HTTP/1.1" CRLF
+ "Host: 127.0.0.1" CRLF
+ "User-Agent: Test-Tool" CRLF
+ "Connection: close" CRLF
+ CRLF;
+
+ TEST(send_request(t, get, -1, 0, buffer, sizeof(buffer), &m), 0);
+
+ m = sspace(buffer); buffer[m] = '\0';
+ TEST_S(buffer, "HTTP/1.1 200");
+ }
+
+ {
+ static char const get[] =
+ "GET / HTTP/1.1" CRLF
+ "Host: 127.0.0.1" CRLF
+ "User-Agent: Test-Tool" CRLF
+ "Connection: close" CRLF
+ CRLF;
+
+ TEST(send_request(t, get, -1, 0, buffer, sizeof(buffer), &m), 0);
+
+ m = strcspn(buffer, CRLF); buffer[m] = '\0';
+ TEST_S(buffer, "HTTP/1.1 200 OK");
+ }
+
+ {
+ static char const request[] =
+ "GET %s HTTP/1.1" CRLF
+ "Host: 127.0.0.1" CRLF
+ "User-Agent: Test-Tool" CRLF
+ "Connection: close" CRLF
+ CRLF;
+ char *get;
+
+ get = su_sprintf(NULL, request, "/sub");
+ TEST(send_request(t, get, -1, 0, buffer, sizeof(buffer), &m), 0);
+ m = sspace(buffer); buffer[m++] = '\0';
+ TEST_S(buffer, "HTTP/1.1 301");
+ m += strcspn(buffer + m, CRLF) + 1;
+ free(get);
+
+ get = su_sprintf(NULL, request, "/sub/");
+ TEST(send_request(t, get, -1, 0, buffer, sizeof(buffer), &m), 0);
+ m = strcspn(buffer, CRLF); buffer[m++] = '\0';
+ TEST_S(buffer, "HTTP/1.1 200 OK");
+ TEST_1(strstr(buffer + m, "<body>sub/</body>"));
+ free(get);
+
+ get = su_sprintf(NULL, request, "/sub2/");
+ TEST(send_request(t, get, -1, 0, buffer, sizeof(buffer), &m), 0);
+ m = strcspn(buffer, CRLF); buffer[m++] = '\0';
+ TEST_S(buffer, "HTTP/1.1 200 OK");
+ TEST_1(strstr(buffer + m, "<body>sub2/</body>"));
+ free(get);
+
+ get = su_sprintf(NULL, request, "/sub2/hub");
+ TEST(send_request(t, get, -1, 0, buffer, sizeof(buffer), &m), 0);
+ m = strcspn(buffer, CRLF); buffer[m++] = '\0';
+ TEST_S(buffer, "HTTP/1.1 200 OK");
+ TEST_1(strstr(buffer + m, "<body>sub2/</body>"));
+ free(get);
+
+ /* Test that absolute path for subdir site is calculated correctly */
+ get = su_sprintf(NULL, request, "/sub2/sub");
+ TEST(send_request(t, get, -1, 0, buffer, sizeof(buffer), &m), 0);
+ m = sspace(buffer); buffer[m++] = '\0';
+ TEST_S(buffer, "HTTP/1.1 301");
+ TEST_1(strstr(buffer + m, "/sub2/sub/" CRLF));
+ free(get);
+
+ get = su_sprintf(NULL, request, "/sub2/sub/");
+ TEST(send_request(t, get, -1, 0, buffer, sizeof(buffer), &m), 0);
+ m = strcspn(buffer, CRLF); buffer[m++] = '\0';
+ TEST_S(buffer, "HTTP/1.1 200 OK");
+ TEST_1(strstr(buffer + m, "<body>sub2/sub/</body>"));
+ free(get);
+
+ get = su_sprintf(NULL, request, "/sub/sub");
+ TEST(send_request(t, get, -1, 0, buffer, sizeof(buffer), &m), 0);
+ m = strcspn(buffer, CRLF); buffer[m++] = '\0';
+ TEST_S(buffer, "HTTP/1.1 200 OK");
+ TEST_1(strstr(buffer + m, "<body>sub/sub</body>"));
+ free(get);
+
+ get = su_sprintf(NULL, request, "/auth/");
+ TEST(send_request(t, get, -1, 0, buffer, sizeof(buffer), &m), 0);
+ m = sspace(buffer); buffer[m++] = '\0';
+ TEST_S(buffer, "HTTP/1.1 401");
+ free(get);
+
+ get = su_sprintf(NULL, request, "/auth2/");
+ TEST(send_request(t, get, -1, 0, buffer, sizeof(buffer), &m), 0);
+ m = sspace(buffer); buffer[m++] = '\0';
+ TEST_S(buffer, "HTTP/1.1 401");
+ free(get);
+ }
+
+ {
+ static char const get[] =
+ "GET /auth2/ HTTP/1.1" CRLF
+ "Host: 127.0.0.1" CRLF
+ "User-Agent: Test-Tool" CRLF
+ "Connection: close" CRLF
+ /* alice:secret in base64 */
+ "Authorization: Basic YWxpY2U6c2VjcmV0" CRLF
+ CRLF;
+
+ TEST(send_request(t, get, -1, 0, buffer, sizeof(buffer), &m), 0);
+ m = sspace(buffer); buffer[m++] = '\0';
+ TEST_S(buffer, "HTTP/1.1 200");
+ }
+
+ {
+ static char const kuik[] =
+ "kuik" CRLF CRLF;
+
+ TEST(send_request(t, kuik, -1, 0, buffer, sizeof(buffer), &m), 0);
+ m = sspace(buffer); buffer[m] = '\0';
+ TEST_S(buffer, "HTTP/1.1 400");
+ }
+
+ {
+ static char const kuik[] =
+ "POST / HTTP/1.1" CRLF
+ "Host: 127.0.0.1" CRLF
+ "Content-Length: 4294967296" CRLF
+ CRLF;
+
+ TEST(send_request(t, kuik, -1, 1, buffer, sizeof(buffer), &m), 0);
+ m = sspace(buffer); buffer[m] = '\0';
+ TEST_S(buffer, "HTTP/1.1 400");
+ }
+
+ {
+ static char const get[] =
+ "GET / HTTP/10.10" CRLF
+ "Host: 127.0.0.1" CRLF
+ "User-Agent: Test-Tool" CRLF
+ "Connection: close" CRLF
+ CRLF;
+
+ TEST(send_request(t, get, -1, 0, buffer, sizeof(buffer), &m), 0);
+
+ m = sspace(buffer); buffer[m] = '\0';
+ TEST_S(buffer, "HTTP/1.1 505");
+ }
+
+ {
+ static char const get[] =
+ "GET /" CRLF;
+
+ TEST(send_request(t, get, -1, 1, buffer, sizeof(buffer) - 1, &m), 0);
+
+ buffer[6] = '\0';
+ TEST_S(buffer, "<html>");
+ }
+
+ if (0)
+ {
+ static char const post[] =
+ "POST /foo HTTP/1.1" CRLF
+ "Host: 127.0.0.1" CRLF
+ "User-Agent: Test-Tool" CRLF
+ "Connection: close" CRLF
+ "Content-Length: 7" CRLF
+ "Expect: 100-continue" CRLF
+ CRLF;
+ static char const body[] =
+ "<html/>";
+
+ TEST(send_request(t, post, -1, -1, buffer, sizeof(buffer) - 1, &m), 0);
+
+ m = sspace(buffer); buffer[m] = '\0';
+ TEST_S(buffer, "HTTP/1.1 100");
+
+ TEST(send_request(t, body, -1, 0, buffer, sizeof(buffer) - 1, &m), 0);
+
+ m = sspace(buffer); buffer[m] = '\0';
+ TEST_S(buffer, "HTTP/1.1 200");
+ }
+
+ END();
+}
+
+
+static int init_engine(tester_t *t)
+{
+ BEGIN();
+ su_socket_t s;
+
+ t->t_engine = nth_engine_create(t->t_root,
+ NTHTAG_STREAMING(0),
+ TAG_END());
+ TEST_1(t->t_engine);
+
+ t->t_sink = s = su_socket(AF_INET, SOCK_STREAM, 0); TEST_1(s != -1);
+ TEST(bind(s, &t->t_sinkaddr->su_sa,
+ t->t_sinkaddrlen = (sizeof t->t_sinkaddr->su_sin)),
+ 0);
+ TEST_1(getsockname(s, &t->t_sinkaddr->su_sa, &t->t_sinkaddrlen) != -1);
+ TEST(listen(t->t_sink, 5), 0);
+
+ TEST_1(t->t_sinkuri = (url_string_t *)
+ su_sprintf(t->t_home, "HTTP://127.0.0.1:%u",
+ htons(t->t_sinkaddr->su_port)));
+
+ END();
+}
+
+
+static int response_to_client(client_t *c,
+ nth_client_t *hc,
+ http_t const *http)
+{
+ if (http) {
+ c->c_status = http->http_status->st_status;
+ }
+ else {
+ c->c_status = nth_client_status(hc);
+ }
+
+ return 0;
+}
+
+
+static int test_client(tester_t *t)
+{
+ BEGIN();
+
+ nth_client_t *hc;
+ char *uri;
+ client_t client[1];
+
+ memset(client, 0, sizeof client);
+
+ TEST_1(uri = su_strcat(NULL, t->t_master->s_url->us_str, "/"));
+ TEST_1(hc = nth_client_tcreate(t->t_engine,
+ response_to_client, client,
+ HTTP_METHOD_GET,
+ URL_STRING_MAKE(uri),
+ TAG_END()));
+ while (client->c_status == 0) su_root_step(t->t_root, 1);
+ TEST(client->c_status, 200);
+ nth_client_destroy(hc);
+ su_free(NULL, uri);
+
+ memset(client, 0, sizeof client);
+
+ TEST_1(hc = nth_client_tcreate(t->t_engine,
+ response_to_client, client,
+ HTTP_METHOD_GET,
+ URL_STRING_MAKE(t->t_sinkuri),
+ NTHTAG_EXPIRES(1000),
+ TAG_END()));
+ while (client->c_status == 0) su_root_step(t->t_root, 1);
+ TEST(client->c_status, 408);
+ nth_client_destroy(hc);
+
+ END();
+}
+#if HAVE_ALARM
+static RETSIGTYPE sig_alarm(int s)
+{
+ fprintf(stderr, "%s: FAIL! test timeout!\n", name);
+ exit(1);
+}
+#endif
+
+void usage(void)
+{
+ fprintf(stderr, "usage: %s [-v|-q] [-p proxy-uri]\n", name);
+ exit(1);
+}
+
+int main(int argc, char **argv)
+{
+ int i;
+ int retval = 0;
+ int o_alarm = 1;
+
+ tester_t t[1] = {{{ SU_HOME_INIT(t) }}};
+
+ char const *srcdir = getenv("srcdir");
+
+ if (srcdir == NULL)
+ srcdir = ".";
+
+ for (i = 1; argv[i]; i++) {
+ if (strcmp(argv[i], "-v") == 0)
+ tstflags |= tst_verbatim;
+ else if (strcmp(argv[i], "-q") == 0)
+ tstflags &= ~tst_verbatim;
+ else if (strcmp(argv[i], "-p") == 0 && argv[i + 1])
+ t->t_proxy = (url_string_t *)argv[++i];
+ else if (strcmp(argv[i], "-s") == 0 && argv[i + 1])
+ srcdir = argv[++i];
+ else if (strcmp(argv[i], "--no-alarm") == 0) {
+ o_alarm = 0;
+ }
+ else if (strcmp(argv[i], "-") == 0) {
+ i++; break;
+ }
+ else if (argv[i][0] != '-') {
+ break;
+ }
+ else
+ usage();
+ }
+
+ t->t_srcdir = srcdir;
+
+#if HAVE_ALARM
+ if (o_alarm) {
+ alarm(60);
+ signal(SIGALRM, sig_alarm);
+ }
+#endif
+
+ su_init();
+
+ retval |= init_test(t);
+ retval |= test_nth_client_api(t);
+ retval |= test_nth_server_api(t);
+ retval |= init_server(t);
+ retval |= test_requests(t);
+ retval |= init_engine(t);
+ retval |= test_client(t);
+ retval |= deinit_test(t);
+
+ su_deinit();
+
+ return retval;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/ChangeLog Thu Dec 21 01:30:28 2006
@@ -0,0 +1,480 @@
+2005-11-15 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * Removed obsolete NUTAG_MEDIA* tags.
+
+2005-11-03 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Indicate the response status with the nua_i_<method>.
+
+ Now returning the status of the returned response in
+ nua_i_<method> events. The application can determine from status
+ code if it has to respond.
+
+ * Added NUTAG_ALLOW() and NUTAG_ALLOW_REF() to nua.
+
+ * Try to catch more errors when responding to invite in nua.
+
+ * Fixed call state events with UPDATE in nua.
+
+ Fixed the order the nua_i_update and nua_i_state events are sent.
+ Now we are using session-timer headers in responses, too.
+
+ * Added NUTAG_ALLOW() and NUTAG_ALLOW_REF() to nua.
+
+ * Renamed NUTAG_USE_LEG() as NUTAG_USE_DIALOG() in nua.
+
+2005-10-21 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Fixed challenge header checking in nua/nua_stack.c when receiving 401/407.
+ Now checking for Proxy-Authenticate header when receiving 407 and
+ WWW-Authenticate header when receiving 401.
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -2 +2
+
+ * Added test case for 407 followed by 401.
+
+ M ./libsofia-sip-ua/nua/test_nua.c -3 +53
+
+2005-10-18 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Test case numbering.
+
+ M ./libsofia-sip-ua/nua/test_nua.c -1 +1
+
+ * Log level setting.
+
+ M ./libsofia-sip-ua/nua/test_nua.c -1 +2
+
+ * Added a basic session timer test.
+
+ M ./libsofia-sip-ua/nua/test_nua.c +121
+
+ * Fixed session-timer role selection at uas end.
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -10 +13
+
+ * Added -s option.
+
+ M ./libsofia-sip-ua/nua/test_nua.c -2 +10
+
+ * Simplified test_basic_call().
+
+ M ./libsofia-sip-ua/nua/test_nua.c -18 +1
+
+ * Added test case for nua_authenticate.
+
+ M ./libsofia-sip-ua/nua/test_nua.c +187
+
+ * Fixed response to 401.
+ We are now not terminating call when application is expected to authenticate
+ request. Should we add
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -10 +28
+
+ * Renumbered test cases. Split reject tests into separate functions.
+
+ M ./libsofia-sip-ua/nua/test_nua.c -135 +159
+
+ * Added aliases for SOATAG_MSS_POINTER and SOATAG_MSS_SESSION.
+
+ M ./libsofia-sip-ua/nua/nua_tag.h -27 +9
+
+2005-10-17 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Using port 5060 by default.
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -7 +13
+
+ * Fixed race condition in 302 test.
+
+ M ./libsofia-sip-ua/nua/test_nua.c -2 +2
+
+ * Silenced some gcc4 warnings.
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -10 +11
+ M ./libsofia-sip-ua/nua/test_nua.c -10 +10
+
+2005-10-15 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Relay real CANCEL response to application.
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -8 +31
+
+ * Added CANCEL and early BYE tests. Added headings for test cases.
+ Added more command-line options, too.
+
+ M ./libsofia-sip-ua/nua/test_nua.c -26 +476
+
+ * Fixed process_bye().
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -1 +15
+
+ * Fixed ua_bye().
+
+ Not mark session as terminated if we have an ongoing INVITE (just as
+ terminating). Instead of sending BYE, send CANCEL, if we have no dialog.
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -24 +34
+
+ * Let nh_init() call soa_set_params() in ua_update().
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -3
+ M ./libsofia-sip-ua/nua/nua_stack.c -7 +4
+
+ * Using new soa API in signal_call_state_change().
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -17 +11
+
+ * Cleaned indentation.
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -4 +11
+
+ * Replaced ancient nta_msg_discard() with msg_destroy().
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -3 +3
+
+ * Refactored nh_create_from_incoming().
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -15 +14
+
+ * Made ua_set_params() and nh_init() to return -1 upon an error.
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -18 +27
+
+ * Updated soa_get_local_sdp() API.
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -2 +2
+
+ * Zapped annoying last modified.
+
+ M ./libsofia-sip-ua/nua/nua.c -1
+ M ./libsofia-sip-ua/nua/nua.h -1
+ M ./libsofia-sip-ua/nua/nua_common.c -1
+ M ./libsofia-sip-ua/nua/nua_stack.c -1
+ M ./libsofia-sip-ua/nua/nua_stack.h -1
+ M ./libsofia-sip-ua/nua/nua_tag.c -1
+ M ./libsofia-sip-ua/nua/nua_tag.h -1
+
+ * Fixed logging options. Allow multithreaded, unsynchronised execution.
+
+ M ./libsofia-sip-ua/nua/test_nua.c -115 +162
+
+2005-10-12 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Fixed logging options. Allow multithreaded, unsynchronised execution.
+
+ M ./libsofia-sip-ua/nua/test_nua.c -115 +162
+
+2005-10-12 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Added test for call hold.
+
+ M ./libsofia-sip-ua/nua/test_nua.c +241
+
+ * Added better logging functions.
+
+ M ./libsofia-sip-ua/nua/test_nua.c -77 +149
+
+ * LDADD now have dependencies.
+
+ M ./libsofia-sip-ua/nua/Makefile.am -15 +15
+
+ * Added call reject cases.
+
+ M ./libsofia-sip-ua/nua/test_nua.c -62 +461
+
+ * When call is retried or terminated, always send nua_i_state after
+ nua_r_invite().
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -53 +55
+
+ * Fixed reference counting bug in process_ack().
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -6 +2
+
+2005-10-11 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Used picture-mode (cleaned up whitespace at eol).
+
+ M ./libsofia-sip-ua/nua/test_nua.c -23 +23
+
+ * Testing call flow on client side, too.
+
+ M ./libsofia-sip-ua/nua/test_nua.c -17 +94
+
+ * Transitions terminating call. Added letter C, S, and T to transitions.
+
+ M ./libsofia-sip-ua/nua/nua.docs -72 +159
+
+2005-10-10 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Fixed basic call test run.
+
+ M ./libsofia-sip-ua/nua/test_nua.c -8 +11
+
+ * It is nua_callstate_completed, not nua_callstate_complete.
+
+ M ./libsofia-sip-ua/nua/nua_common.c -1 +1
+ M ./libsofia-sip-ua/nua/nua_stack.c -1 +1
+ M ./libsofia-sip-ua/nua/test_nua.c -2 +2
+
+ * Running a basic call test case.
+
+ M ./libsofia-sip-ua/nua/test_nua.c -24 +109
+
+ * Added separate nua_i_ack event. Generating it after ACK is received.
+
+ M ./libsofia-sip-ua/nua/nua.h -1 +2
+ M ./libsofia-sip-ua/nua/nua_common.c -1 +3
+ M ./libsofia-sip-ua/nua/nua_stack.c -11 +24
+ M ./libsofia-sip-ua/nua/nua_stack.h -1 +4
+
+ * ua_invite2() crashed if there was problem creating SIP message.
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -1 +1
+
+ * Fixed indenting in nua_stack.c.
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -3 +6
+
+ * Including nua_callstate_terminated in the NUTAG_CALLSTATE always when call
+ is terminated.
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -2 +2
+
+ * nua_handle_has_streaming() is obsolete.
+
+ M ./libsofia-sip-ua/nua/nua.h -2 +3
+
+ * Using nua_callstate_complete.
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -8 +10
+
+ * Added nua_callstate_completing and nua_callstate_completed.
+
+ M ./libsofia-sip-ua/nua/nua_common.c +2
+ M ./libsofia-sip-ua/nua/nua_tag.h -1 +3
+
+ * Added nua_call_model @page.
+
+ M ./libsofia-sip-ua/nua/nua.docs -1 +355
+
+ * Used picture-mode here.
+
+ M ./libsofia-sip-ua/nua/nua.docs -227 +227
+
+ * Fixed nua_set_hparams() documentation.
+
+ M ./libsofia-sip-ua/nua/nua.c -1 +1
+
+ * Exposed struct event_s as nua_event_data_t.
+ Replaced clumsy nua_info_event() with nua_event_data(). Added tests for new
+ function.
+
+ M ./libsofia-sip-ua/nua/nua.c -31 +6
+ M ./libsofia-sip-ua/nua/nua.h -10 +14
+ M ./libsofia-sip-ua/nua/nua_stack.h -10
+ M ./libsofia-sip-ua/nua/test_nua.c -60 +182
+
+ * Fixed nua_set_hparams()/nua_get_hparams().
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -4 +6
+ M ./libsofia-sip-ua/nua/test_nua.c -6 +5
+
+ * nua_set_(h)params() now also returns an event.
+
+ M ./libsofia-sip-ua/nua/nua.h -1 +1
+ M ./libsofia-sip-ua/nua/nua_stack.c -13 +33
+
+ * Removed superfluous tags from nua_tag.h and from documentation.
+
+ M ./libsofia-sip-ua/nua/nua.c -21 +19
+ M ./libsofia-sip-ua/nua/nua_tag.c -1
+ M ./libsofia-sip-ua/nua/nua_tag.h -19
+
+ * Renamed nua_set/get_handle_params() as nua_set/get_hparams().
+
+ M ./libsofia-sip-ua/nua/nua.c -4 +2
+ M ./libsofia-sip-ua/nua/nua.h -3 +3
+ M ./libsofia-sip-ua/nua/test_nua.c -2 +2
+
+ * Added test for nua_set_params() and nua_get_params().
+
+ M ./libsofia-sip-ua/nua/test_nua.c -75 +420
+
+ * Fixed ua_set_params(), added SIPTAG_FROM_STR() to ua_get_params().
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -19 +23
+
+ * Fixed prototypes of nua_save_event() and nua_info_event().
+
+ M ./libsofia-sip-ua/nua/nua.c -1 +1
+ M ./libsofia-sip-ua/nua/nua.h -2 +2
+
+ * Using nua_any_refresher.
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -7 +9
+
+ * Fixed user_agent handling in ua_set_params()
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -2 +2
+
+ * Added NUTAG_RETRY_COUNT() and NUTAG_MAX_SUBSCRIPTIONS().
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -4 +4
+ M ./libsofia-sip-ua/nua/nua_tag.c -1 +4
+ M ./libsofia-sip-ua/nua/nua_tag.h -4 +54
+
+ * Added nua_set_handle_params() and nua_get_handle_params().
+ Revised the internal handling of parameters. They can be now set at handle
+ or user agent level. Once a parameter is set at handle level, changes at
+ user agent level does modify its value within a handle.
+
+ M ./libsofia-sip-ua/nua/nua.c -7 +90
+ M ./libsofia-sip-ua/nua/nua.h -1 +8
+ M ./libsofia-sip-ua/nua/nua_common.c +2
+ M ./libsofia-sip-ua/nua/nua_stack.c -378 +486
+ M ./libsofia-sip-ua/nua/nua_stack.h -64 +113
+
+ * Silenced test run.
+ Disabled debug output from nua functions getting invalid input during test
+ run.
+
+ M ./libsofia-sip-ua/nua/nua.c -2 +2
+ M ./libsofia-sip-ua/nua/test_nua.c -5 +10
+
+2005-10-04 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * nua.h (nua_invite_respond): Removed, no implementation
+ available.
+
+2005-10-04 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Fixed soa_set_params() in respond_to_invite().
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -1 +1
+
+2005-10-03 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Added soa_set_params() to respond_to_invite().
+
+ M ./libsofia-sip-ua/nua/nua_stack.c +3
+
+ * Added API for saving nua events.
+
+ M ./libsofia-sip-ua/nua/nua.c -4 +80
+ M ./libsofia-sip-ua/nua/nua.h +20
+ M ./libsofia-sip-ua/nua/nua_stack.h +2
+
+2005-09-29 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Added nua_callstate_name().
+
+ M ./libsofia-sip-ua/nua/nua_common.c +17
+ M ./libsofia-sip-ua/nua/nua_tag.h +3
+
+ * Responding with 504 if 100rel times out.
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -2 +2
+
+ * Using SOATAG_ACTIVE_*.
+
+ M ./libsofia-sip-ua/nua/nua_stack.h -8 +8
+
+ * Using offer/answer tags.
+
+ M ./libsofia-sip-ua/nua/nua_stack.c +11
+
+ * Commenting.
+
+ M ./libsofia-sip-ua/nua/nua_tag.h +9
+
+ * Added NUTAG_OFFER_RECV(), NUTAG_ANSWER_SENT(), NUTAG_OFFER_SENT(),
+ NUTAG_ANSWER_RECV().
+
+ M ./libsofia-sip-ua/nua/nua_tag.c +4
+ M ./libsofia-sip-ua/nua/nua_tag.h +64
+
+ * Using SOATAG_ACTIVE_*().
+
+ M ./libsofia-sip-ua/nua/nua_tag.c -3
+ M ./libsofia-sip-ua/nua/nua_tag.h -91 +32
+
+ * Updated signal_call_state_change() to take more versatile args.
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -302 +375
+
+ * Added NUTAG_CALLSTATE(), enum nua_callstate.
+
+ M ./libsofia-sip-ua/nua/nua_stack.h -20 +8
+ M ./libsofia-sip-ua/nua/nua_tag.c +1
+ M ./libsofia-sip-ua/nua/nua_tag.h -1 +38
+
+ * Added sdp_session_t and SDP_MIME_TYPE.
+
+ M ./libsofia-sip-ua/nua/nua_stack.c +9
+
+ * Moved nua_event_name() to nua_common.c
+
+ M ./libsofia-sip-ua/nua/nua.h +1
+ M ./libsofia-sip-ua/nua/nua_common.c +62
+ M ./libsofia-sip-ua/nua/nua_stack.c -58
+
+ * Removed SRTP things (they are in soa).
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -10
+ M ./libsofia-sip-ua/nua/nua_stack.h -3
+
+ * Added nua_unpublish()
+
+ M ./libsofia-sip-ua/nua/nua.c -4 +28
+ M ./libsofia-sip-ua/nua/nua.h +1
+ M ./libsofia-sip-ua/nua/nua_stack.c +1
+
+2005-09-28 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Including <soa_tag.h> in <nua_tag.h>.
+
+ M ./libsofia-sip-ua/nua/nua_tag.h -3 +3
+
+ * Compiled with new soa.
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -63 +61
+
+ * Do not pass soa handle to application.
+
+ M ./libsofia-sip-ua/nua/nua_stack.c -3 +3
+
+2005-09-23 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * nua_stack.c: Fix delivering nua_i_active.
+
+2005-09-22 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * nua.docs: Updated event documentation.
+
+ * nua_stack.c: Unused nua_i_terminate event removed.
+
+ * nua_tag.h: Removed NUTAG_MEDIA_SUBSYSTEM.
+
+ * nua.h: Added nua_i_state_change event. Removed
+ nua_i_media_update (replaced by nua_i_state_change).
+
+2005-09-21 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * nua_stack.h, nua_common.c, nua.c: Removed obsolete
+ code related to old media subsystem interface (HAVE_MSS).
+ Added nua_i_media_update event. Removed code related
+ to ring-tone generation (HAVE_HERBIE).
+
+2005-09-20 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * nua.h, nua.c: Removed implementation for obsolete media
+ param functions. Added dummy implementations that print
+ a warning to users of the removed interfaces.
+
+ * nua_stack.c: Removed obsolete media param code.
+
+2005-07-18 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * Initial import of the module to Sofia-SIP tree.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/Doxyfile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/Doxyfile Thu Dec 21 01:30:28 2006
@@ -0,0 +1,35 @@
+PROJECT_NAME = "nua"
+OUTPUT_DIRECTORY = ../docs/html/nua
+
+INPUT = nua.docs . sofia-sip
+
+ at INCLUDE = ../docs/Doxyfile.conf
+
+TAGFILES += ../docs/docs.doxytags=../docs
+TAGFILES += ../docs/su.doxytags=../su
+TAGFILES += ../docs/ipt.doxytags=../ipt
+TAGFILES += ../docs/bnf.doxytags=../bnf
+TAGFILES += ../docs/url.doxytags=../url
+TAGFILES += ../docs/msg.doxytags=../msg
+TAGFILES += ../docs/sip.doxytags=../sip
+TAGFILES += ../docs/sresolv.doxytags=../sresolv
+TAGFILES += ../docs/tport.doxytags=../tport
+TAGFILES += ../docs/nta.doxytags=../nta
+TAGFILES += ../docs/soa.doxytags=../soa
+TAGFILES += ../docs/nea.doxytags=../nea
+TAGFILES += ../docs/sdp.doxytags=../sdp
+
+GENERATE_TAGFILE = ../docs/nua.doxytags
+
+ALIASES += CFILE="@internal @file" IFILE="@internal @file"
+
+ALIASES += nua="@ref index \"nua\""
+# When GENERATE_TAGFILE=YES, we should use \ref main
+#ALIASES += nua="@ref main \"nua\""
+
+ALIASES += NUA_EVENT="@var nua_event_e::"
+ALIASES += END_NUA_EVENT="@par "
+
+VERBATIM_HEADERS = NO
+
+ at INCLUDE = ../sip/sip.doxyaliases
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/Makefile.am Thu Dec 21 01:30:28 2006
@@ -0,0 +1,101 @@
+#
+# Makefile.am for nua module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+INCLUDES = -I$(srcdir)/../bnf -I../bnf \
+ -I$(srcdir)/../ipt -I../ipt \
+ -I$(srcdir)/../iptsec -I../iptsec \
+ -I$(srcdir)/../http -I../http \
+ -I$(srcdir)/../msg -I../msg \
+ -I$(srcdir)/../nea -I../nea \
+ -I$(srcdir)/../nta -I../nta \
+ -I$(srcdir)/../nth -I../nth \
+ -I$(srcdir)/../sdp -I../sdp \
+ -I$(srcdir)/../sip -I../sip \
+ -I$(srcdir)/../soa -I../soa \
+ -I$(srcdir)/../tport -I../tport \
+ -I$(srcdir)/../stun -I../stun \
+ -I$(srcdir)/../url -I../url \
+ -I$(srcdir)/../su -I../su
+
+# ----------------------------------------------------------------------
+# Build targets
+
+noinst_LTLIBRARIES = libnua.la
+
+check_PROGRAMS = test_nua
+
+TESTS = test_nua
+
+CLEANFILES = tmp_sippasswd.??????
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+
+BUILT_SOURCES = nua_tag_ref.c
+
+nobase_include_sofia_HEADERS = \
+ sofia-sip/nua.h sofia-sip/nua_tag.h
+
+libnua_la_SOURCES = nua.c nua_stack.h nua_common.c nua_stack.c \
+ nua_extension.c \
+ nua_dialog.c nua_dialog.h \
+ outbound.c outbound.h \
+ nua_params.c nua_params.h \
+ nua_register.c nua_registrar.c \
+ nua_session.c nua_options.c \
+ nua_message.c nua_publish.c nua_subnotref.c \
+ nua_notifier.c \
+ nua_event_server.c \
+ nua_tag.c nua_tag_ref.c
+
+COVERAGE_INPUT = $(libnua_la_SOURCES) $(include_sofia_HEADERS)
+
+LDADD = libnua.la \
+ ../iptsec/libiptsec.la \
+ ../ipt/libipt.la \
+ ../nea/libnea.la \
+ ../nta/libnta.la \
+ ../sresolv/libsresolv.la \
+ ../tport/libtport.la \
+ ../stun/libstun.la \
+ ../soa/libsoa.la \
+ ../sdp/libsdp.la \
+ ../sip/libsip.la \
+ ../http/libhttp.la \
+ ../msg/libmsg.la \
+ ../url/liburl.la \
+ ../bnf/libbnf.la \
+ ../su/libsu.la
+
+test_nua_LDFLAGS = -static
+
+test_nua_SOURCES = test_nua.c test_nua.h test_ops.c \
+ test_init.c \
+ test_nua_api.c test_nua_params.c \
+ test_register.c test_basic_call.c \
+ test_call_reject.c test_cancel_bye.c \
+ test_call_hold.c test_session_timer.c \
+ test_refer.c test_100rel.c \
+ test_simple.c test_sip_events.c \
+ test_extension.c \
+ test_proxy.h test_proxy.c \
+ test_nat.h test_nat.c test_nat_tags.c
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+
+EXTRA_DIST = Doxyfile nua.docs $(BUILT_SOURCES)
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+
+include ../sofia.am
+
+TAG_DLL_FLAGS = LIST=nua_tag_list
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/Makefile.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1,799 @@
+# 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.
+
+ at SET_MAKE@
+
+#
+# Makefile.am for nua module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+# common Makefile targets for libsofia-sip-ua modules
+# ---------------------------------------------------
+
+
+SOURCES = $(libnua_la_SOURCES) $(test_nua_SOURCES)
+
+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 = test_nua$(EXEEXT)
+DIST_COMMON = $(nobase_include_sofia_HEADERS) $(srcdir)/../sofia.am \
+ $(srcdir)/Makefile.am $(srcdir)/Makefile.in ChangeLog
+subdir = libsofia-sip-ua/nua
+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 =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libnua_la_LIBADD =
+am_libnua_la_OBJECTS = nua.lo nua_common.lo nua_stack.lo \
+ nua_extension.lo nua_dialog.lo outbound.lo nua_params.lo \
+ nua_register.lo nua_registrar.lo nua_session.lo nua_options.lo \
+ nua_message.lo nua_publish.lo nua_subnotref.lo nua_notifier.lo \
+ nua_event_server.lo nua_tag.lo nua_tag_ref.lo
+libnua_la_OBJECTS = $(am_libnua_la_OBJECTS)
+am_test_nua_OBJECTS = test_nua.$(OBJEXT) test_ops.$(OBJEXT) \
+ test_init.$(OBJEXT) test_nua_api.$(OBJEXT) \
+ test_nua_params.$(OBJEXT) test_register.$(OBJEXT) \
+ test_basic_call.$(OBJEXT) test_call_reject.$(OBJEXT) \
+ test_cancel_bye.$(OBJEXT) test_call_hold.$(OBJEXT) \
+ test_session_timer.$(OBJEXT) test_refer.$(OBJEXT) \
+ test_100rel.$(OBJEXT) test_simple.$(OBJEXT) \
+ test_sip_events.$(OBJEXT) test_extension.$(OBJEXT) \
+ test_proxy.$(OBJEXT) test_nat.$(OBJEXT) \
+ test_nat_tags.$(OBJEXT)
+test_nua_OBJECTS = $(am_test_nua_OBJECTS)
+test_nua_LDADD = $(LDADD)
+test_nua_DEPENDENCIES = libnua.la ../iptsec/libiptsec.la \
+ ../ipt/libipt.la ../nea/libnea.la ../nta/libnta.la \
+ ../sresolv/libsresolv.la ../tport/libtport.la \
+ ../stun/libstun.la ../soa/libsoa.la ../sdp/libsdp.la \
+ ../sip/libsip.la ../http/libhttp.la ../msg/libmsg.la \
+ ../url/liburl.la ../bnf/libbnf.la ../su/libsu.la
+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 = $(libnua_la_SOURCES) $(test_nua_SOURCES)
+DIST_SOURCES = $(libnua_la_SOURCES) $(test_nua_SOURCES)
+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|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(include_sofiadir)"
+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)/../bnf -I../bnf \
+ -I$(srcdir)/../ipt -I../ipt \
+ -I$(srcdir)/../iptsec -I../iptsec \
+ -I$(srcdir)/../http -I../http \
+ -I$(srcdir)/../msg -I../msg \
+ -I$(srcdir)/../nea -I../nea \
+ -I$(srcdir)/../nta -I../nta \
+ -I$(srcdir)/../nth -I../nth \
+ -I$(srcdir)/../sdp -I../sdp \
+ -I$(srcdir)/../sip -I../sip \
+ -I$(srcdir)/../soa -I../soa \
+ -I$(srcdir)/../tport -I../tport \
+ -I$(srcdir)/../stun -I../stun \
+ -I$(srcdir)/../url -I../url \
+ -I$(srcdir)/../su -I../su
+
+
+# ----------------------------------------------------------------------
+# Build targets
+noinst_LTLIBRARIES = libnua.la
+TESTS = test_nua
+CLEANFILES = tmp_sippasswd.??????
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+BUILT_SOURCES = nua_tag_ref.c
+nobase_include_sofia_HEADERS = \
+ sofia-sip/nua.h sofia-sip/nua_tag.h
+
+libnua_la_SOURCES = nua.c nua_stack.h nua_common.c nua_stack.c \
+ nua_extension.c \
+ nua_dialog.c nua_dialog.h \
+ outbound.c outbound.h \
+ nua_params.c nua_params.h \
+ nua_register.c nua_registrar.c \
+ nua_session.c nua_options.c \
+ nua_message.c nua_publish.c nua_subnotref.c \
+ nua_notifier.c \
+ nua_event_server.c \
+ nua_tag.c nua_tag_ref.c
+
+COVERAGE_INPUT = $(libnua_la_SOURCES) $(include_sofia_HEADERS)
+LDADD = libnua.la \
+ ../iptsec/libiptsec.la \
+ ../ipt/libipt.la \
+ ../nea/libnea.la \
+ ../nta/libnta.la \
+ ../sresolv/libsresolv.la \
+ ../tport/libtport.la \
+ ../stun/libstun.la \
+ ../soa/libsoa.la \
+ ../sdp/libsdp.la \
+ ../sip/libsip.la \
+ ../http/libhttp.la \
+ ../msg/libmsg.la \
+ ../url/liburl.la \
+ ../bnf/libbnf.la \
+ ../su/libsu.la
+
+test_nua_LDFLAGS = -static
+test_nua_SOURCES = test_nua.c test_nua.h test_ops.c \
+ test_init.c \
+ test_nua_api.c test_nua_params.c \
+ test_register.c test_basic_call.c \
+ test_call_reject.c test_cancel_bye.c \
+ test_call_hold.c test_session_timer.c \
+ test_refer.c test_100rel.c \
+ test_simple.c test_sip_events.c \
+ test_extension.c \
+ test_proxy.h test_proxy.c \
+ test_nat.h test_nat.c test_nat_tags.c
+
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+EXTRA_DIST = Doxyfile nua.docs $(BUILT_SOURCES)
+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
+TAG_DLL_FLAGS = LIST=nua_tag_list
+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/nua/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu libsofia-sip-ua/nua/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-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
+libnua.la: $(libnua_la_OBJECTS) $(libnua_la_DEPENDENCIES)
+ $(LINK) $(libnua_la_LDFLAGS) $(libnua_la_OBJECTS) $(libnua_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
+test_nua$(EXEEXT): $(test_nua_OBJECTS) $(test_nua_DEPENDENCIES)
+ @rm -f test_nua$(EXEEXT)
+ $(LINK) $(test_nua_LDFLAGS) $(test_nua_OBJECTS) $(test_nua_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nua.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nua_common.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nua_dialog.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nua_event_server.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nua_extension.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nua_message.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nua_notifier.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nua_options.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nua_params.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nua_publish.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nua_register.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nua_registrar.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nua_session.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nua_stack.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nua_subnotref.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nua_tag.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nua_tag_ref.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/outbound.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_100rel.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_basic_call.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_call_hold.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_call_reject.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_cancel_bye.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_extension.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_init.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_nat.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_nat_tags.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_nua.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_nua_api.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_nua_params.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_ops.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_proxy.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_refer.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_register.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_session_timer.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_simple.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_sip_events.Po at am__quote@
+
+.c.o:
+ at am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+ at am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ at am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at 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 $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(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:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+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-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-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-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-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-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-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) $<
+
+ at ENABLE_COVERAGE_TRUE@coverage:
+ at 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)
+# 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:
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1159 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@file nua.c High-Level User Agent Library - "nua" Implementation.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Kai Vehmanen <Kai.Vehmanen at nokia.com>
+ * @author Pasi Rinne-Rahkola
+ *
+ * @date Created: Wed Feb 14 18:32:58 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <sofia-sip/su_tag.h>
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/su_tagarg.h>
+
+#include <sofia-sip/su_tag_io.h>
+
+#define SU_LOG (nua_log)
+#include <sofia-sip/su_debug.h>
+
+#define SU_ROOT_MAGIC_T struct nua_s
+#define SU_MSG_ARG_T struct event_s
+#define NUA_SAVED_EVENT_T su_msg_t *
+
+#include <sofia-sip/sip_status.h>
+#include <sofia-sip/sip_header.h>
+#include <sofia-sip/nta.h>
+
+#include "sofia-sip/nua.h"
+#include "sofia-sip/nua_tag.h"
+#include "nua_stack.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+
+/* From AM_INIT/AC_INIT in our "config.h" */
+char const nua_version[] = VERSION;
+
+/**Environment variable determining the debug log level for @nua module.
+ *
+ * The NUA_DEBUG environment variable is used to determine the debug logging
+ * level for @nua module. The default level is 3.
+ *
+ * @sa <sofia-sip/su_debug.h>, nua_log, SOFIA_DEBUG
+ */
+extern char const NUA_DEBUG[];
+
+#ifndef SU_DEBUG
+#define SU_DEBUG 3
+#endif
+
+/**Debug log for @nua module.
+ *
+ * The nua_log is the log object used by @nua module. The level of
+ * #nua_log is set using #NUA_DEBUG environment variable.
+ */
+su_log_t nua_log[] = { SU_LOG_INIT("nua", "NUA_DEBUG", SU_DEBUG) };
+
+/**Create a @nua agent.
+ *
+ * This function creates a Sofia-SIP User Agent stack object (@nua) and
+ * initializes its parameters by given tagged values.
+ *
+ * @param root Pointer to a root object
+ * @param callback Pointer to event callback function
+ * @param magic Pointer to callback context
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @retval !=NULL a pointer to a @nua stack object \n
+ * @retval NULL upon an error
+ *
+ * @par Related tags:
+ * NUTAG_PROXY() \n
+ * NUTAG_URL() \n
+ * NUTAG_SIPS_URL() \n
+ * NUTAG_SIP_PARSER() \n
+ * NUTAG_UICC() \n
+ * NUTAG_CERTIFICATE_DIR() \n
+ * and all tags listed in nua_set_params(), \n
+ * and all relevant NTATAG_* are passed to NTA.
+ *
+ * @note
+ * From the @VERSION_1_12_2 all the nua_set_params() tags are processed.
+ * Previously all nutags except NUTAG_SOA_NAME() and NUTAG_MEDIA_ENABLE()
+ * were ignored.
+ *
+ * @note
+ * Both the NUTAG_URL() and NUTAG_SIPS_URL() are used to pass arguments to
+ * nta_agent_add_tport().
+ *
+ * @par Events:
+ * none
+ *
+ * @sa nua_shutdown(), nua_destroy(), nua_handle()
+ */
+nua_t *nua_create(su_root_t *root,
+ nua_callback_f callback,
+ nua_magic_t *magic,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ nua_t *nua = NULL;
+
+ enter;
+
+ if (callback == NULL)
+ return (void)(errno = EFAULT), NULL;
+
+ if (root == NULL)
+ return (void)(errno = EFAULT), NULL;
+
+ if ((nua = su_home_new(sizeof(*nua)))) {
+ ta_list ta;
+
+ su_home_threadsafe(nua->nua_home);
+ nua->nua_api_root = root;
+
+ ta_start(ta, tag, value);
+
+ nua->nua_args = tl_adup(nua->nua_home, ta_args(ta));
+
+ su_task_copy(nua->nua_client, su_root_task(root));
+
+ /* XXX: where to put this in the nua_server case? */
+#if HAVE_SMIME /* Start NRC Boston */
+ nua->sm = sm_create();
+#endif /* End NRC Boston */
+
+#ifndef NUA_SERVER
+ if (su_clone_start(root,
+ nua->nua_clone,
+ nua,
+ nua_stack_init,
+ nua_stack_deinit) == SU_SUCCESS) {
+ su_task_copy(nua->nua_server, su_clone_task(nua->nua_clone));
+ nua->nua_callback = callback;
+ nua->nua_magic = magic;
+ }
+ else {
+ su_home_unref(nua->nua_home);
+ nua = NULL;
+ }
+#endif
+
+ ta_end(ta);
+ }
+
+ return nua;
+}
+
+/* nua_shutdown() is documented with nua_stack_shutdown() */
+
+void nua_shutdown(nua_t *nua)
+{
+ enter;
+
+ if (nua)
+ nua->nua_shutdown_started = 1;
+ nua_signal(nua, NULL, NULL, 1, nua_r_shutdown, 0, NULL, TAG_END());
+}
+
+/** Destroy the @nua stack.
+ *
+ * Before calling nua_destroy() the application
+ * should call nua_shutdown and wait for successful #nua_r_shutdown event.
+ * Shuts down and destroys the @nua stack. Ongoing calls, registrations,
+ * and subscriptions are left as they are.
+ *
+ * @param nua Pointer to @nua stack object
+ *
+ * @return
+ * nothing
+ *
+ * @par Related tags:
+ * none
+ *
+ * @par Events:
+ * none
+ *
+ * @sa nua_shutdown(), nua_create(), nua_handle_destroy(), nua_handle_unref()
+ */
+void nua_destroy(nua_t *nua)
+{
+ enter;
+
+ if (nua) {
+ if (!nua->nua_shutdown_final) {
+ SU_DEBUG_0(("nua_destroy(%p): FATAL: nua_shutdown not completed\n", nua));
+ assert(nua->nua_shutdown);
+ return;
+ }
+
+ su_task_deinit(nua->nua_server);
+ su_task_deinit(nua->nua_client);
+
+ su_clone_wait(nua->nua_api_root, nua->nua_clone);
+#if HAVE_SMIME /* Start NRC Boston */
+ sm_destroy(nua->sm);
+#endif /* End NRC Boston */
+ su_home_unref(nua->nua_home);
+ }
+}
+
+/** Fetch callback context from nua.
+ *
+ * @param nua Pointer to @nua stack object
+ *
+ * @return Callback context pointer.
+ *
+ * @NEW_1_12_4.
+ */
+nua_magic_t *nua_magic(nua_t *nua)
+{
+ return nua ? nua->nua_magic : NULL;
+}
+
+/** Obtain default operation handle of the @nua stack object.
+ *
+ * A default operation can be used for operations where the
+ * ultimate result is not important or can be discarded.
+ *
+ * @param nua Pointer to @nua stack object
+ *
+ * @retval !=NULL Pointer to @nua operation handle
+ * @retval NULL No default operation exists
+ *
+ * @par Related tags:
+ * none
+ *
+ * @par Events:
+ * none
+ *
+ */
+nua_handle_t *nua_default(nua_t *nua)
+{
+ return nua ? nua->nua_handles : NULL;
+}
+
+/** Create an operation handle
+ *
+ * Allocates a new operation handle and associated storage.
+ *
+ * @param nua Pointer to @nua stack object
+ * @param hmagic Pointer to callback context
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @retval !=NULL Pointer to operation handle
+ * @retval NULL Creation failed
+ *
+ * @par Related tags:
+ * Duplicates the provided tags for use with every operation. Note that
+ * NUTAG_URL() is converted to SIPTAG_TO() if there is no SIPTAG_TO().
+ * And also vice versa, request-URI is taken from SIPTAG_TO() if there
+ * is no NUTAG_URL(). Note that certain SIP headers cannot be saved with
+ * the handle. They include @ContentLength, @CSeq, @RSeq, @RAck, and
+ * @Timestamp.
+ *
+ * @par
+ * nua_handle() accepts all the tags accepted by nua_set_hparams(), too.
+ *
+ *
+ * @par Events:
+ * none
+ *
+ * @sa nua_handle_bind(), nua_handle_destroy(), nua_handle_ref(),
+ * nua_handle_unref().
+ */
+nua_handle_t *nua_handle(nua_t *nua, nua_hmagic_t *hmagic,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ nua_handle_t *nh = NULL;
+
+ if (nua) {
+ ta_list ta;
+
+ ta_start(ta, tag, value);
+
+ nh = nh_create_handle(nua, hmagic, ta_args(ta));
+
+ if (nh)
+ nh->nh_ref_by_user = 1;
+
+ ta_end(ta);
+ }
+
+ return nh;
+}
+
+/** Bind a callback context to an operation handle.
+ *
+ * @param nh Pointer to operation handle
+ * @param hmagic Pointer to callback context
+ *
+ * @return
+ * nothing
+ *
+ * @par Related tags:
+ * none
+ *
+ * @par Events:
+ * none
+ */
+void nua_handle_bind(nua_handle_t *nh, nua_hmagic_t *hmagic)
+{
+ enter;
+
+ if (NH_IS_VALID(nh))
+ nh->nh_magic = hmagic;
+}
+
+/** Fetch a callback context from an operation handle.
+ *
+ * @param nh Pointer to operation handle
+ *
+ * @return
+ * Pointer to callback context
+ *
+ * @par Related tags:
+ * none
+ *
+ * @par Events:
+ * none
+ *
+ * @NEW_1_12_4.
+ */
+nua_hmagic_t *nua_handle_magic(nua_handle_t *nh)
+{
+ nua_hmagic_t *magic = NULL;
+ enter;
+
+ if (NH_IS_VALID(nh))
+ magic = nh->nh_magic;
+
+ return magic;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/** Check if operation handle is used for INVITE
+ *
+ * Check if operation handle has been used with either outgoing or incoming
+ * INVITE request.
+ *
+ * @param nh Pointer to operation handle
+ *
+ * @retval 0 no invite in operation or operation handle is invalid
+ * @retval 1 operation has invite
+ *
+ * @par Related tags:
+ * none
+ *
+ * @par Events:
+ * none
+ */
+int nua_handle_has_invite(nua_handle_t const *nh)
+{
+ return nh ? nh->nh_has_invite : 0;
+}
+
+/**Check if operation handle has active event subscriptions.
+ *
+ * Active subscription can be established either by nua_subscribe() or
+ * nua_refer() calls.
+ *
+ * @param nh Pointer to operation handle
+ *
+ * @retval 0 no event subscriptions in operation or
+ * operation handle is invalid
+ * @retval !=0 operation has event subscriptions
+ *
+ * @par Related tags:
+ * none
+ *
+ * @par Events:
+ * none
+ */
+int nua_handle_has_events(nua_handle_t const *nh)
+{
+ return nh ? nh->nh_ds->ds_has_events : 0;
+}
+
+/** Check if operation handle has active registrations
+ *
+ * A registration is active when either when a REGISTER operation is going
+ * on or when it has successfully completed so that @nua stack is expected to
+ * refresh the registration in the future. Normally, a handle has active
+ * registration after nua_register() until nua_unregister() completes,
+ * unless the initial nua_register() had either expiration time of 0 or it
+ * had SIPTAG_CONTACT(NULL) as an argument.
+ *
+ * @param nh Pointer to operation handle
+ *
+ * @retval 0 no active registration in operation or
+ * operation handle is invalid
+ * @retval 1 operation has registration
+ *
+ * @par Related tags:
+ * none
+ *
+ * @par Events:
+ * none
+ *
+ * @sa nua_register(), nua_unregister(), #nua_r_register, #nua_r_unregister
+ */
+int nua_handle_has_registrations(nua_handle_t const *nh)
+{
+ return nh && nh->nh_ds->ds_has_register;
+}
+
+/** Check if operation handle has been used with outgoing SUBSCRIBE of REFER request.
+ *
+ * @param nh Pointer to operation handle
+ *
+ * @retval 0 no active subscription in operation or
+ * operation handle is invalid
+ * @retval 1 operation has subscription.
+ *
+ * @par Related tags:
+ * none
+ *
+ * @par Events:
+ * none
+ */
+int nua_handle_has_subscribe(nua_handle_t const *nh)
+{
+ return nh ? nh->nh_has_subscribe : 0;
+}
+
+/** Check if operation handle has been used with nua_register() or nua_unregister().
+ *
+ * @param nh Pointer to operation handle
+ *
+ * @retval 0 no active register in operation or operation handle is invalid
+ * @retval 1 operation has been used with nua_register() or nua-unregister()
+ *
+ * @par Related tags:
+ * none
+ *
+ * @par Events:
+ * none
+ */
+int nua_handle_has_register(nua_handle_t const *nh)
+{
+ return nh ? nh->nh_has_register : 0;
+}
+
+/** Check if operation handle has an active call
+ *
+ * @param nh Pointer to operation handle
+ *
+ * @retval 0 no active call in operation or operation handle is invalid
+ * @retval 1 operation has established call or pending call request.
+ *
+ * @par Related tags:
+ * none
+ *
+ * @par Events:
+ * none
+ */
+int nua_handle_has_active_call(nua_handle_t const *nh)
+{
+ return nh ? nh->nh_active_call : 0;
+}
+
+/** Check if operation handle has a call on hold
+ *
+ * Please note that this status is not affected by remote end putting
+ * this end on hold. Remote end can put each media separately on hold
+ * and status is reflected on SOATAG_ACTIVE_AUDIO(), SOATAG_ACTIVE_VIDEO()
+ * and SOATAG_ACTIVE_CHAT() tag values in #nua_i_state event.
+ *
+ * @param nh Pointer to operation handle
+ *
+ * @retval 0 if no call on hold in operation or operation handle is invalid
+ * @retval 1 if operation has call on hold, for example nua_invite() or
+ * nua_update() has been called with SOATAG_HOLD() with non-NULL
+ * argument.
+ *
+ * @par Related tags:
+ * none
+ *
+ * @par Events:
+ * none
+ */
+int nua_handle_has_call_on_hold(nua_handle_t const *nh)
+{
+ return nh ? nh->nh_hold_remote : 0;
+}
+
+/** Get the remote address (From/To header) of operation handle
+ *
+ * Remote address is used as To header in outgoing operations and
+ * derived from From: header in incoming operations.
+ *
+ * @param nh Pointer to operation handle
+ *
+ * @retval NULL no remote address for operation or operation handle invalid
+ * @retval !=NULL pointer to remote address for operation
+ *
+ * @par Related tags:
+ * none
+ *
+ * @par Events:
+ * none
+ */
+sip_to_t const *nua_handle_remote(nua_handle_t const *nh)
+{
+ return nh ? nh->nh_ds->ds_remote : NULL;
+}
+
+/** Get the local address (From/To header) of operation handle
+ *
+ * Local address is used as From header in outgoing operations and
+ * derived from To: header in incoming operations.
+ *
+ * @param nh Pointer to operation handle
+ *
+ * @retval NULL no local address for operation or operation handle invalid
+ * @retval !=NULL pointer to local address for operation
+ *
+ * @par Related tags:
+ * none
+ *
+ * @par Events:
+ * none
+ */
+sip_to_t const *nua_handle_local(nua_handle_t const *nh)
+{
+ return nh ? nh->nh_ds->ds_local : NULL;
+}
+
+/* Documented with nua_stack_set_params() */
+void nua_set_params(nua_t *nua, tag_type_t tag, tag_value_t value, ...)
+{
+ ta_list ta;
+ ta_start(ta, tag, value);
+
+ enter;
+
+ nua_signal(nua, NULL, NULL, 0, nua_r_set_params, 0, NULL, ta_tags(ta));
+
+ ta_end(ta);
+}
+
+/* Documented with nua_stack_get_params() */
+void nua_get_params(nua_t *nua, tag_type_t tag, tag_value_t value, ...)
+{
+ ta_list ta;
+ ta_start(ta, tag, value);
+
+ enter;
+
+ nua_signal(nua, NULL, NULL, 0, nua_r_get_params, 0, NULL, ta_tags(ta));
+
+ ta_end(ta);
+}
+
+#define NUA_SIGNAL(nh, event, tag, value) \
+ enter; \
+ if (NH_IS_VALID((nh))) { \
+ ta_list ta; \
+ ta_start(ta, tag, value); \
+ nua_signal((nh)->nh_nua, nh, NULL, 0, event, 0, NULL, ta_tags(ta)); \
+ ta_end(ta); \
+ } \
+ else { \
+ SU_DEBUG_1(("nua: " #event " with invalid handle %p\n", nh)); \
+ }
+
+/* Documented with nua_stack_set_params() */
+void nua_set_hparams(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+ NUA_SIGNAL(nh, nua_r_set_params, tag, value);
+}
+
+/* Documented with nua_stack_get_params() */
+void nua_get_hparams(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+ NUA_SIGNAL(nh, nua_r_get_params, tag, value);
+}
+
+/* Documented with nua_stack_register() */
+void nua_register(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+ NUA_SIGNAL(nh, nua_r_register, tag, value);
+}
+
+void nua_unregister(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+ NUA_SIGNAL(nh, nua_r_unregister, tag, value);
+}
+
+/* Documented with nua_stack_invite() */
+void nua_invite(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+ NUA_SIGNAL(nh, nua_r_invite, tag, value);
+}
+
+/* Documented with nua_stack_ack() */
+void nua_ack(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+ NUA_SIGNAL(nh, nua_r_ack, tag, value);
+}
+
+/* Documented with nua_stack_bye() */
+void nua_bye(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+ NUA_SIGNAL(nh, nua_r_bye, tag, value);
+}
+
+/* Documented with nua_stack_cancel() */
+void nua_cancel(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+ NUA_SIGNAL(nh, nua_r_cancel, tag, value);
+}
+
+/* Documented with nua_stack_options() */
+void nua_options(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+ NUA_SIGNAL(nh, nua_r_options, tag, value);
+}
+
+/* Documented with nua_stack_message() */
+void nua_message(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+ NUA_SIGNAL(nh, nua_r_message, tag, value);
+}
+
+/* Documented with nua_stack_method() */
+void nua_method(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+ NUA_SIGNAL(nh, nua_r_method, tag, value);
+}
+
+/** Send a chat message.
+ *
+ * A chat channel can be established during call setup using "message" media.
+ * An active chat channel is indicated using #nua_i_state event containing
+ * SOATAG_ACTIVE_CHAT() tag. Chat messages can be sent using this channel with
+ * nua_chat() function. Currently this is implemented using SIP MESSAGE
+ * requests but in future MSRP (message session protocol) will replace it.
+*
+ * @param nh Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return
+ * nothing
+ *
+ * @par Related Tags:
+ * SIPTAG_CONTENT_TYPE() \n
+ * SIPTAG_PAYLOAD() \n
+ * SIPTAG_FROM() \n
+ * SIPTAG_TO() \n
+ * Use of other SIP tags is deprecated
+ *
+ * @par Events:
+ * #nua_r_chat
+ */
+void nua_chat(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+ NUA_SIGNAL(nh, nua_r_chat, tag, value);
+}
+
+/* Documented with nua_stack_subscribe() */
+void nua_subscribe(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+ NUA_SIGNAL(nh, nua_r_subscribe, tag, value);
+}
+
+/* Documented with nua_stack_subscribe() */
+void nua_unsubscribe(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+ NUA_SIGNAL(nh, nua_r_unsubscribe, tag, value);
+}
+
+/* Documented with nua_stack_notify() */
+void nua_notify(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+ NUA_SIGNAL(nh, nua_r_notify, tag, value);
+}
+
+/* nua_r_notify is documented with process_response_to_notify() */
+
+/** Create an event server.
+ *
+ * This function create an event server taking care of sending NOTIFY
+ * requests and responding to further SUBSCRIBE requests. The event
+ * server can accept multiple subscriptions from several sources and
+ * takes care for distributing the notifications. Unlike other functions
+ * this call only accepts the SIP tags listed below.
+ *
+ * @param nh Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return
+ * nothing
+ *
+ * @par Related Tags:
+ * NUTAG_URL() \n
+ * SIPTAG_EVENT() or SIPTAG_EVENT_STR() \n
+ * SIPTAG_CONTENT_TYPE() or SIPTAG_CONTENT_TYPE_STR() \n
+ * SIPTAG_PAYLOAD() or SIPTAG_PAYLOAD_STR() \n
+ * SIPTAG_ACCEPT() or SIPTAG_ACCEPT_STR() \n
+ *
+ * @par Events:
+ * #nua_r_notify
+ */
+void nua_notifier(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+ NUA_SIGNAL(nh, nua_r_notifier, tag, value);
+}
+
+/** Terminate an event server.
+ *
+ * Terminate an event server with matching event and content type. The event
+ * server was created earlier with nua_notifier() function.
+ *
+ * @param nh Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return
+ * nothing
+ *
+ * @par Related Tags:
+ * SIPTAG_EVENT() \n
+ * SIPTAG_CONTENT_TYPE() \n
+ * SIPTAG_PAYLOAD() \n
+ * NEATAG_REASON()
+ *
+ * @par Events:
+ * #nua_r_terminate
+ *
+ * @sa nua_notifier(), nua_authorize().
+ */
+void nua_terminate(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+ NUA_SIGNAL(nh, nua_r_terminate, tag, value);
+}
+
+/* Documented with nua_stack_refer() */
+void nua_refer(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+ NUA_SIGNAL(nh, nua_r_refer, tag, value);
+}
+
+/* Documented with nua_stack_publish() */
+void nua_publish(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+ NUA_SIGNAL(nh, nua_r_publish, tag, value);
+}
+
+/* Documented with nua_stack_publish() */
+void nua_unpublish(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+ NUA_SIGNAL(nh, nua_r_unpublish, tag, value);
+}
+
+/* Documented with nua_stack_info() */
+void nua_info(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+ NUA_SIGNAL(nh, nua_r_info, tag, value);
+}
+
+/* Documented with nua_stack_prack() */
+void nua_prack(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+ NUA_SIGNAL(nh, nua_r_prack, tag, value);
+}
+
+/* Documented with nua_stack_update() */
+void nua_update(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+ NUA_SIGNAL(nh, nua_r_update, tag, value);
+}
+
+/** Authenticate an operation.
+ *
+ * - 401 / 407 response with www-authenticate header/ proxy-authenticate header
+ * - application should provide stack with username&password for each realm
+ * with NUTAG_AUTH() tag
+ * - restarts operation
+ *
+ * @param nh Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return
+ * nothing
+ *
+ * @par Related Tags:
+ * NUTAG_AUTH()
+ *
+ * @par Events:
+ * (any operation events)
+ */
+void nua_authenticate(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+ NUA_SIGNAL(nh, nua_r_authenticate, tag, value);
+}
+
+/** Authorize a subscriber.
+ *
+ * After creating a local presence server by nua_notifier(), an incoming
+ * SUBSCRIBE request causes #nua_i_subscription event. Each subscriber is
+ * identified with NEATAG_SUB() tag in the #nua_i_subscription event.
+ * Application can either authorize the subscriber with
+ * NUTAG_SUBSTATE(#nua_substate_active) or terminate the subscription with
+ * NUTAG_SUBSTATE(#nua_substate_terminated).
+ *
+ * @param nh Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return
+ * nothing
+ *
+ * @par Related Tags:
+ * NEATAG_SUB() \n
+ * NUTAG_SUBSTATE()
+ *
+ * @par Events:
+ * #nua_i_subscription
+ *
+ * @sa nua_notifier(), nua_terminate()
+ */
+void nua_authorize(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+ NUA_SIGNAL(nh, nua_r_authorize, tag, value);
+}
+
+/*# Redirect an operation. */
+void nua_redirect(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+ NUA_SIGNAL(nh, nua_r_redirect, tag, value);
+}
+
+/* Documented with nua_stack_respond() */
+
+void nua_respond(nua_handle_t *nh,
+ int status, char const *phrase,
+ tag_type_t tag, tag_value_t value,
+ ...)
+{
+ enter;
+
+ if (NH_IS_VALID(nh)) {
+ ta_list ta;
+ ta_start(ta, tag, value);
+ nua_signal(nh->nh_nua, nh, NULL, 0, nua_r_respond,
+ status, phrase, ta_tags(ta));
+ ta_end(ta);
+ }
+ else {
+ SU_DEBUG_1(("nua: respond with invalid handle %p\n", nh));
+ }
+}
+
+/** Destroy a handle
+ *
+ * Terminate the protocol state associated with an operation handle. The
+ * stack discards resources and terminates the ongoing dialog usage,
+ * sessions and transactions associated with this handle. For example, calls
+ * are terminated with BYE request. Also, the reference count for the handle
+ * is also decremented.
+ *
+ * The handles use reference counting for memory management. In order to
+ * make it more convenient for programmer, nua_handle_destroy() decreases
+ * the reference count, too.
+ *
+ * @param nh Pointer to operation handle
+ *
+ * @return
+ * nothing
+ *
+ * @par Related Tags:
+ * none
+ *
+ * @par Events:
+ * none
+ *
+ * @sa nua_handle(), nua_handle_bind(), nua_handle_ref(), nua_handle_unref(),
+ * nua_unregister(), nua_unpublish(), nua_unsubscribe(), nua_bye().
+ */
+void nua_handle_destroy(nua_handle_t *nh)
+{
+ enter;
+
+ if (NH_IS_VALID(nh) && !NH_IS_DEFAULT(nh)) {
+ nh->nh_valid = NULL; /* Events are no more delivered to appl. */
+ nua_signal(nh->nh_nua, nh, NULL, 1, nua_r_destroy, 0, NULL, TAG_END());
+ }
+}
+
+/*# Send a request to the protocol thread */
+void nua_signal(nua_t *nua, nua_handle_t *nh, msg_t *msg, int always,
+ nua_event_t event,
+ int status, char const *phrase,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ su_msg_r sumsg = SU_MSG_R_INIT;
+ size_t len, xtra, e_len, l_len = 0, l_xtra = 0;
+ ta_list ta;
+
+ if (nua == NULL || (nua->nua_shutdown_started && event != nua_r_shutdown))
+ return;
+
+ ta_start(ta, tag, value);
+
+ e_len = offsetof(event_t, e_tags);
+ len = tl_len(ta_args(ta));
+ xtra = tl_xtra(ta_args(ta), len);
+
+ if (su_msg_create(sumsg, nua->nua_server, su_task_null,
+ nua_stack_signal,
+ e_len + len + l_len + xtra + l_xtra) == 0) {
+ event_t *e = su_msg_data(sumsg);
+ tagi_t *t = e->e_tags;
+ void *b = (char *)t + len + l_len;
+
+ tagi_t *tend = (tagi_t *)b;
+ char *bend = (char *)b + xtra + l_xtra;
+
+ t = tl_dup(t, ta_args(ta), &b);
+
+ assert(tend == t); (void)tend; assert(b == bend); (void)bend;
+
+ e->e_always = always;
+ e->e_event = event;
+ e->e_nh = event == nua_r_destroy ? nh : nua_handle_ref(nh);
+ e->e_status = status;
+ e->e_phrase = phrase;
+
+ if (su_msg_send(sumsg) != 0)
+ nua_handle_unref(nh);
+ }
+ else {
+ /* XXX - we should return error code to application */
+ assert(ENOMEM == 0);
+ }
+
+ ta_end(ta);
+}
+
+/*# Receive event from protocol machine and hand it over to application */
+void nua_event(nua_t *root_magic, su_msg_r sumsg, event_t *e)
+{
+ nua_t *nua;
+ nua_handle_t *nh = e->e_nh;
+
+ enter;
+
+ if (nh) {
+ if (!nh->nh_ref_by_user && nh->nh_valid) {
+ nh->nh_ref_by_user = 1;
+ nua_handle_ref(nh);
+ }
+ }
+
+ if (!nh || !nh->nh_valid) { /* Handle has been destroyed */
+ if (nh && !NH_IS_DEFAULT(nh) && nua_handle_unref(nh)) {
+ SU_DEBUG_9(("nua(%p): freed by application\n", nh));
+ }
+ if (e->e_msg)
+ msg_destroy(e->e_msg), e->e_msg = NULL;
+ return;
+ }
+
+ nua = nh->nh_nua; assert(nua);
+
+ if (e->e_event == nua_r_shutdown && e->e_status >= 200)
+ nua->nua_shutdown_final = 1;
+
+ if (!nua->nua_callback)
+ return;
+
+ if (NH_IS_DEFAULT(nh))
+ nh = NULL;
+
+ su_msg_save(nua->nua_current, sumsg);
+
+ e->e_nh = NULL;
+
+ nua->nua_callback(e->e_event, e->e_status, e->e_phrase,
+ nua, nua->nua_magic,
+ nh, nh ? nh->nh_magic : NULL,
+ e->e_msg ? sip_object(e->e_msg) : NULL,
+ e->e_tags);
+
+ if (nh && !NH_IS_DEFAULT(nh) && nua_handle_unref(nh)) {
+ SU_DEBUG_9(("nua(%p): freed by application\n", nh));
+ }
+
+ if (!su_msg_is_non_null(nua->nua_current))
+ return;
+
+ if (e->e_msg)
+ msg_destroy(e->e_msg), e->e_msg = NULL;
+
+ su_msg_destroy(nua->nua_current);
+}
+
+/** Get current request message. @NEW_1_12_4. */
+msg_t *nua_current_request(nua_t const *nua)
+{
+ return nua && nua->nua_current ? su_msg_data(nua->nua_current)->e_msg : NULL;
+}
+
+/** Get request message from saved nua event. @NEW_1_12_4. */
+msg_t *nua_saved_event_request(nua_saved_event_t const *saved)
+{
+ return saved ? su_msg_data(saved)->e_msg : NULL;
+}
+
+/** Save nua event and its arguments */
+int nua_save_event(nua_t *nua, nua_saved_event_t return_saved[1])
+{
+ if (nua && return_saved) {
+ su_msg_save(return_saved, nua->nua_current);
+ if (su_msg_is_non_null(return_saved)) {
+ /* Remove references to tasks */
+ su_msg_remove_refs(return_saved);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/** Get event data */
+nua_event_data_t const *nua_event_data(nua_saved_event_t const saved[1])
+{
+ return saved ? su_msg_data(saved) : NULL;
+}
+
+/** Destroy saved event */
+void nua_destroy_event(nua_saved_event_t saved[1])
+{
+ if (su_msg_is_non_null(saved)) {
+ event_t *e = su_msg_data(saved);
+ nua_handle_t *nh = e->e_nh;
+
+ if (e->e_msg)
+ msg_destroy(e->e_msg), e->e_msg = NULL;
+
+ if (nh && !NH_IS_DEFAULT(nh) && nua_handle_unref(nh)) {
+ SU_DEBUG_9(("nua(%p): freed by application\n", nh));
+ }
+
+ su_msg_destroy(saved);
+ }
+}
+
+/* ---------------------------------------------------------------------- */
+
+struct nua_stack_handle_make_replaces_args {
+ sip_replaces_t *retval;
+ nua_handle_t *nh;
+ su_home_t *home;
+ int early_only;
+};
+
+static int nua_stack_handle_make_replaces_call(void *arg)
+{
+ struct nua_stack_handle_make_replaces_args *a = arg;
+
+ a->retval = nua_stack_handle_make_replaces(a->nh, a->home, a->early_only);
+
+ return 0;
+}
+
+
+/**Generate a @Replaces header for handle.
+ *
+ * @since New in @VERSION_1_12_4.
+ *
+ * @sa nua_handle_by_replaces(), @Replaces, @RFC3891, nua_refer(),
+ * #nua_i_refer, @ReferTo, nta_leg_make_replaces()
+ */
+sip_replaces_t *nua_handle_make_replaces(nua_handle_t *nh,
+ su_home_t *home,
+ int early_only)
+{
+ if (nh && nh->nh_valid && nh->nh_nua) {
+ struct nua_stack_handle_make_replaces_args a = { NULL, nh, home, early_only };
+
+ if (su_task_execute(nh->nh_nua->nua_server,
+ nua_stack_handle_make_replaces_call, (void *)&a,
+ NULL) == 0) {
+ return a.retval;
+ }
+ }
+ return NULL;
+}
+
+struct nua_stack_handle_by_replaces_args {
+ nua_handle_t *retval;
+ nua_t *nua;
+ sip_replaces_t const *r;
+};
+
+static int nua_stack_handle_by_replaces_call(void *arg)
+{
+ struct nua_stack_handle_by_replaces_args *a = arg;
+
+ a->retval = nua_stack_handle_by_replaces(a->nua, a->r);
+
+ return 0;
+}
+
+/** Obtain a new reference to an existing handle based on @Replaces header.
+ *
+ * @since New in @VERSION_1_12_4.
+ *
+ * @note
+ * You should release the reference with nua_handle_unref() when you are
+ * done with handle.
+ *
+ * @sa nua_handle_make_replaces(), @Replaces, @RFC3891, nua_refer(),
+ * #nua_i_refer, @ReferTo, nta_leg_by_replaces()
+ */
+nua_handle_t *nua_handle_by_replaces(nua_t *nua, sip_replaces_t const *r)
+{
+ if (nua) {
+ struct nua_stack_handle_by_replaces_args a = { NULL, nua, r };
+
+ if (su_task_execute(nua->nua_server,
+ nua_stack_handle_by_replaces_call, (void *)&a,
+ NULL) == 0) {
+ nua_handle_t *nh = a.retval;
+
+ if (nh && !NH_IS_DEFAULT(nh) && nh->nh_valid)
+ return nua_handle_ref(nh);
+ }
+ }
+ return NULL;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua.docs Thu Dec 21 01:30:28 2006
@@ -0,0 +1,2279 @@
+/* -*- text -*- */
+
+/**@MODULEPAGE "nua" - High-Level User Agent Module
+
+ at section nua_meta Module Meta Information
+
+The @b nua module contains the user-agent library taking care of basic
+SIP User Agent functions. Its functionality includes call management,
+messaging and event retrieval.
+
+ at CONTACT Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ at STATUS @SofiaSIP Core library
+
+ at LICENSE LGPL
+
+ at par Contributor(s):
+- Pekka Pessi <Pekka.Pessi at nokia.com>
+- Pasi Rinne-Rahkola <Pasi.Rinne-Rahkola at nokia.com>
+- Kai Vehmanen <Kai.Vehmanen at nokia.com>
+- Martti Mela <Martti.Mela at nokia.com>
+
+ at section nua_overview Overview
+
+The NUA API gives the high-level application programmer transparent and
+full control to the SIP protocol engine below it. NUA provides the call
+semantics on top of existing transaction semantics found in
+<a href="../nta/index.html"><b>nta</b></a> module.
+API makes it possible to create different kind of User Agents,
+like terminals, gateways or MCUs.
+
+The @b nua engine hides many low-level signaling and media management
+aspects from the application programmer. It is possible to use different
+kind of media interfaces - even remote ones - in a fully transparent way.
+
+The application and the protocol engine within User Agent library can be
+run in separate threads. Communications from the protocol engine is
+conveyed through a callback function. The callback function is called
+within context of the application, so the application must provide
+appropriate handle to a #su_root_t object.
+
+ at section nua_concepts_user Sofia Concepts for NUA User
+
+ at subsection nua_intro Introduction
+
+The Sofia software suite is based on certain basic ideas and concepts that
+are used in all levels of Sofia software. Many of those are implemented in
+Sofia utility library (<a href="../su/index.html"><b>su</b></a>) providing
+unified interface to the most important OS services and utilities .
+
+The following sections contain descriptions of the concepts that a user of
+NUA library must understand to create a working application. The other
+utilities (in the SU library and other libraries of Sofia software suite)
+might also be useful for an application developer but one must be careful
+when using them because they might change the behavior of the Sofia
+software suite in a way that causes NUA library to work incorrectly.
+See [<a href="../su/index.html"><b>su</b></a>] for more detailed
+description of the SU services.
+
+ at subsection nua_root Event loop - root object
+
+The NUA uses the reactor pattern (also known as dispatcher pattern and
+notifier pattern) for event driven systems (see [Using Design Patterns
+to Develop Reusable Object-oriented Communication Software, D.C. Schmidt,
+CACM October '95, 38(10): 65-74]). Sofia uses a task as basic execution
+unit for the programming model. According to the model, the program can
+ask that the event loop invokes a callback function when a certain event
+occurs. Such events include I/O activity, timers or a asynchronously
+delivered messages from other task.
+
+The root object is a handle representing the task in the application.
+Another way of seeing the same thing is that the root object represents
+the main event loop of the task. Through the root object the task code
+can access its context information (magic) and thread-synchronization
+features like wait objects, timers, and messages.
+
+An application using NUA services must create a root object and the
+callback routine to handle events. The root object is created with
+su_root_create() function and the callback routine is registered with
+nua_create() function.
+
+Root object has type #su_root_t.
+
+See documentation of <su_wait.h> and <su_root.c> for more information
+of root object.
+
+See section #nua_event_e for more information of the callback function.
+
+ at subsection nua_magic Magic
+
+The magic is a term used for the context pointer that can be bound
+to various objects in Sofia stack (for example root object and operation
+handle) by the application code. This context pointer is passed back
+to the application code when a registered callback function is called by
+the main event loop. The Sofia stack retains the context information between
+calls to the callback function. An application can use the context information
+to store any information it needs for processing the events.
+
+ at subsection nua_memmgmt Memory Handling
+
+The home-based memory management is useful when a lot of memory blocks are
+allocated for given task. The allocations are done via the memory home,
+which keeps a reference to each allocated memory block. When the memory
+home is then freed, it will free all memory blocks to which it has
+reference. This simplifies application logic because application code does
+not need to keep track of the allocated memory and free every allocated block
+separately.
+
+An application using NUA services can use the memory management services
+provided by the SU library but it is not mandatory.
+
+See documentation of <su_alloc.h> for more information of memory management
+services.
+
+ at subsection nua_tags Tags
+
+Tagging is the mechanism used in Sofia software for packing parameters to
+functions. It enables passing a variable number of parameters having
+non-fixed types. For an application programmer the tagging is visible as
+macros that are used to encapsulate the passed parameters. When evaluated a
+tagging macro creates a structure that contains a tag (telling what is the
+type of a parameter) and a value (pointer to opaque data). By checking the
+tag the layers of Sofia software check whether they can handle the parameter
+or should it just be passed to lower layers for processing.
+
+There are some tags with special meaning:
+- TAG_NULL() (synonymous to TAG_END()) end of tag list
+- TAG_SKIP() empty tag item
+- TAG_NEXT() tag item pointing to another tag list, ends the current tag list
+- TAG_ANY() filter tag accepting any tag
+- TAG_IF() conditional inclusion of tag item
+
+The NUA functions can be called with a list of tagged values if they have
+following parameters at the end of parameter list:
+
+ at code
+tag_type_t tag,
+tag_value_t value,
+...);
+ at endcode
+
+The last tagged value on the parameter list must be TAG_NULL()
+(or TAG_END(), synonym for TAG_NULL()).
+
+Every tag has two versions: \n
+NUTAG_<tagname> \n
+which takes a value parameter and \n
+NUTAG_<tagname>_REF \n
+which takes a reference parameter. The latter is used with
+tl_gets() function to retrieve tag values from tag list.
+
+For SIP headers there exists also additional
+version of tags: \n
+SIPTAG_<tagname>_STR \n
+This tag version takes a C-language character string as parameter.
+The corresponding tag without _STR suffix takes a parsed value structure
+as parameter.
+
+The following is an example of call to NUA function containing tagged values:
+ at code
+nua_unregister(op->op_handle,
+ TAG_IF(use_registrar, NUTAG_REGISTRAR(registrar)),
+ SIPTAG_CONTACT_STR("*"),
+ SIPTAG_EXPIRES_STR("0"),
+ TAG_NULL());
+ at endcode
+
+An application using NUA services must use tagged arguments for passing the
+parameters to functions. See nua_invite() for discussion on how a SIP
+message is constructed from the tags.
+
+See documentation of <su_tag.h> for more information of tags and the
+module-specific documentation of each Sofia module for information of
+tags specific for that module.
+
+ at subsection nua_debugandlogging Debugging and Logging
+
+The modules of Sofia stack contain configurable debugging and logging
+functionality based on the services defined in <su_log.h>. The debugging
+and logging details (for example level of details on output and output
+file name) can be configured by environment variables, directives in
+configuration files and compilation directives in the source files.
+
+Examples of useful directives/ environment variables are:
+- #SOFIA_DEBUG Default debug level (0..9)
+- #NUA_DEBUG NUA debug level (0..9)
+- #NTA_DEBUG Transaction engine debug level (0..9)
+- #TPORT_DEBUG Transport event debug level (0..9)
+- #TPORT_LOG If set, print out all parsed SIP messages on transport layer
+- #TPORT_DUMP Filename for dumping unparsed messages from transport
+
+The defined debug output levels are:
+- 0 fatal errors, panic
+- 1 critical errors, minimal progress at subsystem level
+- 2 non-critical errors
+- 3 warnings, progress messages
+- 5 signaling protocol actions (incoming packets, ...)
+- 7 media protocol actions (incoming packets, ...)
+- 9 entering/exiting functions, very verbatim progress
+
+An application using NUA services can also use the debugging and
+logging services provided by the Sofia stack but it is not mandatory.
+
+See documentation of <su_log.h> for more information of debugging and
+logging services.
+
+ at section nua_concepts NUA Concepts
+
+ at subsection nua_stackobject NUA Stack Object
+
+Stack object represents an instance of SIP stack and media engine. It
+contains reference to root object of that stack, user-agent-specific
+settings, and reference to the SIP transaction engine, for example.
+
+A NUA stack object is created by nua_create() function and deleted by
+nua_destroy() function. The nua_shutdown() function is used to gracefully
+release active the sessions by @b nua engine.
+
+NUA stack object has type nua_t.
+
+ at subsection nua_operationhandle NUA Operation Handle
+
+Operation handle represents an abstract SIP call/session. It contains
+information of SIP dialog and media session, and state machine that
+takes care of the call, high-level SDP offer-answer protocol, registration,
+subscriptions, publications and simple SIP transactions. An operation
+handle may contain list of tags used when SIP messages are created by
+NUA (e.g. From and To headers).
+
+An operation handle is created explicitly by the application using NUA
+for sending messages (function nua_handle()) and by stack for incoming
+calls/sessions (starting with INVITE or MESSAGE). The handle is destroyed
+by the application using NUA (function nua_handle_destroy()).
+
+Indication and response events are associated with an operation handle.
+
+NUA operation handle has type nua_handle_t.
+
+ at subsection nua_stacktread Stack Thread and Message Passing Concepts
+
+The stack thread is a separate thread from application that provides the
+real-time protocol stack operations so that application thread can for
+example block or redraw UI as it likes.
+
+The communication between stack thread and application thread is asynchronous.
+Most of the NUA API functions cause a send of a message to the stack thread
+for processing and similarly when something happens in the stack thread it
+sends a message to the application thread. The messages to the application
+thread are delivered as invokes of the application callback function when
+the application calls su_root_run() or su_root_step() function.
+
+ at subsection nua_sip_message SIP Message and Header Manipulation
+
+SIP messages are manipulated with typesafe SIPTAG_ tags. There are
+three versions of each SIP tag:
+- SIPTAG_<tagname>() takes a parsed value as parameter.
+- SIPTAG_<tagname>_STR() takes an unparsed string as parameter.
+- SIPTAG_<tagname>_REF() takes a reference as parameter, is used
+ with tl_gets() function to retrieve tag values from tag list.
+- SIPTAG_<tagname>__STR_REF() takes a reference as parameter, is used
+ with tl_gets() function to retrieve string tag values from tag list.
+
+For example a header named "Example" would have tags names SIPTAG_EXAMPLE(),
+SIPTAG_EXAMPLE_STR(), and SIPTAG_EXAMPLE_REF().
+
+When tags are used in NUA calls the corresponding headers are added to
+the message. In case the header can be present only once in a message
+and there already exists a value for the header the value given by
+tag replaces the existing header value. Passing tag value NULL has no
+effect on headers. Passing tag value (void *)-1 removes corresponding
+headers from the message.
+
+For example:
+
+- sending a SUBSCRIBE with @b Event: header and two @b Accept: headers:
+
+ at code
+ nua_subscribe(nh,
+ SIPTAG_EVENT_STR("presence"),
+ SIPTAG_ACCEPT(accept1),
+ SIPTAG_ACCEPT(accept2),
+ TAG_END());
+ at endcode
+
+- fetching tag values when processing nua_r_subscribe event:
+
+ at code
+ sip_accept_t *ac = NULL;
+ sip_event_t *o = NULL;
+
+ tl_gets(tl,
+ SIPTAG_EVENT_REF(o), /* _REF takes a reference! */
+ SIPTAG_ACCEPT_REF(ac),
+ TAG_END());
+ at endcode
+
+ at section nua_tutorial SIP/NUA tutorial
+
+This section describes basic usage scenarios of NUA/Sofia stack using
+message sequence charts.
+
+ at subsection nua_outgoingcall Outgoing Call
+
+ at image latex SIP_outgoing_call.eps
+
+ at image html SIP_outgoing_call.gif
+
+
+ at subsection nua_incomingcall Incoming Call
+
+ at image latex SIP_incoming_call.eps
+
+ at image html SIP_incoming_call.gif
+
+ at subsection nua_basicoutgoingoperation Basic Outgoing Operation
+
+ at image latex SIP_basic_outgoing_operation.eps
+
+ at image html SIP_basic_outgoing_operation.gif
+
+
+ at subsection nua_basicincomingoperation Basic Incoming Operation
+
+ at image latex SIP_basic_incoming_operation.eps
+
+ at image html SIP_basic_incoming_operation.gif
+
+
+ at subsection nua_outgoingoperationwithauth Outgoing Operation with Authentication
+
+ at image latex SIP_outgoing_operation_with_auth.eps
+
+ at image html SIP_outgoing_operation_with_auth.gif
+
+
+ at section nua_simpleapplication Simple Application
+
+The following sections will present code examples from a simple application
+that uses services of NUA. The example is not complete but should present
+all relevant details of the basic use of NUA.
+
+The source distribution of Sofia stack contains in directory nua an example
+application nua_cli.c that can be studied for more complete example.
+
+ at subsection nua_datastructures Data Structures & Defines
+
+An application using services of NUA normally defines data areas that are
+used to store context information (i.e., "magic"). The types of pointers to
+these context information areas are passed to NUA by defines.
+
+ at code
+/* type for application context data */
+typedef struct application application;
+#define NUA_MAGIC_T application
+
+/* type for operation context data */
+typedef union oper_ctx_u oper_ctx_t;
+#define NUA_HMAGIC_T oper_ctx_t
+ at endcode
+
+The information area contents themselves can be defined as
+C structures or unions:
+
+ at code
+/* example of application context information structure */
+typedef struct application
+{
+ su_home_t home[1]; /* memory home */
+ su_root_t *root; /* root object */
+ nua_t *nua; /* NUA stack object */
+
+ /* other data as needed ... */
+} application;
+
+/* Example of operation handle context information structure */
+typedef union operation
+{
+ nua_handle_t *handle; /* operation handle /
+
+ struct
+ {
+ nua_handle_t *handle; /* operation handle /
+ ... /* call-related information */
+ } call;
+
+ struct
+ {
+ nua_handle_t *handle; /* operation handle /
+ ... /* subscription-related information */
+ } subscription;
+
+ /* other data as needed ... */
+
+} operation;
+ at endcode
+
+NUA stack object and handle are opaque to the application programmer.
+Likewise, the application context is completely opaque to the NUA stack
+module. NUA functions are passed a pointer, and that pointer is then
+given back to the application within the callback parameters. In this
+case the application context information structure is also used to
+store a root object and memory home for memory handling. The application
+context information also contains the NUA stack object information.
+
+ at subsection nua_initanddeinit Initialization and deinitialization
+
+The following code is an example of application function that initializes
+the system, enters the main loop for processing the messages, and, after
+message processing is ended, deinitalizes the system.
+
+If the application is not just responding to incoming SIP messages there must
+also be means to send messages to NUA. This can be handled for example by
+having a separate thread that calls NUA functions to send messages or by
+having a socket connection to the application for sending commands to the
+application (see documentation of su_wait_create() and su_root_register()).
+
+ at code
+/* Application context structure */
+application appl[1] = {{{{(sizeof appl)}}}};
+
+/* initialize system utilities */
+su_init();
+
+/* initialize memory handling */
+su_home_init(appl->home);
+
+/* initialize root object */
+appl->root = su_root_create(appl);
+
+if (appl->root != NULL) {
+ /* create NUA stack */
+ appl->nua = nua_create(appl->root,
+ app_callback,
+ appl,
+ /* tags as necessary ...*/
+ TAG_NULL());
+
+ if (appl->nua != NULL) {
+ /* set necessary parameters */
+ nua_set_params(appl->nua,
+ /* tags as necessary ... */
+ TAG_NULL());
+
+ /* enter main loop for processing of messages */
+ su_root_run(appl->root);
+
+ /* destroy NUA stack */
+ nua_destroy(appl->nua);
+ }
+
+ /* deinit root object */
+ su_root_destroy(appl->root);
+ appl->root = NULL;
+}
+
+/* deinitialize memory handling */
+su_home_deinit(appl->home);
+
+/* deinitialize system utilities */
+su_deinit();
+ at endcode
+
+ at subsection nua_handlingevents Handling events
+
+Handling of the events coming from NUA stack is done in the callback
+function that is registered for NUA stack with the nua_create() function
+when the application is initialized. The content of callback function is
+in its simplest form just a switch/case statement that dispatches the
+incoming events for processing to separate functions.
+
+ at code
+void app_callback(nua_event_t event,
+ int status,
+ char const *phrase,
+ nua_t *nua,
+ nua_magic_t *magic,
+ nua_handle_t *nh,
+ nua_hmagic_t *hmagic,
+ sip_t const *sip,
+ tagi_t tags[])
+{
+ switch (event) {
+ case nua_i_invite:
+ app_i_invite(status, phrase, nua, magic, nh, hmagic, sip, tags);
+ break;
+
+ case nua_r_invite:
+ app_r_invite(status, phrase, nua, magic, nh, hmagic, sip, tags);
+ break;
+
+ /* and so on ... */
+
+ default:
+ /* unknown event -> print out error message */
+ if (status > 100) {
+ printf("unknown event %d: %03d %s\n",
+ event,
+ status,
+ phrase);
+ }
+ else {
+ printf("unknown event %d\n", event);
+ }
+ tl_print(stdout, "", tags);
+ break;
+ }
+} /* app_callback */
+ at endcode
+
+ at subsection nua_placeacall Place a call
+
+The following three functions show an example of how a basic SIP
+call is created.
+
+The place_a_call() function creates an operation handle and invokes the
+SIP INVITE method.
+
+ at code
+operation *place_a_call(char const *name, url_t const *url)
+{
+ operation *op;
+ sip_to_t *to;
+
+ /* create operation context information */
+ op = su_zalloc(appl->home, (sizeof *op));
+ if (!op)
+ return NULL;
+
+ /* Destination address */
+ to = sip_to_create(NULL, url);
+ if (!to)
+ return NULL;
+
+ to->a_display = name;
+
+ /* create operation handle */
+ op->handle = nua_handle(appl->nua, op, SIPTAG_TO(to), TAG_END());
+
+ if (op->handle == NULL) {
+ printf("cannot create operation handle\n");
+ return NULL;
+ }
+
+ nua_invite(op->handle,
+ /* other tags as needed ... */
+ TAG_END());
+
+} /* place_a_call */
+ at endcode
+
+The app_r_invite() function is called by callback function when response to
+INVITE message is received. Here it is assumed that automatic acknowledge
+is not enabled so ACK response must be sent explicitly.
+
+ at code
+void app_r_invite(int status,
+ char const *phrase,
+ nua_t *nua,
+ nua_magic_t *magic,
+ nua_handle_t *nh,
+ nua_hmagic_t *hmagic,
+ sip_t const *sip,
+ tagi_t tags[])
+{
+ if (status == 200) {
+ nua_ack(nh, TAG_END());
+ }
+ else {
+ printf("response to INVITE: %03d %s\n", status, phrase);
+ }
+} /* app_r_invite */
+ at endcode
+
+The nua_i_state event is sent (and app_i_state() function called by callback
+function) when the call state changes (see @ref nua_uac_call_model
+"client-side call model").
+
+ at code
+void app_i_state(int status,
+ char const *phrase,
+ nua_t *nua,
+ nua_magic_t *magic,
+ nua_handle_t *nh,
+ nua_hmagic_t *hmagic,
+ sip_t const *sip,
+ tagi_t tags[])
+{
+ nua_callstate_t state = nua_callstate_init;
+
+ tl_gets(tags,
+ NUTAG_CALLSTATE_REF(state),
+ NUTAG__REF(state),
+
+
+ state = (nua_callstate_t)t->t_value;
+
+ printf("call %s\n", nua_callstate_name(state));
+
+} /* app_i_state */
+ at endcode
+
+ at subsection nua_receiveacall Receive a call
+
+The app_i_invite() function is called by callback function when incoming
+INVITE message is received. This example assumes that autoanswer is
+not enabled so the response must be sent explicitly.
+
+ at code
+void app_i_invite(int status,
+ char const *phrase,
+ nua_t *nua,
+ nua_magic_t *magic,
+ nua_handle_t *nh,
+ nua_hmagic_t *hmagic,
+ sip_t const *sip,
+ tagi_t tags[])
+{
+ printf("incoming call\n");
+
+ nua_respond(nh, 200, "OK", SOA_USER_SDP(magic->sdp), TAG_END());
+
+} /* app_i_invite */
+ at endcode
+
+The app_i_state() function is called by the callback function when call has
+been successfully set up and the media has been activated.
+
+ at code
+void app_i_active(int status,
+ char const *phrase,
+ nua_t *nua,
+ nua_magic_t *magic,
+ nua_handle_t *nh,
+ nua_hmagic_t *hmagic,
+ sip_t const *sip,
+ tagi_t tags[])
+{
+ printf("call active\n");
+
+} /* app_i_active */
+ at endcode
+
+ at subsection nua_terminatingcall Terminating a call
+
+The following three functions show an example of how a basic SIP
+call is terminated.
+
+The terminate_call() function sends the SIP BYE message.
+
+ at code
+void terminate_call(void)
+{
+ nua_bye(op->handle, TAG_END());
+
+} /* terminate call */
+ at endcode
+
+The app_r_bye() function is called by the callback function when answer to
+the BYE message is received. The function destroys the call handle and
+releases the memory allocated to operation context information.
+
+ at code
+void app_r_bye(int status,
+ char const *phrase,
+ nua_t *nua,
+ nua_magic_t *magic,
+ nua_handle_t *nh,
+ nua_hmagic_t *hmagic,
+ sip_t const *sip,
+ tagi_t tags[])
+{
+ if (status < 200)
+ return;
+
+ printf("call released\n");
+
+ /* release operation handle */
+ nua_handle_destroy(hmagic->handle);
+ op->handle = NULL;
+
+ /* release operation context information */
+ su_free(appl->home, hmagic);
+
+} /* app_r_bye */
+ at endcode
+
+The app_i_bye() function is called by the callback function when an incoming
+BYE message is received. The function destroys the call handle and releases
+the memory allocated to operation context information.
+
+ at code
+void app_i_bye(int status,
+ char const *phrase,
+ nua_t *nua,
+ nua_magic_t *magic,
+ nua_handle_t *nh,
+ nua_hmagic_t *hmagic,
+ sip_t const *sip,
+ tagi_t tags[])
+{
+ printf("call released\n");
+
+ /* release operation handle */
+ nua_handle_destroy(hmagic->handle);
+ op->handle = NULL;
+
+ /* release operation context information */
+ su_free(appl->home, hmagic);
+
+} /* app_i_bye */
+ at endcode
+
+ at subsection nua_sendamessage Sending a message
+
+The following functions show an example of how a SIP MESSAGE is sent.
+
+The send_message() function sends the SIP MESSAGE.
+
+ at code
+void send_message(void)
+{
+ op_t *op;
+
+ /* create operation context information */
+ op = su_zalloc(appl->home, sizeof(op_t));
+ if (op = NULL) {
+ printf("cannot create operation context information\n");
+ return;
+ }
+
+ /* how we create destination_address? */
+
+ /* create operation handle */
+ op->handle = nua_handle(appl->nua,
+ op,
+ NUTAG_URL(destination_address),
+ TAG_END());
+
+ if (op->handle == NULL) {
+ printf("cannot create operation handle\n");
+ return;
+ }
+
+ /* send MESSAGE */
+ nua_message(op->handle,
+ SIPTAG_CONTENT_TYPE_STR("text/plain"),
+ SIPTAG_PAYLOAD_STR("Hello, world!"),
+ /* other tags as needed ... */
+ TAG_END());
+
+} /* send_message */
+ at endcode
+
+The app_r_message() function is called by the callback function when
+answer to the MESSAGE is received.
+
+ at code
+void app_r_message(int status,
+ char const *phrase,
+ nua_t *nua,
+ nua_magic_t *magic,
+ nua_handle_t *nh,
+ nua_hmagic_t *hmagic,
+ sip_t const *sip,
+ tagi_t tags[])
+{
+ printf("response to MESSAGE: %03d %s\n", status, phrase);
+} /* app_r_message */
+ at endcode
+
+ at subsection nua_receivemessage Receiving a message
+
+The following function shows an example of how a SIP MESSAGE is received.
+
+The app_i_message() function is called by the callback function when
+a SIP MESSAGE is received.
+
+ at code
+void app_i_message(int status,
+ char const *phrase,
+ nua_t *nua,
+ nua_magic_t *magic,
+ nua_handle_t *nh,
+ nua_hmagic_t *hmagic,
+ sip_t const *sip,
+ tagi_t tags[])
+{
+ printf("received MESSAGE: %03d %s\n", status, phrase);
+
+ printf("From: %s%s" URL_PRINT_FORMAT "\n",
+ sip->sip_from->a_display ? sip->sip_from->a_display : "",
+ sip->sip_from->a_display ? " " : "",
+ URL_PRINT_ARGS(sip->sip_from->a_url));
+
+ if (sip->sip_subject) {
+ printf("Subject: %s\n", sip->sip_subject->g_value);
+ }
+
+ if (sip->sip_payload) {
+ fwrite(sip->sip_payload->pl_data, sip->sip_payload->pl_len, 1, stdout);
+ fputs("\n", stdout);
+ }
+} /* app_i_message */
+ at endcode
+
+ at subsection nua_notifier Creating a Presence Server
+
+ at code
+
+...
+ application_t *app;
+ operation_t *oper;
+
+...
+
+ oper->app = app;
+
+
+ app->nua = nua_create(ssip->s_root,
+ app_callback,
+ app,
+ TAG_NULL());
+...
+
+ oper->handle = nua_handle(app->nua, app,
+ NUTAG_URL(to->a_url),
+ SIPTAG_TO(to),
+ ta_tags(ta));
+...
+
+ nua_notifier(oper->handle,
+ SIPTAG_EXPIRES_STR("3600"),
+ SIPTAG_EVENT_STR("presence"),
+ SIPTAG_CONTENT_TYPE_STR("application/pidf-partial+xml"),
+ NUTAG_SUBSTATE(nua_substate_pending),
+ TAG_END());
+ at endcode
+
+After the nua_notifier object -- the presence server -- is created, an
+event nua_r_notifier is returned. Status and phrase values of the
+app_callback function indicate the success of the creation.
+
+Authorization of an incoming subscription (to the local presence
+server) can be handled in the callback function.
+
+ at code
+void app_callback(nua_event_t event,
+ int status, char const *phrase,
+ nua_t *nua, application_t *app,
+ nua_handle_t *nh, oper_t *op,
+ sip_t const *sip, tagi_t tags[])
+{
+ nea_sub_t *subscriber = NULL;
+
+ switch (event) {
+ case nua_i_subscription:
+ tl_gets(tags,
+ NEATAG_SUB_REF(subscriber),
+ TAG_END());
+
+
+ nua_authorize(nua_substate_active);
+
+
+ default:
+ break;
+}
+
+
+ at endcode
+
+
+ at subsection nua_shutting_down Shutdown
+
+The following functions show an example of how application terminates
+the NUA stack.
+
+The shutdown() function starts the termination.
+
+ at code
+void shutdown(void)
+{
+ nua_shutdown(appl->nua);
+
+} /* shutdown */
+ at endcode
+
+The app_r_shutdown() function is called by the callback function when NUA
+stack termination is either finished or failed.
+
+ at code
+void app_r_shutdown(int status,
+ char const *phrase,
+ nua_t *nua,
+ nua_magic_t *magic,
+ nua_handle_t *nh,
+ nua_hmagic_t *hmagic,
+ sip_t const *sip,
+ tagi_t tags[])
+{
+ printf("shutdown: %d %s\n", status, phrase);
+
+ if (status < 200) {
+ /* shutdown in progress -> return */
+ return;
+ }
+
+ /* end the event loop. su_root_run() will return */
+ su_root_break(magic->root);
+
+} /* app_r_shutdown */
+ at endcode
+
+*/
+
+/** @page nua_call_model NUA Call Model
+
+The NUA call follows a relatively simple state model presented below. The call
+model is used to present changes in call: when media starts to flow, when
+call is considered established, when call is terminated.
+
+In the figure below, a simplified state diagram for a SIP call is presented.
+After the call state has changes the application will receive an
+#nua_i_state event indicating the change. The states in NUA call model are
+represented by @e enum #nua_callstate, and the current value of state is
+included as the tag NUTAG_CALLSTATE() with the #nua_i_state event.
+
+The @RFC3264 SDP Offer/Answer negotiation status is also included in the
+#nua_i_state event. The negotiation status includes the local SDP (in
+SOATAG_LOCAL_SDP()) sent and flags indicating whether the local SDP was an
+offer or answer (NUTAG_OFFER_SENT(), NUTAG_ANSWER_SENT()). Likewise, the
+received remote SDP is included in tag SOATAG_REMOTE_SDP() and flags
+indicating whether the remote SDP was an offer or an answer in tags
+NUTAG_OFFER_RECV() or NUTAG_ANSWER_RECV(). SOATAG_ACTIVE_AUDIO() and
+SOATAG_ACTIVE_VIDEO() are informational tags used to indicate what is the
+status of these media.
+
+The #nua_i_state event is not sent, however, if the change is invoked by
+application calling API functions like nua_bye() and there is no change in
+SDP offer/answer status.
+
+ at code
+ +---------------+
+ +------| INIT |-----+
+ INVITE/- | +---------------+ | INVITE/100
+ V |
+ +------------+ +------------+
+ +----| CALLING |--+ +---| RECEIVED |--+
+ | +------------+ | | +------------+ |
+ | | | | | |
+ | | 18X/- | | | -/18X |
+ | V | | V |
+ | +------------+ | | +------------+ |
+ |<---| PROCEEDING | | | | EARLY |->|
+ | +------------+ | | +------------+ | -/[3456]XX
+ | | | | | |
+ | | 2XX/- | 2XX/- | -/2XX | -/2XX | or
+ | V | | V |
+ | + - - - - - -+ | | +------------+ | CANCEL/200,487
+ | : COMPLETING :<-+ +-->| COMPLETE | |
+ | + - - - - - -+ +------------+ |
+ | | | |
+ | | -/ACK ACK/- | |
+ | | | |
+ | | | |
+ | | +---------------+ | |
+ | +----->| READY |<----+ |
+ | +---------------+ |
+ | | | |
+ | BYE/200 | | -/BYE |
+ | | | |
+ | | V |
+ | | +--------------+ |
+ | [3456]XX/ACK | | TERMINATING | |
+ | | +--------------+ |
+ | | | |
+ | | | [23456]XX/- |
+ | V V |
+ | +---------------+ |
+ +---------------->| TERMINATED |<--------------+
+ +---------------+
+ at endcode
+
+The labels "input/output" along each transition indicates SIP messages
+received from and sent to network, for instance, state transition
+"INVITE/100" occurs when a SIP @b INVITE request is received, and it is
+immediately returned a 100 (<i>Trying</i>) response. Label "2XX" means any
+200-series response, e.g., <i>200 OK</i> or <i>202 Accepted</i>). Notation
+"[3456]XX" means any final error response in 300, 400, 500, or 600
+series. Label "18X" means any provisional response from 101 to 199, most
+typically 180 (<i>Ringing</i>) or 183 (<i>Session Progress</i>).
+
+ at section nua_uac_call_model Detailed Client Call Model
+
+The detailed call model at client side is presented below. This model does
+not include the extensions like @b 100rel or @b UPDATE.
+
+ at code
+ +------------+
+ | INIT |
+ +------------+
+ |
+ (1) nua_invite/INVITE
+ |
+ V
+ +------------+
+ | |-----------------------------(6a)-----+
+ | |----+ nua_cancel |
+ +------| CALLING | (7a) /CANCEL |
+ | | |<---+ |
+ | | |----------------------+ |
+ | +------------+ | |
+ | | (8a) nua_bye |
+ | (2) 18X/- | /CANCEL |
+ | | | |
+ | V | |
+ | +------------+ | |
+ | | |-----------------------------(6b)---->|
+ | | |----+ nua_cancel | |
+ | | PROCEEDING | (7b) /CANCEL | |
+ | | |<---+ | |
+ | | |----------------------+ |
+ | +------------+ | |
+ | | | |
+ (3a) 2XX/- (3b) 2XX/- | (6) [3456]XX/ACK
+ | | | |
+ | V | |
+ | + - - - - - -+ | |
+ +----->: : | |
+ : COMPLETING :-------+ | |
+ + - - -: : | | |
+ : + - - - - - -+ | | |
+ : | | | |
+ :<auto_ack> | | | |
+ :or nua_ack | <auto_ack> | | |
+ :and media | or nua_ack | nua_bye | |
+ (5) error (4) /ACK (9) /ACK+BYE (8b) nua_bye/BYE |
+ : /ACK+BYE | | | |
+ : V | V |
+ : +------------+ | +-------------+ |
+ : | | | | | |
+ : | READY | | | TERMINATING*| |
+ : | | | | | |
+ : +------------+ | +-------------+ |
+ : | | | |
+ : | (10) 2XX (11) 3XX 4XX |
+ : +-------------+ | | /BYE | 5XX 6XX |
+ : | | V V | /- |
+ + - - >| TERMINATING |<-------------------------+ |
+ | | |
+ +-------------+ |
+ | |
+ (12) [23456]XX to BYE/- |
+ | |
+ V |
+ +------------+ |
+ | TERMINATED |<-------------------------------------+
+ +------------+
+ at endcode
+
+The detailed description of state transitions on the client side is as
+follows:
+
+<table>
+<tr><th>#</th>
+ <th>Previous state</th>
+ <th>Input</th>
+ <th>Output</th>
+ <th>Next state</th>
+ <th>Offer/ Answer</th>
+ <th align="left">Description</th>
+</tr>
+<tr><td>C1</td> <!-- transition -->
+ <td>init</td> <!-- previous state -->
+ <td>nua_invite()</td> <!-- input -->
+ <td>INVITE</td> <!-- output -->
+ <td>calling</td> <!-- next state -->
+ <td>Generate offer</td> <!-- offer/answer -->
+ <td>
+ Client application starts call be invoking nua_invite(). By default, stack runs
+ the initial offer/answer step and sends @b INVITE request with the SDP
+ offer.
+</td></tr>
+<tr><td>C2</td>
+ <td>calling</td><td>18X</td><td>-</td><td>proceeding</td>
+ <td>(Save answer)</td>
+ <td>
+ Stack receives a 18X response (a provisional response between 101
+ and 199). It establishes an early dialog with server. If the provisional
+ response contains an SDP answer, a session with early media is
+ established. The caller can be listen to, for instance, ring tone or
+ announcements about call progress using the early media session.
+</td></tr>
+<tr><td>C3a</td>
+ <td>calling</td><td rowspan="2">2XX</td>
+ <td rowspan="2">-</td><td rowspan="2">completing</td>
+ <td rowspan="2">Save answer</td>
+ <td rowspan="2">
+ Client receives a 2XX response (usually <i>200 OK</i>) indicating that
+ call has been accepted by the server. If there is an SDP session
+ description included with response, it is stored.
+
+ Unless the @ref NUTAG_AUTOACK() "auto-ack" mode is explicitly turned off
+ by application the client does not stay in @b completing state, but
+ proceeds immediately to next state transition.
+</td></tr>
+<tr><td>C3b</td>
+ <td>proceeding</td></tr>
+<tr><td>C4</td>
+ <td>completing</td>
+ <td>nua_ack() or<br>@ref NUTAG_AUTOACK() "auto-ack" </td>
+ <td>ACK</td><td>ready</td>
+ <td>Process answer</td>
+ <td>
+ Client sends an ACK request in this state transition. If the initial
+ offer was sent with INVITE, the answer must have been received by this
+ time, usually in the 2XX response. Client now completes the SDP
+ offer-answer exchange and activates the media.
+</td></tr>
+<tr><td>C5</td>
+ <td>completing</td>
+ <td>nua_ack() or<br>@ref NUTAG_AUTOACK() "auto-ack" and<br> media error</td>
+ <td>ACK<br>BYE</td>
+ <td>terminating</td>
+ <td>Process answer</td>
+ <td>
+ If there was an failure in SDP negotiation or other failure with media,
+ the stack will automatically terminate the call. The BYE follows
+ immediatelhy after the ACK.
+</td></tr>
+<tr><td>C6a</td>
+ <td>calling</td>
+ <td rowspan=2>3XX 4XX <br> 5XX 6XX</td>
+ <td rowspan=2>ACK*</td>
+ <td rowspan=2>terminated</td>
+ <td rowspan=2>-</td>
+ <td rowspan=2>
+ Call is terminated when client receives a final error response (from 300
+ to 699) to its INVITE request. In this case, the underlying transaction
+ engine takes care of sending ACK even when application-driven-ack mode is
+ requested by application.
+</td></tr>
+<tr><td>C6b</td>
+ <td>proceeding</td>
+</tr>
+
+<tr><td>C7a</td>
+ <td>calling</td>
+ <td rowspan=2>nua_cancel()</td>
+ <td rowspan=2>CANCEL</td>
+ <td>calling</td>
+ <td rowspan=2>-</td>
+ <td rowspan=2>
+ Client can ask server to cancel the call attempt while in @b calling or
+ @b proceeding state. There is no direct call state transition caused by
+ nua_cancel(). The call state changes when the server returns a response.
+ After receiving a CANCEL request the server will usually return a <i>487
+ Request Terminated</i> response and call is terminated as in previous
+ item.
+
+ However, there is a race condition and the server can respond with a
+ succesful 2XX response before receiving CANCEL. In that case, the call is
+ established as usual. It is up to application to terminate the call with
+ nua_bye().
+</td></tr>
+<tr><td>C7b</td>
+ <td>proceeding</td>
+ <td>proceeding</td>
+</tr>
+<tr><td>C8a</td>
+ <td>proceeding</td>
+ <td>nua_bye()</td>
+ <td>CANCEL</td>
+ <td rowspan=2>terminating*</td>
+ <td rowspan=2>-</td>
+ <td>
+ The cannot be terminated with BYE before the dialog is established with a
+ non-100 preliminary response. So, instead of @b BYE, stack sends a @b
+ CANCEL request, and enters terminating state.
+
+ However, there is a race condition and the server can respond with a
+ succesful 2XX response before receiving CANCEL. If the server responds with
+ a 2XX response, the nua will automatically send a BYE request asking server
+ to terminate the call.
+</td></tr>
+<tr><td>C8b</td>
+ <td>proceeding</td>
+ <td>nua_bye()</td>
+ <td>BYE</td>
+<td>
+ Even an early session can be terminated after entering @b proceeding
+ state with nua_bye(). Stack sends a @b BYE request, and enters
+ terminating state. Unlike @b CANCEL, @b BYE affects only one fork.
+
+ However, there is a race condition and the server can respond with a
+ succesful 2XX response before receiving BYE. If the server responds with
+ a 2XX response, the nua will automatically send a BYE request asking server
+ to terminate the call.
+</td></tr>
+<tr><td>C9</td>
+ <td>completing</td><td>nua_bye()</td><td>ACK<br>BYE</td><td>terminating</td>
+ <td>-</td>
+ <td>
+ If the stack is in @b completing state (it has already
+ received 2XX response), it will have to @b ACK the final response, too.
+</td></tr>
+
+<tr><td>C10</td>
+ <td>terminating*</td>
+ <td>2XX<br>to INVITE</td>
+ <td>BYE</td>
+ <td>terminating</td>
+ <td>-</td>
+ <td>
+ There is a race condition between @b BYE and @b INVITE. The call may have
+ been re-established with @b INVITE after @b BYE was processed. @b BYE is
+ re-sent and call state transitions to normal terminating state.
+</td></tr>
+
+<tr><td>C11</td>
+ <td>terminating*</td>
+ <td>3XX 4XX<br>5XX 6XX<br>to INVITE</td>
+ <td>BYE</td>
+ <td>terminating</td>
+ <td>-</td>
+ <td>
+ The @b INVITE transaction is completed without a call being created. The
+ call state transitions to normal terminating state.
+</td></tr>
+
+<tr><td>C12</td>
+ <td>terminating</td>
+ <td>3XX 4XX<br>5XX 6XX<br>to BYE</td>
+ <td>-</td>
+ <td>terminated</td>
+ <td>-</td>
+ <td>
+ Call is terminated when the final response to the BYE is received.
+</td></tr>
+
+</table>
+
+ at section nua_uas_call_model Detailed Server-Side Call Model
+
+The detailed call model at server side (UAS) is presented below. This model
+does not include the extensions like @b 100rel or @b UPDATE.
+
+ at code
+
+ +----------------------------------+
+ | INIT |
+ +----------------------------------+
+ | : :
+ | : :
+ (1) INVITE/100 (2b) INVITE/18X (3c) INVITE/2XX
+ | : :
+ | : :
+ V : :
+ +------------+ : :
+ +--------------------| | : :
+ | | RECEIVED |--------------+ :
+ | +---------------| | : | :
+ | | +------------+ : | :
+ | | | : | :
+ | | nua_respond/18X (2) : | :
+ | | | : | :
+ | | V V | :
+ | | +------------+ | :
+ |<------------------------------| | | :
+ | |<-------------------------| EARLY | | :
+ | | +----------| | | :
+ | | | +------------+ | :
+ | nua_respond/ | | | :
+ (6) /[3456]XX | nua_respond/2XX (3b) (3a) :
+ | | | | | :
+ | | | V V V
+ | | | +-------------+
+ | | | | |
+ | | | +-----| COMPLETED |- - +
+ | | | | | | :
+ | | | | +-------------+ :
+ | | | | | :
+ | | | | (4) ACK/- :
+ | | | | | :
+ | | | | V :
+ | | | | +-------------+ :
+ | | | | | | :
+ | | | | | READY | :
+ | | | | | | :
+ | | | | +-------------+ :
+ | | | | :
+ | (7) CANCEL/487 (8) BYE/487 (9) BYE/200 (5) timeout
+ | | | | : /BYE
+ | | | | +-------------+ :
+ | | | | | TERMINATING |<- -+
+ | | | | +-------------+
+ | | | | |
+ | | | | | [23456]XX/-
+ | | | | |
+ | | | | V
+ | V V V +-------------+
+ +---------------------------------------->| TERMINATED |
+ +-------------+
+ at endcode
+
+The detailed description of state transitions on the server side is as
+follows:
+<table>
+<tr><th>#</th>
+ <th>Previous state</th>
+ <th>Input</th>
+ <th>Output</th>
+ <th>Next state</th>
+ <th>Offer/ Answer</th>
+ <th align="left">Description</th>
+</tr>
+<tr><td>S1</td> <!-- transition -->
+ <td>init</td> <!-- previous state -->
+ <td>INVITE</td> <!-- input -->
+ <td>100 Trying</td> <!-- output -->
+ <td>received</td> <!-- next state -->
+ <td>Save offer</td> <!-- offer/answer -->
+ <td>
+ When a @b INVITE request for a new call is received, the server creates a
+ fresh call handle for it, responds to the client with <i>100 Trying</i>
+ and enters in the @b received state by default. It saves the possible SDP
+ offer included in @b INVITE and passes it to the application.
+</td></tr>
+<tr><td>S2a</td> <!-- transition -->
+ <td>received</td> <!-- previous state -->
+ <td>nua_respond()</td> <!-- input -->
+ <td>18X</td> <!-- output -->
+ <td rowspan=2>early</td> <!-- next state -->
+ <td>(Generate early answer)</td> <!-- offer/answer -->
+ <td>
+ When server returns a preliminary response for the initial @b INVITE request,
+ a early dialog is created. The server can also send an SDP answer with
+ the preliminary answer and establish an early session, too. It can use
+ the early session to send early media, e.g., ringing tone and
+ announcements towards the client.
+</td></tr>
+<tr><td>S2b</td> <!-- transition -->
+ <td>init</td> <!-- previous state -->
+ <td>INVITE and <!-- input -->
+ @ref NUTAG_AUTOALERT() "auto-alert"</td>
+ <td>180 Ringing</td> <!-- output -->
+ <td>Save offer (and
+ generate early answer)</td> <!-- offer/answer -->
+ <td>
+ When @ref NUTAG_AUTOALERT() "auto-alert" option is enabled, stack sends
+ 180 Ringing immediately after receiving INVITE and enters @b early state.
+</td></tr>
+<tr><td>S3a</td> <!-- transition -->
+ <td>received</td> <!-- previous state -->
+ <td rowspan=2>nua_respond()</td> <!-- input -->
+ <td rowspan=2>2XX</td> <!-- output -->
+ <td rowspan=3>completed</td> <!-- next state -->
+ <td rowspan=2>Generate answer</td> <!-- offer/answer -->
+ <td rowspan=2>
+ When the server sends a 2XX response towards the client, it accepts the
+ call. The @b INVITE transaction is now considered complete but unconfirmed
+ at the server side. If the offer was sent in @b INVITE request, the answer
+ should be included in the 2XX response.
+</td></tr>
+<tr><td>S3b</td> <!-- transition -->
+ <td>early</td> <!-- previous state -->
+</td></tr>
+<tr><td>S3c</td> <!-- transition -->
+ <td>init</td> <!-- previous state -->
+ <td>INVITE and @ref NUTAG_AUTOANSWER() "auto-answer"
+ </td> <!-- input -->
+ <td>200 OK</td> <!-- output -->
+ <td>Save offer and
+ <br>generate answer</td> <!-- offer/answer -->
+ <td>
+ When @ref NUTAG_AUTOANSWER() "auto-answer" option is enabled, stack send
+ 200 OK immediately after receiving INVITE and enters @b completed state.
+</td></tr>
+</td></tr>
+<tr><td>S4</td> <!-- transition -->
+ <td>completed</td> <!-- previous state -->
+ <td>ACK</td> <!-- input -->
+ <td>-</td> <!-- output -->
+ <td>ready</td> <!-- next state -->
+ <td>-</td> <!-- offer/answer -->
+ <td>
+ The ready state is entered at server side after receiving @b ACK request
+ from client, indicating that the client have received server's 2XX
+ response. The call is ready, the @b INVITE transaction is confirmed.
+</td></tr>
+<tr><td>S5td> <!-- transition -->
+ <td>completed</td> <!-- previous state -->
+ <td>timeout</td> <!-- input -->
+ <td>BYE</td> <!-- output -->
+ <td>terminating</td> <!-- next state -->
+ <td>-</td> <!-- offer/answer -->
+ <td>
+ If the server does not receive an @b ACK request in timely fashion, it will
+ terminate the call by sending a @b BYE request to client.
+</td></tr>
+<tr><td>S6a</td> <!-- transition -->
+ <td>received</td> <!-- previous state -->
+ <td rowspan=2>nua_respond()</td> <!-- input -->
+ <td rowspan=2>3XX 4XX<br>5XX 6XX</td><!-- output -->
+ <td rowspan=2>terminated</td> <!-- next state -->
+ <td rowspan=2>-</td> <!-- offer/answer -->
+ <td rowspan=2>
+ The server can reject the call by sending a 3XX, 4XX, 5XX, or 6XX response
+ towards the client. The underlying transaction engine takes care of
+ retransmitting the response when needed. It consumes the ACK response
+ sent by the client, too.
+</td></tr>
+<tr><td>S6b</td> <!-- transition -->
+ <td>early</td> <!-- previous state -->
+</td></tr>
+<tr><td>S7a</td> <!-- transition -->
+ <td>received</td> <!-- previous state -->
+ <td rowspan=2>CANCEL</td> <!-- input -->
+ <td rowspan=2>487 Request terminated</td><!-- output -->
+ <td rowspan=2>terminated</td> <!-- next state -->
+ <td rowspan=2>-</td> <!-- offer/answer -->
+ <td rowspan=2>
+ The client can cancel the call attempt before it is completed with a @b
+ CANCEL request. Server returns a <i>200 OK</i> response to @b CANCEL and
+ a <i>487 Request Terminated</i> response to the @b INVITE transaction and
+ the call is terminated.
+</td></tr>
+<tr><td>S7b</td> <!-- transition -->
+ <td>early</td> <!-- previous state -->
+</td></tr>
+<tr><td>S8</td> <!-- transition -->
+ <td>early</td> <!-- previous state -->
+ <td>BYE</td> <!-- input -->
+ <td>487 to INVITE<br>
+ 200 to BYE</td> <!-- output -->
+ <td>terminated</td> <!-- next state -->
+ <td>-</td> <!-- offer/answer -->
+ <td>
+ The client can terminate an early session with a @b BYE request, too. Like
+ in the @b CANCEL case above, the server will terminate call immediately,
+ return a <i>200 OK</i> response to @b BYE and a <i>487 Request
+ Terminated</i> response to the @b INVITE transaction.
+</td></tr>
+<tr><td>S9</td> <!-- transition -->
+ <td>completed</td> <!-- previous state -->
+ <td>BYE</td> <!-- input -->
+ <td>200 to BYE</td> <!-- output -->
+ <td>terminated</td> <!-- next state -->
+ <td>-</td> <!-- offer/answer -->
+ <td>
+ The client can terminate a completed dialog with a @b BYE request. Server
+ terminates call immediately, returns a <i>200 OK</i> response to @b BYE
+ and lets the underlying transaction engine to take care of consuming @b
+ ACK.
+</td></tr>
+</table>
+
+ at section nua_3pcc_call_model Third Party Call Control
+
+There is an alternative offer-answer model for third party call control
+(3pcc). The call setup involves a 3rd party, client C, which sends initial
+INVITE to server A without SDP. The call setup looks perfectly ordinary to
+server B, however.
+
+ at code
+ A C B
+ | | |
+ |<-------INVITE---------| |
+ | | |
+ | | |
+ |------200 (offer)----->| |
+ | |----INVITE (offer)---->|
+ | | |
+ | | |
+ | |<-----200 (answer)-----|
+ |<-----ACK (answer)-----| |
+ | | |
+ | |----------ACK--------->|
+ | | |
+ at endcode
+
+The modifications to the call model affect mainly offer-answer model.
+The detailed description of state transitions for 3pcc on the server side is as
+follows:
+
+<table>
+<tr><th>#</th>
+ <th>Previous state</th>
+ <th>Input</th>
+ <th>Output</th>
+ <th>Next state</th>
+ <th>Offer/ Answer</th>
+ <th align="left">Description</th>
+</tr>
+<tr><td>S1'</td> <!-- transition -->
+ <td>init</td> <!-- previous state -->
+ <td>INVITE</td> <!-- input -->
+ <td>100 Trying</td> <!-- output -->
+ <td>received</td> <!-- next state -->
+ <td>-</td> <!-- offer/answer -->
+ <td>
+ There is no SDP to save.
+</td></tr>
+<tr><td>S2b'</td> <!-- transition -->
+ <td>init</td> <!-- previous state -->
+ <td>INVITE and <!-- input -->
+ @ref NUTAG_AUTOALERT() "auto-alert"</td>
+ <td>180 Ringing</td> <!-- output -->
+ <td>early</td> <!-- next state -->
+ <td>-</td> <!-- offer/answer -->
+ <td>
+ There is no SDP to save.
+</td></tr>
+<tr><td>S3a'</td> <!-- transition -->
+ <td>early</td> <!-- previous state -->
+ <td rowspan=2>nua_respond()</td> <!-- input -->
+ <td rowspan=2>2XX</td> <!-- output -->
+ <td rowspan=3>completed</td> <!-- next state -->
+ <td rowspan=3>Generate offer</td> <!-- offer/answer -->
+ <td rowspan=3>
+ The offer is sent in 200 OK.
+</td></tr>
+<tr><td>S3b'</td> <!-- transition -->
+ <td>received</td> <!-- previous state -->
+</td></tr>
+<tr><td>S3c'</td> <!-- transition -->
+ <td>init</td> <!-- previous state -->
+ <td>INVITE and <!-- input -->
+ @ref NUTAG_AUTOANSWER() "auto-answer"</td>
+ <td>200 OK</td> <!-- output -->
+</td></tr>
+<tr><td>S4'</td> <!-- transition -->
+ <td>completed</td> <!-- previous state -->
+ <td>ACK</td> <!-- input -->
+ <td>-</td> <!-- output -->
+ <td>ready</td> <!-- next state -->
+ <td>Save and process answer</td> <!-- offer/answer -->
+ <td>
+ The answer is processed and media activated after receiving @b ACK.
+</td></tr>
+<tr><td>S9b'</td> <!-- transition -->
+ <td>completed</td> <!-- previous state -->
+ <td>ACK and O/A error</td> <!-- input -->
+ <td>BYE</td> <!-- output -->
+ <td>terminating</td> <!-- next state -->
+ <td>Save and process answer</td> <!-- offer/answer -->
+ <td>
+ If the offer/answer negotiation ends in error after the server receives
+ answer in @b ACK request, the server will have to terminate call by
+ sending a @b BYE request.
+</td></tr>
+</table>
+
+
+ at section nua_terminate_call_model Model for Modifying and Terminating Call
+
+After the SIP session has been established, it can be further modified by @b
+INVITE transactions, initiated by either the original client or the original
+server. These so-called re-INVITE transactions can be used to upgrade
+session (add new media to it), put the session on hold or resume a held
+call.
+
+A session can be terminated with a @b BYE request at any time.
+
+If any in-dialog request (including re-INVITE) fails with certain response
+code, the session can be considered terminated, too. These response codes
+are documented with sip_response_terminates_dialog(). In some cases, the
+session should be terminated gracefully by sending a @b BYE request after
+the failed requests.
+
+ at code
+ +-------------------------------------------------------------+
+ | READY |
+ +-------------------------------------------------------------+
+ | | | |
+ | | | |
+ (1) BYE/200 (2) nua_bye/BYE (4) graceful/BYE (5) fatal/-
+ | | | |
+ | V V |
+ | +-----------------------------+ |
+ | | TERMINATING | |
+ | +-----------------------------+ |
+ | | |
+ | (3) [23456]XX/- |
+ | | |
+ V V V
+ +-------------------------------------------------------------+
+ | TERMINATED |
+ +-------------------------------------------------------------+
+ at endcode
+
+The detailed description of state transitions while call is terminated is as
+follows:
+<table>
+<tr><th>#</th>
+ <th>Previous state</th>
+ <th>Input</th>
+ <th>Output</th>
+ <th>Next state</th>
+ <th align="left">Description</th>
+</tr>
+<tr><td>T1</td> <!-- transition -->
+ <td>ready</td> <!-- previous state -->
+ <td>BYE</td> <!-- input -->
+ <td>200 OK</td> <!-- output -->
+ <td>terminated</td> <!-- next state -->
+ <td>
+ When the @b BYE request is received, the recipient terminates the
+ currently ongoing @b INVITE transaction, the session and its dialog
+ usage (if there is another dialog usage active, e.g., a subscription
+ creted by @b REFER.)
+</td></tr>
+<tr><td>T2</td> <!-- transition -->
+ <td>ready</td> <!-- previous state -->
+ <td>nua_bye</td> <!-- input -->
+ <td>BYE</td> <!-- output -->
+ <td>terminating</td> <!-- next state -->
+ <td>
+ The application terminates the session by calling nua_bye(). All the
+ call-related requests on the dialog are rejected while in
+ terminating state with <i>487 No Such Call</i> response.
+</td></tr>
+<tr><td>T3</td> <!-- transition -->
+ <td>terminating</td> <!-- previous state -->
+ <td>2XX 3XX 4XX 5XX 6XX</td> <!-- input -->
+ <td>-</td> <!-- output -->
+ <td>terminated</td> <!-- next state -->
+ <td>
+ The session is finally terminated when a final response to @b BYE is
+ received. Note that nua stack does retry @b BYE requests.
+</td></tr>
+<tr><td>T4</td> <!-- transition -->
+ <td>ready</td> <!-- previous state -->
+ <td>"graceful" response</td> <!-- input -->
+ <td>BYE</td> <!-- output -->
+ <td>terminating</td> <!-- next state -->
+ <td>
+ A call-related request (@b re-INVITE, @b UPDATE, @b INFO, @b PRACK,
+ @b REFER) fails with a response code indicating that the client
+ should gracefully terminate the call.
+</td></tr>
+<tr><td>T5</td> <!-- transition -->
+ <td>ready</td> <!-- previous state -->
+ <td>"fatal" response</td> <!-- input -->
+ <td>-</td> <!-- output -->
+ <td>terminated</td> <!-- next state -->
+ <td>
+ A call-related request (@b re-INVITE, @b UPDATE, @b INFO, @b PRACK,
+ @b REFER) fails with a response code indicating that the call has
+ been terminated.
+</td></tr>
+</table>
+
+ at sa http://www.ietf.org/internet-drafts/draft-sparks-sipping-dialogusage-01.txt
+ at sa sip_response_terminates_dialog()
+
+*/
+
+/*
+For reference:
+
+ +---------------+
+ +-(1)--| INIT |-----+
+ INVITE/- | +---------------+ (A) INVITE/100
+ V |
+ +------------+ +------------+
+ +----| CALLING | +---| RECEIVED |--+
+ | +------------+ | +------------+ |
+ | | | | |
+ | (2) 18X/- | (B) -/18X |
+ | V | V |
+ | +------------+ | +------------+ |
+ |<---| PROCEEDING |--+ | | EARLY |->|
+ | +------------+ | | +------------+ (F) -/[3456]XX
+ | : | | | |
+ | (4) 2XX/- | (E) -/2XX (C) -/2XX | or
+ | V | | V |
+ | + - - - - - -+ | | +------------+ (G) CANCEL/200,487
+ | : COMPLETING : | +-->| COMPLETE | |
+ | + - - - - - -+ | +------------+ |
+ | : | | : |
+ | (5)-/ACK (3) 2XX/ACK ACK/-(D) : |
+ | : | | : |
+ | : V | : |
+ | : +---------------+ | : |
+ | + - - >| READY |<----+ : |
+ | +---------------+ : |
+ | | | : |
+ | BYE/200 (i) (ii) -/BYE timeout/ : |
+ | | | BYE (H) |
+ | | V : |
+ | | +--------------+ : |
+ (6) [3456]XX/ACK | | TERMINATING |<- - + |
+ | | +--------------+ |
+ | | | |
+ | | (iii) [23456]XX/- |
+ | V V |
+ | +---------------+ |
+ +---------------->| TERMINATED |<--------------+
+ +---------------+
+ |
+ V
+ INIT
+
+*/
+
+/**@page nua_event_diagrams NUA Event Diagrams
+
+The example diagrams below try to present how to use NUA API with different
+SIP use cases.
+
+ at section nua_event_diagram_call Basic Call
+
+The SIP following event diagram shows a pretty simple, succesful call case.
+The nua events and nua function calls are show in the diagram below as well
+as the SIP messages.
+
+The call setup above assumes parameters NUTAG_AUTOALERT(0),
+NUTAG_AUTOANSWER(0) on B side, NUTAG_AUTOACK(0) on A side.
+
+ at code
+
+ Alice Proxy Bob
+ 0 | | |
+ 1 nua_handle() | | |
+ 2 nua_invite() -> |-----INVITE---->| |
+ 3 nua_i_state <- | | |
+ 4 | |-----INVITE---->| -> nua_i_invite
+ 5 |<--100 Trying---| | -> nua_i_state
+ 6 | | |
+ 7 | | |
+ 8 | | |
+ 9 | |<--180 Ringing--| <- nua_respond(180)
+10 nua_i_invite <- |<--180 Ringing--| | -> nua_i_state
+11 nua_i_state <- | | |
+12 | |<--200 OK-------| <- nua_respond(200)
+13 nua_i_invite <- |<---200 OK------| | -> nua_i_state
+14 nua_i_state <- | | |
+15 nua_ack() -> |-----ACK------->| |
+16 nua_i_state <- | |-----ACK------->| -> nua_i_ack
+17 | | | -> nua_i_state
+18 | | |
+19 <<====== SIP Session Established =======>>
+20 | | |
+21 | | |
+22 nua_bye() -> |-----BYE------->| |
+23 | |-----BYE------->| -> nua_i_bye
+24 | |<----200 OK-----| -> nua_i_state
+25 nua_r_bye <- |<---200 OK------| |
+26 nua_i_state <- | | |
+ | | |
+ at endcode
+
+ at section nua_event_diagram_call_hold Holding Call
+
+The media (audio, video) can be put on hold. In SIP system this means that
+application can indicate to the remote end that it is engaged in other
+activity (another call, for instance) and does not wish to receive media
+from the remove end.
+
+The call hold is usully implemented using re-INVITE. Re-INVITE is an INVITE
+request sent on existing SIP session. Both original caller and callee can
+send re-INVITEs. The main use of re-INVITE is modifying sessions: adding
+media lines to the session, changing codecs on existing media, and, as you
+might expect, putting existing media on hold as well as resuming media from
+hold.
+
+A re-INVITE is sent by calling nua_invite() on handle with existing call.
+When putting call on hold, the application can include SOATAG_HOLD("audio")
+or SOATAG_HOLD("video") or SOATAG_HOLD("audio, video") or SOATAG_HOLD("*")
+as parameters to re-INVITE nua_invite(). (Note that last SOATAG_HOLD() in
+the tag list will override the SOATAG_HOLD() tags before it.)
+
+Another feature where nua tries to be helpful is autoanswer and auto-ACK on
+existing sessions: the re-INVITE is automatically responded with <i>200 OK</i>
+and ACK is automatically sent. (If the application wants to respond and ACK
+by itself, it should explicitly set NUTAG_AUTOANSWER(0) and/or
+NUTAG_AUTOACK(0) in the handle; either include them in nua_invite() or
+nua_respond() parameters or call nua_set_hparams() explicitly.
+
+ at code
+ Alice Proxy Bob
+ 0 nua_handle() | | |
+ 1 | | |
+ 2 nua_invite() -> |-----INVITE---->| |
+ 3 nua_i_state <- | | |
+ 4 | |-----INVITE---->| -> nua_i_invite
+ 5 |<--100 Trying---| | -> nua_i_state
+ 6 | | |
+ 7 | | |
+ 8 | | |
+ 9 | |<--180 Ringing--| <- nua_respond(180)
+10 nua_i_invite <- |<--180 Ringing--| | -> nua_i_state
+11 nua_i_state <- | | |
+12 | |<--200 OK-------| <- nua_respond(200)
+13 nua_i_invite <- |<---200 OK------| | -> nua_i_state
+14 nua_i_state <- | | |
+15 nua_ack() -> |-----ACK------->| |
+16 nua_i_state <- | |-----ACK------->| -> nua_i_ack
+17 | | | -> nua_i_state
+18 | | |
+19 <<== Bi-Directional RTP Established ==>>
+20 | | |
+21 | | |
+22 | |<--INVITE(hold)-| <- nua_invite(..
+21 | | | NUTAG_HOLD("*")..)
+23 nua_i_invite <- |<-INVITE(hold)--| | -> nua_i_state
+25 nua_i_state <- |----200 OK----->| |
+26 | |----200 OK----->| -> nua_i_invite
+28 | |<-----ACK-------| -> nua_i_state
+29 nua_i_ack <- |<----ACK--------| |
+24 | | |
+30 <<== Uni-Directional RTP Established ==>>
+24 | | |
+31 | | |
+32 | |<--INVITE-------| <- nua_invite(..
+21 | | | NUTAG_HOLD(NULL)..)
+33 nua_i_invite <- |<--INVITE-------| | -> nua_i_state
+35 nua_i_state <- |---200 OK------>| |
+36 | |---200 OK------>| -> nua_i_invite
+38 | |<----ACK--------| -> nua_i_state
+39 nua_i_ack <- |<----ACK--------| |
+40 nua_i_state <- | | |
+19 <<== Bi-Directional RTP Established ==>>
+42 | | |
+43 nua_bye() -> |-----BYE------->| |
+44 nua_i_state <- | |-----BYE------->| -> nua_i_bye
+46 | |<----200 OK-----| -> nua_i_state
+47 |<---200 OK------| |
+ | | |
+ at endcode
+
+
+
+ at section nua_event_diagram_call_transfer Call Transfer
+
+This is the unattended call transfer case.
+
+1st MSC showing Alice's end:
+
+ at code
+ Alice Bob Carol
+ 0 | | |
+ 1 nua_i_invite <- |<-----INVITE--------| |
+ 2 nua_i_state <- | | |
+ 2 | | |
+ 3 nua_respond(180) -> |----180 Ringing---->| |
+ 2 nua_i_state <- | | |
+ 4 | | |
+ 5 nua_respond(200) -> |------200 OK------->| |
+ 6 nua_i_state <- | | |
+ 8 | | |
+ 7 nua_i_ack <- |<-------ACK---------| |
+ 8 nua_i_state <- | | |
+ 9 |<========RTP=======>| |
+10 | | |
+11 << Alice performs unattended transfer >> |
+12 | | |
+13 | | |
+14 nua_refer() -> |---REFER("r: C")--->| |
+15 | | |
+16 nua_r_refer <- |<---202 Accepted----| |
+17 | | |
+18 nua_i_notify <- |<-----NOTIFY--------| |
+19 | | |
+20 |------200 OK------->| |
+21 | |---INVITE("b: A")-->|
+23 | | |
+22 nua_bye() -> |-------BYE--------->| |
+23 | | |
+24 nua_r_bye <- |<----200 OK---------| |
+25 nua_i_state <- | No RTP Session | |
+28 | |<----180 Ringing----|
+26 nua_i_notify <- |<- - -NOTIFY - - - -| |
+27 | | |
+20 |- - - 200 OK- - - ->| |
+29 | | |
+30 | |<------200 OK-------|
+31 | | |
+32 | |---------ACK------->|
+33 | | RTP |
+34 | |<==================>|
+35 | | |
+36 |<-----NOTIFY--------| |
+37 | | |
+38 |------200 OK------->| |
+ | | |
+ at endcode
+
+2nd MSC showing Bobs's end:
+
+ at code
+ Alice Bob (nh1) Bob (nh2) Carol
+ 0 | | | |
+ 1 |<-----INVITE--------| | |
+ 2 | | | |
+ 3 |---180 Ringing----->| | |
+ 4 | | | |
+ 5 |------200 OK------->| | |
+ 6 | | | |
+ 7 |<-------ACK---------| | |
+ 8 | RTP | | |
+ 9 |<==================>| | |
+10 | | | |
+11<< Alice performs unattended transfer >> | |
+12 | | | |
+13 | Refer-To:C F5| | |
+14 |-REFER------------->| -> nua_i_refer | |
+15 | | | |
+16 |<-202 Accepted------| | |
+17 | | | |
+18 |<-----NOTIFY--------| | |
+19 | | | |
+20 |------200 OK------->| -> nua_r_notify | |
+21 | | | |
+22 |-------BYE--------->| -> nua_i_bye | |
+23 | | -> nua_i_state | |
+24 |<----200 OK---------| nua_handle() -> | |
+25 | No RTP Session | nua_invite() -> | |
+26 | | |--INVITE("b: A")--->|
+27 | | | |
+28 | | nua_i_invite <- |<--180 Ringing------|
+29 | | nua_i_state <- | |
+30 | | nua_i_invite <- |<----200 OK---------|
+31 | | nua_i_state <- | |
+32 | | nua_ack -> |-------ACK--------->|
+33 | | | |
+34 | | |<=======RTP========>|
+35 | | | |
+36 |<-----NOTIFY--------| | |
+37 | |
+38 |------200 OK------->| -> nua_r_notify
+39 | | <- nua_handle_destroy
+ | |
+ at endcode
+
+Bob includes nh1 in nua_invite()/25 as NUTAG_NOTIFY_REFER() parameter.
+
+Open Issue 1:
+
+- how Bob know when to destroy nh1?
+
+
+ at section nua_event_diagram_3gpp_call 3GPP Call Model
+
+The 3GPP call model is defined in 3GPP TS 24.229. In order to select only a
+single codec and ensure that the QoS reservationa are made before the call
+is alerting, the 3GPP call model employs multiple offer/answer exchanges. It
+uses 100rel and PRACK (@RFC3262), UPDATE (@RFC3311) and preconditions
+(@RFC3312) extensions specified by IETF.
+
+The call setup below assumes parameters NUTAG_AUTOALERT(0),
+NUTAG_AUTOANSWER(0) on B side, NUTAG_AUTOACK(0) on A side.
+
+ at code
+ A B
+ 0 nua_handle() | |
+ 1 nua_invite() -> | |
+ 2 nua_i_state <- |----INVITE (offer)---->|
+ 3 | | -> nua_i_invite
+ 4 | | -> nua_i_state
+ 5 | |
+ 6 | | <- nua_respond(183)
+ 7 nua_i_invite <- |<----183 (answer)------| -> nua_i_state
+ 8 nua_i_state <- | |
+ 9 << single codec is selected now >>
+10 |-----PRACK(offer2)---->| -> nua_i_prack
+11 | | -> nua_i_state
+12 nua_r_prack <- |<--200/PRACK(answer2)--|
+13 | |
+14 | |
+15 << resource reservations are done now >>
+16 | |
+17 nua_update() -> |----UPDATE (offer3)--->|
+18 nua_i_state <- | |
+19 nua_i_state <- |<-200/UPDATE (answer3)-| -> nua_i_update
+20 | | -> nua_i_state
+21 | |
+22 | | << B rings >>
+23 | |
+24 | | <- nua_respond(180)
+25 nua_i_invite <- |<---------180----------|
+26 nua_i_state <- | |
+27 |--------PRACK--------->| -> nua_i_prack
+28 nua_r_prack <- |<-----200/PRACK------->| -> nua_i_state
+29 | |
+30 | | <- nua_respond(200)
+31 nua_i_invite <- |<---------200----------| -> nua_i_state
+32 nua_i_state <- | |
+33 nua_ack() -> | |
+34 nua_i_state <- |----------ACK--------->| -> nua_i_ack
+35 | | -> nua_i_state
+ | |
+ at endcode
+
+*/
+
+/**@var nua_event_e
+ *
+ * @brief Events
+ *
+ * The NUA event loop calls an event callback function when an application
+ * needs to act on something that happened in the Sofia stack. The callback
+ * function is registered when nua_create() function call is used to create
+ * the NUA stack object.
+ *
+ * The prototype of the event callback function is:
+ * @code
+ * void nua_callback_f(nua_event_t event,
+ * int status,
+ * char const *phrase,
+ * nua_t *nua,
+ * nua_magic_t *magic,
+ * nua_handle_t *nh,
+ * nua_hmagic_t *hmagic,
+ * sip_t const *sip,
+ * tagi_t tags[]);
+ * @endcode
+ *
+ * @param event Callback event identification. \n
+ * Always present
+ * @param status Protocol status code. \n
+ * Always present
+ * @param phrase Text corresponding to status code. \n
+ * Always present
+ * @param nua Pointer to NUA stack object. \n
+ * Always present
+ * @param magic Pointer to callback context from nua_create(). \n
+ * Always present
+ * @param nh Pointer to operation handle.
+ * @param hmagic Pointer to callback context from nua_handle().
+ * @param sip Parsed incoming message. May be NULL.
+ * @param tags Tag list containing more information about the state of NUA.
+ * May be empty.
+ *
+ * Note that the contents of the last four parameters vary depending on
+ * the event. The descriptions can be found from the description of the
+ * individual event.
+ *
+ * The events can be divided into the following categories: \n
+ * @par Indications:
+ * #nua_i_active \n
+ * #nua_i_ack \n
+ * #nua_i_bye \n
+ * #nua_i_cancel \n
+ * #nua_i_chat \n
+ * #nua_i_error \n
+ * #nua_i_fork \n
+ * #nua_i_info \n
+ * #nua_i_invite \n
+ * #nua_i_media_error \n
+ * #nua_i_message \n
+ * #nua_i_method \n
+ * #nua_i_notify \n
+ * #nua_i_options \n
+ * #nua_i_prack \n
+ * #nua_i_publish \n
+ * #nua_i_refer \n
+ * #nua_i_register \n
+ * #nua_i_subscribe \n
+ * #nua_i_subscription \n
+ * #nua_i_state \n
+ * #nua_i_terminated \n
+ * #nua_i_update
+ *
+ * @par Responses:
+ * #nua_r_get_params \n
+ * #nua_r_notifier \n
+ * #nua_r_shutdown \n
+ * #nua_r_terminate
+ *
+ * @par SIP responses:
+ * #nua_r_bye \n
+ * #nua_r_cancel \n
+ * #nua_r_info \n
+ * #nua_r_invite \n
+ * #nua_r_message \n
+ * #nua_r_notify \n
+ * #nua_r_options \n
+ * #nua_r_prack \n
+ * #nua_r_publish \n
+ * #nua_r_refer \n
+ * #nua_r_register \n
+ * #nua_r_subscribe \n
+ * #nua_r_unpublish \n
+ * #nua_r_unregister \n
+ * #nua_r_unsubscribe \n
+ * #nua_r_update
+ */
+
+/** @NUA_EVENT nua_i_chat
+ *
+ * Incoming chat message.
+ *
+ * @param nh operation handle associated with the message
+ * @param hmagic operation magic associated with the handle
+ * @param sip incoming chat message
+ * @param tags empty
+ *
+ * @END_NUA_EVENT
+ */
+
+/** @NUA_EVENT nua_i_error
+ *
+ * Error indication.
+ *
+ * Will be sent when an internal error happened or
+ * an error occurred while responding a request.
+ *
+ * @param status SIP status code or NUA status code (>= 900)
+ * describing the problem
+ * @param phrase a short textual description of @a status code
+ * @param nh NULL or operation handle associated with the call
+ * @param hmagic NULL or operation magic associated with the call
+ * @param sip NULL
+ * @param tags empty or error specific information
+ *
+ * @END_NUA_EVENT
+ */
+
+/** @NUA_EVENT nua_i_fork
+ *
+ * Outgoing call has been forked.
+ *
+ * This is sent when an INVITE request is answered with multiple 200 responses.
+ *
+ * @param status response status code
+ * @param phrase a short textual description of @a status code
+ * @param nh operation handle associated with the original call
+ * @param hmagic operation magic associated with the original call
+ * @param sip preliminary or 2XX response to INVITE
+ * @param tags NUTAG_HANDLE() of the new forked call
+ *
+ * @sa #nua_r_invite, #nua_i_state, @ref nua_call_model
+ *
+ * @END_NUA_EVENT
+ */
+
+/** @NUA_EVENT nua_i_media_error
+ *
+ * Media error indication.
+ *
+ * This may be sent after an SOA operation has failed while processing
+ * incoming or outgoing call.
+ *
+ * @param status SIP status code or NUA status code (>= 900)
+ * describing the problem
+ * @param phrase a short textual description of @a status code
+ * @param nh operation handle associated with the call
+ * @param hmagic operation magic associated with this handle
+ * (maybe NULL if call handle was created for this call)
+ * @param sip NULL
+ * @param tags empty
+ *
+ * @END_NUA_EVENT
+ */
+
+/* nua_i_message is documented with nua_stack_process_message() */
+
+/* nua_i_method is documented with nua_stack_process_method() */
+
+/** @NUA_EVENT nua_i_network_changed
+ *
+ * Local IP(v6) address has changed.
+ *
+ * @param nh default operation handle
+ * @param hmagic operation magic associated with the default operation handle
+ * @param sip NULL
+ * @param tags empty
+ *
+ * @since Experimental in @VERSION_1_12_2.
+ *
+ * @END_NUA_EVENT
+ */
+
+/* nua_i_notify is documented with nua_stack_process_notify() */
+
+/* nua_i_options is documented with nua_stack_process_options() */
+
+/* nua_i_publish is documented with nua_stack_process_publish() */
+
+/* nua_i_refer is documented with nua_stack_process_refer() */
+
+/* nua_i_subscribe is documented with nua_stack_process_subscribe() */
+
+/** @NUA_EVENT nua_i_subscription
+ *
+ * Incoming subscription to be authorized.
+ *
+ * This event is launched by nua_notifier() to inform application of the
+ * current state of the subscriber. The subscriber state is included in the
+ * NUTAG_SUBSTATE() tag. If the state is #nua_substate_pending or
+ * #nua_substate_embryonic, application should to authorize the subscriber
+ * with nua_authorize().
+ *
+ * @param nh operation handle associated with the notifier
+ * @param hmagic operation magic
+ * @param status statuscode of response sent automatically by stack
+ * @param sip incoming SUBSCRIBE request
+ * @param tags NEATAG_SUB(),
+ * NUTAG_SUBSTATE()
+ *
+ * @sa nua_notifier(), #nua_i_subscribe, nua_authorize(), nua_terminate()
+ * @RFC3265
+ *
+ * @END_NUA_EVENT
+ */
+
+/* nua_i_update is documented with nua_stack_process_update() */
+
+/* nua_r_bye is documented with process_response_to_bye() */
+
+/* nua_r_cancel is documented with process_response_to_cancel() */
+
+/** @NUA_EVENT nua_r_chat
+ *
+ * Answer to outgoing chat message.
+ *
+ * @param nh operation handle associated with the notifier
+ * @param hmagic operation magic associated with the notifier
+ * @param sip response to MESSAGE request or NULL upon an error
+ * (error code and message are in status an phrase parameters)
+ * @param tags empty
+ *
+ * @sa nua_chat(), #nua_r_message
+ *
+ * @END_NUA_EVENT
+ */
+
+/* nua_r_info is documented with process_response_to_info() */
+
+/* nua_r_invite is documented with process_response_to_invite() */
+
+/* nua_r_message is documented with process_response_to_message() */
+
+/** @NUA_EVENT nua_r_notifier
+ *
+ * Answer to nua_notitier()
+ *
+ * @param nh operation handle associated with the call
+ * @param hmagic operation magic associated with the call
+ * @param sip NULL
+ * @param tags SIPTAG_EVENT() \n
+ * SIPTAG_CONTENT_TYPE()
+ *
+ * @sa nua_notitier(), #nua_i_subscription, @RFC3265
+ *
+ * @END_NUA_EVENT
+ */
+
+/* nua_r_notify is documented with process_response_to_notify() */
+
+/* nua_r_options is documented with process_response_to_options() */
+
+/* nua_r_prack is documented with process_response_to_prack() */
+
+/* nua_r_publish is documented with process_response_to_publish() */
+
+/* nua_r_refer is documented with process_response_to_refer() */
+
+/* nua_r_shutdown is documented with nua_stack_shutdown() */
+
+/* nua_r_subscribe is documented with process_response_to_subscribe() */
+
+/** @NUA_EVENT nua_r_terminate
+ *
+ * Answer to nua_terminate().
+ *
+ * @param nh operation handle associated with the notifier
+ * @param hmagic operation magic associated with the notifier
+ * @param sip NULL
+ * @param tags empty
+ *
+ * @sa nua_terminate(), nua_handle_destroy()
+ *
+ * @END_NUA_EVENT
+ */
+
+/* nua_r_unsubscribe is documented with process_response_to_subscribe() */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_common.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_common.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,303 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nua_common.c
+ * @brief Function common to both stack and application side.
+ *
+ * @author Pekka.Pessi at nokia.com
+ *
+ * @date Created: Tue Apr 26 13:23:17 2005 ppessi
+ *
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <assert.h>
+
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/su_tagarg.h>
+#include <sofia-sip/su_uniqueid.h>
+
+#include <stdio.h>
+
+#include <sofia-sip/su_tag_io.h>
+
+#define SU_LOG (nua_log)
+#include <sofia-sip/su_debug.h>
+
+#define SU_ROOT_MAGIC_T struct nua_s
+#define SU_MSG_ARG_T struct event_s
+
+#include <sofia-sip/su_wait.h>
+
+#include <sofia-sip/su_strlst.h>
+
+#include "sofia-sip/nua.h"
+#include "sofia-sip/nua_tag.h"
+
+#include <sofia-sip/sip_protos.h>
+#include <sofia-sip/nta.h>
+#include <sofia-sip/nea.h>
+
+#include <sofia-sip/auth_client.h>
+#if HAVE_SMIME /* Start NRC Boston */
+#include "smimec.h"
+#endif /* End NRC Boston */
+
+#include <sofia-sip/sdp.h>
+
+#include "nua_stack.h"
+
+static void nh_destructor(void *arg);
+
+/**@internal
+ * Create an operation handle
+ *
+ * Allocates a new operation handle and associated storage.
+ *
+ * @param nua Pointer to NUA stack object
+ * @param hmagic Pointer to callback context
+ * @param tags List of tagged parameters
+ *
+ * @retval non-NULL Pointer to operation handle
+ * @retval NULL Creation failed
+ *
+ * @par Related tags:
+ * Creates a copy of the provided tags which will
+ * be used with every operation.
+ *
+ * @par Events:
+ * none
+ *
+ * @note
+ * This function is called by both stack and application sides.
+ */
+nua_handle_t *nh_create_handle(nua_t *nua,
+ nua_hmagic_t *hmagic,
+ tagi_t *tags)
+{
+ nua_handle_t *nh;
+ static int8_t _handle_lifetime = 1;
+
+ enter;
+
+ assert(nua->nua_home);
+
+ if ((nh = su_home_clone(nua->nua_home, sizeof(*nh)))) {
+ nh->nh_valid = nua_handle;
+ nh->nh_nua = nua;
+ nh->nh_magic = hmagic;
+ nh->nh_prefs = nua->nua_dhandle->nh_prefs;
+
+ if (nua_handle_save_tags(nh, tags) < 0) {
+ SU_DEBUG_5(("nua(%p): creating handle %p failed\n", nua, nh));
+ su_home_unref(nh->nh_home), nh = NULL;
+ }
+
+ if (nh && su_home_is_threadsafe(nua->nua_home)) {
+ if (su_home_threadsafe(nh->nh_home) < 0) {
+ su_home_unref(nh->nh_home);
+ nh = NULL;
+ }
+ }
+
+ if (nh && _handle_lifetime) {
+ /* This far, we have nothing real to destruct but
+ * when _NUA_HANDLE_DEBUG is set, we add destructor
+ * and get more entertaining debugging output */
+ if (_handle_lifetime == 1 && !getenv("_NUA_HANDLE_DEBUG")) {
+ _handle_lifetime = 0;
+ }
+ else {
+ _handle_lifetime = 2;
+ SU_DEBUG_0(("nh_handle_create(%p)\n", nh));
+ su_home_destructor(nh->nh_home, nh_destructor);
+ }
+ }
+ }
+
+ return nh;
+}
+
+/**@var _NUA_HANDLE_DEBUG
+ *
+ * If this environment variable is set, nua stack logs a message whenever a
+ * handle is created and when it is destroyed. This is mainly useful when
+ * debugging #nua_handle_t leaks.
+ *
+ * @sa nua_handle(), nua_handle_destroy()
+ */
+extern char const _NUA_HANDLE_DEBUG[];
+
+/* nua handle destructor. It does nothing. */
+static void nh_destructor(void *arg)
+{
+ nua_handle_t *nh = arg;
+
+ SU_DEBUG_0(("nh_destructor(%p)\n", nh));
+}
+
+/** Make a new reference to handle.
+ *
+ * The handles use reference counting for memory management. In addition to
+ * the memory management, there is protocol state associated with the
+ * handles. The protocol state is terminated with nua_handle_destroy(). In
+ * order to make it more convenient for programmer, nua_handle_destroy()
+ * decreases the reference count, too.
+ *
+ * @note All handle references are destroyed when the nua object is destroyed.
+ *
+ * @sa nua_handle_unref(), nua_handle(), nua_handle_destroy().
+ */
+nua_handle_t *nua_handle_ref(nua_handle_t *nh)
+{
+ return (nua_handle_t *)su_home_ref(nh->nh_home);
+}
+
+
+/** Destroy reference to handle.
+ *
+ * The handles use reference counting for memory management. In addition to
+ * the memory management, there is protocol state associated with the
+ * handles. The protocol state is terminated with nua_handle_destroy(). In
+ * order to make it more convenient for programmer, nua_handle_destroy()
+ * decreases the reference count, too.
+ *
+ * @sa nua_handle_ref(), nua_handle(), nua_handle_destroy().
+ */
+int nua_handle_unref(nua_handle_t *nh)
+{
+ return su_home_unref(nh->nh_home);
+}
+
+/** Generate an instance identifier. */
+char const *nua_generate_instance_identifier(su_home_t *home)
+{
+ char str[su_guid_strlen + 1];
+ su_guid_t guid[1];
+
+ su_guid_generate(guid);
+ /*
+ * Guid looks like "NNNNNNNN-NNNN-NNNN-NNNN-XXXXXXXXXXXX"
+ * where NNNNNNNN-NNNN-NNNN-NNNN is timestamp and XX is MAC address
+ * (but we use usually random ID for MAC because we do not have
+ * guid generator available for all processes within node)
+ */
+ su_guid_sprintf(str, su_guid_strlen + 1, guid);
+
+ return su_strdup(home, str);
+}
+
+/** Get name for a NUA event. */
+char const *nua_event_name(nua_event_t event)
+{
+ switch (event) {
+ case nua_i_error: return "nua_i_error";
+ case nua_i_invite: return "nua_i_invite";
+ case nua_i_cancel: return "nua_i_cancel";
+ case nua_i_ack: return "nua_i_ack";
+
+ case nua_i_register: return "nua_i_register";
+ case nua_i_fork: return "nua_i_fork";
+ case nua_i_active: return "nua_i_active";
+ case nua_i_terminated: return "nua_i_terminated";
+ case nua_i_state: return "nua_i_state";
+ case nua_i_outbound: return "nua_i_outbound";
+
+ case nua_i_bye: return "nua_i_bye";
+ case nua_i_options: return "nua_i_options";
+ case nua_i_refer: return "nua_i_refer";
+ case nua_i_publish: return "nua_i_publish";
+ case nua_i_prack: return "nua_i_prack";
+ case nua_i_info: return "nua_i_info";
+ case nua_i_update: return "nua_i_update";
+ case nua_i_message: return "nua_i_message";
+ case nua_i_chat: return "nua_i_chat";
+ case nua_i_subscribe: return "nua_i_subscribe";
+ case nua_i_subscription: return "nua_i_subscription";
+ case nua_i_notify: return "nua_i_notify";
+ case nua_i_method: return "nua_i_method";
+
+ case nua_i_media_error: return "nua_i_media_error";
+
+ /* Responses */
+ case nua_r_get_params: return "nua_r_get_params";
+ case nua_r_shutdown: return "nua_r_shutdown";
+ case nua_r_notifier: return "nua_r_notifier";
+ case nua_r_terminate: return "nua_r_terminate";
+
+ case nua_r_register: return "nua_r_register";
+ case nua_r_unregister: return "nua_r_unregister";
+ case nua_r_invite: return "nua_r_invite";
+ case nua_r_bye: return "nua_r_bye";
+ case nua_r_options: return "nua_r_options";
+ case nua_r_refer: return "nua_r_refer";
+ case nua_r_publish: return "nua_r_publish";
+ case nua_r_unpublish: return "nua_r_unpublish";
+ case nua_r_info: return "nua_r_info";
+ case nua_r_prack: return "nua_r_prack";
+ case nua_r_update: return "nua_r_update";
+ case nua_r_message: return "nua_r_message";
+ case nua_r_chat: return "nua_r_chat";
+ case nua_r_subscribe: return "nua_r_subscribe";
+ case nua_r_unsubscribe: return "nua_r_unsubscribe";
+ case nua_r_notify: return "nua_r_notify";
+ case nua_r_method: return "nua_r_method";
+
+ case nua_r_cancel: return "nua_r_cancel";
+ case nua_r_authenticate: return "nua_r_authenticate";
+ case nua_r_authorize: return "nua_r_authorize";
+ case nua_r_redirect: return "nua_r_redirect";
+ case nua_r_destroy: return "nua_r_destroy";
+ case nua_r_respond: return "nua_r_respond";
+ case nua_r_nit_respond: return "nua_r_nit_respond";
+ case nua_r_set_params: return "nua_r_set_params";
+ case nua_r_ack: return "nua_r_ack";
+ default: return "NUA_UNKNOWN";
+ }
+}
+
+/** Return name of call state */
+char const *nua_callstate_name(enum nua_callstate state)
+{
+ switch (state) {
+ case nua_callstate_init: return "init";
+ case nua_callstate_authenticating: return "authenticating";
+ case nua_callstate_calling: return "calling";
+ case nua_callstate_proceeding: return "proceeding";
+ case nua_callstate_completing: return "completing";
+ case nua_callstate_received: return "received";
+ case nua_callstate_early: return "early";
+ case nua_callstate_completed: return "completed";
+ case nua_callstate_ready: return "ready";
+ case nua_callstate_terminating: return "terminating";
+ case nua_callstate_terminated: return "terminated";
+ default: return "UNKNOWN";
+ }
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,554 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nua_dialog.c
+ * @brief Dialog and dialog usage handling
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Mar 8 11:48:49 EET 2006 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include <assert.h>
+
+#include <sofia-sip/string0.h>
+#include <sofia-sip/su_uniqueid.h>
+
+#include <sofia-sip/sip_protos.h>
+
+#define NUA_OWNER_T su_home_t
+
+#include "nua_dialog.h"
+
+#define SU_LOG (nua_log)
+#include <sofia-sip/su_debug.h>
+
+#ifndef NONE
+#define NONE ((void *)-1)
+#endif
+
+/* ======================================================================== */
+/* Dialog handling */
+
+static void nua_dialog_usage_remove_at(nua_owner_t*, nua_dialog_state_t*,
+ nua_dialog_usage_t**);
+static void nua_dialog_log_usage(nua_owner_t *, nua_dialog_state_t *);
+
+/**@internal
+ * UAS tag and route.
+ *
+ * Update dialog tags and route on the UAS side.
+ *
+ * @param own dialog owner
+ * @param ds dialog state
+ * @param sip SIP message containing response used to update dialog
+ * @param rtag if true, set remote tag within the leg
+ */
+void nua_dialog_uas_route(nua_owner_t *own,
+ nua_dialog_state_t *ds,
+ sip_t const *sip,
+ int rtag)
+{
+ int established = nua_dialog_is_established(ds);
+
+ if (!established && sip->sip_from->a_tag)
+ ds->ds_remote_tag = su_strdup(own, sip->sip_from->a_tag);
+
+ if (ds->ds_leg == NULL)
+ return;
+
+ nta_leg_server_route(ds->ds_leg, sip->sip_record_route, sip->sip_contact);
+ ds->ds_route = ds->ds_route || sip->sip_record_route || sip->sip_contact;
+
+ if (rtag && !established && sip->sip_from->a_tag)
+ nta_leg_rtag(ds->ds_leg, sip->sip_from->a_tag);
+}
+
+/**@internal
+ * UAC tag and route.
+ *
+ * Update dialog tags and route on the UAC side.
+ *
+ * @param own dialog owner
+ * @param ds dialog state
+ * @param sip SIP message containing response used to update dialog
+ * @param rtag if true, set remote tag within the leg
+ */
+void nua_dialog_uac_route(nua_owner_t *own,
+ nua_dialog_state_t *ds,
+ sip_t const *sip,
+ int rtag)
+{
+ int established = nua_dialog_is_established(ds);
+
+ if (!established && sip->sip_to->a_tag)
+ ds->ds_remote_tag = su_strdup(own, sip->sip_to->a_tag);
+
+ if (ds->ds_leg == NULL)
+ return;
+
+ nta_leg_client_route(ds->ds_leg, sip->sip_record_route, sip->sip_contact);
+ ds->ds_route = ds->ds_route || sip->sip_record_route || sip->sip_contact;
+
+ if (rtag && !established && sip->sip_to->a_tag)
+ nta_leg_rtag(ds->ds_leg, sip->sip_to->a_tag);
+}
+
+/**@internal Store information from remote endpoint. */
+void nua_dialog_store_peer_info(nua_owner_t *own,
+ nua_dialog_state_t *ds,
+ sip_t const *sip)
+{
+ nua_remote_t *nr = ds->ds_remote_ua;
+ nua_dialog_usage_t *du;
+ nua_remote_t old[1];
+
+ *old = *nr;
+
+ if (sip && sip->sip_status &&
+ sip->sip_status->st_status >= 300 &&
+ sip->sip_status->st_status <= 399)
+ sip = NULL; /* Redirected */
+
+ if (sip == NULL) {
+ nr->nr_allow = NULL, su_free(own, old->nr_allow);
+ nr->nr_accept = NULL, su_free(own, old->nr_accept);
+ nr->nr_require = NULL, su_free(own, old->nr_require);
+ nr->nr_supported = NULL, su_free(own, old->nr_supported);
+ nr->nr_user_agent = NULL, su_free(own, old->nr_user_agent);
+ return;
+ }
+
+ if (sip->sip_allow) {
+ nr->nr_allow = sip_allow_dup(own, sip->sip_allow);
+ su_free(own, old->nr_allow);
+ }
+
+ if (sip->sip_accept) {
+ nr->nr_accept = sip_accept_dup(own, sip->sip_accept);
+ su_free(own, old->nr_accept);
+ }
+
+ if (sip->sip_require) {
+ nr->nr_require = sip_require_dup(own, sip->sip_require);
+ su_free(own, old->nr_require);
+ }
+
+ if (sip->sip_supported) {
+ nr->nr_supported = sip_supported_dup(own, sip->sip_supported);
+ su_free(own, old->nr_supported);
+ }
+
+ if (sip->sip_user_agent) {
+ nr->nr_user_agent = sip_user_agent_dup(own, sip->sip_user_agent);
+ su_free(own, old->nr_user_agent);
+ }
+ else if (sip->sip_server) {
+ nr->nr_user_agent = sip_user_agent_dup(own, sip->sip_server);
+ su_free(own, old->nr_user_agent);
+ }
+
+ for (du = ds->ds_usage; du; du = du->du_next) {
+ if (du->du_class->usage_peer_info)
+ du->du_class->usage_peer_info(du, ds, sip);
+ }
+}
+
+/** Remove dialog (if there is no other usages). */
+int nua_dialog_remove(nua_owner_t *own,
+ nua_dialog_state_t *ds,
+ nua_dialog_usage_t *usage)
+{
+ if (ds->ds_usage == usage && (usage == NULL || usage->du_next == NULL)) {
+ nua_dialog_store_peer_info(own, ds, NULL); /* zap peer info */
+ nta_leg_destroy(ds->ds_leg), ds->ds_leg = NULL;
+ su_free(own, (void *)ds->ds_remote_tag), ds->ds_remote_tag = NULL;
+ ds->ds_route = 0;
+ }
+ return 0;
+}
+
+
+/** @internal Get dialog usage slot. */
+nua_dialog_usage_t **
+nua_dialog_usage_at(nua_dialog_state_t const *ds,
+ nua_usage_class const *kind,
+ sip_event_t const *event)
+{
+ static nua_dialog_usage_t *none = NULL;
+
+ if (ds) {
+ nua_dialog_usage_t *du, * const * prev;
+ sip_event_t const *o;
+
+ for (prev = &ds->ds_usage; (du = *prev); prev = &du->du_next) {
+ if (du->du_class != kind)
+ continue;
+
+ if (event == NONE)
+ return (nua_dialog_usage_t **)prev;
+
+ o = du->du_event;
+
+ if (!event && !o)
+ return (nua_dialog_usage_t **)prev;
+
+ if (event != o) {
+ if (event == NULL || o == NULL)
+ continue;
+ if (strcmp(event->o_type, o->o_type))
+ continue;
+ if (str0casecmp(event->o_id, o->o_id)) {
+ if (event->o_id || strcmp(event->o_type, "refer"))
+ continue;
+ }
+ }
+
+ return (nua_dialog_usage_t **)prev;
+ }
+ }
+
+ return &none;
+}
+
+/** @internal Get a dialog usage */
+nua_dialog_usage_t *nua_dialog_usage_get(nua_dialog_state_t const *ds,
+ nua_usage_class const *kind,
+ sip_event_t const *event)
+{
+ return *nua_dialog_usage_at(ds, kind, event);
+}
+
+/** @internal Get dialog usage name */
+char const *nua_dialog_usage_name(nua_dialog_usage_t const *du)
+{
+ if (du == NULL)
+ return "<NULL>";
+ return du->du_class->usage_name(du);
+}
+
+/** @internal Add dialog usage */
+nua_dialog_usage_t *nua_dialog_usage_add(nua_owner_t *own,
+ struct nua_dialog_state *ds,
+ nua_usage_class const *uclass,
+ sip_event_t const *event)
+{
+ if (ds) {
+ sip_event_t *o;
+ nua_dialog_usage_t *du, **prev_du;
+
+ prev_du = nua_dialog_usage_at(ds, uclass, event);
+ du = *prev_du;
+ if (du) { /* Already exists */
+ SU_DEBUG_5(("nua(%p): adding already existing %s usage%s%s\n",
+ own, nua_dialog_usage_name(du),
+ event ? " with event " : "", event ? event->o_type : ""));
+
+ if (prev_du != &ds->ds_usage) {
+ /* Move as a first usage in the list */
+ *prev_du = du->du_next;
+ du->du_next = ds->ds_usage;
+ ds->ds_usage = du;
+ }
+ return du;
+ }
+
+ o = event ? sip_event_dup(own, event) : NULL;
+
+ if (o != NULL || event == NULL)
+ du = su_zalloc(own, sizeof *du + uclass->usage_size);
+
+ if (du) {
+ du->du_class = uclass;
+ du->du_event = o;
+
+ if (uclass->usage_add(own, ds, du) < 0) {
+ su_free(own, o);
+ su_free(own, du);
+ return NULL;
+ }
+
+ SU_DEBUG_5(("nua(%p): adding %s usage%s%s\n",
+ own, nua_dialog_usage_name(du),
+ o ? " with event " : "", o ? o->o_type :""));
+
+ su_home_ref(own);
+ du->du_next = ds->ds_usage, ds->ds_usage = du;
+
+ return du;
+ }
+
+ su_free(own, o);
+ }
+
+ return NULL;
+}
+
+/** @internal Remove dialog usage. */
+void nua_dialog_usage_remove(nua_owner_t *own,
+ nua_dialog_state_t *ds,
+ nua_dialog_usage_t *du)
+{
+ nua_dialog_usage_t **at;
+
+ assert(own); assert(ds); assert(du);
+
+ for (at = &ds->ds_usage; *at; at = &(*at)->du_next)
+ if (du == *at)
+ break;
+
+ assert(*at);
+
+ nua_dialog_usage_remove_at(own, ds, at);
+}
+
+/** @internal Remove dialog usage.
+ *
+ * Zap dialog state (leg, tag and route) if no usages remain.
+*/
+static
+void nua_dialog_usage_remove_at(nua_owner_t *own,
+ nua_dialog_state_t *ds,
+ nua_dialog_usage_t **at)
+{
+ if (*at) {
+ nua_dialog_usage_t *du = *at;
+ sip_event_t const *o = NULL;
+ nua_client_request_t *cr, *cr_next;
+ nua_server_request_t *sr, *sr_next;
+
+ for (cr = ds->ds_cr; cr; cr = cr_next) {
+ cr_next = cr->cr_next;
+ if (cr->cr_usage == du)
+ cr->cr_usage = NULL;
+ }
+
+ for (sr = ds->ds_sr; sr; sr = sr_next) {
+ sr_next = sr->sr_next;
+ if (sr->sr_usage == du)
+ nua_server_request_destroy(sr);
+ }
+
+ *at = du->du_next;
+
+ o = du->du_event;
+
+ SU_DEBUG_5(("nua(%p): removing %s usage%s%s\n",
+ own, nua_dialog_usage_name(du),
+ o ? " with event " : "", o ? o->o_type :""));
+ du->du_class->usage_remove(own, ds, du);
+ msg_destroy(du->du_msg), du->du_msg = NULL;
+ su_home_unref(own);
+ su_free(own, du);
+ }
+
+ /* Zap dialog if there is no more usages */
+ if (ds->ds_usage == NULL) {
+ nta_leg_destroy(ds->ds_leg), ds->ds_leg = NULL;
+ su_free(own, (void *)ds->ds_remote_tag), ds->ds_remote_tag = NULL;
+ ds->ds_route = 0;
+ ds->ds_has_events = 0;
+ ds->ds_terminated = 0;
+ return;
+ }
+ else if (!ds->ds_terminated) {
+ nua_dialog_log_usage(own, ds);
+ }
+}
+
+static
+void nua_dialog_log_usage(nua_owner_t *own, nua_dialog_state_t *ds)
+{
+ nua_dialog_usage_t *du;
+
+ if (SU_LOG->log_level >= 3) {
+ char buffer[160];
+ size_t l = 0, N = sizeof buffer;
+ ssize_t n;
+
+ buffer[0] = '\0';
+
+ for (du = ds->ds_usage; du; du = du->du_next) {
+ msg_header_t const *h = (void *)du->du_event;
+
+ if (!h)
+ continue;
+
+ n = sip_event_e(buffer + l, N - l, h, 0);
+ if (n == -1)
+ break;
+ l += (size_t)n;
+ if (du->du_next && l + 2 < sizeof(buffer)) {
+ strcpy(buffer + l, ", ");
+ l += 2;
+ }
+ }
+
+ SU_DEBUG_3(("nua(%p): handle with %s%s%s\n", own,
+ ds->ds_has_session ? "session and " : "",
+ ds->ds_has_events ? "events " : "",
+ buffer));
+ }
+}
+
+/** Deinitialize dialog and its usage. @internal */
+void nua_dialog_deinit(nua_owner_t *own,
+ nua_dialog_state_t *ds)
+{
+ while (ds->ds_usage) {
+ nua_dialog_usage_remove_at(own, ds, &ds->ds_usage);
+ }
+}
+
+
+/** @internal Dialog has been terminated. Remove all usages. */
+void nua_dialog_terminated(nua_owner_t *own,
+ struct nua_dialog_state *ds,
+ int status,
+ char const *phrase)
+{
+
+ ds->ds_terminated = 1;
+
+ while (ds->ds_usage) {
+#if 0
+ int call = 0;
+
+ if (ds->ds_usage->du_kind == nua_session_usage)
+ call = 1; /* Delay sending the event */
+ else
+ /* XXX */;
+#endif
+ nua_dialog_usage_remove_at(own, ds, &ds->ds_usage);
+ }
+}
+
+/**@internal
+ * Set expiration time.
+ */
+void nua_dialog_usage_set_expires(nua_dialog_usage_t *du,
+ unsigned delta)
+{
+ if (delta) {
+ sip_time_t now = sip_now(), expires = now + delta;
+ if (expires < now)
+ expires = SIP_TIME_MAX;
+ du->du_expires = expires;
+ nua_dialog_usage_set_refresh(du, delta);
+ }
+ else
+ du->du_expires = 0, du->du_refresh = 0;
+}
+
+/**@internal
+ * Set refresh value suitably.
+ *
+ * The refresh time is set either around half of the @a delta interval or,
+ * if @a delta is less than 5 minutes but longer than 90 seconds, 30..60
+ * seconds before end of interval.
+ *
+ * If @a delta is 0, the refresh time is set at the end of the world
+ * (maximum time, for 32-bit systems sometimes during 2036).
+ */
+void nua_dialog_usage_set_refresh(nua_dialog_usage_t *du, unsigned delta)
+{
+ if (delta == 0)
+ du->du_refresh = 0;
+ else if (delta > 90 && delta < 5 * 60)
+ /* refresh 30..60 seconds before deadline */
+ nua_dialog_usage_refresh_range(du, delta - 60, delta - 30);
+ else {
+ /* By default, refresh around half time before deadline */
+ unsigned min = (delta + 2) / 4;
+ unsigned max = (delta + 2) / 4 + (delta + 1) / 2;
+ if (min == 0)
+ min = 1;
+ nua_dialog_usage_refresh_range(du, min, max);
+ }
+}
+
+/**@internal Set refresh in range min..max seconds in the future. */
+void nua_dialog_usage_refresh_range(nua_dialog_usage_t *du,
+ unsigned min, unsigned max)
+{
+ sip_time_t now = sip_now(), target;
+ unsigned delta;
+
+ if (max < min)
+ max = min;
+
+ if (min != max)
+ delta = su_randint(min, max);
+ else
+ delta = min;
+
+ if (now + delta >= now)
+ target = now + delta;
+ else
+ target = SIP_TIME_MAX;
+
+ SU_DEBUG_7(("nua(): refresh %s after %lu seconds (in [%u..%u])\n",
+ nua_dialog_usage_name(du), target - now, min, max));
+
+ du->du_refresh = target;
+}
+
+/**@internal Do not refresh. */
+void nua_dialog_usage_reset_refresh(nua_dialog_usage_t *du)
+{
+ du->du_refresh = 0;
+}
+
+/** @internal Refresh usage or shutdown usage if @a now is 0. */
+void nua_dialog_usage_refresh(nua_owner_t *owner,
+ nua_dialog_state_t *ds,
+ nua_dialog_usage_t *du,
+ sip_time_t now)
+{
+ if (du) {
+ du->du_refresh = 0;
+
+ if (now > 0) {
+ if (du->du_class->usage_refresh) {
+ du->du_class->usage_refresh(owner, ds, du, now);
+ return;
+ }
+ }
+ else {
+ du->du_shutdown = 1;
+ if (du->du_class->usage_shutdown) {
+ du->du_class->usage_shutdown(owner, ds, du);
+ return;
+ }
+ }
+ }
+}
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,304 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef NUA_DIALOG_H
+/** Defined when <nua_dialog.h> has been included. */
+#define NUA_DIALOG_H
+
+/**@IFILE nua_dialog.h
+ * @brief Dialog and dialog usage handling
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Kai Vehmanen <Kai.Vehmanen at nokia.com>
+ *
+ * @date Created: Wed Mar 8 11:38:18 EET 2006 ppessi
+ */
+
+typedef struct nua_dialog_state nua_dialog_state_t;
+typedef struct nua_dialog_usage nua_dialog_usage_t;
+typedef struct nua_remote_s nua_remote_t;
+
+#ifndef NUA_OWNER_T
+#define NUA_OWNER_T struct nua_owner_s
+#endif
+typedef NUA_OWNER_T nua_owner_t;
+
+#ifndef NTA_H
+#include <sofia-sip/nta.h>
+#endif
+
+typedef struct nua_server_request nua_server_request_t;
+typedef struct nua_client_request nua_client_request_t;
+
+/** Respond to an incoming request. */
+typedef int nua_server_respond_f(nua_server_request_t *, tagi_t const *);
+
+/** Restart an outgoing request. */
+typedef void nua_creq_restart_f(nua_owner_t *, tagi_t *tags);
+
+/** Server side transaction */
+struct nua_server_request {
+ struct nua_server_request *sr_next, **sr_prev;
+
+ nua_owner_t *sr_owner; /**< Backpointer to handle */
+ nua_dialog_usage_t *sr_usage; /**< Backpointer to usage */
+
+ /** When the application responds to an request with
+ * nua_respond(), the sr_respond() is called
+ */
+ nua_server_respond_f *sr_respond;
+
+ nta_incoming_t *sr_irq; /**< Server transaction object */
+ msg_t *sr_msg; /**< Request message */
+
+ sip_method_t sr_method; /**< Request method */
+ int sr_status; /**< Status code */
+ char const *sr_phrase; /**< Status phrase */
+
+ unsigned sr_auto:1; /**< Autoresponse - no event has been sent */
+ unsigned sr_initial:1; /**< Handle was created by this request */
+
+ /* Flags used with offer-answer */
+ unsigned sr_offer_recv:1; /**< We have received an offer */
+ unsigned sr_answer_sent:2; /**< We have answered (reliably, if >1) */
+
+ unsigned sr_offer_sent:1; /**< We have offered SDP */
+ unsigned sr_answer_recv:1; /**< We have received SDP answer */
+};
+
+#define SR_INIT(sr) \
+ ((void)memset((sr), 0, sizeof (sr)[0]), \
+ (void)(SR_STATUS1((sr), SIP_100_TRYING)), \
+ sr)
+
+#define SR_STATUS(sr, status, phrase) \
+ ((sr)->sr_phrase = (phrase), (sr)->sr_status = (status))
+
+#define SR_STATUS1(sr, statusphrase) \
+ sr_status(sr, statusphrase)
+
+su_inline
+int sr_status(nua_server_request_t *sr, int status, char const *phrase)
+{
+ return (void)(sr->sr_phrase = phrase), (sr->sr_status = status);
+}
+
+struct nua_client_request
+{
+ nua_client_request_t *cr_next; /**< Linked list of requests */
+ /*nua_event_t*/ int cr_event; /**< Request event */
+ nua_creq_restart_f *cr_restart;
+ nta_outgoing_t *cr_orq;
+ msg_t *cr_msg;
+ nua_dialog_usage_t *cr_usage;
+ unsigned short cr_retry_count; /**< Retry count for this request */
+
+ /* Flags used with offer-answer */
+ unsigned short cr_answer_recv; /**< Recv answer in response
+ * with this status.
+ */
+ unsigned cr_offer_sent:1; /**< Sent offer in this request */
+
+ unsigned cr_offer_recv:1; /**< Recv offer in a response */
+ unsigned cr_answer_sent:1; /**< Sent answer in (PR)ACK */
+
+ unsigned cr_has_contact:1; /**< Request has application contact */
+};
+
+
+struct nua_dialog_state
+{
+ nua_client_request_t ds_cr[1];
+ nua_server_request_t *ds_sr;
+
+ /** Dialog usages. */
+ nua_dialog_usage_t *ds_usage;
+
+ /* Dialog and subscription state */
+ unsigned ds_route:1; /**< We have route */
+ unsigned ds_terminated:1; /**< Being terminated */
+
+ unsigned ds_has_session:1; /**< We have session */
+ unsigned ds_has_register:1; /**< We have registration */
+ unsigned ds_has_publish:1; /**< We have publish */
+
+ unsigned ds_has_referrals:1; /**< We have (or have had) referrals */
+
+ unsigned :0;
+
+ unsigned ds_has_events; /**< We have events */
+ unsigned ds_has_subscribes; /**< We have subscriptions */
+ unsigned ds_has_notifys; /**< We have notifiers */
+
+ sip_from_t const *ds_local; /**< Local address */
+ sip_to_t const *ds_remote; /**< Remote address */
+ nta_leg_t *ds_leg;
+ char const *ds_remote_tag; /**< Remote tag (if any).
+ * Should be non-NULL
+ * if dialog is established.
+ */
+
+ struct nua_remote_s {
+ sip_allow_t *nr_allow;
+ sip_accept_t *nr_accept;
+ sip_require_t *nr_require;
+ sip_supported_t *nr_supported;
+ sip_user_agent_t *nr_user_agent;
+ } ds_remote_ua[1];
+};
+
+typedef void nh_pending_f(nua_owner_t *,
+ nua_dialog_usage_t *du,
+ sip_time_t now);
+
+/** Virtual function pointer table for dialog usage. */
+typedef struct {
+ unsigned usage_size, usage_class_size;
+ int (*usage_add)(nua_owner_t *,
+ nua_dialog_state_t *ds,
+ nua_dialog_usage_t *du);
+ void (*usage_remove)(nua_owner_t *,
+ nua_dialog_state_t *ds,
+ nua_dialog_usage_t *du);
+ char const *(*usage_name)(nua_dialog_usage_t const *du);
+ void (*usage_peer_info)(nua_dialog_usage_t *du,
+ nua_dialog_state_t const *ds,
+ sip_t const *sip);
+ void (*usage_refresh)(nua_owner_t *, nua_dialog_state_t *ds,
+ nua_dialog_usage_t *, sip_time_t now);
+ int (*usage_shutdown)(nua_owner_t *, nua_dialog_state_t *ds,
+ nua_dialog_usage_t *);
+} nua_usage_class;
+
+
+/** Base structure for dialog usage. */
+struct nua_dialog_usage {
+ nua_dialog_usage_t *du_next;
+ nua_usage_class const *du_class;
+
+ unsigned du_terminating:1; /**< Now trying to terminate usage */
+ unsigned du_ready:1; /**< Established usage */
+ unsigned du_shutdown:1; /**< Shutdown in progress */
+ unsigned:0;
+
+ /** When usage expires.
+ * Non-zero if the usage is established, SIP_TIME_MAX if there no
+ * expiration time.
+ */
+ sip_time_t du_expires;
+
+ sip_time_t du_refresh; /**< When to refresh */
+
+ sip_event_t const *du_event; /**< Event of usage */
+
+ msg_t *du_msg; /**< Template message */
+};
+
+void nua_dialog_uac_route(nua_owner_t *, nua_dialog_state_t *ds,
+ sip_t const *sip, int rtag);
+void nua_dialog_uas_route(nua_owner_t *, nua_dialog_state_t *ds,
+ sip_t const *sip, int rtag);
+void nua_dialog_store_peer_info(nua_owner_t *, nua_dialog_state_t *ds,
+ sip_t const *sip);
+int nua_dialog_remove(nua_owner_t *own,
+ nua_dialog_state_t *ds,
+ nua_dialog_usage_t *usage);
+
+char const *nua_dialog_usage_name(nua_dialog_usage_t const *du);
+
+nua_dialog_usage_t *nua_dialog_usage_add(nua_owner_t *,
+ struct nua_dialog_state *ds,
+ nua_usage_class const *uclass,
+ sip_event_t const *event);
+
+nua_dialog_usage_t *nua_dialog_usage_get(nua_dialog_state_t const *ds,
+ nua_usage_class const *uclass,
+ sip_event_t const *event);
+
+void nua_dialog_usage_remove(nua_owner_t *,
+ nua_dialog_state_t *ds,
+ nua_dialog_usage_t *du);
+
+void nua_dialog_deinit(nua_owner_t *own,
+ nua_dialog_state_t *ds);
+
+void nua_dialog_terminated(nua_owner_t *,
+ struct nua_dialog_state *ds,
+ int status,
+ char const *phrase);
+
+void nua_dialog_usage_set_expires(nua_dialog_usage_t *du, unsigned delta);
+
+void nua_dialog_usage_set_refresh(nua_dialog_usage_t *du, unsigned delta);
+
+void nua_dialog_usage_refresh_range(nua_dialog_usage_t *du,
+ unsigned min, unsigned max);
+
+void nua_dialog_usage_reset_refresh(nua_dialog_usage_t *du);
+
+void nua_dialog_usage_refresh(nua_owner_t *owner,
+ nua_dialog_state_t *ds,
+ nua_dialog_usage_t *du,
+ sip_time_t now);
+
+static inline
+int nua_dialog_is_established(nua_dialog_state_t const *ds)
+{
+ return ds->ds_remote_tag != NULL;
+}
+
+#if 0
+static inline
+void *nua_dialog_usage_private(nua_dialog_usage_t const *du)
+{
+ return du ? (void *)(du + 1) : NULL;
+}
+
+static inline
+nua_dialog_usage_t *nua_dialog_usage_public(void const *p)
+{
+ return p ? (nua_dialog_usage_t *)p - 1 : NULL;
+}
+#else
+#define nua_dialog_usage_private(du) ((du) ? (void*)((du) + 1) : NULL)
+#define nua_dialog_usage_public(p) ((p) ? (nua_dialog_usage_t*)(p) - 1 : NULL)
+#endif
+
+/* ---------------------------------------------------------------------- */
+
+void nua_server_request_destroy(nua_server_request_t *sr);
+
+int nua_server_respond(nua_server_request_t *sr,
+ int status, char const *phrase,
+ tag_type_t tag, tag_value_t value, ...);
+
+msg_t *nua_server_response(nua_server_request_t *sr,
+ int status, char const *phrase,
+ tag_type_t tag, tag_value_t value, ...);
+
+int nua_default_respond(nua_server_request_t *sr,
+ tagi_t const *tags);
+
+
+#endif /* NUA_DIALOG_H */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_event_server.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_event_server.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,351 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nua_event_server.c
+ * @brief Easy event server
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Mar 8 11:48:49 EET 2006 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include <assert.h>
+
+#include <sofia-sip/string0.h>
+
+#include <sofia-sip/sip_protos.h>
+#include <sofia-sip/sip_status.h>
+#include <sofia-sip/su_tagarg.h>
+
+#define NTA_LEG_MAGIC_T struct nua_handle_s
+#define NTA_OUTGOING_MAGIC_T struct nua_handle_s
+
+#define NEA_SMAGIC_T struct nua_handle_s
+#define NEA_EMAGIC_T struct nua_handle_s
+
+#include "nua_stack.h"
+
+/* ======================================================================== */
+/* Event server */
+
+static
+nea_event_t *nh_notifier_event(nua_handle_t *nh,
+ su_home_t *home,
+ sip_event_t const *event,
+ tagi_t const *tags);
+
+static
+void authorize_watcher(nea_server_t *nes,
+ nua_handle_t *nh,
+ nea_event_t *ev,
+ nea_subnode_t *sn,
+ sip_t const *sip);
+
+void
+nua_stack_notifier(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags)
+{
+ su_home_t home[1] = { SU_HOME_INIT(home) };
+ sip_event_t const *event = NULL;
+ sip_content_type_t const *ct = NULL;
+ sip_payload_t const *pl = NULL;
+ url_string_t const *url = NULL;
+ char const *event_s = NULL, *ct_s = NULL, *pl_s = NULL;
+ nea_event_t *ev;
+ int status = 900;
+ char const *phrase = nua_internal_error;
+
+ nua_stack_init_handle(nua, nh, TAG_NEXT(tags));
+
+ tl_gets(tags,
+ NUTAG_URL_REF(url),
+ SIPTAG_EVENT_REF(event),
+ SIPTAG_EVENT_STR_REF(event_s),
+ SIPTAG_CONTENT_TYPE_STR_REF(ct_s),
+ SIPTAG_PAYLOAD_REF(pl),
+ SIPTAG_PAYLOAD_STR_REF(pl_s),
+ TAG_END());
+
+ if (!event && !event_s)
+ status = 400, phrase = "Missing Event";
+
+ else if (!ct && !ct_s)
+ status = 400, phrase = "Missing Content-Type";
+
+ else if (!nh->nh_notifier &&
+ !(nh->nh_notifier =
+ nea_server_create(nua->nua_nta, nua->nua_root,
+ url->us_url,
+ NH_PGET(nh, max_subscriptions),
+ NULL, nh,
+ TAG_NEXT(tags))))
+ status = 900, phrase = nua_internal_error;
+
+ else if (!event && !(event = sip_event_make(home, event_s)))
+ status = 900, phrase = "Could not create an event header";
+
+ else if (!(ev = nh_notifier_event(nh, home, event, tags)))
+ status = 900, phrase = "Could not create an event view";
+
+ else if (nea_server_update(nh->nh_notifier, ev, TAG_NEXT(tags)) < 0)
+ status = 900, phrase = "No content for event";
+
+ else if (nea_server_notify(nh->nh_notifier, ev) < 0)
+ status = 900, phrase = "Error when notifying watchers";
+
+ else
+ nua_stack_event(nua, nh, NULL, e, status = SIP_200_OK,
+ SIPTAG_EVENT(event),
+ SIPTAG_CONTENT_TYPE(ct),
+ TAG_END());
+
+ if (status != 200)
+ nua_stack_event(nua, nh, NULL, e, status, phrase, TAG_END());
+
+ su_home_deinit(home);
+}
+
+
+/* Create a event view for notifier */
+static
+nea_event_t *nh_notifier_event(nua_handle_t *nh,
+ su_home_t *home,
+ sip_event_t const *event,
+ tagi_t const *tags)
+{
+ nea_event_t *ev = nea_event_get(nh->nh_notifier, event->o_type);
+ sip_accept_t const *accept = NULL;
+ char const *accept_s = NULL;
+ sip_content_type_t const *ct = NULL;
+ char const *ct_s = NULL;
+
+ if (ev == NULL) {
+ char *o_type = su_strdup(home, event->o_type);
+ char *o_subtype = strchr(o_type, '.');
+
+ if (o_subtype)
+ *o_subtype++ = '\0';
+
+ tl_gets(tags,
+ SIPTAG_ACCEPT_REF(accept),
+ SIPTAG_ACCEPT_STR_REF(accept_s),
+ SIPTAG_CONTENT_TYPE_REF(ct),
+ SIPTAG_CONTENT_TYPE_STR_REF(ct_s),
+ TAG_END());
+
+ /*
+ * XXX - We really should build accept header when we add new content
+ * types
+ */
+ if (accept_s == NULL && accept)
+ accept_s = sip_header_as_string(home, (sip_header_t *)accept);
+ if (accept_s == NULL && ct)
+ accept_s = ct->c_type;
+ if (accept_s == NULL && ct_s)
+ accept_s = ct_s;
+
+ ev = nea_event_create(nh->nh_notifier,
+ authorize_watcher, nh,
+ o_type, o_subtype,
+ ct ? ct->c_type : ct_s,
+ accept_s);
+ }
+
+ return ev;
+}
+
+/* Callback from nea_server asking nua to authorize subscription */
+static
+void authorize_watcher(nea_server_t *nes,
+ nua_handle_t *nh,
+ nea_event_t *ev,
+ nea_subnode_t *sn,
+ sip_t const *sip)
+{
+ nua_t *nua = nh->nh_nua;
+ msg_t *msg = NULL;
+ nta_incoming_t *irq = NULL;
+ int substate = sn->sn_state;
+ int status; char const *phrase;
+
+ SET_STATUS1(SIP_200_OK);
+
+ /* OK. In nhp (nua_handle_preferences_t) structure we have the
+ current default action (or state) for incoming
+ subscriptions.
+ Action can now be modified by the application with NUTAG_SUBSTATE().
+ */
+ irq = nea_sub_get_request(sn->sn_subscriber);
+ msg = nta_incoming_getrequest(irq);
+
+ if (sn->sn_state == nea_embryonic) {
+ char const *what;
+
+ substate = NH_PGET(nh, substate);
+
+ if (substate == nua_substate_embryonic)
+ substate = nua_substate_pending;
+
+ if (substate == nua_substate_terminated) {
+ what = "rejected"; SET_STATUS1(SIP_403_FORBIDDEN);
+ }
+ else if (substate == nua_substate_pending) {
+ what = "pending"; SET_STATUS1(SIP_202_ACCEPTED);
+ }
+ else {
+ what = "active";
+ }
+
+ SU_DEBUG_7(("nua(%p): authorize_watcher: %s\n", nh, what));
+ nea_sub_auth(sn->sn_subscriber, substate,
+ TAG_IF(substate == nua_substate_pending,
+ NEATAG_FAKE(1)),
+ TAG_IF(substate == nua_substate_terminated,
+ NEATAG_REASON("rejected")),
+ TAG_END());
+ }
+ else if (sn->sn_state == nea_terminated || sn->sn_expires == 0) {
+ substate = nua_substate_terminated;
+ nea_server_flush(nes, NULL);
+ SU_DEBUG_7(("nua(%p): authorize_watcher: %s\n",
+ nh, "watcher is removed"));
+ }
+
+ nua_stack_event(nua, nh, msg, nua_i_subscription, status, phrase,
+ NUTAG_SUBSTATE(substate),
+ NEATAG_SUB(sn->sn_subscriber),
+ TAG_END());
+}
+
+/* ---------------------------------------------------------------------- */
+/* Authorization of watchers by application */
+
+void nua_stack_authorize(nua_t *nua,
+ nua_handle_t *nh,
+ nua_event_t e,
+ tagi_t const *tags)
+{
+ nea_sub_t *sub = NULL;
+ int state = nea_extended;
+
+ tl_gets(tags,
+ NEATAG_SUB_REF(sub),
+ NUTAG_SUBSTATE_REF(state),
+ TAG_END());
+
+ if (sub && state > 0) {
+ nea_sub_auth(sub, state, TAG_NEXT(tags));
+ nua_stack_event(nua, nh, NULL, e, SIP_200_OK, TAG_END());
+ }
+ else {
+ nua_stack_event(nua, nh, NULL, e, NUA_INTERNAL_ERROR, TAG_END());
+ }
+ return;
+}
+
+/** @internal Shutdown notifier object */
+int nh_notifier_shutdown(nua_handle_t *nh,
+ nea_event_t *ev,
+ tag_type_t t,
+ tag_value_t v, ...)
+{
+ nea_server_t *nes = nh->nh_notifier;
+ nea_subnode_t const **subs;
+ int busy = 0;
+
+ if (nes == NULL)
+ return 0;
+
+ subs = nea_server_get_subscribers(nes, ev);
+
+ if (subs) {
+ int i;
+ ta_list ta;
+
+ ta_start(ta, t, v);
+
+ for (i = 0; subs[i]; i++)
+ nea_sub_auth(subs[i]->sn_subscriber, nea_terminated, ta_tags(ta));
+
+ ta_end(ta);
+
+ busy++;
+ }
+
+ nea_server_free_subscribers(nes, subs);
+
+ nea_server_flush(nh->nh_notifier, NULL);
+
+ if (ev == NULL)
+ nea_server_destroy(nh->nh_notifier), nh->nh_notifier = NULL;
+
+ return busy;
+}
+
+
+/** @internal Terminate notifier. */
+void nua_stack_terminate(nua_t *nua,
+ nua_handle_t *nh,
+ nua_event_t e,
+ tagi_t const *tags)
+{
+ sip_event_t const *event = NULL;
+ sip_content_type_t const *ct = NULL;
+ sip_payload_t const *pl = NULL;
+ char const *event_s = NULL, *ct_s = NULL, *pl_s = NULL;
+ nea_event_t *nev = NULL;
+
+ if (nh->nh_notifier == NULL) {
+ UA_EVENT2(e, 900, "No event server to terminate");
+ return;
+ }
+
+ tl_gets(tags,
+ SIPTAG_EVENT_REF(event),
+ SIPTAG_EVENT_STR_REF(event_s),
+ SIPTAG_CONTENT_TYPE_REF(ct),
+ SIPTAG_CONTENT_TYPE_STR_REF(ct_s),
+ SIPTAG_PAYLOAD_REF(pl),
+ SIPTAG_PAYLOAD_STR_REF(pl_s),
+ TAG_END());
+
+ nev = nea_event_get(nh->nh_notifier,
+ event ? event->o_type : event_s);
+
+ if (nev && (pl || pl_s) && (ct || ct_s)) {
+ nea_server_update(nh->nh_notifier, nev, TAG_NEXT(tags));
+ }
+
+ nh_notifier_shutdown(nh, NULL,
+ NEATAG_REASON("noresource"),
+ TAG_NEXT(tags));
+
+ nua_stack_event(nua, nh, NULL, e, SIP_200_OK, TAG_END());
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_extension.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_extension.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,204 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nua_extension.c
+ * @brief Extension method
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Mon Nov 13 15:18:54 EET 2006
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include <assert.h>
+
+#include <sofia-sip/string0.h>
+#include <sofia-sip/sip_protos.h>
+#include <sofia-sip/sip_status.h>
+
+#define NTA_LEG_MAGIC_T struct nua_handle_s
+#define NTA_OUTGOING_MAGIC_T struct nua_handle_s
+
+#include "nua_stack.h"
+
+static int process_response_to_method(nua_handle_t *nh,
+ nta_outgoing_t *orq,
+ sip_t const *sip);
+static void restart_method(nua_handle_t *nh, tagi_t *tags);
+static int respond_to_method(nua_server_request_t *sr, tagi_t const *tags);
+
+/** Send an extension request.
+ *
+ * Send an entension request message.
+ *
+ * @param nh Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return
+ * nothing
+ *
+ * @par Related Tags:
+ * NUTAG_METHOD() \n
+ * NUTAG_URL() \n
+ * Tags of nua_set_hparams() \n
+ * Tags in <sip_tag.h>
+ *
+ * @par Events:
+ * #nua_r_method
+ *
+ * @sa SIP_METHOD_UNKNOWN(), #nua_r_method, #nua_i_method
+ *
+ * @since New in @VERSION_1_12_4.
+ */
+
+int
+nua_stack_method(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags)
+{
+ nua_client_request_t *cr = nh->nh_ds->ds_cr;
+ msg_t *msg;
+
+ if (cr->cr_orq)
+ return UA_EVENT2(e, 900, "Request already in progress");
+
+ nua_stack_init_handle(nua, nh, TAG_NEXT(tags));
+
+ msg = nua_creq_msg(nua, nh, cr, cr->cr_retry_count,
+ SIP_METHOD_UNKNOWN,
+ TAG_NEXT(tags));
+ if (msg)
+ cr->cr_orq = nta_outgoing_mcreate(nua->nua_nta,
+ process_response_to_method, nh, NULL,
+ msg,
+ SIPTAG_END(),
+ TAG_NEXT(tags));
+ if (!cr->cr_orq) {
+ msg_destroy(msg);
+ return UA_EVENT1(e, NUA_INTERNAL_ERROR);
+ }
+
+ return cr->cr_event = e;
+}
+
+/** @NUA_EVENT nua_r_method
+ *
+ * Response to an outgoing extension request.
+ *
+ * @param status response status code
+ * (if the request is retried, @a status is 100, the @a
+ * sip->sip_status->st_status contain the real status code
+ * from the response method, e.g., 302, 401, or 407)
+ * @param phrase a short textual description of @a status code
+ * @param nh operation handle associated with the method
+ * @param hmagic application context associated with the handle
+ * @param sip response to the extension request or NULL upon an error
+ * (status code is in @a status and
+ * descriptive method in @a phrase parameters)
+ * @param tags empty
+ *
+ * @sa nua_method(), #nua_i_method, @RFC3428
+ *
+ * @END_NUA_EVENT
+ */
+
+static int process_response_to_method(nua_handle_t *nh,
+ nta_outgoing_t *orq,
+ sip_t const *sip)
+{
+ if (nua_creq_check_restart(nh, nh->nh_ds->ds_cr, orq, sip, restart_method))
+ return 0;
+ return nua_stack_process_response(nh, nh->nh_ds->ds_cr, orq, sip, TAG_END());
+}
+
+void restart_method(nua_handle_t *nh, tagi_t *tags)
+{
+ nua_creq_restart(nh, nh->nh_ds->ds_cr, process_response_to_method, tags);
+}
+
+/** @NUA_EVENT nua_i_method
+ *
+ * @brief Incoming extension request.
+ *
+ * The extension request does not create a dialog. If the incoming request
+ * was not assiciated with an existing dialog the stack creates a new handle
+ * for it. If the handle @a nh is not bound, you should probably destroy it
+ * after responding to the request.
+ *
+ * @param status status code of response sent automatically by stack
+ * @param phrase a short textual description of @a status code
+ * @param nh operation handle associated with the method
+ * @param hmagic application context associated with the handle
+ * (maybe NULL if outside session)
+ * @param sip incoming request
+ * @param tags NUTAG_METHOD()
+ *
+ * The extension name is in sip->sip_request->rq_method_name, too.
+ *
+ * @sa nua_method(), #nua_r_method
+ *
+ * @END_NUA_EVENT
+ */
+
+int nua_stack_process_method(nua_t *nua,
+ nua_handle_t *nh,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ nua_server_request_t *sr, sr0[1];
+
+ sr = SR_INIT(sr0);
+
+ sr = nua_server_request(nua, nh, irq, sip, sr, sizeof *sr,
+ respond_to_method, 0);
+
+ return nua_stack_server_event(nua, sr, nua_i_method, TAG_END());
+}
+
+static
+int respond_to_method(nua_server_request_t *sr, tagi_t const *tags)
+{
+ nua_handle_t *nh = sr->sr_owner;
+ nua_t *nua = nh->nh_nua;
+ msg_t *msg;
+
+ msg = nua_server_response(sr, sr->sr_status, sr->sr_phrase, TAG_NEXT(tags));
+
+ if (msg) {
+ nta_incoming_mreply(sr->sr_irq, msg);
+ }
+ else {
+ SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR);
+ nta_incoming_treply(sr->sr_irq, sr->sr_status, sr->sr_phrase, TAG_END());
+ nua_stack_event(nua, nh, NULL,
+ nua_i_error, 900, "Response to Extension Method Fails",
+ TAG_END());
+ }
+
+ return sr->sr_status >= 200 ? sr->sr_status : 0;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_message.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_message.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,199 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nua_message.c
+ * @brief MESSAGE method
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Mar 8 17:01:22 EET 2006 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include <assert.h>
+
+#include <sofia-sip/string0.h>
+#include <sofia-sip/sip_protos.h>
+#include <sofia-sip/sip_status.h>
+
+#define NTA_LEG_MAGIC_T struct nua_handle_s
+#define NTA_OUTGOING_MAGIC_T struct nua_handle_s
+
+#include "nua_stack.h"
+
+/* ======================================================================== */
+/* MESSAGE */
+
+/** Send an instant message.
+ *
+ * Send an instant message using SIP MESSAGE method.
+ *
+ * @param nh Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return
+ * nothing
+ *
+ * @par Related Tags:
+ * NUTAG_URL() \n
+ * Tags of nua_set_hparams() \n
+ * Tags in <sip_tag.h>
+ *
+ * @par Events:
+ * #nua_r_message
+ *
+ * @sa #nua_i_message, @RFC3428
+ */
+
+static int process_response_to_message(nua_handle_t *nh,
+ nta_outgoing_t *orq,
+ sip_t const *sip);
+
+int
+nua_stack_message(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags)
+{
+ nua_client_request_t *cr = nh->nh_ds->ds_cr;
+ msg_t *msg;
+ sip_t *sip;
+
+ if (nh_is_special(nh)) {
+ return UA_EVENT2(e, 900, "Invalid handle for MESSAGE");
+ }
+ else if (cr->cr_orq) {
+ return UA_EVENT2(e, 900, "Request already in progress");
+ }
+
+ nua_stack_init_handle(nua, nh, TAG_NEXT(tags));
+
+ msg = nua_creq_msg(nua, nh, cr, cr->cr_retry_count,
+ SIP_METHOD_MESSAGE,
+ NUTAG_ADD_CONTACT(NH_PGET(nh, win_messenger_enable)),
+ TAG_NEXT(tags));
+ sip = sip_object(msg);
+
+ if (sip)
+ cr->cr_orq = nta_outgoing_mcreate(nua->nua_nta,
+ process_response_to_message, nh, NULL,
+ msg,
+ SIPTAG_END(), TAG_NEXT(tags));
+ if (!cr->cr_orq) {
+ msg_destroy(msg);
+ return UA_EVENT1(e, NUA_INTERNAL_ERROR);
+ }
+
+ return cr->cr_event = e;
+}
+
+void restart_message(nua_handle_t *nh, tagi_t *tags)
+{
+ nua_creq_restart(nh, nh->nh_ds->ds_cr, process_response_to_message, tags);
+}
+
+/** @NUA_EVENT nua_r_message
+ *
+ * Response to an outgoing @b MESSAGE request.
+ *
+ * @param status response status code
+ * (if the request is retried, @a status is 100, the @a
+ * sip->sip_status->st_status contain the real status code
+ * from the response message, e.g., 302, 401, or 407)
+ * @param phrase a short textual description of @a status code
+ * @param nh operation handle associated with the message
+ * @param hmagic application context associated with the handle
+ * @param sip response to MESSAGE request or NULL upon an error
+ * (status code is in @a status and
+ * descriptive message in @a phrase parameters)
+ * @param tags empty
+ *
+ * @sa nua_message(), #nua_i_message, @RFC3428
+ *
+ * @END_NUA_EVENT
+ */
+
+static int process_response_to_message(nua_handle_t *nh,
+ nta_outgoing_t *orq,
+ sip_t const *sip)
+{
+ if (nua_creq_check_restart(nh, nh->nh_ds->ds_cr, orq, sip, restart_message))
+ return 0;
+ return nua_stack_process_response(nh, nh->nh_ds->ds_cr, orq, sip, TAG_END());
+}
+
+/** @NUA_EVENT nua_i_message
+ *
+ * @brief Incoming @b MESSAGE request.
+ *
+ * The @b MESSAGE request does not create a dialog. If the incoming @b
+ * MESSAGE request is not assiciated with an existing dialog the stack
+ * creates a new handle for it. If the handle @a nh is not bound, you should
+ * probably destroy it after responding to the MESSAGE request.
+ *
+ * @param status status code of response sent automatically by stack
+ * @param phrase a short textual description of @a status code
+ * @param nh operation handle associated with the message
+ * @param hmagic application context associated with the handle
+ * (maybe NULL if outside session)
+ * @param sip incoming MESSAGE request
+ * @param tags empty
+ *
+ * @sa nua_message(), #nua_r_message, @RFC3428, @RFC3862
+ *
+ * @END_NUA_EVENT
+ */
+
+int nua_stack_process_message(nua_t *nua,
+ nua_handle_t *nh,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ msg_t *msg;
+
+ if (nh
+ ? !NH_PGET(nh, message_enable)
+ : !DNH_PGET(nua->nua_dhandle, message_enable))
+ return 403;
+
+ if (nh == NULL)
+ if (!(nh = nua_stack_incoming_handle(nua, irq, sip, 0)))
+ return 500; /* respond with 500 Internal Server Error */
+
+ msg = nta_incoming_getrequest(irq);
+
+ nua_stack_event(nh->nh_nua, nh, msg, nua_i_message, SIP_200_OK, TAG_END());
+
+#if 0 /* XXX */
+ if (nh->nh_nua->nua_messageRespond) {
+ nh->nh_irq = irq;
+ return 0;
+ }
+#endif
+
+ return 200;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_notifier.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_notifier.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,722 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nua_notifier.c
+ * @brief SUBSCRIBE server, NOTIFY client and REFER server
+ *
+ * Simpler event server. See nua_event_server.c for more complex event
+ * server.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Mar 8 15:10:08 EET 2006 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include <assert.h>
+
+#include <sofia-sip/string0.h>
+#include <sofia-sip/sip_protos.h>
+#include <sofia-sip/sip_status.h>
+#include <sofia-sip/sip_util.h>
+#include <sofia-sip/su_uniqueid.h>
+
+#define NTA_LEG_MAGIC_T struct nua_handle_s
+#define NTA_OUTGOING_MAGIC_T struct nua_handle_s
+
+#include "nua_stack.h"
+
+/* ---------------------------------------------------------------------- */
+/* Notifier event usage */
+
+struct notifier_usage
+{
+ enum nua_substate nu_substate; /**< Subscription state */
+ sip_time_t nu_expires;
+};
+
+static char const *nua_notify_usage_name(nua_dialog_usage_t const *du);
+static int nua_notify_usage_add(nua_handle_t *nh,
+ nua_dialog_state_t *ds,
+ nua_dialog_usage_t *du);
+static void nua_notify_usage_remove(nua_handle_t *nh,
+ nua_dialog_state_t *ds,
+ nua_dialog_usage_t *du);
+static void nua_notify_usage_refresh(nua_handle_t *nh,
+ nua_dialog_state_t *ds,
+ nua_dialog_usage_t *du,
+ sip_time_t now);
+static int nua_notify_usage_shutdown(nua_handle_t *nh,
+ nua_dialog_state_t *ds,
+ nua_dialog_usage_t *du);
+
+static nua_usage_class const nua_notify_usage[1] = {
+ {
+ sizeof (struct notifier_usage), (sizeof nua_notify_usage),
+ nua_notify_usage_add,
+ nua_notify_usage_remove,
+ nua_notify_usage_name,
+ NULL,
+ nua_notify_usage_refresh,
+ nua_notify_usage_shutdown,
+ }};
+
+static char const *nua_notify_usage_name(nua_dialog_usage_t const *du)
+{
+ return "notify";
+}
+
+static
+int nua_notify_usage_add(nua_handle_t *nh,
+ nua_dialog_state_t *ds,
+ nua_dialog_usage_t *du)
+{
+ ds->ds_has_events++;
+ ds->ds_has_notifys++;
+ return 0;
+}
+
+static
+void nua_notify_usage_remove(nua_handle_t *nh,
+ nua_dialog_state_t *ds,
+ nua_dialog_usage_t *du)
+{
+ ds->ds_has_events--;
+ ds->ds_has_notifys--;
+}
+
+/* ====================================================================== */
+/* SUBSCRIBE server */
+
+static int respond_to_subscribe(nua_server_request_t *sr, tagi_t const *tags);
+
+/** @NUA_EVENT nua_i_subscribe
+ *
+ * Incoming @b SUBSCRIBE request.
+ *
+ * @b SUBSCRIBE request is used to query SIP event state or establish a SIP
+ * event subscription.
+ *
+ * Initial SUBSCRIBE requests are dropped with <i>489 Bad Event</i>
+ * response, unless the application has explicitly included the @Event in
+ * the list of allowed events with nua_set_params() tag NUTAG_ALLOW_EVENTS()
+ * (or SIPTAG_ALLOW_EVENTS() or SIPTAG_ALLOW_EVENTS_STR()). The application
+ * can decide whether to accept the SUBSCRIBE request or reject it. The
+ * nua_response() call responding to a SUBSCRIBE request must have
+ * NUTAG_WITH() (or NUTAG_WITH_CURRENT()/NUTAG_WITH_SAVED()) tag.
+ *
+ * If the application accepts the SUBSCRIBE request, it must immediately
+ * send an initial NOTIFY establishing the dialog. This is because the
+ * response to the SUBSCRIBE request may be lost because the SUBSCRIBE
+ * request was forked by an intermediate proxy.
+ *
+ * SUBSCRIBE requests modifying (usually refreshing or terminating) an
+ * existing event subscription are accepted by default and a <i>200 OK</i>
+ * response along with a copy of previously sent NOTIFY is sent
+ * automatically.
+ *
+ * By default, only event subscriptions accepted are those created
+ * implicitly by REFER request. See #nua_i_refer how the application must
+ * handle the REFER requests.
+ *
+ * @param status status code of response sent automatically by stack
+ * @param phrase response phrase sent automatically by stack
+ * @param nh operation handle associated with the incoming request
+ * @param hmagic application context associated with the handle
+ * (NULL when handle is created by the stack)
+ * @param sip SUBSCRIBE request headers
+ * @param tags NUTAG_SUBSTATE()
+ *
+ * @sa @RFC3265, nua_notify(), NUTAG_SUBSTATE(), @SubscriptionState,
+ * @Event, nua_subscribe(), #nua_r_subscribe, #nua_i_refer, nua_refer()
+ *
+ * @END_NUA_EVENT
+ */
+
+
+/** @internal Process incoming SUBSCRIBE. */
+int nua_stack_process_subscribe(nua_t *nua,
+ nua_handle_t *nh,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ nua_server_request_t *sr, sr0[1];
+ nua_dialog_state_t *ds;
+ nua_dialog_usage_t *du = NULL;
+ sip_event_t *o = sip->sip_event;
+ char const *event = o ? o->o_type : NULL;
+
+ enum nua_substate substate = nua_substate_terminated;
+
+ enter;
+
+ if (nh)
+ du = nua_dialog_usage_get(ds = nh->nh_ds, nua_notify_usage, o);
+
+ sr = SR_INIT(sr0);
+
+ if (nh == NULL || du == NULL) {
+ sip_allow_events_t *allow_events = NUA_PGET(nua, nh, allow_events);
+
+ if (event && str0cmp(event, "refer") == 0)
+ /* refer event subscription should be initiated with REFER */
+ SR_STATUS1(sr, SIP_403_FORBIDDEN);
+ else if (!event || !msg_header_find_param(allow_events->k_common, event))
+ SR_STATUS1(sr, SIP_489_BAD_EVENT);
+ else
+ substate = nua_substate_embryonic;
+ }
+ else {
+ /* Refresh existing subscription */
+ struct notifier_usage *nu = nua_dialog_usage_private(du);
+ unsigned long expires;
+
+ assert(nh && du && nu);
+
+ expires = str0cmp(event, "refer") ? 3600 : NH_PGET(nh, refer_expires);
+
+ if (sip->sip_expires && sip->sip_expires->ex_delta < expires)
+ expires = sip->sip_expires->ex_delta;
+
+ if (expires == 0)
+ nu->nu_substate = nua_substate_terminated;
+
+ nu->nu_expires = sip_now() + expires;
+ substate = nu->nu_substate;
+
+ /* XXX - send notify */
+
+ SR_STATUS1(sr, SIP_200_OK);
+ }
+
+ sr = nua_server_request(nua, nh, irq, sip, sr, sizeof *sr,
+ respond_to_subscribe, 1);
+
+ if (!du && substate == nua_substate_embryonic && sr->sr_status < 300) {
+ nh = sr->sr_owner; assert(nh && nh != nua->nua_dhandle);
+ du = nua_dialog_usage_add(nh, nh->nh_ds, nua_notify_usage, sip->sip_event);
+ if (du) {
+ struct notifier_usage *nu = nua_dialog_usage_private(du);
+ unsigned long expires = 3600; /* XXX */
+
+ if (sip->sip_expires && sip->sip_expires->ex_delta < expires)
+ expires = sip->sip_expires->ex_delta;
+
+ nu->nu_expires = sip_now() + expires;
+ nu->nu_substate = substate;
+ }
+ else
+ SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR);
+ }
+
+ if (substate == nua_substate_embryonic && sr->sr_status >= 300)
+ substate = nua_substate_terminated;
+
+ sr->sr_usage = du;
+
+ return nua_stack_server_event(nua, sr, nua_i_subscribe,
+ NUTAG_SUBSTATE(substate), TAG_END());
+}
+
+/** @internal Respond to an SUBSCRIBE request.
+ *
+ */
+static
+int respond_to_subscribe(nua_server_request_t *sr, tagi_t const *tags)
+{
+ nua_handle_t *nh = sr->sr_owner;
+ nua_dialog_state_t *ds = nh->nh_ds;
+ nua_t *nua = nh->nh_nua;
+ struct notifier_usage *nu;
+ sip_allow_events_t *allow_events = NUA_PGET(nua, nh, allow_events);
+ sip_expires_t ex[1];
+ sip_time_t now = sip_now();
+ msg_t *msg;
+
+ sip_expires_init(ex);
+
+ nu = nua_dialog_usage_private(sr->sr_usage);
+ if (nu && nu->nu_expires > now)
+ ex->ex_delta = nu->nu_expires - now;
+
+ msg = nua_server_response(sr,
+ sr->sr_status, sr->sr_phrase,
+ NUTAG_ADD_CONTACT(sr->sr_status < 300),
+ TAG_IF(nu, SIPTAG_EXPIRES(ex)),
+ SIPTAG_SUPPORTED(NH_PGET(nh, supported)),
+ SIPTAG_ALLOW_EVENTS(allow_events),
+ TAG_NEXT(tags));
+
+ if (msg) {
+ sip_t *sip = sip_object(msg);
+
+ if (nu && sip->sip_expires && sr->sr_status < 300)
+ nu->nu_expires = now + sip->sip_expires->ex_delta;
+
+ nta_incoming_mreply(sr->sr_irq, msg);
+
+ if (nu && nu->nu_substate != nua_substate_embryonic)
+ /* Send NOTIFY (and terminate subscription, when needed) */
+ nua_dialog_usage_refresh(nh, ds, sr->sr_usage, sip_now());
+ }
+ else {
+ /* XXX - send nua_i_error */
+ SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR);
+ nta_incoming_treply(sr->sr_irq, sr->sr_status, sr->sr_phrase, TAG_END());
+ }
+
+ return sr->sr_status >= 200 ? sr->sr_status : 0;
+}
+
+/* ======================================================================== */
+/* NOTIFY */
+
+static int process_response_to_notify(nua_handle_t *nh,
+ nta_outgoing_t *orq,
+ sip_t const *sip);
+
+static int nua_stack_notify2(nua_t *, nua_handle_t *, nua_event_t,
+ nua_dialog_usage_t *du,
+ tagi_t const *tags);
+
+
+/**@fn void nua_notify(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
+ *
+ * Send a SIP NOTIFY request message.
+ *
+ * This function is used when the application implements itself the
+ * notifier. The application must provide valid @SubscriptionState and
+ * @Event headers using SIP tags. If there is no @SubscriptionState header,
+ * the subscription state can be modified with NUTAG_SUBSTATE().
+ *
+ * @bug If the @Event is not given by application, stack uses the @Event
+ * header from the first subscription usage on handle.
+ *
+ * @param nh Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return
+ * nothing
+ *
+ * @par Related Tags:
+ * NUTAG_SUBSTATE() \n
+ * Tags of nua_set_hparams() \n
+ * Tags in <sip_tag.h>
+ *
+ * @par Events:
+ * #nua_r_notify
+ *
+ * @sa @RFC3265, #nua_i_subscribe, #nua_i_refer, NUTAG_ALLOW_EVENTS()
+ */
+
+/**@internal Send NOTIFY. */
+int nua_stack_notify(nua_t *nua,
+ nua_handle_t *nh,
+ nua_event_t e,
+ tagi_t const *tags)
+{
+ return nua_stack_notify2(nua, nh, e, NULL, tags);
+}
+
+
+int nua_stack_notify2(nua_t *nua,
+ nua_handle_t *nh,
+ nua_event_t e,
+ nua_dialog_usage_t *du,
+ tagi_t const *tags)
+{
+ nua_client_request_t *cr = nh->nh_ds->ds_cr;
+ struct notifier_usage *nu;
+ msg_t *msg;
+ sip_t *sip;
+ sip_event_t const *o;
+ sip_time_t now;
+ int refresh = du != NULL;
+
+ if (cr->cr_orq) {
+ return UA_EVENT2(e, 900, "Request already in progress");
+ }
+
+ nua_stack_init_handle(nua, nh, TAG_NEXT(tags));
+
+ if (refresh) {
+ assert(!cr->cr_msg);
+ if (cr->cr_msg)
+ msg_destroy(cr->cr_msg);
+ cr->cr_msg = msg_copy(du->du_msg);
+ }
+
+ msg = nua_creq_msg(nua, nh, cr, cr->cr_retry_count || refresh,
+ SIP_METHOD_NOTIFY,
+ NUTAG_ADD_CONTACT(1),
+ TAG_NEXT(tags));
+ sip = sip_object(msg);
+ if (!sip)
+ return UA_EVENT1(e, NUA_INTERNAL_ERROR);
+
+ if (nh->nh_ds->ds_has_notifys == 1 && !sip->sip_event)
+ o = NONE;
+ else
+ o = sip->sip_event;
+
+ du = nua_dialog_usage_get(nh->nh_ds, nua_notify_usage, o);
+ nu = nua_dialog_usage_private(du);
+
+ if (du && du->du_event && !sip->sip_event)
+ sip_add_dup(msg, sip, (sip_header_t *)du->du_event);
+
+ now = sip_now();
+
+ if (!du)
+ ;
+ else if (sip->sip_subscription_state) {
+ /* SIPTAG_SUBSCRIPTION_STATE() overrides NUTAG_SUBSTATE() */
+ char const *ss_substate = sip->sip_subscription_state->ss_substate;
+
+ if (strcasecmp(ss_substate, "terminated") == 0)
+ nu->nu_substate = nua_substate_terminated;
+ else if (strcasecmp(ss_substate, "pending") == 0)
+ nu->nu_substate = nua_substate_pending;
+ else /* if (strcasecmp(subs->ss_substate, "active") == 0) */
+ nu->nu_substate = nua_substate_active;
+
+ if (sip->sip_subscription_state->ss_expires) {
+ unsigned long expires;
+ expires = strtoul(sip->sip_subscription_state->ss_expires, NULL, 10);
+ if (expires > 3600)
+ expires = 3600;
+ nu->nu_expires = now + expires;
+ }
+ else if (nu->nu_substate != nua_substate_terminated) {
+ sip_subscription_state_t *ss = sip->sip_subscription_state;
+ char *param;
+
+ if (now < nu->nu_expires)
+ param = su_sprintf(msg_home(msg), "expires=%lu", nu->nu_expires - now);
+ else
+ param = "expires=0";
+
+ msg_header_add_param(msg_home(msg), ss->ss_common, param);
+ }
+ }
+ else {
+ sip_subscription_state_t *ss;
+ enum nua_substate substate;
+ char const *name;
+
+ substate = nu->nu_substate;
+
+ if (nu->nu_expires <= now)
+ substate = nua_substate_terminated;
+
+ if (substate != nua_substate_terminated) {
+ tagi_t const *t = tl_find_last(tags, nutag_substate);
+ if (t)
+ substate = (enum nua_substate)t->t_value;
+ }
+
+ switch (substate) {
+ case nua_substate_embryonic:
+ /*FALLTHROUGH*/
+ case nua_substate_pending:
+ name = "pending";
+ nu->nu_substate = nua_substate_pending;
+ break;
+ case nua_substate_active:
+ default:
+ name = "active";
+ nu->nu_substate = nua_substate_active;
+ break;
+ case nua_substate_terminated:
+ name = "terminated";
+ nu->nu_substate = nua_substate_terminated;
+ break;
+ }
+
+ if (nu->nu_substate != nua_substate_terminated) {
+ unsigned long expires = nu->nu_expires - now;
+ ss = sip_subscription_state_format(msg_home(msg), "%s;expires=%lu",
+ name, expires);
+ }
+ else {
+ ss = sip_subscription_state_make(msg_home(msg), "terminated; "
+ "reason=noresource");
+ }
+
+ msg_header_insert(msg, (void *)sip, (void *)ss);
+ }
+
+ if (du) {
+ if (nu->nu_substate == nua_substate_terminated)
+ du->du_terminating = 1;
+
+ if (!du->du_terminating && !refresh) {
+ /* Save template */
+ if (du->du_msg)
+ msg_destroy(du->du_msg);
+ du->du_msg = msg_ref_create(cr->cr_msg);
+ }
+ }
+
+ /* NOTIFY outside a dialog */
+ cr->cr_orq = nta_outgoing_mcreate(nua->nua_nta,
+ process_response_to_notify, nh, NULL,
+ msg,
+ SIPTAG_END(), TAG_NEXT(tags));
+
+ if (!cr->cr_orq) {
+ msg_destroy(msg);
+ return UA_EVENT1(e, NUA_INTERNAL_ERROR);
+ }
+
+ cr->cr_usage = du;
+
+ return cr->cr_event = e;
+}
+
+static
+void restart_notify(nua_handle_t *nh, tagi_t *tags)
+{
+ nua_creq_restart(nh, nh->nh_ds->ds_cr, process_response_to_notify, tags);
+}
+
+/** @NUA_EVENT nua_r_notify
+ *
+ * Response to an outgoing @b NOTIFY request.
+ *
+ * The @b NOTIFY may be sent explicitly by nua_notify() or implicitly by NUA
+ * state machine. Implicit @b NOTIFY is sent when an established dialog is
+ * refreshed by client or it is terminated (either by client or because of a
+ * timeout)
+ *
+ * @param status response status code
+ * (if the request is retried, @a status is 100, the @a
+ * sip->sip_status->st_status contain the real status code
+ * from the response message, e.g., 302, 401, or 407)
+ * @param phrase a short textual description of @a status code
+ * @param nh operation handle associated with the subscription
+ * @param hmagic application context associated with the handle
+ * @param sip response to @b NOTIFY request or NULL upon an error
+ * (status code is in @a status and
+ * descriptive message in @a phrase parameters)
+ * @param tags NUTAG_SUBSTATE() indicating subscription state
+ *
+ * @sa nua_notify(), @RFC3265, #nua_i_subscribe, #nua_i_refer
+ *
+ * @END_NUA_EVENT
+ */
+
+static int process_response_to_notify(nua_handle_t *nh,
+ nta_outgoing_t *orq,
+ sip_t const *sip)
+{
+ enum nua_substate substate = nua_substate_terminated;
+
+ if (nua_creq_check_restart(nh, nh->nh_ds->ds_cr, orq, sip, restart_notify))
+ return 0;
+
+ if (nh->nh_ds->ds_cr->cr_usage) {
+ struct notifier_usage *nu = nua_dialog_usage_private(nh->nh_ds->ds_cr->cr_usage);
+ substate = nu->nu_substate;
+ assert(substate != nua_substate_embryonic);
+ }
+
+ return nua_stack_process_response(nh, nh->nh_ds->ds_cr, orq, sip,
+ NUTAG_SUBSTATE(substate),
+ TAG_END());
+}
+
+
+static void nua_notify_usage_refresh(nua_handle_t *nh,
+ nua_dialog_state_t *ds,
+ nua_dialog_usage_t *du,
+ sip_time_t now)
+{
+ struct notifier_usage *nu = nua_dialog_usage_private(du);
+
+ if (nh->nh_ds->ds_cr->cr_usage == du) /* Already notifying. */
+ return;
+
+ if (now >= nu->nu_expires) {
+ sip_subscription_state_t ss[1];
+ char const *params[] = { NULL, NULL };
+ tagi_t tags[2] = {
+ { SIPTAG_SUBSCRIPTION_STATE(ss) }, { TAG_END() }
+ };
+
+ sip_subscription_state_init(ss);
+
+ ss->ss_substate = "terminated";
+ ss->ss_params = params;
+ params[0] = "reason=timeout";
+ ss->ss_reason = "timeout";
+
+ nua_stack_notify2(nh->nh_nua, nh, nua_r_notify, du, tags);
+ }
+ else {
+ nua_stack_notify2(nh->nh_nua, nh, nua_r_notify, du, NULL);
+ }
+}
+
+/** @interal Shut down NOTIFY usage.
+ *
+ * @retval >0 shutdown done
+ * @retval 0 shutdown in progress
+ * @retval <0 try again later
+ */
+static int nua_notify_usage_shutdown(nua_handle_t *nh,
+ nua_dialog_state_t *ds,
+ nua_dialog_usage_t *du)
+{
+ nua_client_request_t *cr = nh->nh_ds->ds_cr;
+
+ if (!cr->cr_usage) {
+ /* Unnotify */
+ nua_stack_notify2(nh->nh_nua, nh, nua_r_destroy, du, NULL);
+ return cr->cr_usage != du;
+ }
+
+ if (!du->du_ready && !cr->cr_orq)
+ return 1; /* Unauthenticated NOTIFY? */
+
+ return -1; /* Request in progress */
+}
+
+
+/* ======================================================================== */
+/* REFER */
+/* RFC 3515 */
+
+/** @NUA_EVENT nua_i_refer
+ *
+ * Incoming @b REFER request used to transfer calls.
+ *
+ * @param status status code of response sent automatically by stack
+ * @param phrase a short textual description of @a status code
+ * @param nh operation handle associated with the incoming request
+ * @param hmagic application context associated with the handle
+ * (NULL if outside of an already established session)
+ * @param sip incoming REFER request
+ * @param tags NUTAG_REFER_EVENT() \n
+ * SIPTAG_REFERRED_BY()
+ *
+ * @sa nua_refer(), #nua_r_refer, @ReferTo, NUTAG_REFER_EVENT(),
+ * SIPTAG_REFERRED_BY(), @ReferredBy, NUTAG_NOTIFY_REFER(),
+ * NUTAG_REFER_WITH_ID(), @RFC3515.
+ *
+ * @END_NUA_EVENT
+ */
+
+/** @internal Process incoming REFER. */
+int nua_stack_process_refer(nua_t *nua,
+ nua_handle_t *nh,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ nua_dialog_usage_t *du = NULL;
+ struct notifier_usage *nu;
+ sip_event_t *event;
+ sip_referred_by_t *by = NULL, default_by[1];
+ msg_t *response;
+ sip_time_t expires;
+ int created = 0;
+
+ if (nh == NULL) {
+ if (!(nh = nua_stack_incoming_handle(nua, irq, sip, 1)))
+ return 500;
+ created = 1;
+ }
+
+ if (nh->nh_ds->ds_has_referrals || NH_PGET(nh, refer_with_id))
+ event = sip_event_format(nh->nh_home, "refer;id=%u", sip->sip_cseq->cs_seq);
+ else
+ event = sip_event_make(nh->nh_home, "refer");
+
+ if (event)
+ du = nua_dialog_usage_add(nh, nh->nh_ds, nua_notify_usage, event);
+
+ if (!du || du->du_ready) {
+ if (du->du_ready) {
+ SU_DEBUG_1(("nua(%p): REFER with existing refer;id=%u\n", nh,
+ sip->sip_cseq->cs_seq));
+ }
+ if (created)
+ nh_destroy(nua, nh);
+ return 500;
+ }
+
+ nu = nua_dialog_usage_private(du);
+ du->du_ready = 1;
+ nh->nh_ds->ds_has_referrals = 1;
+
+ nua_dialog_uas_route(nh, nh->nh_ds, sip, 1); /* Set route and tags */
+
+ if (!sip->sip_referred_by) {
+ sip_from_t *a = sip->sip_from;
+
+ sip_referred_by_init(by = default_by);
+
+ *by->b_url = *a->a_url;
+ by->b_display = a->a_display;
+ }
+
+ response = nh_make_response(nua, nh, irq,
+ SIP_202_ACCEPTED,
+ NUTAG_ADD_CONTACT(1),
+ TAG_END());
+
+ nta_incoming_mreply(irq, response);
+
+ expires = NH_PGET(nh, refer_expires);
+
+ if (sip->sip_expires && sip->sip_expires->ex_delta < expires)
+ expires = sip->sip_expires->ex_delta;
+ nu->nu_substate = nua_substate_pending;
+ nu->nu_expires = sip_now() + expires;
+
+ /* Immediate notify in order to establish the dialog */
+ if (!sip->sip_to->a_tag)
+ nua_stack_post_signal(nh,
+ nua_r_notify,
+ SIPTAG_EVENT(event),
+ SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
+ SIPTAG_PAYLOAD_STR("SIP/2.0 100 Trying\r\n"),
+ TAG_END());
+
+ nua_stack_event(nh->nh_nua, nh, nta_incoming_getrequest(irq),
+ nua_i_refer, SIP_202_ACCEPTED,
+ NUTAG_REFER_EVENT(event),
+ TAG_IF(by, SIPTAG_REFERRED_BY(by)),
+ TAG_END());
+
+ su_free(nh->nh_home, event);
+
+ return 500;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_options.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_options.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,140 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nua_options.c
+ * @brief Implementation of OPTIONS client.
+ *
+ * OPTIONS server is in nua_session.c.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Mar 8 17:02:19 EET 2006 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include <assert.h>
+
+#include <sofia-sip/string0.h>
+#include <sofia-sip/sip_protos.h>
+#include <sofia-sip/sip_status.h>
+
+#define NTA_LEG_MAGIC_T struct nua_handle_s
+#define NTA_OUTGOING_MAGIC_T struct nua_handle_s
+
+#include "nua_stack.h"
+
+/**@fn void nua_options(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
+ *
+ * Query capabilities from server with OPTIONS request.
+ *
+ * @param nh Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return
+ * nothing
+ *
+ * @par Related Tags:
+ * Tags in <sip_tag.h>
+ *
+ * @par Events:
+ * #nua_r_options
+ *
+ * @sa #nua_i_options, @RFC3261 section 10
+ */
+
+static int process_response_to_options(nua_handle_t *nh,
+ nta_outgoing_t *orq,
+ sip_t const *sip);
+
+int
+nua_stack_options(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags)
+{
+ nua_client_request_t *cr = nh->nh_ds->ds_cr;
+ msg_t *msg;
+
+ if (nh_is_special(nh)) {
+ return UA_EVENT2(e, 900, "Invalid handle for OPTIONS");
+ }
+ else if (cr->cr_orq) {
+ return UA_EVENT2(e, 900, "Request already in progress");
+ }
+
+ nua_stack_init_handle(nua, nh, TAG_NEXT(tags));
+
+ msg = nua_creq_msg(nua, nh, cr, cr->cr_retry_count,
+ SIP_METHOD_OPTIONS,
+ TAG_NEXT(tags));
+
+ cr->cr_orq = nta_outgoing_mcreate(nua->nua_nta,
+ process_response_to_options, nh, NULL,
+ msg,
+ SIPTAG_END(), TAG_NEXT(tags));
+ if (!cr->cr_orq) {
+ msg_destroy(msg);
+ return UA_EVENT1(e, NUA_INTERNAL_ERROR);
+ }
+
+ return cr->cr_event = e;
+}
+
+void restart_options(nua_handle_t *nh, tagi_t *tags)
+{
+ nua_creq_restart(nh, nh->nh_ds->ds_cr, process_response_to_options, tags);
+}
+
+/** @NUA_EVENT nua_r_options
+ *
+ * Answer to outgoing OPTIONS.
+ *
+ * @param status response status code
+ * (if the request is retried the @a status is 100 and the @a
+ * sip->sip_status->st_status contain the real status code
+ * from the response message, e.g., 302, 401, or 407)
+ * @param phrase a short textual description of @a status code
+ * @param nh operation handle associated with the incoming OPTIONS request
+ * @param hmagic application context associated with the handle
+ * @param sip response to OPTIONS request or NULL upon an error
+ * (status code is in @a status and
+ * descriptive message in @a phrase parameters)
+ * @param tags empty
+ *
+ * @sa nua_options(), @RFC3261 section 11, #nua_i_options
+ *
+ * @END_NUA_EVENT
+ */
+
+static int process_response_to_options(nua_handle_t *nh,
+ nta_outgoing_t *orq,
+ sip_t const *sip)
+{
+ if (nua_creq_check_restart(nh, nh->nh_ds->ds_cr, orq, sip, restart_options))
+ return 0;
+ return nua_stack_process_response(nh, nh->nh_ds->ds_cr, orq, sip, TAG_END());
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1617 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nua_register.c
+ * @brief REGISTER and registrations
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Mar 8 11:48:49 EET 2006 ppessi
+ */
+
+#include "config.h"
+
+#include <sofia-sip/string0.h>
+#include <sofia-sip/su_strlst.h>
+#include <sofia-sip/token64.h>
+#include <sofia-sip/su_tagarg.h>
+#include <sofia-sip/su_tag_inline.h>
+
+#include <sofia-sip/bnf.h>
+
+#include <sofia-sip/sip_protos.h>
+#include <sofia-sip/sip_util.h>
+#include <sofia-sip/sip_status.h>
+#include <sofia-sip/msg_parser.h>
+
+#include "nua_stack.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include <assert.h>
+
+#if !HAVE_STRCASESTR
+char *strcasestr(char const *haystack, char const *needle);
+#endif
+
+/* ====================================================================== */
+/* Helper macros and functions for handling #nua_handle_preferences_t. */
+
+#define NHP_IS_ANY_SET(nhp) nhp_is_any_set((nhp))
+
+/** Check if any preference is set in @a nhp. */
+su_inline int nhp_is_any_set(nua_handle_preferences_t const *nhp)
+{
+ char nhp_zero[sizeof nhp->nhp_set] = { 0 };
+ return memcmp(&nhp->nhp_set, nhp_zero, sizeof nhp->nhp_set) != 0;
+}
+
+/** Copy set parameters from @a b to @a a.
+ *
+ * If preference is set in @a b, mark it set also in @a a.
+ */
+su_inline void nhp_or_set(nua_handle_preferences_t *a,
+ nua_handle_preferences_t const *b)
+{
+ unsigned *ap = a->nhp_set_.set_unsigned;
+ unsigned const *bp = b->nhp_set_.set_unsigned;
+ size_t i;
+
+ memcpy(a, b, offsetof(nua_handle_preferences_t, nhp_set));
+
+ for (i = 0; i < (sizeof a->nhp_set); i += (sizeof *ap))
+ *ap++ |= *bp++;
+}
+
+static int nhp_set_tags(su_home_t *home,
+ nua_handle_preferences_t *nhp,
+ int global,
+ tagi_t const *tags);
+
+static int nhp_merge_lists(su_home_t *home,
+ msg_hclass_t *hc,
+ msg_list_t **return_new_list,
+ msg_list_t const *old_list,
+ int already_set,
+ int already_parsed,
+ int always_merge,
+ tag_value_t value);
+
+static
+nua_handle_preferences_t *nhp_move_params(su_home_t *home,
+ nua_handle_preferences_t *dst,
+ su_home_t *tmphome,
+ nua_handle_preferences_t const *src);
+
+/* ====================================================================== */
+/* Magical NUTAG_USER_AGENT() - add NHP_USER_AGENT there if it is not there */
+
+#define NHP_USER_AGENT PACKAGE_NAME "/" PACKAGE_VERSION
+
+static int already_contains_package_name(char const *s)
+{
+ char const pn[] = " " PACKAGE_NAME "/";
+ size_t pnlen = strlen(pn + 1);
+
+ return strncasecmp(s, pn + 1, pnlen) == 0 || strcasestr(s, pn);
+}
+
+/* ====================================================================== */
+/* Stack and handle parameters */
+
+static int nua_stack_set_smime_params(nua_t *nua, tagi_t const *tags);
+
+/** @internal Methods allowed by default. */
+static char const nua_allow_str[] =
+"INVITE, ACK, BYE, CANCEL, OPTIONS, PRACK, "
+"MESSAGE, SUBSCRIBE, NOTIFY, REFER, UPDATE";
+
+/** @internal Set default parameters */
+int nua_stack_set_defaults(nua_handle_t *nh,
+ nua_handle_preferences_t *nhp)
+{
+ su_home_t *home = (su_home_t *)nh;
+
+ /* Set some defaults */
+ NHP_SET(nhp, retry_count, 3);
+ NHP_SET(nhp, max_subscriptions, 20);
+
+ NHP_SET(nhp, media_enable, 1);
+ NHP_SET(nhp, invite_enable, 1);
+ NHP_SET(nhp, auto_alert, 0);
+ NHP_SET(nhp, early_media, 0);
+ NHP_SET(nhp, only183_100rel, 0);
+ NHP_SET(nhp, auto_answer, 0);
+ NHP_SET(nhp, auto_ack, 1);
+ NHP_SET(nhp, invite_timeout, 120);
+
+ NHP_SET(nhp, session_timer, 1800);
+ NHP_SET(nhp, min_se, 120);
+ NHP_SET(nhp, refresher, nua_no_refresher);
+ NHP_SET(nhp, update_refresh, 0);
+
+ NHP_SET(nhp, message_enable, 1);
+ NHP_SET(nhp, win_messenger_enable, 0);
+ if (getenv("PIMIW_HACK") != 0)
+ NHP_SET(nhp, message_auto_respond, 1);
+
+ NHP_SET(nhp, media_features, 0);
+ NHP_SET(nhp, callee_caps, 0);
+ NHP_SET(nhp, service_route_enable, 1);
+ NHP_SET(nhp, path_enable, 1);
+
+ NHP_SET(nhp, refer_expires, 300);
+ NHP_SET(nhp, refer_with_id, 1);
+
+ NHP_SET(nhp, substate, nua_substate_active);
+
+ NHP_SET(nhp, allow, sip_allow_make(home, nua_allow_str));
+ NHP_SET(nhp, supported, sip_supported_make(home, "timer, 100rel"));
+ NHP_SET(nhp, user_agent, su_strdup(home, NHP_USER_AGENT));
+
+ NHP_SET(nhp, outbound, su_strdup(home, "natify"));
+
+ NHP_SET(nhp, keepalive, 120000);
+
+ NHP_SET(nhp, appl_method,
+ sip_allow_make(home, "INVITE, REGISTER, PUBLISH, SUBSCRIBE"));
+
+ if (!nhp->nhp_allow ||
+ !nhp->nhp_supported ||
+ !nhp->nhp_user_agent ||
+ !nhp->nhp_outbound)
+ return -1;
+
+ return 0;
+}
+
+/** @internal Set the default from field */
+int nua_stack_set_from(nua_t *nua, int initial, tagi_t const *tags)
+{
+ sip_from_t const *from = NONE;
+ char const *str = NONE;
+ sip_from_t *f = NULL, f0[1];
+
+ char const *uicc_name = "default";
+
+ tl_gets(tags,
+ /* By nua_stack_set_from() */
+ SIPTAG_FROM_REF(from),
+ SIPTAG_FROM_STR_REF(str),
+ NUTAG_UICC_REF(uicc_name),
+ TAG_END());
+
+#if HAVE_UICC_H
+ if (initial && uicc_name)
+ nua->nua_uicc = uicc_create(root, uicc_name);
+#endif
+
+ if (!initial && from == NONE && str == NONE)
+ return 0;
+
+ sip_from_init(f0);
+
+ if (from && from != NONE) {
+ f0->a_display = from->a_display;
+ *f0->a_url = *from->a_url;
+ f = sip_from_dup(nua->nua_home, f0);
+ }
+ else if (str && str != NONE) {
+ f = sip_from_make(nua->nua_home, str);
+ if (f)
+ *f0 = *f, f = f0, f->a_params = NULL;
+ }
+ else {
+ sip_contact_t const *m;
+
+ m = nua_stack_get_contact(nua->nua_registrations);
+
+ if (m) {
+ f0->a_display = m->m_display;
+ *f0->a_url = *m->m_url;
+ f = sip_from_dup(nua->nua_home, f0);
+ }
+ }
+
+ if (!f)
+ return -1;
+
+ *nua->nua_from = *f;
+ return 0;
+}
+
+/** @internal Initialize instance ID. */
+int nua_stack_init_instance(nua_handle_t *nh, tagi_t const *tags)
+{
+ nua_handle_preferences_t *nhp = nh->nh_prefs;
+
+ char const *instance = NONE;
+
+ tl_gets(tags, NUTAG_INSTANCE_REF(instance), TAG_END());
+
+ if (instance != NONE) {
+ NHP_SET(nhp, instance, su_strdup(nh->nh_home, instance));
+ if (instance && !nhp->nhp_instance)
+ return -1;
+ }
+
+ return 0;
+}
+
+/**@fn void nua_set_params(nua_t *nua, tag_type_t tag, tag_value_t value, ...)
+ *
+ * Set @nua parameters, shared by all handles.
+ *
+ * @param nua Pointer to NUA stack object
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return
+ * nothing
+ *
+ * @par Related tags:
+ * NUTAG_ALLOW(), SIPTAG_ALLOW(), and SIPTAG_ALLOW_STR() \n
+ * NUTAG_ALLOW_EVENTS(), SIPTAG_ALLOW_EVENTS(), and
+ * SIPTAG_ALLOW_EVENTS_STR() \n
+ * NUTAG_AUTOACK() \n
+ * NUTAG_AUTOALERT() \n
+ * NUTAG_AUTOANSWER() \n
+ * NUTAG_CALLEE_CAPS() \n
+ * NUTAG_DETECT_NETWORK_UPDATES() \n
+ * NUTAG_EARLY_ANSWER() \n
+ * NUTAG_EARLY_MEDIA() \n
+ * NUTAG_ENABLEINVITE() \n
+ * NUTAG_ENABLEMESSAGE() \n
+ * NUTAG_ENABLEMESSENGER() \n
+ * NUTAG_INSTANCE() \n
+ * NUTAG_INVITE_TIMER() \n
+ * NUTAG_KEEPALIVE() \n
+ * NUTAG_KEEPALIVE_STREAM() \n
+ * NUTAG_MAX_SUBSCRIPTIONS() \n
+ * NUTAG_MEDIA_ENABLE() \n
+ * NUTAG_MEDIA_FEATURES() \n
+ * NUTAG_MIN_SE() \n
+ * NUTAG_M_DISPLAY() \n
+ * NUTAG_M_FEATURES() \n
+ * NUTAG_M_PARAMS() \n
+ * NUTAG_M_USERNAME() \n
+ * NUTAG_ONLY183_100REL() \n
+ * NUTAG_OUTBOUND() \n
+ * NUTAG_PATH_ENABLE() \n
+ * NUTAG_REFER_EXPIRES() \n
+ * NUTAG_REFER_WITH_ID() \n
+ * NUTAG_REGISTRAR() \n
+ * NUTAG_RETRY_COUNT() \n
+ * NUTAG_SERVICE_ROUTE_ENABLE() \n
+ * NUTAG_SESSION_REFRESHER() \n
+ * NUTAG_SESSION_TIMER() \n
+ * NUTAG_SMIME_ENABLE() \n
+ * NUTAG_SMIME_KEY_ENCRYPTION() \n
+ * NUTAG_SMIME_MESSAGE_DIGEST() \n
+ * NUTAG_SMIME_MESSAGE_ENCRYPTION() \n
+ * NUTAG_SMIME_OPT() \n
+ * NUTAG_SMIME_PROTECTION_MODE() \n
+ * NUTAG_SMIME_SIGNATURE() \n
+ * NUTAG_SOA_NAME() \n
+ * NUTAG_SUBSTATE() \n
+ * NUTAG_SUPPORTED(), SIPTAG_SUPPORTED(), and SIPTAG_SUPPORTED_STR() \n
+ * NUTAG_UPDATE_REFRESH() \n
+ * NUTAG_USER_AGENT(), SIPTAG_USER_AGENT() and SIPTAG_USER_AGENT_STR() \n
+ * SIPTAG_ORGANIZATION() and SIPTAG_ORGANIZATION_STR() \n
+ *
+ * nua_set_params() also accepts any soa tags, defined in
+ * <sofia-sip/soa_tag.h>, and nta tags, defined in <sofia-sip/nta_tag.h>.
+ *
+ * @par Events:
+ * #nua_r_set_params
+ *
+ * @par SIP Header as NUA Parameters
+ * The @nua parameters include SIP headers @Allow, @Supported, @Organization,
+ * @UserAgent and @From. They are included in most of the SIP messages sent
+ * by @nua. They are set in the same way as the tagged arguments are
+ * used to populate a SIP message.
+ * @par
+ * When multiple tags for the same header are specified, the behaviour
+ * depends on the header type. If only a single header field can be included
+ * in a SIP message, the latest non-NULL value is used, e.g., @Organization.
+ * However, if the SIP header can consist of multiple lines or header fields
+ * separated by comma, in this case, @Allow and @Supported, all the tagged
+ * values are concatenated.
+ * @par
+ * However, if the tag value is #SIP_NONE (-1 casted as a void pointer), the
+ * values from previous tags are ignored.
+ *
+ * For example, the nua_set_params() call like this:
+ * @code
+ * nua_set_params(nua,
+ * SIPTAG_USER_AGENT_STR("tester/1.0"),
+ * SIPTAG_ALLOW_STR("INVITE,CANCEL,BYE,ACK"),
+ * SIPTAG_ORGANIZATION(NULL),
+ * SIPTAG_USER_AGENT(NULL),
+ * SIPTAG_ALLOW(SIP_NONE),
+ * TAG_END());
+ * @endcode
+ * will leave @Allow and @Organization headers empty. The @UserAgent header
+ * will contain value "tester/1.0".
+ * @code
+ * nua_set_params(nua,
+ * SIPTAG_ORGANIZATION_STR("Malevolent Microwavers"),
+ * SIPTAG_ALLOW_STR("OPTIONS"),
+ * SIPTAG_ALLOW(SIP_NONE),
+ * SIPTAG_ORGANIZATION_STR("The Phone Company"),
+ * SIPTAG_ALLOW_STR("SUBSCRIBE"),
+ * SIPTAG_ALLOW(NULL),
+ * SIPTAG_ORGANIZATION_STR(NULL),
+ * TAG_END());
+ * @endcode
+ * sets the header @Allow with value <code>SUBSCRIBE</code> and the
+ * header @Organization will have value <code>The Phone Company</code>.
+ *
+ */
+
+/**@fn void nua_set_hparams(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
+ *
+ * Set the handle-specific parameters.
+ *
+ * The handle-specific parameters override default or global parameters set
+ * by nua_set_params(). The handle-specific parameters are set by several
+ * other operations: nua_invite(), nua_respond(), nua_ack(),
+ * nua_prack(), nua_update(), nua_info(), nua_bye(), nua_options(),
+ * nua_message(), nua_register(), nua_publish(), nua_refer(),
+ * nua_subscribe(), nua_notify(), nua_refer(), and nua_notifier().
+ *
+ * @param nh Pointer to a NUA handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return
+ * nothing
+ *
+ * @par Tags Used to Set Handle-Specific Parameters:
+ * NUTAG_ALLOW(), SIPTAG_ALLOW(), and SIPTAG_ALLOW_STR() \n
+ * NUTAG_ALLOW_EVENTS(), SIPTAG_ALLOW_EVENTS(), and
+ * SIPTAG_ALLOW_EVENTS_STR() \n
+ * NUTAG_AUTOACK() \n
+ * NUTAG_AUTOALERT() \n
+ * NUTAG_AUTOANSWER() \n
+ * NUTAG_CALLEE_CAPS() \n
+ * NUTAG_EARLY_ANSWER() \n
+ * NUTAG_EARLY_MEDIA() \n
+ * NUTAG_ENABLEINVITE() \n
+ * NUTAG_ENABLEMESSAGE() \n
+ * NUTAG_ENABLEMESSENGER() \n
+ * NUTAG_INSTANCE() \n
+ * NUTAG_INVITE_TIMER() \n
+ * NUTAG_KEEPALIVE() \n
+ * NUTAG_KEEPALIVE_STREAM() \n
+ * NUTAG_MAX_SUBSCRIPTIONS() \n
+ * NUTAG_MEDIA_ENABLE() \n
+ * NUTAG_MEDIA_FEATURES() \n
+ * NUTAG_MIN_SE() \n
+ * NUTAG_M_DISPLAY() \n
+ * NUTAG_M_FEATURES() \n
+ * NUTAG_M_PARAMS() \n
+ * NUTAG_M_USERNAME() \n
+ * NUTAG_ONLY183_100REL() \n
+ * NUTAG_OUTBOUND() \n
+ * NUTAG_PATH_ENABLE() \n
+ * NUTAG_REFER_EXPIRES() \n
+ * NUTAG_REFER_WITH_ID() \n
+ * NUTAG_REGISTRAR() \n
+ * NUTAG_RETRY_COUNT() \n
+ * NUTAG_SERVICE_ROUTE_ENABLE() \n
+ * NUTAG_SESSION_REFRESHER() \n
+ * NUTAG_SESSION_TIMER() \n
+ * NUTAG_SOA_NAME() \n
+ * NUTAG_SUBSTATE() \n
+ * NUTAG_SUPPORTED(), SIPTAG_SUPPORTED(), and SIPTAG_SUPPORTED_STR() \n
+ * NUTAG_UPDATE_REFRESH() \n
+ * NUTAG_USER_AGENT(), SIPTAG_USER_AGENT() and SIPTAG_USER_AGENT_STR() \n
+ * SIPTAG_ORGANIZATION() and SIPTAG_ORGANIZATION_STR() \n
+ * Any soa tags are also considered as handle-specific parameters. They are
+ * defined in <sofia-sip/soa_tag.h>.
+ *
+ * The global parameters that can not be set by nua_set_hparams() include
+ * NUTAG_DETECT_NETWORK_UPDATES(), NUTAG_SMIME_* tags, and all NTA tags.
+ *
+ * @par Events:
+ * #nua_r_set_params
+ */
+
+/** @NUA_EVENT nua_r_set_params
+ *
+ * Response to nua_set_params() or nua_set_hparams().
+ *
+ * @param status 200 when successful, error code otherwise
+ * @param phrase a short textual description of @a status code
+ * @param nh NULL when responding to nua_set_params(),
+ * operation handle when responding to nua_set_hparams()
+ * @param hmagic NULL when responding to nua_set_params(),
+ * application contact associated with the operation handle
+ * when responding to nua_set_hparams()
+ * @param sip NULL
+ * @param tags None
+ *
+ * @sa nua_set_params(), nua_set_hparams(),
+ * #nua_r_get_params, nua_get_params(), nua_get_hparams()
+ *
+ * @END_NUA_EVENT
+ */
+
+int nua_stack_set_params(nua_t *nua, nua_handle_t *nh, nua_event_t e,
+ tagi_t const *tags)
+{
+ nua_handle_t *dnh = nua->nua_dhandle;
+ nua_handle_preferences_t tmp[1], *nhp = nh->nh_prefs;
+ nua_handle_preferences_t const *dnhp = dnh->nh_prefs;
+
+ su_home_t tmphome[1] = { SU_HOME_INIT(tmphome) };
+
+ tagi_t const *ptags;
+
+ int error, global;
+ int status = 900;
+ char const *phrase = "Error storing parameters";
+ sip_supported_t const *supported = NULL;
+ sip_allow_t const *allow = NULL;
+ sip_allow_events_t const *allow_events = NULL;
+ sip_allow_t const *appl_method = NULL;
+
+ enter;
+
+ ptags = !nh->nh_used_ptags ? nh->nh_ptags : NULL;
+
+ *tmp = *nhp; NHP_UNSET_ALL(tmp);
+
+ /* Supported features, allowed methods and events are merged
+ with previous ones */
+ if (!NHP_ISSET(nhp, supported))
+ supported = tmp->nhp_supported = dnhp->nhp_supported;
+ if (!NHP_ISSET(nhp, allow))
+ allow = tmp->nhp_allow = dnhp->nhp_allow;
+ if (!NHP_ISSET(nhp, allow_events))
+ allow_events = tmp->nhp_allow_events = dnhp->nhp_allow_events;
+ if (!NHP_ISSET(nhp, appl_method))
+ appl_method = tmp->nhp_appl_method = dnhp->nhp_appl_method;
+
+ error = 0;
+ global = nh == dnh; /* save also stack-specific params */
+
+ /* Set and save parameters to tmp */
+ if (nhp_set_tags(tmphome, tmp, global, ptags) < 0)
+ error = 1, phrase = "Error storing default handle parameters";
+ else if (nhp_set_tags(tmphome, tmp, global, tags) < 0)
+ error = 1, phrase = "Error storing parameters";
+ else {
+ if (NHP_IS_ANY_SET(tmp)) {
+ if (tmp->nhp_supported == supported)
+ tmp->nhp_supported = NULL;
+
+ if (tmp->nhp_allow == allow)
+ tmp->nhp_allow = NULL;
+
+ if (tmp->nhp_allow_events == allow_events)
+ tmp->nhp_allow_events = NULL;
+
+ if (tmp->nhp_appl_method == appl_method)
+ tmp->nhp_appl_method = NULL;
+
+ /* Move parameters from tmp to nhp (or allocate new nhp) */
+ if (nh != dnh && nhp == dnh->nh_prefs)
+ nhp = NULL;
+ nhp = nhp_move_params(nh->nh_home, nhp, tmphome, tmp);
+
+ if (nhp)
+ nh->nh_prefs = nhp;
+ else
+ /* Fail miserably with ENOMEM */
+ error = 1, status = 900, phrase = su_strerror(ENOMEM);
+ }
+
+ if (!error)
+ nh->nh_used_ptags = 1;
+ }
+
+ su_home_deinit(tmphome);
+
+ if (error)
+ ;
+ else if (!nh->nh_soa && NHP_GET(nhp, dnhp, media_enable)) {
+ /* Create soa when needed */
+ char const *soa_name = NHP_GET(nhp, dnhp, soa_name);
+
+ if (dnh->nh_soa)
+ nh->nh_soa = soa_clone(dnh->nh_soa, nua->nua_root, nh);
+ else
+ nh->nh_soa = soa_create(soa_name, nua->nua_root, nh);
+
+ ptags = nh->nh_ptags;
+
+ if (!nh->nh_soa)
+ error = 1, status = 900, phrase = "Error Creating SOA Object";
+ }
+ else if (nh->nh_soa && !NHP_GET(nhp, dnhp, media_enable)) {
+ /* ... destroy soa when not needed */
+ soa_destroy(nh->nh_soa), nh->nh_soa = NULL;
+ }
+
+ if (!error && nh->nh_soa) {
+ if ((ptags && soa_set_params(nh->nh_soa, TAG_NEXT(ptags)) < 0) ||
+ (tags && soa_set_params(nh->nh_soa, TAG_NEXT(tags)) < 0))
+ error = 1, status = 900, phrase = "Error Setting SOA Parameters";
+ }
+
+ if (error || nh != dnh) {
+ ;
+ }
+ else if (nua_stack_set_smime_params(nua, tags) < 0) {
+ error = 1, status = 900, phrase = "Error setting S/MIME parameters";
+ }
+ else if (!nua->nua_nta) {
+ }
+ /* Set stack-specific things below */
+ else if (nta_agent_set_params(nua->nua_nta, TAG_NEXT(tags)) < 0) {
+ status = 900, phrase = "Error setting NTA parameters";
+ error = 1;
+ }
+ else {
+ nua_stack_set_from(nua, 0, tags);
+ if (NHP_ISSET(nhp, detect_network_updates))
+ nua_stack_launch_network_change_detector(nua);
+ }
+
+ if (error) {
+ if (e == nua_i_none)
+ SU_DEBUG_1(("nua_set_params(): failed: %s\n", phrase));
+ return UA_EVENT2(e, status, phrase), -1;
+ }
+
+ if (e == nua_r_set_params)
+ UA_EVENT2(e, 200, "OK");
+
+ return 0;
+}
+
+/** Parse parameters from tags to @a nhp.
+ *
+ * @param home allocate new values from @a home
+ * @param nhp structure to store handle preferences
+ * @param global if true, save also global parameters
+ * @param tags list of tags to parse
+ */
+static int nhp_set_tags(su_home_t *home,
+ nua_handle_preferences_t *nhp,
+ int global,
+ tagi_t const *tags)
+{
+
+/* Set copy of string to handle pref structure */
+#define NHP_SET_STR(nhp, name, v) \
+ if ((v) != (tag_value_t)0) { \
+ char const *_value = (char const *)v; \
+ char *_new = _value ? su_strdup(home, _value) : NULL; \
+ if (NHP_ISSET(nhp, name)) \
+ su_free(home, (void *)nhp->nhp_##name); \
+ NHP_SET(nhp, name, _new); \
+ if (_new == NULL && _value != NULL) \
+ return -1; \
+ }
+
+/* Set copy of string from url to handle pref structure */
+#define NHP_SET_STR_BY_URL(nhp, name, v) \
+ if ((v) != (tag_value_t)-1) { \
+ url_t const *_value = (url_t const *)(v); \
+ char *_new; \
+ _new = url_as_string(home, (void *)_value); \
+ if (NHP_ISSET(nhp, name)) \
+ su_free(home, (void *)nhp->nhp_##name); \
+ NHP_SET(nhp, name, _new); \
+ if (_new == NULL && _value != NULL) \
+ return -1; \
+ }
+
+/* Set copy of header to handle pref structure */
+#define NHP_SET_HEADER(nhp, name, v) \
+ if ((v) != 0) { \
+ sip_##name##_t const *_value = (sip_##name##_t const *)(v); \
+ sip_##name##_t *_new = NULL; \
+ if (_value != SIP_NONE) \
+ _new = sip_##name##_dup(home, _value); \
+ if (NHP_ISSET(nhp, name)) \
+ msg_header_free_all(home, (void *)nhp->nhp_##name); \
+ NHP_SET(nhp, name, _new); \
+ if (_new == NULL && _value != SIP_NONE) \
+ return -1; \
+ }
+
+/* Set header made of string to handle pref structure */
+#define NHP_SET_HEADER_STR(nhp, name, v) \
+ if ((v) != 0) { \
+ char const *_value = (char const *)(v); \
+ sip_##name##_t *_new = NULL; \
+ if (_value != SIP_NONE) \
+ _new = sip_##name##_make(home, _value); \
+ if (NHP_ISSET(nhp, name)) \
+ msg_header_free_all(home, (void *)nhp->nhp_##name); \
+ NHP_SET(nhp, name, _new); \
+ if (_new == NULL && _value != SIP_NONE) \
+ return -1; \
+ }
+
+/* Set copy of string from header to handle pref structure */
+#define NHP_SET_STR_BY_HEADER(nhp, name, v) \
+ if ((v) != 0) { \
+ sip_##name##_t const *_value = (sip_##name##_t const *)(v); \
+ char *_new = NULL; \
+ if (_value != SIP_NONE) \
+ _new = sip_header_as_string(home, (void *)_value); \
+ if (NHP_ISSET(nhp, name)) \
+ su_free(home, (void *)nhp->nhp_##name); \
+ NHP_SET(nhp, name, _new); \
+ if (_new == NULL && _value != SIP_NONE) \
+ return -1; \
+ }
+
+
+ tagi_t const *t;
+
+ for (t = tags; t; t = tl_next(t)) {
+ tag_type_t tag = t->t_tag;
+ tag_value_t value = t->t_value;
+
+ if (tag == NULL)
+ break;
+ /* NUTAG_RETRY_COUNT(retry_count) */
+ else if (tag == nutag_retry_count) {
+ NHP_SET(nhp, retry_count, (unsigned)value);
+ }
+ /* NUTAG_MAX_SUBSCRIPTIONS(max_subscriptions) */
+ else if (tag == nutag_max_subscriptions) {
+ NHP_SET(nhp, max_subscriptions, (unsigned)value);
+ }
+ /* NUTAG_SOA_NAME(soa_name) */
+ else if (tag == nutag_soa_name) {
+ NHP_SET_STR(nhp, soa_name, value);
+ }
+ /* NUTAG_MEDIA_ENABLE(media_enable) */
+ else if (tag == nutag_media_enable) {
+ NHP_SET(nhp, media_enable, value != 0);
+ }
+ /* NUTAG_ENABLEINVITE(invite_enable) */
+ else if (tag == nutag_enableinvite) {
+ NHP_SET(nhp, invite_enable, value != 0);
+ }
+ /* NUTAG_AUTOALERT(auto_alert) */
+ else if (tag == nutag_autoalert) {
+ NHP_SET(nhp, auto_alert, value != 0);
+ }
+ /* NUTAG_EARLY_ANSWER(early_answer) */
+ else if (tag == nutag_early_answer) {
+ NHP_SET(nhp, early_answer, value != 0);
+ }
+ /* NUTAG_EARLY_MEDIA(early_media) */
+ else if (tag == nutag_early_media) {
+ NHP_SET(nhp, early_media, value != 0);
+ }
+ /* NUTAG_ONLY183_100REL(only183_100rel) */
+ else if (tag == nutag_only183_100rel) {
+ NHP_SET(nhp, only183_100rel, value != 0);
+ }
+ /* NUTAG_AUTOANSWER(auto_answer) */
+ else if (tag == nutag_autoanswer) {
+ NHP_SET(nhp, auto_answer, value != 0);
+ }
+ /* NUTAG_AUTOACK(auto_ack) */
+ else if (tag == nutag_autoack) {
+ NHP_SET(nhp, auto_ack, value != 0);
+ }
+ /* NUTAG_INVITE_TIMER(invite_timeout) */
+ else if (tag == nutag_invite_timer) {
+ NHP_SET(nhp, invite_timeout, (unsigned)value);
+ }
+ /* NUTAG_SESSION_TIMER(session_timer) */
+ else if (tag == nutag_session_timer) {
+ NHP_SET(nhp, session_timer, (unsigned)value);
+ }
+ /* NUTAG_MIN_SE(min_se) */
+ else if (tag == nutag_min_se) {
+ NHP_SET(nhp, min_se, (unsigned)value);
+ }
+ /* NUTAG_SESSION_REFRESHER(refresher) */
+ else if (tag == nutag_session_refresher) {
+ int refresher = value;
+
+ if (refresher >= nua_remote_refresher)
+ refresher = nua_remote_refresher;
+ else if (refresher <= nua_no_refresher)
+ refresher = nua_no_refresher;
+
+ NHP_SET(nhp, refresher, refresher);
+ }
+ /* NUTAG_UPDATE_REFRESH(update_refresh) */
+ else if (tag == nutag_update_refresh) {
+ NHP_SET(nhp, update_refresh, value != 0);
+ }
+ /* NUTAG_ENABLEMESSAGE(message_enable) */
+ else if (tag == nutag_enablemessage) {
+ NHP_SET(nhp, message_enable, value != 0);
+ }
+ /* NUTAG_ENABLEMESSENGER(win_messenger_enable) */
+ else if (tag == nutag_enablemessenger) {
+ NHP_SET(nhp, win_messenger_enable, value != 0);
+ }
+#if 0
+ /* NUTAG_AUTORESPOND(autorespond) */
+ else if (tag == nutag_autorespond) {
+ NHP_SET(nhp, autorespond, value);
+ }
+#endif
+ /* NUTAG_CALLEE_CAPS(callee_caps) */
+ else if (tag == nutag_callee_caps) {
+ NHP_SET(nhp, callee_caps, value != 0);
+ }
+ /* NUTAG_MEDIA_FEATURES(media_features) */
+ else if (tag == nutag_media_features) {
+ NHP_SET(nhp, media_features, value != 0);
+ }
+ /* NUTAG_SERVICE_ROUTE_ENABLE(service_route_enable) */
+ else if (tag == nutag_service_route_enable) {
+ NHP_SET(nhp, service_route_enable, value != 0);
+ }
+ /* NUTAG_PATH_ENABLE(path_enable) */
+ else if (tag == nutag_path_enable) {
+ NHP_SET(nhp, path_enable, value != 0);
+ }
+ /* NUTAG_REFER_EXPIRES(refer_expires) */
+ else if (tag == nutag_refer_expires) {
+ NHP_SET(nhp, refer_expires, value);
+ }
+ /* NUTAG_REFER_WITH_ID(refer_with_id) */
+ else if (tag == nutag_refer_with_id) {
+ NHP_SET(nhp, refer_with_id, value != 0);
+ }
+ /* NUTAG_SUBSTATE(substate) */
+ else if (tag == nutag_substate) {
+ NHP_SET(nhp, substate, (int)value);
+ }
+ /* NUTAG_KEEPALIVE(keepalive) */
+ else if (tag == nutag_keepalive) {
+ NHP_SET(nhp, keepalive, (unsigned)value);
+ }
+ /* NUTAG_KEEPALIVE_STREAM(keepalive_stream) */
+ else if (tag == nutag_keepalive_stream) {
+ NHP_SET(nhp, keepalive_stream, (unsigned)value);
+ }
+
+ /* NUTAG_SUPPORTED(feature) */
+ /* SIPTAG_SUPPORTED_STR(supported_str) */
+ /* SIPTAG_SUPPORTED(supported) */
+ else if (tag == nutag_supported ||
+ tag == siptag_supported ||
+ tag == siptag_supported_str) {
+ int ok;
+ sip_supported_t *supported = NULL;
+
+ ok = nhp_merge_lists(home,
+ sip_supported_class, &supported, nhp->nhp_supported,
+ NHP_ISSET(nhp, supported), /* already set by tags */
+ tag == siptag_supported, /* dup it, don't make */
+ tag == nutag_supported, /* merge with old value */
+ t->t_value);
+ if (ok < 0)
+ return -1;
+ else if (ok)
+ NHP_SET(nhp, supported, supported);
+ }
+ /* NUTAG_ALLOW(allowing) */
+ /* SIPTAG_ALLOW_STR(allow_str) */
+ /* SIPTAG_ALLOW(allow) */
+ else if (tag == nutag_allow ||
+ tag == siptag_allow_str ||
+ tag == siptag_allow) {
+ int ok;
+ msg_list_t *allow = NULL;
+
+ ok = nhp_merge_lists(home,
+ sip_allow_class,
+ &allow,
+ (msg_list_t const *)nhp->nhp_allow,
+ NHP_ISSET(nhp, allow), /* already set by tags */
+ tag == siptag_allow, /* dup it, don't make */
+ tag == nutag_allow, /* merge with old value */
+ t->t_value);
+ if (ok < 0)
+ return -1;
+ else if (ok)
+ NHP_SET(nhp, allow, (sip_allow_t *)allow);
+ }
+ /* NUTAG_ALLOW_EVENTS(allow_events) */
+ /* SIPTAG_ALLOW_EVENTS_STR(allow_events) */
+ /* SIPTAG_ALLOW_EVENTS(allow_events) */
+ else if (tag == nutag_allow_events ||
+ tag == siptag_allow_events_str ||
+ tag == siptag_allow_events) {
+ int ok;
+ sip_allow_events_t *allow_events = NULL;
+
+ ok = nhp_merge_lists(home,
+ sip_allow_events_class,
+ &allow_events,
+ nhp->nhp_allow_events,
+ NHP_ISSET(nhp, allow_events), /* already set */
+ tag == siptag_allow_events, /* dup it, don't make */
+ tag == nutag_allow_events, /* merge with old value */
+ t->t_value);
+ if (ok < 0)
+ return -1;
+ else if (ok)
+ NHP_SET(nhp, allow_events, allow_events);
+ }
+ /* NUTAG_APPL_METHOD(appl_method) */
+ else if (tag == nutag_appl_method) {
+ if (t->t_value == 0) {
+ NHP_SET(nhp, appl_method, NULL);
+ }
+ else {
+ int ok;
+ msg_list_t *appl_method = NULL;
+
+ ok = nhp_merge_lists(home,
+ sip_allow_class,
+ &appl_method,
+ (msg_list_t const *)nhp->nhp_appl_method,
+ NHP_ISSET(nhp, allow), /* already set by tags */
+ 0, /* dup it, don't make */
+ 1, /* merge with old value */
+ t->t_value);
+ if (ok < 0)
+ return -1;
+ else if (ok)
+ NHP_SET(nhp, appl_method, (sip_allow_t *)appl_method);
+ }
+ }
+ /* SIPTAG_USER_AGENT(user_agent) */
+ else if (tag == siptag_user_agent) {
+ NHP_SET_STR_BY_HEADER(nhp, user_agent, value);
+ }
+ /* SIPTAG_USER_AGENT_STR(user_agent_str) */
+ else if (tag == siptag_user_agent_str && value != 0) {
+ if (value == -1)
+ value = 0;
+ NHP_SET_STR(nhp, user_agent, value);
+ }
+ /* NUTAG_USER_AGENT(ua_name) */
+ else if (tag == nutag_user_agent) {
+ /* Add contents of NUTAG_USER_AGENT() to our distribution name */
+ char const *str = (void *)value, *ua;
+
+ if (str && !already_contains_package_name(str))
+ ua = su_sprintf(home, "%s %s", str, NHP_USER_AGENT);
+ else if (str)
+ ua = su_strdup(home, str);
+ else
+ ua = su_strdup(home, NHP_USER_AGENT);
+
+ NHP_SET(nhp, user_agent, ua);
+ }
+ /* SIPTAG_ORGANIZATION(organization) */
+ else if (tag == siptag_organization) {
+ NHP_SET_STR_BY_HEADER(nhp, organization, value);
+ }
+ /* SIPTAG_ORGANIZATION_STR(organization_str) */
+ else if (tag == siptag_organization_str) {
+ if (value == -1)
+ value = 0;
+ NHP_SET_STR(nhp, organization, value);
+ }
+ /* NUTAG_REGISTRAR(registrar) */
+ else if (tag == nutag_registrar) {
+ NHP_SET_STR_BY_URL(nhp, registrar, value);
+ if (NHP_ISSET(nhp, registrar) && !str0cmp(nhp->nhp_registrar, "*"))
+ NHP_SET_STR(nhp, registrar, 0);
+ }
+ /* NUTAG_INSTANCE(instance) */
+ else if (tag == nutag_instance) {
+ NHP_SET_STR(nhp, instance, value);
+ }
+ /* NUTAG_M_DISPLAY(m_display) */
+ else if (tag == nutag_m_display) {
+ NHP_SET_STR(nhp, m_display, value);
+ }
+ /* NUTAG_M_USERNAME(m_username) */
+ else if (tag == nutag_m_username) {
+ NHP_SET_STR(nhp, m_username, value);
+ }
+ /* NUTAG_M_PARAMS(m_params) */
+ else if (tag == nutag_m_params) {
+ NHP_SET_STR(nhp, m_params, value);
+ }
+ /* NUTAG_M_FEATURES(m_features) */
+ else if (tag == nutag_m_features) {
+ NHP_SET_STR(nhp, m_features, value);
+ }
+ /* NUTAG_OUTBOUND(outbound) */
+ else if (tag == nutag_outbound) {
+ NHP_SET_STR(nhp, outbound, value);
+ }
+ /* NUTAG_DETECT_NETWORK_UPDATES(detect_network_updates) */
+ else if (global && tag == nutag_detect_network_updates) {
+ int detector = (int)value;
+
+ if (detector < NUA_NW_DETECT_NOTHING)
+ detector = NUA_NW_DETECT_NOTHING;
+ else if (detector > NUA_NW_DETECT_TRY_FULL)
+ detector = NUA_NW_DETECT_TRY_FULL;
+
+ NHP_SET(nhp, detect_network_updates, detector);
+ }
+ }
+
+ return 0;
+}
+
+/** Merge (when needed) new values with old values. */
+static int nhp_merge_lists(su_home_t *home,
+ msg_hclass_t *hc,
+ msg_list_t **return_new_list,
+ msg_list_t const *old_list,
+ int already_set,
+ int already_parsed,
+ int always_merge,
+ tag_value_t value)
+{
+ msg_list_t *list, *elems;
+
+ if (value == -1) {
+ *return_new_list = NULL;
+ return 1;
+ }
+
+ if (value == 0) {
+ if (!already_set && !always_merge) {
+ *return_new_list = NULL;
+ return 1;
+ }
+ return 0;
+ }
+
+ if (already_parsed)
+ elems = (void *)msg_header_dup_as(home, hc, (msg_header_t *)value);
+ else
+ elems = (void *)msg_header_make(home, hc, (char const *)value);
+
+ if (!elems)
+ return -1;
+
+ list = (msg_list_t *)old_list;
+
+ if (!already_set) {
+ if (always_merge && list) {
+ list = (void *)msg_header_dup_as(home, hc, (void *)old_list);
+ if (!list)
+ return -1;
+ }
+ else
+ list = NULL;
+ }
+
+ if (!list) {
+ *return_new_list = elems;
+ return 1;
+ }
+
+ /* Add contents to the new list to the old list */
+ if (msg_params_join(home, (msg_param_t **)&list->k_items, elems->k_items,
+ 2 /* prune */, 0 /* don't dup */) < 0)
+ return -1;
+
+ *return_new_list =
+ (msg_list_t *)msg_header_dup_as(home, hc, (msg_header_t *)list);
+ if (!*return_new_list)
+ return -1;
+
+ msg_header_free(home, (msg_header_t *)list);
+ msg_header_free(home, (msg_header_t *)elems);
+
+ return 1;
+}
+
+static
+nua_handle_preferences_t *nhp_move_params(su_home_t *home,
+ nua_handle_preferences_t *dst,
+ su_home_t *tmphome,
+ nua_handle_preferences_t const *src)
+{
+ /* Update prefs structure */
+ nua_handle_preferences_t tbf[1];
+
+ if (dst == NULL)
+ dst = su_zalloc(home, sizeof *dst);
+ if (dst == NULL)
+ return NULL;
+ if (su_home_move(home, tmphome) < 0)
+ return NULL;
+
+ *tbf = *dst;
+ nhp_or_set(dst, src);
+
+ /* Handle pointer items. Free changed ones and zap unset ones. */
+#define NHP_ZAP_OVERRIDEN(tbf, nhp, pref) \
+ (((tbf)->nhp_set.nhb_##pref \
+ && (tbf)->nhp_##pref != (nhp)->nhp_##pref \
+ ? su_free(home, (void *)(tbf)->nhp_##pref) : (void)0), \
+ (void)(!(nhp)->nhp_set.nhb_##pref ? (nhp)->nhp_##pref = NULL : NULL))
+
+ NHP_ZAP_OVERRIDEN(tbf, dst, soa_name);
+ NHP_ZAP_OVERRIDEN(tbf, dst, registrar);
+ NHP_ZAP_OVERRIDEN(tbf, dst, supported);
+ NHP_ZAP_OVERRIDEN(tbf, dst, allow);
+ NHP_ZAP_OVERRIDEN(tbf, dst, user_agent);
+ NHP_ZAP_OVERRIDEN(tbf, dst, organization);
+ NHP_ZAP_OVERRIDEN(tbf, dst, instance);
+ NHP_ZAP_OVERRIDEN(tbf, dst, m_display);
+ NHP_ZAP_OVERRIDEN(tbf, dst, m_username);
+ NHP_ZAP_OVERRIDEN(tbf, dst, m_params);
+ NHP_ZAP_OVERRIDEN(tbf, dst, m_features);
+ NHP_ZAP_OVERRIDEN(tbf, dst, outbound);
+
+ return dst;
+}
+
+static int nua_handle_tags_filter(tagi_t const *f, tagi_t const *t);
+static int nua_handle_param_filter(tagi_t const *f, tagi_t const *t);
+
+/** Save taglist to a handle */
+int nua_handle_save_tags(nua_handle_t *nh, tagi_t *tags)
+{
+ tagi_t const tagfilter[] = {
+ { TAG_FILTER(nua_handle_tags_filter) },
+ { TAG_NULL() }
+ };
+ tagi_t const paramfilter[] = {
+ { TAG_FILTER(nua_handle_param_filter) },
+ { TAG_NULL() }
+ };
+
+ /* Initialization parameters */
+ url_string_t const *url = NULL;
+ sip_to_t const *p_to = NULL;
+ char const *to_str = NULL;
+ sip_from_t from[1];
+ sip_from_t const *p_from = NULL;
+ char const *from_str = NULL;
+ nua_handle_t *identity = NULL;
+
+ tagi_t const *t;
+
+ su_home_t tmphome[SU_HOME_AUTO_SIZE(1024)];
+
+ int error;
+
+ for (t = tags; t; t = tl_next(t)) {
+ if (t->t_tag == NULL)
+ break;
+ /* SIPTAG_FROM_REF(p_from) */
+ else if (t->t_tag == siptag_from) {
+ p_from = (sip_from_t *)t->t_value, from_str = NULL;
+ }
+ /* SIPTAG_FROM_STR_REF(from_str) */
+ else if (t->t_tag == siptag_from_str) {
+ from_str = (char const *)t->t_value, p_from = NULL;
+ }
+ /* SIPTAG_TO_REF(p_to) */
+ else if (t->t_tag == siptag_to) {
+ p_to = (sip_to_t *)t->t_value, to_str = NULL;
+ }
+ /* SIPTAG_TO_STR_REF(to_str) */
+ else if (t->t_tag == siptag_to_str) {
+ to_str = (char const *)t->t_value, p_to = NULL;
+ }
+ /* NUTAG_IDENTITY_REF(identity) */
+ else if (t->t_tag == nutag_identity) {
+ identity = (nua_handle_t *)t->t_value;
+ }
+ /* NUTAG_URL_REF(url) */
+ else if (t->t_tag == nutag_url) {
+ url = (url_string_t *)t->t_value;
+ }
+ /* NUTAG_SIPS_URL_REF(url) */
+ else if (t->t_tag == nutag_url) {
+ url = (url_string_t *)t->t_value;
+ }
+ }
+
+ su_home_auto(tmphome, sizeof tmphome);
+
+ if (p_from)
+ ;
+ else if (from_str)
+ p_from = sip_from_make(tmphome, from_str);
+ else if (!p_from && nh->nh_nua->nua_from)
+ *from = *nh->nh_nua->nua_from, from->a_params = NULL, p_from = from;
+ else
+ p_from = SIP_NONE; /* XXX - why? */
+
+ if (p_to)
+ ;
+ else if (to_str)
+ p_to = sip_to_make(tmphome, to_str);
+ else if (url)
+ p_to = sip_to_create(tmphome, url),
+ p_to ? sip_aor_strip((url_t*)p_to->a_url) : 0;
+ else
+ p_to = SIP_NONE;
+
+ if (p_to == NULL || p_from == NULL) {
+ su_home_deinit(tmphome);
+ return -1;
+ }
+
+ nh->nh_tags =
+ tl_filtered_tlist(nh->nh_home, tagfilter,
+ SIPTAG_FROM(p_from),
+ TAG_FILTER(nua_handle_tags_filter),
+ SIPTAG_TO(p_to),
+ TAG_FILTER(nua_handle_tags_filter),
+ TAG_NEXT(tags));
+
+ nh->nh_ptags =
+ tl_filtered_tlist(nh->nh_home, paramfilter, TAG_NEXT(tags));
+
+ error = nh->nh_tags == NULL || nh->nh_ptags == NULL;
+
+ if (!error)
+ tl_gets(nh->nh_tags, /* These does not change while nh lives */
+ SIPTAG_FROM_REF(nh->nh_ds->ds_local),
+ SIPTAG_TO_REF(nh->nh_ds->ds_remote),
+ TAG_END());
+
+ if (nh->nh_ptags && nh->nh_ptags->t_tag == NULL)
+ su_free(nh->nh_home, nh->nh_ptags), nh->nh_ptags = NULL;
+
+ if (identity)
+ nh->nh_identity = nua_handle_ref(identity);
+
+ su_home_deinit(tmphome);
+
+ return -error;
+}
+
+/** Filter tags used for settings. */
+static int nua_handle_param_filter(tagi_t const *f, tagi_t const *t)
+{
+ char const *ns;
+
+ if (!t || !t->t_tag)
+ return 0;
+
+ if (t->t_tag == nutag_url ||
+ t->t_tag == nutag_sips_url ||
+ t->t_tag == nutag_identity)
+ return 0;
+
+ ns = t->t_tag->tt_ns;
+ if (!ns)
+ return 0;
+
+ return strcmp(ns, "nua") == 0 || strcmp(ns, "soa") == 0;
+}
+
+/** Filter tags stored permanently as taglist. */
+static int nua_handle_tags_filter(tagi_t const *f, tagi_t const *t)
+{
+ tag_type_t tag;
+
+ if (!t || !t->t_tag)
+ return 0;
+
+ tag = t->t_tag;
+
+ if (tag == tag_filter)
+ return 0;
+
+ /* Accept @From or @To only when they are followed by
+ TAG_FILTER(nua_handle_tags_filter) */
+ if (tag == siptag_from || tag == siptag_to) {
+ t = tl_next(t);
+ return t && t->t_tag == tag_filter &&
+ t->t_value == (tag_value_t)nua_handle_tags_filter;
+ }
+
+ if (tag == nutag_identity)
+ return 0;
+ if (tag == siptag_from_str)
+ return 0;
+ if (tag == siptag_to_str)
+ return 0;
+
+ /** Ignore @CSeq, @RSeq, @RAck, @Timestamp, and @ContentLength */
+ if (tag == siptag_cseq || tag == siptag_cseq_str)
+ return 0;
+ if (tag == siptag_rseq || tag == siptag_rseq_str)
+ return 0;
+ if (tag == siptag_rack || tag == siptag_rack_str)
+ return 0;
+ if (tag == siptag_timestamp || tag == siptag_timestamp_str)
+ return 0;
+ if (tag == siptag_content_length || tag == siptag_content_length_str)
+ return 0;
+
+ return ! nua_handle_param_filter(f, t);
+}
+
+static
+int nua_stack_set_smime_params(nua_t *nua, tagi_t const *tags)
+{
+#if HAVE_SOFIA_SMIME
+ int smime_enable = nua->sm->sm_enable;
+ int smime_opt = nua->sm->sm_opt;
+ int smime_protection_mode = nua->sm->sm_protection_mode;
+ char const *smime_message_digest = NONE;
+ char const *smime_signature = NONE;
+ char const *smime_key_encryption = NONE;
+ char const *smime_message_encryption = NONE;
+ char const *smime_path = NONE;
+
+ int n;
+
+ n = tl_gets(tags,
+ NUTAG_SMIME_ENABLE_REF(smime_enable),
+ NUTAG_SMIME_OPT_REF(smime_opt),
+ NUTAG_SMIME_PROTECTION_MODE_REF(smime_protection_mode),
+ NUTAG_SMIME_MESSAGE_DIGEST_REF(smime_message_digest),
+ NUTAG_SMIME_SIGNATURE_REF(smime_signature),
+ NUTAG_SMIME_KEY_ENCRYPTION_REF(smime_key_encryption),
+ NUTAG_SMIME_MESSAGE_ENCRYPTION_REF(smime_message_encryption),
+ NUTAG_CERTIFICATE_DIR_REF(smime_path),
+ TAG_NULL());
+ if (n <= 0)
+ return n;
+
+ /* XXX - all other S/MIME parameters? */
+ return sm_set_params(nua->sm, smime_enable, smime_opt,
+ smime_protection_mode, smime_path);
+#endif
+
+ return 0;
+}
+
+/**@fn void nua_get_params(nua_t *nua, tag_type_t tag, tag_value_t value, ...)
+ *
+ * Get NUA parameters matching with the given filter.
+ * The values of NUA parameters is returned in #nua_r_get_params event.
+ *
+ * @param nua Pointer to NUA stack object
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return
+ * nothing
+ *
+ * @par Related tags:
+ * TAG_ANY() \n
+ * otherwise same tags as nua_set_params()
+ *
+ * @par Events:
+ * #nua_r_get_params
+ *
+ * @par Examples
+ * Find out default values of all parameters:
+ * @code
+ * nua_get_params(nua, TAG_ANY(), TAG_END());
+ * @endcode
+ */
+
+/**@fn void nua_get_hparams(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+ *
+ * Get values of handle-specific parameters in #nua_r_get_params event.
+ *
+ * Application will specify either expilicit list of tags it is interested
+ * in, or a filter (at the moment, TAG_ANY()). The values are returned as a
+ * list of tags in the #nua_r_get_params event.
+ *
+ * @param nh Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * The handle-specific parameters will contain only the parameters actually
+ * modified by application, either by nua_set_hparams() or some other
+ * handle-specific call. Currently, no NTA parameters are returned. They are
+ * returned only when application asks for user-agent-level parameters using
+ * either nua_get_params() or using default handle, eg.
+ * @code
+ * nua_get_hparams(nua_default(nua), TAG_ANY())
+ * @endcode
+ *
+ * @return
+ * nothing
+ *
+ * @par Related tags:
+ * #TAG_ANY \n
+ * othervise same tags as nua_set_hparams()
+ *
+ * @par Events:
+ * #nua_r_get_params
+ */
+
+/** @NUA_EVENT nua_r_get_params
+ *
+ * Answer to nua_get_params() or nua_get_hparams().
+ *
+ * @param status 200 when succesful, error code otherwise
+ * @param phrase a short textual description of @a status code
+ * @param nh NULL when responding to nua_get_params(),
+ * operation handle when responding to nua_get_hparams()
+ * @param hmagic NULL when responding to nua_get_params(),
+ * application contact associated with the operation handle
+ * when responding to nua_get_hparams()
+ * @param sip NULL
+ * @param tags
+ * NUTAG_AUTOACK() \n
+ * NUTAG_AUTOALERT() \n
+ * NUTAG_AUTOANSWER() \n
+ * NUTAG_CALLEE_CAPS() \n
+ * NUTAG_DETECT_NETWORK_UPDATES() \n
+ * NUTAG_EARLY_ANSWER() \n
+ * NUTAG_EARLY_MEDIA() \n
+ * NUTAG_ENABLEINVITE() \n
+ * NUTAG_ENABLEMESSAGE() \n
+ * NUTAG_ENABLEMESSENGER() \n
+ * NUTAG_INSTANCE() \n
+ * NUTAG_INVITE_TIMER() \n
+ * NUTAG_KEEPALIVE() \n
+ * NUTAG_KEEPALIVE_STREAM() \n
+ * NUTAG_MAX_SUBSCRIPTIONS() \n
+ * NUTAG_MEDIA_ENABLE() \n
+ * NUTAG_MEDIA_FEATURES() \n
+ * NUTAG_MIN_SE() \n
+ * NUTAG_M_DISPLAY() \n
+ * NUTAG_M_FEATURES() \n
+ * NUTAG_M_PARAMS() \n
+ * NUTAG_M_USERNAME() \n
+ * NUTAG_ONLY183_100REL() \n
+ * NUTAG_OUTBOUND() \n
+ * NUTAG_PATH_ENABLE() \n
+ * NUTAG_REFER_EXPIRES() \n
+ * NUTAG_REFER_WITH_ID() \n
+ * NUTAG_REGISTRAR() \n
+ * NUTAG_RETRY_COUNT() \n
+ * NUTAG_SERVICE_ROUTE_ENABLE() \n
+ * NUTAG_SESSION_REFRESHER() \n
+ * NUTAG_SESSION_TIMER() \n
+ * NUTAG_SMIME_ENABLE() \n
+ * NUTAG_SMIME_KEY_ENCRYPTION() \n
+ * NUTAG_SMIME_MESSAGE_DIGEST() \n
+ * NUTAG_SMIME_MESSAGE_ENCRYPTION() \n
+ * NUTAG_SMIME_OPT() \n
+ * NUTAG_SMIME_PROTECTION_MODE() \n
+ * NUTAG_SMIME_SIGNATURE() \n
+ * NUTAG_SOA_NAME() \n
+ * NUTAG_SUBSTATE() \n
+ * NUTAG_UPDATE_REFRESH() \n
+ * NUTAG_USER_AGENT() \n
+ * SIPTAG_ALLOW() \n
+ * SIPTAG_ALLOW_STR() \n
+ * SIPTAG_ALLOW_EVENTS() \n
+ * SIPTAG_ALLOW_EVENTS_STR() \n
+ * SIPTAG_FROM() \n
+ * SIPTAG_FROM_STR() \n
+ * SIPTAG_ORGANIZATION() \n
+ * SIPTAG_ORGANIZATION_STR() \n
+ * SIPTAG_SUPPORTED() \n
+ * SIPTAG_SUPPORTED_STR() \n
+ * SIPTAG_USER_AGENT() \n
+ * SIPTAG_USER_AGENT_STR() \n
+ *
+ * @sa nua_get_params(), nua_get_hparams(),
+ * nua_set_params(), nua_set_hparams(), #nua_r_set_params
+ *
+ * @END_NUA_EVENT
+ */
+
+/**@internal
+ * Send a list of NUA parameters to the application.
+ *
+ * This function gets invoked when application calls either nua_get_params()
+ * or nua_get_hparams().
+ *
+ * The parameter tag list will initially contain all the relevant parameter
+ * tags, and it will be filtered down to parameters asked by application.
+ *
+ * The handle-specific parameters will contain only the parameters actually
+ * modified by application, either by nua_set_hparams() or some other
+ * handle-specific call. NTA parameters are returned only when application
+ * asks for user-agent-level parameters using nua_get_params().
+ *
+ */
+int nua_stack_get_params(nua_t *nua, nua_handle_t *nh, nua_event_t e,
+ tagi_t const *tags)
+{
+ nua_handle_t *dnh = nua->nua_dhandle;
+ nua_handle_preferences_t const *nhp = nh->nh_prefs;
+
+ tagi_t *lst;
+
+ int has_from;
+ sip_from_t from[1];
+
+ sip_contact_t const *m;
+
+ /* nta */
+ usize_t udp_mtu = 0;
+ unsigned sip_t1 = 0, sip_t2 = 0, sip_t4 = 0, sip_t1x64 = 0;
+ unsigned debug_drop_prob = 0;
+ url_string_t const *proxy = NULL;
+ sip_contact_t const *aliases = NULL;
+ unsigned flags = 0;
+
+ /* soa */
+ tagi_t *media_params = NULL;
+
+ su_home_t tmphome[SU_HOME_AUTO_SIZE(16536)];
+
+ enter;
+
+ su_home_auto(tmphome, sizeof(tmphome));
+
+ nta_agent_get_params(nua->nua_nta,
+ NTATAG_UDP_MTU_REF(udp_mtu),
+ NTATAG_SIP_T1_REF(sip_t1),
+ NTATAG_SIP_T2_REF(sip_t2),
+ NTATAG_SIP_T4_REF(sip_t4),
+ NTATAG_SIP_T1X64_REF(sip_t1x64),
+ NTATAG_DEBUG_DROP_PROB_REF(debug_drop_prob),
+ NTATAG_DEFAULT_PROXY_REF(proxy),
+ NTATAG_ALIASES_REF(aliases),
+ NTATAG_SIPFLAGS_REF(flags),
+ TAG_END());
+
+ if (nh->nh_ds->ds_local)
+ has_from = 1, *from = *nh->nh_ds->ds_local, from->a_params = NULL;
+ else
+ has_from = 0;
+
+ media_params = soa_get_paramlist(nh->nh_soa, TAG_END());
+
+ m = nua_stack_get_contact(nua->nua_registrations);
+
+ /* Include tag in the list returned to user
+ * if it has been earlier set (by user) */
+#define TIF(TAG, pref) \
+ TAG_IF(nhp->nhp_set.nhb_##pref, TAG(nhp->nhp_##pref))
+
+ /* Include string tag made out of SIP header
+ * if it has been earlier set (by user) */
+#define TIF_STR(TAG, pref) \
+ TAG_IF(nhp->nhp_set.nhb_##pref, \
+ TAG(nhp->nhp_set.nhb_##pref && nhp->nhp_##pref \
+ ? sip_header_as_string(tmphome, (void *)nhp->nhp_##pref) : NULL))
+
+ /* Include header tag made out of string
+ * if it has been earlier set (by user) */
+#define TIF_SIP(TAG, pref) \
+ TAG_IF(nhp->nhp_set.nhb_##pref, \
+ TAG(nhp->nhp_set.nhb_##pref && nhp->nhp_##pref \
+ ? sip_##pref##_make(tmphome, (char *)nhp->nhp_##pref) \
+ : NULL))
+
+ lst = tl_filtered_tlist
+ (tmphome, tags,
+ TAG_IF(has_from, SIPTAG_FROM(from)),
+ TAG_IF(has_from,
+ SIPTAG_FROM_STR(has_from
+ ? sip_header_as_string(tmphome, (void *)from)
+ : NULL)),
+
+ TIF(NUTAG_RETRY_COUNT, retry_count),
+ TIF(NUTAG_MAX_SUBSCRIPTIONS, max_subscriptions),
+
+ TIF(NUTAG_SOA_NAME, soa_name),
+ TIF(NUTAG_MEDIA_ENABLE, media_enable),
+ TIF(NUTAG_ENABLEINVITE, invite_enable),
+ TIF(NUTAG_AUTOALERT, auto_alert),
+ TIF(NUTAG_EARLY_ANSWER, early_answer),
+ TIF(NUTAG_EARLY_MEDIA, early_media),
+ TIF(NUTAG_ONLY183_100REL, only183_100rel),
+ TIF(NUTAG_AUTOANSWER, auto_answer),
+ TIF(NUTAG_AUTOACK, auto_ack),
+ TIF(NUTAG_INVITE_TIMER, invite_timeout),
+
+ TIF(NUTAG_SESSION_TIMER, session_timer),
+ TIF(NUTAG_MIN_SE, min_se),
+ TIF(NUTAG_SESSION_REFRESHER, refresher),
+ TIF(NUTAG_UPDATE_REFRESH, update_refresh),
+
+ TIF(NUTAG_ENABLEMESSAGE, message_enable),
+ TIF(NUTAG_ENABLEMESSENGER, win_messenger_enable),
+ /* TIF(NUTAG_AUTORESPOND, autorespond), */
+
+ TIF(NUTAG_CALLEE_CAPS, callee_caps),
+ TIF(NUTAG_MEDIA_FEATURES, media_features),
+ TIF(NUTAG_SERVICE_ROUTE_ENABLE, service_route_enable),
+ TIF(NUTAG_PATH_ENABLE, path_enable),
+ TIF(NUTAG_REFER_EXPIRES, refer_expires),
+ TIF(NUTAG_REFER_WITH_ID, refer_with_id),
+
+ TIF(NUTAG_SUBSTATE, substate),
+
+ TIF(SIPTAG_SUPPORTED, supported),
+ TIF_STR(SIPTAG_SUPPORTED_STR, supported),
+ TIF(SIPTAG_ALLOW, allow),
+ TIF_STR(SIPTAG_ALLOW_STR, allow),
+ TIF(SIPTAG_ALLOW_EVENTS, allow_events),
+ TIF_STR(SIPTAG_ALLOW_EVENTS_STR, allow_events),
+ TIF_SIP(SIPTAG_USER_AGENT, user_agent),
+ TIF(SIPTAG_USER_AGENT_STR, user_agent),
+ TIF(NUTAG_USER_AGENT, user_agent),
+
+ TIF_SIP(SIPTAG_ORGANIZATION, organization),
+ TIF(SIPTAG_ORGANIZATION_STR, organization),
+
+ TIF(NUTAG_REGISTRAR, registrar),
+ TIF(NUTAG_KEEPALIVE, keepalive),
+ TIF(NUTAG_KEEPALIVE_STREAM, keepalive_stream),
+
+ TIF(NUTAG_INSTANCE, instance),
+ TIF(NUTAG_M_DISPLAY, m_display),
+ TIF(NUTAG_M_USERNAME, m_username),
+ TIF(NUTAG_M_PARAMS, m_params),
+ TIF(NUTAG_M_FEATURES, m_features),
+ TIF(NUTAG_OUTBOUND, outbound),
+ TIF(NUTAG_DETECT_NETWORK_UPDATES, detect_network_updates),
+
+ /* Skip user-agent-level parameters if parameters are for handle only */
+ TAG_IF(nh != dnh, TAG_NEXT(media_params)),
+
+ NTATAG_CONTACT(m),
+
+#if HAVE_SOFIA_SMIME
+ NUTAG_SMIME_ENABLE(nua->sm->sm_enable),
+ NUTAG_SMIME_OPT(nua->sm->sm_opt),
+ NUTAG_SMIME_PROTECTION_MODE(nua->sm->sm_protection_mode),
+ NUTAG_SMIME_MESSAGE_DIGEST(nua->sm->sm_message_digest),
+ NUTAG_SMIME_SIGNATURE(nua->sm->sm_signature),
+ NUTAG_SMIME_KEY_ENCRYPTION(nua->sm->sm_key_encryption),
+ NUTAG_SMIME_MESSAGE_ENCRYPTION(nua->sm->sm_message_encryption),
+#endif
+
+ NTATAG_UDP_MTU(udp_mtu),
+ NTATAG_SIP_T1(sip_t1),
+ NTATAG_SIP_T2(sip_t2),
+ NTATAG_SIP_T4(sip_t4),
+ NTATAG_SIP_T1X64(sip_t1x64),
+ NTATAG_DEBUG_DROP_PROB(debug_drop_prob),
+ NTATAG_DEFAULT_PROXY(proxy),
+ NTATAG_ALIASES(aliases),
+ NTATAG_SIPFLAGS(flags),
+
+ TAG_NEXT(media_params));
+
+ nua_stack_event(nua, nh, NULL, nua_r_get_params, SIP_200_OK, TAG_NEXT(lst));
+
+ su_home_deinit(tmphome);
+
+ tl_vfree(media_params);
+
+ return 0;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,226 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef NUA_PARAMS_H
+/** Defined when <nua_params.h> has been included. */
+#define NUA_PARAMS_H
+
+/**@internal @file nua_params.h
+ * @brief Parameters and their handling
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Kai Vehmanen <Kai.Vehmanen at nokia.com>
+ *
+ * @date Created: Wed Mar 8 11:38:18 EET 2006 ppessi
+ */
+
+/** NUA preferences.
+ *
+ * This structure contains values for various preferences and a separate
+ * bitmap (nhp_set) for each preference. Preferences are set using
+ * nua_set_params() or nua_set_hparams() or a handle-specific operation
+ * setting the preferences, including nua_invite(), nua_respond(),
+ * nua_ack(), nua_prack(), nua_update(), nua_info(), nua_bye(),
+ * nua_options(), nua_message(), nua_register(), nua_publish(), nua_refer(),
+ * nua_subscribe(), nua_notify(), nua_refer(), and nua_notifier().
+ *
+ * The stack uses preference value if corresponding bit in bitmap is set,
+ * otherwise it uses preference value from default handle.
+ *
+ * @see NHP_GET(), NH_PGET(), NHP_ISSET(), NH_PISSET()
+ */
+typedef struct nua_handle_preferences
+{
+ unsigned nhp_retry_count; /**< times to retry a request */
+ unsigned nhp_max_subscriptions;
+
+ /* Session-related preferences */
+ char const *nhp_soa_name;
+ unsigned nhp_media_enable:1;
+ unsigned nhp_invite_enable:1;
+ unsigned nhp_auto_alert:1;
+ unsigned nhp_early_answer:1; /**< Include answer in 1XX */
+ unsigned nhp_early_media:1; /**< Establish early media with 100rel */
+ unsigned nhp_only183_100rel:1;/**< Only 100rel 183. */
+ unsigned nhp_auto_answer:1;
+ unsigned nhp_auto_ack:1; /**< Automatically ACK a final response */
+ unsigned :0;
+
+ /** INVITE timeout.
+ *
+ * If no response is received in nhp_invite_timeout seconds,
+ * INVITE client transaction times out
+ */
+ unsigned nhp_invite_timeout;
+ /** Default session timer (in seconds, 0 disables) */
+ unsigned nhp_session_timer;
+ /** Default Min-SE Delta value */
+ unsigned nhp_min_se;
+ /** no (preference), local or remote */
+ enum nua_session_refresher nhp_refresher;
+ unsigned nhp_update_refresh:1; /**< Use UPDATE to refresh */
+
+ /* Messaging preferences */
+ unsigned nhp_message_enable : 1;
+ /** Be bug-compatible with Windows Messenger */
+ unsigned nhp_win_messenger_enable : 1;
+ /** PIM-IW hack */
+ unsigned nhp_message_auto_respond : 1;
+
+ /* Preferences for registration (and dialog establishment) */
+ unsigned nhp_callee_caps:1; /**< Add callee caps to contact */
+ unsigned nhp_media_features:1;/**< Add media features to caps*/
+ /** Enable Service-Route */
+ unsigned nhp_service_route_enable:1;
+ /** Enable Path */
+ unsigned nhp_path_enable:1;
+ /** Always include id with Event: refer */
+ unsigned nhp_refer_with_id:1;
+
+ unsigned:0;
+
+ /* Default lifetime for implicit subscriptions created by REFER */
+ unsigned nhp_refer_expires;
+
+ /* Subscriber state, i.e. nua_substate_pending */
+ unsigned nhp_substate;
+
+ /* REGISTER Keepalive intervals */
+ unsigned nhp_keepalive, nhp_keepalive_stream;
+ char const *nhp_registrar;
+
+ sip_allow_t *nhp_allow;
+ sip_supported_t *nhp_supported;
+ sip_allow_events_t *nhp_allow_events;
+ char const *nhp_user_agent;
+ char const *nhp_organization;
+
+ char const *nhp_m_display;
+ char const *nhp_m_username;
+ char const *nhp_m_params;
+ char const *nhp_m_features;
+ char const *nhp_instance;
+
+ /**< Outbound OPTIONS */
+ char const *nhp_outbound;
+
+ /**< Network detection: NONE, INFORMAL, TRY_FULL */
+ int nhp_detect_network_updates;
+
+ sip_allow_t *nhp_appl_method;
+
+ union { struct {
+ /* A bit for each feature set by application */
+ unsigned nhb_retry_count:1;
+ unsigned nhb_max_subscriptions:1;
+
+ unsigned nhb_soa_name:1;
+ unsigned nhb_media_enable:1;
+ unsigned nhb_invite_enable:1;
+ unsigned nhb_auto_alert:1;
+ unsigned nhb_early_answer:1;
+ unsigned nhb_early_media:1;
+ unsigned nhb_only183_100rel:1;
+ unsigned nhb_auto_answer:1;
+ unsigned nhb_auto_ack:1;
+ unsigned nhb_invite_timeout:1;
+
+ unsigned nhb_session_timer:1;
+ unsigned nhb_min_se:1;
+ unsigned nhb_refresher:1;
+ unsigned nhb_update_refresh:1;
+ unsigned nhb_message_enable:1;
+ unsigned nhb_win_messenger_enable:1;
+ unsigned nhb_message_auto_respond:1;
+ unsigned nhb_callee_caps:1;
+ unsigned nhb_media_features:1;
+ unsigned nhb_service_route_enable:1;
+ unsigned nhb_path_enable:1;
+ unsigned nhb_refer_with_id:1;
+ unsigned nhb_refer_expires:1;
+ unsigned nhb_substate:1;
+ unsigned nhb_keepalive:1;
+ unsigned nhb_keepalive_stream:1;
+ unsigned nhb_registrar:1;
+
+ unsigned nhb_allow:1;
+ unsigned nhb_supported:1;
+ unsigned nhb_allow_events:1;
+ unsigned :0; /* at most 32 bits ... */
+ unsigned nhb_user_agent:1;
+ unsigned nhb_organization:1;
+
+ unsigned nhb_m_display:1;
+ unsigned nhb_m_username:1;
+ unsigned nhb_m_params:1;
+ unsigned nhb_m_features:1;
+ unsigned nhb_instance:1;
+ unsigned nhb_outbound:1;
+ unsigned nhb_detect_network_updates:1;
+ unsigned nhb_appl_method:1;
+ unsigned :0;
+ } set_bits;
+ unsigned set_unsigned[2];
+ } nhp_set_;
+} nua_handle_preferences_t;
+
+#define nhp_set nhp_set_.set_bits
+
+#define DNHP_GET(dnhp, pref) ((dnhp)->nhp_##pref)
+
+#define NHP_GET(nhp, dnhp, pref) \
+ ((nhp)->nhp_set.nhb_##pref \
+ ? (nhp)->nhp_##pref : (dnhp)->nhp_##pref)
+
+#define NHP_SET(nhp, pref, value) \
+ ((nhp)->nhp_##pref = (value), \
+ (nhp)->nhp_set.nhb_##pref = 1)
+
+/* Check if preference is set */
+#define NHP_ISSET(nhp, pref) \
+ ((nhp)->nhp_set.nhb_##pref)
+
+#define NHP_UNSET_ALL(nhp) (memset(&(nhp)->nhp_set, 0, sizeof (nhp)->nhp_set))
+#define NHP_SET_ALL(nhp) (memset(&(nhp)->nhp_set, 255, sizeof (nhp)->nhp_set))
+
+/* Get preference from handle, if set, otherwise from default handle */
+#define NH_PGET(nh, pref) \
+ NHP_GET((nh)->nh_prefs, (nh)->nh_nua->nua_dhandle->nh_prefs, pref)
+
+/* Get preference from handle, if exists and set,
+ otherwise from default handle */
+#define NUA_PGET(nua, nh, pref) \
+ NHP_GET((nh) ? (nh)->nh_prefs : (nua)->nua_dhandle->nh_prefs, \
+ (nua)->nua_dhandle->nh_prefs, \
+ pref)
+
+/* Get preference from default handle */
+#define DNH_PGET(dnh, pref) \
+ DNHP_GET((dnh)->nh_prefs, pref)
+/* Check if preference is set in the handle */
+#define NH_PISSET(nh, pref) \
+ (NHP_ISSET((nh)->nh_prefs, pref) && \
+ (nh)->nh_nua->nua_dhandle->nh_prefs != (nh)->nh_prefs)
+
+#endif /* NUA_PARAMS_H */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_publish.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_publish.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,528 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nua_publish.c
+ * @brief PUBLISH and publications
+ *
+ * @sa @RFC3903
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Mar 8 17:01:32 EET 2006 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include <assert.h>
+
+#include <sofia-sip/string0.h>
+#include <sofia-sip/sip_protos.h>
+#include <sofia-sip/sip_status.h>
+
+#define NTA_LEG_MAGIC_T struct nua_handle_s
+#define NTA_OUTGOING_MAGIC_T struct nua_handle_s
+
+#include "nua_stack.h"
+
+/* ====================================================================== */
+/* Publish usage */
+
+struct publish_usage {
+ sip_etag_t *pu_etag;
+};
+
+static char const *nua_publish_usage_name(nua_dialog_usage_t const *du);
+static int nua_publish_usage_add(nua_handle_t *nh,
+ nua_dialog_state_t *ds,
+ nua_dialog_usage_t *du);
+static void nua_publish_usage_remove(nua_handle_t *nh,
+ nua_dialog_state_t *ds,
+ nua_dialog_usage_t *du);
+static void nua_publish_usage_refresh(nua_handle_t *nh,
+ nua_dialog_state_t *ds,
+ nua_dialog_usage_t *du,
+ sip_time_t now);
+static int nua_publish_usage_shutdown(nua_handle_t *nh,
+ nua_dialog_state_t *ds,
+ nua_dialog_usage_t *du);
+
+static nua_usage_class const nua_publish_usage[1] = {
+ {
+ sizeof (struct publish_usage),
+ sizeof nua_publish_usage,
+ nua_publish_usage_add,
+ nua_publish_usage_remove,
+ nua_publish_usage_name,
+ NULL,
+ nua_publish_usage_refresh,
+ nua_publish_usage_shutdown,
+ }};
+
+static
+char const *nua_publish_usage_name(nua_dialog_usage_t const *du)
+{
+ return "publish";
+}
+
+static
+int nua_publish_usage_add(nua_handle_t *nh,
+ nua_dialog_state_t *ds,
+ nua_dialog_usage_t *du)
+{
+ if (ds->ds_has_publish)
+ return -1; /* There can be only one */
+ ds->ds_has_publish = 1;
+ return 0;
+}
+
+static
+void nua_publish_usage_remove(nua_handle_t *nh,
+ nua_dialog_state_t *ds,
+ nua_dialog_usage_t *du)
+{
+ struct publish_usage *pu = nua_dialog_usage_private(du);
+
+ su_free(nh->nh_home, pu->pu_etag);
+
+ ds->ds_has_publish = 0; /* There can be only one */
+}
+
+/* ======================================================================== */
+/* PUBLISH */
+
+static int nua_stack_publish2(nua_t *nua, nua_handle_t *nh, nua_event_t e,
+ int refresh, tagi_t const *tags);
+
+static int process_response_to_publish(nua_handle_t *nh,
+ nta_outgoing_t *orq,
+ sip_t const *sip);
+
+
+/**@fn \
+ * void nua_publish(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
+ *
+ * Send PUBLISH request to publication server.
+ *
+ * Request status will be delivered to the application using #nua_r_publish
+ * event. When successful the publication will be updated periodically until
+ * nua_unpublish() is called or handle is destroyed. Note that the periodic
+ * updates and unpublish do not include the original message body nor the @b
+ * Content-Type header. Instead, the periodic update will include the
+ * @SIPIfMatch header, which was generated from the latest @SIPETag
+ * header received in response to @b PUBLISH request.
+ *
+ * The handle used for publication cannot be used for any other purposes.
+ *
+ * @param nh Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return
+ * nothing
+ *
+ * @par Related Tags:
+ * NUTAG_URL() \n
+ * Tags of nua_set_hparams() \n
+ * Tags in <sip_tag.h>
+ *
+ * @par Events:
+ * #nua_r_publish
+ *
+ * @sa #nua_r_publish, @RFC3903, @SIPIfMatch,
+ * nua_unpublish(), #nua_r_unpublish, #nua_i_publish
+ */
+
+/** @NUA_EVENT nua_r_publish
+ *
+ * Response to an outgoing PUBLISH.
+ *
+ * The PUBLISH request may be sent explicitly by nua_publish() or implicitly
+ * by NUA state machine.
+ *
+ * @param status status code of PUBLISH request
+ * (if the request is retried, @a status is 100, the @a
+ * sip->sip_status->st_status contain the real status code
+ * from the response message, e.g., 302, 401, or 407)
+ * @param phrase a short textual description of @a status code
+ * @param nh operation handle associated with the publication
+ * @param hmagic application context associated with the handle
+ * @param sip response to PUBLISH request or NULL upon an error
+ * (status code is in @a status and
+ * descriptive message in @a phrase parameters)
+ * @param tags empty
+ *
+ * @sa nua_publish(), @RFC3903, @SIPETag, @Expires,
+ * nua_unpublish(), #nua_r_unpublish, #nua_i_publish
+ *
+ * @END_NUA_EVENT
+ */
+
+/**@fn \
+void nua_unpublish(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
+ *
+ * Send un-PUBLISH request to publication server. Un-PUBLISH request is just
+ * a PUBLISH request with @Expires set to 0. It is possible to un-publish a
+ * publication not associated with the handle by providing correct ETag in
+ * SIPTAG_IF_MATCH() or SIPTAG_IF_MATCH_STR() tags.
+ *
+ * Response to the un-PUBLISH request will be delivered to the application
+ * using #nua_r_unpublish event.
+ *
+ * The handle used for publication cannot be used for any other purposes.
+ *
+ * @param nh Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return
+ * nothing
+ *
+ * @par Related Tags:
+ * NUTAG_URL() \n
+ * SIPTAG_IF_MATCH(), SIPTAG_IF_MATCH_STR() \n
+ * SIPTAG_EVENT(), SIPTAG_EVENT_STR() \n
+ * Tags of nua_set_hparams() \n
+ * Tags in <sip_tag.h>
+ *
+ * @par Events:
+ * #nua_r_unpublish
+ *
+ * @sa #nua_r_unpublish, @RFC3903, @SIPIfMatch,
+ * #nua_i_publish, nua_publish(), #nua_r_publish
+ */
+
+/** @NUA_EVENT nua_r_unpublish
+ *
+ * Response to an outgoing un-PUBLISH.
+ *
+ * @param status response status code
+ * (if the request is retried, @a status is 100, the @a
+ * sip->sip_status->st_status contain the real status code
+ * from the response message, e.g., 302, 401, or 407)
+ * @param phrase a short textual description of @a status code
+ * @param nh operation handle associated with the publication
+ * @param hmagic application context associated with the handle
+ * @param sip response to PUBLISH request or NULL upon an error
+ * (status code is in @a status and
+ * descriptive message in @a phrase parameters)
+ * @param tags empty
+ *
+ * @sa nua_unpublish(), @RFC3903, @SIPETag, @Expires,
+ * nua_publish(), #nua_r_publish, #nua_i_publish
+ *
+ * @END_NUA_EVENT
+ */
+
+int nua_stack_publish(nua_t *nua, nua_handle_t *nh, nua_event_t e,
+ tagi_t const *tags)
+{
+ return nua_stack_publish2(nua, nh, e, 0, tags);
+}
+
+static
+int nua_stack_publish2(nua_t *nua, nua_handle_t *nh, nua_event_t e,
+ int refresh,
+ tagi_t const *tags)
+{
+ nua_dialog_usage_t *du;
+ struct publish_usage *pu;
+ nua_client_request_t *cr = nh->nh_ds->ds_cr;
+ msg_t *msg = NULL;
+ sip_t *sip;
+ int remove_body = 0;
+
+ if (nua_stack_set_handle_special(nh, nh_has_nothing, nua_r_publish) < 0)
+ return UA_EVENT2(e, 900, "Invalid handle for PUBLISH");
+
+ if (cr->cr_orq) {
+ return UA_EVENT2(e, 900, "Request already in progress");
+ }
+
+ nua_stack_init_handle(nua, nh, TAG_NEXT(tags));
+
+ if (e == nua_r_unpublish) {
+ du = nua_dialog_usage_get(nh->nh_ds, nua_publish_usage, NULL);
+ if (du)
+ refresh = 1;
+ else
+ du = nua_dialog_usage_add(nh, nh->nh_ds, nua_publish_usage, NULL);
+ }
+ else if (!refresh)
+ du = nua_dialog_usage_add(nh, nh->nh_ds, nua_publish_usage, NULL);
+ else
+ du = nua_dialog_usage_get(nh->nh_ds, nua_publish_usage, NULL);
+
+ if (!du)
+ return UA_EVENT1(e, NUA_INTERNAL_ERROR);
+
+ nua_dialog_usage_reset_refresh(du);
+ pu = nua_dialog_usage_private(du); assert(pu);
+
+ if (refresh) {
+ if (cr->cr_msg)
+ msg_destroy(cr->cr_msg);
+ cr->cr_msg = msg_copy(du->du_msg);
+ remove_body = pu->pu_etag != NULL;
+ }
+
+ msg = nua_creq_msg(nua, nh, cr, cr->cr_retry_count || refresh,
+ SIP_METHOD_PUBLISH,
+ NUTAG_ADD_CONTACT(0),
+ TAG_NEXT(tags));
+ sip = sip_object(msg);
+
+ if (!msg || !sip)
+ goto error;
+
+ du->du_terminating =
+ e != nua_r_publish ||
+ (sip->sip_expires && sip->sip_expires->ex_delta == 0);
+
+ if (!du->du_terminating && !refresh) {
+ /* Save template */
+ if (du->du_msg)
+ msg_destroy(du->du_msg);
+ du->du_msg = msg_ref_create(cr->cr_msg);
+ }
+
+ cr->cr_orq =
+ nta_outgoing_mcreate(nua->nua_nta,
+ process_response_to_publish, nh, NULL,
+ msg,
+ SIPTAG_IF_MATCH(pu->pu_etag),
+ TAG_IF(remove_body, SIPTAG_PAYLOAD(NONE)),
+ TAG_IF(remove_body, SIPTAG_CONTENT_TYPE(NONE)),
+ TAG_IF(e != nua_r_publish,
+ SIPTAG_EXPIRES_STR("0")),
+ SIPTAG_END(), TAG_NEXT(tags));
+ if (!cr->cr_orq)
+ goto error;
+
+ cr->cr_usage = du;
+
+ return cr->cr_event = e;
+
+ error:
+ msg_destroy(msg);
+ if (!du->du_ready == 0)
+ nua_dialog_usage_remove(nh, nh->nh_ds, du);
+ return UA_EVENT1(e, NUA_INTERNAL_ERROR);
+}
+
+
+static void
+restart_publish(nua_handle_t *nh, tagi_t *tags)
+{
+ nua_creq_restart(nh, nh->nh_ds->ds_cr, process_response_to_publish, tags);
+}
+
+
+static
+int process_response_to_publish(nua_handle_t *nh,
+ nta_outgoing_t *orq,
+ sip_t const *sip)
+{
+ int status = sip->sip_status->st_status;
+ nua_client_request_t *cr = nh->nh_ds->ds_cr;
+ nua_dialog_usage_t *du = cr->cr_usage;
+ struct publish_usage *pu = nua_dialog_usage_private(du);
+ unsigned saved_retry_count = cr->cr_retry_count + 1;
+
+ if (nua_creq_check_restart(nh, cr, orq, sip, restart_publish))
+ return 0;
+
+ if (status < 200 || pu == NULL)
+ return nua_stack_process_response(nh, cr, orq, sip, TAG_END());
+
+ if (pu->pu_etag)
+ su_free(nh->nh_home, pu->pu_etag), pu->pu_etag = NULL;
+
+ if (!du->du_terminating) {
+ int retry = 0, invalid_expiration = 0;
+
+ if (status < 300) {
+ if (!sip->sip_expires)
+ invalid_expiration = 1;
+ else if (sip->sip_expires->ex_delta == 0)
+ retry = 1, invalid_expiration = 1;
+ }
+ else if (status == 412)
+ retry = 1;
+
+ if (status < 300 && !invalid_expiration && !retry) {
+ pu->pu_etag = sip_etag_dup(nh->nh_home, sip->sip_etag);
+ du->du_ready = 1;
+ nua_dialog_usage_set_expires(du, sip->sip_expires->ex_delta);
+ }
+ else if (retry && saved_retry_count < NH_PGET(nh, retry_count)) {
+ msg_t *response = nta_outgoing_getresponse(orq);
+ nua_stack_event(nh->nh_nua, nh, response, cr->cr_event,
+ 100, "Trying re-PUBLISH",
+ TAG_END());
+ nua_creq_deinit(cr, orq);
+ nua_stack_publish2(nh->nh_nua, nh, cr->cr_event, 1, NULL);
+ cr->cr_retry_count = saved_retry_count;
+ return 0;
+ }
+ else if (invalid_expiration) {
+ msg_t *response = nta_outgoing_getresponse(orq);
+ nua_stack_event(nh->nh_nua, nh, response, cr->cr_event,
+ 900, "Received Invalid Expiration Time",
+ TAG_END());
+ nua_dialog_usage_remove(nh, nh->nh_ds, cr->cr_usage);
+ nua_creq_deinit(cr, orq);
+ cr->cr_usage = NULL;
+ return 0;
+ }
+ }
+
+ return nua_stack_process_response(nh, cr, orq, sip, TAG_END());
+}
+
+
+static void nua_publish_usage_refresh(nua_handle_t *nh,
+ nua_dialog_state_t *ds,
+ nua_dialog_usage_t *du,
+ sip_time_t now)
+{
+ if (ds->ds_cr->cr_usage == du) /* Already publishing. */
+ return;
+ nua_stack_publish2(nh->nh_nua, nh, nua_r_publish, 1, NULL);
+}
+
+/** @interal Shut down PUBLISH usage.
+ *
+ * @retval >0 shutdown done
+ * @retval 0 shutdown in progress
+ * @retval <0 try again later
+ */
+static int nua_publish_usage_shutdown(nua_handle_t *nh,
+ nua_dialog_state_t *ds,
+ nua_dialog_usage_t *du)
+{
+ nua_client_request_t *cr = ds->ds_cr;
+
+ if (!cr->cr_usage) {
+ /* Unpublish */
+ nua_stack_publish2(nh->nh_nua, nh, nua_r_destroy, 1, NULL);
+ return cr->cr_usage != du;
+ }
+
+ if (!du->du_ready && !cr->cr_orq)
+ return 1; /* had unauthenticated initial request */
+
+ return -1; /* Request in progress */
+}
+
+/* ---------------------------------------------------------------------- */
+/* Server side */
+
+static
+int respond_to_publish(nua_server_request_t *sr, tagi_t const *tags);
+
+/** @NUA_EVENT nua_i_publish
+ *
+ * Incoming PUBLISH request.
+ *
+ * In order to receive #nua_i_publish events, the application must enable
+ * both the PUBLISH method with NUTAG_ALLOW() tag and the acceptable SIP
+ * events with nua_set_params() tag NUTAG_ALLOW_EVENTS().
+ *
+ * The nua_response() call responding to a PUBLISH request must have
+ * NUTAG_WITH() (or NUTAG_WITH_CURRENT()/NUTAG_WITH_SAVED()) tag. Note that
+ * a successful response to PUBLISH @b MUST include @Expires and @SIPETag
+ * headers.
+ *
+ * The PUBLISH request does not create a dialog. Currently the processing
+ * of incoming PUBLISH creates a new handle for each incoming request which
+ * is not assiciated with an existing dialog. If the handle @a nh is not
+ * bound, you should probably destroy it after responding to the PUBLISH
+ * request.
+ *
+ * @param status status code of response sent automatically by stack
+ * @param phrase a short textual description of @a status code
+ * @param nh operation handle associated with the incoming request
+ * @param hmagic application context associated with the call
+ * (usually NULL)
+ * @param sip incoming PUBLISH request
+ * @param tags empty
+ *
+ * @sa @RFC3903, nua_respond(),
+ * @Expires, @SIPETag, @SIPIfMatch, @Event,
+ * nua_subscribe(), #nua_i_subscribe,
+ * nua_notifier(), #nua_i_subscription,
+ *
+ * @since First used in @VERSION_1_12_4
+ *
+ * @END_NUA_EVENT
+ */
+
+int nua_stack_process_publish(nua_t *nua,
+ nua_handle_t *nh,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ nua_server_request_t *sr, sr0[1];
+ sip_allow_events_t *allow_events = NUA_PGET(nua, nh, allow_events);
+ sip_event_t *o = sip->sip_event;
+ char const *event = o ? o->o_type : NULL;
+
+ sr = SR_INIT(sr0);
+
+ if (!allow_events)
+ SR_STATUS1(sr, SIP_501_NOT_IMPLEMENTED);
+ else if (!event || !msg_header_find_param(allow_events->k_common, event))
+ SR_STATUS1(sr, SIP_489_BAD_EVENT);
+
+ sr = nua_server_request(nua, nh, irq, sip, sr, sizeof *sr,
+ respond_to_publish, 0);
+
+ return nua_stack_server_event(nua, sr, nua_i_publish, TAG_END());
+}
+
+static
+int respond_to_publish(nua_server_request_t *sr, tagi_t const *tags)
+{
+ nua_handle_t *nh = sr->sr_owner;
+ nua_t *nua = nh->nh_nua;
+ msg_t *msg;
+
+ msg = nua_server_response(sr, sr->sr_status, sr->sr_phrase, TAG_NEXT(tags));
+
+ if (msg) {
+ nta_incoming_mreply(sr->sr_irq, msg);
+ }
+ else {
+ SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR);
+ nta_incoming_treply(sr->sr_irq, sr->sr_status, sr->sr_phrase, TAG_END());
+ nua_stack_event(nua, nh, NULL,
+ nua_i_error, 900, "PUBLISH Response Fails",
+ TAG_END());
+ }
+
+ return sr->sr_status >= 200 ? sr->sr_status : 0;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_register.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_register.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1972 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nua_register.c
+ * @brief REGISTER and registrations
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ *
+ * @date Created: Wed Mar 8 11:48:49 EET 2006 ppessi
+ */
+
+#include "config.h"
+
+/** @internal SU network changed detector argument pointer type */
+#define SU_NETWORK_CHANGED_MAGIC_T struct nua_s
+
+#include <sofia-sip/string0.h>
+#include <sofia-sip/su_strlst.h>
+#include <sofia-sip/su_uniqueid.h>
+#include <sofia-sip/su_tagarg.h>
+
+#include <sofia-sip/sip_protos.h>
+#include <sofia-sip/sip_util.h>
+#include <sofia-sip/sip_status.h>
+
+#define NTA_LEG_MAGIC_T struct nua_handle_s
+#define NTA_OUTGOING_MAGIC_T struct nua_handle_s
+#define NTA_UPDATE_MAGIC_T struct nua_s
+
+#include "nua_stack.h"
+
+#include <sofia-sip/hostdomain.h>
+#include <sofia-sip/nta_tport.h>
+#include <sofia-sip/tport.h>
+#include <sofia-sip/tport_tag.h>
+
+#define OUTBOUND_OWNER_T struct nua_handle_s
+
+#include "outbound.h"
+
+#if HAVE_SIGCOMP
+#include <sigcomp.h>
+#endif
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include <assert.h>
+
+/* ======================================================================== */
+/* Registrations and contacts */
+
+int nua_registration_from_via(nua_registration_t **list,
+ nua_handle_t *nh,
+ sip_via_t const *via,
+ int public);
+
+int nua_registration_add(nua_registration_t **list, nua_registration_t *nr);
+
+void nua_registration_remove(nua_registration_t *nr);
+
+int nua_registration_set_aor(su_home_t *, nua_registration_t *nr,
+ sip_from_t const *aor);
+
+int nua_registration_set_contact(nua_handle_t *,
+ nua_registration_t *nr,
+ sip_contact_t const *m,
+ int terminating);
+
+void nua_registration_set_ready(nua_registration_t *nr, int ready);
+
+/* ====================================================================== */
+/* REGISTER usage */
+
+static char const *nua_register_usage_name(nua_dialog_usage_t const *du);
+
+static int nua_register_usage_add(nua_handle_t *nh,
+ nua_dialog_state_t *ds,
+ nua_dialog_usage_t *du);
+static void nua_register_usage_remove(nua_handle_t *nh,
+ nua_dialog_state_t *ds,
+ nua_dialog_usage_t *du);
+static void nua_register_usage_peer_info(nua_dialog_usage_t *du,
+ nua_dialog_state_t const *ds,
+ sip_t const *sip);
+static void nua_register_usage_refresh(nua_handle_t *,
+ nua_dialog_state_t *,
+ nua_dialog_usage_t *,
+ sip_time_t);
+static int nua_register_usage_shutdown(nua_handle_t *,
+ nua_dialog_state_t *,
+ nua_dialog_usage_t *);
+
+/** REGISTER usage, aka nua_registration_t */
+struct register_usage {
+ nua_registration_t *nr_next, **nr_prev, **nr_list; /* Doubly linked list and its head */
+ sip_from_t *nr_aor; /**< AoR for this registration, NULL if none */
+ sip_contact_t *nr_contact; /**< Our Contact */
+ sip_via_t *nr_via; /**< Corresponding Via headers */
+
+ /** Status of registration */
+ unsigned nr_ready:1;
+ /** Kind of registration.
+ *
+ * If nr_default is true, this is not a real registration but placeholder
+ * for Contact header derived from a transport address.
+ *
+ * If nr_secure is true, this registration supports SIPS/TLS.
+ *
+ * If nr_public is true, transport should have public address.
+ */
+ unsigned nr_default:1, nr_secure:1, nr_public:1, nr_ip4:1, nr_ip6:1;
+
+ /** Stack-generated contact */
+ unsigned nr_by_stack:1, :0;
+
+ sip_route_t *nr_route; /**< Outgoing Service-Route */
+ sip_path_t *nr_path; /**< Incoming Path */
+
+ tport_t *nr_tport; /**< Transport to be used when registered */
+ nua_dialog_state_t *nr_dialogs; /**< List of our dialogs */
+
+#if HAVE_SIGCOMP
+ struct sigcomp_compartment *nr_compartment;
+#endif
+
+ outbound_t *nr_ob; /**< Outbound connection */
+};
+
+nua_usage_class const nua_register_usage[1] = {
+ {
+ sizeof (struct register_usage),
+ (sizeof nua_register_usage),
+ nua_register_usage_add,
+ nua_register_usage_remove,
+ nua_register_usage_name,
+ nua_register_usage_peer_info,
+ nua_register_usage_refresh,
+ nua_register_usage_shutdown
+ }};
+
+static char const *nua_register_usage_name(nua_dialog_usage_t const *du)
+{
+ return "register";
+}
+
+static int nua_register_usage_add(nua_handle_t *nh,
+ nua_dialog_state_t *ds,
+ nua_dialog_usage_t *du)
+{
+ nua_registration_t *nr = nua_dialog_usage_private(du);
+
+ if (ds->ds_has_register)
+ return -1; /* There can be only one usage */
+
+ ds->ds_has_register = 1;
+
+ nr->nr_public = 1; /* */
+
+ return 0;
+}
+
+
+static void nua_register_usage_remove(nua_handle_t *nh,
+ nua_dialog_state_t *ds,
+ nua_dialog_usage_t *du)
+{
+ nua_registration_t *nr = nua_dialog_usage_private(du);
+
+ if (nr->nr_list)
+ nua_registration_remove(nr); /* Remove from list of registrations */
+
+ if (nr->nr_ob)
+ outbound_unref(nr->nr_ob);
+
+#if HAVE_SIGCOMP
+ if (nr->nr_compartment)
+ sigcomp_compartment_unref(nr->nr_compartment);
+ nr->nr_compartment = NULL;
+#endif
+
+ ds->ds_has_register = 0; /* There can be only one */
+}
+
+
+/** @internal Store information about registrar. */
+static void nua_register_usage_peer_info(nua_dialog_usage_t *du,
+ nua_dialog_state_t const *ds,
+ sip_t const *sip)
+{
+ nua_registration_t *nr = nua_dialog_usage_private(du);
+ if (nr->nr_ob)
+ outbound_peer_info(nr->nr_ob, sip);
+}
+
+/* ======================================================================== */
+/* REGISTER */
+
+static void restart_register(nua_handle_t *nh, tagi_t *tags);
+
+static int process_response_to_register(nua_handle_t *nh,
+ nta_outgoing_t *orq,
+ sip_t const *sip);
+
+static void unregister_expires_contacts(msg_t *msg, sip_t *sip);
+
+/* Interface towards outbound_t */
+sip_contact_t *nua_handle_contact_by_via(nua_handle_t *nh,
+ su_home_t *home,
+ char const *extra_username,
+ sip_via_t const *v,
+ char const *transport,
+ char const *m_param,
+ ...);
+
+static int nua_stack_outbound_features(nua_handle_t *nh, outbound_t *ob);
+
+static int nua_stack_outbound_refresh(nua_handle_t *,
+ outbound_t *ob);
+
+static int nua_stack_outbound_status(nua_handle_t *,
+ outbound_t *ob,
+ int status, char const *phrase,
+ tag_type_t tag, tag_value_t value, ...);
+
+static int nua_stack_outbound_failed(nua_handle_t *,
+ outbound_t *ob,
+ int status, char const *phrase,
+ tag_type_t tag, tag_value_t value, ...);
+
+static int nua_stack_outbound_credentials(nua_handle_t *, auth_client_t **auc);
+
+outbound_owner_vtable nua_stack_outbound_callbacks = {
+ sizeof nua_stack_outbound_callbacks,
+ nua_handle_contact_by_via,
+ nua_stack_outbound_refresh,
+ nua_stack_outbound_status,
+ nua_stack_outbound_failed,
+ nua_stack_outbound_failed,
+ nua_stack_outbound_credentials
+ };
+
+/**@fn void nua_register(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
+ *
+ * Send SIP REGISTER request to the registrar.
+ *
+ * Request status will be delivered to the application using #nua_r_register
+ * event. When successful the registration will be updated periodically.
+ *
+ * The handle used for registration cannot be used for any other purposes.
+ *
+ * @param nh Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return
+ * nothing
+ *
+ * @par Related tags:
+ * NUTAG_REGISTRAR(), NUTAG_INSTANCE(), NUTAG_OUTBOUND(),
+ * NUTAG_KEEPALIVE(), NUTAG_KEEPALIVE_STREAM(), NUTAG_M_USERNAME(),
+ * NUTAG_M_DISPLAY(), NUTAG_M_PARAMS(), NUTAG_M_FEATURES(),
+ *
+ * @par Events:
+ * #nua_r_register, #nua_i_outbound
+ *
+ * @par Generating Contact Header
+ *
+ * If the application did not specify the Contact header in the tags,
+ * nua_register() will generate one. It will obtain the schema, IP address
+ * for the host and port number for the Contact URI from the transport
+ * socket. The diplay name is taken from NUTAG_M_DISPLAY(), URL username
+ * part is taken from NUTAG_M_USERNAME(), URI parameters from
+ * NUTAG_M_PARAMS(), and Contact header parameters from NUTAG_M_FEATURES().
+ * If NUTAG_CALLEE_CAPS(1) is specified, additional Contact header
+ * parameters are generated based on SDP capabilities and SIP @Allow header.
+ *
+ * Note that @b nua may append a identifier of its own to the @Contact URI
+ * username. Such nua-generated identifier trailer always starts with "="
+ * (equal sign), rest of the nua-generated identifier may contain any
+ * url-unreserved characters except "=".
+ *
+ * Likewise, nua may add transport parameters (such as "transport=tcp" or
+ * "maddr") to the @Contact URI. It can add addtional header parameters, like
+ * "+sip.instance" or "reg-id", too.
+ *
+ * For instance, if application uses tags like
+ * @code
+ * nua_register(nh,
+ * NUTAG_M_DISPLAY("1"),
+ * NUTAG_M_USERNAME("line-1"),
+ * NUTAG_M_PARAMS("user=phone"),
+ * NUTAG_M_FEATURES("audio"),
+ * NUTAG_CALLEE_CAPS(0),
+ * TAG_END())
+ * @endcode
+ * @b nua can generate a Contact header like
+ * @code
+ * Contact: 1 <sip:line-1=SSQAIbjv at 192.168.1.200;transport=tcp;user=phone>
+ * ;audio;reg-id=1
+ * ;+sip.instance=urn:uuid:97701ad9-39df-1229-1083-dbc0a85f029c
+ * @endcode
+ *
+ * The incoming request from the proxy should contain the registered contact
+ * URI as the request URI. The application can use the username prefix set
+ * by NUTAG_M_USERNAME() and the non-transport parameters of the request URI
+ * set by NUTAG_M_PARAMS() when determining to which registration the
+ * incoming request belongs.
+ *
+ * For example, a request line correspoding to the @Contact in above example
+ * may look like:
+ * @code
+ * INVITE sip:line-1=SSQAIbjv at 192.168.1.200;user=phone SIP/2.0
+ * @endcode
+ *
+ * @sa NUTAG_M_DISPLAY(), NUTAG_M_USERNAME(), NUTAG_M_PARAMS(),
+ * NUTAG_M_FEATURES(), NUTAG_CALLEE_CAPS().
+ *
+ * @par NAT, Firewall and Outbound Support
+ *
+ * Normally, @b nua will start start a protocol engine for outbound
+ * connections used for NAT and firewall traversal and connectivity checks
+ * when registering.
+ *
+ * @note If the application provides @b nua with a
+ * @Contact header of its own (or includes a SIPTAG_CONTACT(NULL) tag in
+ * nua_register() tags), the outbound protocol engine is not started. It is
+ * assumed that the application knows better what it is doing when it sets
+ * the @Contact, or it is using experimental CPL upload as specified in
+ * <a href="http://www.ietf.org/internet-drafts/draft-lennox-sip-reg-payload-01.txt">
+ * draft-lennox-sip-reg-payload-01.txt</a>.
+ *
+ * First, outbound engine will probe for NATs in between UA and registrar.
+ * It will send a REGISTER request as usual. Upon receiving the response it
+ * checks for the presence of "received" and "rport" parameters in the Via
+ * header returned by registrar. The presence of NAT is determined from the
+ * "received" parameter in a Via header. When a REGISTER request was sent,
+ * the stack inserted the actual source IP address in the Via header: if
+ * that is different from the source IP address seen by the registrar, the
+ * registrar inserts the source IP address it sees into the "received"
+ * parameter.
+ *
+ * Please note that an ALG (application-level gateway) modifying the Via
+ * headers in outbound requests and again in incoming responses will make
+ * the above-described NAT check to fail.
+ *
+ * The response to the initial REGISTER should also include option tags
+ * indicating whether registrar supports various SIP extension options: @e
+ * outbound, @e pref, @e path, @e gruu.
+ *
+ * Basically, @e outbound means that instead of registering its contact URI
+ * with a particular address-of-record URI, the user-agent registers a
+ * transport-level connection. Such a connection is identified on the
+ * Contact header field with an instance identifier, application-provided
+ * @ref NUTAG_INSTANCE() "unique string" identifying the user-agent instance
+ * and a stack-generated numeric index identifying the transport-level
+ * connection.
+ *
+ * If the @e outbound extension is supported, NUTAG_OUTBOUND() contains
+ * option string "outbound" and the application has provided an instance
+ * identifer to the stack with NUTAG_INSTANCE(), the nua_register() will try
+ * to use outbound.
+ *
+ * If @e outbound is not supported, nua_register() has to generate a URI
+ * that can be used to reach it from outside. It will check for public
+ * transport addresses detected by underlying stack with, e.g., STUN, UPnP
+ * or SOCKS. If there are public addresses, nua_register() will use them. If
+ * there is no public address, it will try to generate a Contact URI from
+ * the "received" and "rport" parameters found in the Via header of the
+ * response message.
+ *
+ * @todo Actually generate public addresses.
+ *
+ * You can disable this kind of NAT traversal by setting "no-natify" into
+ * NUTAG_OUTBOUND() options string.
+ *
+ * @par GRUU and Service-Route
+ *
+ * After a successful response to the REGISTER request has been received,
+ * nua_register() will update the information about the registration based
+ * on it. If there is a "gruu" parameter included in the response,
+ * nua_register() will save it and use the gruu URI in the Contact header
+ * fields of dialog-establishing messages, such as INVITE or SUBSCRIBE.
+ * Also, if the registrar has included a Service-Route header in the
+ * response, and the service route feature has not been disabled using
+ * NUTAG_SERVICE_ROUTE_ENABLE(), the route URIs from the Service-Route
+ * header will be used for initial non-REGISTER requests.
+ *
+ * The #nua_r_register message will include the contact header and route
+ * used in with the registration.
+ *
+ * @par Registration Keep-Alive
+ *
+ * After the registration has successfully completed the nua_register() will
+ * validate the registration and initiate the keepalive mechanism, too. The
+ * user-agent validates the registration by sending a OPTIONS requests to
+ * itself. If there is an error, nua_register() will indicate that to the
+ * application using #nua_i_outbound event, and start unregistration
+ * procedure (unless that has been explicitly disabled).
+ *
+ * You can disable validation by inserting "no-validate" into
+ * NUTAG_OUTBOUND() string.
+ *
+ * The keepalive mechanism depends on the network features detected earlier.
+ * If @a outbound extension is used, the STUN keepalives will be used.
+ * Otherwise, NUA stack will repeatedly send OPTIONS requests to itself. In
+ * order to save bandwidth, it will include Max-Forwards: 0 in the
+ * keep-alive requests, however. The keepalive interval is determined by
+ * NUTAG_KEEPALIVE() parameter. If the interval is 0, no keepalive messages
+ * is sent.
+ *
+ * You can disable keepalive OPTIONS by inserting "no-options-keepalive"
+ * into NUTAG_OUTBOUND() string. Currently there are no other keepalive
+ * mechanisms available.
+ *
+ * The value of NUTAG_KEEPALIVE_STREAM(), if specified, is used to indicate
+ * the desired transport-layer keepalive interval for stream-based
+ * transports like TLS and TCP.
+ *
+ * @sa #nua_r_register, nua_unregister(), #nua_r_unregister,
+ * #nua_i_register,
+ * @RFC3261 section 10,
+ * @Expires, @Contact, @CallID, @CSeq,
+ * @Path, @RFC3327, @ServiceRoute, @RFC3608, @RFC3680,
+ * NUTAG_REGISTRAR(), NUTAG_INSTANCE(), NUTAG_OUTBOUND(),
+ * NUTAG_KEEPALIVE(), NUTAG_KEEPALIVE_STREAM(),
+ * SIPTAG_CONTACT(), SIPTAG_CONTACT_STR(), NUTAG_M_USERNAME(),
+ * NUTAG_M_DISPLAY(), NUTAG_M_PARAMS(), NUTAG_M_FEATURES(),
+ */
+
+/** @NUA_EVENT nua_r_register
+ *
+ * Response to an outgoing REGISTER.
+ *
+ * The REGISTER may be sent explicitly by nua_register() or implicitly by
+ * NUA state machines.
+ *
+ * When REGISTER request has been restarted the @a status may be 100 even
+ * while the real response status returned is different.
+ *
+ * @param status response status code
+ * (if the request is retried, @a status is 100, the @a
+ * sip->sip_status->st_status contain the real status code
+ * from the response message, e.g., 302, 401, or 407)
+ * @param phrase a short textual description of @a status code
+ * @param nh operation handle associated with the registration
+ * @param hmagic application context associated with the registration
+ * @param sip response message to REGISTER request or NULL upon an error
+ * (status code is in @a status and
+ * descriptive message in @a phrase parameters)
+ * @param tags empty
+ *
+ * @sa nua_register(), nua_unregister(), #nua_r_unregister,
+ * @Contact, @CallID, @CSeq, @RFC3261 section 10,
+ * @Path, @RFC3327, @ServiceRoute, @RFC3608, @RFC3680
+ *
+ * @END_NUA_EVENT
+ */
+
+/**@fn void nua_unregister(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
+ * Unregister.
+ *
+ * Send a REGISTER request with expiration time 0. This removes the
+ * registration from the registrar. If the handle was earlier used
+ * with nua_register() the periodic updates will be terminated.
+ *
+ * If a SIPTAG_CONTACT_STR() with argument "*" is used, all the
+ * registrations will be removed from the registrar otherwise only the
+ * contact address belonging to the NUA stack is removed.
+ *
+ * @param nh Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return
+ * nothing
+ *
+ * @par Related tags:
+ * NUTAG_REGISTRAR() \n
+ * Tags in <sip_tag.h> except SIPTAG_EXPIRES() or SIPTAG_EXPIRES_STR()
+ *
+ * @par Events:
+ * #nua_r_unregister
+ *
+ * @sa nua_register(), #nua_r_register, nua_handle_destroy(), nua_shutdown(),
+ * #nua_i_register,
+ * @Expires, @Contact, @CallID, @CSeq, @RFC3261 section 10,
+ * @Path, @RFC3327, @ServiceRoute, @RFC3608, @RFC3680,
+ * NUTAG_REGISTRAR(), NUTAG_INSTANCE(), NUTAG_OUTBOUND(),
+ * NUTAG_KEEPALIVE(), NUTAG_KEEPALIVE_STREAM(),
+ * SIPTAG_CONTACT(), SIPTAG_CONTACT_STR(), NUTAG_M_USERNAME(),
+ * NUTAG_M_DISPLAY(), NUTAG_M_PARAMS(), NUTAG_M_FEATURES(),
+ */
+
+/** @NUA_EVENT nua_r_unregister
+ *
+ * Answer to outgoing un-REGISTER.
+ *
+ * @param status response status code
+ * (if the request is retried, @a status is 100, the @a
+ * sip->sip_status->st_status contain the real status code
+ * from the response message, e.g., 302, 401, or 407)
+ * @param phrase a short textual description of @a status code
+ * @param nh operation handle associated with the registration
+ * @param hmagic application context associated with the registration
+ * @param sip response message to REGISTER request or NULL upon an error
+ * (status code is in @a status and
+ * descriptive message in @a phrase parameters)
+ * @param tags empty
+ *
+ * @sa nua_unregister(), nua_register(), #nua_r_register,
+ * @Contact, @CallID, @CSeq, @RFC3261 section 10,
+ * @Path, @RFC3327, @ServiceRoute, @RFC3608, @RFC3680
+ *
+ * @END_NUA_EVENT
+ */
+
+int
+nua_stack_register(nua_t *nua, nua_handle_t *nh, nua_event_t e,
+ tagi_t const *tags)
+{
+ nua_dialog_usage_t *du;
+ nua_registration_t *nr = NULL;
+ outbound_t *ob = NULL;
+ nua_client_request_t *cr = nh->nh_ds->ds_cr;
+ msg_t *msg = NULL;
+ sip_t *sip;
+ int terminating = e != nua_r_register;
+
+ if (nua_stack_set_handle_special(nh, nh_has_register, nua_r_register) < 0)
+ return UA_EVENT2(e, 900, "Invalid handle for REGISTER");
+ if (cr->cr_orq)
+ return UA_EVENT2(e, 900, "Request already in progress");
+
+ nua_stack_init_handle(nua, nh, TAG_NEXT(tags));
+
+ du = nua_dialog_usage_add(nh, nh->nh_ds, nua_register_usage, NULL);
+ if (!du)
+ return UA_EVENT1(e, NUA_INTERNAL_ERROR);
+ nr = nua_dialog_usage_private(du); assert(nr);
+ nua_registration_add(&nh->nh_nua->nua_registrations, nr);
+ if (!terminating && du->du_terminating)
+ return UA_EVENT2(e, 900, "Unregister in progress");
+
+ if (cr->cr_msg)
+ msg_destroy(cr->cr_msg), cr->cr_msg = NULL;
+ /* Use original message as template when unregistering */
+ if (terminating)
+ cr->cr_msg = msg_ref_create(du->du_msg);
+
+ msg = nua_creq_msg(nua, nh, cr, cr->cr_msg != NULL,
+ SIP_METHOD_REGISTER,
+ TAG_IF(!terminating, NUTAG_USE_DIALOG(1)),
+ TAG_NEXT(tags));
+ sip = sip_object(msg);
+ if (!msg || !sip)
+ goto error;
+
+ if (!nr->nr_aor) {
+ if (nua_registration_set_aor(nh->nh_home, nr, sip->sip_to) < 0)
+ goto error;
+ }
+
+ if (terminating)
+ /* Add Expires: 0 and remove the expire parameters from contacts */
+ unregister_expires_contacts(msg, sip);
+
+ if (!sip->sip_contact && cr->cr_has_contact) {
+ terminating = 1;
+ }
+ else if (nua_registration_set_contact(nh, nr, sip->sip_contact, terminating)
+ < 0)
+ goto error;
+
+ du->du_terminating = terminating;
+
+ if (du->du_msg == NULL && !terminating)
+ du->du_msg = msg_ref_create(cr->cr_msg); /* Save original message */
+
+ ob = nr->nr_ob;
+
+ if (!ob && (NH_PGET(nh, outbound) || NH_PGET(nh, instance))) {
+ nr->nr_ob = ob = outbound_new(nh, &nua_stack_outbound_callbacks,
+ nh->nh_nua->nua_root,
+ nh->nh_nua->nua_nta,
+ NH_PGET(nh, instance));
+ if (!ob)
+ goto error;
+ }
+
+ if (ob) {
+ outbound_set_options(ob,
+ NH_PGET(nh, outbound),
+ NH_PGET(nh, keepalive),
+ NH_PISSET(nh, keepalive_stream)
+ ? NH_PGET(nh, keepalive_stream)
+ : NH_PGET(nh, keepalive));
+ nua_stack_outbound_features(nh, ob);
+ outbound_stop_keepalive(ob);
+
+ if (outbound_set_contact(ob, sip->sip_contact, nr->nr_via, terminating) < 0)
+ goto error;
+ }
+
+ /* This calls nta_outgoing_mcreate() but adds a few tags */
+ cr->cr_orq =
+ outbound_register_request(ob, terminating,
+ nr->nr_by_stack ? nr->nr_contact : NULL,
+ nua->nua_nta,
+ process_response_to_register, nh, NULL,
+ msg,
+ SIPTAG_END(),
+ TAG_IF(terminating, NTATAG_SIGCOMP_CLOSE(1)),
+ TAG_IF(!terminating, NTATAG_COMP("sigcomp")),
+ TAG_NEXT(tags));
+
+ if (!cr->cr_orq)
+ goto error;
+
+ cr->cr_usage = du;
+ return cr->cr_event = e;
+
+ error:
+ msg_destroy(msg);
+ msg_destroy(cr->cr_msg), cr->cr_msg = NULL;
+ nua_dialog_usage_remove(nh, nh->nh_ds, du);
+ return UA_EVENT1(e, NUA_INTERNAL_ERROR);
+}
+
+static void
+restart_register(nua_handle_t *nh, tagi_t *tags)
+{
+ nua_client_request_t *cr = nh->nh_ds->ds_cr;
+ msg_t *msg;
+ nua_dialog_usage_t *du = cr->cr_usage;
+ nua_registration_t *nr = nua_dialog_usage_private(du);
+ int terminating = du && du->du_terminating;
+
+ cr->cr_restart = NULL;
+
+ if (!cr->cr_msg)
+ return;
+
+ msg = nua_creq_msg(nh->nh_nua, nh, cr, 1,
+ SIP_METHOD_UNKNOWN,
+ TAG_NEXT(tags));
+
+ if (!msg)
+ return; /* XXX - Uh-oh */
+
+ if (terminating)
+ unregister_expires_contacts(msg, sip_object(msg));
+
+ /* This calls nta_outgoing_mcreate() but adds a few tags */
+ cr->cr_orq =
+ outbound_register_request(nr->nr_ob, terminating,
+ nr->nr_by_stack ? nr->nr_contact : NULL,
+ nh->nh_nua->nua_nta,
+ process_response_to_register, nh, NULL,
+ msg,
+ SIPTAG_END(),
+ TAG_IF(terminating, NTATAG_SIGCOMP_CLOSE(1)),
+ TAG_IF(!terminating, NTATAG_COMP("sigcomp")),
+ TAG_NEXT(tags));
+
+ if (!cr->cr_orq)
+ msg_destroy(msg);
+}
+
+/** Refresh registration */
+static
+void nua_register_usage_refresh(nua_handle_t *nh,
+ nua_dialog_state_t *ds,
+ nua_dialog_usage_t *du,
+ sip_time_t now)
+{
+ nua_t *nua = nh->nh_nua;
+ nua_client_request_t *cr = nh->nh_ds->ds_cr;
+ nua_registration_t *nr = nua_dialog_usage_private(du);
+ msg_t *msg;
+ sip_t *sip;
+
+ if (du->du_terminating || du->du_shutdown)
+ return;
+
+ if (cr->cr_msg) {
+ /* Dialog is busy, delay of 5 .. 15 seconds */
+ nua_dialog_usage_refresh_range(du, 5, 15);
+ return;
+ }
+
+ outbound_stop_keepalive(nr->nr_ob);
+
+ cr->cr_msg = msg_copy(du->du_msg);
+ msg = nua_creq_msg(nua, nh, cr, 1,
+ SIP_METHOD_REGISTER,
+ NUTAG_USE_DIALOG(1),
+ TAG_END());
+ sip = sip_object(msg);
+ if (!msg || !sip)
+ goto error;
+
+ cr->cr_orq =
+ outbound_register_request(nr->nr_ob, 0,
+ nr->nr_by_stack ? nr->nr_contact : NULL,
+ nh->nh_nua->nua_nta,
+ process_response_to_register, nh, NULL,
+ msg,
+ SIPTAG_END(),
+ NTATAG_COMP("sigcomp"),
+ TAG_END());
+ if (!cr->cr_orq)
+ goto error;
+
+ cr->cr_usage = du;
+ cr->cr_event = nua_r_register;
+ return;
+
+ error:
+ msg_destroy(msg);
+ msg_destroy(cr->cr_msg);
+ UA_EVENT2(nua_r_register, NUA_INTERNAL_ERROR, TAG_END());
+ return;
+}
+
+/** Shutdown register usage.
+ *
+ * Called when stack is shut down or handle is destroyed. Unregister.
+ */
+static
+int nua_register_usage_shutdown(nua_handle_t *nh,
+ nua_dialog_state_t *ds,
+ nua_dialog_usage_t *du)
+{
+ nua_t *nua = nh->nh_nua;
+ nua_client_request_t *cr = nh->nh_ds->ds_cr;
+ nua_registration_t *nr = nua_dialog_usage_private(du);
+ msg_t *msg;
+ sip_t *sip;
+
+ if (du->du_terminating) /* Already terminating? */
+ return 100;
+
+ du->du_terminating = 1;
+
+ if (cr->cr_msg) /* Busy */
+ return 100;
+
+ outbound_stop_keepalive(nr->nr_ob);
+
+ cr->cr_msg = msg_copy(du->du_msg);
+ msg = nua_creq_msg(nua, nh, cr, 1,
+ SIP_METHOD_REGISTER,
+ NUTAG_USE_DIALOG(1),
+ TAG_END());
+ sip = sip_object(msg);
+ if (!msg || !sip)
+ goto error;
+
+ unregister_expires_contacts(msg, sip);
+
+ cr->cr_orq =
+ outbound_register_request(nr->nr_ob, 1,
+ nr->nr_by_stack ? nr->nr_contact : NULL,
+ nh->nh_nua->nua_nta,
+ process_response_to_register, nh, NULL,
+ msg,
+ SIPTAG_END(),
+ NTATAG_SIGCOMP_CLOSE(1),
+ TAG_END());
+ if (!cr->cr_orq)
+ goto error;
+
+ cr->cr_usage = du;
+ cr->cr_event = nua_r_destroy;
+ return 200;
+
+ error:
+ nua_dialog_usage_remove(nh, nh->nh_ds, du);
+ msg_destroy(msg);
+ msg_destroy(cr->cr_msg);
+ return 500;
+}
+
+
+static
+int process_response_to_register(nua_handle_t *nh,
+ nta_outgoing_t *orq,
+ sip_t const *sip)
+{
+ nua_client_request_t *cr = nh->nh_ds->ds_cr;
+ nua_dialog_usage_t *du = cr->cr_usage;
+ nua_registration_t *nr = nua_dialog_usage_private(du);
+ int status, ready, reregister, terminating;
+ char const *phrase;
+ msg_t *_reqmsg = nta_outgoing_getrequest(orq);
+ sip_t *req = sip_object(_reqmsg); msg_destroy(_reqmsg);
+
+ assert(sip);
+ assert(du && du->du_class == nua_register_usage);
+ status = sip->sip_status->st_status;
+ phrase = sip->sip_status->st_phrase;
+
+ if (status < 200 || !du)
+ return nua_stack_process_response(nh, cr, orq, sip, TAG_END());
+
+ terminating = du->du_terminating;
+ if (!terminating)
+ nua_dialog_store_peer_info(nh, nh->nh_ds, sip);
+
+ reregister = outbound_register_response(nr->nr_ob, terminating, req, sip);
+ if (reregister < 0)
+ SET_STATUS1(NUA_INTERNAL_ERROR);
+ else if (reregister >= ob_reregister) {
+ /* Save msg otherwise nua_creq_check_restart() will zap it */
+ msg_t *msg = msg_ref_create(cr->cr_msg);
+
+ if (nua_creq_check_restart(nh, cr, orq, sip, restart_register)) {
+ msg_destroy(msg);
+ return 0;
+ }
+
+ assert(cr->cr_msg == NULL);
+ cr->cr_msg = msg;
+
+ if (reregister >= ob_reregister_now) {
+ /* We can try to reregister immediately */
+ nua_creq_restart_with(nh, cr, orq, 100, "Updated Contact",
+ restart_register,
+ TAG_END());
+ }
+ else {
+ /* Outbound will invoke refresh_register() later */
+ nua_creq_save_restart(nh, cr, orq, 100, "Updated Contact",
+ restart_register);
+ }
+ return 0;
+ }
+
+ if (status >= 300)
+ if (nua_creq_check_restart(nh, cr, orq, sip, restart_register))
+ return 0;
+
+ ready = !terminating && status < 300;
+ du->du_ready = ready;
+
+ if (status < 300) {
+ if (!du->du_terminating) {
+ sip_time_t mindelta = 0;
+ sip_time_t now = sip_now(), delta, reqdelta;
+ sip_contact_t const *m, *sent;
+
+ /** Search for lowest delta of SIP contacts we tried to register */
+ mindelta = SIP_TIME_MAX;
+
+ reqdelta = req->sip_expires ? req->sip_expires->ex_delta : 0;
+
+ for (m = sip->sip_contact; m; m = m->m_next) {
+ if (m->m_url->url_type != url_sip &&
+ m->m_url->url_type != url_sips)
+ continue;
+ for (sent = req->sip_contact; sent; sent = sent->m_next)
+ if (url_cmp(m->m_url, sent->m_url) == 0) {
+ sip_time_t mdelta = reqdelta;
+
+ if (sent->m_expires)
+ mdelta = strtoul(sent->m_expires, NULL, 10);
+ if (mdelta == 0)
+ mdelta = 3600;
+
+ delta = sip_contact_expires(m, sip->sip_expires, sip->sip_date,
+ mdelta, now);
+ if (delta > 0 && delta < mindelta)
+ mindelta = delta;
+ if (url_cmp_all(m->m_url, sent->m_url) == 0)
+ break;
+ }
+ }
+
+ if (mindelta == SIP_TIME_MAX)
+ mindelta = 3600;
+ nua_dialog_usage_set_expires(du, mindelta);
+ }
+ else
+ nua_dialog_usage_set_expires(du, 0);
+ }
+
+#if HAVE_SIGCOMP
+ if (ready) {
+ struct sigcomp_compartment *cc;
+ cc = nta_outgoing_compartment(orq);
+ sigcomp_compartment_unref(nr->nr_compartment);
+ nr->nr_compartment = cc;
+ }
+#endif
+
+ /* RFC 3608 Section 6.1 Procedures at the UA
+
+ The UA performs a registration as usual. The REGISTER response may
+ contain a Service-Route header field. If so, the UA MAY store the
+ value of the Service-Route header field in an association with the
+ address-of-record for which the REGISTER transaction had registered a
+ contact. If the UA supports multiple addresses-of-record, it may be
+ able to store multiple service routes, one per address-of-record. If
+ the UA refreshes the registration, the stored value of the Service-
+ Route is updated according to the Service-Route header field of the
+ latest 200 class response. If there is no Service-Route header field
+ in the response, the UA clears any service route for that address-
+ of-record previously stored by the UA. If the re-registration
+ request is refused or if an existing registration expires and the UA
+ chooses not to re-register, the UA SHOULD discard any stored service
+ route for that address-of-record.
+
+ */
+ if (ready) {
+ su_free(nh->nh_home, nr->nr_route);
+ nr->nr_route = sip_route_dup(nh->nh_home, sip->sip_service_route);
+ }
+ else {
+ su_free(nh->nh_home, nr->nr_route);
+ nr->nr_route = NULL;
+ }
+
+ if (ready) {
+ /* RFC 3327 */
+ /* Store last URI in Path header */
+ sip_path_t *path = sip->sip_path;
+
+ while (path && path->r_next)
+ path = path->r_next;
+
+ if (!nr->nr_path || !path ||
+ url_cmp_all(nr->nr_path->r_url, path->r_url)) {
+ su_free(nh->nh_home, nr->nr_path);
+ nr->nr_path = sip_path_dup(nh->nh_home, path);
+ }
+ }
+
+ if (ready)
+ if (sip->sip_to->a_url->url_type == url_sips)
+ nr->nr_secure = 1;
+
+ if (nr->nr_ob) {
+ if (ready) {
+ outbound_gruuize(nr->nr_ob, sip);
+ outbound_start_keepalive(nr->nr_ob, orq);
+ }
+ else
+ outbound_stop_keepalive(nr->nr_ob);
+ }
+
+ nua_registration_set_ready(nr, ready);
+
+ return nua_stack_process_response(nh, cr, orq, sip, TAG_END());
+}
+
+/* ---------------------------------------------------------------------- */
+/* nua_registration_t interface */
+
+#if HAVE_SOFIA_STUN
+#include <sofia-sip/stun.h>
+#endif
+
+static void nua_stack_tport_update(nua_t *nua, nta_agent_t *nta);
+static int nua_registration_add_contact_and_route(nua_registration_t *nr,
+ msg_t *msg,
+ sip_t *sip,
+ int add_contact,
+ int add_service_route);
+
+int
+nua_stack_init_transport(nua_t *nua, tagi_t const *tags)
+{
+ url_string_t const *contact1 = NULL, *contact2 = NULL;
+ char const *name1 = "sip", *name2 = "sip";
+ char const *certificate_dir = NULL;
+
+ tl_gets(tags,
+ NUTAG_URL_REF(contact1),
+ NUTAG_SIPS_URL_REF(contact2),
+ NUTAG_CERTIFICATE_DIR_REF(certificate_dir),
+ TAG_END());
+
+ if (!contact1 && contact2)
+ contact1 = contact2, contact2 = NULL;
+
+ if (contact1 &&
+ (url_is_string(contact1)
+ ? strncasecmp(contact1->us_str, "sips:", 5) == 0
+ : contact1->us_url->url_type == url_sips))
+ name1 = "sips";
+
+ if (contact2 &&
+ (url_is_string(contact2)
+ ? strncasecmp(contact2->us_str, "sips:", 5) == 0
+ : contact2->us_url->url_type == url_sips))
+ name2 = "sips";
+
+ if (!contact1 /* && !contact2 */) {
+ if (nta_agent_add_tport(nua->nua_nta, NULL,
+ TPTAG_IDENT("sip"),
+ TPTAG_CERTIFICATE(certificate_dir),
+ TAG_NEXT(nua->nua_args)) < 0 &&
+ nta_agent_add_tport(nua->nua_nta, URL_STRING_MAKE("sip:*:*"),
+ TPTAG_IDENT("sip"),
+ TPTAG_CERTIFICATE(certificate_dir),
+ TAG_NEXT(nua->nua_args)) < 0)
+ return -1;
+#if HAVE_SOFIA_STUN
+ if (stun_is_requested(TAG_NEXT(nua->nua_args)) &&
+ nta_agent_add_tport(nua->nua_nta, URL_STRING_MAKE("sip:0.0.0.0:*"),
+ TPTAG_IDENT("stun"),
+ TPTAG_PUBLIC(tport_type_stun), /* use stun */
+ TPTAG_CERTIFICATE(certificate_dir),
+ TAG_NEXT(nua->nua_args)) < 0) {
+ SU_DEBUG_0(("nua: error initializing STUN transport\n"));
+ }
+#endif
+ }
+ else {
+ if (nta_agent_add_tport(nua->nua_nta, contact1,
+ TPTAG_IDENT(name1),
+ TPTAG_CERTIFICATE(certificate_dir),
+ TAG_NEXT(nua->nua_args)) < 0)
+ return -1;
+
+ if (contact2 &&
+ nta_agent_add_tport(nua->nua_nta, contact2,
+ TPTAG_IDENT(name2),
+ TPTAG_CERTIFICATE(certificate_dir),
+ TAG_NEXT(nua->nua_args)) < 0)
+ return -1;
+ }
+
+
+ if (nua_stack_init_registrations(nua) < 0)
+ return -1;
+
+ return 0;
+}
+
+#if 0
+ /* Store network detector param value */
+ if (agent->sa_nw_updates == 0)
+ agent->sa_nw_updates = nw_updates;
+ NTATAG_DETECT_NETWORK_UPDATES_REF(nw_updates),
+ unsigned nw_updates = 0;
+ unsigned nw_updates = 0;
+
+ su_network_changed_t *sa_nw_changed;
+
+#endif
+
+static
+void nua_network_changed_cb(nua_t *nua, su_root_t *root)
+{
+
+ uint32_t nw_updates = NUA_NW_DETECT_TRY_FULL;
+
+ switch (nw_updates) {
+ case NUA_NW_DETECT_ONLY_INFO:
+ nua_stack_event(nua, NULL, NULL, nua_i_network_changed,
+ SIP_200_OK, TAG_END());
+
+ break;
+
+ case NUA_NW_DETECT_TRY_FULL:
+
+ /* 1) Shutdown all tports */
+ nta_agent_close_tports(nua->nua_nta);
+
+ /* 2) Create new tports */
+ if (nua_stack_init_transport(nua, nua->nua_args) < 0)
+ /* We are hosed */
+ nua_stack_event(nua, NULL, NULL, nua_i_network_changed,
+ 900, "Internal Error", TAG_END());
+ else
+ nua_stack_event(nua, NULL, NULL, nua_i_network_changed,
+ SIP_200_OK, TAG_END());
+
+ break;
+
+ default:
+ break;
+ }
+
+ return;
+}
+
+int nua_stack_launch_network_change_detector(nua_t *nua)
+{
+ su_network_changed_t *snc = NULL;
+
+ snc = su_root_add_network_changed(nua->nua_home,
+ nua->nua_api_root,
+ nua_network_changed_cb,
+ nua);
+
+ if (!snc)
+ return -1;
+
+ nua->nua_nw_changed = snc;
+
+ return 0;
+}
+
+
+int
+nua_stack_init_registrations(nua_t *nua)
+{
+ /* Create initial identities: peer-to-peer, public, sips */
+ nua_registration_t **nr_list = &nua->nua_registrations, **nr_next;
+ nua_handle_t **nh_list;
+ nua_handle_t *dnh = nua->nua_dhandle;
+ sip_via_t const *v;
+
+ /* Remove existing, local address based registrations and count the
+ rest */
+ while (nr_list && *nr_list) {
+ nr_next = &(*nr_list)->nr_next;
+ if ((*nr_list)->nr_default == 1) {
+ nua_registration_remove(*nr_list);
+ /* memset(*nr_list, 170, sizeof(**nr_list)); */
+ /* XXX - free, too */
+ }
+ nr_list = nr_next;
+ }
+ nr_list = &nua->nua_registrations;
+
+ v = nta_agent_public_via(nua->nua_nta);
+ if (v) {
+ nua_registration_from_via(nr_list, dnh, v, 1);
+ }
+
+ v = nta_agent_via(nua->nua_nta);
+ if (v) {
+ nua_registration_from_via(nr_list, dnh, v, 0);
+ }
+ else {
+ sip_via_t v[2];
+
+ sip_via_init(v)->v_next = v + 1;
+ v[0].v_protocol = sip_transport_udp;
+ v[0].v_host = "addr.is.invalid.";
+ sip_via_init(v + 1);
+ v[1].v_protocol = sip_transport_tcp;
+ v[1].v_host = "addr.is.invalid.";
+
+ nua_registration_from_via(nr_list, dnh, v, 0);
+ }
+
+ /* Go through all the registrations and set to refresh almost
+ immediately */
+ nh_list = &nua->nua_handles;
+ for (; *nh_list; nh_list = &(*nh_list)->nh_next) {
+ nua_dialog_state_t *ds;
+ nua_dialog_usage_t *du;
+
+ ds = (*nh_list)->nh_ds;
+ du = ds->ds_usage;
+
+ if (ds->ds_has_register == 1 && du->du_class->usage_refresh) {
+ nua_dialog_usage_refresh(*nh_list, ds, du, 1);
+ }
+ }
+
+ nta_agent_bind_tport_update(nua->nua_nta, nua, nua_stack_tport_update);
+
+ return 0;
+}
+
+int nua_registration_from_via(nua_registration_t **list,
+ nua_handle_t *nh,
+ sip_via_t const *via,
+ int public)
+{
+ su_home_t *home = nh->nh_home;
+ sip_via_t *v, *pair, /* v2[2], */ *vias, **vv, **prev;
+ nua_registration_t *nr = NULL, **next;
+ su_home_t autohome[SU_HOME_AUTO_SIZE(1024)];
+ int nr_items = 0;
+
+ vias = sip_via_copy(su_home_auto(autohome, sizeof autohome), via);
+
+ for (; *list; list = &(*list)->nr_next)
+ ++nr_items;
+
+ next = list;
+
+ for (vv = &vias; (v = *vv);) {
+ char const *protocol;
+ sip_contact_t *contact;
+ sip_via_t v2[2];
+
+ *vv = v->v_next, v->v_next = NULL, pair = NULL;
+
+ if (v->v_protocol == sip_transport_tcp)
+ protocol = sip_transport_udp;
+ else if (v->v_protocol == sip_transport_udp)
+ protocol = sip_transport_tcp;
+ else
+ protocol = NULL;
+
+ if (protocol) {
+ /* Try to pair vias if we have both udp and tcp */
+ for (prev = vv; *prev; prev = &(*prev)->v_next) {
+ if (strcasecmp(protocol, (*prev)->v_protocol))
+ continue;
+ if (strcasecmp(v->v_host, (*prev)->v_host))
+ continue;
+ if (str0cmp(v->v_port, (*prev)->v_port))
+ continue;
+ break;
+ }
+
+ if (*prev) {
+ pair = *prev; *prev = pair->v_next; pair->v_next = NULL;
+ }
+ }
+
+ /* if more than one candidate, ignore local entries */
+ if (v && (*vv || nr_items > 0) &&
+ host_is_local(v->v_host)) {
+ SU_DEBUG_9(("nua_register: ignoring contact candidate %s:%s.\n",
+ v->v_host, v->v_port ? v->v_port : ""));
+ continue;
+ }
+
+ nr = su_zalloc(home, sizeof *nr);
+ if (!nr)
+ break;
+
+ v2[0] = *v;
+
+ if (pair)
+ /* Don't use protocol if we have both udp and tcp */
+ protocol = NULL, v2[0].v_next = &v2[1], v2[1] = *pair;
+ else
+ protocol = via->v_protocol, v2[0].v_next = NULL;
+
+ v2[1].v_next = NULL;
+
+#if 1
+ contact = nua_handle_contact_by_via(nh, home, NULL, v2, protocol, NULL);
+#else
+ contact = sip_contact_create_from_via_with_transport(home, v2, NULL, protocol);
+#endif
+ v = sip_via_dup(home, v2);
+
+ if (!contact || !v) {
+ su_free(home, nr);
+ break;
+ }
+
+ nr->nr_ready = 1, nr->nr_default = 1, nr->nr_public = public;
+ nr->nr_secure = contact->m_url->url_type == url_sips;
+ nr->nr_contact = contact;
+ nr->nr_via = v;
+ nr->nr_ip4 = host_is_ip4_address(contact->m_url->url_host);
+ nr->nr_ip6 = !nr->nr_ip4 && host_is_ip6_reference(contact->m_url->url_host);
+
+ SU_DEBUG_9(("nua_register: Adding contact URL '%s' to list.\n", contact->m_url->url_host));
+
+ ++nr_items;
+ nr->nr_next = *next, nr->nr_prev = next; *next = nr, next = &nr->nr_next;
+ nr->nr_list = list;
+ }
+
+ su_home_deinit(autohome);
+
+ return 0;
+}
+
+static
+void nua_stack_tport_update(nua_t *nua, nta_agent_t *nta)
+{
+#if 0
+ nua_registration_t *default_oc;
+ nua_registration_t const *defaults = nua->nua_registrations;
+ sip_via_t *via = nta_agent_via(nta);
+
+ default_oc = outbound_by_aor(defaults, NULL, 1);
+
+ if (default_oc) {
+ assert(default_oc->nr_via);
+
+ outbound_contacts_from_via(default_oc,
+ via,
+ via->v_next);
+
+ /* refresh_register(nua_handle_t *nh, nua_dialog_usage_t *du, sip_time_t now); */
+ }
+#endif
+ return;
+}
+
+nua_registration_t *nua_registration_by_aor(nua_registration_t const *list,
+ sip_from_t const *aor,
+ url_t const *remote_uri,
+ int only_default)
+{
+ sip_from_t *alt_aor = NULL, _alt_aor[1];
+ int sips_aor = aor && aor->a_url->url_type == url_sips;
+ int sips_uri = remote_uri && remote_uri->url_type == url_sips;
+
+ nua_registration_t const *nr, *public = NULL, *any = NULL;
+ nua_registration_t const *namewise = NULL, *sipswise = NULL;
+
+ int ip4 = remote_uri && host_is_ip4_address(remote_uri->url_host);
+ int ip6 = remote_uri && host_is_ip6_reference(remote_uri->url_host);
+
+ if (only_default || aor == NULL) {
+ /* Ignore AoR, select only by remote_uri */
+ for (nr = list; nr; nr = nr->nr_next) {
+ if (!nr->nr_ready)
+ continue;
+ if (only_default && !nr->nr_default)
+ continue;
+ if (nr->nr_ip4 && ip6)
+ continue;
+ if (nr->nr_ip6 && ip4)
+ continue;
+ if (sips_uri ? nr->nr_secure : !nr->nr_secure)
+ return (nua_registration_t *)nr;
+ if (!public && nr->nr_public)
+ public = nr;
+ if (!any)
+ any = nr;
+ }
+ if (public)
+ return (nua_registration_t *)public;
+ if (any)
+ return (nua_registration_t *)any;
+ return NULL;
+ }
+
+ if (!sips_aor && aor)
+ alt_aor = memcpy(_alt_aor, aor, sizeof _alt_aor);
+
+ for (nr = list; nr; nr = nr->nr_next) {
+ if (!nr->nr_ready || !nr->nr_contact)
+ continue;
+ if (nr->nr_aor) {
+ if (aor && url_cmp(nr->nr_aor->a_url, aor->a_url) == 0)
+ return (nua_registration_t *)nr;
+ if (!namewise && alt_aor && url_cmp(nr->nr_aor->a_url, aor->a_url) == 0)
+ namewise = nr;
+ }
+ else {
+ if (!sipswise && ((sips_aor || sips_uri) ?
+ nr->nr_secure : !nr->nr_secure))
+ sipswise = nr;
+ }
+ if (!public && nr->nr_public)
+ public = nr;
+ if (!any)
+ any = nr;
+ }
+
+ if (namewise)
+ return (nua_registration_t *)namewise;
+ if (sipswise)
+ return (nua_registration_t *)sipswise;
+
+ /* XXX -
+ should we do some policing whether sips_aor or sips_uri can be used
+ with sip contact?
+ */
+ if (public)
+ return (nua_registration_t *)public;
+ if (any)
+ return (nua_registration_t *)any;
+
+ return NULL;
+}
+
+
+nua_registration_t *
+nua_registration_for_request(nua_registration_t const *list, sip_t const *sip)
+{
+ sip_from_t const *aor;
+ url_t *uri;
+
+ aor = sip->sip_from;
+ uri = sip->sip_request->rq_url;
+
+ return nua_registration_by_aor(list, aor, uri, 0);
+}
+
+nua_registration_t *
+nua_registration_for_response(nua_registration_t const *list,
+ sip_t const *sip,
+ sip_record_route_t const *record_route,
+ sip_contact_t const *remote_contact)
+{
+ nua_registration_t *nr;
+ sip_to_t const *aor = NULL;
+ url_t const *uri = NULL;
+
+ if (sip)
+ aor = sip->sip_to;
+
+ if (record_route)
+ uri = record_route->r_url;
+ else if (sip && sip->sip_record_route)
+ uri = sip->sip_record_route->r_url;
+ else if (remote_contact)
+ uri = remote_contact->m_url;
+ else if (sip && sip->sip_from)
+ uri = sip->sip_from->a_url;
+
+ nr = nua_registration_by_aor(list, aor, uri, 0);
+
+ return nr;
+}
+
+
+/** Return Contact usable in dialogs */
+sip_contact_t const *nua_registration_contact(nua_registration_t const *nr)
+{
+ if (nr->nr_by_stack && nr->nr_ob) {
+ sip_contact_t const *m = outbound_dialog_contact(nr->nr_ob);
+ if (m)
+ return m;
+ }
+
+ return nr->nr_contact;
+}
+
+/** Return initial route. */
+sip_route_t const *nua_registration_route(nua_registration_t const *nr)
+{
+ return nr ? nr->nr_route : NULL;
+}
+
+sip_contact_t const *nua_stack_get_contact(nua_registration_t const *nr)
+{
+ nr = nua_registration_by_aor(nr, NULL, NULL, 1);
+ return nr ? nr->nr_contact : NULL;
+}
+
+/** Add a Contact (and Route) header to request */
+int nua_registration_add_contact_to_request(nua_handle_t *nh,
+ msg_t *msg,
+ sip_t *sip,
+ int add_contact,
+ int add_service_route)
+{
+ nua_registration_t *nr = NULL;
+
+ if (!add_contact && !add_service_route)
+ return 0;
+
+ if (nh == NULL || msg == NULL)
+ return -1;
+
+ if (sip == NULL)
+ sip = sip_object(msg);
+
+ if (nr == NULL)
+ nr = nua_registration_for_request(nh->nh_nua->nua_registrations, sip);
+
+ return nua_registration_add_contact_and_route(nr, msg, sip,
+ add_contact,
+ add_service_route);
+}
+
+/** Add a Contact header to response.
+ *
+ * @param nh
+ * @param msg response message
+ * @param sip response headers
+ * @param record_route record-route from request
+ * @param remote_contact Contact from request
+ */
+int nua_registration_add_contact_to_response(nua_handle_t *nh,
+ msg_t *msg,
+ sip_t *sip,
+ sip_record_route_t const *record_route,
+ sip_contact_t const *remote_contact)
+{
+ nua_registration_t *nr = NULL;
+
+ if (sip == NULL)
+ sip = sip_object(msg);
+
+ if (nh == NULL || msg == NULL || sip == NULL)
+ return -1;
+
+ if (nr == NULL)
+ nr = nua_registration_for_response(nh->nh_nua->nua_registrations, sip,
+ record_route, remote_contact);
+
+ return nua_registration_add_contact_and_route(nr, msg, sip, 1, 0);
+}
+
+/** Add a Contact (and Route) header to request */
+static
+int nua_registration_add_contact_and_route(nua_registration_t *nr,
+ msg_t *msg,
+ sip_t *sip,
+ int add_contact,
+ int add_service_route)
+{
+ if (nr == NULL)
+ return -1;
+
+ if (add_contact) {
+ sip_contact_t const *m = nua_registration_contact(nr);
+ if (!m || msg_header_add_dup(msg, (msg_pub_t *)sip, (void const *)m) < 0)
+ return -1;
+ }
+
+ if (add_service_route && !sip->sip_status) {
+ sip_route_t const *sr = nua_registration_route(nr);
+ if (msg_header_add_dup(msg, (msg_pub_t *)sip, (void const *)sr) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/** Add a registration to list of contacts */
+int nua_registration_add(nua_registration_t **list,
+ nua_registration_t *nr)
+{
+ assert(list && nr);
+
+ if (nr->nr_list == NULL) {
+ nua_registration_t *next = *list;
+ if (next)
+ next->nr_prev = &nr->nr_next;
+ nr->nr_next = next, nr->nr_prev = list, nr->nr_list = list;
+ *list = nr;
+ }
+
+ return 0;
+}
+
+/** Remove from list of registrations */
+void nua_registration_remove(nua_registration_t *nr)
+{
+ if ((*nr->nr_prev = nr->nr_next))
+ nr->nr_next->nr_prev = nr->nr_prev;
+ nr->nr_next = NULL, nr->nr_prev = NULL, nr->nr_list = NULL;
+}
+
+/** Set address-of-record. */
+int nua_registration_set_aor(su_home_t *home,
+ nua_registration_t *nr,
+ sip_from_t const *aor)
+{
+ sip_from_t *new_aor, *old_aor;
+
+ if (!home || !nr || !aor)
+ return -1;
+
+ new_aor = sip_from_dup(home, aor);
+ if (!new_aor)
+ return -1;
+
+ old_aor = nr->nr_aor;
+ nr->nr_aor = new_aor;
+ msg_header_free(home, (void *)old_aor);
+
+ return 0;
+}
+
+/** Set contact. */
+int nua_registration_set_contact(nua_handle_t *nh,
+ nua_registration_t *nr,
+ sip_contact_t const *application_contact,
+ int terminating)
+{
+ sip_contact_t *m = NULL, *previous;
+ url_t *uri;
+
+ if (!nh || !nr)
+ return -1;
+
+ uri = nr->nr_aor ? nr->nr_aor->a_url : NULL;
+
+ previous = nr->nr_contact;
+
+ if (application_contact) {
+ m = sip_contact_dup(nh->nh_home, application_contact);
+ }
+ else if (terminating && nr->nr_contact) {
+ return 0;
+ }
+ else {
+ nua_registration_t *nr0;
+
+ nr0 = nua_registration_by_aor(*nr->nr_list, NULL, uri, 1);
+
+ if (nr0 && nr0->nr_via) {
+ char const *tport = nr0->nr_via->v_next ? NULL : nr0->nr_via->v_protocol;
+ m = nua_handle_contact_by_via(nh, nh->nh_home,
+ NULL, nr0->nr_via, tport, NULL);
+ }
+ }
+
+ if (!m)
+ return -1;
+
+ nr->nr_contact = m;
+ nr->nr_ip4 = host_is_ip4_address(m->m_url->url_host);
+ nr->nr_ip6 = !nr->nr_ip4 && host_is_ip6_reference(m->m_url->url_host);
+ nr->nr_by_stack = !application_contact;
+
+ msg_header_free(nh->nh_home, (void *)previous);
+
+ return 0;
+}
+
+/** Mark registration as ready */
+void nua_registration_set_ready(nua_registration_t *nr, int ready)
+{
+ assert(!ready || nr->nr_contact);
+ nr->nr_ready = ready;
+}
+
+/** @internal Hook for processing incoming request by registration.
+ *
+ * This is used for keepalive/validate OPTIONS.
+ */
+int nua_registration_process_request(nua_registration_t *list,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ sip_call_id_t *i;
+ nua_registration_t *nr;
+
+ if (!outbound_targeted_request(sip))
+ return 0;
+
+ /* Process by outbound... */
+ i = sip->sip_call_id;
+
+ for (nr = list; nr; nr = nr->nr_next) {
+ outbound_t *ob = nr->nr_ob;
+ if (ob)
+ if (outbound_process_request(ob, irq, sip))
+ return 501; /* Just in case */
+ }
+
+ return 481; /* Call/Transaction does not exist */
+}
+
+/**@internal
+ * Fix contacts for un-REGISTER.
+ *
+ * Remove (possible non-zero) "expires" parameters from contacts and extra
+ * contacts, add Expire: 0.
+ */
+static
+void unregister_expires_contacts(msg_t *msg, sip_t *sip)
+{
+ sip_contact_t *m;
+ int unregister_all;
+
+ if (msg == NULL || sip == NULL)
+ return;
+
+ /* Remove payload */
+ while (sip->sip_payload)
+ sip_header_remove(msg, sip, (sip_header_t *)sip->sip_payload);
+ while (sip->sip_content_type)
+ sip_header_remove(msg, sip, (sip_header_t *)sip->sip_content_type);
+
+ for (m = sip->sip_contact; m; m = m->m_next) {
+ if (m->m_url->url_type == url_any)
+ break;
+ msg_header_remove_param(m->m_common, "expires");
+#if 0
+ msg_header_add_param(msg_home(msg), m->m_common, "expires=0");
+#endif
+ }
+
+ unregister_all = m && (m != sip->sip_contact || m->m_next);
+
+ sip_add_tl(msg, sip,
+ /* Remove existing contacts */
+ TAG_IF(unregister_all, SIPTAG_CONTACT(NONE)),
+ /* Add '*' contact: 0 */
+ TAG_IF(unregister_all, SIPTAG_CONTACT_STR("*")),
+ SIPTAG_EXPIRES_STR("0"),
+ TAG_END());
+}
+
+
+/** Outbound requests us to refresh registration */
+static int nua_stack_outbound_refresh(nua_handle_t *nh,
+ outbound_t *ob)
+{
+ nua_dialog_state_t *ds = nh->nh_ds;
+ nua_dialog_usage_t *du;
+
+ du = nua_dialog_usage_get(ds, nua_register_usage, NULL);
+
+ if (du)
+ nua_dialog_usage_refresh(nh, ds, du, 1);
+
+ return 0;
+}
+
+/** @NUA_EVENT nua_i_outbound
+ *
+ * Status from outbound engine.
+ *
+ * @param status SIP status code or NUA status code (>= 900)
+ * describing the outbound state
+ * @param phrase a short textual description of @a status code
+ * @param nh operation handle associated with the outbound engine
+ * @param hmagic application context associated with the handle
+ * @param sip NULL or response message to an keepalive message or
+ * registration probe
+ * (error code and message are in status an phrase parameters)
+ * @param tags empty
+ *
+ * @sa NUTAG_OUTBOUND(), NUTAG_KEEPALIVE(), NUTAG_KEEPALIVE_STREAM(),
+ * nua_register(), #nua_r_register, nua_unregister(), #nua_r_unregister
+ *
+ * @END_NUA_EVENT
+ */
+
+/** @internal Callback from outbound_t */
+static int nua_stack_outbound_status(nua_handle_t *nh, outbound_t *ob,
+ int status, char const *phrase,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ ta_list ta;
+
+ ta_start(ta, tag, value);
+
+ nua_stack_event(nh->nh_nua, nh, NULL,
+ nua_i_outbound, status, phrase,
+ ta_tags(ta));
+
+ ta_end(ta);
+
+ return 0;
+}
+
+/** @internal Callback from outbound_t */
+static int nua_stack_outbound_failed(nua_handle_t *nh, outbound_t *ob,
+ int status, char const *phrase,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ ta_list ta;
+ ta_start(ta, tag, value);
+
+ nua_stack_event(nh->nh_nua, nh, NULL,
+ nua_i_outbound, status, phrase,
+ ta_tags(ta));
+
+ ta_end(ta);
+
+ return 0;
+}
+
+/** @internal Callback for obtaining credentials for keepalive */
+static int nua_stack_outbound_credentials(nua_handle_t *nh,
+ auth_client_t **auc)
+{
+ return auc_copy_credentials(auc, nh->nh_auth);
+}
+
+#include <ctype.h>
+#include <sofia-sip/bnf.h>
+
+/** @internal Generate a @Contact header. */
+sip_contact_t *nua_handle_contact_by_via(nua_handle_t *nh,
+ su_home_t *home,
+ char const *extra_username,
+ sip_via_t const *v,
+ char const *transport,
+ char const *m_param,
+ ...)
+{
+ su_strlst_t *l;
+ char const *s;
+ char const *scheme = "sip:", *host, *port, *maddr, *comp;
+ int one = 1;
+ char _transport[16];
+ va_list va;
+ sip_contact_t *m;
+
+ if (!v) return NULL;
+
+ host = v->v_host;
+ if (v->v_received)
+ host = v->v_received;
+ port = sip_via_port(v, &one);
+ maddr = v->v_maddr;
+ comp = v->v_comp;
+
+ if (host == NULL)
+ return NULL;
+
+ if (sip_transport_has_tls(v->v_protocol) ||
+ sip_transport_has_tls(transport)) {
+ scheme = "sips:";
+ if (port && strcmp(port, SIPS_DEFAULT_SERV) == 0)
+ port = NULL;
+ if (port || host_is_ip_address(host))
+ transport = NULL;
+ }
+ else if (port && host_is_ip_address(host) &&
+ strcmp(port, SIP_DEFAULT_SERV) == 0) {
+ port = NULL;
+ }
+
+ if (transport) {
+ if (strncasecmp(transport, "SIP/2.0/", 8) == 0)
+ transport += 8;
+
+ /* Make transport parameter lowercase */
+ if (strlen(transport) < (sizeof _transport)) {
+ char *s = strcpy(_transport, transport);
+
+ for (s = _transport; *s && *s != ';'; s++)
+ if (isupper(*s))
+ *s = tolower(*s);
+
+ transport = _transport;
+ }
+ }
+
+ l = su_strlst_create(NULL);
+
+ s = NH_PGET(nh, m_display);
+ if (s) {
+ int quote = s[span_token_lws(s)] != '\0';
+
+ su_strlst_append(l, quote ? "\"" : "");
+ su_strlst_append(l, s);
+ su_strlst_append(l, quote ? "\" " : " ");
+ }
+ su_strlst_append(l, "<");
+ su_strlst_append(l, scheme);
+ s = NH_PGET(nh, m_username);
+ if (s) su_strlst_append(l, s);
+ if (extra_username) su_strlst_append(l, s);
+ if (s || extra_username)
+ su_strlst_append(l, "@");
+ su_strlst_append(l, host);
+ if (port)
+ su_strlst_append(l, ":"), su_strlst_append(l, port);
+ if (transport)
+ su_strlst_append(l, ";transport="), su_strlst_append(l, transport);
+ if (maddr)
+ su_strlst_append(l, ";maddr="), su_strlst_append(l, maddr);
+ if (comp)
+ su_strlst_append(l, ";comp="), su_strlst_append(l, comp);
+ s = NH_PGET(nh, m_params);
+ if (s)
+ su_strlst_append(l, s[0] == ';' ? "" : ";"), su_strlst_append(l, s);
+ su_strlst_append(l, ">");
+
+ va_start(va, m_param);
+
+ for (s = m_param; s; s = va_arg(va, char *)) {
+ if (strlen(s) == 0)
+ continue;
+ su_strlst_append(l, s[0] == ';' ? "" : ";");
+ su_strlst_append(l, s);
+ }
+
+ va_end(va);
+
+ m = sip_contact_make(home, su_strlst_join(l, su_strlst_home(l), ""));
+
+ su_strlst_destroy(l);
+
+ return m;
+}
+
+/** @internal Return a string describing our features. */
+static char *nua_handle_features(nua_handle_t *nh)
+{
+ char *retval = NULL;
+ su_strlst_t *l = su_strlst_create(NULL);
+ su_home_t *home = su_strlst_home(l);
+
+ if (!l)
+ return NULL;
+
+ if (NH_PGET(nh, m_features)) {
+ char const *m_features = NH_PGET(nh, m_features);
+
+ if (m_features[0] != ';')
+ su_strlst_append(l, ";");
+
+ su_strlst_append(l, m_features);
+ }
+
+ if (NH_PGET(nh, callee_caps)) {
+ sip_allow_t const *allow = NH_PGET(nh, allow);
+
+ if (allow) {
+ /* Skip ";" if this is first one */
+ su_strlst_append(l, ";methods=\"" + (su_strlst_len(l) == 0));
+ if (allow->k_items) {
+ size_t i;
+ for (i = 0; allow->k_items[i]; i++) {
+ su_strlst_append(l, allow->k_items[i]);
+ if (allow->k_items[i + 1])
+ su_strlst_append(l, ",");
+ }
+ }
+ su_strlst_append(l, "\"");
+ }
+
+ if (nh->nh_soa) {
+ char **media = soa_media_features(nh->nh_soa, 0, home);
+
+ while (*media) {
+ if (su_strlst_len(l))
+ su_strlst_append(l, ";");
+ su_strlst_append(l, *media++);
+ }
+ }
+ }
+
+ if (su_strlst_len(l))
+ retval = su_strlst_join(l, nh->nh_home, "");
+
+ su_strlst_destroy(l);
+
+ return retval;
+}
+
+static int nua_stack_outbound_features(nua_handle_t *nh, outbound_t *ob)
+{
+ char *features;
+ int retval;
+
+ if (!nh)
+ return -1;
+ if (!ob)
+ return 0;
+
+ features = nua_handle_features(nh);
+ retval = outbound_set_features(ob, features);
+ su_free(nh->nh_home, features);
+
+ return retval;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_registrar.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_registrar.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,103 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nua_registrar.c
+ * @brief REGISTER UAS
+ *
+ * @author Michael Jerris
+ *
+ * @date Created: Tue Oct 3 10:14:54 EEST 2006 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include <assert.h>
+
+#include <sofia-sip/string0.h>
+#include <sofia-sip/sip_protos.h>
+#include <sofia-sip/sip_status.h>
+#include <sofia-sip/sip_util.h>
+
+#define NTA_LEG_MAGIC_T struct nua_handle_s
+#define NTA_OUTGOING_MAGIC_T struct nua_handle_s
+#define NTA_INCOMING_MAGIC_T struct nua_handle_s
+#define NTA_RELIABLE_MAGIC_T struct nua_handle_s
+
+#include "nua_stack.h"
+
+/* ======================================================================== */
+/* REGISTER */
+
+/** @NUA_EVENT nua_i_register
+ *
+ * Incoming REGISTER request.
+ *
+ * In order to receive #nua_i_register events, the application must enable
+ * the REGISTER method with NUTAG_ALLOW() tag.
+ *
+ * The nua_response() call responding to a REGISTER request must have
+ * NUTAG_WITH() (or NUTAG_WITH_CURRENT()/NUTAG_WITH_SAVED()) tag. Note that
+ * a successful response to REGISTER @b MUST include the @Contact header
+ * bound to the the AoR URI (in @To header).
+ *
+ * The REGISTER request does not create a dialog. Currently the processing
+ * of incoming REGISTER creates a new handle for each incoming request which
+ * is not assiciated with an existing dialog. If the handle @a nh is not
+ * bound, you should probably destroy it after responding to the REGISTER
+ * request.
+ *
+ * @param status status code of response sent automatically by stack
+ * @param phrase a short textual description of @a status code
+ * @param nh operation handle associated with the request
+ * @param hmagic application context associated with the handle
+ * (usually NULL)
+ * @param sip incoming REGISTER request
+ * @param tags empty
+ *
+ * @sa nua_respond(), @RFC3261 section 10.3,
+ * @Expires, @Contact, @CallID, @CSeq,
+ * @Path, @RFC3327, @ServiceRoute, @RFC3608, @RFC3680,
+ * nua_register(), #nua_i_register, nua_unregister(), #nua_i_unregister
+ *
+ * @since New in @VERSION_1_12_4
+ * @END_NUA_EVENT
+ */
+
+int nua_stack_process_register(nua_t *nua,
+ nua_handle_t *nh,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ nua_server_request_t *sr, sr0[1];
+
+ sr = nua_server_request(nua, nh, irq, sip, SR_INIT(sr0), sizeof *sr,
+ nua_default_respond, 0);
+
+ return nua_stack_server_event(nua, sr, nua_i_register, TAG_END());
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,3986 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nua_session.c
+ * @brief SIP session handling
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Mar 8 16:17:27 EET 2006 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include <assert.h>
+
+#include <sofia-sip/string0.h>
+#include <sofia-sip/sip_protos.h>
+#include <sofia-sip/sip_status.h>
+#include <sofia-sip/sip_util.h>
+#include <sofia-sip/su_uniqueid.h>
+
+#define NTA_LEG_MAGIC_T struct nua_handle_s
+#define NTA_OUTGOING_MAGIC_T struct nua_handle_s
+#define NTA_INCOMING_MAGIC_T struct nua_server_request
+#define NTA_RELIABLE_MAGIC_T struct nua_handle_s
+
+#include "nua_stack.h"
+#include <sofia-sip/soa.h>
+
+#ifndef SDP_H
+typedef struct sdp_session_s sdp_session_t;
+#endif
+
+/* ---------------------------------------------------------------------- */
+
+/** @enum nua_callstate
+
+The states for SIP session established with INVITE.
+
+Initially the call states follow the state of the INVITE transaction. If the
+initial INVITE transaction fails, the call is terminated. The status codes
+401 and 407 are an exception: if the client (on the left side in the diagram
+below) receives them, it enters in #nua_callstate_authenticating state.
+
+If a re-INVITE transaction fails, the result depends on the status code in
+failure. The call can return to the ready state, be terminated immediately,
+or be terminated gracefully. The proper action to take is determined with
+sip_response_terminates_dialog().
+
+ at sa @ref nua_call_model, #nua_i_state, nua_invite(), #nua_i_invite
+
+ at par Session State Diagram
+
+ at code
+ +----------+
+ | |---------------------+
+ | Init | |
+ | |----------+ |
+ +----------+ | |
+ | | | |
+ --/INVITE| |INVITE/100 | |
+ V V | |
+ +----------+ +----------+ | |
+ +--------| | | | | |
+ | 18X +-| Calling | | Received | |INVITE/ |
+ | /- | | | | | | /18X |
+ | V +----------+ +----------+ V |
+ | +----------+ | | | +----------+ |
+ |---| | |2XX -/ | -/ | | | |
+ | | Proceed- | | /- 2XX| 18X| | Early | |INVITE/
+ | | ing | | | +->| | | /200
+ | +----------+ V V +----------+ |
+ | | +----------+ +----------+ | -/ |
+ | 2XX| | | | |<--+ 2XX |
+ | /-| | Complet- | | Complete |<-----------+
+ | +->| ing | | |------+
+ | +----------+ +----------+ |
+ | | | | |
+ |401,407/ -/ACK| |ACK/- |timeout/ |
+ | /ACK V V | /BYE |
+ | +----------+ | |
+ | | | | |
+ | +--| Ready | | |
+ | | | | | |
+ | | +----------+ | |
+ | | | | |
+ | BYE/ | |-/BYE | |BYE/
+ V /200 | V | |/200
+ +----------+ | +----------+ | |
+ | | | | | | |
+ |Authentic-| | | Terminat-|<----+ |
+ | ating | | | ing | |
+ +----------+ | +----------+ |
+ | | |
+ | |[23456]XX/- |
+ | V |
+ | +----------+ |
+ | | | |
+ +->|Terminated|<--------------+
+ | |
+ +----------+
+ |
+ V
+ +----------+
+ | |
+ | Init |
+ | |
+ +----------+
+ at endcode
+*/
+
+/* ---------------------------------------------------------------------- */
+/* Session event usage */
+
+/** Session-related state */
+typedef struct nua_session_usage
+{
+ /* enum nua_callstate */
+ unsigned ss_state:4; /**< Session status (enum nua_callstate) */
+
+ unsigned ss_100rel:1; /**< Use 100rel, send 183 */
+ unsigned ss_alerting:1; /**< 180 is sent/received */
+
+ unsigned ss_update_needed:2; /**< Send an UPDATE (do O/A if > 1) */
+
+ unsigned ss_precondition:1; /**< Precondition required */
+
+ unsigned ss_timer_set:1; /**< We have active session timer. */
+ unsigned : 0;
+
+ unsigned ss_session_timer; /**< Value of Session-Expires (delta) */
+ unsigned ss_min_se; /**< Minimum session expires */
+ enum nua_session_refresher ss_refresher; /**< none, local or remote */
+
+ char const *ss_ack_needed; /**< If non-null, need to send an ACK
+ * (do O/A, if "offer" or "answer")
+ */
+
+ nua_client_request_t ss_crequest[1]; /* Outgoing invite */
+} nua_session_usage_t;
+
+static char const *nua_session_usage_name(nua_dialog_usage_t const *du);
+static int nua_session_usage_add(nua_handle_t *nh,
+ nua_dialog_state_t *ds,
+ nua_dialog_usage_t *du);
+static void nua_session_usage_remove(nua_handle_t *nh,
+ nua_dialog_state_t *ds,
+ nua_dialog_usage_t *du);
+static void nua_session_usage_refresh(nua_owner_t *,
+ nua_dialog_state_t *,
+ nua_dialog_usage_t *,
+ sip_time_t now);
+static int nua_session_usage_shutdown(nua_owner_t *,
+ nua_dialog_state_t *,
+ nua_dialog_usage_t *);
+
+static nua_usage_class const nua_session_usage[1] = {
+ {
+ sizeof (nua_session_usage_t),
+ sizeof nua_session_usage,
+ nua_session_usage_add,
+ nua_session_usage_remove,
+ nua_session_usage_name,
+ NULL,
+ nua_session_usage_refresh,
+ nua_session_usage_shutdown
+ }};
+
+static char const *nua_session_usage_name(nua_dialog_usage_t const *du)
+{
+ return "session";
+}
+
+static
+int nua_session_usage_add(nua_handle_t *nh,
+ nua_dialog_state_t *ds,
+ nua_dialog_usage_t *du)
+{
+ nua_session_usage_t *ss = nua_dialog_usage_private(du);
+
+ if (ds->ds_has_session)
+ return -1;
+ ds->ds_has_session = 1;
+
+ nh->nh_ds->ds_cr->cr_next = ss->ss_crequest;
+
+ return 0;
+}
+
+static
+void nua_session_usage_remove(nua_handle_t *nh,
+ nua_dialog_state_t *ds,
+ nua_dialog_usage_t *du)
+{
+ nua_session_usage_t *ss = nua_dialog_usage_private(du);
+
+ ds->ds_has_session = 0;
+
+ if (ss->ss_crequest)
+ nua_creq_deinit(ss->ss_crequest, NULL);
+
+ ds->ds_cr->cr_next = NULL;
+}
+
+static
+nua_session_usage_t *nua_session_usage_get(nua_dialog_state_t const *ds)
+{
+ nua_dialog_usage_t *du;
+
+ if (ds == ((nua_handle_t *)NULL)->nh_ds)
+ return NULL;
+
+ du = nua_dialog_usage_get(ds, nua_session_usage, NULL);
+
+ return (nua_session_usage_t *)nua_dialog_usage_private(du);
+}
+
+/* ======================================================================== */
+/* INVITE and call (session) processing */
+
+static int nua_stack_invite2(nua_t *, nua_handle_t *, nua_event_t e,
+ int restarted, tagi_t const *tags);
+static int process_response_to_invite(nua_handle_t *nh,
+ nta_outgoing_t *orq,
+ sip_t const *sip);
+static void
+ session_timeout(nua_handle_t *nh, nua_dialog_usage_t *du, sip_time_t now);
+
+static void restart_invite(nua_handle_t *nh, tagi_t *tags);
+
+static int process_100rel(nua_handle_t *nh,
+ nua_session_usage_t *ss,
+ nta_outgoing_t *orq,
+ sip_t const *sip);
+
+int nua_stack_prack(nua_t *nua, nua_handle_t *nh, nua_event_t e,
+ tagi_t const *tags);
+
+static int process_response_to_prack(nua_handle_t *nh,
+ nta_outgoing_t *orq,
+ sip_t const *sip);
+
+static void nua_session_usage_destroy(nua_handle_t *, nua_session_usage_t *);
+
+static void session_timer_preferences(nua_session_usage_t *ss,
+ unsigned expires,
+ unsigned min_se,
+ enum nua_session_refresher refresher);
+static int session_timer_is_supported(nua_handle_t const *nh);
+static int prefer_session_timer(nua_handle_t const *nh);
+
+static int use_session_timer(nua_session_usage_t *ss, int uas, int always,
+ msg_t *msg, sip_t *);
+static int init_session_timer(nua_session_usage_t *ss, sip_t const *, int refresher);
+static void set_session_timer(nua_session_usage_t *ss);
+
+static int
+check_session_timer_restart(nua_handle_t *nh,
+ nua_session_usage_t *ss,
+ nua_client_request_t *cr,
+ nta_outgoing_t *orq,
+ sip_t const *sip,
+ nua_creq_restart_f *restart_function);
+
+static int nh_referral_check(nua_handle_t *nh, tagi_t const *tags);
+static void nh_referral_respond(nua_handle_t *,
+ int status, char const *phrase);
+
+static void signal_call_state_change(nua_handle_t *nh,
+ nua_session_usage_t *ss,
+ int status, char const *phrase,
+ enum nua_callstate next_state,
+ char const *oa_recv,
+ char const *oa_sent);
+
+static
+int session_get_description(sip_t const *sip,
+ char const **return_sdp,
+ size_t *return_len);
+
+static
+int session_include_description(soa_session_t *soa,
+ int session,
+ msg_t *msg,
+ sip_t *sip);
+
+static
+int session_make_description(su_home_t *home,
+ soa_session_t *soa,
+ int session,
+ sip_content_disposition_t **return_cd,
+ sip_content_type_t **return_ct,
+ sip_payload_t **return_pl);
+
+static
+int session_process_response(nua_handle_t *nh,
+ nua_client_request_t *cr,
+ nta_outgoing_t *orq,
+ sip_t const *sip,
+ char const **return_received);
+
+static
+int respond_with_retry_after(nua_handle_t *nh, nta_incoming_t *irq,
+ int status, char const *phrase,
+ int min, int max);
+
+/**@fn void nua_invite(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
+ *
+ * Place a call using SIP INVITE method.
+ *
+ * Incomplete call can be hung-up with nua_cancel(). Complete or incomplete
+ * calls can be hung-up with nua_bye().
+ *
+ * Optionally
+ * - uses early media if NUTAG_EARLY_MEDIA() tag is used with non zero-value
+ * - media parameters can be set by SOA tags
+ * - nua_invite() can be used to change status of an existing call:
+ * - #SOATAG_HOLD tag can be used to list the media that will be put on hold,
+ * the value "*" sets all the media beloginging to the session on hold
+ *
+ * @param nh Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return
+ * nothing
+ *
+ * @par Related Tags:
+ * NUTAG_URL() \n
+ * Tags of nua_set_hparams() \n
+ * NUTAG_INCLUDE_EXTRA_SDP() \n
+ * SOATAG_HOLD(), SOATAG_AF(), SOATAG_ADDRESS(),
+ * SOATAG_RTP_SELECT(), SOATAG_RTP_SORT(), SOATAG_RTP_MISMATCH(),
+ * SOATAG_AUDIO_AUX(), \n
+ * SOATAG_USER_SDP() or SOATAG_USER_SDP_STR() \n
+ * See use of tags in <sip_tag.h> below
+ *
+ * @par Events:
+ * #nua_r_invite \n
+ * #nua_i_state (#nua_i_active, #nua_i_terminated) \n
+ * #nua_i_media_error \n
+ * #nua_i_fork \n
+ *
+ * @par Populating SIP Request Message with Tagged Arguments
+ * The tagged arguments can be used to pass values for any SIP headers to
+ * the stack. When the INVITE message (or any other SIP message) is created,
+ * the tagged values saved with nua_handle() are used first, next the tagged
+ * values given with the operation (nua_invite()) are added.
+ *
+ * @par
+ * When multiple tags for the same header are specified, the behaviour
+ * depends on the header type. If only a single header field can be included
+ * in a SIP message, the latest non-NULL value is used, e.g., @Subject.
+ * However, if the SIP header can consist of multiple lines or header fields
+ * separated by comma, e.g., @Accept, all the tagged
+ * values are concatenated.
+ *
+ * @par
+ * However, if a tag value is #SIP_NONE (-1 casted as a void pointer), the
+ * values from previous tags are ignored.
+ *
+ * @par
+ * Next, values previously set with nua_set_params() or nua_set_hparams()
+ * are used: @Allow, @Supported, @Organization, and @UserAgent headers are
+ * added to the request if they are not already set.
+ *
+ * @par
+ * Now, the target URI for the request needs to be determined.
+ *
+ * @par
+ * For initial INVITE requests, values from tags are used. If NUTAG_URL() is
+ * given, it is used as target URI. Otherwise, if SIPTAG_TO() is given, it
+ * is used as target URI. If neither is given, the complete request line
+ * already specified using SIPTAG_REQUEST() or SIPTAG_REQUEST_STR() is used.
+ * If none of the tags above are given, an internal error is returned to the
+ * application. At this point, the target URI is stored in the request line,
+ * together with method name ("INVITE") and protocol version ("SIP/2.0").
+ * The initial dialog information is also created: @CallID, @CSeq headers
+ * are generated, if they do not exist, and tag is added to @From header.
+ *
+ * @par
+ * For in-dialog INVITE (re-INVITE), the request URI is taken from the
+ * @Contact header received from the remote party during the dialog
+ * establishment. Also, the @CallID and @CSeq headers and @From and @To tags
+ * are generated based on the dialog information and added to the request.
+ * If the dialog has a route (set by @RecordRoute headers), it is added to
+ * the request, too.
+ *
+ * @par
+ * @MaxForwards header (with default value set by NTATAG_MAX_FORWARDS()) is
+ * also added now, if it does not exist.
+ *
+ * @par
+ * Next, the stack generates a @Contact header for the request (Unless the
+ * application already gave a @Contact header or it does not want to use
+ * @Contact and indicates that by including SIPTAG_CONTACT(NULL) or
+ * SIPTAG_CONTACT(SIP_NONE) in the tagged parameters.) If the application
+ * has registered the URI in @From header, the @Contact header used with
+ * registration is used. Otherwise, the @Contact header is generated from the
+ * local IP address and port number.
+ *
+ * @par
+ * For the initial INVITE requests, @ServiceRoute set received from
+ * the registrar is also added to the request message.
+ *
+ * @par
+ * The INVITE request message created by nua_invite() operation is saved as
+ * a template for automatic re-INVITE requests sent by the session timer
+ * ("timer") feature (see NUTAG_SESSION_TIMER() for more details). Please
+ * note that the template message is not used when ACK, PRACK, UPDATE or
+ * INFO requests are created (however, these requests will include
+ * dialog-specific headers like @To, @From, and @CallID as well as
+ * preference headers @Allow, @Supported, @UserAgent, @Organization).
+ *
+ * @par SDP Handling
+ * The initial nua_invite() creates a @ref soa_session_t "soa media session"
+ * unless NUTAG_MEDIA_ENABLE(0) has been given. The SDP description of the
+ * @ref soa_session_t "soa media session" is included in the INVITE request
+ * as message body.
+ *
+ * @par
+ * The SDP in a 1XX or 2XX response message is interpreted as an answer,
+ * given to the @ref soa_session_t "soa media session" object for
+ * processing.
+ *
+ * @bug If the INVITE request already contains a message body, SDP is not
+ * added. Also, if the response contains a multipart body, it is not parsed.
+ *
+ * @par Authentication
+ * The INVITE request may need authentication. Each proxy or server
+ * requiring authentication can respond with 401 or 407 response. The
+ * nua_authenticate() operation stores authentication information (username
+ * and password) to the handle, and stack tries to authenticate all the rest
+ * of the requests (e.g., PRACK, ACK, UPDATE, re-INVITE, BYE) using same
+ * username and password.
+ *
+ * @sa @ref nua_call_model, #nua_r_invite, #nua_i_state, \n
+ * nua_handle_has_active_call() \n
+ * nua_handle_has_call_on_hold()\n
+ * nua_handle_has_invite() \n
+ * nua_authenticate() \n
+ * nua_prack() \n
+ * nua_update() \n
+ * nua_info() \n
+ * nua_cancel() \n
+ * nua_bye() \n
+ * #nua_i_invite, nua_respond()
+ */
+
+/* Tags not implemented
+ * NUTAG_REFER_PAUSE() \n
+ */
+int
+nua_stack_invite(nua_t *nua, nua_handle_t *nh, nua_event_t e,
+ tagi_t const *tags)
+{
+ char const *what;
+
+ if (nh_is_special(nh) ||
+ nua_stack_set_handle_special(nh, nh_has_invite, nua_i_error))
+ what = "Invalid handle for INVITE";
+ else if (nh_referral_check(nh, tags) < 0) {
+ what = "Invalid referral";
+ }
+ else if (nua_stack_init_handle(nua, nh, TAG_NEXT(tags)) < 0) {
+ what = "Handle initialization failed";
+ }
+ else
+ return nua_stack_invite2(nua, nh, e, 0, tags);
+
+ UA_EVENT2(e, 900, what);
+
+ signal_call_state_change(nh, NULL, 900, what, nua_callstate_init, 0, 0);
+
+ return e;
+}
+
+static int
+nua_stack_invite2(nua_t *nua, nua_handle_t *nh, nua_event_t e,
+ int restarted,
+ tagi_t const *tags)
+{
+ nua_dialog_usage_t *du;
+ nua_session_usage_t *ss;
+ nua_client_request_t *cr;
+ int offer_sent = 0;
+
+ msg_t *msg = NULL;
+ sip_t *sip = NULL;
+
+ char const *what;
+
+ du = nua_dialog_usage_add(nh, nh->nh_ds, nua_session_usage, NULL);
+ ss = nua_dialog_usage_private(du);
+ cr = ss->ss_crequest;
+ what = nua_internal_error; /* Internal error */
+
+ if (du == NULL)
+ goto failure;
+
+ if (cr->cr_orq) {
+ what = "INVITE request already in progress";
+ goto failure;
+ }
+
+ if (ss->ss_state == nua_callstate_terminated)
+ ss->ss_state = nua_callstate_init;
+
+ if (!restarted) {
+ session_timer_preferences(ss,
+ NH_PGET(nh, session_timer),
+ NH_PGET(nh, min_se),
+ NH_PGET(nh, refresher));
+ }
+
+ if (restarted && !cr->cr_msg) {
+ if (du->du_msg)
+ cr->cr_msg = msg_dup(du->du_msg);
+ else
+ restarted = 0;
+ }
+
+ msg = nua_creq_msg(nua, nh, cr, restarted,
+ SIP_METHOD_INVITE,
+ NUTAG_USE_DIALOG(1),
+ NUTAG_ADD_CONTACT(1),
+ TAG_NEXT(tags));
+ sip = sip_object(msg);
+
+ if (!sip) {
+ what = "Cannot Initialize Request";
+ goto failure;
+ }
+
+ if (!restarted) {
+ msg_destroy(du->du_msg), du->du_msg = msg_dup(msg);
+ }
+
+ if (nh->nh_soa) {
+ soa_init_offer_answer(nh->nh_soa);
+
+ if (sip->sip_payload)
+ offer_sent = 0;
+ else if (soa_generate_offer(nh->nh_soa, 0, NULL) < 0)
+ offer_sent = -1;
+ else
+ offer_sent = 1;
+ }
+
+ if (offer_sent >= 0) {
+ sip_time_t invite_timeout = NH_PGET(nh, invite_timeout);
+ if (invite_timeout == 0)
+ invite_timeout = UINT_MAX;
+ /* Cancel if we don't get response within timeout*/
+ nua_dialog_usage_set_expires(du, invite_timeout);
+ nua_dialog_usage_set_refresh(du, 0);
+
+ /* Add session timer headers */
+ if (session_timer_is_supported(nh))
+ use_session_timer(ss, 0, prefer_session_timer(nh), msg, sip);
+
+ ss->ss_100rel = NH_PGET(nh, early_media);
+ ss->ss_precondition = sip_has_feature(sip->sip_require, "precondition");
+
+ if (ss->ss_precondition)
+ ss->ss_update_needed = ss->ss_100rel = 1;
+
+ if (offer_sent > 0 &&
+ session_include_description(nh->nh_soa, 1, msg, sip) < 0) {
+ what = "Internal media error"; goto failure;
+ }
+
+ if (nh->nh_soa &&
+ NH_PGET(nh, media_features) && !nua_dialog_is_established(nh->nh_ds) &&
+ !sip->sip_accept_contact && !sip->sip_reject_contact) {
+ sip_accept_contact_t ac[1];
+ sip_accept_contact_init(ac);
+
+ ac->cp_params = (msg_param_t *)
+ soa_media_features(nh->nh_soa, 1, msg_home(msg));
+
+ if (ac->cp_params) {
+ msg_header_replace_param(msg_home(msg), ac->cp_common, "explicit");
+ sip_add_dup(msg, sip, (sip_header_t *)ac);
+ }
+ }
+
+ if (nh->nh_auth) {
+ if (auc_authorize(&nh->nh_auth, msg, sip) < 0) {
+ what = "Internal authentication error"; goto failure;
+ }
+ }
+
+ cr->cr_orq = nta_outgoing_mcreate(nua->nua_nta,
+ process_response_to_invite, nh, NULL,
+ msg,
+ NTATAG_REL100(ss->ss_100rel),
+ SIPTAG_END(), TAG_NEXT(tags));
+
+ if (cr->cr_orq) {
+ cr->cr_offer_sent = offer_sent;
+ cr->cr_usage = du;
+ du->du_refresh = 0;
+ signal_call_state_change(nh, ss, 0, "INVITE sent",
+ nua_callstate_calling, 0,
+ offer_sent ? "offer" : 0);
+ return cr->cr_event = e;
+ }
+ }
+
+ failure:
+
+ msg_destroy(msg);
+ if (du && !du->du_ready)
+ nua_dialog_usage_remove(nh, nh->nh_ds, du), ss = NULL;
+
+ UA_EVENT2(e, 900, what);
+ signal_call_state_change(nh, ss, 900, what, nua_callstate_init, 0, 0);
+
+ return e;
+}
+
+/** @NUA_EVENT nua_r_invite
+ *
+ * Answer to outgoing INVITE.
+ *
+ * The INVITE may be sent explicitly by nua_invite() or
+ * implicitly by NUA state machine.
+ *
+ * @param status response status code
+ * (if the request is retried, @a status is 100, the @a
+ * sip->sip_status->st_status contain the real status code
+ * from the response message, e.g., 302, 401, or 407)
+ * @param phrase a short textual description of @a status code
+ * @param nh operation handle associated with the call
+ * @param hmagic application context associated with the call
+ * @param sip response message to INVITE or NULL upon an error
+ * (status code is in @a status and
+ * descriptive message in @a phrase parameters)
+ * @param tags empty
+ *
+ * @sa nua_invite(), @ref nua_call_model, #nua_i_state, #nua_i_invite,
+ * nua_ack(), NUTAG_AUTOACK()
+ *
+ * @END_NUA_EVENT
+ */
+
+static int process_response_to_invite(nua_handle_t *nh,
+ nta_outgoing_t *orq,
+ sip_t const *sip)
+{
+ nua_t *nua = nh->nh_nua;
+ nua_client_request_t *cr;
+ nua_dialog_usage_t *du;
+ nua_session_usage_t *ss;
+ int status = sip->sip_status->st_status;
+ char const *phrase = sip->sip_status->st_phrase;
+ int terminated = 0;
+ int gracefully = 1;
+ char const *received = NULL;
+
+ cr = nua_client_request_by_orq(nh->nh_ds->ds_cr, orq);
+ du = cr ? cr->cr_usage : NULL;
+ ss = nua_dialog_usage_private(du);
+
+ assert(cr && du && ss);
+
+ if (ss->ss_state == nua_callstate_terminating && 200 <= status) {
+ /*
+ * If the call is being terminated but re-INVITE was responded with 2XX
+ * re-send the BYE, otherwise terminate the call.
+ */
+ gracefully = status < 300, terminated = !gracefully;
+ }
+ else if (status >= 300) {
+ if (sip->sip_retry_after)
+ gracefully = 0;
+
+ terminated = sip_response_terminates_dialog(status, sip_method_invite,
+ &gracefully);
+
+ if (!terminated) {
+ if (check_session_timer_restart(nh, ss, cr, orq, sip, restart_invite))
+ return 0;
+
+ if (ss->ss_state < nua_callstate_ready)
+ terminated = 1;
+ }
+ }
+ else if (status >= 200) {
+ du->du_ready = 1;
+ cr->cr_usage = NULL;
+
+ /* XXX - check remote tag, handle forks */
+ /* Set route, contact, nh_ds->ds_remote_tag */
+ nua_dialog_uac_route(nh, nh->nh_ds, sip, 1);
+ nua_dialog_store_peer_info(nh, nh->nh_ds, sip);
+
+ init_session_timer(ss, sip, NH_PGET(nh, refresher));
+ set_session_timer(ss);
+
+ /* signal_call_state_change */
+ if (session_process_response(nh, cr, orq, sip, &received) >= 0) {
+ ss->ss_ack_needed = received ? received : "";
+
+ if (NH_PGET(nh, auto_ack) ||
+ /* Auto-ACK response to re-INVITE unless auto_ack is set to 0 */
+ (ss->ss_state == nua_callstate_ready &&
+ !NH_PISSET(nh, auto_ack)))
+ nua_stack_ack(nua, nh, nua_r_ack, NULL);
+ else
+ signal_call_state_change(nh, ss, status, phrase,
+ nua_callstate_completing, received, 0);
+ nh_referral_respond(nh, SIP_200_OK);
+ return 0;
+ }
+
+ status = 500, phrase = "Malformed Session in Response";
+
+ nua_stack_ack(nua, nh, nua_r_ack, NULL);
+ gracefully = 1;
+ }
+ else if (sip->sip_rseq) {
+ /* Reliable provisional response */
+ nh_referral_respond(nh, status, phrase);
+
+ return process_100rel(nh, ss, orq, sip); /* signal_call_state_change */
+ }
+ else {
+ /* Provisional response */
+ nh_referral_respond(nh, status, phrase);
+ session_process_response(nh, cr, orq, sip, &received);
+ signal_call_state_change(nh, ss, status, phrase,
+ nua_callstate_proceeding, received, 0);
+ return 0;
+ }
+
+ cr->cr_usage = NULL;
+
+ nh_referral_respond(nh, status, phrase);
+ nua_stack_process_response(nh, cr, orq, sip, TAG_END());
+
+ if (terminated)
+ signal_call_state_change(nh, ss, status, phrase,
+ nua_callstate_terminated, 0, 0);
+
+ if (terminated < 0) {
+ nua_dialog_terminated(nh, nh->nh_ds, status, phrase);
+ }
+ else if (terminated > 0) {
+ nua_dialog_usage_remove(nh, nh->nh_ds, du);
+ }
+ else if (gracefully) {
+ char *reason =
+ su_sprintf(NULL, "SIP;cause=%u;text=\"%s\"",
+ status > 699 ? 500 : status, phrase);
+
+ signal_call_state_change(nh, ss, status, phrase,
+ nua_callstate_terminating, 0, 0);
+
+ nua_stack_post_signal(nh, nua_r_bye,
+ SIPTAG_REASON_STR(reason),
+ TAG_END());
+
+ su_free(NULL, reason);
+ }
+
+ return 0;
+}
+
+/**@fn void nua_ack(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
+ *
+ * Acknowledge a succesful response to INVITE request.
+ *
+ * Acknowledge a successful response (200..299) to INVITE request with the
+ * SIP ACK request message. This function is need only if NUTAG_AUTOACK()
+ * parameter has been cleared.
+ *
+ * @param nh Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return
+ * nothing
+ *
+ * @par Related Tags:
+ * Tags in <sip_tag.h>
+ *
+ * @par Events:
+ * #nua_i_media_error \n
+ * #nua_i_state (#nua_i_active, #nua_i_terminated)
+ *
+ * @sa NUTAG_AUTOACK(), @ref nua_call_model, #nua_i_state
+ */
+
+int nua_stack_ack(nua_t *nua, nua_handle_t *nh, nua_event_t e,
+ tagi_t const *tags)
+{
+ nua_session_usage_t *ss;
+ nua_client_request_t *cr;
+ nta_outgoing_t *ack = NULL;
+ msg_t *msg;
+ sip_t *sip;
+ int status = 200;
+ char const *phrase = "OK", *reason = NULL, *sent = NULL;
+ char const *received;
+
+ ss = nua_session_usage_get(nh->nh_ds);
+ cr = ss->ss_crequest;
+
+ received = ss ? ss->ss_ack_needed : NULL;
+
+ if (!received)
+ return UA_EVENT2(nua_i_error, 900, "No response to ACK");
+
+ ss->ss_ack_needed = 0;
+
+ if (!received[0])
+ received = NULL;
+
+ if (tags)
+ nua_stack_set_params(nua, nh, nua_i_error, tags);
+
+ msg = nua_creq_msg(nua, nh, cr, 0,
+ SIP_METHOD_ACK,
+ /* NUTAG_COPY(0), */
+ TAG_NEXT(tags));
+ sip = sip_object(msg);
+
+ if (sip && nh->nh_soa) {
+ if (tags)
+ soa_set_params(nh->nh_soa, TAG_NEXT(tags));
+
+ if (cr->cr_offer_recv && !cr->cr_answer_sent) {
+ if (soa_generate_answer(nh->nh_soa, NULL) < 0 ||
+ session_include_description(nh->nh_soa, 1, msg, sip) < 0) {
+ reason = soa_error_as_sip_reason(nh->nh_soa);
+ status = 900, phrase = "Internal media error";
+ reason = "SIP;cause=500;text=\"Internal media error\"";
+ }
+ else {
+ cr->cr_answer_sent = 1;
+ soa_activate(nh->nh_soa, NULL);
+
+ /* signal that O/A round is complete */
+ sent = "answer";
+ }
+ }
+
+ if (!reason &&
+ /* ss->ss_offer_sent && !ss->ss_answer_recv */
+ !soa_is_complete(nh->nh_soa)) {
+ /* No SDP answer in 2XX response -> terminate call */
+ status = 988, phrase = "Incomplete offer/answer";
+ reason = "SIP;cause=488;text=\"Incomplete offer/answer\"";
+ }
+ }
+
+ if (sip) {
+ msg_t *imsg = nta_outgoing_getrequest(cr->cr_orq);
+ sip_t const *isip = sip_object(imsg);
+ if (isip->sip_proxy_authorization)
+ sip_add_dup(msg, sip, (void *)isip->sip_proxy_authorization);
+ if (isip->sip_authorization)
+ sip_add_dup(msg, sip, (void *)isip->sip_authorization);
+ msg_destroy(imsg);
+ }
+
+ if (sip)
+ ack = nta_outgoing_mcreate(nua->nua_nta, NULL, NULL, NULL, msg,
+ SIPTAG_END(), TAG_NEXT(tags));
+
+ if (!ack) {
+ if (!reason) {
+ status = 900, phrase = "Cannot send ACK";
+ reason = "SIP;cause=500;text=\"Internal Error\"";
+ }
+ msg_destroy(msg);
+ }
+
+ nua_creq_deinit(cr, NULL); /* Destroy INVITE transaction */
+ nta_outgoing_destroy(ack); /* TR engine keeps this around for T2 */
+
+ if (status < 300) {
+ signal_call_state_change(nh, ss, status, phrase, nua_callstate_ready,
+ received, sent);
+ }
+ else {
+ signal_call_state_change(nh, ss, status, phrase, nua_callstate_terminating,
+ 0, 0);
+ nua_stack_post_signal(nh, nua_r_bye,
+ SIPTAG_REASON_STR(reason),
+ TAG_END());
+ }
+
+ return 0;
+}
+
+
+/* Process reliable provisional response */
+static int
+process_100rel(nua_handle_t *nh,
+ nua_session_usage_t *ss,
+ nta_outgoing_t *orq,
+ sip_t const *sip)
+{
+ nua_client_request_t *cr_invite = ss->ss_crequest;
+ nua_client_request_t *cr_prack = nh->nh_ds->ds_cr;
+
+ sip_rseq_t *rseq;
+ char const *recv = NULL;
+ int status; char const *phrase;
+
+ if (cr_prack->cr_orq) {
+ /* XXX - better luck next time */
+ SU_DEBUG_3(("nua(%p): cannot send PRACK because %s is pending\n", nh,
+ nta_outgoing_method_name(cr_prack->cr_orq)));
+ return 0; /* Wait until this response is re-transmitted */
+ }
+
+ if (!nua_dialog_is_established(nh->nh_ds)) {
+ /* Establish early dialog */
+ nua_dialog_uac_route(nh, nh->nh_ds, sip, 1);
+ nua_dialog_store_peer_info(nh, nh->nh_ds, sip);
+
+ /* Tag the INVITE request */
+ cr_invite->cr_orq =
+ nta_outgoing_tagged(orq, process_response_to_invite, nh,
+ sip->sip_to->a_tag, sip->sip_rseq);
+ nta_outgoing_destroy(orq);
+ orq = cr_invite->cr_orq;
+ }
+
+ assert(sip);
+
+ status = sip->sip_status->st_status, phrase = sip->sip_status->st_phrase;
+ rseq = sip->sip_rseq;
+
+ if (!rseq) {
+ SU_DEBUG_5(("nua(%p): 100rel missing RSeq\n", nh));
+ }
+ else if (rseq->rs_response <= nta_outgoing_rseq(orq)) {
+ SU_DEBUG_5(("nua(%p): 100rel bad RSeq %u (got %u)\n", nh,
+ (unsigned)rseq->rs_response,
+ nta_outgoing_rseq(orq)));
+ /* XXX - send nua_r_invite event or not? */
+ return 0;
+ }
+ else if (nta_outgoing_setrseq(orq, rseq->rs_response) < 0) {
+ SU_DEBUG_1(("nua(%p): cannot set RSeq %u\n", nh,
+ (unsigned)rseq->rs_response));
+ }
+ else if (session_process_response(nh, cr_invite, orq, sip, &recv) < 0) {
+ assert(nh->nh_soa);
+ status = soa_error_as_sip_response(nh->nh_soa, &phrase);
+ nua_stack_event(nh->nh_nua, nh, NULL,
+ nua_i_media_error, status, phrase, TAG_END());
+ }
+ /* Here we could let application PRACK and just send state event */
+ else {
+ sip_rack_t rack[1];
+ tagi_t tags[] = {
+ { TAG_SKIP(nua_stack_prack) }, /* this is autoprack */
+ { NUTAG_STATUS(status), },
+ { NUTAG_PHRASE(phrase), },
+ { NUTAG_PHRASE(recv), },
+ { SIPTAG_RACK(rack) },
+ { TAG_END() }
+ };
+
+ sip_rack_init(rack);
+
+ rack->ra_response = sip->sip_rseq->rs_response;
+ rack->ra_cseq = sip->sip_cseq->cs_seq;
+ rack->ra_method = sip->sip_cseq->cs_method;
+ rack->ra_method_name = sip->sip_cseq->cs_method_name;
+
+ nua_stack_prack(nh->nh_nua, nh, nua_r_prack, tags);
+
+ return 0;
+ }
+
+ /* XXX - CANCEL INVITE or BYE this session? */
+ /* Because we don't do forking very well we just cancel INVITE */
+ nua_stack_cancel(nh->nh_nua, nh, nua_r_cancel, NULL);
+
+ return 0;
+}
+
+/**@fn void nua_prack(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
+ * Send a PRACK request.
+ *
+ * PRACK is used to acknowledge receipt of 100rel responses. See @RFC3262.
+ *
+ * @param nh Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return
+ * nothing
+ *
+ * @par Related Tags:
+ * Tags in <sofia-sip/soa_tag.h>, <sofia-sip/sip_tag.h>.
+ *
+ * @par Events:
+ * #nua_r_prack
+ */
+
+/** @NUA_EVENT nua_r_prack
+ *
+ * Response to an outgoing @b PRACK request. PRACK request is used to
+ * acknowledge reliable preliminary responses and it is usually sent
+ * automatically by the nua stack.
+ *
+ * @param status response status code
+ * (if the request is retried, @a status is 100, the @a
+ * sip->sip_status->st_status contain the real status code
+ * from the response message, e.g., 302, 401, or 407)
+ * @param phrase a short textual description of @a status code
+ * @param nh operation handle associated with the call
+ * @param hmagic application context associated with the call
+ * @param sip response to @b PRACK or NULL upon an error
+ * (status code is in @a status and
+ * descriptive message in @a phrase parameters)
+ * @param tags empty
+ *
+ * @sa nua_prack(), #nua_i_prack, @RFC3262
+ *
+ * @END_NUA_EVENT
+ */
+
+
+int nua_stack_prack(nua_t *nua, nua_handle_t *nh, nua_event_t e,
+ tagi_t const *tags)
+{
+ nua_session_usage_t *ss;
+ nua_client_request_t *cr;
+ msg_t *msg;
+ sip_t *sip;
+ int offer_sent_in_prack = 0, answer_sent_in_prack = 0;
+
+ int status = 0; char const *phrase = "PRACK sent";
+ char const *recv = NULL, *sent = NULL;
+
+ int autoprack = /* XXX - should have common indication */
+ tags && tags->t_tag == tag_skip &&
+ tags->t_value == (tag_value_t)nua_stack_prack;
+
+ if (autoprack) {
+ status = (int)tags[1].t_value;
+ phrase = (char const *)tags[2].t_value;
+ recv = (char const *)tags[3].t_value;
+ tags += 4;
+ }
+
+ ss = nua_session_usage_get(nh->nh_ds);
+
+ if (!ss || !ss->ss_crequest || !nta_outgoing_rseq(ss->ss_crequest->cr_orq))
+ return UA_EVENT2(e, 900, "Nothing to PRACK");
+ else if (nh->nh_ds->ds_cr->cr_orq)
+ return UA_EVENT2(e, 900, "Request already in progress");
+
+ nua_stack_init_handle(nua, nh, TAG_NEXT(tags));
+
+ cr = nh->nh_ds->ds_cr;
+
+ msg = nua_creq_msg(nua, nh, cr, cr->cr_retry_count,
+ SIP_METHOD_PRACK,
+ NUTAG_USE_DIALOG(1),
+ NUTAG_ADD_CONTACT(1),
+ TAG_NEXT(tags));
+
+ sip = sip_object(msg);
+
+ if (sip) {
+ nua_client_request_t *cri = ss->ss_crequest;
+ if (nh->nh_soa == NULL)
+ /* It is up to application to handle SDP */;
+ else if (sip->sip_payload)
+ /* XXX - we should just do MIME in session_include_description() */;
+ else if (cri->cr_offer_recv && !cri->cr_answer_sent) {
+
+ if (soa_generate_answer(nh->nh_soa, NULL) < 0 ||
+ session_include_description(nh->nh_soa, 1, msg, sip) < 0) {
+
+ status = soa_error_as_sip_response(nh->nh_soa, &phrase);
+ SU_DEBUG_3(("nua(%p): PRACK answer: %d %s\n", nh, status, phrase));
+ nua_stack_event(nh->nh_nua, nh, NULL,
+ nua_i_media_error, status, phrase, TAG_END());
+
+ goto error;
+ }
+ else {
+ answer_sent_in_prack = 1, sent = "answer";
+ soa_activate(nh->nh_soa, NULL);
+ }
+ }
+ /* When 100rel response status was 183 fake support for preconditions */
+ else if (autoprack && status == 183 && ss->ss_precondition) {
+
+ if (soa_generate_offer(nh->nh_soa, 0, NULL) < 0 ||
+ session_include_description(nh->nh_soa, 1, msg, sip) < 0) {
+
+ status = soa_error_as_sip_response(nh->nh_soa, &phrase);
+ SU_DEBUG_3(("nua(%p): PRACK offer: %d %s\n", nh, status, phrase));
+ nua_stack_event(nh->nh_nua, nh, NULL,
+ nua_i_media_error, status, phrase, TAG_END());
+ goto error;
+ }
+ else {
+ offer_sent_in_prack = 1, sent = "offer";
+ }
+ }
+
+ if (nh->nh_auth) {
+ if (auc_authorize(&nh->nh_auth, msg, sip) < 0)
+ /* xyzzy */;
+ }
+
+ cr->cr_orq = nta_outgoing_mcreate(nua->nua_nta,
+ process_response_to_prack, nh, NULL,
+ msg,
+ SIPTAG_END(), TAG_NEXT(tags));
+ if (cr->cr_orq) {
+ cr->cr_usage = nua_dialog_usage_public(ss);
+ cr->cr_event = nua_r_prack;
+
+ if (answer_sent_in_prack)
+ cri->cr_answer_sent = 1;
+ else if (offer_sent_in_prack)
+ cr->cr_offer_sent = 1;
+
+ if (autoprack)
+ signal_call_state_change(nh, ss, status, phrase,
+ nua_callstate_proceeding, recv, sent);
+ else
+ signal_call_state_change(nh, ss, 0, "PRACK sent",
+ nua_callstate_proceeding, NULL, sent);
+
+
+ return cr->cr_event = e;
+ }
+ }
+
+ error:
+ msg_destroy(msg);
+ return UA_EVENT1(e, NUA_INTERNAL_ERROR);
+}
+
+void restart_prack(nua_handle_t *nh, tagi_t *tags)
+{
+ nua_creq_restart(nh, nh->nh_ds->ds_cr, process_response_to_prack, tags);
+}
+
+
+static int
+process_response_to_prack(nua_handle_t *nh,
+ nta_outgoing_t *orq,
+ sip_t const *sip)
+{
+ nua_client_request_t *cr = nh->nh_ds->ds_cr;
+ nua_session_usage_t *ss = nua_dialog_usage_private(cr->cr_usage);
+ int status;
+ char const *phrase = "OK", *reason = NULL, *recv = NULL;
+
+ assert(cr->cr_usage && cr->cr_usage->du_class == nua_session_usage);
+
+ if (sip)
+ status = sip->sip_status->st_status, phrase = sip->sip_status->st_phrase;
+ else
+ status = 408, phrase = sip_408_Request_timeout;
+
+ SU_DEBUG_5(("nua: process_response_to_prack: %u %s\n", status, phrase));
+
+ if (nua_creq_check_restart(nh, cr, orq, sip, restart_prack))
+ return 0;
+
+ if (status < 200)
+ return 0;
+
+ cr->cr_usage = NULL;
+
+ if (status < 300) {
+ if (session_process_response(nh, cr, orq, sip, &recv) < 0) {
+ status = 900, phrase = "Malformed Session in Response";
+ reason = "SIP;status=400;phrase=\"Malformed Session in Response\"";
+ }
+ }
+ else
+ nua_stack_process_response(nh, cr, orq, sip, TAG_END());
+
+ if (recv)
+ signal_call_state_change(nh, ss, status, phrase,
+ nua_callstate_proceeding, recv, NULL);
+
+ if (status < 300 && ss->ss_update_needed)
+ nua_stack_update(nh->nh_nua, nh, nua_r_update, NULL);
+
+ return 0;
+}
+
+/** Refresh session usage */
+static void nua_session_usage_refresh(nua_handle_t *nh,
+ nua_dialog_state_t *ds,
+ nua_dialog_usage_t *du,
+ sip_time_t now)
+{
+ tagi_t const timer_tags[2] = {
+ { SIPTAG_SUBJECT_STR("Session refresh") },
+ { TAG_END() }
+ };
+ tagi_t const refresh_tags[2] = {
+ { SIPTAG_SUBJECT_STR("Dialog refresh") },
+ { TAG_END() }
+ };
+
+ nua_session_usage_t const *ss = nua_dialog_usage_private(du);
+ nua_client_request_t const *cri = ss->ss_crequest, *cro = ds->ds_cr;
+ nua_server_request_t const *sr;
+
+ for (sr = ds->ds_sr; sr; sr = sr->sr_next)
+ if (sr->sr_usage == du &&
+ (sr->sr_method == sip_method_invite ||
+ sr->sr_method == sip_method_update))
+ break;
+
+ /* INVITE or UPDATE in progress or being authenticated */
+ if ((cri && cri->cr_orq) || sr)
+ return;
+ if (ss->ss_state >= nua_callstate_terminating)
+ return;
+
+ if (!ss->ss_refresher) {
+ if (now >= du->du_expires)
+ session_timeout(nh, du, now);
+ else
+ /* Refreshing contact & route set */
+ nua_stack_invite2(nh->nh_nua, nh, nua_r_invite, 1, refresh_tags);
+ }
+ else if (NH_PGET(nh, update_refresh)) {
+ if (!cro->cr_orq)
+ nua_stack_update(nh->nh_nua, nh, nua_r_update, timer_tags);
+ else
+ nua_dialog_usage_refresh_range(du, 5, 15);
+ }
+ else {
+ nua_stack_invite2(nh->nh_nua, nh, nua_r_invite, 1, timer_tags);
+ }
+}
+
+static
+char const reason_timeout[] = "SIP;cause=408;text=\"Session timeout\"";
+
+static void
+session_timeout(nua_handle_t *nh, nua_dialog_usage_t *du, sip_time_t now)
+{
+ if (now > 1) {
+ nua_session_usage_t *ss = nua_dialog_usage_private(du);
+
+ signal_call_state_change(nh, ss, 408, "Session Timeout",
+ nua_callstate_terminating, NULL, NULL);
+
+ nua_stack_post_signal(nh, nua_r_bye,
+ SIPTAG_REASON_STR(reason_timeout),
+ TAG_END());
+ }
+}
+
+/** Terminate usage/dialog/handle/agent gracefully */
+static int nua_session_usage_shutdown(nua_handle_t *nh,
+ nua_dialog_state_t *ds,
+ nua_dialog_usage_t *du)
+{
+ nua_session_usage_t *ss = nua_dialog_usage_private(du);
+ nua_client_request_t *cr;
+ nua_server_request_t *sr, *sr_next;
+ int status;
+
+ /* Zap client-side invite transaction */
+ if (ss->ss_crequest->cr_orq) {
+ cr = ss->ss_crequest;
+ status = nta_outgoing_status(cr->cr_orq);
+
+ if (status < 200)
+ nta_outgoing_tcancel(cr->cr_orq, NULL, NULL, TAG_END());
+
+ if (ss->ss_ack_needed) {
+ msg_t *ack = nua_creq_msg(nh->nh_nua, nh, cr, 0,
+ SIP_METHOD_ACK,
+ TAG_END());
+ nta_outgoing_mcreate(nh->nh_nua->nua_nta, NULL, NULL, NULL,
+ ack, TAG_END());
+ }
+
+ nua_creq_deinit(cr, NULL);
+ }
+
+ /* Zap server-side transactions */
+ for (sr = ds->ds_sr; sr; sr = sr_next) {
+ sr_next = sr->sr_next;
+ if (sr->sr_usage == du) {
+ assert(sr->sr_usage == du);
+ sr->sr_usage = NULL;
+ if (sr->sr_respond)
+ nua_server_respond(sr, SIP_480_TEMPORARILY_UNAVAILABLE, TAG_END());
+ else
+ nua_server_request_destroy(sr);
+ }
+ }
+
+ assert(ss == nua_session_usage_get(nh->nh_ds));
+
+ switch (ss->ss_state) {
+ case nua_callstate_completing:
+ case nua_callstate_ready:
+ case nua_callstate_completed:
+ {
+ msg_t *bye;
+
+ cr = ds->ds_cr;
+ nua_creq_deinit(cr, NULL);
+ bye = nua_creq_msg(nh->nh_nua, nh, ds->ds_cr, 0,
+ SIP_METHOD_BYE,
+ TAG_END());
+ cr->cr_orq = nta_outgoing_mcreate(nh->nh_nua->nua_nta,
+ NULL, NULL, NULL,
+ bye,
+ TAG_END());
+ nua_creq_deinit(cr, NULL);
+ }
+ }
+
+ nua_dialog_usage_remove(nh, ds, du);
+
+ return 0;
+}
+
+/** Restart invite (e.g., after 302 or 407) */
+void
+restart_invite(nua_handle_t *nh, tagi_t *tags)
+{
+ nua_stack_invite2(nh->nh_nua, nh, nua_r_invite, 1, tags);
+}
+
+static int process_response_to_cancel(nua_handle_t *nh,
+ nta_outgoing_t *orq,
+ sip_t const *sip);
+
+/**@fn void nua_cancel(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
+ *
+ * Cancel an INVITE operation
+ *
+ * @param nh Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return
+ * nothing
+ *
+ * @par Related Tags:
+ * Tags in <sip_tag.h>
+ *
+ * @par Events:
+ * #nua_r_cancel, #nua_i_state (#nua_i_active, #nua_i_terminated)
+ *
+ * @sa @ref nua_call_model, nua_invite(), #nua_i_cancel
+ */
+
+int
+nua_stack_cancel(nua_t *nua, nua_handle_t *nh, nua_event_t e,
+ tagi_t const *tags)
+{
+ nua_session_usage_t *ss;
+ nua_client_request_t *cri, *crc;
+
+ ss = nua_session_usage_get(nh->nh_ds);
+
+ if (!nh || !ss || !ss->ss_crequest->cr_usage ||
+ nta_outgoing_status(ss->ss_crequest->cr_orq) >= 200) {
+ return UA_EVENT2(e, 481, "No transaction to CANCEL");
+ }
+
+ cri = ss->ss_crequest;
+ crc = nh->nh_ds->ds_cr;
+
+ if (tags)
+ nua_stack_set_params(nua, nh, nua_i_error, tags);
+
+ if (nh && cri->cr_orq && cri->cr_usage) {
+ nta_outgoing_t *orq;
+
+ /* nh_referral_respond(nh, SIP_487_REQUEST_TERMINATED); */
+
+ if (e)
+ orq = nta_outgoing_tcancel(cri->cr_orq, process_response_to_cancel, nh,
+ TAG_NEXT(tags));
+ else
+ orq = nta_outgoing_tcancel(cri->cr_orq, NULL, NULL, TAG_NEXT(tags));
+
+ if (orq == NULL)
+ return nua_stack_event(nua, nh, NULL, e, 400, "Internal error",
+ TAG_END());
+
+ if (e && crc->cr_orq == NULL)
+ crc->cr_orq = orq, crc->cr_event = e;
+ }
+
+ return 0;
+}
+
+/** @NUA_EVENT nua_r_cancel
+ *
+ * Answer to outgoing CANCEL.
+ *
+ * The CANCEL may be sent explicitly by nua_cancel() or implicitly by NUA
+ * state machine.
+ *
+ * @param status response status code
+ * @param phrase a short textual description of @a status code
+ * @param nh operation handle associated with the call
+ * @param hmagic application context associated with the call
+ * @param sip response to CANCEL request or NULL upon an error
+ * (status code is in @a status and
+ * descriptive message in @a phrase parameters)
+ * @param tags empty
+ *
+ * @sa nua_cancel(), @ref nua_uac_call_model, #nua_r_invite, nua_invite(),
+ * #nua_i_state
+ *
+ * @END_NUA_EVENT
+ */
+
+
+
+static int process_response_to_cancel(nua_handle_t *nh,
+ nta_outgoing_t *orq,
+ sip_t const *sip)
+{
+ return nua_stack_process_response(nh, nh->nh_ds->ds_cr, orq, sip, TAG_END());
+}
+
+/* ---------------------------------------------------------------------- */
+/* UAS side of INVITE */
+
+static int respond_to_invite(nua_server_request_t *sr, tagi_t const *tags);
+
+static int
+ preprocess_invite(nua_t *, nua_handle_t *, nua_server_request_t **, sip_t *),
+ session_check_request(nua_t *nua,
+ nua_handle_t *nh,
+ nta_incoming_t *irq,
+ sip_t const *sip),
+ process_invite(nua_t *, nua_handle_t *, nua_server_request_t *, sip_t *),
+ process_prack(nua_handle_t *, nta_reliable_t *, nta_incoming_t *,
+ sip_t const *);
+
+static int
+ process_ack_or_cancel(nua_server_request_t *, nta_incoming_t *,
+ sip_t const *),
+ process_ack(nua_server_request_t *, nta_incoming_t *, sip_t const *),
+ process_cancel(nua_server_request_t *, nta_incoming_t *, sip_t const *),
+ process_timeout(nua_server_request_t *, nta_incoming_t *);
+
+/** @NUA_EVENT nua_i_invite
+ *
+ * Indication of incoming call or re-INVITE request.
+ *
+ * @param status statuscode of response sent automatically by stack
+ * @param phrase a short textual description of @a status code
+ * @param nh operation handle associated with this call
+ * (maybe created for this call)
+ * @param hmagic application context associated with this call
+ * (maybe NULL if call handle was created for this call)
+ * @param sip incoming INVITE request
+ * @param tags SOATAG_ACTIVE_AUDIO(), SOATAG_ACTIVE_VIDEO()
+ *
+ * @par Responding to INVITE with nua_respond()
+ *
+ * If @a status in #nua_i_invite event is below 200, the application should
+ * accept or reject the call with nua_respond(). See the @ref nua_call_model
+ * for the detailed explanation of various options in call processing at
+ * server end.
+ *
+ * The @b INVITE request takes care of session setup using SDP Offer-Answer
+ * negotiation as specified in @RFC3264 (updated in @RFC3262 section 5,
+ * @RFC3311, and @RFC3312). The Offer-Answer can be taken care by
+ * application (if NUTAG_MEDIA_ENABLE(0) parameter has been set) or by the
+ * built-in SDP Offer/Answer engine @soa (by default and when
+ * NUTAG_MEDIA_ENABLE(1) parameter has been set). When @soa is enabled, it
+ * will take care of parsing the SDP, negotiating the media and codecs, and
+ * including the SDP in the SIP message bodies as required by the
+ * Offer-Answer model.
+ *
+ * When @soa is enabled, the SDP in the incoming INVITE is parsed and feed
+ * to a #soa_session_t object. The #nua_i_state event sent to the
+ * application immediately after #nua_i_invite will contain the parsing
+ * results in SOATAG_REMOTE_SDP() and SOATAG_REMOTE_SDP_STR() tags.
+ *
+ * Note that currently the parser within @nua does not handle MIME
+ * multipart. The SDP Offer/Answer engine can get confused if the SDP offer
+ * is included in a MIME multipart, therefore such an @b INVITE is rejected
+ * with <i>415 Unsupported Media Type</i> error response: the client is
+ * expected to retry the INVITE without MIME multipart content.
+ *
+ * If the call is to be accepted, the application should include the SDP in
+ * the 2XX response. If @soa is not disabled with NUTAG_MEDIA_ENABLE(0), the
+ * SDP should be included in the SOATAG_USER_SDP() or SOATAG_USER_SDP_STR()
+ * parameter given to nua_respond(). If it is disabled, the SDP should be
+ * included in message
+ *
+ * @par Preliminary Responses and 100rel
+ *
+ * Call progress can be signaled with preliminary responses (with status
+ * code in the range 101..199). It is possible to conclude the SDP
+ * Offer-Answer negotiation using preliminary responses, too. If
+ * SOATAG_USER_SDP() or SOATAG_USER_SDP_STR() parameter is included with in
+ * a preliminary nua_response(), the SDP answer is generated and sent with
+ * the preliminary responses, too.
+ *
+ * The preliminary responses are sent reliably if feature tag "100rel" is
+ * included in the @Require header of the response or if
+ * NUTAG_EARLY_MEDIA(1) parameter has been given. The reliably delivery of
+ * preliminary responses mean that a sequence number is included in the
+ * @RSeq header in the response message and the response message is resent
+ * until the client responds with a @b PRACK request with matching sequence
+ * number in @RAck header.
+ *
+ * Note that only the "183" response is sent reliably if the
+ * NUTAG_ONLY183_100REL(1) parameter has been given. The reliable
+ * preliminary responses are acknowledged with @b PRACK request sent by the
+ * client.
+ *
+ * Note if the SDP offer-answer is completed with the reliable preliminary
+ * responses, the is no need to include SDP in 200 OK response (or other 2XX
+ * response). However, it the tag NUTAG_INCLUDE_EXTRA_SDP(1) is included
+ * with nua_respond(), a copy of the SDP answer generated earlier by @soa is
+ * included as the message body.
+ *
+ * @sa nua_respond(), @ref nua_uas_call_model, #nua_i_state,
+ * NUTAG_MEDIA_ENABLE(), SOATAG_USER_SDP(), SOATAG_USER_SDP_STR(),
+ * @RFC3262, NUTAG_EARLY_MEDIA(), NUTAG_ONLY183_100REL(),
+ * NUTAG_INCLUDE_EXTRA_SDP(),
+ * #nua_i_prack, #nua_i_update, nua_update(),
+ * nua_invite(), #nua_r_invite
+ *
+ * @par Third Party Call Control
+ *
+ * When so called 2rd party call control is used, the initial @b INVITE may
+ * not contain SDP offer. In that case, the offer is sent by the recipient
+ * of the @b INVITE request (User-Agent Server, UAS). The SDP sent in 2XX
+ * response (or in a preliminary reliable response) is considered as an
+ * offer, and the answer will be included in the @b ACK request sent by the
+ * UAC (or @b PRACK in case of preliminary reliable response).
+ *
+ * @sa @ref nua_3pcc_call_model
+ *
+ * @END_NUA_EVENT
+ */
+
+/** @internal Process incoming INVITE. */
+int nua_stack_process_invite(nua_t *nua,
+ nua_handle_t *nh,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ nua_server_request_t *sr, sr0[1];
+ int status;
+
+ sr = SR_INIT(sr0);
+ sr->sr_irq = irq;
+
+ status = preprocess_invite(nua, nh, &sr, (sip_t *)sip);
+
+ if (status) {
+ if (sr->sr_status > 100)
+ nta_incoming_treply(irq, sr->sr_status, sr->sr_phrase,
+ SIPTAG_USER_AGENT_STR(NUA_PGET(nua, nh, user_agent)),
+ TAG_END());
+ nua_server_request_destroy(sr);
+ /* if something has failed, respond with 500 Internal Server Error */
+ return 500;
+ }
+
+ assert(sr != sr0);
+
+ return process_invite(nua, sr->sr_owner, sr, (sip_t *)sip);
+}
+
+/** @internal Preprocess incoming invite - sure we have a valid request.
+ *
+ * @return 0 if request is valid, or error statuscode when request has been
+ * responded.
+ */
+static
+int preprocess_invite(nua_t *nua,
+ nua_handle_t *nh,
+ nua_server_request_t **inout_sr,
+ sip_t *sip)
+{
+ nua_dialog_state_t *ds;
+ nua_server_request_t *sr = *inout_sr;
+ nua_server_request_t const *sr0;
+ nua_dialog_usage_t *du;
+ nua_session_usage_t *ss;
+ int have_sdp;
+ char const *sdp;
+ size_t len;
+
+ if (nh) {
+ ds = nh->nh_ds;
+ du = nua_dialog_usage_get(ds, nua_session_usage, NULL);
+ ss = nua_dialog_usage_private(du);
+ }
+ else {
+ nh = nua->nua_dhandle, ds = NULL, du = NULL, ss = NULL;
+ }
+
+ sr->sr_usage = du;
+
+ if (!NUA_PGET(nua, nh, invite_enable))
+ return SR_STATUS1(sr, SIP_403_FORBIDDEN);
+
+ if (session_check_request(nua, nh, sr->sr_irq, sip))
+ return 500;
+
+ have_sdp = session_get_description(sip, &sdp, &len);
+
+ if (ss) {
+ /* Existing session */
+
+ for (sr0 = ds->ds_sr; sr0; sr0 = sr0->sr_next) {
+ /* Final response have not been sent to previous INVITE */
+ if (sr0->sr_method == sip_method_invite && sr0->sr_respond)
+ break;
+ /* Or we have sent offer but have not received answer */
+ if (have_sdp && sr0->sr_offer_sent && !sr0->sr_answer_recv)
+ break;
+ /* Or we have received request with offer but not sent answer */
+ if (have_sdp && sr0->sr_offer_recv && !sr0->sr_answer_sent)
+ break;
+ }
+
+ if (sr0)
+ /* Overlapping invites - RFC 3261 14.2 */
+ return respond_with_retry_after(nh, sr->sr_irq,
+ 500, "Overlapping Requests",
+ 0, 10);
+
+ if ((ss->ss_crequest && ss->ss_crequest->cr_orq) ||
+ (have_sdp && ds && ds->ds_cr->cr_orq && ds->ds_cr->cr_offer_sent)) {
+ /* Glare - RFC 3261 14.2 and RFC 3311 section 5.2 */
+ return SR_STATUS1(sr, SIP_491_REQUEST_PENDING);
+ }
+ }
+
+ /* Create handle and server request structure when needed */
+ sr = nua_server_request(nua, nh, sr->sr_irq, sip, sr, sizeof *sr,
+ respond_to_invite, create_dialog);
+ *inout_sr = sr;
+
+ if (sr->sr_status > 100)
+ return sr->sr_status;
+
+ nh = sr->sr_owner; assert(nh != nua->nua_dhandle);
+ ds = nh->nh_ds;
+
+ if (nh->nh_soa) {
+ soa_init_offer_answer(nh->nh_soa);
+
+ if (have_sdp) {
+ if (soa_set_remote_sdp(nh->nh_soa, NULL, sdp, len) < 0) {
+ SU_DEBUG_5(("nua(%p): error parsing SDP in INVITE\n", nh));
+ return SR_STATUS(sr, 400, "Bad Session Description");
+ }
+ else
+ sr->sr_offer_recv = 1;
+ }
+ }
+
+ /* Add the session usage */
+ if (du == NULL)
+ du = nua_dialog_usage_add(nh, nh->nh_ds, nua_session_usage, NULL);
+
+ if (!du)
+ return SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR);
+
+ sr->sr_usage = du;
+
+ return 0;
+}
+
+static int
+session_check_request(nua_t *nua,
+ nua_handle_t *nh,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ char const *user_agent = NUA_PGET(nua, nh, user_agent);
+
+ if (nh->nh_soa) {
+ /* Make sure caller uses application/sdp without compression */
+ if (nta_check_session_content(irq, sip,
+ nua->nua_invite_accept,
+ SIPTAG_USER_AGENT_STR(user_agent),
+ SIPTAG_ACCEPT_ENCODING_STR(""),
+ TAG_END()))
+ return 415;
+
+ /* Make sure caller accepts application/sdp */
+ if (nta_check_accept(irq, sip,
+ nua->nua_invite_accept,
+ NULL,
+ SIPTAG_USER_AGENT_STR(user_agent),
+ SIPTAG_ACCEPT_ENCODING_STR(""),
+ TAG_END()))
+ return 406;
+ }
+
+ if (sip->sip_session_expires) {
+ unsigned min_se = NH_PGET(nh, min_se);
+ if (sip->sip_min_se && min_se < sip->sip_min_se->min_delta)
+ min_se = sip->sip_min_se->min_delta;
+ if (nta_check_session_expires(irq, sip,
+ min_se,
+ SIPTAG_USER_AGENT_STR(user_agent),
+ TAG_END()))
+ return 422;
+ }
+
+ return 0;
+}
+
+/** @internal Process incoming invite - initiate media, etc. */
+static
+int process_invite(nua_t *nua,
+ nua_handle_t *nh,
+ nua_server_request_t *sr,
+ sip_t *sip)
+{
+ nua_session_usage_t *ss = nua_dialog_usage_private(sr->sr_usage);
+ int status = sr->sr_status; char const *phrase = sr->sr_phrase;
+
+ assert(ss); assert(status == 100);
+
+ ss->ss_100rel = NH_PGET(nh, early_media);
+ ss->ss_precondition = sip_has_feature(sip->sip_require, "precondition");
+ if (ss->ss_precondition)
+ ss->ss_100rel = 1;
+
+ session_timer_preferences(ss,
+ NH_PGET(nh, session_timer),
+ NH_PGET(nh, min_se),
+ NH_PGET(nh, refresher));
+
+ /* Session Timer negotiation */
+ if (sip_has_supported(NH_PGET(nh, supported), "timer"))
+ init_session_timer(ss, sip, ss->ss_refresher);
+
+ nua_dialog_uas_route(nh, nh->nh_ds, sip, 1); /* Set route and tags */
+
+ nta_incoming_bind(sr->sr_irq, process_ack_or_cancel, sr);
+
+ assert(ss->ss_state >= nua_callstate_ready ||
+ ss->ss_state == nua_callstate_init);
+
+ if (NH_PGET(nh, auto_answer) ||
+ /* Auto-answer to re-INVITE unless auto_answer is set to 0 on handle */
+ (ss->ss_state == nua_callstate_ready &&
+ /* Auto-answer requires enabled media (soa).
+ * XXX - if the re-INVITE modifies the media we should not auto-answer.
+ */
+ nh->nh_soa &&
+ !NH_PISSET(nh, auto_answer))) {
+ SET_STATUS1(SIP_200_OK);
+ }
+ else if (NH_PGET(nh, auto_alert)) {
+ if (ss->ss_100rel &&
+ (sip_has_feature(nh->nh_ds->ds_remote_ua->nr_supported, "100rel") ||
+ sip_has_feature(nh->nh_ds->ds_remote_ua->nr_require, "100rel"))) {
+ SET_STATUS1(SIP_183_SESSION_PROGRESS);
+ }
+ else {
+ SET_STATUS1(SIP_180_RINGING);
+ }
+ }
+
+ /* Magical value indicating autoanswer within respond_to_invite() */
+#define AUTOANSWER ((void*)-1)
+
+ if (status > 100) {
+ sr->sr_auto = 1;
+ nua_server_respond(sr, status, phrase, TAG_END());
+ sr->sr_auto = 0;
+ return 0;
+ }
+
+ nta_incoming_treply(sr->sr_irq, SIP_100_TRYING,
+ SIPTAG_USER_AGENT_STR(NUA_PGET(nua, nh, user_agent)),
+ TAG_END());
+
+ nua_stack_event(nh->nh_nua, nh,
+ sr->sr_msg = nta_incoming_getrequest(sr->sr_irq),
+ nua_i_invite, SIP_100_TRYING,
+ NH_ACTIVE_MEDIA_TAGS(1, nh->nh_soa),
+ TAG_END());
+
+ signal_call_state_change(nh, ss, SIP_100_TRYING,
+ nua_callstate_received,
+ sr->sr_offer_recv ? "offer" : 0, 0);
+
+ return 0;
+}
+
+/** @internal Respond to an INVITE request.
+ *
+ * XXX - use tags to indicate when to use reliable responses.
+ * XXX - change prototype.
+ */
+static
+int respond_to_invite(nua_server_request_t *sr, tagi_t const *tags)
+{
+ nua_handle_t *nh = sr->sr_owner;
+ nua_t *nua = nh->nh_nua;
+ nua_dialog_state_t *ds = nh->nh_ds;
+ nua_dialog_usage_t *du;
+ nua_session_usage_t *ss;
+ msg_t *msg;
+ sip_t *sip;
+ int reliable;
+ int status = sr->sr_status; char const *phrase = sr->sr_phrase;
+ sip_warning_t *warning = NULL;
+
+ int offer = 0, answer = 0, early_answer = 0;
+
+ enter;
+
+ du = sr->sr_usage, ss = nua_dialog_usage_private(du);
+
+ if (du == NULL)
+ return nua_default_respond(sr, tags);
+
+ assert(ss == nua_session_usage_get(nh->nh_ds));
+
+ if (tags) {
+ nua_stack_set_params(nua, nh, nua_i_error, tags);
+
+ if (!NHP_ISSET(nh->nh_prefs, early_answer)
+ && 100 < status && status < 200) {
+ sdp_session_t const *user_sdp = NULL;
+ char const *user_sdp_str = NULL;
+
+ tl_gets(tags,
+ SOATAG_USER_SDP_REF(user_sdp),
+ SOATAG_USER_SDP_STR_REF(user_sdp_str),
+ TAG_END());
+
+ early_answer = user_sdp || user_sdp_str;
+ }
+ else
+ early_answer = NH_PGET(nh, early_answer);
+ }
+
+ msg = nua_server_response(sr,
+ status, phrase,
+ TAG_IF(status < 300, NUTAG_ADD_CONTACT(1)),
+ SIPTAG_SUPPORTED(NH_PGET(nh, supported)),
+ TAG_NEXT(tags));
+ sip = sip_object(msg);
+
+ if (!sip) {
+ SET_STATUS1(SIP_500_INTERNAL_SERVER_ERROR), reliable = 0;
+ goto send_response;
+ }
+
+ reliable =
+ (status >= 200)
+ || (status > 100 && sip->sip_require &&
+ sip_has_feature(sip->sip_require, "100rel"))
+ || (status > 100 &&
+ ds->ds_remote_ua->nr_require &&
+ sip_has_feature(ds->ds_remote_ua->nr_require, "100rel"))
+ || (status > 100 && !NH_PGET(nh, only183_100rel) &&
+ (NH_PGET(nh, early_media) ||
+ (ds->ds_remote_ua->nr_require &&
+ sip_has_feature(ds->ds_remote_ua->nr_require, "precondition"))) &&
+ ds->ds_remote_ua->nr_supported &&
+ sip_has_feature(ds->ds_remote_ua->nr_supported, "100rel"))
+ || (status == 183 &&
+ ds->ds_remote_ua->nr_supported &&
+ sip_has_feature(ds->ds_remote_ua->nr_supported, "100rel"))
+ || (status == 183 &&
+ ds->ds_remote_ua->nr_require &&
+ sip_has_feature(ds->ds_remote_ua->nr_require, "precondition"))
+ || (status > 100 &&
+ ds->ds_remote_ua->nr_require &&
+ sip_has_feature(ds->ds_remote_ua->nr_require, "precondition") &&
+ sr->sr_offer_recv && !sr->sr_answer_sent);
+
+ if (!nh->nh_soa)
+ /* Xyzzy */;
+ else if (status >= 300) {
+ soa_clear_remote_sdp(nh->nh_soa);
+ }
+ else {
+ int extra = 0;
+
+ if (sr->sr_offer_sent && !sr->sr_answer_recv)
+ /* Wait for answer */;
+ else if (sr->sr_offer_recv && sr->sr_answer_sent > 1) {
+ /* We have sent answer */
+ /* ... but we may want to send it again */
+ tagi_t const *t = tl_find_last(tags, nutag_include_extra_sdp);
+ extra = t && t->t_value;
+ }
+ else if (sr->sr_offer_recv && !sr->sr_answer_sent &&
+ (reliable || early_answer)) {
+ /* Generate answer */
+ if (soa_generate_answer(nh->nh_soa, NULL) >= 0) {
+ answer = 1;
+ soa_activate(nh->nh_soa, NULL);
+ /* signal that O/A answer sent (answer to invite) */
+ }
+ else if (status >= 200) {
+ int wcode;
+ char const *text;
+ char const *host = "invalid.";
+ status = soa_error_as_sip_response(nh->nh_soa, &phrase);
+
+ wcode = soa_get_warning(nh->nh_soa, &text);
+ if (wcode) {
+ if (sip->sip_contact)
+ host = sip->sip_contact->m_url->url_host;
+ warning = sip_warning_format(msg_home(msg), "%u %s \"%s\"",
+ wcode, host, text);
+ }
+ }
+ else {
+ /* 1xx - we don't have to send answer */
+ }
+ }
+ else if (sr->sr_offer_recv && sr->sr_answer_sent == 1 &&
+ (reliable || early_answer)) {
+ /* The answer was sent unreliably, keep sending it */
+ answer = 1;
+ }
+ else if (!sr->sr_offer_recv && !sr->sr_offer_sent && reliable) {
+ /* Generate offer */
+ if (soa_generate_offer(nh->nh_soa, 0, NULL) < 0)
+ status = soa_error_as_sip_response(nh->nh_soa, &phrase);
+ else
+ offer = 1;
+ }
+
+ if (offer || answer || extra) {
+ if (session_include_description(nh->nh_soa, 1, msg, sip) < 0)
+ SET_STATUS1(SIP_500_INTERNAL_SERVER_ERROR);
+ }
+ }
+
+ if (ss->ss_refresher && 200 <= status && status < 300)
+ if (session_timer_is_supported(nh))
+ use_session_timer(ss, 1, 1, msg, sip);
+
+ if (reliable && status < 200) {
+ nta_reliable_t *rel;
+ rel = nta_reliable_mreply(sr->sr_irq,
+ process_prack, nh, msg);
+ if (!rel)
+ SET_STATUS1(SIP_500_INTERNAL_SERVER_ERROR);
+ }
+
+ send_response:
+
+ if (reliable && status < 200)
+ /* we are done */;
+ else if (status != sr->sr_status) { /* Error responding */
+ assert(status >= 200);
+ sr->sr_respond = NULL;
+ nta_incoming_treply(sr->sr_irq,
+ status, phrase,
+ SIPTAG_WARNING(warning),
+ SIPTAG_USER_AGENT_STR(NH_PGET(nh, user_agent)),
+ TAG_END());
+ msg_destroy(msg), msg = NULL;
+ }
+ else {
+ if (status >= 200)
+ sr->sr_respond = NULL;
+ nta_incoming_mreply(sr->sr_irq, msg);
+ }
+
+ if (sr->sr_auto) {
+ msg_t *request = nta_incoming_getrequest(sr->sr_irq);
+ if (status < 200)
+ sr->sr_msg = request;
+ nua_stack_event(nh->nh_nua, nh, request,
+ nua_i_invite, status, phrase,
+ NH_ACTIVE_MEDIA_TAGS(1, nh->nh_soa),
+ TAG_END());
+ }
+ else if (status != sr->sr_status)
+ nua_stack_event(nua, nh, NULL, nua_i_error, status, phrase, TAG_END());
+
+ sr->sr_status = status, sr->sr_phrase = phrase;
+
+ if (status >= 300)
+ offer = 0, answer = 0;
+
+ if (offer)
+ sr->sr_offer_sent = 1;
+ else if (answer)
+ sr->sr_answer_sent = 1 + reliable;
+
+ /* Update session state */
+ assert(ss->ss_state != nua_callstate_calling);
+ assert(ss->ss_state != nua_callstate_proceeding);
+
+ signal_call_state_change(nh, ss, status, phrase,
+ status >= 300
+ ? nua_callstate_init
+ : status >= 200
+ ? nua_callstate_completed
+ : nua_callstate_early,
+ sr->sr_auto && sr->sr_offer_recv ? "offer" : 0,
+ offer ? "offer" : answer ? "answer" : 0);
+
+ if (status == 180)
+ ss->ss_alerting = 1;
+ else if (status >= 200)
+ ss->ss_alerting = 0;
+
+ if (status >= 200 && status < 300) {
+ du->du_ready = 1;
+ }
+ else if (status >= 300) {
+ sr->sr_usage = NULL;
+ if (nh->nh_soa)
+ soa_init_offer_answer(nh->nh_soa);
+ }
+
+ if (ss->ss_state == nua_callstate_init) {
+ assert(status >= 300);
+ nua_session_usage_destroy(nh, ss);
+ }
+
+ return status >= 300 ? status : 0;
+}
+
+
+/** @internal Process ACK or CANCEL or timeout (no ACK) for incoming INVITE */
+static
+int process_ack_or_cancel(nua_server_request_t *sr,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ enter;
+
+ assert(sr->sr_usage);
+ assert(sr->sr_usage->du_class == nua_session_usage);
+
+ if (sip && sip->sip_request->rq_method == sip_method_ack)
+ return process_ack(sr, irq, sip);
+ else if (sip && sip->sip_request->rq_method == sip_method_cancel)
+ return process_cancel(sr, irq, sip);
+ else
+ return process_timeout(sr, irq);
+}
+
+/** @NUA_EVENT nua_i_prack
+ *
+ * Incoming PRACK request. PRACK request is used to acknowledge reliable
+ * preliminary responses and it is usually sent automatically by the nua
+ * stack.
+ *
+ * @param status status code of response sent automatically by stack
+ * @param phrase a short textual description of @a status code
+ * @param nh operation handle associated with the call
+ * @param hmagic application context associated with the call
+ * @param sip incoming INFO request
+ * @param tags empty
+ *
+ * @sa nua_prack(), #nua_r_prack, @RFC3262, NUTAG_EARLY_MEDIA()
+ *
+ * @END_NUA_EVENT
+ */
+
+/** @internal Process PRACK or (timeout from 100rel) */
+static
+int process_prack(nua_handle_t *nh,
+ nta_reliable_t *rel,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ nua_dialog_state_t *ds = nh->nh_ds;
+ nua_dialog_usage_t *du;
+ nua_session_usage_t *ss;
+ nua_server_request_t *sri;
+ int status = 200; char const *phrase = sip_200_OK;
+ char const *recv = NULL, *sent = NULL;
+
+ nta_reliable_destroy(rel);
+
+ ss = nua_session_usage_get(ds); du = nua_dialog_usage_public(ss);
+
+ for (sri = ds->ds_sr; sri; sri = sri->sr_next) {
+ if (sri->sr_method == sip_method_invite && sri->sr_usage == du)
+ break;
+ }
+
+ if (!sri || !sri->sr_respond) /* XXX */
+ return 481;
+
+ if (sip)
+ /* received PRACK */;
+ else if (!sri || irq == NULL) { /* Final response interrupted 100rel */
+ /* Ignore */
+ return 200;
+ }
+ else if (sip == NULL) {
+ SET_STATUS(504, "Reliable Response Timeout");
+
+ nua_stack_event(nh->nh_nua, nh, NULL,
+ nua_i_error, status, phrase,
+ TAG_END());
+
+ nua_server_respond(sri, status, phrase, TAG_END());
+
+ return status;
+ }
+
+ if (nh->nh_soa) {
+ msg_t *msg = nta_incoming_getrequest(irq);
+ char const *sdp;
+ size_t len;
+
+ if (session_get_description(sip, &sdp, &len)) {
+ su_home_t home[1] = { SU_HOME_INIT(home) };
+
+ sip_content_disposition_t *cd = NULL;
+ sip_content_type_t *ct = NULL;
+ sip_payload_t *pl = NULL;
+
+ if (soa_set_remote_sdp(nh->nh_soa, NULL, sdp, len) < 0) {
+ SU_DEBUG_5(("nua(%p): error parsing SDP in INVITE\n", nh));
+ msg_destroy(msg);
+ status = 400, phrase = "Bad Session Description";
+ }
+
+ /* Respond to PRACK */
+
+ if (status >= 300)
+ ;
+ else if (sri->sr_offer_sent) {
+ recv = "answer";
+ sri->sr_answer_recv = 1;
+ if (soa_process_answer(nh->nh_soa, NULL) < 0)
+ status = soa_error_as_sip_response(nh->nh_soa, &phrase);
+ }
+ else {
+ recv = "offer";
+ if (soa_generate_answer(nh->nh_soa, NULL) < 0) {
+ status = soa_error_as_sip_response(nh->nh_soa, &phrase);
+ }
+ else {
+ if (session_make_description(home, nh->nh_soa, 1, &cd, &ct, &pl) > 0)
+ sent = "answer";
+ }
+ }
+
+ if (nta_incoming_treply(irq, status, phrase,
+ SIPTAG_CONTENT_DISPOSITION(cd),
+ SIPTAG_CONTENT_TYPE(ct),
+ SIPTAG_PAYLOAD(pl),
+ TAG_END()) < 0)
+ /* Respond with 500 if nta_incoming_treply() failed */
+ SET_STATUS1(SIP_500_INTERNAL_SERVER_ERROR);
+
+ su_home_deinit(home);
+ }
+
+ msg_destroy(msg);
+ }
+
+ nua_stack_event(nh->nh_nua, nh, nta_incoming_getrequest(irq),
+ nua_i_prack, status, phrase, TAG_END());
+
+ if (status >= 300)
+ return status;
+
+ if (recv || sent) {
+ soa_activate(nh->nh_soa, NULL);
+ signal_call_state_change(nh, ss, status, phrase,
+ nua_callstate_early, recv, sent);
+ }
+
+ if (NH_PGET(nh, auto_alert) && !ss->ss_alerting && !ss->ss_precondition)
+ nua_server_respond(sri, SIP_180_RINGING, TAG_END());
+
+ return status;
+}
+
+/** @NUA_EVENT nua_i_ack
+ *
+ * Final response to INVITE has been acknowledged by UAC with ACK.
+ *
+ * @note This event is only sent after 2XX response.
+ *
+ * @param nh operation handle associated with the call
+ * @param hmagic application context associated with the call
+ * @param sip incoming ACK request
+ * @param tags empty
+ *
+ * @sa #nua_i_invite, #nua_i_state, @ref nua_uas_call_model, nua_ack()
+ *
+ * @END_NUA_EVENT
+ */
+
+int process_ack(nua_server_request_t *sr,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ nua_handle_t *nh = sr->sr_owner;
+ nua_session_usage_t *ss = nua_dialog_usage_private(sr->sr_usage);
+ msg_t *msg = nta_incoming_getrequest_ackcancel(irq);
+ char const *recv = NULL;
+
+ if (ss == NULL)
+ return 0;
+
+ if (nh->nh_soa && sr->sr_offer_sent && !sr->sr_answer_recv) {
+ char const *sdp;
+ size_t len;
+
+ if (!session_get_description(sip, &sdp, &len) ||
+ !(recv = "answer") ||
+ soa_set_remote_sdp(nh->nh_soa, NULL, sdp, len) < 0 ||
+ soa_process_answer(nh->nh_soa, NULL) < 0 ||
+ soa_activate(nh->nh_soa, NULL)) {
+ int status; char const *phrase, *reason;
+
+ status = soa_error_as_sip_response(nh->nh_soa, &phrase);
+ reason = soa_error_as_sip_reason(nh->nh_soa);
+
+ nua_stack_event(nh->nh_nua, nh, msg,
+ nua_i_ack, status, phrase, TAG_END());
+ nua_stack_event(nh->nh_nua, nh, NULL,
+ nua_i_media_error, status, phrase, TAG_END());
+
+ signal_call_state_change(nh, ss, 488, "Offer-Answer Error",
+ nua_callstate_terminating, recv, 0);
+ nua_stack_post_signal(nh, nua_r_bye,
+ SIPTAG_REASON_STR(reason),
+ TAG_END());
+
+ return 0;
+ }
+ }
+
+ soa_clear_remote_sdp(nh->nh_soa);
+ nua_stack_event(nh->nh_nua, nh, msg, nua_i_ack, SIP_200_OK, TAG_END());
+ signal_call_state_change(nh, ss, 200, "OK", nua_callstate_ready, recv, 0);
+ set_session_timer(ss);
+
+ nua_server_request_destroy(sr);
+
+ return 0;
+}
+
+/** @NUA_EVENT nua_i_cancel
+ *
+ * Incoming INVITE has been cancelled by the client.
+ *
+ * @param status status code of response to CANCEL sent automatically by stack
+ * @param phrase a short textual description of @a status code
+ * @param nh operation handle associated with the call
+ * @param hmagic application context associated with the call
+ * @param sip incoming CANCEL request
+ * @param tags empty
+ *
+ * @sa @ref nua_uas_call_model, nua_cancel(), #nua_i_invite, #nua_i_state
+ *
+ * @END_NUA_EVENT
+ */
+
+/* CANCEL */
+static
+int process_cancel(nua_server_request_t *sr,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ nua_handle_t *nh = sr->sr_owner;
+ nua_session_usage_t *ss = nua_dialog_usage_private(sr->sr_usage);
+ msg_t *cancel = nta_incoming_getrequest_ackcancel(irq);
+
+ assert(nta_incoming_status(irq) < 200); assert(sr->sr_respond);
+ assert(ss); assert(ss == nua_session_usage_get(nh->nh_ds)); (void)ss;
+
+ nua_stack_event(nh->nh_nua, nh, cancel, nua_i_cancel, SIP_200_OK, TAG_END());
+
+ nua_server_respond(sr, SIP_487_REQUEST_TERMINATED, TAG_END());
+
+ return 0;
+}
+
+/* Timeout (no ACK or PRACK received) */
+static
+int process_timeout(nua_server_request_t *sr,
+ nta_incoming_t *irq)
+{
+ nua_handle_t *nh = sr->sr_owner;
+ nua_session_usage_t *ss = nua_dialog_usage_private(sr->sr_usage);
+
+ assert(ss); assert(ss == nua_session_usage_get(nh->nh_ds));
+
+ nua_stack_event(nh->nh_nua, nh, 0, nua_i_error,
+ 408, "Response timeout",
+ TAG_END());
+
+ if (sr->sr_respond) {
+ /* PRACK timeout */
+ nua_server_respond(sr, SIP_504_GATEWAY_TIME_OUT,
+ SIPTAG_REASON_STR("SIP;cause=504;"
+ "text=\"PRACK Timeout\""),
+ TAG_END());
+ ss = nua_session_usage_get(nh->nh_ds);
+ sr = NULL;
+ }
+
+ if (ss) {
+ /* send BYE, too if 200 OK (or 183 to re-INVITE) timeouts */
+ signal_call_state_change(nh, ss, 0, "Timeout",
+ nua_callstate_terminating, 0, 0);
+ nua_stack_post_signal(nh, nua_r_bye,
+ SIPTAG_REASON_STR("SIP;cause=408;text=\"ACK Timeout\""),
+ TAG_END());
+ }
+
+ if (sr)
+ nua_server_request_destroy(sr);
+
+ return 0;
+}
+
+
+/* ---------------------------------------------------------------------- */
+/* Session timer - RFC 4028 */
+
+static int session_timer_is_supported(nua_handle_t const *nh)
+{
+ /* Is timer feature supported? */
+ return sip_has_supported(NH_PGET(nh, supported), "timer");
+}
+
+static int prefer_session_timer(nua_handle_t const *nh)
+{
+ return
+ NH_PGET(nh, refresher) != nua_no_refresher ||
+ NH_PGET(nh, session_timer) != 0;
+}
+
+/* Initialize session timer */
+static
+void session_timer_preferences(nua_session_usage_t *ss,
+ unsigned expires,
+ unsigned min_se,
+ enum nua_session_refresher refresher)
+{
+ if (expires < min_se)
+ expires = min_se;
+ if (refresher && expires == 0)
+ expires = 3600;
+
+ ss->ss_min_se = min_se;
+ ss->ss_session_timer = expires;
+ ss->ss_refresher = refresher;
+}
+
+
+/** Add timer featuretag and Session-Expires/Min-SE headers */
+static int
+use_session_timer(nua_session_usage_t *ss, int uas, int always,
+ msg_t *msg, sip_t *sip)
+{
+ sip_min_se_t min_se[1];
+ sip_session_expires_t session_expires[1];
+
+ static sip_param_t const x_params_uac[] = {"refresher=uac", NULL};
+ static sip_param_t const x_params_uas[] = {"refresher=uas", NULL};
+
+ /* Session-Expires timer */
+ if (ss->ss_refresher == nua_no_refresher && !always)
+ return 0;
+
+ sip_min_se_init(min_se)->min_delta = ss->ss_min_se;
+ sip_session_expires_init(session_expires)->x_delta = ss->ss_session_timer;
+
+ if (ss->ss_refresher == nua_remote_refresher)
+ session_expires->x_params = uas ? x_params_uac : x_params_uas;
+ else if (ss->ss_refresher == nua_local_refresher)
+ session_expires->x_params = uas ? x_params_uas : x_params_uac;
+
+ sip_add_tl(msg, sip,
+ TAG_IF(ss->ss_session_timer,
+ SIPTAG_SESSION_EXPIRES(session_expires)),
+ TAG_IF(ss->ss_min_se != 0
+ /* Min-SE: 0 is optional with initial INVITE */
+ || ss->ss_state != nua_callstate_init,
+ SIPTAG_MIN_SE(min_se)),
+ TAG_IF(ss->ss_refresher == nua_remote_refresher,
+ SIPTAG_REQUIRE_STR("timer")),
+ TAG_END());
+
+ return 1;
+}
+
+static int
+init_session_timer(nua_session_usage_t *ss,
+ sip_t const *sip,
+ int refresher)
+{
+ int server;
+
+ /* Session timer is not needed */
+ if (!sip->sip_session_expires) {
+ if (!sip_has_supported(sip->sip_supported, "timer"))
+ ss->ss_refresher = nua_local_refresher;
+ return 0;
+ }
+
+ ss->ss_refresher = nua_no_refresher;
+ ss->ss_session_timer = sip->sip_session_expires->x_delta;
+
+ if (sip->sip_min_se != NULL
+ && sip->sip_min_se->min_delta > ss->ss_min_se)
+ ss->ss_min_se = sip->sip_min_se->min_delta;
+
+ server = sip->sip_request != NULL;
+
+ if (!sip_has_supported(sip->sip_supported, "timer"))
+ ss->ss_refresher = nua_local_refresher;
+ else if (!str0casecmp("uac", sip->sip_session_expires->x_refresher))
+ ss->ss_refresher = server ? nua_remote_refresher : nua_local_refresher;
+ else if (!str0casecmp("uas", sip->sip_session_expires->x_refresher))
+ ss->ss_refresher = server ? nua_local_refresher : nua_remote_refresher;
+ else if (!server)
+ return 0; /* XXX */
+ /* User preferences */
+ else if (refresher == nua_local_refresher)
+ ss->ss_refresher = nua_local_refresher;
+ else
+ ss->ss_refresher = nua_remote_refresher;
+
+ SU_DEBUG_7(("nua session: session expires in %u refreshed by %s (%s %s)\n",
+ ss->ss_session_timer,
+ ss->ss_refresher == nua_local_refresher ? "local" : "remote",
+ server ? sip->sip_request->rq_method_name : "response to",
+ server ? "request" : sip->sip_cseq->cs_method_name));
+
+ return 1;
+}
+
+static void
+set_session_timer(nua_session_usage_t *ss)
+{
+ nua_dialog_usage_t *du = nua_dialog_usage_public(ss);
+
+ if (ss == NULL)
+ return;
+
+ if (ss->ss_refresher == nua_local_refresher) {
+ ss->ss_timer_set = 1;
+ nua_dialog_usage_set_expires(du, ss->ss_session_timer);
+ }
+ else if (ss->ss_refresher == nua_remote_refresher) {
+ ss->ss_timer_set = 1;
+ nua_dialog_usage_set_expires(du, ss->ss_session_timer + 32);
+ nua_dialog_usage_reset_refresh(du);
+ }
+ else {
+ ss->ss_timer_set = 0;
+ nua_dialog_usage_set_expires(du, UINT_MAX);
+ nua_dialog_usage_reset_refresh(du);
+ }
+}
+
+static int
+check_session_timer_restart(nua_handle_t *nh,
+ nua_session_usage_t *ss,
+ nua_client_request_t *cr,
+ nta_outgoing_t *orq,
+ sip_t const *sip,
+ nua_creq_restart_f *restart_function)
+{
+ if (ss && sip && sip->sip_status->st_status == 422) {
+ if (sip->sip_min_se && ss->ss_min_se < sip->sip_min_se->min_delta)
+ ss->ss_min_se = sip->sip_min_se->min_delta;
+ if (ss->ss_min_se > ss->ss_session_timer)
+ ss->ss_session_timer = ss->ss_min_se;
+
+ if (orq == cr->cr_orq)
+ cr->cr_orq = NULL;
+
+ return nua_creq_restart_with(nh, cr, orq,
+ 100, "Re-Negotiating Session Timer",
+ restart_function, TAG_END());
+ }
+
+ return nua_creq_check_restart(nh, cr, orq, sip, restart_function);
+}
+
+static inline int
+is_session_timer_set(nua_session_usage_t *ss)
+{
+ return ss->ss_timer_set;
+}
+
+/* ---------------------------------------------------------------------- */
+/* Automatic notifications from a referral */
+
+static int
+nh_referral_check(nua_handle_t *nh, tagi_t const *tags)
+{
+ sip_event_t const *event = NULL;
+ int pause = 1;
+ struct nua_referral *ref = nh->nh_referral;
+ nua_handle_t *ref_handle = ref->ref_handle;
+
+ if (!ref_handle
+ &&
+ tl_gets(tags,
+ NUTAG_NOTIFY_REFER_REF(ref_handle),
+ NUTAG_REFER_EVENT_REF(event),
+ NUTAG_REFER_PAUSE_REF(pause),
+ TAG_END()) == 0
+ &&
+ tl_gets(nh->nh_tags,
+ NUTAG_NOTIFY_REFER_REF(ref_handle),
+ NUTAG_REFER_EVENT_REF(event),
+ NUTAG_REFER_PAUSE_REF(pause),
+ TAG_END()) == 0)
+ return 0;
+
+ if (!ref_handle)
+ return 0;
+
+ /* Remove nh_referral and nh_notevent */
+ tl_tremove(nh->nh_tags,
+ NUTAG_NOTIFY_REFER(ref_handle),
+ TAG_IF(event, NUTAG_REFER_EVENT(event)),
+ TAG_END());
+
+ if (event)
+ ref->ref_event = sip_event_dup(nh->nh_home, event);
+
+ if (!nh_validate(nh->nh_nua, ref_handle)) {
+ SU_DEBUG_3(("nua: invalid NOTIFY_REFER handle\n"));
+ return -1;
+ }
+ else if (!ref->ref_event) {
+ SU_DEBUG_3(("nua: NOTIFY event missing\n"));
+ return -1;
+ }
+
+ if (ref_handle != ref->ref_handle) {
+ if (ref->ref_handle)
+ nua_handle_unref(ref->ref_handle);
+ ref->ref_handle = nua_handle_ref(ref_handle);
+ }
+
+#if 0
+ if (pause) {
+ /* Pause media on REFER handle */
+ nmedia_pause(nua, ref_handle->nh_nm, NULL);
+ }
+#endif
+
+ return 0;
+}
+
+
+static void
+nh_referral_respond(nua_handle_t *nh, int status, char const *phrase)
+{
+ char payload[128];
+ char const *substate;
+ struct nua_referral *ref = nh->nh_referral;
+
+ if (!nh_validate(nh->nh_nua, ref->ref_handle)) {
+ if (ref) {
+ if (ref->ref_handle)
+ SU_DEBUG_1(("nh_handle_referral: stale referral handle %p\n",
+ ref->ref_handle));
+ ref->ref_handle = NULL;
+ }
+ return;
+ }
+
+ /* XXX - we should have a policy here whether to send 101..199 */
+
+ assert(ref->ref_event);
+
+ if (status >= 300)
+ status = 503, phrase = sip_503_Service_unavailable;
+
+ snprintf(payload, sizeof(payload), "SIP/2.0 %03u %s\r\n", status, phrase);
+
+ if (status < 200)
+ substate = "active";
+ else
+ substate = "terminated ;reason=noresource";
+
+ nua_stack_post_signal(ref->ref_handle,
+ nua_r_notify,
+ SIPTAG_EVENT(ref->ref_event),
+ SIPTAG_SUBSCRIPTION_STATE_STR(substate),
+ SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
+ SIPTAG_PAYLOAD_STR(payload),
+ TAG_END());
+
+ if (status < 200)
+ return;
+
+ su_free(nh->nh_home, ref->ref_event), ref->ref_event = NULL;
+
+ nua_handle_unref(ref->ref_handle), ref->ref_handle = NULL;
+}
+
+
+/** Zap the session associated with the handle */
+static
+void nua_session_usage_destroy(nua_handle_t *nh,
+ nua_session_usage_t *ss)
+{
+ nh->nh_has_invite = 0;
+ nh->nh_active_call = 0;
+ nh->nh_hold_remote = 0;
+
+ if (nh->nh_soa)
+ soa_destroy(nh->nh_soa), nh->nh_soa = NULL;
+
+ /* Remove usage */
+ nua_dialog_usage_remove(nh, nh->nh_ds, nua_dialog_usage_public(ss));
+
+ SU_DEBUG_5(("nua: terminated session %p\n", nh));
+}
+
+
+/* ======================================================================== */
+/* INFO */
+
+static int process_response_to_info(nua_handle_t *nh,
+ nta_outgoing_t *orq,
+ sip_t const *sip);
+
+/**@fn void nua_info(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
+ *
+ * Send an INFO request.
+ *
+ * INFO is used to send call related information like DTMF
+ * digit input events. See @RFC2976.
+ *
+ * @param nh Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return
+ * nothing
+ *
+ * @par Related Tags:
+ * Tags in <sip_tag.h>.
+ *
+ * @par Events:
+ * #nua_r_info
+ *
+ * @sa #nua_i_info
+ */
+
+int
+nua_stack_info(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags)
+{
+ nua_client_request_t *cr = nh->nh_ds->ds_cr;
+ msg_t *msg;
+
+ if (nh_is_special(nh)) {
+ return UA_EVENT2(e, 900, "Invalid handle for INFO");
+ }
+ else if (cr->cr_orq) {
+ return UA_EVENT2(e, 900, "Request already in progress");
+ }
+
+ nua_stack_init_handle(nua, nh, TAG_NEXT(tags));
+
+ msg = nua_creq_msg(nua, nh, cr, cr->cr_retry_count,
+ SIP_METHOD_INFO ,
+ NUTAG_ADD_CONTACT(1),
+ TAG_NEXT(tags));
+
+ cr->cr_orq = nta_outgoing_mcreate(nua->nua_nta,
+ process_response_to_info, nh, NULL,
+ msg,
+ SIPTAG_END(), TAG_NEXT(tags));
+ if (!cr->cr_orq) {
+ msg_destroy(msg);
+ return UA_EVENT1(e, NUA_INTERNAL_ERROR);
+ }
+
+ return cr->cr_event = e;
+}
+
+void restart_info(nua_handle_t *nh, tagi_t *tags)
+{
+ nua_creq_restart(nh, nh->nh_ds->ds_cr, process_response_to_info, tags);
+}
+
+/** @NUA_EVENT nua_r_info
+ *
+ * Response to an outgoing @b INFO request.
+ *
+ * @param status response status code
+ * (if the request is retried, @a status is 100, the @a
+ * sip->sip_status->st_status contain the real status code
+ * from the response message, e.g., 302, 401, or 407)
+ * @param phrase a short textual description of @a status code
+ * @param nh operation handle associated with the call
+ * @param hmagic application context associated with the call
+ * @param sip response to @b INFO or NULL upon an error
+ * (status code is in @a status and
+ * descriptive message in @a phrase parameters)
+ * @param tags empty
+ *
+ * @sa nua_info(), #nua_i_info, @RFC2976
+ *
+ * @END_NUA_EVENT
+ */
+
+static int process_response_to_info(nua_handle_t *nh,
+ nta_outgoing_t *orq,
+ sip_t const *sip)
+{
+ if (nua_creq_check_restart(nh, nh->nh_ds->ds_cr, orq, sip, restart_info))
+ return 0;
+ return nua_stack_process_response(nh, nh->nh_ds->ds_cr, orq, sip, TAG_END());
+}
+
+/** @NUA_EVENT nua_i_info
+ *
+ * Incoming session INFO request.
+ *
+ * @param status statuscode of response sent automatically by stack
+ * @param phrase a short textual description of @a status code
+ * @param nh operation handle associated with the call
+ * @param hmagic application context associated with the call
+ * @param sip incoming INFO request
+ * @param tags empty
+ *
+ * @sa nua_info(), #nua_r_info, @RFC2976
+ *
+ * @END_NUA_EVENT
+ */
+
+int nua_stack_process_info(nua_t *nua,
+ nua_handle_t *nh,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ nua_stack_event(nh->nh_nua, nh, nta_incoming_getrequest(irq),
+ nua_i_info, SIP_200_OK, TAG_END());
+
+ return 200; /* Respond automatically with 200 Ok */
+}
+
+
+/* ======================================================================== */
+/* UPDATE */
+
+static int process_response_to_update(nua_handle_t *nh,
+ nta_outgoing_t *orq,
+ sip_t const *sip);
+
+/**@fn void nua_update(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
+ *
+ * Update a session.
+ *
+ * Update a session using SIP UPDATE method. See @RFC3311.
+ *
+ * Update method can be used when the session has been established with
+ * INVITE. It's mainly used during the session establishment when
+ * preconditions are used (@RFC3312). It can be also used during the call if
+ * no user input is needed for offer/answer negotiation.
+ *
+ * @param nh Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return
+ * nothing
+ *
+ * @par Related Tags:
+ * same as nua_invite()
+ *
+ * @par Events:
+ * #nua_r_update \n
+ * #nua_i_state (#nua_i_active, #nua_i_terminated)\n
+ * #nua_i_media_error \n
+ *
+ * @sa @ref nua_call_model, @RFC3311, nua_update(), #nua_i_update
+ */
+
+int nua_stack_update(nua_t *nua, nua_handle_t *nh, nua_event_t e,
+ tagi_t const *tags)
+{
+ nua_dialog_state_t *ds = nh->nh_ds;
+ nua_session_usage_t *ss;
+ nua_client_request_t *cr;
+ msg_t *msg;
+ sip_t *sip;
+ char const *offer_sent = 0;
+
+ ss = nua_session_usage_get(ds);
+ cr = ds->ds_cr;
+
+ if (!ss)
+ return UA_EVENT2(e, 900, "Invalid handle for UPDATE");
+ else if (cr->cr_orq)
+ return UA_EVENT2(e, 900, "Request already in progress");
+
+ nua_stack_init_handle(nua, nh, TAG_NEXT(tags));
+
+ msg = nua_creq_msg(nua, nh, cr, cr->cr_retry_count,
+ SIP_METHOD_UPDATE,
+ NUTAG_USE_DIALOG(1),
+ NUTAG_ADD_CONTACT(1),
+ TAG_NEXT(tags));
+
+ sip = sip_object(msg);
+
+ if (sip) {
+ nua_client_request_t *cri = ss->ss_crequest;
+ nua_server_request_t *sr;
+
+ for (sr = ds->ds_sr; sr; sr = sr->sr_next)
+ if ((sr->sr_offer_sent && !sr->sr_answer_recv) ||
+ (sr->sr_offer_recv && !sr->sr_answer_sent))
+ break;
+
+ if (nh->nh_soa && !sip->sip_payload &&
+ !sr &&
+ !(cri && cri->cr_offer_sent && !cri->cr_answer_recv) &&
+ !(cri && cri->cr_offer_recv && !cri->cr_answer_sent)) {
+ soa_init_offer_answer(nh->nh_soa);
+
+ if (soa_generate_offer(nh->nh_soa, 0, NULL) < 0 ||
+ session_include_description(nh->nh_soa, 1, msg, sip) < 0) {
+ if (ss->ss_state < nua_callstate_ready) {
+ /* XXX */
+ }
+ msg_destroy(msg);
+ return UA_EVENT2(e, 900, "Local media failed");
+ }
+
+ offer_sent = "offer";
+ }
+
+ /* Add session timer headers */
+ if (session_timer_is_supported(nh))
+ use_session_timer(ss, 0, prefer_session_timer(nh), msg, sip);
+
+ if (nh->nh_auth) {
+ if (auc_authorize(&nh->nh_auth, msg, sip) < 0)
+ /* xyzzy */;
+ }
+
+ cr->cr_orq = nta_outgoing_mcreate(nua->nua_nta,
+ process_response_to_update, nh, NULL,
+ msg,
+ SIPTAG_END(), TAG_NEXT(tags));
+ if (cr->cr_orq) {
+ if (offer_sent)
+ cr->cr_offer_sent = 1;
+ ss->ss_update_needed = 0;
+ signal_call_state_change(nh, ss, 0, "UPDATE sent",
+ ss->ss_state, 0, offer_sent);
+ return cr->cr_event = e;
+ }
+ }
+
+ msg_destroy(msg);
+ return UA_EVENT1(e, NUA_INTERNAL_ERROR);
+}
+
+void restart_update(nua_handle_t *nh, tagi_t *tags)
+{
+ nua_creq_restart(nh, nh->nh_ds->ds_cr, process_response_to_update, tags);
+}
+
+/** @NUA_EVENT nua_r_update
+ *
+ * Answer to outgoing UPDATE.
+ *
+ * The UPDATE may be sent explicitly by nua_update() or
+ * implicitly by NUA state machine.
+ *
+ * @param status response status code
+ * (if the request is retried, @a status is 100, the @a
+ * sip->sip_status->st_status contain the real status code
+ * from the response message, e.g., 302, 401, or 407)
+ * @param phrase a short textual description of @a status code
+ * @param nh operation handle associated with the call
+ * @param hmagic application context associated with the call
+ * @param sip response to UPDATE request or NULL upon an error
+ * (status code is in @a status and
+ * descriptive message in @a phrase parameters)
+ * @param tags empty
+ *
+ * @sa @ref nua_call_model, @RFC3311, nua_update(), #nua_i_update
+ *
+ * @END_NUA_EVENT
+ */
+
+static int process_response_to_update(nua_handle_t *nh,
+ nta_outgoing_t *orq,
+ sip_t const *sip)
+{
+ nua_t *nua = nh->nh_nua;
+ nua_session_usage_t *ss;
+ nua_client_request_t *cr = nh->nh_ds->ds_cr;
+
+ int status = sip->sip_status->st_status;
+ char const *phrase = sip->sip_status->st_phrase;
+ char const *recv = NULL;
+ int terminate = 0, gracefully = 1;
+
+ ss = nua_session_usage_get(nh->nh_ds); assert(ss);
+
+ if (status >= 300) {
+ if (sip->sip_retry_after)
+ gracefully = 0;
+
+ terminate = sip_response_terminates_dialog(status, sip_method_update,
+ &gracefully);
+
+ if (!terminate &&
+ check_session_timer_restart(nh, ss, cr, orq, sip, restart_update)) {
+ return 0;
+ }
+ /* XXX - if we have a concurrent INVITE, what we do with it? */
+ }
+ else if (status >= 200) {
+ /* XXX - check remote tag, handle forks */
+ /* Set (route), contact, (remote tag) */
+ nua_dialog_uac_route(nh, nh->nh_ds, sip, 1);
+ nua_dialog_store_peer_info(nh, nh->nh_ds, sip);
+
+ if (is_session_timer_set(ss)) {
+ init_session_timer(ss, sip, NH_PGET(nh, refresher));
+ set_session_timer(ss);
+ }
+
+ if (session_process_response(nh, cr, orq, sip, &recv) < 0) {
+ nua_stack_event(nua, nh, NULL, nua_i_error,
+ 400, "Bad Session Description", TAG_END());
+ }
+
+ signal_call_state_change(nh, ss, status, phrase, ss->ss_state, recv, 0);
+
+ return 0;
+ }
+ else
+ gracefully = 0;
+
+ nua_stack_process_response(nh, cr, orq, sip, TAG_END());
+
+ if (!terminate && !gracefully)
+ return 0;
+
+ nh_referral_respond(nh, status, phrase);
+
+ if (ss == NULL) {
+
+ }
+ else if (terminate ||
+ (ss->ss_state < nua_callstate_completed &&
+ ss->ss_state != nua_callstate_completing)) {
+ signal_call_state_change(nh, ss, status, phrase,
+ nua_callstate_terminated, recv, 0);
+ nua_session_usage_destroy(nh, ss);
+ }
+ else /* if (gracefully) */ {
+ signal_call_state_change(nh, ss, status, phrase,
+ nua_callstate_terminating, recv, 0);
+#if 0
+ if (nh->nh_ss->ss_crequest->cr_orq)
+ nua_stack_post_signal(nh, nua_r_cancel, TAG_END());
+ else
+#endif
+ nua_stack_post_signal(nh, nua_r_bye, TAG_END());
+ }
+
+ return 0;
+}
+
+int nua_stack_process_update(nua_t *nua,
+ nua_handle_t *nh,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ nua_dialog_state_t *ds = nh->nh_ds;
+ nua_session_usage_t *ss;
+ nua_dialog_usage_t *du;
+ msg_t *msg = nta_incoming_getrequest(irq);
+
+ char const *sdp;
+ size_t len;
+
+ int original_status = 200, status = 200;
+ char const *phrase = sip_200_OK;
+
+ char const *offer_recv = NULL, *answer_sent = NULL;
+ int use_timer = 0;
+
+ msg_t *rmsg;
+ sip_t *rsip;
+
+ ss = nua_session_usage_get(ds); du = nua_dialog_usage_public(ss);
+ if (!ss) {
+ /* RFC 3261 section 12.2.2:
+ If the UAS wishes to reject the request because it does not wish to
+ recreate the dialog, it MUST respond to the request with a 481
+ (Call/Transaction Does Not Exist) status code and pass that to the
+ server transaction.
+ */
+ return 481;
+ }
+
+ if (session_check_request(nua, nh, irq, sip))
+ return 501;
+
+ /* Do session timer negotiation */
+ if (sip->sip_session_expires) {
+ use_timer = 1;
+ init_session_timer(ss, sip, NH_PGET(nh, refresher));
+ }
+
+ if (status < 300 && nh->nh_soa &&
+ session_get_description(sip, &sdp, &len)) {
+ nua_client_request_t *cr;
+ nua_server_request_t *sr;
+ int overlap = 0;
+
+ /*
+ A UAS that receives an UPDATE before it has generated a final
+ response to a previous UPDATE on the same dialog MUST return a 500
+ response to the new UPDATE, and MUST include a Retry-After header
+ field with a randomly chosen value between 0 and 10 seconds.
+
+ If an UPDATE is received that contains an offer, and the UAS has
+ generated an offer (in an UPDATE, PRACK or INVITE) to which it has
+ not yet received an answer, the UAS MUST reject the UPDATE with a 491
+ response. Similarly, if an UPDATE is received that contains an
+ offer, and the UAS has received an offer (in an UPDATE, PRACK, or
+ INVITE) to which it has not yet generated an answer, the UAS MUST
+ reject the UPDATE with a 500 response, and MUST include a Retry-After
+ header field with a randomly chosen value between 0 and 10 seconds.
+ */
+ for (cr = ds->ds_cr; cr && !overlap; cr = cr->cr_next)
+ overlap = cr->cr_offer_sent && !cr->cr_answer_recv;
+ for (sr = ds->ds_sr; sr && !overlap; sr = sr->sr_next)
+ overlap = (sr->sr_offer_recv && !sr->sr_answer_sent) ||
+ (sr->sr_method == sip_method_update && sr->sr_respond);
+
+ if (overlap)
+ return respond_with_retry_after(nh, irq,
+ 500, "Overlapping Offer/Answer",
+ 0, 10);
+
+ offer_recv = "offer";
+
+ if (soa_set_remote_sdp(nh->nh_soa, NULL, sdp, len) < 0) {
+ SU_DEBUG_5(("nua(%p): error parsing SDP in UPDATE\n", nh));
+ msg_destroy(msg);
+ status = soa_error_as_sip_response(nh->nh_soa, &phrase);
+ offer_recv = NULL;
+ }
+ /* Respond to UPDATE */
+ else if (soa_generate_answer(nh->nh_soa, NULL) < 0) {
+ SU_DEBUG_5(("nua(%p): error processing SDP in UPDATE\n", nh));
+ msg_destroy(msg);
+ status = soa_error_as_sip_response(nh->nh_soa, &phrase);
+ }
+ else if (soa_activate(nh->nh_soa, NULL) < 0) {
+ SU_DEBUG_5(("nua(%p): error activating media after %s\n",
+ nh, "UPDATE"));
+ /* XXX */
+ }
+ else {
+ answer_sent = "answer";
+ }
+ }
+
+ rmsg = nh_make_response(nua, nh, irq,
+ status, phrase,
+ TAG_IF(status < 300, NUTAG_ADD_CONTACT(1)),
+ SIPTAG_SUPPORTED(NH_PGET(nh, supported)),
+ TAG_NEXT(NULL));
+ rsip = sip_object(rmsg);
+ assert(sip); /* XXX */
+
+ if (answer_sent &&
+ session_include_description(nh->nh_soa, 1, rmsg, rsip) < 0) {
+ status = 500, phrase = sip_500_Internal_server_error;
+ answer_sent = NULL;
+ }
+
+ if (200 <= status && status < 300 && session_timer_is_supported(nh)) {
+ use_session_timer(ss, 1, use_timer, rmsg, rsip);
+ set_session_timer(ss);
+ }
+
+ if (status == original_status) {
+ if (nta_incoming_mreply(irq, rmsg) < 0)
+ status = 500, phrase = sip_500_Internal_server_error;
+ }
+
+ if (status != original_status) {
+ nua_stack_event(nua, nh, NULL, nua_i_error, status, phrase, TAG_END());
+ nta_incoming_treply(irq, status, phrase, TAG_END());
+ msg_destroy(rmsg), rmsg = NULL;
+ }
+
+/** @NUA_EVENT nua_i_update
+ *
+ * @brief Incoming session UPDATE request.
+ *
+ * @param status statuscode of response sent automatically by stack
+ * @param phrase a short textual description of @a status code
+ * @param nh operation handle associated with the call
+ * @param hmagic application context associated with the call
+ * @param sip incoming UPDATE request
+ * @param tags empty
+ *
+ * @sa nua_update(), #nua_r_update, #nua_i_state
+ *
+ * @END_NUA_EVENT
+ */
+
+ nua_stack_event(nh->nh_nua, nh, msg, nua_i_update, status, phrase, TAG_END());
+
+ if (offer_recv || answer_sent)
+ /* signal offer received, answer sent */
+ signal_call_state_change(nh, ss, 200, "OK", ss->ss_state,
+ offer_recv, answer_sent);
+
+ if (NH_PGET(nh, auto_alert)
+ && ss->ss_state < nua_callstate_ready
+ && !ss->ss_alerting
+ && ss->ss_precondition) {
+ nua_server_request_t *sr;
+
+ for (sr = ds->ds_sr; sr; sr = sr->sr_next)
+ if (sr->sr_method == sip_method_invite &&
+ sr->sr_usage == du && sr->sr_respond)
+ break;
+
+ if (sr)
+ nua_server_respond(sr, SIP_180_RINGING, TAG_END());
+ }
+
+ return status;
+}
+
+
+/* ======================================================================== */
+/* BYE */
+
+static int process_response_to_bye(nua_handle_t *nh,
+ nta_outgoing_t *orq,
+ sip_t const *sip);
+
+/**@fn void nua_bye(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
+ *
+ * Hangdown a call.
+ *
+ * Hangdown a call using SIP BYE method. Also the media session
+ * associated with the call is terminated.
+ *
+ * @param nh Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return
+ * nothing
+ *
+ * @par Related Tags:
+ * none
+ *
+ * @par Events:
+ * #nua_r_bye \n
+ * #nua_i_media_error
+ */
+
+int
+nua_stack_bye(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags)
+{
+ nua_session_usage_t *ss;
+ nua_client_request_t *cr = nh->nh_ds->ds_cr;
+ msg_t *msg;
+ nta_outgoing_t *orq;
+
+ ss = nua_session_usage_get(nh->nh_ds);
+
+ if (!ss || ss->ss_state >= nua_callstate_terminating)
+ return UA_EVENT2(e, 900, "Invalid handle for BYE");
+
+ nua_stack_init_handle(nua, nh, TAG_NEXT(tags));
+
+ if (!nua_dialog_is_established(nh->nh_ds)) {
+ nua_client_request_t *cri = ss->ss_crequest;
+
+ if (cri->cr_orq == NULL)
+ return UA_EVENT2(e, 900, "No session to BYE");
+
+ /* No (early) dialog. BYE is invalid action, do CANCEL instead */
+ orq = nta_outgoing_tcancel(cri->cr_orq,
+ process_response_to_cancel, nh,
+ TAG_NEXT(tags));
+ if (!cr->cr_orq)
+ cr->cr_orq = orq, cr->cr_event = e;
+
+ return 0;
+ }
+
+ if (cr->cr_orq) {
+ if (cr->cr_usage == nua_dialog_usage_public(ss)) {
+ nua_creq_deinit(cr, cr->cr_orq);
+ }
+ else {
+ cr = ss->ss_crequest;
+ if (cr->cr_orq)
+ nua_creq_deinit(cr, cr->cr_orq);
+ }
+ }
+
+ assert(!cr->cr_orq);
+
+ msg = nua_creq_msg(nua, nh, cr, 0, SIP_METHOD_BYE, TAG_NEXT(tags));
+
+ cr->cr_orq = nta_outgoing_mcreate(nua->nua_nta,
+ process_response_to_bye, nh, NULL,
+ msg,
+ SIPTAG_END(), TAG_NEXT(tags));
+
+ ss->ss_state = nua_callstate_terminating;
+ if (nh->nh_soa)
+ soa_terminate(nh->nh_soa, 0);
+
+ if (cr->cr_orq) {
+ cr->cr_event = e;
+ }
+ else {
+ msg_destroy(msg);
+ UA_EVENT2(e, 400, "Internal error");
+ signal_call_state_change(nh, ss, 400, "Failure sending BYE",
+ nua_callstate_terminated, 0, 0);
+ nua_session_usage_destroy(nh, ss);
+ }
+
+ return 0;
+}
+
+
+void restart_bye(nua_handle_t *nh, tagi_t *tags)
+{
+ nua_creq_restart(nh, nh->nh_ds->ds_cr, process_response_to_bye, tags);
+}
+
+/** @NUA_EVENT nua_r_bye
+ *
+ * Answer to outgoing BYE.
+ *
+ * The BYE may be sent explicitly by nua_bye() or
+ * implicitly by NUA state machine.
+ *
+ * @param status response status code
+ * (if the request is retried, @a status is 100, the @a
+ * sip->sip_status->st_status contain the real status code
+ * from the response message, e.g., 302, 401, or 407)
+ * @param phrase a short textual description of @a status code
+ * @param nh operation handle associated with the call
+ * @param hmagic application context associated with the call
+ * @param sip response to BYE request or NULL upon an error
+ * (status code is in @a status and
+ * descriptive message in @a phrase parameters)
+ * @param tags empty
+ *
+ * @sa nua_bye(), @ref nua_call_model, #nua_i_state, #nua_r_invite()
+ *
+ * @END_NUA_EVENT
+ */
+
+static int process_response_to_bye(nua_handle_t *nh,
+ nta_outgoing_t *orq,
+ sip_t const *sip)
+{
+ nua_client_request_t *cr = NULL;
+ nua_session_usage_t *ss;
+ int status = sip ? sip->sip_status->st_status : 400;
+ char const *phrase = sip ? sip->sip_status->st_phrase : "";
+
+ cr = nua_client_request_by_orq(nh->nh_ds->ds_cr, orq); assert(cr);
+
+ if (cr) {
+ if (nua_creq_check_restart(nh, cr, orq, sip, restart_bye))
+ return 0;
+ nua_stack_process_response(nh, cr, orq, sip, TAG_END());
+ }
+ else { /* No cr for BYE */
+ msg_t *msg = nta_outgoing_getresponse(orq);
+ nua_stack_event(nh->nh_nua, nh, msg, nua_r_bye, status, phrase, TAG_END());
+ nta_outgoing_destroy(orq);
+ }
+
+ ss = nua_session_usage_get(nh->nh_ds);
+
+ if (status >= 200 && ss) {
+ if (ss->ss_crequest->cr_orq) {
+ /* Do not destroy usage while INVITE is alive */
+ }
+ else {
+ signal_call_state_change(nh, ss, status, "to BYE",
+ nua_callstate_terminated, 0, 0);
+ nua_session_usage_destroy(nh, ss);
+ }
+ }
+
+ return 0;
+}
+
+
+/** @NUA_EVENT nua_i_bye
+ *
+ * Incoming BYE request, call hangup.
+ *
+ * @param status statuscode of response sent automatically by stack
+ * @param phrase a short textual description of @a status code
+ * @param nh operation handle associated with the call
+ * @param hmagic application context associated with the call
+ * @param sip pointer to BYE request
+ * @param tags empty
+ *
+ * @sa @ref nua_call_model, #nua_i_state, nua_bye(), nua_bye(), #nua_r_cancel
+ *
+ * @END_NUA_EVENT
+ */
+
+int nua_stack_process_bye(nua_t *nua,
+ nua_handle_t *nh,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ nua_dialog_state_t *ds = nh->nh_ds;
+ nua_session_usage_t *ss;
+ nua_server_request_t *sr, *sr_next;
+ int early = 0;
+
+ ss = nua_session_usage_get(ds);
+ if (!ss)
+ return 481;
+
+ assert(nh && ss);
+
+ nua_stack_event(nh->nh_nua, nh, nta_incoming_getrequest(irq),
+ nua_i_bye, SIP_200_OK, TAG_END());
+ nta_incoming_treply(irq, SIP_200_OK, TAG_END());
+ nta_incoming_destroy(irq), irq = NULL;
+
+ for (sr = ds->ds_sr; sr; sr = sr_next) {
+ sr_next = sr->sr_next;
+ if (sr->sr_respond && sr->sr_usage == nua_dialog_usage_public(ss)) {
+ char const *phrase;
+ early = ss->ss_state < nua_callstate_ready;
+ phrase = early ? "Early Session Terminated" : "Session Terminated";
+ sr->sr_usage = NULL;
+ if (sr->sr_respond)
+ nua_server_respond(sr, 487, phrase, TAG_END());
+ else
+ nua_server_request_destroy(sr);
+ }
+ }
+
+ signal_call_state_change(nh, ss, 200,
+ early ? "Received early BYE" : "Received BYE",
+ nua_callstate_terminated, 0, 0);
+
+ nua_session_usage_destroy(nh, ss);
+
+ return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/**
+ * Delivers call state changed event to the nua client. @internal
+ *
+ * @param nh call handle
+ * @param status status code
+ * @param tr_event SIP transaction event triggering this change
+ * @param oa_recv Received SDP
+ * @param oa_sent Sent SDP
+ */
+
+static void signal_call_state_change(nua_handle_t *nh,
+ nua_session_usage_t *ss,
+ int status, char const *phrase,
+ enum nua_callstate next_state,
+ char const *oa_recv,
+ char const *oa_sent)
+{
+ enum nua_callstate ss_state;
+
+ sdp_session_t const *remote_sdp = NULL;
+ char const *remote_sdp_str = NULL;
+ sdp_session_t const *local_sdp = NULL;
+ char const *local_sdp_str = NULL;
+
+ int offer_recv = 0, answer_recv = 0, offer_sent = 0, answer_sent = 0;
+
+ ss_state = ss ? ss->ss_state : nua_callstate_init;
+
+ if (ss_state < nua_callstate_ready || next_state > nua_callstate_ready)
+ SU_DEBUG_5(("nua(%p): call state changed: %s -> %s%s%s%s%s\n",
+ nh, nua_callstate_name(ss_state),
+ nua_callstate_name(next_state),
+ oa_recv ? ", received " : "", oa_recv ? oa_recv : "",
+ oa_sent && oa_recv ? ", and sent " :
+ oa_sent ? ", sent " : "", oa_sent ? oa_sent : ""));
+ else
+ SU_DEBUG_5(("nua(%p): ready call updated: %s%s%s%s%s\n",
+ nh, nua_callstate_name(next_state),
+ oa_recv ? " received " : "", oa_recv ? oa_recv : "",
+ oa_sent && oa_recv ? ", sent " :
+ oa_sent ? " sent " : "", oa_sent ? oa_sent : ""));
+
+ if (oa_recv) {
+ soa_get_remote_sdp(nh->nh_soa, &remote_sdp, &remote_sdp_str, 0);
+ offer_recv = strcasecmp(oa_recv, "offer") == 0;
+ answer_recv = strcasecmp(oa_recv, "answer") == 0;
+ }
+
+ if (oa_sent) {
+ soa_get_local_sdp(nh->nh_soa, &local_sdp, &local_sdp_str, 0);
+ offer_sent = strcasecmp(oa_sent, "offer") == 0;
+ answer_sent = strcasecmp(oa_sent, "answer") == 0;
+ }
+
+ if (answer_recv || answer_sent) {
+ /* Update nh_hold_remote */
+
+ char const *held;
+
+ soa_get_params(nh->nh_soa, SOATAG_HOLD_REF(held), TAG_END());
+
+ nh->nh_hold_remote = held && strlen(held) > 0;
+ }
+
+ if (ss) {
+ /* Update state variables */
+ if (next_state > ss_state)
+ ss->ss_state = next_state;
+ else if (next_state == nua_callstate_init && ss_state < nua_callstate_ready)
+ ss->ss_state = nua_callstate_init, next_state = nua_callstate_terminated;
+ }
+
+ if (ss && ss->ss_state == nua_callstate_ready)
+ nh->nh_active_call = 1;
+ else if (next_state == nua_callstate_terminated)
+ nh->nh_active_call = 0;
+
+ /* Send events */
+ if (phrase == NULL)
+ phrase = "Call state";
+
+/** @NUA_EVENT nua_i_state
+ *
+ * @brief Call state has changed.
+ *
+ * This event will be sent whenever the call state changes.
+ *
+ * In addition to basic changes of session status indicated with enum
+ * ::nua_callstate, the @RFC3264 SDP Offer/Answer negotiation status is also
+ * included if it is enabled (by default or with NUTAG_MEDIA_ENABLE(1)). The
+ * received remote SDP is included in tag SOATAG_REMOTE_SDP(). The tags
+ * NUTAG_OFFER_RECV() or NUTAG_ANSWER_RECV() indicate whether the remote SDP
+ * was an offer or an answer. The SDP negotiation result is included in the
+ * tags SOATAG_LOCAL_SDP() and SOATAG_LOCAL_SDP_STR() and tags
+ * NUTAG_OFFER_SENT() or NUTAG_ANSWER_SENT() indicate whether the local SDP
+ * was an offer or answer.
+ *
+ * SOATAG_ACTIVE_AUDIO() and SOATAG_ACTIVE_VIDEO() are informational tags
+ * used to indicate what is the status of audio or video.
+ *
+ * Note that #nua_i_state also covers call establisment events
+ * (#nua_i_active) and termination (#nua_i_terminated).
+ *
+ * @param status protocol status code \n
+ * (always present)
+ * @param phrase short description of status code \n
+ * (always present)
+ * @param nh operation handle associated with the call
+ * @param hmagic application context associated with the call
+ * @param sip NULL
+ * @param tags NUTAG_CALLSTATE(),
+ * SOATAG_LOCAL_SDP(), SOATAG_LOCAL_SDP_STR(),
+ * NUTAG_OFFER_SENT(), NUTAG_ANSWER_SENT(),
+ * SOATAG_REMOTE_SDP(), SOATAG_REMOTE_SDP_STR(),
+ * NUTAG_OFFER_RECV(), NUTAG_ANSWER_RECV(),
+ * SOATAG_ACTIVE_AUDIO(), SOATAG_ACTIVE_VIDEO(),
+ * SOATAG_ACTIVE_IMAGE(), SOATAG_ACTIVE_CHAT().
+ *
+ * @sa @ref nua_call_model, #nua_i_active, #nua_i_terminated,
+ * nua_invite(), #nua_r_invite, #nua_i_invite, nua_respond(),
+ * NUTAG_AUTOALERT(), NUTAG_AUTOANSWER(), NUTAG_EARLY_MEDIA(),
+ * NUTAG_EARLY_ANSWER(), NUTAG_INCLUDE_EXTRA_SDP(),
+ * nua_ack(), NUTAG_AUTOACK(), nua_bye(), #nua_r_bye, #nua_i_bye,
+ * nua_cancel(), #nua_r_cancel, #nua_i_cancel,
+ * nua_prack(), #nua_r_prack, #nua_i_prack,
+ * nua_update(), #nua_r_update, #nua_i_update
+ *
+ * @END_NUA_EVENT
+ */
+
+ nua_stack_event(nh->nh_nua, nh, NULL, nua_i_state,
+ status, phrase,
+ NUTAG_CALLSTATE(next_state),
+ NH_ACTIVE_MEDIA_TAGS(1, nh->nh_soa),
+ /* NUTAG_SOA_SESSION(nh->nh_soa), */
+ TAG_IF(offer_recv, NUTAG_OFFER_RECV(offer_recv)),
+ TAG_IF(answer_recv, NUTAG_ANSWER_RECV(answer_recv)),
+ TAG_IF(offer_sent, NUTAG_OFFER_SENT(offer_sent)),
+ TAG_IF(answer_sent, NUTAG_ANSWER_SENT(answer_sent)),
+ TAG_IF(oa_recv, SOATAG_REMOTE_SDP(remote_sdp)),
+ TAG_IF(oa_recv, SOATAG_REMOTE_SDP_STR(remote_sdp_str)),
+ TAG_IF(oa_sent, SOATAG_LOCAL_SDP(local_sdp)),
+ TAG_IF(oa_sent, SOATAG_LOCAL_SDP_STR(local_sdp_str)),
+ TAG_END());
+
+/** @NUA_EVENT nua_i_active
+ *
+ * A call has been activated.
+ *
+ * This event will be sent after a succesful response to the initial
+ * INVITE has been received and the media has been activated.
+ *
+ * @param nh operation handle associated with the call
+ * @param hmagic application context associated with the call
+ * @param sip NULL
+ * @param tags SOATAG_ACTIVE_AUDIO(), SOATAG_ACTIVE_VIDEO(),
+ * SOATAG_ACTIVE_IMAGE(), SOATAG_ACTIVE_CHAT().
+ *
+ * @deprecated Use #nua_i_state instead.
+ *
+ * @sa @ref nua_call_model, #nua_i_state, #nua_i_terminated,
+ * #nua_i_invite
+ *
+ * @END_NUA_EVENT
+ */
+
+ if (next_state == nua_callstate_ready && ss_state <= nua_callstate_ready) {
+ nua_stack_event(nh->nh_nua, nh, NULL, nua_i_active, status, "Call active",
+ NH_ACTIVE_MEDIA_TAGS(1, nh->nh_soa),
+ /* NUTAG_SOA_SESSION(nh->nh_soa), */
+ TAG_END());
+ }
+
+/** @NUA_EVENT nua_i_terminated
+ *
+ * A call has been terminated.
+ *
+ * This event will be sent after a call has been terminated. A call is
+ * terminated, when
+ * 1) an error response (300..599) is sent to an incoming initial INVITE
+ * 2) a reliable response (200..299 or reliable preliminary response) to
+ * an incoming initial INVITE is not acknowledged with ACK or PRACK
+ * 3) BYE is received or sent
+ *
+ * @param nh operation handle associated with the call
+ * @param hmagic application context associated with the call
+ * @param sip NULL
+ * @param tags empty
+ *
+ * @deprecated Use #nua_i_state instead.
+ *
+ * @sa @ref nua_call_model, #nua_i_state, #nua_i_active, #nua_i_bye,
+ * #nua_i_invite
+ *
+ * @END_NUA_EVENT
+ */
+
+ else if (next_state == nua_callstate_terminated) {
+ nua_stack_event(nh->nh_nua, nh, NULL, nua_i_terminated, status, phrase,
+ TAG_END());
+ }
+}
+
+/* ======================================================================== */
+
+static
+int respond_with_retry_after(nua_handle_t *nh, nta_incoming_t *irq,
+ int status, char const *phrase,
+ int min, int max)
+{
+ sip_retry_after_t af[1];
+
+ sip_retry_after_init(af);
+ af->af_delta = (unsigned)su_randint(min, max);
+ af->af_comment = phrase;
+
+ nta_incoming_treply(irq, status, phrase,
+ SIPTAG_RETRY_AFTER(af),
+ SIPTAG_USER_AGENT_STR(NH_PGET(nh, user_agent)),
+ TAG_END());
+
+ return 500;
+}
+
+/* ======================================================================== */
+
+/** Get SDP from a SIP message */
+static
+int session_get_description(sip_t const *sip,
+ char const **return_sdp,
+ size_t *return_len)
+{
+ sip_payload_t const *pl = sip->sip_payload;
+ sip_content_type_t const *ct = sip->sip_content_type;
+ int matching_content_type = 0;
+
+ if (pl == NULL)
+ return 0;
+ else if (pl->pl_len == 0 || pl->pl_data == NULL)
+ return 0;
+ else if (ct == NULL)
+ /* Be bug-compatible with our old gateways */
+ SU_DEBUG_3(("nua: no %s, assuming %s\n",
+ "Content-Type", SDP_MIME_TYPE));
+ else if (ct->c_type == NULL)
+ SU_DEBUG_3(("nua: empty %s, assuming %s\n",
+ "Content-Type", SDP_MIME_TYPE));
+ else if (strcasecmp(ct->c_type, SDP_MIME_TYPE)) {
+ SU_DEBUG_5(("nua: unknown %s: %s\n", "Content-Type", ct->c_type));
+ return 0;
+ }
+ else
+ matching_content_type = 1;
+
+ if (pl == NULL)
+ return 0;
+
+ if (!matching_content_type) {
+ /* Make sure we got SDP */
+ if (pl->pl_len < 3 || strncasecmp(pl->pl_data, "v=0", 3))
+ return 0;
+ }
+
+ *return_sdp = pl->pl_data;
+ *return_len = pl->pl_len;
+
+ return 1;
+}
+
+/** Insert SDP into SIP message */
+static
+int session_include_description(soa_session_t *soa,
+ int session,
+ msg_t *msg,
+ sip_t *sip)
+{
+ su_home_t *home = msg_home(msg);
+
+ sip_content_disposition_t *cd = NULL;
+ sip_content_type_t *ct = NULL;
+ sip_payload_t *pl = NULL;
+
+ int retval;
+
+ if (!soa)
+ return 0;
+
+ retval = session_make_description(home, soa, session, &cd, &ct, &pl);
+
+ if (retval <= 0)
+ return retval;
+
+ if ((cd && sip_header_insert(msg, sip, (sip_header_t *)cd) < 0) ||
+ sip_header_insert(msg, sip, (sip_header_t *)ct) < 0 ||
+ sip_header_insert(msg, sip, (sip_header_t *)pl) < 0)
+ return -1;
+
+ return retval;
+}
+
+/** Generate SDP headers */
+static
+int session_make_description(su_home_t *home,
+ soa_session_t *soa,
+ int session,
+ sip_content_disposition_t **return_cd,
+ sip_content_type_t **return_ct,
+ sip_payload_t **return_pl)
+{
+ char const *sdp;
+ isize_t len;
+ int retval;
+
+ if (!soa)
+ return 0;
+
+ if (session)
+ retval = soa_get_local_sdp(soa, 0, &sdp, &len);
+ else
+ retval = soa_get_capability_sdp(soa, 0, &sdp, &len);
+
+ if (retval > 0) {
+ *return_pl = sip_payload_create(home, sdp, len);
+ *return_ct = sip_content_type_make(home, SDP_MIME_TYPE);
+ if (session)
+ *return_cd = sip_content_disposition_make(home, "session");
+ else
+ *return_cd = NULL;
+
+ if (!*return_pl || !*return_cd)
+ return -1;
+
+ if (session && !*return_cd)
+ return -1;
+ }
+
+ return retval;
+}
+
+/**
+ * Stores and processes SDP from incoming response, then calls
+ * nua_stack_process_response().
+ *
+ * @retval 1 if there was SDP to process.
+ */
+static
+int session_process_response(nua_handle_t *nh,
+ nua_client_request_t *cr,
+ nta_outgoing_t *orq,
+ sip_t const *sip,
+ char const **return_received)
+{
+ char const *method = nta_outgoing_method_name(orq);
+ msg_t *msg = nta_outgoing_getresponse(orq);
+ int retval = 0;
+ char const *sdp = NULL;
+ size_t len;
+
+ if (nh->nh_soa == NULL)
+ /* Xyzzy */;
+ else if (!session_get_description(sip, &sdp, &len))
+ /* No SDP */;
+ else if (cr->cr_answer_recv) {
+ /* Ignore spurious answers after completing O/A */
+ SU_DEBUG_3(("nua(%p): %s: ignoring duplicate SDP in %u %s\n",
+ nh, method,
+ sip->sip_status->st_status, sip->sip_status->st_phrase));
+ sdp = NULL;
+ }
+ else if (!cr->cr_offer_sent &&
+ nta_outgoing_method(orq) != sip_method_invite) {
+ /* If non-invite request did not have offer, ignore SDP in response */
+ SU_DEBUG_3(("nua(%p): %s: ignoring extra SDP in %u %s\n",
+ nh, method,
+ sip->sip_status->st_status, sip->sip_status->st_phrase));
+ sdp = NULL;
+ }
+ else {
+ if (cr->cr_offer_sent) {
+ cr->cr_answer_recv = sip->sip_status->st_status;
+ *return_received = "answer";
+ }
+ else {
+ cr->cr_offer_recv = 1, cr->cr_answer_sent = 0;
+ *return_received = "offer";
+ }
+
+ if (soa_set_remote_sdp(nh->nh_soa, NULL, sdp, len) < 0) {
+ SU_DEBUG_5(("nua(%p): %s: error parsing SDP in %u %s\n",
+ nh, method,
+ sip->sip_status->st_status,
+ sip->sip_status->st_phrase));
+ retval = -1;
+ sdp = NULL;
+ }
+ else if (cr->cr_offer_recv) {
+ /* note: case 1: incoming offer */
+ SU_DEBUG_5(("nua(%p): %s: get SDP %s in %u %s\n",
+ nh, method, "offer",
+ sip->sip_status->st_status,
+ sip->sip_status->st_phrase));
+ retval = 1;
+ }
+ else if (soa_process_answer(nh->nh_soa, NULL) < 0) {
+ SU_DEBUG_5(("nua(%p): %s: error processing SDP answer in %u %s\n",
+ nh, method,
+ sip->sip_status->st_status,
+ sip->sip_status->st_phrase));
+ sdp = NULL;
+ }
+ else {
+ /* note: case 2: answer to our offer */
+ if (soa_activate(nh->nh_soa, NULL) < 0) {
+ SU_DEBUG_3(("nua(%p): %s: error activating media after %u %s\n",
+ nh, method,
+ sip->sip_status->st_status,
+ sip->sip_status->st_phrase));
+ /* XXX */
+ }
+ else {
+ SU_DEBUG_5(("nua(%p): %s: processed SDP answer in %u %s\n",
+ nh, method,
+ sip->sip_status->st_status,
+ sip->sip_status->st_phrase));
+ }
+
+ assert(!cr->cr_offer_recv);
+ }
+ }
+
+ msg_destroy(msg); /* unref */
+
+ nua_stack_process_response(nh, cr, orq, sip,
+ NH_REMOTE_MEDIA_TAGS(sdp != NULL, nh->nh_soa),
+ TAG_END());
+
+ return retval;
+}
+
+#if 0
+/** Parse and store SDP from incoming request */
+static
+int session_process_request(nua_handle_t *nh,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ char const *sdp = NULL;
+ isize_t len;
+
+ if (nh->nh_soa) {
+ msg_t *msg = nta_outgoing_getresponse(irq);
+
+ if (session_get_description(msg, sip, &sdp, &len)) {
+ if (soa_is_complete(nh->nh_soa)) {
+ /* Ignore spurious answers after completing O/A */
+ SU_DEBUG_5(("nua: ignoring duplicate SDP in %u %s\n",
+ sip->sip_status->st_status, sip->sip_status->st_phrase));
+ sdp = NULL;
+ }
+ else if (soa_parse_sdp(nh->nh_soa, sdp, len) < 0) {
+ SU_DEBUG_5(("nua: error parsing SDP in %u %s\n",
+ sip->sip_status->st_status,
+ sip->sip_status->st_phrase));
+ sdp = NULL;
+ }
+ }
+
+ msg_destroy(msg);
+ }
+
+ return
+ nua_stack_process_response(nh, cr, orq, sip,
+ NH_REMOTE_MEDIA_TAGS(sdp != NULL, nh->nh_soa),
+ TAG_END());
+}
+#endif
+
+static int respond_to_options(nua_server_request_t *sr, tagi_t const *tags);
+
+/** @NUA_EVENT nua_i_options
+ *
+ * Incoming OPTIONS request. The user-agent should respond to an OPTIONS
+ * request with the same statuscode as it would respond to an INVITE
+ * request.
+ *
+ * Stack responds automatically to OPTIONS request unless OPTIONS is
+ * included in the set of application methods, set by NUTAG_APPL_METHOD().
+ *
+ * The OPTIONS request does not create a dialog. Currently the processing
+ * of incoming OPTIONS creates a new handle for each incoming request which
+ * is not assiciated with an existing dialog. If the handle @a nh is not
+ * bound, you should probably destroy it after responding to the OPTIONS
+ * request.
+ *
+ * @param status status code of response sent automatically by stack
+ * @param phrase a short textual description of @a status code
+ * @param nh operation handle associated with the OPTIONS request
+ * @param hmagic application context associated with the call
+ * (NULL if outside session)
+ * @param sip incoming OPTIONS request
+ * @param tags empty
+ *
+ * @sa nua_respond(), nua_options(), #nua_r_options, @RFC3261 section 11.2
+ *
+ * @END_NUA_EVENT
+ */
+
+int nua_stack_process_options(nua_t *nua,
+ nua_handle_t *nh,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ nua_server_request_t *sr, sr0[1];
+ int done;
+
+ /* Hook to outbound */
+ done = nua_registration_process_request(nua->nua_registrations, irq, sip);
+ if (done)
+ return done;
+
+ sr = nua_server_request(nua, nh, irq, sip, SR_INIT(sr0), sizeof *sr,
+ respond_to_options, 0);
+
+ SR_STATUS1(sr, SIP_200_OK);
+
+ return nua_stack_server_event(nua, sr, nua_i_options, TAG_END());
+}
+
+/** @internal Respond to an OPTIONS request.
+ *
+ */
+static int respond_to_options(nua_server_request_t *sr, tagi_t const *tags)
+{
+ nua_handle_t *nh = sr->sr_owner;
+ nua_t *nua = nh->nh_nua;
+ msg_t *msg;
+ int final;
+
+ msg = nua_server_response(sr,
+ sr->sr_status, sr->sr_phrase,
+ SIPTAG_ALLOW(NH_PGET(nh, allow)),
+ SIPTAG_SUPPORTED(NH_PGET(nh, supported)),
+ TAG_IF(NH_PGET(nh, path_enable),
+ SIPTAG_SUPPORTED_STR("path")),
+ SIPTAG_ACCEPT_STR(SDP_MIME_TYPE),
+ TAG_NEXT(tags));
+
+ final = sr->sr_status >= 200;
+
+ if (msg) {
+ sip_t *sip = sip_object(msg);
+
+ if (!sip->sip_payload) { /* XXX - do MIME multipart? */
+ soa_session_t *soa = nh->nh_soa;
+
+ if (soa == NULL)
+ soa = nua->nua_dhandle->nh_soa;
+
+ session_include_description(soa, 0, msg, sip);
+ }
+
+ if (nta_incoming_mreply(sr->sr_irq, msg) < 0)
+ final = 1;
+ }
+
+ return final;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,2113 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nua_stack.c
+ * @brief Sofia-SIP User Agent Engine implementation
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Kai Vehmanen <Kai.Vehmanen at nokia.com>
+ * @author Martti Mela <Martti Mela at nokia.com>
+ * @author Remeres Jacobs <Remeres.Jacobs at nokia.com>
+ * @author Tat Chan <Tat.Chan at nokia.com>
+ *
+ * @date Created: Wed Feb 14 18:32:58 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/su_tagarg.h>
+#include <sofia-sip/su_strlst.h>
+#include <sofia-sip/su_uniqueid.h>
+
+#include <sofia-sip/su_tag_io.h>
+
+#define SU_ROOT_MAGIC_T struct nua_s
+#define SU_MSG_ARG_T struct event_s
+
+#define NUA_SAVED_EVENT_T su_msg_t *
+
+#define NTA_AGENT_MAGIC_T struct nua_s
+#define NTA_LEG_MAGIC_T struct nua_handle_s
+#define NTA_OUTGOING_MAGIC_T struct nua_handle_s
+#define NTA_INCOMING_MAGIC_T struct nua_handle_s
+
+#include <sofia-sip/sip.h>
+#include <sofia-sip/sip_header.h>
+#include <sofia-sip/sip_status.h>
+#include <sofia-sip/sip_util.h>
+
+#include <sofia-sip/tport_tag.h>
+#include <sofia-sip/nta.h>
+#include <sofia-sip/nta_tport.h>
+#include <sofia-sip/auth_client.h>
+
+#include <sofia-sip/soa.h>
+
+#include "sofia-sip/nua.h"
+#include "sofia-sip/nua_tag.h"
+#include "nua_stack.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <stdio.h>
+
+#include <assert.h>
+
+/* ========================================================================
+ *
+ * Protocol stack side
+ *
+ * ======================================================================== */
+
+nua_handle_t *nh_create(nua_t *nua, tag_type_t t, tag_value_t v, ...);
+static void nh_append(nua_t *nua, nua_handle_t *nh);
+static void nh_remove(nua_t *nua, nua_handle_t *nh);
+
+static int nh_authorize(nua_handle_t *nh,
+ tag_type_t tag, tag_value_t value, ...);
+
+static int nh_challenge(nua_handle_t *nh, sip_t const *sip);
+
+static void nua_stack_timer(nua_t *nua, su_timer_t *t, su_timer_arg_t *a);
+
+/* ---------------------------------------------------------------------- */
+/* Constant data */
+
+/**@internal Default internal error. */
+char const nua_internal_error[] = "Internal NUA Error";
+
+char const nua_application_sdp[] = "application/sdp";
+
+#define NUA_STACK_TIMER_INTERVAL (1000)
+
+/* ----------------------------------------------------------------------
+ * Initialization & deinitialization
+ */
+
+int nua_stack_init(su_root_t *root, nua_t *nua)
+{
+ su_home_t *home;
+ nua_handle_t *dnh;
+
+ static int initialized_logs = 0;
+
+ enter;
+
+ if (!initialized_logs) {
+ extern su_log_t tport_log[];
+ extern su_log_t nta_log[];
+ extern su_log_t nea_log[];
+ extern su_log_t iptsec_log[];
+
+ su_log_init(tport_log);
+ su_log_init(nta_log);
+ su_log_init(nea_log);
+ su_log_init(iptsec_log);
+
+ initialized_logs = 1;
+ }
+
+ nua->nua_root = root;
+ nua->nua_timer = su_timer_create(su_root_task(root),
+ NUA_STACK_TIMER_INTERVAL);
+ if (!nua->nua_timer)
+ return -1;
+
+ home = nua->nua_home;
+ nua->nua_handles_tail = &nua->nua_handles;
+ sip_from_init(nua->nua_from);
+
+ dnh = su_home_clone(nua->nua_home, sizeof (*dnh) + sizeof(*dnh->nh_prefs));
+ if (!dnh)
+ return -1;
+
+ dnh->nh_prefs = (void *)(dnh + 1);
+ dnh->nh_valid = nua_handle;
+ dnh->nh_nua = nua;
+ nua_handle_ref(dnh); dnh->nh_ref_by_stack = 1;
+ nua_handle_ref(dnh); dnh->nh_ref_by_user = 1;
+ nh_append(nua, dnh);
+ dnh->nh_identity = dnh;
+ dnh->nh_ds->ds_local = nua->nua_from;
+ dnh->nh_ds->ds_remote = nua->nua_from;
+
+ if (nua_stack_set_defaults(dnh, dnh->nh_prefs) < 0)
+ return -1;
+
+ if (nua_stack_set_params(nua, dnh, nua_i_none, nua->nua_args) < 0)
+ return -1;
+
+ nua->nua_invite_accept = sip_accept_make(home, SDP_MIME_TYPE);
+
+ nua->nua_nta = nta_agent_create(root, NONE, NULL, NULL,
+ NTATAG_MERGE_482(1),
+ NTATAG_CLIENT_RPORT(1),
+ NTATAG_UA(1),
+#if HAVE_SOFIA_SMIME
+ NTATAG_SMIME(nua->sm),
+#endif
+ TPTAG_STUN_SERVER(1),
+ TAG_NEXT(nua->nua_args));
+
+ dnh->nh_ds->ds_leg = nta_leg_tcreate(nua->nua_nta,
+ nua_stack_process_request, dnh,
+ NTATAG_NO_DIALOG(1),
+ TAG_END());
+
+ if (nua->nua_nta == NULL ||
+ dnh->nh_ds->ds_leg == NULL ||
+ nta_agent_set_params(nua->nua_nta, NTATAG_UA(1), TAG_END()) < 0 ||
+ nua_stack_init_transport(nua, nua->nua_args) < 0) {
+ SU_DEBUG_1(("nua: initializing SIP stack failed\n"));
+ return -1;
+ }
+
+ if (nua_stack_set_from(nua, 1, nua->nua_args) < 0)
+ return -1;
+
+ if (NHP_ISSET(dnh->nh_prefs, detect_network_updates))
+ nua_stack_launch_network_change_detector(nua);
+
+ nua_stack_timer(nua, nua->nua_timer, NULL);
+
+ return 0;
+}
+
+void nua_stack_deinit(su_root_t *root, nua_t *nua)
+{
+ enter;
+
+ su_timer_destroy(nua->nua_timer), nua->nua_timer = NULL;
+ nta_agent_destroy(nua->nua_nta), nua->nua_nta = NULL;
+}
+
+/* ----------------------------------------------------------------------
+ * Sending events to client application
+ */
+
+static void nua_stack_shutdown(nua_t *);
+
+void
+ nua_stack_authenticate(nua_t *, nua_handle_t *, nua_event_t, tagi_t const *),
+ nua_stack_respond(nua_t *, nua_handle_t *, int , char const *, tagi_t const *),
+ nua_stack_destroy_handle(nua_t *, nua_handle_t *, tagi_t const *);
+
+/* Notifier */
+void
+ nua_stack_authorize(nua_t *, nua_handle_t *, nua_event_t, tagi_t const *),
+ nua_stack_notifier(nua_t *, nua_handle_t *, nua_event_t, tagi_t const *),
+ nua_stack_terminate(nua_t *, nua_handle_t *, nua_event_t, tagi_t const *);
+
+int nh_notifier_shutdown(nua_handle_t *nh, nea_event_t *ev,
+ tag_type_t t, tag_value_t v, ...);
+
+/** @internal Send an event to the application. */
+int nua_stack_event(nua_t *nua, nua_handle_t *nh, msg_t *msg,
+ nua_event_t event, int status, char const *phrase,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ su_msg_r sumsg = SU_MSG_R_INIT;
+
+ ta_list ta;
+ size_t e_len, len, xtra, p_len;
+
+ if (event == nua_r_ack || event == nua_i_none)
+ return event;
+
+ enter;
+
+ if (nua_log->log_level >= 5) {
+ char const *name = nua_event_name(event) + 4;
+ char const *p = phrase ? phrase : "";
+
+ if (status == 0)
+ SU_DEBUG_5(("nua(%p): %s %s\n", nh, name, p));
+ else
+ SU_DEBUG_5(("nua(%p): %s %u %s\n", nh, name, status, p));
+ }
+
+ if (event == nua_r_destroy) {
+ if (msg)
+ msg_destroy(msg);
+ if (status >= 200) {
+ nh_destroy(nua, nh);
+ }
+ return event;
+ }
+
+ if ((event > nua_r_authenticate && event <= nua_r_ack)
+ || event < nua_i_error
+ || (nh && !nh->nh_valid)
+ || (nua->nua_shutdown && event != nua_r_shutdown)) {
+ if (msg)
+ msg_destroy(msg);
+ return event;
+ }
+
+ ta_start(ta, tag, value);
+
+ e_len = offsetof(event_t, e_tags);
+ len = tl_len(ta_args(ta));
+ xtra = tl_xtra(ta_args(ta), len);
+ p_len = phrase ? strlen(phrase) + 1 : 1;
+
+ if (su_msg_create(sumsg, nua->nua_client, su_task_null,
+ nua_event, e_len + len + xtra + p_len) == 0) {
+ event_t *e = su_msg_data(sumsg);
+
+ tagi_t *t = e->e_tags, *t_end = (tagi_t *)((char *)t + len);
+ void *b = t_end, *end = (char *)b + xtra;
+
+ t = tl_dup(t, ta_args(ta), &b);
+ assert(t == t_end); assert(b == end);
+
+ e->e_event = event;
+ e->e_nh = nh ? nua_handle_ref(nh) : nua->nua_dhandle;
+ e->e_status = status;
+ e->e_phrase = strcpy(end, phrase ? phrase : "");
+ if (msg)
+ e->e_msg = msg, su_home_threadsafe(msg_home(msg));
+
+ if (su_msg_send(sumsg) != 0)
+ nua_handle_unref(nh);
+ }
+
+ ta_end(ta);
+
+ return event;
+}
+
+/* ----------------------------------------------------------------------
+ * Post signal to stack itself
+ */
+void nua_stack_post_signal(nua_handle_t *nh, nua_event_t event,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ ta_list ta;
+ ta_start(ta, tag, value);
+ nua_signal((nh)->nh_nua, nh, NULL, 1, event, 0, NULL, ta_tags(ta));
+ ta_end(ta);
+}
+
+
+/* ----------------------------------------------------------------------
+ * Receiving events from client
+ */
+void nua_stack_signal(nua_t *nua, su_msg_r msg, nua_event_data_t *e)
+{
+ nua_handle_t *nh = e->e_nh;
+ tagi_t *tags = e->e_tags;
+
+ assert(tags);
+
+ if (nh) {
+ if (!nh->nh_prev)
+ nh_append(nua, nh);
+ if (!nh->nh_ref_by_stack) {
+ /* Mark handle as used by stack */
+ nh->nh_ref_by_stack = 1;
+ nua_handle_ref(nh);
+ }
+ }
+
+ if (nua_log->log_level >= 5) {
+ char const *name = nua_event_name(e->e_event);
+ if (e->e_status == 0)
+ SU_DEBUG_5(("nua(%p): signal %s\n", nh, name + 4));
+ else
+ SU_DEBUG_5(("nua(%p): signal %s %u %s\n",
+ nh, name + 4, e->e_status, e->e_phrase ? e->e_phrase : ""));
+ }
+
+ su_msg_save(nua->nua_signal, msg);
+
+ if (nua->nua_shutdown && !e->e_always) {
+ /* Shutting down */
+ nua_stack_event(nua, nh, NULL, e->e_event,
+ 901, "Stack is going down",
+ TAG_END());
+ }
+
+ else switch (e->e_event) {
+ case nua_r_get_params:
+ nua_stack_get_params(nua, nh ? nh : nua->nua_dhandle, e->e_event, tags);
+ break;
+ case nua_r_set_params:
+ nua_stack_set_params(nua, nh ? nh : nua->nua_dhandle, e->e_event, tags);
+ break;
+ case nua_r_shutdown:
+ nua_stack_shutdown(nua);
+ break;
+ case nua_r_register:
+ case nua_r_unregister:
+ nua_stack_register(nua, nh, e->e_event, tags);
+ break;
+ case nua_r_invite:
+ nua_stack_invite(nua, nh, e->e_event, tags);
+ break;
+ case nua_r_cancel:
+ nua_stack_cancel(nua, nh, e->e_event, tags);
+ break;
+ case nua_r_bye:
+ nua_stack_bye(nua, nh, e->e_event, tags);
+ break;
+ case nua_r_options:
+ nua_stack_options(nua, nh, e->e_event, tags);
+ break;
+ case nua_r_refer:
+ nua_stack_refer(nua, nh, e->e_event, tags);
+ break;
+ case nua_r_publish:
+ case nua_r_unpublish:
+ nua_stack_publish(nua, nh, e->e_event, tags);
+ break;
+ case nua_r_info:
+ nua_stack_info(nua, nh, e->e_event, tags);
+ break;
+ case nua_r_update:
+ nua_stack_update(nua, nh, e->e_event, tags);
+ break;
+ case nua_r_message:
+ nua_stack_message(nua, nh, e->e_event, tags);
+ break;
+ case nua_r_subscribe:
+ case nua_r_unsubscribe:
+ nua_stack_subscribe(nua, nh, e->e_event, tags);
+ break;
+ case nua_r_notify:
+ nua_stack_notify(nua, nh, e->e_event, tags);
+ break;
+ case nua_r_notifier:
+ nua_stack_notifier(nua, nh, e->e_event, tags);
+ break;
+ case nua_r_terminate:
+ nua_stack_terminate(nua, nh, e->e_event, tags);
+ break;
+ case nua_r_method:
+ nua_stack_method(nua, nh, e->e_event, tags);
+ break;
+ case nua_r_authenticate:
+ nua_stack_authenticate(nua, nh, e->e_event, tags);
+ break;
+ case nua_r_authorize:
+ nua_stack_authorize(nua, nh, e->e_event, tags);
+ break;
+ case nua_r_ack:
+ nua_stack_ack(nua, nh, e->e_event, tags);
+ break;
+ case nua_r_respond:
+ nua_stack_respond(nua, nh, e->e_status, e->e_phrase, tags);
+ break;
+ case nua_r_destroy:
+ nua_stack_destroy_handle(nua, nh, tags);
+ break;
+ default:
+ break;
+ }
+
+ if (su_msg_is_non_null(nua->nua_signal))
+ su_msg_destroy(nua->nua_signal);
+
+ if (nh != nua->nua_dhandle)
+ nua_handle_unref(nh);
+}
+
+/* ====================================================================== */
+
+static int nh_call_pending(nua_handle_t *nh, sip_time_t time);
+
+/**@internal
+ * Timer routine.
+ *
+ * Go through all active handles and execute pending tasks
+ */
+void nua_stack_timer(nua_t *nua, su_timer_t *t, su_timer_arg_t *a)
+{
+ nua_handle_t *nh, *nh_next;
+ sip_time_t now = sip_now();
+ su_root_t *root = su_timer_root(t);
+
+ su_timer_set(t, nua_stack_timer, a);
+
+ if (nua->nua_shutdown) {
+ nua_stack_shutdown(nua);
+ return;
+ }
+
+ for (nh = nua->nua_handles; nh; nh = nh_next) {
+ nh_next = nh->nh_next;
+ nh_call_pending(nh, now);
+ su_root_yield(root); /* Handle received packets */
+ }
+}
+
+
+static
+int nh_call_pending(nua_handle_t *nh, sip_time_t now)
+{
+ nua_dialog_state_t *ds = nh->nh_ds;
+ nua_dialog_usage_t *du;
+ sip_time_t next = now + NUA_STACK_TIMER_INTERVAL / 1000;
+
+ for (du = ds->ds_usage; du; du = du->du_next) {
+ if (now == 0)
+ break;
+ if (du->du_refresh && du->du_refresh < next)
+ break;
+ }
+
+ if (du == NULL)
+ return 0;
+
+ nua_handle_ref(nh);
+
+ while (du) {
+ nua_dialog_usage_t *du_next = du->du_next;
+
+ nua_dialog_usage_refresh(nh, ds, du, now);
+
+ if (du_next == NULL)
+ break;
+
+ for (du = nh->nh_ds->ds_usage; du; du = du->du_next)
+ if (du == du_next)
+ break;
+
+ for (; du; du = du->du_next) {
+ if (now == 0)
+ break;
+ if (du->du_refresh && du->du_refresh < next)
+ break;
+ }
+ }
+
+ nua_handle_unref(nh);
+
+ return 1;
+}
+
+
+/* ====================================================================== */
+
+/**Shutdown a @nua stack.
+ *
+ * When the @nua stack is shutdown, ongoing calls are released,
+ * registrations unregistered, publications un-PUBLISHed and subscriptions
+ * terminated. If the stack cannot terminate everything within 30 seconds,
+ * it sends the #nua_r_shutdown event with status 500.
+ *
+ * @param nua Pointer to @nua stack object
+ *
+ * @return
+ * nothing
+ *
+ * @par Related tags:
+ * none
+ *
+ * @par Events:
+ * #nua_r_shutdown
+ *
+ * @sa #nua_r_shutdown, nua_destroy(), nua_create(), nua_bye(),
+ * nua_unregister(), nua_unpublish(), nua_unsubscribe(), nua_notify(),
+ * nua_handle_destroy(), nua_handle_unref()
+ */
+
+/** @NUA_EVENT nua_r_shutdown
+ *
+ * Answer to nua_shutdown().
+ *
+ * Status codes
+ * - 100 shutdown started
+ * - 101 shutdown in progress (sent when shutdown has been progressed)
+ * - 200 shutdown was successful
+ * - 500 shutdown timeout after 30 sec
+ *
+ * @param status shutdown status code
+ * @param nh NULL
+ * @param hmagic NULL
+ * @param sip NULL
+ * @param tags empty
+ *
+ * @sa nua_shutdown(), nua_destroy()
+ *
+ * @END_NUA_EVENT
+ */
+
+/** @internal Shut down stack. */
+void nua_stack_shutdown(nua_t *nua)
+{
+ nua_handle_t *nh, *nh_next;
+ int busy = 0;
+ sip_time_t now = sip_now();
+ int status;
+ char const *phrase;
+
+ enter;
+
+ if (!nua->nua_shutdown)
+ nua->nua_shutdown = now;
+
+ for (nh = nua->nua_handles; nh; nh = nh_next) {
+ nua_dialog_state_t *ds = nh->nh_ds;
+ nua_server_request_t *sr, *sr_next;
+
+ nh_next = nh->nh_next;
+
+ for (sr = ds->ds_sr; sr; sr = sr_next) {
+ sr_next = sr->sr_next;
+
+ if (sr->sr_respond) {
+ SR_STATUS1(sr, SIP_410_GONE);
+ sr->sr_usage = NULL;
+ sr->sr_respond(sr, NULL);
+ sr->sr_respond = NULL;
+ busy++;
+ }
+
+ nua_server_request_destroy(sr);
+ }
+
+ busy += nh_call_pending(nh, 0);
+
+ if (nh->nh_soa) {
+ soa_destroy(nh->nh_soa), nh->nh_soa = NULL;
+ }
+
+ if (nua_client_request_pending(ds->ds_cr))
+ busy++;
+
+ if (nh_notifier_shutdown(nh, NULL, NEATAG_REASON("noresource"), TAG_END()))
+ busy++;
+ }
+
+ if (!busy)
+ SET_STATUS(200, "Shutdown successful");
+ else if (now == nua->nua_shutdown)
+ SET_STATUS(100, "Shutdown started");
+ else if (now - nua->nua_shutdown < 30)
+ SET_STATUS(101, "Shutdown in progress");
+ else
+ SET_STATUS(500, "Shutdown timeout");
+
+ if (status >= 200) {
+ for (nh = nua->nua_handles; nh; nh = nh_next) {
+ nh_next = nh->nh_next;
+ while (nh->nh_ds && nh->nh_ds->ds_usage) {
+ nua_dialog_usage_remove(nh, nh->nh_ds, nh->nh_ds->ds_usage);
+ }
+ }
+ su_timer_destroy(nua->nua_timer), nua->nua_timer = NULL;
+ nta_agent_destroy(nua->nua_nta), nua->nua_nta = NULL;
+ }
+
+ nua_stack_event(nua, NULL, NULL, nua_r_shutdown, status, phrase, TAG_END());
+}
+
+/* ---------------------------------------------------------------------- */
+
+/** @internal Create a handle */
+nua_handle_t *nh_create(nua_t *nua, tag_type_t tag, tag_value_t value, ...)
+{
+ ta_list ta;
+ nua_handle_t *nh;
+
+ enter;
+
+ ta_start(ta, tag, value);
+ nh = nh_create_handle(nua, NULL, ta_args(ta));
+ ta_end(ta);
+
+ if (nh) {
+ nh->nh_ref_by_stack = 1;
+ nh_append(nua, nh);
+ }
+
+ return nh;
+}
+
+/** @internal Append an handle to the list of handles */
+void nh_append(nua_t *nua, nua_handle_t *nh)
+{
+ nh->nh_next = NULL;
+ nh->nh_prev = nua->nua_handles_tail;
+ *nua->nua_handles_tail = nh;
+ nua->nua_handles_tail = &nh->nh_next;
+}
+
+nua_handle_t *nh_validate(nua_t *nua, nua_handle_t *maybe)
+{
+ nua_handle_t *nh;
+
+ if (maybe)
+ for (nh = nua->nua_handles; nh; nh = nh->nh_next)
+ if (nh == maybe)
+ return nh;
+
+ return NULL;
+}
+
+void nua_stack_destroy_handle(nua_t *nua, nua_handle_t *nh, tagi_t const *tags)
+{
+ nh_call_pending(nh, 0); /* Call pending operations with 0 */
+
+ if (nh->nh_notifier)
+ nua_stack_terminate(nua, nh, 0, NULL);
+
+#if 0
+ if (nh->nh_ref_by_user) {
+ nh->nh_ref_by_user = 0;
+ nua_handle_unref(nh);
+ }
+#endif
+
+ nh_destroy(nua, nh);
+}
+
+#define nh_is_inserted(nh) ((nh)->nh_prev != NULL)
+
+/** @internal Remove a handle from list of handles */
+static
+void nh_remove(nua_t *nua, nua_handle_t *nh)
+{
+ assert(nh_is_inserted(nh)); assert(*nh->nh_prev == nh);
+
+ if (nh->nh_next)
+ nh->nh_next->nh_prev = nh->nh_prev;
+ else
+ nua->nua_handles_tail = nh->nh_prev;
+
+ *nh->nh_prev = nh->nh_next;
+
+ nh->nh_prev = NULL;
+ nh->nh_next = NULL;
+}
+
+
+void nh_destroy(nua_t *nua, nua_handle_t *nh)
+{
+ assert(nh); assert(nh != nua->nua_dhandle);
+
+ nh_enter;
+
+ if (nh->nh_notifier)
+ nea_server_destroy(nh->nh_notifier), nh->nh_notifier = NULL;
+
+ nua_creq_deinit(nh->nh_ds->ds_cr, NULL);
+
+ nua_dialog_deinit(nh, nh->nh_ds);
+
+ if (nh->nh_soa)
+ soa_destroy(nh->nh_soa), nh->nh_soa = NULL;
+
+ if (nh_is_inserted(nh))
+ nh_remove(nua, nh);
+
+ nua_handle_unref(nh); /* Remove stack reference */
+}
+
+/* ======================================================================== */
+
+/**@internal
+ * Initialize handle Allow and authentication info, save parameters.
+ *
+ * @retval -1 upon an error
+ * @retval 0 when successful
+ */
+int nua_stack_init_handle(nua_t *nua, nua_handle_t *nh,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ ta_list ta;
+ int retval = 0;
+
+ if (nh == NULL)
+ return -1;
+
+ assert(nh != nua->nua_dhandle);
+
+ ta_start(ta, tag, value);
+
+ if (nua_stack_set_params(nua, nh, nua_i_error, ta_args(ta)) < 0)
+ retval = -1;
+
+ if (!retval && nh->nh_soa)
+ if (soa_set_params(nh->nh_soa, ta_tags(ta)) < 0)
+ retval = -1;
+
+ ta_end(ta);
+
+ if (retval || nh->nh_init) /* Already initialized? */
+ return retval;
+
+ if (nh->nh_tags)
+ nh_authorize(nh, TAG_NEXT(nh->nh_tags));
+
+ nh->nh_init = 1;
+
+ return 0;
+}
+
+/** @internal Create a handle for processing incoming request */
+nua_handle_t *nua_stack_incoming_handle(nua_t *nua,
+ nta_incoming_t *irq,
+ sip_t const *sip,
+ int create_dialog)
+{
+ nua_handle_t *nh;
+ url_t const *url;
+ sip_to_t to[1];
+ sip_from_t from[1];
+
+ assert(sip && sip->sip_from && sip->sip_to);
+
+ if (sip->sip_contact)
+ url = sip->sip_contact->m_url;
+ else
+ url = sip->sip_from->a_url;
+
+ /* Strip away parameters */
+ sip_from_init(from)->a_display = sip->sip_to->a_display;
+ *from->a_url = *sip->sip_to->a_url;
+
+ sip_to_init(to)->a_display = sip->sip_from->a_display;
+ *to->a_url = *sip->sip_from->a_url;
+
+ nh = nh_create(nua,
+ NUTAG_URL((url_string_t *)url), /* Remote target */
+ SIPTAG_TO(to), /* Local AoR */
+ SIPTAG_FROM(from), /* Remote AoR */
+ TAG_END());
+
+ if (nua_stack_init_handle(nh->nh_nua, nh, TAG_END()) < 0)
+ nh_destroy(nua, nh), nh = NULL;
+
+ if (nh && create_dialog) {
+ struct nua_dialog_state *ds = nh->nh_ds;
+
+ nua_dialog_store_peer_info(nh, ds, sip);
+
+ ds->ds_leg = nta_leg_tcreate(nua->nua_nta, nua_stack_process_request, nh,
+ SIPTAG_CALL_ID(sip->sip_call_id),
+ SIPTAG_FROM(sip->sip_to),
+ SIPTAG_TO(sip->sip_from),
+ NTATAG_REMOTE_CSEQ(sip->sip_cseq->cs_seq),
+ TAG_END());
+
+ if (!ds->ds_leg || !nta_leg_tag(ds->ds_leg, nta_incoming_tag(irq, NULL)))
+ nh_destroy(nua, nh), nh = NULL;
+ }
+
+ if (nh)
+ nua_dialog_uas_route(nh, nh->nh_ds, sip, 1);
+
+ return nh;
+}
+
+
+/** Set flags and special event on handle.
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error
+ */
+int nua_stack_set_handle_special(nua_handle_t *nh,
+ enum nh_kind kind,
+ nua_event_t special)
+{
+ if (nh == NULL)
+ return -1;
+
+ if (special && nh->nh_special && nh->nh_special != special)
+ return -1;
+
+ if (!nh_is_special(nh) && !nh->nh_has_invite) {
+ switch (kind) {
+ case nh_has_invite: nh->nh_has_invite = 1; break;
+ case nh_has_subscribe: nh->nh_has_subscribe = 1; break;
+ case nh_has_notify: nh->nh_has_notify = 1; break;
+ case nh_has_register: nh->nh_has_register = 1; break;
+ case nh_has_nothing:
+ default:
+ break;
+ }
+
+ if (special)
+ nh->nh_special = special;
+ }
+
+ return 0;
+}
+
+sip_replaces_t *nua_stack_handle_make_replaces(nua_handle_t *nh,
+ su_home_t *home,
+ int early_only)
+{
+ if (nh && nh->nh_ds && nh->nh_ds->ds_leg)
+ return nta_leg_make_replaces(nh->nh_ds->ds_leg, home, early_only);
+ else
+ return NULL;
+}
+
+nua_handle_t *nua_stack_handle_by_replaces(nua_t *nua,
+ sip_replaces_t const *r)
+{
+ if (nua) {
+ nta_leg_t *leg = nta_leg_by_replaces(nua->nua_nta, r);
+ if (leg)
+ return nta_leg_magic(leg, nua_stack_process_request);
+ }
+ return NULL;
+}
+
+
+/** @internal Add authorization data */
+int nh_authorize(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
+{
+ int retval = 0;
+ tagi_t const *ti;
+ ta_list ta;
+
+ ta_start(ta, tag, value);
+
+ for (ti = ta_args(ta); ti; ti = tl_next(ti)) {
+ if (ti->t_tag == nutag_auth && ti->t_value) {
+ char *data = (char *)ti->t_value;
+ int rv = auc_credentials(&nh->nh_auth, nh->nh_home, data);
+
+ if (rv > 0) {
+ retval = 1;
+ }
+ else if (rv < 0) {
+ retval = -1;
+ break;
+ }
+ }
+ }
+
+ ta_end(ta);
+
+ return retval;
+}
+
+/**@internal
+ * Collect challenges from response.
+ *
+ * @return Number of updated challenges, 0 if no updates found.
+ * @retval -1 upon error.
+ */
+static
+int nh_challenge(nua_handle_t *nh, sip_t const *sip)
+{
+ int server = 0, proxy = 0;
+
+ if (sip->sip_www_authenticate)
+ server = auc_challenge(&nh->nh_auth, nh->nh_home,
+ sip->sip_www_authenticate,
+ sip_authorization_class);
+
+ if (sip->sip_proxy_authenticate)
+ proxy = auc_challenge(&nh->nh_auth, nh->nh_home,
+ sip->sip_proxy_authenticate,
+ sip_proxy_authorization_class);
+
+ if (server < 0 || proxy < 0)
+ return -1;
+
+ return server + proxy;
+}
+
+#include <sofia-sip/su_tag_inline.h>
+
+/** Check if tag list has contact */
+int nua_tagis_have_contact_tag(tagi_t const *t)
+{
+ for (; t && t->t_tag; t = t_next(t))
+ if (t->t_tag == siptag_contact ||
+ t->t_tag == siptag_contact_str)
+ return 1;
+ return 0;
+}
+
+/**@internal
+ * Create a request message.
+ *
+ * @param nua
+ * @param nh
+ * @param cr
+ * @param restart
+ * @param method
+ * @param name
+ * @param tag, value, ... list of tag-value pairs
+ */
+msg_t *nua_creq_msg(nua_t *nua,
+ nua_handle_t *nh,
+ nua_client_request_t *cr,
+ int restart,
+ sip_method_t method, char const *name,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ struct nua_dialog_state *ds = nh->nh_ds;
+ msg_t *msg = NULL;
+ sip_t *sip;
+ ta_list ta;
+ url_string_t const *url = NULL;
+ long seq = -1;
+ int copy = 1;
+
+ /* If restarting, use existing message */
+ if (restart) {
+ msg = cr->cr_msg; sip = sip_object(msg);
+
+ /* Trying to restart different method? */
+ if (sip && method && sip->sip_request->rq_method != method) {
+ SU_DEBUG_3(("nua(%p): trying to %s "
+ "but there is already %s waiting to restart\n",
+ nh, name, sip->sip_request->rq_method_name));
+ restart = 0, msg = NULL; sip = NULL;
+ }
+
+ /* Remove CSeq */
+ if (sip && sip->sip_cseq)
+ sip_header_remove(msg, sip, (sip_header_t *)sip->sip_cseq);
+ if (sip && sip->sip_request)
+ method = sip->sip_request->rq_method,
+ name = sip->sip_request->rq_method_name;
+ }
+
+ if (!restart) {
+ if (cr->cr_msg) {
+ /* If method is ACK or CANCEL, use existing CSeq */
+ if (method == sip_method_ack || method == sip_method_cancel) {
+ sip_t *nh_sip = sip_object(cr->cr_msg);
+ if (nh_sip && nh_sip->sip_cseq)
+ seq = nh_sip->sip_cseq->cs_seq;
+ /* ACK/CANCEL cannot be restarted so we do not copy message */
+ copy = 0;
+ }
+ else
+ msg_destroy(cr->cr_msg), cr->cr_msg = NULL;
+ }
+ msg = nta_msg_create(nua->nua_nta, 0);
+
+ /**@par Populating SIP Request Message with Tagged Arguments
+ *
+ * The tagged arguments can be used to pass values for any SIP headers
+ * to the stack. When the INVITE message (or any other SIP message) is
+ * created, the tagged values saved with nua_handle() are used first,
+ * next the tagged values given with the operation (nua_invite()) are
+ * added.
+ *
+ * When multiple tags for the same header are specified, the behaviour
+ * depends on the header type. If only a single header field can be
+ * included in a SIP message, the latest non-NULL value is used, e.g.,
+ * @Subject. However, if the SIP header can consist of multiple lines or
+ * header fields separated by comma, e.g., @Accept, all the tagged
+ * values are concatenated.
+ *
+ * However, if a tag value is #SIP_NONE (-1 casted as a void pointer),
+ * the values from previous tags are ignored.
+ */
+ tl_gets(nh->nh_tags, NUTAG_URL_REF(url), TAG_END());
+ sip_add_tl(msg, sip_object(msg), TAG_NEXT(nh->nh_tags));
+ }
+
+ ta_start(ta, tag, value);
+
+ sip = sip_object(msg);
+ if (!sip)
+ goto error;
+ if (sip_add_tl(msg, sip, ta_tags(ta)) < 0)
+ goto error;
+
+ if (method != sip_method_ack) {
+ /**
+ * Next, values previously set with nua_set_params() or nua_set_hparams()
+ * are used: @Allow, @Supported, @Organization, and @UserAgent headers are
+ * added to the request if they are not already set.
+ */
+ if (!sip->sip_allow && !ds->ds_remote_tag)
+ sip_add_dup(msg, sip, (sip_header_t*)NH_PGET(nh, allow));
+
+ if (!sip->sip_supported && NH_PGET(nh, supported))
+ sip_add_dup(msg, sip, (sip_header_t *)NH_PGET(nh, supported));
+
+ if (method == sip_method_register && NH_PGET(nh, path_enable) &&
+ !sip_has_feature(sip->sip_supported, "path") &&
+ !sip_has_feature(sip->sip_require, "path"))
+ sip_add_make(msg, sip, sip_supported_class, "path");
+
+ if (!sip->sip_organization && NH_PGET(nh, organization))
+ sip_add_dup(msg, sip, (sip_header_t *)NH_PGET(nh, organization));
+
+ if (!sip->sip_user_agent && NH_PGET(nh, user_agent))
+ sip_add_make(msg, sip, sip_user_agent_class, NH_PGET(nh, user_agent));
+ }
+
+ {
+ int add_contact = 0, use_dialog = 0, add_service_route, has_contact = 0;
+ tagi_t const *t;
+
+ for (t = ta_args(ta); t; t = t_next(t)) {
+ if (t->t_tag == siptag_contact ||
+ t->t_tag == siptag_contact_str)
+ has_contact = 1;
+ else if (t->t_tag == nutag_url)
+ url = (url_string_t const *)t->t_value;
+ else if (t->t_tag == nutag_method && method == sip_method_unknown)
+ name = (char const *)t->t_value;
+ else if (t->t_tag == nutag_use_dialog)
+ use_dialog = t->t_value != 0;
+ else if (t->t_tag == _nutag_add_contact)
+ add_contact = t->t_value != 0;
+ }
+
+ if (!restart)
+ cr->cr_has_contact = has_contact;
+
+ if (has_contact) add_contact = 0;
+
+ if (method == sip_method_register && url == NULL)
+ url = (url_string_t const *)NH_PGET(nh, registrar);
+
+ if (seq != -1) {
+ sip_cseq_t *cseq;
+
+ assert(method != sip_method_unknown || name || sip->sip_request);
+
+ if (method || name)
+ cseq = sip_cseq_create(msg_home(msg), seq, method, name);
+ else
+ cseq = sip_cseq_create(msg_home(msg), seq,
+ sip->sip_request->rq_method,
+ sip->sip_request->rq_method_name);
+
+ sip_header_insert(msg, sip, (sip_header_t *)cseq);
+ }
+
+ /**
+ * Now, the target URI for the request needs to be determined.
+ *
+ * For initial requests, values from tags are used. If NUTAG_URL() is
+ * given, it is used as target URI. Otherwise, if SIPTAG_TO() is given,
+ * it is used as target URI. If neither is given, the complete request
+ * line already specified using SIPTAG_REQUEST() or SIPTAG_REQUEST_STR()
+ * is used. At this point, the target URI is stored in the request line,
+ * together with method name and protocol version ("SIP/2.0"). The
+ * initial dialog information is also created: @CallID, @CSeq headers
+ * are generated, if they do not exist, and a tag is added to the @From
+ * header.
+ */
+ if (!ds->ds_leg) {
+ nta_leg_t *leg = nua->nua_dhandle->nh_ds->ds_leg;
+
+ if ((ds->ds_remote_tag && ds->ds_remote_tag[0] &&
+ sip_to_tag(nh->nh_home, sip->sip_to, ds->ds_remote_tag) < 0)
+ ||
+ (sip->sip_from == NULL &&
+ sip_add_dup(msg, sip, (sip_header_t *)nua->nua_from) < 0))
+ goto error;
+
+ if (use_dialog) {
+ ds->ds_leg = nta_leg_tcreate(nua->nua_nta,
+ nua_stack_process_request, nh,
+ SIPTAG_CALL_ID(sip->sip_call_id),
+ SIPTAG_FROM(sip->sip_from),
+ SIPTAG_TO(sip->sip_to),
+ SIPTAG_CSEQ(sip->sip_cseq),
+ TAG_END());
+ if (!ds->ds_leg)
+ goto error;
+
+ leg = ds->ds_leg;
+
+ if (!sip->sip_from->a_tag &&
+ sip_from_tag(msg_home(msg), sip->sip_from,
+ nta_leg_tag(ds->ds_leg, NULL)) < 0)
+ goto error;
+ }
+
+ if (nta_msg_request_complete(msg, leg, method, name, url) < 0)
+ goto error;
+
+ add_service_route = !restart;
+ }
+ else {
+ /**
+ * For in-dialog requests, the request URI is taken from the @Contact
+ * header received from the remote party during dialog establishment,
+ * and the NUTAG_URL() is ignored.
+ */
+ if (ds->ds_route)
+ url = NULL;
+
+ /**Also, the @CallID and @CSeq headers and @From and @To tags are
+ * generated based on the dialog information and added to the request.
+ * If the dialog has a route, it is added to the request, too.
+ */
+ if (nta_msg_request_complete(msg, ds->ds_leg, method, name, url) < 0)
+ goto error;
+ add_service_route = 0;
+ }
+ /***
+ * @MaxForwards header (with default value set by NTATAG_MAX_FORWARDS()) is
+ * also added now, if it does not exist.
+ */
+
+ /**
+ * Next, the stack generates a @Contact header for the request (unless
+ * the application already gave a @Contact header or it does not want to
+ * use @Contact and indicates that by including SIPTAG_CONTACT(NULL) or
+ * SIPTAG_CONTACT(SIP_NONE) in the tagged parameters.) If the
+ * application has registered the URI in @From header, the @Contact
+ * header used with registration is used. Otherwise, the @Contact header
+ * is generated from the local IP address and port number.
+ */
+ if (!add_contact ||
+ sip->sip_contact ||
+ nua_tagis_have_contact_tag(nh->nh_tags) ||
+ nua_tagis_have_contact_tag(ta_args(ta)))
+ add_contact = 0;
+
+ /**For the initial requests, @ServiceRoute set received from the registrar
+ * is also added to the request message.
+ */
+ if (add_contact || add_service_route) {
+ if (nua_registration_add_contact_to_request(nh, msg, sip,
+ add_contact,
+ add_service_route) < 0)
+ goto error;
+ }
+
+ if (method != sip_method_ack) {
+ if (nh->nh_auth) {
+ nh_authorize(nh, ta_tags(ta));
+
+ if (method != sip_method_invite &&
+ method != sip_method_update &&
+ method != sip_method_prack &&
+ /* auc_authorize() removes existing authentication headers */
+ auc_authorize(&nh->nh_auth, msg, sip) < 0)
+ goto error;
+ }
+ }
+ else /* ACK */ {
+ while (sip->sip_allow)
+ sip_header_remove(msg, sip, (sip_header_t*)sip->sip_allow);
+ while (sip->sip_priority)
+ sip_header_remove(msg, sip, (sip_header_t*)sip->sip_priority);
+ while (sip->sip_proxy_require)
+ sip_header_remove(msg, sip, (sip_header_t*)sip->sip_proxy_require);
+ while (sip->sip_require)
+ sip_header_remove(msg, sip, (sip_header_t*)sip->sip_require);
+ while (sip->sip_subject)
+ sip_header_remove(msg, sip, (sip_header_t*)sip->sip_subject);
+ while (sip->sip_supported)
+ sip_header_remove(msg, sip, (sip_header_t*)sip->sip_supported);
+ }
+
+ ta_end(ta);
+
+ if (!ds->ds_remote)
+ ds->ds_remote = sip_to_dup(nh->nh_home, sip->sip_to);
+ if (!ds->ds_local)
+ ds->ds_local = sip_from_dup(nh->nh_home, sip->sip_from);
+
+ if (copy) {
+ cr->cr_msg = msg;
+ msg = msg_copy(msg);
+ }
+ }
+
+ return msg;
+
+ error:
+ ta_end(ta);
+ msg_destroy(msg);
+ return NULL;
+}
+
+/* ---------------------------------------------------------------------- */
+nua_client_request_t *
+nua_client_request_pending(nua_client_request_t const *cr)
+{
+ for (;cr;cr = cr->cr_next)
+ if (cr->cr_orq)
+ return (nua_client_request_t *)cr;
+
+ return NULL;
+}
+
+nua_client_request_t *
+nua_client_request_restarting(nua_client_request_t const *cr)
+{
+ for (;cr;cr = cr->cr_next)
+ if (cr->cr_restart)
+ return (nua_client_request_t *)cr;
+
+ return NULL;
+}
+
+nua_client_request_t *
+nua_client_request_by_orq(nua_client_request_t const *cr,
+ nta_outgoing_t const *orq)
+{
+ for (;cr;cr = cr->cr_next)
+ if (cr->cr_orq == orq)
+ return (nua_client_request_t *)cr;
+
+ return NULL;
+}
+
+void nua_creq_deinit(nua_client_request_t *cr, nta_outgoing_t *orq)
+{
+ if (orq == NULL || orq == cr->cr_orq) {
+ cr->cr_retry_count = 0;
+ cr->cr_offer_sent = cr->cr_answer_recv = 0;
+
+ if (cr->cr_msg)
+ msg_destroy(cr->cr_msg);
+ cr->cr_msg = NULL;
+
+ if (cr->cr_orq)
+ nta_outgoing_destroy(cr->cr_orq);
+ cr->cr_orq = NULL;
+ }
+ else {
+ nta_outgoing_destroy(orq);
+ }
+}
+
+
+/**@internal
+ * Get remote contact header for @a irq */
+static inline
+sip_contact_t const *incoming_contact(nta_incoming_t *irq)
+{
+ sip_contact_t const *retval = NULL;
+ msg_t *request;
+ sip_t *sip;
+
+ request = nta_incoming_getrequest(irq);
+ sip = sip_object(request);
+ if (sip)
+ retval = sip->sip_contact;
+ msg_destroy(request);
+
+ return retval;
+}
+
+/**@internal
+ * Create a response message.
+ */
+msg_t *nh_make_response(nua_t *nua,
+ nua_handle_t *nh,
+ nta_incoming_t *irq,
+ int status, char const *phrase,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ ta_list ta;
+ msg_t *msg = nta_msg_create(nua->nua_nta, 0);
+ sip_t *sip = sip_object(msg);
+ msg_t *retval = NULL;
+ tagi_t const *t;
+
+ ta_start(ta, tag, value);
+
+ if (!msg)
+ /* retval is NULL */;
+ else if (nta_msg_response_complete(msg, irq, status, phrase) < 0)
+ msg_destroy(msg);
+ else if (sip_add_tl(msg, sip, ta_tags(ta)) < 0)
+ msg_destroy(msg);
+ else if (sip_complete_message(msg) < 0)
+ msg_destroy(msg);
+ else if (!sip->sip_supported && NH_PGET(nh, supported) &&
+ sip_add_dup(msg, sip, (sip_header_t *)NH_PGET(nh, supported)) < 0)
+ msg_destroy(msg);
+ else if (!sip->sip_user_agent && NH_PGET(nh, user_agent) &&
+ sip_add_make(msg, sip, sip_user_agent_class,
+ NH_PGET(nh, user_agent)) < 0)
+ msg_destroy(msg);
+ else if (!sip->sip_organization && NH_PGET(nh, organization) &&
+ sip_add_dup(msg, sip, (sip_header_t *)NH_PGET(nh, organization)) < 0)
+ msg_destroy(msg);
+ else if (!sip->sip_allow && NH_PGET(nh, allow) &&
+ sip_add_dup(msg, sip, (sip_header_t*)NH_PGET(nh, allow)) < 0)
+ msg_destroy(msg);
+ else if (!sip->sip_allow_events &&
+ (sip->sip_cseq &&
+ (sip->sip_cseq->cs_method == sip_method_publish ||
+ sip->sip_cseq->cs_method == sip_method_subscribe)) &&
+ NH_PGET(nh, allow_events) &&
+ sip_add_dup(msg, sip, (sip_header_t*)NH_PGET(nh, allow_events)) < 0)
+ msg_destroy(msg);
+ else if (!sip->sip_contact &&
+ (t = tl_find(ta_args(ta), _nutag_add_contact)) &&
+ t->t_value &&
+ nua_registration_add_contact_to_response(nh, msg, sip, NULL,
+ incoming_contact(irq)) < 0)
+ msg_destroy(msg);
+ else
+ retval = msg;
+
+ ta_end(ta);
+
+ return retval;
+}
+
+
+/* ======================================================================== */
+/* Generic processing */
+
+int nua_stack_process_unknown(nua_t *nua,
+ nua_handle_t *nh,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ return 501;
+}
+
+/**@internal
+ * Relay response message to the application.
+ *
+ * If handle has already been marked as destroyed by nua_handle_destroy(),
+ * release the handle with nh_destroy().
+ */
+int nua_stack_process_response(nua_handle_t *nh,
+ nua_client_request_t *cr,
+ nta_outgoing_t *orq,
+ sip_t const *sip,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ msg_t *msg = nta_outgoing_getresponse(orq);
+ int status = sip->sip_status->st_status;
+ char const *phrase = sip->sip_status->st_phrase;
+ ta_list ta;
+ int final;
+
+ if (status >= 200 && status < 300)
+ nh_challenge(nh, sip); /* Collect nextnonce */
+
+ if (nta_outgoing_method(orq) == sip_method_invite)
+ final = status >= 300;
+ else
+ final = status >= 200;
+
+ if (final && cr) {
+ nua_creq_deinit(cr, orq);
+
+ if (cr->cr_usage && nh->nh_ds->ds_cr == cr) {
+ if ((status >= 300 && !cr->cr_usage->du_ready) ||
+ cr->cr_usage->du_terminating)
+ nua_dialog_usage_remove(nh, nh->nh_ds, cr->cr_usage);
+ }
+
+ cr->cr_usage = NULL;
+ }
+
+ ta_start(ta, tag, value);
+
+ nua_stack_event(nh->nh_nua, nh, msg, cr->cr_event, status, phrase,
+ ta_tags(ta));
+
+ if (final)
+ cr->cr_event = nua_i_error;
+
+ ta_end(ta);
+
+ return 0;
+}
+
+static inline
+int can_redirect(sip_contact_t const *m, sip_method_t method)
+{
+ if (m && m->m_url->url_host) {
+ enum url_type_e type = m->m_url->url_type;
+ return
+ type == url_sip ||
+ type == url_sips ||
+ (type == url_tel &&
+ (method == sip_method_invite || method == sip_method_message)) ||
+ (type == url_im && method == sip_method_message) ||
+ (type == url_pres && method == sip_method_subscribe);
+ }
+ return 0;
+}
+
+int nua_creq_restart_with(nua_handle_t *nh,
+ nua_client_request_t *cr,
+ nta_outgoing_t *orq,
+ int status, char const *phrase,
+ nua_creq_restart_f *f,
+ TAG_LIST)
+{
+ ta_list ta;
+ msg_t *msg = nta_outgoing_getresponse(orq);
+
+ nua_stack_event(nh->nh_nua, nh, msg, cr->cr_event, status, phrase,
+ TAG_END());
+
+ nta_outgoing_destroy(orq);
+
+ if (f) {
+ ta_start(ta, tag, value);
+ f(nh, ta_args(ta));
+ ta_end(ta);
+ }
+
+ return 1;
+}
+
+
+/** @internal Save operation until it can be restarted */
+int nua_creq_save_restart(nua_handle_t *nh,
+ nua_client_request_t *cr,
+ nta_outgoing_t *orq,
+ int status, char const *phrase,
+ nua_creq_restart_f *restart_function)
+{
+ nua_dialog_usage_t *du = cr->cr_usage;
+ msg_t *msg = nta_outgoing_getresponse(orq);
+
+ nua_stack_event(nh->nh_nua, nh, msg, cr->cr_event,
+ status, phrase,
+ TAG_END());
+ nta_outgoing_destroy(orq);
+
+ if (du)
+ du->du_refresh = 0;
+
+ cr->cr_restart = restart_function;
+ return 1;
+}
+
+
+/**@internal
+ * Check response, return true if we can restart the request.
+ *
+ */
+int nua_creq_check_restart(nua_handle_t *nh,
+ nua_client_request_t *cr,
+ nta_outgoing_t *orq,
+ sip_t const *sip,
+ nua_creq_restart_f *restart_function)
+{
+ int status = sip->sip_status->st_status;
+ sip_method_t method = nta_outgoing_method(orq);
+
+ nua_dialog_usage_t *du = cr->cr_usage;
+
+ assert(restart_function);
+
+ if (orq != cr->cr_orq)
+ return 0;
+
+ cr->cr_orq = NULL;
+ cr->cr_restart = NULL;
+
+ if (cr->cr_msg == NULL || status < 200)
+ ;
+ else if (++cr->cr_retry_count > NH_PGET(nh, retry_count))
+ ;
+ else if (status == 302) {
+ if (can_redirect(sip->sip_contact, method)) {
+ return
+ nua_creq_restart_with(nh, cr, orq, 100, "Redirected",
+ restart_function,
+ NUTAG_URL(sip->sip_contact->m_url),
+ TAG_END());
+ }
+ }
+ else if (status == 423) {
+ sip_t *req = sip_object(cr->cr_msg);
+ unsigned my_expires = 0;
+
+ if (req->sip_expires)
+ my_expires = req->sip_expires->ex_delta;
+
+ if (sip->sip_min_expires &&
+ sip->sip_min_expires->me_delta > my_expires) {
+ sip_expires_t ex[1];
+ sip_expires_init(ex);
+ ex->ex_delta = sip->sip_min_expires->me_delta;
+
+ return
+ nua_creq_restart_with(nh, cr, orq,
+ 100, "Re-Negotiating Expiration",
+ restart_function,
+ SIPTAG_EXPIRES(ex),
+ TAG_END());
+ }
+ }
+ else if (method != sip_method_ack && method != sip_method_cancel &&
+ ((status == 401 && sip->sip_www_authenticate) ||
+ (status == 407 && sip->sip_proxy_authenticate)) &&
+ nh_challenge(nh, sip) > 0) {
+ msg_t *request = nta_outgoing_getrequest(orq);
+ sip_t *rsip = sip_object(request);
+ int done;
+
+ /* XXX - check for instant restart */
+ done = auc_authorization(&nh->nh_auth, cr->cr_msg, (msg_pub_t*)NULL,
+ rsip->sip_request->rq_method_name,
+ rsip->sip_request->rq_url,
+ rsip->sip_payload);
+
+ msg_destroy(request);
+
+ if (done > 0) {
+ return
+ nua_creq_restart_with(nh, cr, orq,
+ 100, "Request Authorized by Cache",
+ restart_function, TAG_END());
+ }
+ else if (done == 0) {
+ /* Operation waits for application to call nua_authenticate() */
+ return nua_creq_save_restart(nh, cr, orq,
+ status, sip->sip_status->st_phrase,
+ restart_function);
+ }
+ else {
+ SU_DEBUG_5(("nua(%p): auc_authorization failed\n", nh));
+ }
+ }
+
+ /* This was final response that cannot be restarted. */
+ cr->cr_orq = orq;
+
+ if (du)
+ du->du_refresh = 0;
+ cr->cr_retry_count = 0;
+
+ if (cr->cr_msg)
+ msg_destroy(cr->cr_msg), cr->cr_msg = NULL;
+
+ return 0;
+}
+
+/** @internal Restart a request */
+int nua_creq_restart(nua_handle_t *nh,
+ nua_client_request_t *cr,
+ nta_response_f *cb,
+ tagi_t *tags)
+{
+ msg_t *msg;
+
+ cr->cr_restart = NULL;
+
+ if (!cr->cr_msg)
+ return 0;
+
+ msg = nua_creq_msg(nh->nh_nua, nh, cr, 1, SIP_METHOD_UNKNOWN,
+ TAG_NEXT(tags));
+
+ cr->cr_orq = nta_outgoing_mcreate(nh->nh_nua->nua_nta, cb, nh, NULL, msg,
+ SIPTAG_END(), TAG_NEXT(tags));
+
+ if (!cr->cr_orq) {
+ msg_destroy(msg);
+ return 0;
+ }
+
+ return 1;
+}
+
+/* ======================================================================== */
+/* Authentication */
+
+/** @NUA_EVENT nua_r_authenticate
+ *
+ * Response to nua_authenticate(). Under normal operation, this event is
+ * never sent but rather the unauthenticated operation is completed.
+ * However, if there is no operation to authentication or if there is an
+ * authentication error the #nua_r_authenticate event is sent to the
+ * application with the status code as follows:
+ * - <i>202 No operation to restart</i>:\n
+ * The authenticator associated with the handle was updated, but there was
+ * no operation to retry with the new credentials.
+ * - <i>900 Cannot add credentials</i>:\n
+ * There was internal problem updating authenticator.
+ * - <i>904 No matching challenge</i>:\n
+ * There was no challenge matching with the credentials provided by
+ * nua_authenticate(), e.g., their realm did not match with the one
+ * received with the challenge.
+ *
+ * @param status status code from authentication
+ * @param phrase a short textual description of @a status code
+ * @param nh operation handle authenticated
+ * @param hmagic application context associated with the handle
+ * @param sip NULL
+ * @param tags empty
+ *
+ * @sa nua_terminate(), nua_handle_destroy()
+ *
+ * @END_NUA_EVENT
+ */
+
+void
+nua_stack_authenticate(nua_t *nua, nua_handle_t *nh, nua_event_t e,
+ tagi_t const *tags)
+{
+ int status = nh_authorize(nh, TAG_NEXT(tags));
+
+ if (status > 0) {
+ nua_client_request_t *cr;
+ nua_creq_restart_f *restart = NULL;
+
+ cr = nua_client_request_restarting(nh->nh_ds->ds_cr);
+
+ if (cr)
+ restart = cr->cr_restart, cr->cr_restart = NULL;
+
+ if (restart) {
+ /* nua_stack_event(nua, nh, NULL, e, SIP_200_OK, TAG_END()); */
+ restart(nh, (tagi_t *)tags); /* Restart operation */
+ }
+ else {
+ nua_stack_event(nua, nh, NULL, e,
+ 202, "No operation to restart",
+ TAG_END());
+ }
+ }
+ else if (status < 0) {
+ nua_stack_event(nua, nh, NULL, e, 900, "Cannot add credentials", TAG_END());
+ }
+ else {
+ nua_stack_event(nua, nh, NULL, e, 904, "No matching challenge", TAG_END());
+ }
+}
+
+/* ======================================================================== */
+/*
+ * Process incoming requests
+ */
+
+int nua_stack_process_request(nua_handle_t *nh,
+ nta_leg_t *leg,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ nua_t *nua = nh->nh_nua;
+ sip_method_t method = sip->sip_request->rq_method;
+ char const *user_agent = NH_PGET(nh, user_agent);
+ sip_supported_t const *supported = NH_PGET(nh, supported);
+ sip_allow_t const *allow = NH_PGET(nh, allow);
+ enter;
+
+ nta_incoming_tag(irq, NULL);
+
+ if (nta_check_method(irq, sip, allow,
+ SIPTAG_SUPPORTED(supported),
+ SIPTAG_USER_AGENT_STR(user_agent),
+ TAG_END()))
+ return 405;
+
+ switch (sip->sip_request->rq_url->url_type) {
+ case url_sip:
+ case url_sips:
+ case url_im:
+ case url_pres:
+ case url_tel:
+ break;
+ default:
+ nta_incoming_treply(irq, SIP_416_UNSUPPORTED_URI,
+ SIPTAG_ALLOW(allow),
+ SIPTAG_SUPPORTED(supported),
+ SIPTAG_USER_AGENT_STR(user_agent),
+ TAG_END());
+ }
+
+ if (nta_check_required(irq, sip, supported,
+ SIPTAG_ALLOW(allow),
+ SIPTAG_USER_AGENT_STR(user_agent),
+ TAG_END()))
+ return 420;
+
+ if (nh == nua->nua_dhandle) {
+ if (!sip->sip_to->a_tag)
+ ;
+ else if (method == sip_method_message && NH_PGET(nh, win_messenger_enable))
+ ;
+ else {
+ nta_incoming_treply(irq, 481, "Initial transaction with a To tag",
+ TAG_END());
+ return 481;
+ }
+ nh = NULL;
+ }
+
+ if (sip->sip_timestamp)
+ nta_incoming_treply(irq, SIP_100_TRYING, TAG_END());
+
+ switch (method) {
+ case sip_method_invite:
+ return nua_stack_process_invite(nua, nh, irq, sip);
+
+ case sip_method_info:
+ if (nh) return nua_stack_process_info(nua, nh, irq, sip);
+ /*FALLTHROUGH*/
+
+ case sip_method_update:
+ if (nh) return nua_stack_process_update(nua, nh, irq, sip);
+ /*FALLTHROUGH*/
+
+ case sip_method_bye:
+ if (nh) return nua_stack_process_bye(nua, nh, irq, sip);
+
+ nta_incoming_treply(irq,
+ 481, "Call Does Not Exist",
+ SIPTAG_ALLOW(allow),
+ SIPTAG_SUPPORTED(supported),
+ SIPTAG_USER_AGENT_STR(user_agent),
+ TAG_END());
+ return 481;
+
+ case sip_method_message:
+ return nua_stack_process_message(nua, nh, irq, sip);
+
+ case sip_method_notify:
+ return nua_stack_process_notify(nua, nh, irq, sip);
+
+ case sip_method_subscribe:
+ return nua_stack_process_subscribe(nua, nh, irq, sip);
+
+ case sip_method_register:
+ return nua_stack_process_register(nua, nh, irq, sip);
+
+ case sip_method_options:
+ return nua_stack_process_options(nua, nh, irq, sip);
+
+ case sip_method_refer:
+ return nua_stack_process_refer(nua, nh, irq, sip);
+
+ case sip_method_publish:
+ return nua_stack_process_publish(nua, nh, irq, sip);
+
+ case sip_method_ack:
+ case sip_method_cancel:
+ SU_DEBUG_1(("nua(%p): strange %s from <" URL_PRINT_FORMAT ">\n", nh,
+ sip->sip_request->rq_method_name,
+ URL_PRINT_ARGS(sip->sip_from->a_url)));
+ /* Send nua_i_error ? */
+ return 481;
+
+ case sip_method_unknown:
+ return nua_stack_process_method(nua, nh, irq, sip);
+
+ default:
+ return nua_stack_process_unknown(nua, nh, irq, sip);
+ }
+}
+
+nua_server_request_t *nua_server_request(nua_t *nua,
+ nua_handle_t *nh,
+ nta_incoming_t *irq,
+ sip_t const *sip,
+ nua_server_request_t *sr,
+ size_t size,
+ nua_server_respond_f *respond,
+ int create_dialog)
+{
+ int initial = 1, final = 200;
+
+ assert(nua && irq && sip && sr);
+
+ initial = nh == NULL || nh == nua->nua_dhandle;
+
+ /* INVITE server request is not finalized after 2XX response */
+ if (sip->sip_request->rq_method == sip_method_invite)
+ final = 300;
+
+ /* Create handle if request does not fail */
+ if (sr->sr_status >= 300)
+ ;
+ else if (initial) {
+ if (!(nh = nua_stack_incoming_handle(nua, irq, sip, create_dialog)))
+ SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR);
+ }
+ else if (create_dialog) {
+ nua_dialog_store_peer_info(nh, nh->nh_ds, sip);
+ nua_dialog_uas_route(nh, nh->nh_ds, sip, 1);
+ }
+
+ if (nh == NULL)
+ nh = nua->nua_dhandle;
+
+ if (sr->sr_status < final) {
+ nua_server_request_t *sr0 = sr;
+
+ if (size < (sizeof *sr))
+ size = sizeof *sr;
+
+ sr = su_zalloc(nh->nh_home, size);
+
+ if (sr) {
+ if ((sr->sr_next = nh->nh_ds->ds_sr))
+ *(sr->sr_prev = sr->sr_next->sr_prev) = sr,
+ sr->sr_next->sr_prev = &sr->sr_next;
+ else
+ *(sr->sr_prev = &nh->nh_ds->ds_sr) = sr;
+ SR_STATUS(sr, sr0->sr_status, sr0->sr_phrase);
+ }
+ else {
+ sr = sr0;
+ SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR);
+ }
+ }
+
+ sr->sr_owner = nh;
+ sr->sr_method = sip->sip_request->rq_method;
+ sr->sr_respond = respond;
+ sr->sr_irq = irq;
+ sr->sr_initial = initial;
+
+ return sr;
+}
+
+void nua_server_request_destroy(nua_server_request_t *sr)
+{
+ if (sr->sr_irq)
+ nta_incoming_destroy(sr->sr_irq), sr->sr_irq = NULL;
+
+ sr->sr_msg = NULL;
+
+ if (sr->sr_prev) {
+ if ((*sr->sr_prev = sr->sr_next))
+ sr->sr_next->sr_prev = sr->sr_prev;
+
+ if (sr->sr_owner)
+ su_free(sr->sr_owner->nh_home, sr);
+ }
+}
+
+/** Send server event (nua_i_*) to the application. */
+int nua_stack_server_event(nua_t *nua,
+ nua_server_request_t *sr,
+ nua_event_t event,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ nua_handle_t *nh = sr->sr_owner;
+ int status, final = 0;
+
+ if (nh == NULL) nh = nua->nua_dhandle;
+
+ if (sr->sr_status > 100)
+ /* Note that this may change the sr->sr_status */
+ final = sr->sr_respond(sr, NULL);
+
+ status = sr->sr_status;
+
+ if (status >= 200)
+ sr->sr_respond = NULL;
+
+ if (status < 300 || !sr->sr_initial) {
+ ta_list ta;
+ msg_t *request;
+
+ ta_start(ta, tag, value);
+
+ assert(sr->sr_owner);
+ request = nta_incoming_getrequest(sr->sr_irq);
+ nua_stack_event(nua, sr->sr_owner, request, event,
+ sr->sr_status, sr->sr_phrase,
+ ta_tags(ta));
+ ta_end(ta);
+
+ if (final)
+ nua_server_request_destroy(sr);
+ else if (sr->sr_status < 200)
+ sr->sr_msg = request;
+ }
+ else {
+ nh = sr->sr_owner;
+
+ nua_server_request_destroy(sr);
+
+ if (nh && nh != nua->nua_dhandle)
+ nh_destroy(nua, nh);
+ }
+
+ return 0;
+}
+
+/** Respond to a request. */
+int nua_server_respond(nua_server_request_t *sr,
+ int status, char const *phrase,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ ta_list ta;
+ int final;
+
+ assert(sr && sr->sr_respond);
+ SR_STATUS(sr, status, phrase);
+
+ ta_start(ta, tag, value);
+ final = sr->sr_respond(sr, ta_args(ta));
+ ta_end(ta);
+
+ if (final) {
+ nua_server_request_destroy(sr);
+ return final;
+ }
+
+ if (sr->sr_status >= 200)
+ sr->sr_respond = NULL;
+
+ return 0;
+}
+
+msg_t *nua_server_response(nua_server_request_t *sr,
+ int status, char const *phrase,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ msg_t *msg;
+ ta_list(ta);
+
+ assert(sr && sr->sr_owner && sr->sr_owner->nh_nua);
+
+ ta_start(ta, tag, value);
+
+ msg = nh_make_response(sr->sr_owner->nh_nua, sr->sr_owner, sr->sr_irq,
+ sr->sr_status, sr->sr_phrase,
+ ta_tags(ta));
+
+ ta_end(ta);
+
+ return msg;
+}
+
+int nua_default_respond(nua_server_request_t *sr,
+ tagi_t const *tags)
+{
+ msg_t *m;
+
+ assert(sr && sr->sr_owner && sr->sr_owner->nh_nua);
+
+ m = nh_make_response(sr->sr_owner->nh_nua, sr->sr_owner,
+ sr->sr_irq,
+ sr->sr_status, sr->sr_phrase,
+ TAG_NEXT(tags));
+
+ if (m) {
+ if (nta_incoming_mreply(sr->sr_irq, m) < 0)
+ SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR);
+ }
+
+ return sr->sr_status >= 200 ? sr->sr_status : 0;
+}
+
+/** Respond to an request with given status.
+ *
+ * When nua protocol engine receives an incoming SIP request, it can either
+ * respond to the request automatically or let it up to application to
+ * respond to the request. The automatic answer is sent if the request fails
+ * because of method, SIP extension or, in some times, MIME content
+ * negotiation fails.
+ *
+ * When responding to an incoming INVITE request, the nua_respond() can be
+ * called without NUTAG_WITH() (or NUTAG_WITH_CURRENT() or
+ * NUTAG_WITH_SAVED()). Otherwise, NUTAG_WITH() will contain an indication
+ * of the request being responded.
+ *
+ * In order to simplify the simple applications, most requests are responded
+ * automatically. The set of requests always responded by the stack include
+ * BYE, CANCEL and NOTIFY. The application can add methods that it likes to
+ * handle by itself with NUTAG_APPL_METHOD(). The default set of
+ * NUTAG_APPL_METHOD() includes INVITE, PUBLISH, REGISTER and SUBSCRIBE.
+ * Note that unless the method is also included in the set of allowed
+ * methods with NUTAG_ALLOW(), the stack will respond to the incoming
+ * methods with <i>405 Not Allowed</i>.
+ *
+ * Note that certain methods are rejected outside a SIP session (created
+ * with INVITE transaction). They include BYE, UPDATE, PRACK and INFO. Also
+ * the auxiliary methods ACK and CANCEL are rejected by stack if there is no
+ * ongoing INVITE transaction corresponding to them.
+ *
+ * @param nh Pointer to operation handle
+ * @param status SIP response status (see RFCs of SIP)
+ * @param phrase free text (default response phrase used if NULL)
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return
+ * nothing
+ *
+ * @par Related Tags:
+ * NUTAG_WITH(), NUTAG_WITH_CURRENT(), NUTAG_WITH_SAVED() \n
+ * NUTAG_EARLY_ANSWER() \n
+ * SOATAG_ADDRESS() \n
+ * SOATAG_AF() \n
+ * SOATAG_HOLD() \n
+ * Tags in <sip_tag.h>.
+ *
+ * @par Events:
+ * #nua_i_state \n
+ * #nua_i_media_error \n
+ * #nua_i_error \n
+ * #nua_i_active \n
+ * #nua_i_terminated \n
+ *
+ * @sa #nua_i_invite, #nua_i_register, #nua_i_subscribe, #nua_i_publish
+ */
+void
+nua_stack_respond(nua_t *nua, nua_handle_t *nh,
+ int status, char const *phrase, tagi_t const *tags)
+{
+ nua_server_request_t *sr;
+ tagi_t const *t;
+ msg_t const *request = NULL;
+
+ t = tl_find_last(tags, nutag_with);
+
+ if (t)
+ request = (msg_t const *)t->t_value;
+
+ for (sr = nh->nh_ds->ds_sr; sr; sr = sr->sr_next) {
+ if (request && sr->sr_msg == request)
+ break;
+ /* nua_respond() to INVITE can be used without NUTAG_WITH() */
+ if (!t && sr->sr_method == sip_method_invite && sr->sr_respond)
+ break;
+ }
+
+ if (sr && sr->sr_respond) {
+ int final;
+ SR_STATUS(sr, status, phrase);
+ final = sr->sr_respond(sr, tags);
+ if (final)
+ nua_server_request_destroy(sr);
+ else if (sr->sr_status >= 200)
+ sr->sr_respond = NULL;
+ return;
+ }
+ else if (sr) {
+ nua_stack_event(nua, nh, NULL, nua_i_error,
+ 500, "Already Sent Final Response", TAG_END());
+ return;
+ }
+
+ nua_stack_event(nua, nh, NULL, nua_i_error,
+ 500, "Responding to a Non-Existing Request", TAG_END());
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,505 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef NUA_STACK_H
+/** Defined when <nua_stack.h> has been included. */
+#define NUA_STACK_H
+/**@IFILE nua_stack.h
+ * @brief Sofia-SIP User Agent Engine - internal stack interface
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Kai Vehmanen <Kai.Vehmanen at nokia.com>
+ *
+ * @date Created: Wed Feb 14 17:09:44 2001 ppessi
+ */
+
+#ifndef SU_CONFIG_H
+#include <su_config.h>
+#endif
+
+#ifndef SU_OS_NW_H
+#include <sofia-sip/su_os_nw.h>
+#endif
+#ifndef SOA_H
+#include "sofia-sip/soa.h"
+#endif
+#ifndef NTA_H
+#include <sofia-sip/nta.h>
+#endif
+#ifndef AUTH_CLIENT_H
+#include <sofia-sip/auth_client.h>
+#endif
+#ifndef NEA_H
+#include <sofia-sip/nea.h>
+#endif
+#ifndef NUA_H
+#include <sofia-sip/nua.h>
+#endif
+
+#define SU_LOG (nua_log)
+#include <sofia-sip/su_debug.h>
+
+#ifndef NUA_DIALOG_H
+#define NUA_OWNER_T struct nua_handle_s
+#include <nua_dialog.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+#if HAVE_SIGCOMP
+#include <sigcomp.h>
+#endif
+
+#ifndef NUA_PARAMS_H
+#include <nua_params.h>
+#endif
+
+typedef struct event_s event_t;
+
+#define NONE ((void *)-1)
+
+typedef struct register_usage nua_registration_t;
+
+#define \
+ NH_ACTIVE_MEDIA_TAGS(include, soa) \
+ TAG_IF((include) && (soa) && soa_is_audio_active(soa) >= 0, \
+ SOATAG_ACTIVE_AUDIO(soa_is_audio_active(soa))), \
+ TAG_IF((include) && (soa) && soa_is_video_active(soa) >= 0, \
+ SOATAG_ACTIVE_VIDEO(soa_is_video_active(soa))), \
+ TAG_IF((include) && (soa) && soa_is_image_active(soa) >= 0, \
+ SOATAG_ACTIVE_IMAGE(soa_is_image_active(soa))), \
+ TAG_IF((include) && (soa) && soa_is_chat_active(soa) >= 0, \
+ SOATAG_ACTIVE_CHAT(soa_is_chat_active(soa)))
+
+#define \
+ NH_REMOTE_MEDIA_TAGS(include, soa) \
+ TAG_IF((include) && (soa) && soa_is_remote_audio_active(soa) >= 0, \
+ SOATAG_ACTIVE_AUDIO(soa_is_remote_audio_active(soa))), \
+ TAG_IF((include) && (soa) && soa_is_remote_video_active(soa) >= 0, \
+ SOATAG_ACTIVE_VIDEO(soa_is_remote_video_active(soa))), \
+ TAG_IF((include) && (soa) && soa_is_remote_image_active(soa) >= 0, \
+ SOATAG_ACTIVE_IMAGE(soa_is_remote_image_active(soa))), \
+ TAG_IF((include) && (soa) && soa_is_remote_chat_active(soa) >= 0, \
+ SOATAG_ACTIVE_CHAT(soa_is_remote_chat_active(soa)))
+
+/** NUA handle.
+ *
+ */
+struct nua_handle_s
+{
+ su_home_t nh_home[1]; /**< Memory home */
+ nua_handle_t *nh_next;
+ nua_handle_t **nh_prev;
+
+ nua_t *nh_nua; /**< Pointer to NUA object */
+ void *nh_valid;
+ nua_hmagic_t *nh_magic; /**< Application context */
+
+ tagi_t *nh_tags; /**< Initial tags */
+ tagi_t *nh_ptags; /**< Initial parameters */
+
+ nua_handle_t *nh_identity; /**< Identity */
+
+ nua_handle_preferences_t *nh_prefs; /**< Preferences */
+
+ /* Handle type is determined by special event and flags. */
+ nua_event_t nh_special; /**< Special event */
+ unsigned nh_has_invite:1; /**< Has call */
+ unsigned nh_has_subscribe:1; /**< Has watcher */
+ unsigned nh_has_notify:1; /**< Has notifier */
+ unsigned nh_has_register:1; /**< Has registration */
+
+ /* Call status */
+ unsigned nh_active_call:1;
+ unsigned nh_hold_remote:1;
+
+ unsigned nh_ref_by_stack:1; /**< Has stack used the handle? */
+ unsigned nh_ref_by_user:1; /**< Has user used the handle? */
+ unsigned nh_init:1; /**< Handle has been initialized */
+ unsigned nh_used_ptags:1; /**< Ptags has been used */
+ unsigned :0;
+
+ nua_dialog_state_t nh_ds[1];
+
+ auth_client_t *nh_auth; /**< Authorization objects */
+
+ soa_session_t *nh_soa; /**< Media session */
+
+ struct nua_referral {
+ nua_handle_t *ref_handle; /**< Referring handle */
+ sip_event_t *ref_event; /**< Event used with NOTIFY */
+ } nh_referral[1];
+
+ nea_server_t *nh_notifier; /**< SIP notifier */
+};
+
+#define NH_IS_VALID(nh) ((nh) && (nh)->nh_valid)
+
+#define NH_STATUS(nh) \
+ (nh)->nh_status, \
+ (nh)->nh_phrase, \
+ SIPTAG_WARNING_STR(nh->nh_warning)
+
+#define NH_IS_DEFAULT(nh) ((nh) == (nh)->nh_nua->nua_handles)
+
+static inline
+int nh_is_special(nua_handle_t *nh)
+{
+ return nh == NULL || nh->nh_special;
+}
+
+extern char const nua_internal_error[];
+
+#define NUA_INTERNAL_ERROR 900, nua_internal_error
+
+struct nua_s {
+ su_home_t nua_home[1];
+
+ /* API (client) side */
+ su_root_t *nua_api_root;
+ su_clone_r nua_clone;
+ su_task_r nua_client;
+
+ su_network_changed_t *nua_nw_changed;
+
+ nua_callback_f nua_callback;
+ nua_magic_t *nua_magic;
+
+ nua_saved_event_t nua_current[1];
+ nua_saved_event_t nua_signal[1];
+
+ /* Engine state flags */
+ unsigned nua_shutdown_started:1; /**< Shutdown initiated */
+ unsigned nua_shutdown_final:1; /**< Shutdown is complete */
+ unsigned :0;
+
+ /**< Used by stop-and-wait args calls */
+ tagi_t const *nua_args;
+
+ /**< Local SIP address. Contents are kept around for ever. */
+ sip_from_t nua_from[1];
+
+ /* Protocol (server) side */
+
+ nua_registration_t *nua_registrations; /**< Active registrations */
+
+ /* Constants */
+ sip_accept_t *nua_invite_accept; /* What we accept for invite */
+
+ su_root_t *nua_root;
+ su_task_r nua_server;
+ nta_agent_t *nua_nta;
+ su_timer_t *nua_timer;
+
+ void *nua_sip_parser;
+
+ sip_time_t nua_shutdown;
+
+ /* Route */
+ sip_service_route_t *nua_service_route;
+
+ /* User-agent parameters */
+ unsigned nua_media_enable:1;
+
+ unsigned :0;
+
+#if HAVE_SMIME /* Start NRC Boston */
+ sm_object_t *sm;
+#endif /* End NRC Boston */
+
+ nua_handle_t *nua_handles;
+ nua_handle_t **nua_handles_tail;
+};
+
+#define nua_dhandle nua_handles
+
+#if HAVE_FUNC
+#define enter (void)SU_DEBUG_9(("nua: %s: entering\n", __func__))
+#define nh_enter (void)SU_DEBUG_9(("nua %s(%p): entering\n", __func__, nh))
+#elif HAVE_FUNCTION
+#define enter (void)SU_DEBUG_9(("nua: %s: entering\n", __FUNCTION__))
+#define nh_enter (void)SU_DEBUG_9(("nua %s(%p): entering\n", __FUNCTION__, nh))
+#define __func__ __FUNCTION__
+#else
+#define enter ((void)0)
+#define nh_enter ((void)0)
+#define __func__ "nua"
+#endif
+
+/* Internal prototypes */
+int nua_stack_init(su_root_t *root, nua_t *nua);
+void nua_stack_deinit(su_root_t *root, nua_t *nua);
+void nua_stack_signal(nua_t *nua, su_msg_r msg, event_t *e);
+
+int nua_stack_init_transport(nua_t *nua, tagi_t const *tags);
+
+int nua_stack_init_registrations(nua_t *nua);
+
+nua_registration_t *nua_registration_by_aor(nua_registration_t const *list,
+ sip_from_t const *aor,
+ url_t const *remote_uri,
+ int only_default);
+
+sip_contact_t const *nua_registration_contact(nua_registration_t const *nr);
+
+int nua_registration_process_request(nua_registration_t *nr,
+ nta_incoming_t *irq,
+ sip_t const *sip);
+
+void nua_stack_post_signal(nua_handle_t *nh, nua_event_t event,
+ tag_type_t tag, tag_value_t value, ...);
+
+typedef int nua_stack_signal_handler(nua_t *,
+ nua_handle_t *,
+ nua_event_t,
+ tagi_t const *);
+
+nua_stack_signal_handler
+ nua_stack_set_params, nua_stack_get_params,
+ nua_stack_register,
+ nua_stack_invite, nua_stack_ack, nua_stack_cancel,
+ nua_stack_bye, nua_stack_info, nua_stack_update,
+ nua_stack_options, nua_stack_publish, nua_stack_message,
+ nua_stack_subscribe, nua_stack_notify, nua_stack_refer,
+ nua_stack_method;
+
+#define UA_EVENT1(e, statusphrase) \
+ nua_stack_event(nua, nh, NULL, e, statusphrase, TAG_END())
+
+#define UA_EVENT2(e, status, phrase) \
+ nua_stack_event(nua, nh, NULL, e, status, phrase, TAG_END())
+
+#define UA_EVENT3(e, status, phrase, tag) \
+ nua_stack_event(nua, nh, NULL, e, status, phrase, tag, TAG_END())
+
+int nua_stack_event(nua_t *nua, nua_handle_t *nh, msg_t *msg,
+ nua_event_t event, int status, char const *phrase,
+ tag_type_t tag, tag_value_t value, ...);
+
+nua_handle_t *nh_create_handle(nua_t *nua, nua_hmagic_t *hmagic,
+ tagi_t *tags);
+
+nua_handle_t *nua_stack_incoming_handle(nua_t *nua,
+ nta_incoming_t *irq,
+ sip_t const *sip,
+ int create_dialog);
+
+enum { create_dialog = 1 };
+
+int nua_stack_init_handle(nua_t *nua, nua_handle_t *nh,
+ tag_type_t tag, tag_value_t value, ...);
+
+enum nh_kind {
+ nh_has_nothing,
+ nh_has_invite,
+ nh_has_subscribe,
+ nh_has_notify,
+ nh_has_register,
+ nh_has_streaming
+};
+
+int nua_stack_set_handle_special(nua_handle_t *nh,
+ enum nh_kind kind,
+ nua_event_t special);
+
+int nua_handle_save_tags(nua_handle_t *h, tagi_t *tags);
+
+void nh_destroy(nua_t *nua, nua_handle_t *nh);
+
+nua_handle_t *nh_validate(nua_t *nua, nua_handle_t *maybe);
+
+sip_replaces_t *nua_stack_handle_make_replaces(nua_handle_t *handle,
+ su_home_t *home,
+ int early_only);
+
+nua_handle_t *nua_stack_handle_by_replaces(nua_t *nua,
+ sip_replaces_t const *r);
+
+/* ---------------------------------------------------------------------- */
+
+int nua_stack_set_defaults(nua_handle_t *nh, nua_handle_preferences_t *nhp);
+
+int nua_stack_set_from(nua_t *, int initial, tagi_t const *tags);
+
+int nua_stack_init_instance(nua_handle_t *nh, tagi_t const *tags);
+
+int nua_stack_process_request(nua_handle_t *nh,
+ nta_leg_t *leg,
+ nta_incoming_t *irq,
+ sip_t const *sip);
+
+int nua_stack_process_response(nua_handle_t *nh,
+ nua_client_request_t *cr,
+ nta_outgoing_t *orq,
+ sip_t const *sip,
+ tag_type_t tag, tag_value_t value, ...);
+
+int nua_stack_launch_network_change_detector(nua_t *nua);
+
+msg_t *nua_creq_msg(nua_t *nua, nua_handle_t *nh,
+ nua_client_request_t *cr,
+ int restart,
+ sip_method_t method, char const *name,
+ tag_type_t tag, tag_value_t value, ...);
+
+int nua_tagis_have_contact_tag(tagi_t const *t);
+
+int nua_creq_check_restart(nua_handle_t *nh,
+ nua_client_request_t *cr,
+ nta_outgoing_t *orq,
+ sip_t const *sip,
+ nua_creq_restart_f *f);
+
+int nua_creq_restart_with(nua_handle_t *nh,
+ nua_client_request_t *cr,
+ nta_outgoing_t *orq,
+ int status, char const *phrase,
+ nua_creq_restart_f *f,
+ tag_type_t tag, tag_value_t value, ...);
+
+int nua_creq_save_restart(nua_handle_t *nh,
+ nua_client_request_t *cr,
+ nta_outgoing_t *orq,
+ int status, char const *phrase,
+ nua_creq_restart_f *f);
+
+int nua_creq_restart(nua_handle_t *nh,
+ nua_client_request_t *cr,
+ nta_response_f *cb,
+ tagi_t *tags);
+
+void nua_creq_deinit(nua_client_request_t *cr, nta_outgoing_t *orq);
+
+sip_contact_t const *nua_stack_get_contact(nua_registration_t const *nr);
+
+int nua_registration_add_contact_to_request(nua_handle_t *nh,
+ msg_t *msg,
+ sip_t *sip,
+ int add_contact,
+ int add_service_route);
+
+int nua_registration_add_contact_to_response(nua_handle_t *nh,
+ msg_t *msg,
+ sip_t *sip,
+ sip_record_route_t const *,
+ sip_contact_t const *remote);
+
+msg_t *nh_make_response(nua_t *nua, nua_handle_t *nh,
+ nta_incoming_t *irq,
+ int status, char const *phrase,
+ tag_type_t tag, tag_value_t value, ...);
+
+
+typedef int nua_stack_process_request_t(nua_t *nua,
+ nua_handle_t *nh,
+ nta_incoming_t *irq,
+ sip_t const *sip);
+
+nua_stack_process_request_t nua_stack_process_invite;
+nua_stack_process_request_t nua_stack_process_info;
+nua_stack_process_request_t nua_stack_process_update;
+nua_stack_process_request_t nua_stack_process_bye;
+nua_stack_process_request_t nua_stack_process_message;
+nua_stack_process_request_t nua_stack_process_options;
+nua_stack_process_request_t nua_stack_process_publish;
+nua_stack_process_request_t nua_stack_process_subscribe;
+nua_stack_process_request_t nua_stack_process_notify;
+nua_stack_process_request_t nua_stack_process_refer;
+nua_stack_process_request_t nua_stack_process_unknown;
+nua_stack_process_request_t nua_stack_process_register;
+nua_stack_process_request_t nua_stack_process_method;
+
+nua_client_request_t
+ *nua_client_request_pending(nua_client_request_t const *),
+ *nua_client_request_restarting(nua_client_request_t const *),
+ *nua_client_request_by_orq(nua_client_request_t const *cr,
+ nta_outgoing_t const *orq);
+
+nua_server_request_t *nua_server_request(nua_t *nua,
+ nua_handle_t *nh,
+ nta_incoming_t *irq,
+ sip_t const *sip,
+ nua_server_request_t *sr,
+ size_t size,
+ nua_server_respond_f *respond,
+ int create_dialog);
+
+int nua_stack_server_event(nua_t *nua,
+ nua_server_request_t *sr,
+ nua_event_t event,
+ tag_type_t tag, tag_value_t value, ...);
+
+/* ---------------------------------------------------------------------- */
+
+#ifndef SDP_MIME_TYPE
+#define SDP_MIME_TYPE nua_application_sdp
+#endif
+
+extern char const nua_application_sdp[];
+
+/* ---------------------------------------------------------------------- */
+
+#define SIP_METHOD_UNKNOWN sip_method_unknown, NULL
+
+/* Private tags */
+#define NUTAG_ADD_CONTACT(v) _nutag_add_contact, tag_bool_v(v)
+extern tag_typedef_t _nutag_add_contact;
+
+#define NUTAG_ADD_CONTACT_REF(v) _nutag_add_contact_ref, tag_bool_vr(&v)
+extern tag_typedef_t _nutag_add_contact_ref;
+
+#define NUTAG_COPY(v) _nutag_copy, tag_bool_v(v)
+extern tag_typedef_t _nutag_copy;
+
+#define NUTAG_COPY_REF(v) _nutag_copy_ref, tag_bool_vr(&v)
+extern tag_typedef_t _nutag_copy_ref;
+
+/* ---------------------------------------------------------------------- */
+
+typedef unsigned longlong ull;
+
+#define SET_STATUS(_status, _phrase) status = _status, phrase = _phrase
+
+#define SET_STATUS2(_status, _phrase) status = _status, phrase = _phrase
+
+/* This is an "interesting" macro:
+ * x is a define expanding to <i>num, str</i>.
+ * @a num is assigned to variable status, @a str to variable phrase.
+ * Macro SET_STATUS1 expands to two comma-separated expressions that are
+ * also usable as function arguments.
+ */
+#define SET_STATUS1(x) ((status = x), status), (phrase = ((void)x))
+
+/* ---------------------------------------------------------------------- */
+/* Application side prototypes */
+
+void nua_signal(nua_t *nua, nua_handle_t *nh, msg_t *msg, int always,
+ nua_event_t event, int status, char const *phrase,
+ tag_type_t tag, tag_value_t value, ...);
+
+void nua_event(nua_t *root_magic, su_msg_r sumsg, event_t *e);
+
+SOFIA_END_DECLS
+
+#endif /* NUA_STACK_H */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_subnotref.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_subnotref.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,926 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nua_subnotref.c
+ * @brief Subscriber (event watcher)
+ *
+ * This file contains implementation SUBSCRIBE UAC, NOTIFY UAS, REFER UAC.
+ * The implementation of SUBSCRIBE UAS, NOTIFY UAC and REFER UAS is in
+ * nua_notifier.c.
+ * Alternative implementation using nea is in nua_event_server.c.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Mar 8 15:10:08 EET 2006 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include <assert.h>
+
+#include <sofia-sip/string0.h>
+#include <sofia-sip/sip_protos.h>
+#include <sofia-sip/sip_status.h>
+#include <sofia-sip/sip_util.h>
+#include <sofia-sip/su_uniqueid.h>
+
+#define NTA_LEG_MAGIC_T struct nua_handle_s
+#define NTA_OUTGOING_MAGIC_T struct nua_handle_s
+
+#include "nua_stack.h"
+
+/* ---------------------------------------------------------------------- */
+/* Subcriber event usage */
+
+struct event_usage
+{
+ enum nua_substate eu_substate; /**< Subscription state */
+ sip_time_t eu_expires; /**< Proposed expiration time */
+ unsigned eu_notified; /**< Number of NOTIFYs received */
+ unsigned eu_final_wait:1; /**< Waiting for final NOTIFY */
+ unsigned eu_no_id:1; /**< Do not use "id" (even if we have one) */
+};
+
+static char const *nua_subscribe_usage_name(nua_dialog_usage_t const *du);
+static int nua_subscribe_usage_add(nua_handle_t *nh,
+ nua_dialog_state_t *ds,
+ nua_dialog_usage_t *du);
+static void nua_subscribe_usage_remove(nua_handle_t *nh,
+ nua_dialog_state_t *ds,
+ nua_dialog_usage_t *du);
+static void nua_subscribe_usage_refresh(nua_handle_t *,
+ nua_dialog_state_t *,
+ nua_dialog_usage_t *,
+ sip_time_t);
+static int nua_subscribe_usage_shutdown(nua_handle_t *,
+ nua_dialog_state_t *,
+ nua_dialog_usage_t *);
+
+static nua_usage_class const nua_subscribe_usage[1] = {
+ {
+ sizeof (struct event_usage), (sizeof nua_subscribe_usage),
+ nua_subscribe_usage_add,
+ nua_subscribe_usage_remove,
+ nua_subscribe_usage_name,
+ NULL,
+ nua_subscribe_usage_refresh,
+ nua_subscribe_usage_shutdown
+ }};
+
+static char const *nua_subscribe_usage_name(nua_dialog_usage_t const *du)
+{
+ return "subscribe";
+}
+
+static
+int nua_subscribe_usage_add(nua_handle_t *nh,
+ nua_dialog_state_t *ds,
+ nua_dialog_usage_t *du)
+{
+ ds->ds_has_events++;
+ ds->ds_has_subscribes++;
+ return 0;
+}
+
+static
+void nua_subscribe_usage_remove(nua_handle_t *nh,
+ nua_dialog_state_t *ds,
+ nua_dialog_usage_t *du)
+{
+ ds->ds_has_events--;
+ ds->ds_has_subscribes--;
+}
+
+/* ====================================================================== */
+/* SUBSCRIBE */
+
+/** Subscribe to a SIP event.
+ *
+ * Subscribe a SIP event using the SIP SUBSCRIBE request. If the
+ * SUBSCRBE is successful a subscription state is established and
+ * the subscription is refreshed regularly. The refresh requests will
+ * generate #nua_r_subscribe events.
+ *
+ * @param nh Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return
+ * nothing
+ *
+ * @par Related Tags:
+ * NUTAG_URL()
+ * Tags in <sip_tag.h>
+ *
+ * @par Events:
+ * #nua_r_subscribe \n
+ * #nua_i_notify
+ *
+ * @sa NUTAG_SUBSTATE(), @RFC3265
+ */
+
+/** Unsubscribe an event.
+ *
+ * Unsubscribe an active or pending subscription with SUBSCRIBE request
+ * containing Expires: header with value 0. The dialog associated with
+ * subscription will be destroyed if there is no other subscriptions or
+ * call using this dialog.
+ *
+ * @param nh Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return
+ * nothing
+ *
+ * @par Related Tags:
+ * SIPTAG_EVENT() or SIPTAG_EVENT_STR() \n
+ * Tags in <sip_tag.h> except SIPTAG_EXPIRES() or SIPTAG_EXPIRES_STR()
+ *
+ * @par Events:
+ * #nua_r_unsubscribe
+ *
+ * @sa NUTAG_SUBSTATE(), @RFC3265
+ */
+
+static int process_response_to_subscribe(nua_handle_t *nh,
+ nta_outgoing_t *orq,
+ sip_t const *sip);
+
+
+int
+nua_stack_subscribe(nua_t *nua, nua_handle_t *nh, nua_event_t e,
+ tagi_t const *tags)
+{
+ nua_client_request_t *cr = nh->nh_ds->ds_cr;
+ nua_dialog_usage_t *du = NULL;
+ struct event_usage *eu;
+ msg_t *msg;
+ sip_t *sip;
+
+ if (nua_stack_set_handle_special(nh, nh_has_subscribe, nua_r_subscribe) < 0)
+ return UA_EVENT3(e, 500, "Invalid handle for SUBSCRIBE",
+ NUTAG_SUBSTATE(nua_substate_terminated));
+ else if (cr->cr_orq)
+ return UA_EVENT2(e, 900, "Request already in progress");
+
+ /* Initialize allow and auth */
+ nua_stack_init_handle(nua, nh, TAG_NEXT(tags));
+
+ msg = nua_creq_msg(nua, nh, cr, 0,
+ SIP_METHOD_SUBSCRIBE,
+ NUTAG_USE_DIALOG(1),
+ NUTAG_ADD_CONTACT(1),
+ TAG_NEXT(tags));
+ sip = sip_object(msg);
+
+ if (sip) {
+ sip_event_t *o = sip->sip_event;
+
+ du = nua_dialog_usage_get(nh->nh_ds, nua_subscribe_usage, o);
+
+ if (du == NULL && o == NULL)
+ du = nua_dialog_usage_get(nh->nh_ds, nua_subscribe_usage, NONE);
+
+ eu = nua_dialog_usage_private(du);
+
+ if (du && du->du_event && (o == NULL || (o->o_id && eu->eu_no_id))) {
+ if (eu->eu_no_id) /* No id (XXX - nor other parameters) */
+ sip_add_make(msg, sip, sip_event_class, du->du_event->o_type);
+ else
+ sip_add_dup(msg, sip, (sip_header_t *)du->du_event);
+ }
+
+ if (e == nua_r_subscribe) {
+ if (du == NULL) /* Create dialog usage */
+ /* We allow here SUBSCRIBE without event */
+ du = nua_dialog_usage_add(nh, nh->nh_ds, nua_subscribe_usage, o);
+ }
+ else if (du) { /* Unsubscribe */
+ /* Embryonic subscription is just a placeholder */
+ if (eu->eu_substate == nua_substate_terminated ||
+ eu->eu_substate == nua_substate_embryonic) {
+ nua_dialog_usage_remove(nh, nh->nh_ds, du);
+ msg_destroy(msg);
+ return UA_EVENT3(e, SIP_200_OK,
+ NUTAG_SUBSTATE(nua_substate_terminated),
+ TAG_END());
+ }
+ }
+ }
+
+ /* Store message template with supported features (eventlist) */
+ if (du && sip) {
+ if (du->du_msg)
+ msg_destroy(du->du_msg);
+ du->du_msg = msg_ref_create(cr->cr_msg);
+ }
+
+ if (du)
+ cr->cr_orq = nta_outgoing_mcreate(nua->nua_nta,
+ process_response_to_subscribe, nh, NULL,
+ msg,
+ TAG_IF(e != nua_r_subscribe,
+ SIPTAG_EXPIRES_STR("0")),
+ SIPTAG_END(), TAG_NEXT(tags));
+
+ eu = nua_dialog_usage_private(du);
+
+ if (!cr->cr_orq) {
+ int substate = nua_substate_terminated;
+
+ if (du == NULL)
+ ;
+ else if (du->du_ready)
+ substate = eu->eu_substate; /* No change in subscription state */
+ else
+ nua_dialog_usage_remove(nh, nh->nh_ds, du);
+
+ msg_destroy(msg);
+
+ return UA_EVENT3(e, NUA_INTERNAL_ERROR,
+ NUTAG_SUBSTATE(substate), TAG_END());
+ }
+
+ nua_dialog_usage_reset_refresh(du); /* during SUBSCRIBE transaction */
+ du->du_terminating = e != nua_r_subscribe; /* Unsubscribe or destroy */
+
+ if (du->du_terminating)
+ eu->eu_expires = 0;
+ else if (sip->sip_expires)
+ eu->eu_expires = sip->sip_expires->ex_delta;
+ else
+ /* We just use common default value, but the default is actually
+ package-specific according to the RFC 3265 section 4.4.4:
+ [Event] packages MUST also define a
+ default "Expires" value to be used if none is specified. */
+ eu->eu_expires = 3600;
+
+ eu->eu_final_wait = 0;
+
+ if (sip->sip_expires && sip->sip_expires->ex_delta == 0)
+ du->du_terminating = 1;
+
+ if (eu->eu_substate == nua_substate_terminated)
+ eu->eu_substate = nua_substate_embryonic;
+
+ cr->cr_usage = du;
+ return cr->cr_event = e;
+}
+
+static void restart_subscribe(nua_handle_t *nh, tagi_t *tags)
+{
+ nua_creq_restart(nh, nh->nh_ds->ds_cr, process_response_to_subscribe, tags);
+}
+
+/** @NUA_EVENT nua_r_subscribe
+ *
+ * Response to an outgoing SUBSCRIBE request.
+ *
+ * The SUBSCRIBE request may have been sent explicitly by nua_subscribe() or
+ * implicitly by NUA state machine.
+ *
+ * @param status response status code
+ * (if the request is retried, @a status is 100, the @a
+ * sip->sip_status->st_status contain the real status code
+ * from the response message, e.g., 302, 401, or 407)
+ * @param phrase a short textual description of @a status code
+ * @param nh operation handle associated with the subscription
+ * @param hmagic application context associated with the handle
+ * @param sip response to SUBSCRIBE request or NULL upon an error
+ * (status code is in @a status and
+ * descriptive message in @a phrase parameters)
+ * @param tags NUTAG_SUBSTATE()
+ *
+ * @sa nua_subscribe(), @RFC3265
+ *
+ * @END_NUA_EVENT
+ */
+
+/** @NUA_EVENT nua_r_unsubscribe
+ *
+ * Response to an outgoing un-SUBSCRIBE.
+ *
+ * @param status response status code
+ * (if the request is retried, @a status is 100, the @a
+ * sip->sip_status->st_status contain the real status code
+ * from the response message, e.g., 302, 401, or 407)
+ * @param phrase a short textual description of @a status code
+ * @param nh operation handle associated with the subscription
+ * @param hmagic application context associated with the handle
+ * @param sip response to SUBSCRIBE request or NULL upon an error
+ * (status code is in @a status and
+ * descriptive message in @a phrase parameters)
+ * @param tags NUTAG_SUBSTATE()
+ *
+ * @sa nua_unsubscribe(), @RFC3265
+ *
+ * @END_NUA_EVENT
+ */
+
+static int process_response_to_subscribe(nua_handle_t *nh,
+ nta_outgoing_t *orq,
+ sip_t const *sip)
+{
+ nua_client_request_t *cr = nh->nh_ds->ds_cr;
+ nua_dialog_usage_t *du = cr->cr_usage;
+ struct event_usage *eu = nua_dialog_usage_private(du);
+ int status = sip ? sip->sip_status->st_status : 408;
+ int gracefully = 0;
+ int substate = nua_substate_embryonic;
+
+ assert(du); assert(du->du_class == nua_subscribe_usage);
+
+ if (status < 200)
+ ;
+ else if (du == NULL) {
+ /* NOTIFY already removed du */
+ }
+ /* We have not received NOTIFY. */
+ else if (status < 300) {
+ int win_messenger_enable = NH_PGET(nh, win_messenger_enable);
+ sip_time_t delta, now = sip_now();
+
+ du->du_ready = 1;
+ substate = eu->eu_substate;
+
+ if (du->du_terminating)
+ delta = 0;
+ else
+ /* If there is no expires header,
+ use default value stored in eu_expires */
+ delta = sip_contact_expires(NULL, sip->sip_expires, sip->sip_date,
+ eu->eu_expires, now);
+
+ if (win_messenger_enable && !nua_dialog_is_established(nh->nh_ds)) {
+ /* Notify from messanger does not match with dialog tag */
+ nh->nh_ds->ds_remote_tag = su_strdup(nh->nh_home, "");
+ }
+
+ nua_dialog_uac_route(nh, nh->nh_ds, sip, 1);
+ nua_dialog_store_peer_info(nh, nh->nh_ds, sip);
+
+ if (delta > 0) {
+ nua_dialog_usage_set_refresh(du, delta);
+ }
+ else if (!eu->eu_notified) {
+ /* This is a fetch: subscription was really terminated
+ but we wait 32 seconds for NOTIFY. */
+ delta = 64 * NTA_SIP_T1 / 1000;
+
+ if (win_messenger_enable)
+ delta = 4 * 60; /* Wait 4 minutes for NOTIFY from Messenger */
+
+ eu->eu_final_wait = 1;
+
+ /* Do not remove usage in nua_stack_process_response */
+ cr->cr_usage = NULL;
+
+ nua_dialog_usage_refresh_range(du, delta, delta);
+ }
+ else {
+ eu->eu_substate = substate = nua_substate_terminated;
+ }
+ }
+ else /* if (status >= 300) */ {
+ int terminated;
+
+ if (nua_creq_check_restart(nh, cr, orq, sip, restart_subscribe))
+ return 0;
+
+ cr->cr_usage = NULL; /* We take care of removing/not removing usage */
+
+ substate = eu->eu_substate;
+
+ if (!sip || !sip->sip_retry_after)
+ gracefully = 1;
+
+ terminated =
+ sip_response_terminates_dialog(status, sip_method_subscribe,
+ &gracefully);
+
+ /* XXX - zap dialog if terminated < 0 ? */
+
+ if (terminated || !du->du_ready || du->du_terminating) {
+ substate = nua_substate_terminated;
+ nua_dialog_usage_remove(nh, nh->nh_ds, du);
+ }
+ else if (gracefully && substate != nua_substate_terminated)
+ /* Post un-subscribe event */
+ nua_stack_post_signal(nh, nua_r_unsubscribe,
+ SIPTAG_EVENT(du->du_event),
+ SIPTAG_EXPIRES_STR("0"),
+ TAG_END());
+ }
+
+ nua_stack_process_response(nh, cr, orq, sip,
+ TAG_IF(substate >= 0, NUTAG_SUBSTATE(substate)),
+ TAG_END());
+ return 0;
+}
+
+/** Refresh subscription */
+static void nua_subscribe_usage_refresh(nua_handle_t *nh,
+ nua_dialog_state_t *ds,
+ nua_dialog_usage_t *du,
+ sip_time_t now)
+{
+ nua_t *nua = nh->nh_nua;
+ nua_client_request_t *cr = ds->ds_cr;
+ struct event_usage *eu = nua_dialog_usage_private(du);
+ msg_t *msg;
+
+ assert(eu);
+
+ if (eu->eu_final_wait) {
+ /* Did not receive NOTIFY for fetch... */
+ sip_event_t const *o = du->du_event;
+ char const *id = o ? o->o_id : NULL;
+
+ SU_DEBUG_3(("nua(%p): fetch event %s%s%s timeouts\n",
+ nh, o ? o->o_type : "(empty)",
+ id ? "; id=" : "", id ? id : ""));
+
+ nua_stack_event(nh->nh_nua, nh, NULL,
+ nua_i_notify, 408, "Fetch Timeouts without NOTIFY",
+ NUTAG_SUBSTATE(nua_substate_terminated),
+ SIPTAG_EVENT(o),
+ TAG_END());
+
+ nua_dialog_usage_remove(nh, ds, du);
+
+ return;
+ }
+
+ if (du->du_terminating) /* No need to refresh. */
+ return;
+
+ if (cr->cr_msg) {
+ /* Already doing something, delay 5..15 seconds? */
+ if (cr->cr_usage != du)
+ nua_dialog_usage_refresh_range(du, 5, 15);
+ return;
+ }
+
+ cr->cr_msg = msg_copy(du->du_msg);
+
+ msg = nua_creq_msg(nua, nh, cr, 1,
+ SIP_METHOD_SUBSCRIBE,
+ NUTAG_USE_DIALOG(1),
+ NUTAG_ADD_CONTACT(1),
+ /* If dialog is established, remove initial route */
+ TAG_IF(nua_dialog_is_established(nh->nh_ds),
+ SIPTAG_ROUTE(NONE)),
+ TAG_END());
+
+ cr->cr_orq = nta_outgoing_mcreate(nua->nua_nta,
+ process_response_to_subscribe, nh, NULL,
+ msg,
+ SIPTAG_END(), TAG_NEXT(NULL));
+ if (cr->cr_orq) {
+ cr->cr_usage = du;
+ cr->cr_event = nua_r_subscribe;
+ return;
+ }
+
+ if (du->du_terminating)
+ nua_dialog_usage_remove(nh, nh->nh_ds, du);
+ else /* Try again later? */
+ nua_dialog_usage_refresh_range(du, 5, 15);
+
+ msg_destroy(msg);
+ UA_EVENT3(nua_r_subscribe, NUA_INTERNAL_ERROR,
+ NUTAG_SUBSTATE(eu->eu_substate),
+ TAG_END());
+}
+
+
+/** Terminate subscription */
+static int nua_subscribe_usage_shutdown(nua_handle_t *nh,
+ nua_dialog_state_t *ds,
+ nua_dialog_usage_t *du)
+{
+ nua_t *nua = nh->nh_nua;
+ nua_client_request_t *cr = ds->ds_cr;
+ struct event_usage *eu = nua_dialog_usage_private(du);
+ msg_t *msg;
+
+ assert(eu); (void)eu;
+
+ if (du->du_terminating)
+ return 100; /* ...in progress */
+
+ if (cr->cr_msg)
+ /* XXX - already doing something else? */
+ return 100;
+
+ cr->cr_msg = msg_copy(du->du_msg);
+
+ msg = nua_creq_msg(nua, nh, cr, 1,
+ SIP_METHOD_SUBSCRIBE,
+ NUTAG_USE_DIALOG(1),
+ NUTAG_ADD_CONTACT(1),
+ SIPTAG_EXPIRES_STR("0"),
+ /* If dialog is established, remove initial route */
+ TAG_IF(nua_dialog_is_established(nh->nh_ds),
+ SIPTAG_ROUTE(NONE)),
+ TAG_END());
+
+ cr->cr_orq = nta_outgoing_mcreate(nua->nua_nta,
+ process_response_to_subscribe, nh, NULL,
+ msg,
+ SIPTAG_END(), TAG_NEXT(NULL));
+ if (cr->cr_orq) {
+ cr->cr_usage = du;
+ cr->cr_event = nua_r_destroy;
+ return 100;
+ }
+
+ /* Too bad. */
+ nua_dialog_usage_remove(nh, ds, du);
+ msg_destroy(msg);
+ return 200;
+}
+
+/* ======================================================================== */
+/* NOTIFY server */
+
+/** @NUA_EVENT nua_i_notify
+ *
+ * Event for incoming NOTIFY request.
+ *
+ * @param status statuscode of response sent automatically by stack
+ * @param phrase a short textual description of @a status code
+ * @param nh operation handle associated with the subscription
+ * @param hmagic application context associated with the handle
+ * @param sip incoming NOTIFY request
+ * @param tags NUTAG_SUBSTATE() indicating the subscription state
+ *
+ * @sa nua_subscribe(), nua_unsubscribe(), @RFC3265, #nua_i_subscribe
+ *
+ * @END_NUA_EVENT
+ */
+
+/** @internal Process incoming NOTIFY. */
+int nua_stack_process_notify(nua_t *nua,
+ nua_handle_t *nh,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ nua_dialog_state_t *ds = nh->nh_ds;
+ nua_dialog_usage_t *du;
+ struct event_usage *eu;
+ sip_subscription_state_t *subs = sip ? sip->sip_subscription_state : NULL;
+ sip_subscription_state_t ss0[1];
+ msg_t *response;
+ char expires[32];
+ int retry = -1;
+ char const *what = NULL, *why = NULL;
+
+ enter;
+
+ if (nh == NULL) {
+ nta_incoming_treply(irq, 481, "Subscription Does Not Exist",
+ TAG_END());
+ return 481;
+ }
+ assert(nh);
+
+ if (/* XXX - support forking of subscriptions?... */
+ ds->ds_remote_tag && ds->ds_remote_tag[0] &&
+ sip && sip->sip_from->a_tag &&
+ strcmp(ds->ds_remote_tag, sip->sip_from->a_tag)) {
+ sip_contact_t const *m = NULL;
+ sip_warning_t *w = NULL, w0[1];
+
+ m = nua_stack_get_contact(nua->nua_registrations);
+ if (m) {
+ w = sip_warning_init(w0);
+ w->w_code = 399;
+ w->w_host = m->m_url->url_host;
+ w->w_port = m->m_url->url_port;
+ w->w_text = "Forking SUBSCRIBEs are not supported";
+ }
+
+ nta_incoming_treply(irq, 481, "Subscription Does Not Exist",
+ SIPTAG_WARNING(w),
+ TAG_END());
+ return 481;
+ }
+
+ du = nua_dialog_usage_get(nh->nh_ds, nua_subscribe_usage, sip->sip_event);
+
+ if (du == NULL) {
+ nta_incoming_treply(irq, 481, "Subscription Does Not Exist", TAG_END());
+ return 481;
+ }
+
+ eu = nua_dialog_usage_private(du); assert(eu);
+ eu->eu_notified++;
+
+ if (!sip->sip_event->o_id) {
+ eu->eu_no_id = 1;
+ }
+
+ if (subs == NULL) {
+ /* Do some compatibility stuff here */
+ unsigned long delta;
+
+ sip_subscription_state_init(subs = ss0);
+
+ delta = sip->sip_expires ? sip->sip_expires->ex_delta : eu->eu_expires;
+
+ if (delta == 0)
+ subs->ss_substate = "terminated";
+ else
+ subs->ss_substate = "active";
+
+ if (delta > 0 && sip->sip_expires) {
+ snprintf(expires, sizeof expires, "%lu", delta);
+ subs->ss_expires = expires;
+ }
+ }
+
+ nua_dialog_store_peer_info(nh, nh->nh_ds, sip);
+ nua_dialog_uas_route(nh, nh->nh_ds, sip, 1);
+
+ if (strcasecmp(subs->ss_substate, what = "terminated") == 0) {
+ eu->eu_substate = nua_substate_terminated;
+
+ if (str0casecmp(subs->ss_reason, why = "deactivated") == 0) {
+ eu->eu_substate = nua_substate_embryonic;
+ retry = 0; /* retry immediately */
+ }
+ else if (str0casecmp(subs->ss_reason, why = "probation") == 0) {
+ eu->eu_substate = nua_substate_embryonic;
+ retry = 30;
+ if (subs->ss_retry_after)
+ retry = strtoul(subs->ss_retry_after, NULL, 10);
+ if (retry > 3600)
+ retry = 3600;
+ }
+ else
+ why = subs->ss_reason;
+ }
+ else if (strcasecmp(subs->ss_substate, what = "pending") == 0)
+ eu->eu_substate = nua_substate_pending;
+ else /* if (strcasecmp(subs->ss_substate, "active") == 0) */ {
+ /* Any extended state is considered as active */
+ what = subs->ss_substate ? subs->ss_substate : "active";
+ eu->eu_substate = nua_substate_active;
+ }
+
+ if (du->du_terminating)
+ retry = -1;
+
+ response = nh_make_response(nua, nh, irq, SIP_200_OK,
+ SIPTAG_ALLOW(NH_PGET(nh, allow)),
+ SIPTAG_SUPPORTED(NH_PGET(nh, supported)),
+ TAG_END());
+
+ if (response &&
+ nua_registration_add_contact_to_response(nh, response, NULL,
+ sip->sip_record_route,
+ sip->sip_contact) >= 0)
+ nta_incoming_mreply(irq, response);
+ else
+ nta_incoming_treply(irq, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
+
+ if (eu->eu_substate == nua_substate_terminated && retry > 0)
+ eu->eu_substate = nua_substate_embryonic;
+
+ nua_stack_event(nh->nh_nua, nh, nta_incoming_getrequest(irq),
+ nua_i_notify, SIP_200_OK,
+ NUTAG_SUBSTATE(eu->eu_substate),
+ TAG_END());
+
+ nta_incoming_destroy(irq), irq = NULL;
+
+ SU_DEBUG_5(("nua(%p): nua_stack_process_notify: %s (%s)\n",
+ nh, what, why ? why : ""));
+
+ if (eu->eu_substate == nua_substate_terminated) {
+ if (du != nh->nh_ds->ds_cr->cr_usage)
+ nua_dialog_usage_remove(nh, nh->nh_ds, du);
+ else
+ nua_dialog_usage_reset_refresh(du);
+ }
+ else if (eu->eu_substate == nua_substate_embryonic) {
+ if (retry >= 0) {
+ /* Try to subscribe again */
+ nua_dialog_remove(nh, nh->nh_ds, du); /* tear down */
+ nua_dialog_usage_refresh_range(du, retry, retry + 5);
+ }
+ else if (du != nh->nh_ds->ds_cr->cr_usage)
+ nua_dialog_usage_remove(nh, nh->nh_ds, du);
+ else
+ nua_dialog_usage_reset_refresh(du);
+ }
+ else if (du->du_terminating) {
+ nua_dialog_usage_reset_refresh(du);
+ }
+ else {
+ sip_time_t delta;
+
+ if (subs->ss_expires)
+ delta = strtoul(subs->ss_expires, NULL, 10);
+ else
+ delta = eu->eu_expires;
+
+ nua_dialog_usage_set_refresh(du, delta);
+ }
+
+ return 0;
+}
+
+/* ======================================================================== */
+/* REFER */
+
+/** Transfer a call.
+ *
+ * Send a REFER request asking the recipient to transfer the call.
+ *
+ * The REFER request also establishes an implied subscription to the "refer"
+ * event. The "refer" event can have an "id" parameter, which has the value
+ * of CSeq number in the REFER request. After initiating the REFER request,
+ * the nua engine sends application a #nua_r_refer event with status 100 and
+ * tag NUTAG_REFER_EVENT() containing a matching event header with id
+ * parameter.
+ *
+ * Note that the @Event header in the locally generated #nua_r_refer event
+ * contains the @a id parameter. The @a id parameter contains the @CSeq
+ * number of the REFER request, and it may get incremented if the request is
+ * retried because it got challenged or redirected. In that case, the
+ * application gets a new #nua_r_refer event with status 100 and tag
+ * NUTAG_REFER_EVENT(). Also the recipient of the REFER request may or may
+ * not include the @a id parameter with the @Event header in the NOTIFY
+ * requests messages which it sends to the sender of the REFER request.
+ *
+ * Therefore the application is not able to modify the state of the implied
+ * subscription before receiving the first NOTIFY request.
+ *
+ * @param nh Pointer to operation handle
+ * @param tag, value, ... List of tagged parameters
+ *
+ * @return
+ * nothing
+ *
+ * @par Related Tags:
+ * NUTAG_URL() \n
+ * Tags of nua_set_hparams() \n
+ * Tags in <sip_tag.h>
+ *
+ * @par Events:
+ * #nua_r_refer \n
+ * #nua_i_notify
+ *
+ * @sa #nua_r_refer, NUTAG_SUBSTATE(), NUTAG_REFER_EVENT(),#nua_i_refer,
+ * @RFC3515, @ReferTo, @RFC3892, @ReferredBy
+ */
+
+static int process_response_to_refer(nua_handle_t *nh,
+ nta_outgoing_t *orq,
+ sip_t const *sip);
+
+int
+nua_stack_refer(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags)
+{
+ nua_dialog_usage_t *du = NULL;
+ nua_client_request_t *cr = nh->nh_ds->ds_cr;
+ msg_t *msg;
+ sip_t *sip;
+ sip_referred_by_t by[1];
+ sip_event_t *event = NULL;
+
+ if (nua_stack_set_handle_special(nh, nh_has_subscribe, nua_r_subscribe) < 0)
+ return UA_EVENT2(e, 900, "Invalid handle for REFER");
+ else if (cr->cr_orq)
+ return UA_EVENT2(e, 900, "Request already in progress");
+
+ nua_stack_init_handle(nua, nh, TAG_NEXT(tags));
+
+ sip_referred_by_init(by);
+ by->b_display = nua->nua_from->a_display;
+ *by->b_url = *nua->nua_from->a_url;
+
+ /* Now we create a REFER request message */
+ msg = nua_creq_msg(nua, nh, cr, cr->cr_retry_count,
+ SIP_METHOD_REFER,
+ NUTAG_USE_DIALOG(1),
+ SIPTAG_EVENT(SIP_NONE), /* remove event */
+ SIPTAG_REFERRED_BY(by), /* Overriden by user tags */
+ NUTAG_ADD_CONTACT(1),
+ TAG_NEXT(tags));
+ sip = sip_object(msg);
+
+ if (sip && sip->sip_cseq)
+ event = sip_event_format(nh->nh_home, "refer;id=%u",
+ sip->sip_cseq->cs_seq);
+
+ if (event)
+ du = nua_dialog_usage_add(nh, nh->nh_ds, nua_subscribe_usage, event);
+
+ if (du)
+ cr->cr_orq = nta_outgoing_mcreate(nua->nua_nta,
+ process_response_to_refer, nh, NULL,
+ msg,
+ SIPTAG_END(), TAG_NEXT(tags));
+
+ if (!cr->cr_orq) {
+ if (du)
+ nua_dialog_usage_remove(nh, nh->nh_ds, du);
+ su_free(nh->nh_home, event);
+ msg_destroy(msg);
+ return UA_EVENT1(e, NUA_INTERNAL_ERROR);
+ }
+
+ /*
+ * We send a 100 trying event so that application gets a event
+ * it can use to match NOTIFYs with its REFER
+ */
+ nua_stack_event(nua, nh, NULL, e, SIP_100_TRYING,
+ NUTAG_REFER_EVENT(event),
+ TAG_END());
+ su_free(nh->nh_home, event);
+
+ cr->cr_usage = du;
+
+ return cr->cr_event = e;
+}
+
+void restart_refer(nua_handle_t *nh, tagi_t *tags)
+{
+ nua_stack_refer(nh->nh_nua, nh, nh->nh_ds->ds_cr->cr_event, tags);
+}
+
+/**@NUA_EVENT nua_r_refer
+ *
+ * @brief Response to outgoing REFER.
+ *
+ * @param status response status code
+ * (if the request is retried, @a status is 100, the @a
+ * sip->sip_status->st_status contain the real status code
+ * from the response message, e.g., 302, 401, or 407)
+ * @param phrase a short textual description of @a status code
+ * @param nh operation handle associated with the REFER request
+ * @param hmagic application context associated with the handle
+ * @param sip response to REFER request or NULL upon an error
+ * (status code is in @a status and
+ * descriptive message in @a phrase parameters)
+ * @param tags NUTAG_REFER_EVENT() \n
+ * NUTAG_SUBSTATE()
+ *
+ * @sa nua_refer(), NUTAG_SUBSTATE(), #nua_i_refer,
+ * @RFC3515, @ReferTo, @RFC3892, @ReferredBy
+ *
+ * @END_NUA_EVENT
+ */
+
+static int process_response_to_refer(nua_handle_t *nh,
+ nta_outgoing_t *orq,
+ sip_t const *sip)
+{
+ nua_client_request_t *cr = nh->nh_ds->ds_cr;
+ int status = sip ? sip->sip_status->st_status : 408;
+
+ if (status < 200)
+ ;
+ else if (status < 300) {
+ if (cr->cr_usage)
+ cr->cr_usage->du_ready = 1;
+ nua_dialog_uac_route(nh, nh->nh_ds, sip, 1);
+ nua_dialog_store_peer_info(nh, nh->nh_ds, sip);
+ }
+ else /* if (status >= 300) */ {
+ if (cr->cr_usage)
+ nua_dialog_usage_remove(nh, nh->nh_ds, cr->cr_usage), cr->cr_usage = NULL;
+ if (nua_creq_check_restart(nh, cr, orq, sip, restart_refer))
+ return 0;
+ }
+
+ return nua_stack_process_response(nh, cr, orq, sip, TAG_END());
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_tag.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_tag.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,152 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE nua_tag.c Tags and tag lists for NUA
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ *
+ * @date Created: Wed Feb 21 10:13:29 2001 ppessi
+ */
+
+#include "config.h"
+
+#define TAG_NAMESPACE "nua"
+
+#include "sofia-sip/nua_tag.h"
+
+#include <sofia-sip/msg_header.h>
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/url_tag_class.h>
+#include <sofia-sip/sip_tag_class.h>
+#include <sofia-sip/sip_hclasses.h>
+
+tag_typedef_t nutag_any = NSTAG_TYPEDEF(*);
+
+tag_typedef_t nutag_url = URLTAG_TYPEDEF(url);
+tag_typedef_t nutag_address = STRTAG_TYPEDEF(address);
+tag_typedef_t nutag_method = STRTAG_TYPEDEF(method);
+tag_typedef_t nutag_uicc = STRTAG_TYPEDEF(uicc);
+tag_typedef_t nutag_media_features = BOOLTAG_TYPEDEF(media_features);
+tag_typedef_t nutag_callee_caps = BOOLTAG_TYPEDEF(callee_caps);
+tag_typedef_t nutag_early_media = BOOLTAG_TYPEDEF(early_media);
+tag_typedef_t nutag_only183_100rel = BOOLTAG_TYPEDEF(only183_100rel);
+tag_typedef_t nutag_early_answer = BOOLTAG_TYPEDEF(early_answer);
+tag_typedef_t nutag_include_extra_sdp = BOOLTAG_TYPEDEF(include_extra_sdp);
+tag_typedef_t nutag_media_enable = BOOLTAG_TYPEDEF(media_enable);
+
+tag_typedef_t nutag_soa_session = PTRTAG_TYPEDEF(soa_session);
+tag_typedef_t nutag_soa_name = STRTAG_TYPEDEF(soa_name);
+
+tag_typedef_t nutag_retry_count = UINTTAG_TYPEDEF(retry_count);
+tag_typedef_t nutag_max_subscriptions = UINTTAG_TYPEDEF(max_subscriptions);
+
+tag_typedef_t nutag_callstate = INTTAG_TYPEDEF(callstate);
+tag_typedef_t nutag_offer_recv = BOOLTAG_TYPEDEF(offer_recv);
+tag_typedef_t nutag_answer_recv = BOOLTAG_TYPEDEF(answer_recv);
+tag_typedef_t nutag_offer_sent = BOOLTAG_TYPEDEF(offer_sent);
+tag_typedef_t nutag_answer_sent = BOOLTAG_TYPEDEF(answer_sent);
+tag_typedef_t nutag_substate = INTTAG_TYPEDEF(substate);
+tag_typedef_t nutag_invite_timer = UINTTAG_TYPEDEF(invite_timer);
+tag_typedef_t nutag_session_timer = UINTTAG_TYPEDEF(session_timer);
+tag_typedef_t nutag_min_se = UINTTAG_TYPEDEF(min_se);
+tag_typedef_t nutag_session_refresher = INTTAG_TYPEDEF(session_refresher);
+tag_typedef_t nutag_update_refresh = BOOLTAG_TYPEDEF(update_refresh);
+tag_typedef_t nutag_refer_expires = UINTTAG_TYPEDEF(refer_expires);
+tag_typedef_t nutag_refer_with_id = BOOLTAG_TYPEDEF(refer_with_id);
+tag_typedef_t nutag_autoalert = BOOLTAG_TYPEDEF(autoAlert);
+tag_typedef_t nutag_autoanswer = BOOLTAG_TYPEDEF(autoAnswer);
+tag_typedef_t nutag_autoack = BOOLTAG_TYPEDEF(autoACK);
+tag_typedef_t nutag_enableinvite = BOOLTAG_TYPEDEF(enableInvite);
+tag_typedef_t nutag_enablemessage = BOOLTAG_TYPEDEF(enableMessage);
+tag_typedef_t nutag_enablemessenger = BOOLTAG_TYPEDEF(enableMessenger);
+
+
+/* Start NRC Boston */
+tag_typedef_t nutag_smime_enable = BOOLTAG_TYPEDEF(smime_enable);
+tag_typedef_t nutag_smime_opt = INTTAG_TYPEDEF(smime_opt);
+tag_typedef_t nutag_smime_protection_mode =
+ INTTAG_TYPEDEF(smime_protection_mode);
+tag_typedef_t nutag_smime_message_digest =
+ STRTAG_TYPEDEF(smime_message_digest);
+tag_typedef_t nutag_smime_signature =
+ STRTAG_TYPEDEF(smime_signature);
+tag_typedef_t nutag_smime_key_encryption =
+ STRTAG_TYPEDEF(smime_key_encryption);
+tag_typedef_t nutag_smime_message_encryption =
+ STRTAG_TYPEDEF(smime_message_encryption);
+/* End NRC Boston */
+
+tag_typedef_t nutag_sips_url = URLTAG_TYPEDEF(sips_url);
+tag_typedef_t nutag_certificate_dir = STRTAG_TYPEDEF(certificate_dir);
+tag_typedef_t nutag_certificate_phrase = STRTAG_TYPEDEF(certificate_phrase);
+
+tag_typedef_t nutag_registrar = URLTAG_TYPEDEF(registrar);
+tag_typedef_t nutag_identity = PTRTAG_TYPEDEF(identity);
+tag_typedef_t nutag_m_display = STRTAG_TYPEDEF(m_display);
+tag_typedef_t nutag_m_username = STRTAG_TYPEDEF(m_username);
+tag_typedef_t nutag_m_params = STRTAG_TYPEDEF(m_params);
+tag_typedef_t nutag_m_features = STRTAG_TYPEDEF(m_features);
+tag_typedef_t nutag_instance = STRTAG_TYPEDEF(instance);
+tag_typedef_t nutag_outbound = STRTAG_TYPEDEF(outbound);
+
+tag_typedef_t nutag_outbound_set1 = STRTAG_TYPEDEF(outbound_set1);
+tag_typedef_t nutag_outbound_set2 = STRTAG_TYPEDEF(outbound_set2);
+tag_typedef_t nutag_outbound_set3 = STRTAG_TYPEDEF(outbound_set3);
+tag_typedef_t nutag_outbound_set4 = STRTAG_TYPEDEF(outbound_set4);
+
+tag_typedef_t nutag_keepalive = UINTTAG_TYPEDEF(keepalive);
+tag_typedef_t nutag_keepalive_stream = UINTTAG_TYPEDEF(keepalive_stream);
+
+tag_typedef_t nutag_use_dialog = BOOLTAG_TYPEDEF(use_dialog);
+
+tag_typedef_t nutag_auth = STRTAG_TYPEDEF(auth);
+tag_typedef_t nutag_authtime = INTTAG_TYPEDEF(authtime);
+
+tag_typedef_t nutag_event = INTTAG_TYPEDEF(event);
+tag_typedef_t nutag_status = INTTAG_TYPEDEF(status);
+tag_typedef_t nutag_phrase = STRTAG_TYPEDEF(phrase);
+
+tag_typedef_t nutag_handle = PTRTAG_TYPEDEF(handle);
+
+tag_typedef_t nutag_hold = BOOLTAG_TYPEDEF(hold);
+
+tag_typedef_t nutag_notify_refer = PTRTAG_TYPEDEF(notify_refer);
+tag_typedef_t nutag_refer_event = SIPHDRTAG_NAMED_TYPEDEF(refer_event, event);
+tag_typedef_t nutag_refer_pause = BOOLTAG_TYPEDEF(refer_pause);
+tag_typedef_t nutag_user_agent = STRTAG_TYPEDEF(user_agent);
+tag_typedef_t nutag_allow = STRTAG_TYPEDEF(allow);
+tag_typedef_t nutag_allow_events = STRTAG_TYPEDEF(allow_events);
+tag_typedef_t nutag_appl_method = STRTAG_TYPEDEF(appl_method);
+tag_typedef_t nutag_supported = STRTAG_TYPEDEF(supported);
+tag_typedef_t nutag_path_enable = BOOLTAG_TYPEDEF(path_enable);
+tag_typedef_t nutag_service_route_enable =
+ BOOLTAG_TYPEDEF(service_route_enable);
+
+tag_typedef_t nutag_detect_network_updates = UINTTAG_TYPEDEF(detect_network_updates);
+
+tag_typedef_t nutag_with = PTRTAG_TYPEDEF(with);
+
+tag_typedef_t _nutag_add_contact = BOOLTAG_TYPEDEF(add_contact);
+tag_typedef_t _nutag_copy = BOOLTAG_TYPEDEF(copy);
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/outbound.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/outbound.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1237 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE outbound.c
+ * @brief Implementation of SIP NAT traversal and outbound
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Kai Vehmanen <Kai.Vehmanen at nokia.com>
+ * @author Martti Mela <Martti Mela at nokia.com>
+ *
+ * @date Created: Wed May 10 12:11:54 EEST 2006 ppessi
+ */
+
+#include "config.h"
+
+#define NTA_OUTGOING_MAGIC_T struct outbound
+
+#include <outbound.h>
+
+#include <sofia-sip/hostdomain.h>
+#include <sofia-sip/sip.h>
+#include <sofia-sip/sip_protos.h>
+#include <sofia-sip/sip_util.h>
+#include <sofia-sip/sip_status.h>
+#include <sofia-sip/su_tagarg.h>
+#include <sofia-sip/tport.h>
+#include <sofia-sip/nta_tport.h>
+
+#include <sofia-sip/su_md5.h>
+#include <sofia-sip/su_uniqueid.h>
+#include <sofia-sip/token64.h>
+
+#define SU_LOG (nua_log)
+#include <sofia-sip/su_debug.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+
+struct outbound {
+ su_home_t ob_home[1];
+ outbound_owner_vtable
+ const *ob_oo; /**< Callbacks */
+ outbound_owner_t *ob_owner; /**< Backpointer */
+
+ su_root_t *ob_root; /**< Root for timers and stuff */
+ nta_agent_t *ob_nta; /**< SIP transactions */
+
+ char ob_cookie[32]; /**< Our magic cookie */
+
+ struct outbound_prefs {
+ unsigned interval; /**< Default keepalive interval for datagram */
+ unsigned stream_interval; /**< Default keepalive interval for streams */
+ unsigned gruuize:1; /**< Establish a GRUU */
+ unsigned outbound:1; /**< Try to use outbound */
+ unsigned natify:1; /**< Try to detect NAT */
+ unsigned okeepalive:1; /**< Connection keepalive with OPTIONS */
+ unsigned validate:1; /**< Validate registration with OPTIONS */
+ /* How to detect NAT binding or connect to outbound: */
+ unsigned use_connect:1; /**< Use HTTP connect */
+ unsigned use_rport:1; /**< Use received/rport */
+ unsigned use_socks:1; /**< Detect and use SOCKS V5 */
+ unsigned use_upnp:1; /**< Detect and use UPnP */
+ unsigned use_stun:1; /**< Detect and try to use STUN */
+ unsigned :0;
+ } ob_prefs;
+
+ struct outbound_info {
+ /* See enum outbound_feature: */
+ /* 0 do not support, 1 - perhaps supports, 2 - supports, 3 - requires */
+ unsigned gruu:2, outbound:2, pref:2;
+ } ob_info;
+
+ /** Source of Contact header */
+ unsigned ob_by_stack:1;
+ /** Self-generated contacts */
+ unsigned ob_contacts:1, :0;
+
+ /* The registration state machine. */
+ /** Initial REGISTER containing ob_rcontact has been sent */
+ unsigned ob_registering:1;
+ /** 2XX response to REGISTER containg ob_rcontact has been received */
+ unsigned ob_registered:1;
+ /**The registration has been validated:
+ * We have successfully sent OPTIONS to ourselves.
+ */
+ unsigned ob_validated:1;
+ /** The registration has been validated once.
+ * We have successfully sent OPTIONS to ourselves, so do not give
+ * up if OPTIONS probe fails.
+ */
+ unsigned ob_once_validated:1;
+ unsigned :0;
+
+ char const *ob_instance; /**< Our instance ID */
+ int32_t ob_reg_id; /**< Flow-id */
+ char const *ob_features; /**< Feature parameters for rcontact */
+ sip_contact_t *ob_rcontact; /**< Our contact */
+ sip_contact_t *ob_dcontact; /**< Contact for dialogs */
+ sip_contact_t *ob_previous; /**< Stale contact */
+ sip_contact_t *ob_gruu; /**< Contact added to requests */
+ sip_via_t *ob_via; /**< Via header used to generate contacts */
+
+ sip_contact_t *ob_obp; /**< Contacts from outbound proxy */
+
+ char *ob_nat_detected; /**< Our public address */
+ char *ob_nat_port; /**< Our public port number */
+
+ void *ob_stun; /**< Stun context */
+ void *ob_upnp; /**< UPnP context */
+
+ struct {
+ char *sipstun; /**< Stun server usable for keep-alives */
+ unsigned interval; /**< Interval. */
+ su_timer_t *timer; /**< Keep-alive timer */
+ msg_t *msg; /**< Keep-alive OPTIONS message */
+ nta_outgoing_t *orq; /**< Keep-alive OPTIONS transaction */
+ auth_client_t *auc[1]; /**< Authenticator for OPTIONS */
+ /** Progress of registration validation */
+ unsigned validating:1, validated:1,:0;
+ } ob_keepalive; /**< Keepalive informatio */
+};
+
+static
+int outbound_nat_detect(outbound_t *ob,
+ sip_t const *request,
+ sip_t const *response);
+
+/** Return values for outbound_nat_detect(). */
+enum {
+ ob_nat_error = -1, /* or anything below zero */
+ ob_no_nat = 0,
+ ob_nat_detected = 1,
+ ob_nat_changed = 2
+};
+
+/* ---------------------------------------------------------------------- */
+
+#define SIP_METHOD_UNKNOWN sip_method_unknown, NULL
+
+/** Content-Type sent in OPTIONS probing connectivity */
+char const * const outbound_content_type = "application/vnd.nokia-register-usage";
+
+static
+int outbound_check_for_nat(outbound_t *ob,
+ sip_t const *request,
+ sip_t const *response);
+
+enum outbound_feature {
+ outbound_feature_unsupported = 0,
+ outbound_feature_unsure = 1,
+ outbound_feature_supported = 2,
+ outbound_feature_required = 3
+};
+
+static enum outbound_feature feature_level(sip_t const *sip,
+ char const *tag, int level);
+
+static int outbound_contacts_from_via(outbound_t *ob,
+ sip_via_t const *via);
+
+/* ---------------------------------------------------------------------- */
+
+/** Create a new outbound object */
+outbound_t *
+outbound_new(outbound_owner_t *owner,
+ outbound_owner_vtable const *owner_methods,
+ su_root_t *root,
+ nta_agent_t *agent,
+ char const *instance)
+{
+ outbound_t *ob;
+
+ if (!owner || !owner_methods || !root || !agent)
+ return NULL;
+
+ ob = su_home_clone((su_home_t *)owner, sizeof *ob);
+
+ if (ob) {
+ su_md5_t md5[1];
+ uint8_t digest[SU_MD5_DIGEST_SIZE];
+ su_guid_t guid[1];
+
+ ob->ob_owner = owner;
+ ob->ob_oo = owner_methods;
+ ob->ob_root = root;
+ ob->ob_nta = agent;
+
+ if (instance)
+ ob->ob_instance = su_strcat_all(ob->ob_home, "+sip.instance=\"<", instance, ">\"", NULL);
+ ob->ob_reg_id = 0;
+
+ /* Generate a cookie (used as Call-ID) for us */
+ su_md5_init(md5);
+ su_guid_generate(guid);
+ if (instance)
+ su_md5_update(md5, (void *)instance, strlen(instance));
+ su_md5_update(md5, (void *)guid, sizeof guid);
+ su_md5_digest(md5, digest);
+ token64_e(ob->ob_cookie, sizeof ob->ob_cookie, digest, sizeof digest);
+
+ if (instance && !ob->ob_instance)
+ su_home_unref(ob->ob_home), ob = NULL;
+ }
+
+ return ob;
+}
+
+void outbound_unref(outbound_t *ob)
+{
+ if (ob->ob_keepalive.timer)
+ su_timer_destroy(ob->ob_keepalive.timer), ob->ob_keepalive.timer = NULL;
+
+ if (ob->ob_keepalive.orq)
+ nta_outgoing_destroy(ob->ob_keepalive.orq), ob->ob_keepalive.orq = NULL;
+
+ if (ob->ob_keepalive.msg)
+ msg_destroy(ob->ob_keepalive.msg), ob->ob_keepalive.msg = NULL;
+
+ su_home_unref(ob->ob_home);
+}
+
+#include <sofia-sip/bnf.h>
+
+/** Set various outbound and nat-traversal related options. */
+int outbound_set_options(outbound_t *ob,
+ char const *options,
+ unsigned interval,
+ unsigned stream_interval)
+{
+ struct outbound_prefs prefs[1] = {{ 0 }};
+ char const *s;
+
+ prefs->interval = interval;
+ prefs->stream_interval = stream_interval;
+
+ prefs->gruuize = 1;
+ prefs->outbound = 0;
+ prefs->natify = 1;
+ prefs->okeepalive = 1;
+ prefs->validate = 1;
+ prefs->use_rport = 1;
+
+#define MATCH(v) (len == sizeof(#v) - 1 && strncasecmp(#v, s, len) == 0)
+
+ for (s = options; s && s[0]; ) {
+ size_t len = span_token(s);
+ int value = 1;
+
+ if (len > 3 && strncasecmp(s, "no-", 3) == 0)
+ value = 0, s += 3, len -= 3;
+ else if (len > 4 && strncasecmp(s, "not-", 4) == 0)
+ value = 0, s += 4, len -= 4;
+ else if (len > 3 && strncasecmp(s, "no_", 3) == 0)
+ value = 0, s += 3, len -= 3;
+ else if (len > 4 && strncasecmp(s, "not_", 4) == 0)
+ value = 0, s += 4, len -= 4;
+
+ if (len == 0)
+ break;
+ else if (MATCH(gruuize)) prefs->gruuize = value;
+ else if (MATCH(outbound)) prefs->outbound = value;
+ else if (MATCH(natify)) prefs->natify = value;
+ else if (MATCH(validate)) prefs->validate = value;
+ else if (MATCH(options-keepalive)) prefs->okeepalive = value;
+ else if (MATCH(options_keepalive)) prefs->okeepalive = value;
+ else if (MATCH(use-connect)) prefs->use_connect = value;
+ else if (MATCH(use_connect)) prefs->use_connect = value;
+ else if (MATCH(use-rport) || MATCH(use_rport)) prefs->use_rport = value;
+ else if (MATCH(use-socks) || MATCH(use_socks)) prefs->use_socks = value;
+ else if (MATCH(use-upnp) || MATCH(use_upnp)) prefs->use_upnp = value;
+ else if (MATCH(use-stun) || MATCH(use_stun)) prefs->use_stun = value;
+ else
+ SU_DEBUG_1(("outbound_t: unknown option \"%.*s\"\n", (int)len, s));
+
+ s += len;
+ len = strspn(s, " \t\n\r,;");
+ if (len == 0)
+ break;
+ s += len;
+ }
+
+ if (s && s[0]) {
+ SU_DEBUG_1(("outbound_t: invalid options \"%s\"\n", options));
+ return -1;
+ }
+
+ if (prefs->natify &&
+ !(prefs->outbound ||
+ prefs->use_connect ||
+ prefs->use_rport ||
+ prefs->use_socks ||
+ prefs->use_upnp ||
+ prefs->use_stun)) {
+ SU_DEBUG_1(("outbound(%p): no nat traversal method given\n", ob->ob_owner));
+ }
+
+ ob->ob_prefs = *prefs;
+ ob->ob_reg_id = prefs->outbound ? 1 : 0;
+
+ return 0;
+}
+
+/** Set the feature string (added to the Contact header when registering). */
+int outbound_set_features(outbound_t *ob, char *features)
+{
+ char *old_features = (char *)ob->ob_features;
+ char *new_features = su_strdup(ob->ob_home, features);
+
+ if (features && !new_features)
+ return -1;
+
+ ob->ob_features = new_features;
+ su_free(ob->ob_home, old_features);
+ return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/** Hook for sending register request with extra outbound-ish headers. */
+nta_outgoing_t *outbound_register_request(outbound_t *ob, int terminating,
+ sip_contact_t *stack_contact,
+ nta_agent_t *nta,
+ nta_response_f *callback,
+ nta_outgoing_magic_t *magic,
+ url_string_t *next_hop,
+ msg_t *msg,
+ tag_type_t tag, tag_value_t value,
+ ...)
+{
+ sip_contact_t *previous_contact = NULL;
+ ta_list ta;
+ nta_outgoing_t *orq;
+
+ if (stack_contact) {
+ if (ob) {
+ if (ob->ob_contacts)
+ stack_contact = ob->ob_rcontact;
+ previous_contact = ob->ob_previous;
+ }
+ }
+
+ ta_start(ta, tag, value);
+
+ orq = nta_outgoing_mcreate(nta, callback, magic, next_hop, msg,
+ TAG_IF(previous_contact,
+ SIPTAG_CONTACT(previous_contact)),
+ TAG_IF(stack_contact,
+ SIPTAG_CONTACT(stack_contact)),
+ ta_tags(ta));
+
+ ta_end(ta);
+
+ if (orq && ob)
+ ob->ob_registering = 1;
+
+ return orq;
+}
+
+/** Process response to REGISTER request */
+int outbound_register_response(outbound_t *ob,
+ int terminating,
+ sip_t const *request,
+ sip_t const *response)
+{
+ int status, reregister;
+
+ if (!ob)
+ return 0;
+
+ assert(!request || request->sip_request);
+ assert(!response || response->sip_status);
+
+ if (!response || !request)
+ return 0;
+
+ if (terminating) {
+ ob->ob_registered = ob->ob_registering = 0;
+ return 0; /* Cleanup is done separately */
+ }
+
+ reregister = outbound_check_for_nat(ob, request, response);
+ if (reregister)
+ return reregister;
+
+ status = response->sip_status->st_status;
+
+ if (status < 300) {
+ if (request->sip_contact && response->sip_contact)
+ ob->ob_registered = ob->ob_registering;
+ else
+ ob->ob_registered = 0;
+
+ if (ob->ob_previous)
+ msg_header_free(ob->ob_home, (void *)ob->ob_previous);
+ ob->ob_previous = NULL;
+ }
+
+ return 0;
+}
+
+
+/** @internal Check if there is a NAT between us and registrar */
+static
+int outbound_check_for_nat(outbound_t *ob,
+ sip_t const *request,
+ sip_t const *response)
+{
+ int binding_changed;
+ sip_contact_t *m = ob->ob_rcontact;
+
+ /* Update NAT information */
+ binding_changed = outbound_nat_detect(ob, request, response);
+
+ if (!ob->ob_nat_detected)
+ return ob_no_nat;
+
+ /* Contact was set by application, do not change it */
+ if (!ob->ob_by_stack)
+ return ob_no_nat;
+
+ /* Application does not want us to do any NAT traversal */
+ if (!ob->ob_prefs.natify)
+ return ob_no_nat;
+
+ /* We have detected NAT. Now, what to do?
+ * 1) do nothing - register as usual and let proxy take care of it?
+ * 2) try to detect our public nat binding and use it
+ * 2A) use public vias from nta generated by STUN or UPnP
+ * 2B) use SIP Via header
+ */
+
+ /* Do we have to ask for reregistration */
+ if (!m || binding_changed >= ob_nat_changed) {
+ if (ob->ob_stun) {
+ /* Use STUN? */
+ return 1;
+ }
+ else if (ob->ob_upnp) {
+ /* Use UPnP */
+ return 1;
+ }
+ else {
+ if (outbound_contacts_from_via(ob, response->sip_via) < 0)
+ return -1;
+ }
+
+ return 2;
+ }
+
+ return 0;
+}
+
+/**@internal
+ *
+ * Detect NAT.
+ *
+ * Based on "received" and possible "rport" parameters in the top-most Via,
+ * check and update our NAT status.
+ *
+ * @retval ob_nat_changed (2) change in public NAT binding detected
+ * @retval ob_nat_detected (1) NAT binding detected
+ * @retval ob_no_nat (0) no NAT binding detected
+ * @retval -1 an error occurred
+ */
+static
+int outbound_nat_detect(outbound_t *ob,
+ sip_t const *request,
+ sip_t const *response)
+{
+ sip_via_t const *v;
+ int one = 1;
+ char const *received, *rport;
+ char *nat_detected, *nat_port;
+ char *new_detected, *new_port;
+
+ assert(request && request->sip_request);
+ assert(response && response->sip_status);
+
+ if (!ob || !response || !response->sip_via || !request->sip_via)
+ return -1;
+
+ v = response->sip_via;
+
+ received = v->v_received;
+ if (!received || !strcmp(received, request->sip_via->v_host))
+ return 0;
+
+ if (!host_is_ip_address(received)) {
+ if (received[0])
+ SU_DEBUG_3(("outbound(%p): Via with invalid received=%s\n",
+ ob->ob_owner, received));
+ return 0;
+ }
+
+ rport = sip_via_port(v, &one); assert(rport);
+
+ nat_detected = ob->ob_nat_detected;
+ nat_port = ob->ob_nat_port;
+
+ if (nat_detected && host_cmp(received, nat_detected) == 0) {
+ if (nat_port && strcasecmp(rport, nat_port) == 0)
+ return 1;
+ if (!v->v_rport || !v->v_rport[0])
+ return 1;
+ }
+
+ if (!nat_detected) {
+ SU_DEBUG_1(("outbound(%p): detected NAT: %s != %s\n",
+ ob->ob_owner, v->v_host, received));
+ if (ob->ob_oo && ob->ob_oo->oo_status)
+ ob->ob_oo->oo_status(ob->ob_owner, ob, 101, "NAT detected", TAG_END());
+ }
+ else {
+ SU_DEBUG_1(("outbound(%p): NAT binding changed: "
+ "[%s]:%s != [%s]:%s\n",
+ ob->ob_owner, nat_detected, nat_port, received, rport));
+ if (ob->ob_oo && ob->ob_oo->oo_status)
+ ob->ob_oo->oo_status(ob->ob_owner, ob, 102, "NAT binding changed", TAG_END());
+ }
+
+ /* Save our nat binding */
+ new_detected = su_strdup(ob->ob_home, received);
+ new_port = su_strdup(ob->ob_home, rport);
+
+ if (!new_detected || !new_port) {
+ su_free(ob->ob_home, new_detected);
+ su_free(ob->ob_home, new_port);
+ return -1;
+ }
+
+ ob->ob_nat_detected = new_detected;
+ ob->ob_nat_port = new_port;
+
+ su_free(ob->ob_home, nat_detected);
+ su_free(ob->ob_home, nat_port);
+
+ return 2;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/** Convert "gruu" parameter returned by registrar to Contact header. */
+int outbound_gruuize(outbound_t *ob, sip_t const *sip)
+{
+ sip_contact_t *m = NULL;
+ char *gruu;
+
+ if (!ob)
+ return 0;
+
+ if (ob->ob_rcontact == NULL)
+ return -1;
+
+ if (!ob->ob_prefs.gruuize && ob->ob_instance) {
+ char const *my_instance, *my_reg_id = NULL;
+ char const *instance, *reg_id;
+
+ m = ob->ob_rcontact;
+ my_instance = msg_header_find_param(m->m_common, "+sip.instance=");
+ if (my_instance)
+ my_reg_id = msg_header_find_param(m->m_common, "reg-id=");
+
+ for (m = sip->sip_contact; m; m = m->m_next) {
+ if (my_instance) {
+ instance = msg_header_find_param(m->m_common, "+sip.instance=");
+ if (!instance || strcmp(instance, my_instance))
+ continue;
+ if (my_reg_id) {
+ reg_id = msg_header_find_param(m->m_common, "reg-id=");
+ if (!reg_id || strcmp(reg_id, my_reg_id))
+ continue;
+ }
+ }
+
+ if (url_cmp_all(ob->ob_rcontact->m_url, m->m_url) == 0)
+ break;
+ }
+ }
+
+ if (m == NULL) {
+ if (ob->ob_gruu)
+ msg_header_free(ob->ob_home, (void *)ob->ob_gruu), ob->ob_gruu = NULL;
+ return 0;
+ }
+
+ gruu = (char *)msg_header_find_param(m->m_common, "gruu=");
+
+ if (gruu == NULL || gruu[0] == '\0')
+ return 0;
+
+ gruu = msg_unquote_dup(NULL, gruu);
+ m = gruu ? sip_contact_format(ob->ob_home, "<%s>", gruu) : NULL;
+ su_free(NULL, gruu);
+
+ if (!m)
+ return -1;
+
+ if (ob->ob_gruu)
+ msg_header_free(ob->ob_home, (void *)ob->ob_gruu);
+ ob->ob_gruu = m;
+
+ return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int create_keepalive_message(outbound_t *ob,
+ sip_t const *register_request);
+
+static int keepalive_options(outbound_t *ob);
+static int keepalive_options_with_registration_probe(outbound_t *ob);
+
+static int response_to_keepalive_options(outbound_t *ob,
+ nta_outgoing_t *orq,
+ sip_t const *sip);
+
+static void keepalive_timer(su_root_magic_t *root_magic,
+ su_timer_t *t,
+ su_timer_arg_t *ob_as_timer_arg);
+
+/** Start OPTIONS keepalive or contact validation process */
+void outbound_start_keepalive(outbound_t *ob,
+ nta_outgoing_t *register_transaction)
+{
+ unsigned interval = 0;
+ int need_to_validate;
+
+ if (!ob)
+ return;
+
+ if (ob->ob_prefs.natify && ob->ob_prefs.okeepalive)
+ interval = ob->ob_prefs.interval;
+ need_to_validate = ob->ob_prefs.validate && !ob->ob_validated;
+
+ if (!ob->ob_nat_detected || !register_transaction ||
+ !(need_to_validate || interval != 0)) {
+ outbound_stop_keepalive(ob);
+ return;
+ }
+
+ if (ob->ob_keepalive.timer)
+ su_timer_destroy(ob->ob_keepalive.timer), ob->ob_keepalive.timer = NULL;
+
+ if (interval)
+ ob->ob_keepalive.timer =
+ su_timer_create(su_root_task(ob->ob_root), interval);
+
+ ob->ob_keepalive.interval = interval;
+
+ if (!ob->ob_validated && ob->ob_keepalive.sipstun
+ && 0 /* Stun is disabled for now */) {
+ nta_tport_keepalive(register_transaction);
+ }
+ else {
+ if (register_transaction) {
+ msg_t *msg = nta_outgoing_getrequest(register_transaction);
+ sip_t const *register_request = sip_object(msg);
+ create_keepalive_message(ob, register_request);
+ msg_destroy(msg);
+ }
+
+ keepalive_options(ob);
+ }
+}
+
+void outbound_stop_keepalive(outbound_t *ob)
+{
+ if (!ob)
+ return;
+
+ ob->ob_keepalive.interval = 0;
+
+ if (ob->ob_keepalive.timer)
+ su_timer_destroy(ob->ob_keepalive.timer), ob->ob_keepalive.timer = NULL;
+
+ if (ob->ob_keepalive.orq)
+ nta_outgoing_destroy(ob->ob_keepalive.orq), ob->ob_keepalive.orq = NULL;
+
+ if (ob->ob_keepalive.msg)
+ msg_destroy(ob->ob_keepalive.msg), ob->ob_keepalive.msg = NULL;
+}
+
+/** @internal Create a message template for keepalive. */
+static int create_keepalive_message(outbound_t *ob, sip_t const *regsip)
+{
+ msg_t *msg = nta_msg_create(ob->ob_nta, MSG_FLG_COMPACT), *previous;
+ sip_t *osip = sip_object(msg);
+ sip_accept_contact_t *ac;
+
+ char const *p1 = ob->ob_instance;
+ char const *p2 = ob->ob_features;
+
+ unsigned d = ob->ob_keepalive.interval;
+
+ assert(regsip); assert(regsip->sip_request);
+
+ if (p1 || p2) {
+ ac = sip_accept_contact_format(msg_home(msg), "*;require;explicit;%s%s%s",
+ p1 ? p1 : "",
+ p2 && p2 ? ";" : "",
+ p2 ? p2 : "");
+ msg_header_insert(msg, NULL, (void *)ac);
+ }
+
+ if (0 >
+ /* Duplicate essential headers from REGISTER request: */
+ sip_add_tl(msg, osip,
+ SIPTAG_TO(regsip->sip_to),
+ SIPTAG_FROM(regsip->sip_from),
+ /* XXX - we should only use loose routing here */
+ /* XXX - if we used strict routing,
+ the route header/request_uri must be restored
+ */
+ SIPTAG_ROUTE(regsip->sip_route),
+ /* Add Max-Forwards 0 */
+ TAG_IF(d, SIPTAG_MAX_FORWARDS_STR("0")),
+ TAG_IF(d, SIPTAG_SUBJECT_STR("KEEPALIVE")),
+ SIPTAG_CALL_ID_STR(ob->ob_cookie),
+ SIPTAG_ACCEPT_STR(outbound_content_type),
+ TAG_END()) ||
+ /* Create request-line, Call-ID, CSeq */
+ nta_msg_request_complete(msg,
+ nta_default_leg(ob->ob_nta),
+ SIP_METHOD_OPTIONS,
+ (void *)regsip->sip_to->a_url) < 0 ||
+ msg_serialize(msg, (void *)osip) < 0 ||
+ msg_prepare(msg) < 0)
+ return msg_destroy(msg), -1;
+
+ previous = ob->ob_keepalive.msg;
+ ob->ob_keepalive.msg = msg;
+ msg_destroy(previous);
+
+ return 0;
+}
+
+static int keepalive_options(outbound_t *ob)
+{
+ msg_t *req;
+ sip_t *sip;
+
+ if (ob->ob_keepalive.orq)
+ return 0;
+
+ if (ob->ob_prefs.validate && ob->ob_registered && !ob->ob_validated)
+ return keepalive_options_with_registration_probe(ob);
+
+ req = msg_copy(ob->ob_keepalive.msg);
+ if (!req)
+ return -1;
+ sip = sip_object(req); assert(sip); assert(sip->sip_request);
+
+ if (nta_msg_request_complete(req, nta_default_leg(ob->ob_nta),
+ SIP_METHOD_UNKNOWN, NULL) < 0)
+ return msg_destroy(req), -1;
+
+ if (ob->ob_keepalive.auc[0])
+ auc_authorization(ob->ob_keepalive.auc, req, (void *)sip,
+ "OPTIONS", sip->sip_request->rq_url, sip->sip_payload);
+
+ ob->ob_keepalive.orq =
+ nta_outgoing_mcreate(ob->ob_nta,
+ response_to_keepalive_options,
+ ob,
+ NULL,
+ req,
+ TAG_END());
+
+ if (!ob->ob_keepalive.orq)
+ return msg_destroy(req), -1;
+
+ return 0;
+}
+
+static int response_to_keepalive_options(outbound_t *ob,
+ nta_outgoing_t *orq,
+ sip_t const *sip)
+{
+ int status = 408;
+ char const *phrase = sip_408_Request_timeout;
+ int binding_check;
+ int challenged = 0, credentials = 0;
+ msg_t *_reqmsg = nta_outgoing_getrequest(orq);
+ sip_t *request = sip_object(_reqmsg); msg_destroy(_reqmsg);
+
+ if (sip && sip->sip_status) {
+ status = sip->sip_status->st_status;
+ phrase = sip->sip_status->st_phrase;
+ }
+
+ if (status == 100) {
+ /* This probably means that we are in trouble. whattodo, whattodo */
+ }
+
+ if (status < 200)
+ return 0;
+
+ if (status == 401 || status == 407) {
+ if (sip->sip_www_authenticate)
+ challenged += auc_challenge(ob->ob_keepalive.auc,
+ ob->ob_home,
+ sip->sip_www_authenticate,
+ sip_authorization_class) > 0;
+ if (sip->sip_proxy_authenticate)
+ challenged += auc_challenge(ob->ob_keepalive.auc,
+ ob->ob_home,
+ sip->sip_proxy_authenticate,
+ sip_proxy_authorization_class) > 0;
+ if (ob->ob_oo->oo_credentials)
+ credentials = ob->ob_oo->oo_credentials(ob->ob_owner,
+ ob->ob_keepalive.auc);
+ }
+
+ binding_check = outbound_nat_detect(ob, request, sip);
+
+ if (orq == ob->ob_keepalive.orq)
+ ob->ob_keepalive.orq = NULL;
+ nta_outgoing_destroy(orq);
+
+ if (binding_check > 1) {
+ /* Bindings have changed */
+ if (outbound_contacts_from_via(ob, sip->sip_via) == 0) {
+ /* XXX - Destroy old keepalive template message */
+
+ /* re-REGISTER */
+ ob->ob_oo->oo_refresh(ob->ob_owner, ob);
+ return 0;
+ }
+ }
+
+ if (binding_check <= 1 && ob->ob_registered && ob->ob_keepalive.validating) {
+ int failed = 0;
+ unsigned loglevel = 3;
+
+ if (challenged > 0 && credentials > 0) {
+ keepalive_options_with_registration_probe(ob);
+ return 0;
+ }
+
+ if (status < 300 && ob->ob_keepalive.validated) {
+ loglevel = 5;
+ if (ob->ob_validated)
+ loglevel = 99; /* only once */
+ ob->ob_validated = ob->ob_once_validated = 1;
+ }
+ else if (status == 401 || status == 407 || status == 403)
+ loglevel = 5, failed = 1;
+ else
+ loglevel = 3, failed = 1;
+
+ loglevel = 1; /* XXX ... for now */
+
+ if (loglevel >= SU_LOG->log_level) {
+ su_llog(SU_LOG, loglevel,
+ "outbound(%p): %s <" URL_PRINT_FORMAT ">\n",
+ ob->ob_owner, failed ? "FAILED to validate" : "validated",
+ URL_PRINT_ARGS(ob->ob_rcontact->m_url));
+ if (failed)
+ su_llog(SU_LOG, loglevel, "outbound(%p): FAILED with %u %s\n",
+ ob->ob_owner, status, phrase);
+ }
+
+ if (failed)
+ ob->ob_oo->oo_probe_error(ob->ob_owner, ob, status, phrase, TAG_END());
+ }
+ else if (status == 408) {
+ SU_DEBUG_1(("outbound(%p): keepalive timeout\n", ob->ob_owner));
+ ob->ob_oo->oo_keepalive_error(ob->ob_owner, ob, status, phrase, TAG_END());
+ return 0;
+ }
+
+ ob->ob_keepalive.validating = 0;
+
+ if (ob->ob_keepalive.timer)
+ su_timer_set(ob->ob_keepalive.timer, keepalive_timer, ob);
+
+ return 0;
+}
+
+static void keepalive_timer(su_root_magic_t *root_magic,
+ su_timer_t *t,
+ su_timer_arg_t *ob_casted_as_timer_arg)
+{
+ outbound_t *ob = (outbound_t *)ob_casted_as_timer_arg;
+
+ (void)root_magic;
+
+ if (keepalive_options(ob) < 0)
+ su_timer_set(t, keepalive_timer, ob_casted_as_timer_arg); /* XXX */
+}
+
+
+/** @internal Send a keepalive OPTIONS that probes the registration */
+static int keepalive_options_with_registration_probe(outbound_t *ob)
+{
+ msg_t *req;
+ sip_t *sip;
+ void *request_uri;
+
+ if (ob->ob_keepalive.orq)
+ return 0;
+
+ req = msg_copy(ob->ob_keepalive.msg);
+ if (!req)
+ return -1;
+
+ sip = sip_object(req); assert(sip);
+ request_uri = sip->sip_to->a_url;
+
+ if (nta_msg_request_complete(req, nta_default_leg(ob->ob_nta),
+ SIP_METHOD_OPTIONS, request_uri) < 0)
+ return msg_destroy(req), -1;
+
+ if (ob->ob_keepalive.auc[0])
+ auc_authorization(ob->ob_keepalive.auc, req, (void *)sip,
+ "OPTIONS", request_uri, sip->sip_payload);
+
+ ob->ob_keepalive.orq =
+ nta_outgoing_mcreate(ob->ob_nta,
+ response_to_keepalive_options,
+ ob,
+ NULL,
+ req,
+ SIPTAG_SUBJECT_STR("REGISTRATION PROBE"),
+ /* NONE is used to remove
+ Max-Forwards: 0 found in ordinary keepalives */
+ SIPTAG_MAX_FORWARDS(SIP_NONE),
+ TAG_END());
+
+ if (!ob->ob_keepalive.orq)
+ return msg_destroy(req), -1;
+
+ ob->ob_keepalive.validating = 1;
+ ob->ob_keepalive.validated = 0;
+
+ return 0;
+}
+
+/** Check if request should be processed by outbound */
+int outbound_targeted_request(sip_t const *sip)
+{
+ return
+ sip && sip->sip_request &&
+ sip->sip_request->rq_method == sip_method_options &&
+ sip->sip_accept &&
+ sip->sip_accept->ac_type &&
+ strcasecmp(sip->sip_accept->ac_type, outbound_content_type) == 0;
+}
+
+/** Answer to the connectivity probe OPTIONS */
+int outbound_process_request(outbound_t *ob,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ /* XXX - We assume that Call-ID is not modified. */
+ if (strcmp(sip->sip_call_id->i_id, ob->ob_cookie))
+ return 0;
+
+ if (ob->ob_keepalive.validating) {
+ SU_DEBUG_1(("outbound(%p): registration check OPTIONS received\n",
+ ob->ob_owner));
+ ob->ob_keepalive.validated = 1;
+ }
+
+ nta_incoming_treply(irq, SIP_200_OK,
+ SIPTAG_CONTENT_TYPE_STR(outbound_content_type),
+ SIPTAG_PAYLOAD_STR(ob->ob_cookie),
+ TAG_END());
+ return 200;
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+/**@internal
+ * Create contacts for outbound.
+ *
+ * There are two contacts:
+ * one suitable for registrations (ob_rcontact) and another that can be used
+ * in dialogs (ob_dcontact).
+ */
+int outbound_contacts_from_via(outbound_t *ob, sip_via_t const *via)
+{
+ su_home_t *home = ob->ob_home;
+ sip_contact_t *rcontact, *dcontact;
+ int reg_id = 0;
+ char reg_id_param[20] = "";
+ sip_contact_t *previous_previous, *previous_rcontact, *previous_dcontact;
+ sip_via_t *v, v0[1], *previous_via;
+ int contact_uri_changed;
+
+ if (!via)
+ return -1;
+
+ v = v0; *v0 = *via; v0->v_next = NULL;
+
+ dcontact = ob->ob_oo->oo_contact(ob->ob_owner, home,
+ NULL, v, v->v_protocol, NULL);
+
+ if (ob->ob_instance && ob->ob_reg_id != 0)
+ snprintf(reg_id_param, sizeof reg_id_param, ";reg-id=%u", ob->ob_reg_id);
+
+ rcontact = ob->ob_oo->oo_contact(ob->ob_owner, home,
+ NULL, v, v->v_protocol,
+ ob->ob_features ? ob->ob_features : "",
+ ob->ob_instance, reg_id_param, NULL);
+
+#if 0
+ char *uri;
+
+ /* uri contains < > */
+ uri = sip_contact_string_from_via(NULL, via, NULL, v->v_protocol);
+
+ dcontact = sip_contact_make(home, uri);
+
+
+
+ if (ob->ob_instance) {
+ char reg_id[20];
+
+ if (ob->ob_instance && ob->ob_reg_id)
+ snprintf(reg_id, sizeof reg_id, ";reg-id=%u", ob->ob_reg_id);
+ else
+ strcpy(reg_id, "");
+
+ rcontact = sip_contact_format(home, "%s;%s%s%s%s",
+ uri, ob->ob_instance, reg_id,
+ ob->ob_features ? ";" : "",
+ ob->ob_features ? ob->ob_features : "");
+ }
+ else if (ob->ob_features)
+ rcontact = sip_contact_format(home, "%s;%s", uri, ob->ob_features);
+ else
+ rcontact = dcontact;
+
+ free(uri);
+#endif
+
+ v = sip_via_dup(home, v);
+
+ if (!rcontact || !dcontact || !v) {
+ msg_header_free(home, (void *)dcontact);
+ if (rcontact != dcontact)
+ msg_header_free(home, (void *)rcontact);
+ msg_header_free(home, (void *)v);
+ return -1;
+ }
+
+ contact_uri_changed = !ob->ob_rcontact ||
+ url_cmp_all(ob->ob_rcontact->m_url, rcontact->m_url);
+
+ if (contact_uri_changed) {
+ previous_previous = ob->ob_previous;
+ previous_dcontact = ob->ob_dcontact;
+ previous_via = ob->ob_via;
+
+ if (ob->ob_registering &&
+ (reg_id == 0 || ob->ob_info.outbound < outbound_feature_supported))
+ previous_rcontact = NULL, ob->ob_previous = ob->ob_rcontact;
+ else
+ previous_rcontact = ob->ob_rcontact, ob->ob_previous = NULL;
+
+ if (ob->ob_previous)
+ msg_header_replace_param(home, (void*)ob->ob_previous, "expires=0");
+ }
+ else {
+ previous_previous = ob->ob_rcontact;
+ previous_rcontact = NULL;
+ previous_dcontact = ob->ob_dcontact;
+ previous_via = ob->ob_via;
+ }
+
+ ob->ob_contacts = 1;
+
+ ob->ob_rcontact = rcontact;
+ ob->ob_dcontact = dcontact;
+ ob->ob_via = v;
+
+ if (contact_uri_changed) {
+ ob->ob_registering = 0;
+ ob->ob_registered = 0;
+ ob->ob_validated = 0;
+ }
+
+ msg_header_free(home, (void *)previous_rcontact);
+ msg_header_free(home, (void *)previous_previous);
+ if (previous_dcontact != ob->ob_previous &&
+ previous_dcontact != previous_rcontact &&
+ previous_dcontact != previous_previous)
+ msg_header_free(home, (void *)previous_dcontact);
+ msg_header_free(home, (void *)previous_via);
+
+ return 0;
+}
+
+/**Set new contact.
+ *
+ * @retval 0 when successful
+ * @retval -1 error setting contact
+ */
+int outbound_set_contact(outbound_t *ob,
+ sip_contact_t const *application_contact,
+ sip_via_t const *v,
+ int terminating)
+{
+ su_home_t *home = ob->ob_home;
+ sip_contact_t *rcontact = NULL, *dcontact = NULL, *previous = NULL;
+ sip_contact_t *m1, *m2, *m3;
+ int contact_uri_changed = 0;
+
+ m1 = ob->ob_rcontact;
+ m2 = ob->ob_dcontact;
+ m3 = ob->ob_previous;
+
+ if (terminating) {
+ if (ob->ob_contacts)
+ previous = ob->ob_rcontact;
+ }
+ else if (application_contact) {
+ if (!ob->ob_rcontact ||
+ url_cmp_all(ob->ob_rcontact->m_url, application_contact->m_url)) {
+ contact_uri_changed = 1;
+ previous = ob->ob_contacts ? ob->ob_rcontact : NULL;
+ }
+ }
+ else if (v) {
+ char const *tport = !v->v_next ? v->v_protocol : NULL;
+ char reg_id_param[20];
+
+ dcontact = ob->ob_oo->oo_contact(ob->ob_owner, home,
+ NULL, v, tport, NULL);
+ if (!dcontact)
+ return -1;
+
+ if (ob->ob_instance && ob->ob_reg_id != 0)
+ snprintf(reg_id_param, sizeof reg_id_param, ";reg-id=%u", ob->ob_reg_id);
+
+ rcontact = ob->ob_oo->oo_contact(ob->ob_owner, home,
+ NULL, v, v->v_protocol,
+ ob->ob_features ? ob->ob_features : "",
+ ob->ob_instance, reg_id_param, NULL);
+ if (!rcontact)
+ return -1;
+
+ if (!ob->ob_rcontact ||
+ url_cmp_all(ob->ob_rcontact->m_url, rcontact->m_url)) {
+ contact_uri_changed = 1;
+ previous = ob->ob_contacts ? ob->ob_rcontact : NULL;
+ }
+ }
+
+ ob->ob_by_stack = application_contact == NULL;
+
+ ob->ob_rcontact = rcontact;
+ ob->ob_dcontact = dcontact;
+ ob->ob_previous = previous;
+
+ if (contact_uri_changed) {
+ ob->ob_registering = 0;
+ ob->ob_registered = 0;
+ ob->ob_validated = 0;
+ ob->ob_once_validated = 0;
+ }
+
+ if (m1 != previous)
+ msg_header_free(home, (void *)m1);
+ if (m2 != m1 && m2 != m3)
+ msg_header_free(home, (void *)m2);
+ msg_header_free(home, (void *)m3);
+
+ return 0;
+}
+
+sip_contact_t const *outbound_dialog_contact(outbound_t const *ob)
+{
+ if (ob == NULL)
+ return NULL;
+ else if (ob->ob_gruu)
+ return ob->ob_gruu;
+ else
+ return ob->ob_dcontact;
+}
+
+/* ---------------------------------------------------------------------- */
+
+
+static enum outbound_feature
+feature_level(sip_t const *sip, char const *tag, int level)
+{
+ if (sip_has_feature(sip->sip_require, tag))
+ return outbound_feature_required;
+ else if (sip_has_feature(sip->sip_supported, tag))
+ return outbound_feature_supported;
+ else if (sip_has_feature(sip->sip_unsupported, tag))
+ return outbound_feature_unsupported;
+ else
+ return level;
+}
+
+
+void outbound_peer_info(outbound_t *ob, sip_t const *sip)
+{
+ if (sip == NULL) {
+ ob->ob_info.outbound = outbound_feature_unsure;
+ ob->ob_info.gruu = outbound_feature_unsure;
+ ob->ob_info.pref = outbound_feature_unsure;
+ return;
+ }
+
+ ob->ob_info.outbound = feature_level(sip, "outbound", ob->ob_info.outbound);
+ ob->ob_info.gruu = feature_level(sip, "gruu", ob->ob_info.gruu);
+ ob->ob_info.pref = feature_level(sip, "pref", ob->ob_info.pref);
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/outbound.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/outbound.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,145 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef OUTBOUND_H
+/** Defined when <outbound.h> has been included. */
+#define OUTBOUND_H
+/**@IFILE outbound.h
+ *
+ * @brief Interface to SIP NAT traversal and outbound
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed May 10 12:01:38 EEST 2006 ppessi
+ */
+
+#ifndef SU_CONFIG_H
+#include <sofia-sip/su_config.h>
+#endif
+#ifndef NTA_H
+#include <sofia-sip/nta.h>
+#endif
+#ifndef AUTH_CLIENT_H
+#include <sofia-sip/auth_client.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/* ====================================================================== */
+/* Outbound connection */
+
+#ifndef OUTBOUND_OWNER_T
+#define OUTBOUND_OWNER_T struct nua_handle_s /* Just for now */
+#endif
+
+typedef struct outbound outbound_t;
+typedef struct outbound_owner_vtable outbound_owner_vtable;
+typedef OUTBOUND_OWNER_T outbound_owner_t;
+
+outbound_t *outbound_new(outbound_owner_t *owner,
+ outbound_owner_vtable const *owner_methods,
+ su_root_t *root,
+ nta_agent_t *agent,
+ char const *instance);
+
+void outbound_unref(outbound_t *ob);
+
+int outbound_set_options(outbound_t *ob,
+ char const *options,
+ unsigned dgram_interval,
+ unsigned stream_interval);
+
+int outbound_set_features(outbound_t *ob, char *features);
+
+nta_outgoing_t *outbound_register_request(outbound_t *ob, int terminating,
+ sip_contact_t *stack_contact,
+ nta_agent_t *nta,
+ nta_response_f *callback,
+ nta_outgoing_magic_t *magic,
+ url_string_t *next_hop,
+ msg_t *msg,
+ tag_type_t tag, tag_value_t value,
+ ...);
+
+int outbound_register_response(outbound_t *ob,
+ int terminating,
+ sip_t const *request,
+ sip_t const *response);
+
+/** Return values for outbound_register_response(). */
+enum {
+ ob_register_error = -1, /* Or anything below zero */
+ ob_register_ok = 0, /* No need to re-register */
+ ob_reregister = 1, /* Re-register when oo_refresh() is called */
+ ob_reregister_now = 2 /* Re-register immediately */
+};
+
+int outbound_set_contact(outbound_t *ob,
+ sip_contact_t const *application_contact,
+ sip_via_t const *v,
+ int terminating);
+
+sip_contact_t const *outbound_dialog_contact(outbound_t const *ob);
+
+int outbound_gruuize(outbound_t *ob, sip_t const *sip);
+
+void outbound_start_keepalive(outbound_t *ob,
+ nta_outgoing_t *register_trans);
+
+void outbound_stop_keepalive(outbound_t *ob);
+
+int outbound_targeted_request(sip_t const *sip);
+
+int outbound_process_request(outbound_t *ob,
+ nta_incoming_t *irq,
+ sip_t const *sip);
+
+void outbound_peer_info(outbound_t *ob, sip_t const *sip);
+
+struct outbound_owner_vtable
+{
+ int oo_size;
+ sip_contact_t *(*oo_contact)(outbound_owner_t *,
+ su_home_t *home,
+ char const *extra_username,
+ sip_via_t const *v,
+ char const *transport,
+ char const *m_param,
+ ...);
+ int (*oo_refresh)(outbound_owner_t *, outbound_t *ob);
+ int (*oo_status)(outbound_owner_t *, outbound_t *ob,
+ int status, char const *phrase,
+ tag_type_t tag, tag_value_t value, ...);
+ int (*oo_probe_error)(outbound_owner_t *, outbound_t *ob,
+ int status, char const *phrase,
+ tag_type_t tag, tag_value_t value, ...);
+ int (*oo_keepalive_error)(outbound_owner_t *, outbound_t *ob,
+ int status, char const *phrase,
+ tag_type_t tag, tag_value_t value, ...);
+ int (*oo_credentials)(outbound_owner_t *, auth_client_t **auc);
+};
+
+SOFIA_END_DECLS
+
+#endif /* OUTBOUND_H */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,379 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@file sofia-sip/nua.h
+ * @brief Sofia-SIP User Agent Library API
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Feb 14 17:09:44 2001 ppessi
+ */
+
+#ifndef NUA_H
+/** Defined when <sofia-sip/nua.h> has been included. */
+#define NUA_H
+
+#ifndef SU_WAIT_H
+#include <sofia-sip/su_wait.h>
+#endif
+
+
+#ifndef URL_H
+#include <sofia-sip/url.h>
+#endif
+
+#ifndef SIP_H
+#include <sofia-sip/sip.h>
+#endif
+
+#ifndef NUA_TAG_H
+#include <sofia-sip/nua_tag.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+#ifndef NUA_MAGIC_T
+#define NUA_MAGIC_T void
+#endif
+/** Application context for NUA agent. */
+typedef NUA_MAGIC_T nua_magic_t;
+
+#ifndef NUA_HMAGIC_T
+#define NUA_HMAGIC_T void
+#endif
+/** Application context for NUA handle. */
+typedef NUA_HMAGIC_T nua_hmagic_t;
+
+/**Network change event levels given to NUTAG_DETECT_NETWORK_UPDATES().
+ *
+ * @sa NUTAG_DETECT_NETWORK_UPDATES(), #nua_i_network_changed
+ *
+ * @since New in @VERSION_1_12_2.
+ */
+typedef enum nua_nw_detector_e {
+ NUA_NW_DETECT_NOTHING = 0,
+ NUA_NW_DETECT_ONLY_INFO,
+ NUA_NW_DETECT_TRY_FULL,
+} nua_nw_detector_t;
+
+/** Events */
+typedef enum nua_event_e {
+ /* Event used by stack internally */
+ nua_i_none = -1,
+
+ /* Indications */
+ nua_i_error, /**< Error indication */
+
+ nua_i_invite, /**< Incoming call INVITE */
+ nua_i_cancel, /**< Incoming INVITE has been cancelled */
+ nua_i_ack, /**< Final response to INVITE has been ACKed */
+ nua_i_fork, /**< Outgoing call has been forked */
+ nua_i_active, /**< A call has been activated */
+ nua_i_terminated, /**< A call has been terminated */
+ nua_i_state, /**< Call state has changed */
+
+ nua_i_outbound, /**< Status from outbound processing */
+
+ nua_i_bye, /**< Incoming BYE call hangup */
+ nua_i_options, /**< Incoming OPTIONS */
+ nua_i_refer, /**< Incoming REFER call transfer */
+ nua_i_publish, /**< Incoming PUBLISH */
+ nua_i_prack, /**< Incoming PRACK */
+ nua_i_info, /**< Incoming session INFO */
+ nua_i_update, /**< Incoming session UPDATE */
+ nua_i_message, /**< Incoming MESSAGE */
+ nua_i_chat, /**< Incoming chat MESSAGE */
+ nua_i_subscribe, /**< Incoming SUBSCRIBE */
+ nua_i_subscription, /**< Incoming subscription to be authorized */
+ nua_i_notify, /**< Incoming event NOTIFY */
+ nua_i_method, /**< Incoming, unknown method */
+
+ nua_i_media_error, /**< Offer-answer error indication */
+
+ /* Responses */
+ nua_r_set_params, /**< Answer to nua_set_params() or
+ * nua_get_hparams(). */
+ nua_r_get_params, /**< Answer to nua_get_params() or
+ * nua_get_hparams(). */
+ nua_r_shutdown, /**< Answer to nua_shutdown() */
+ nua_r_notifier, /**< Answer to nua_notifier() */
+ nua_r_terminate, /**< Answer to nua_terminate() */
+ nua_r_authorize, /**< Answer to nua_authorize() */
+
+ /* SIP responses */
+ nua_r_register, /**< Answer to outgoing REGISTER */
+ nua_r_unregister, /**< Answer to outgoing un-REGISTER */
+ nua_r_invite, /**< Answer to outgoing INVITE */
+ nua_r_cancel, /**< Answer to outgoing CANCEL */
+ nua_r_bye, /**< Answer to outgoing BYE */
+ nua_r_options, /**< Answer to outgoing OPTIONS */
+ nua_r_refer, /**< Answer to outgoing REFER */
+ nua_r_publish, /**< Answer to outgoing PUBLISH */
+ nua_r_unpublish, /**< Answer to outgoing un-PUBLISH */
+ nua_r_info, /**< Answer to outgoing INFO */
+ nua_r_prack, /**< Answer to outgoing PRACK */
+ nua_r_update, /**< Answer to outgoing UPDATE */
+ nua_r_message, /**< Answer to outgoing MESSAGE */
+ nua_r_chat, /**< Answer to outgoing chat message */
+ nua_r_subscribe, /**< Answer to outgoing SUBSCRIBE */
+ nua_r_unsubscribe, /**< Answer to outgoing un-SUBSCRIBE */
+ nua_r_notify, /**< Answer to outgoing NOTIFY */
+ nua_r_method, /**< Answer to unknown outgoing method */
+
+ nua_r_authenticate, /**< Answer to nua_authenticate() */
+
+ /* Internal events: nua hides them from application */
+ nua_r_redirect,
+ nua_r_destroy,
+ nua_r_respond,
+ nua_r_nit_respond,
+ nua_r_ack, /*#< Answer to ACK */
+
+ /* NOTE: Post 1.12 release events come here (below) to keep ABI
+ compatibility! */
+ nua_i_network_changed, /**< Local IP(v6) address has changed.
+ @NEW_1_12_2 */
+ nua_i_register, /**< Incoming REGISTER. @NEW_1_12_4. */
+} nua_event_t;
+
+typedef struct event_s {
+ nua_handle_t *e_nh;
+ int e_event;
+ short e_always;
+ short e_status;
+ char const *e_phrase;
+ msg_t *e_msg;
+ tagi_t e_tags[1];
+} nua_event_data_t;
+
+/** NUA API version */
+#define NUA_VERSION "2.0"
+/** NUA module version */
+SOFIAPUBVAR char const nua_version[];
+
+typedef void (*nua_callback_f)(nua_event_t event,
+ int status, char const *phrase,
+ nua_t *nua, nua_magic_t *magic,
+ nua_handle_t *nh, nua_hmagic_t *hmagic,
+ sip_t const *sip,
+ tagi_t tags[]);
+
+/** Create a NUA agent. */
+SOFIAPUBFUN nua_t *nua_create(su_root_t *root,
+ nua_callback_f callback,
+ nua_magic_t *magic,
+ tag_type_t tag, tag_value_t value,
+ ...);
+
+/** Shutdown NUA stack. */
+SOFIAPUBFUN void nua_shutdown(nua_t *nua);
+
+/** Destroy the NUA stack. */
+SOFIAPUBFUN void nua_destroy(nua_t *nua);
+
+/** Fetch callback context from nua. */
+SOFIAPUBFUN nua_magic_t *nua_magic(nua_t *nua);
+
+/** Set NUA parameters. */
+SOFIAPUBFUN void nua_set_params(nua_t *, tag_type_t, tag_value_t, ...);
+
+/** Get NUA parameters. */
+SOFIAPUBFUN void nua_get_params(nua_t *nua, tag_type_t, tag_value_t, ...);
+
+/** Obtain default operation handle of the NUA stack object. */
+SOFIAPUBFUN nua_handle_t *nua_default(nua_t *nua);
+
+/** Create an operation handle */
+SOFIAPUBFUN nua_handle_t *nua_handle(nua_t *nua, nua_hmagic_t *hmagic,
+ tag_type_t, tag_value_t, ...);
+
+/** Destroy a handle */
+SOFIAPUBFUN void nua_handle_destroy(nua_handle_t *h);
+
+/** Make a new reference to handle */
+SOFIAPUBFUN nua_handle_t *nua_handle_ref(nua_handle_t *);
+
+/** Destroy reference to handle */
+SOFIAPUBFUN int nua_handle_unref(nua_handle_t *);
+
+/** Bind a callback context to an operation handle. */
+SOFIAPUBFUN void nua_handle_bind(nua_handle_t *nh, nua_hmagic_t *magic);
+
+/** Fetch a callback context from an operation handle. */
+SOFIAPUBFUN nua_hmagic_t *nua_handle_magic(nua_handle_t *nh);
+
+/** Set handle parameters. */
+SOFIAPUBFUN void nua_set_hparams(nua_handle_t *, tag_type_t, tag_value_t, ...);
+
+/** Get handle parameters. */
+SOFIAPUBFUN void nua_get_hparams(nua_handle_t *, tag_type_t, tag_value_t, ...);
+
+/** Check if operation handle is used for INVITE */
+SOFIAPUBFUN int nua_handle_has_invite(nua_handle_t const *nh);
+
+/** Check if operation handle has been used with outgoing SUBSCRIBE of REFER request. */
+SOFIAPUBFUN int nua_handle_has_subscribe(nua_handle_t const *nh);
+
+/** Check if operation handle has been used with nua_register() or nua_unregister(). */
+SOFIAPUBFUN int nua_handle_has_register(nua_handle_t const *nh);
+
+/** Check if operation handle has an active call */
+SOFIAPUBFUN int nua_handle_has_active_call(nua_handle_t const *nh);
+
+/** Check if operation handle has a call on hold */
+SOFIAPUBFUN int nua_handle_has_call_on_hold(nua_handle_t const *nh);
+
+/** Check if handle has active event subscriptions (refers sent). */
+SOFIAPUBFUN int nua_handle_has_events(nua_handle_t const *nh);
+
+/** Check if operation handle has active registrations */
+SOFIAPUBFUN int nua_handle_has_registrations(nua_handle_t const *nh);
+
+/** Get the remote address (From/To header) of operation handle */
+SOFIAPUBFUN sip_to_t const *nua_handle_remote(nua_handle_t const *nh);
+
+/** Get the local address (From/To header) of operation handle */
+SOFIAPUBFUN sip_to_t const *nua_handle_local(nua_handle_t const *nh);
+
+/** Get name for NUA event. */
+SOFIAPUBFUN char const *nua_event_name(nua_event_t event);
+
+/** Get name for NUA callstate. */
+SOFIAPUBFUN char const *nua_callstate_name(enum nua_callstate state);
+
+/** Send SIP REGISTER request to the registrar. */
+SOFIAPUBFUN void nua_register(nua_handle_t *nh, tag_type_t, tag_value_t, ...);
+
+/** Unregister. */
+SOFIAPUBFUN void nua_unregister(nua_handle_t *nh, tag_type_t, tag_value_t, ...);
+
+/** Place a call using SIP INVITE method. */
+SOFIAPUBFUN void nua_invite(nua_handle_t *nh, tag_type_t, tag_value_t, ...);
+
+/** Acknowledge a succesfull response to INVITE request. */
+SOFIAPUBFUN void nua_ack(nua_handle_t *nh, tag_type_t, tag_value_t, ...);
+
+/** Acknowledge a reliable preliminary response to INVITE request. */
+SOFIAPUBFUN void nua_prack(nua_handle_t *nh, tag_type_t, tag_value_t, ...);
+
+/** Query capabilities from server */
+SOFIAPUBFUN void nua_options(nua_handle_t *nh, tag_type_t, tag_value_t, ...);
+
+/** Send PUBLISH request to publication server. */
+SOFIAPUBFUN void nua_publish(nua_handle_t *nh, tag_type_t, tag_value_t, ...);
+
+/** Send un-PUBLISH request to publication server. */
+SOFIAPUBFUN void nua_unpublish(nua_handle_t *nh, tag_type_t, tag_value_t, ...);
+
+/** Send an instant message. */
+SOFIAPUBFUN void nua_message(nua_handle_t *nh, tag_type_t, tag_value_t, ...);
+
+/** Send a chat message. */
+SOFIAPUBFUN void nua_chat(nua_handle_t *nh, tag_type_t, tag_value_t, ...);
+
+/** Send an INFO request. */
+SOFIAPUBFUN void nua_info(nua_handle_t *nh, tag_type_t, tag_value_t, ...);
+
+/** Subscribe a SIP event. */
+SOFIAPUBFUN void nua_subscribe(nua_handle_t *nh, tag_type_t, tag_value_t, ...);
+
+/** Unsubscribe an event. */
+SOFIAPUBFUN void nua_unsubscribe(nua_handle_t *, tag_type_t, tag_value_t, ...);
+
+/** Send a NOTIFY message. */
+SOFIAPUBFUN void nua_notify(nua_handle_t *, tag_type_t, tag_value_t, ...);
+
+/** Create an event server. */
+SOFIAPUBFUN void nua_notifier(nua_handle_t *, tag_type_t, tag_value_t, ...);
+
+/** Terminate an event server. */
+SOFIAPUBFUN void nua_terminate(nua_handle_t *, tag_type_t, tag_value_t, ...);
+
+/** Transfer a call. */
+SOFIAPUBFUN void nua_refer(nua_handle_t *, tag_type_t, tag_value_t, ...);
+
+/** Update a call */
+SOFIAPUBFUN void nua_update(nua_handle_t *, tag_type_t, tag_value_t, ...);
+
+/** Hangdown a call. */
+SOFIAPUBFUN void nua_bye(nua_handle_t *, tag_type_t, tag_value_t, ...);
+
+/** Cancel an INVITE operation */
+SOFIAPUBFUN void nua_cancel(nua_handle_t *, tag_type_t, tag_value_t, ...);
+
+/** Authenticate an operation. */
+SOFIAPUBFUN void nua_authenticate(nua_handle_t *, tag_type_t, tag_value_t, ...);
+
+/** Authorize a subscriber. */
+SOFIAPUBFUN void nua_authorize(nua_handle_t *, tag_type_t, tag_value_t, ...);
+
+/*# Redirect an operation. @deprecated */
+SOFIAPUBFUN void nua_redirect(nua_handle_t *, tag_type_t, tag_value_t, ...);
+
+/** Extension request method. */
+SOFIAPUBFUN void nua_method(nua_handle_t *, tag_type_t, tag_value_t, ...);
+
+/** Respond with given status. */
+SOFIAPUBFUN void nua_respond(nua_handle_t *nh,
+ int status, char const *phrase,
+ tag_type_t, tag_value_t,
+ ...);
+
+#define nua_handle_home(nh) ((su_home_t *)(nh))
+
+/** Generate an instance identifier */
+SOFIAPUBFUN char const *nua_generate_instance_identifier(su_home_t *);
+
+#ifndef NUA_SAVED_EVENT_T
+#define NUA_SAVED_EVENT_T struct nua_saved_event *
+#endif
+/** Abstract type for saved nua events. */
+typedef NUA_SAVED_EVENT_T nua_saved_event_t;
+
+/** Save last nua event */
+SOFIAPUBFUN int nua_save_event(nua_t *nua, nua_saved_event_t return_saved[1]);
+
+/** Get information from saved event */
+SOFIAPUBFUN nua_event_data_t const *nua_event_data(nua_saved_event_t const saved[1]);
+
+/** Destroy a save nua event */
+SOFIAPUBFUN void nua_destroy_event(nua_saved_event_t *saved);
+
+/** Get request message from saved nua event. */
+SOFIAPUBFUN msg_t *nua_saved_event_request(nua_saved_event_t const *saved);
+
+/** Get current request message. */
+SOFIAPUBFUN msg_t *nua_current_request(nua_t const *nua);
+
+SOFIAPUBFUN sip_replaces_t *nua_handle_make_replaces(nua_handle_t *nh,
+ su_home_t *home,
+ int early_only);
+
+SOFIAPUBFUN nua_handle_t *nua_handle_by_replaces(nua_t *nua,
+ sip_replaces_t const *rp);
+
+
+SOFIA_END_DECLS
+
+#endif
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua_tag.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua_tag.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,2199 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef NUA_TAG_H
+/** Defined when <sofia-sip/nua_tag.h> has been included. */
+#define NUA_TAG_H
+
+/**@file sofia-sip/nua_tag.h
+ * @brief Tags for Sofia-SIP User Agent Library
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ *
+ * @date Created: Mon Feb 19 18:54:26 EET 2001 ppessi
+ */
+
+#ifndef SU_TAG_H
+#include <sofia-sip/su_tag.h>
+#endif
+#ifndef SDP_TAG_H
+#include <sofia-sip/sdp_tag.h>
+#endif
+#ifndef URL_TAG_H
+#include <sofia-sip/url_tag.h>
+#endif
+#ifndef SIP_TAG_H
+#include <sofia-sip/sip_tag.h>
+#endif
+#ifndef NTA_TAG_H
+#include <sofia-sip/nta_tag.h>
+#endif
+#ifndef NEA_TAG_H
+#include <sofia-sip/nea_tag.h>
+#endif
+#ifndef SOA_TAG_H
+#include <sofia-sip/soa_tag.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** NUA agent. */
+typedef struct nua_s nua_t;
+
+/** NUA transaction handle. */
+typedef struct nua_handle_s nua_handle_t;
+
+/** List of all NUA tags. */
+SOFIAPUBVAR tag_type_t nua_tag_list[];
+
+/** Filter tag matching any nua tag. */
+#define NUTAG_ANY() nutag_any, ((tag_value_t)0)
+SOFIAPUBVAR tag_typedef_t nutag_any;
+
+/** URL address from application to NUA
+ *
+ * @par Used with
+ * any function that create SIP request or nua_handle() \n
+ * nua_create() \n
+ * nua_set_params() \n
+ * nua_get_params() \n
+ *
+ * @par Parameter type
+ * char const *
+ *
+ * @par Values
+ * #url_string_t, which is either a pointer to #url_t or NULL terminated
+ * character string representing URL \n
+ *
+ * For normal nua calls, this tag is used as request target, which is usually
+ * stored as request-URI.
+ *
+ * It is used to set stack's own address with nua_create(), nua_set_params()
+ * and nua_get_params().
+ *
+ * @sa SIPTAG_TO()
+ *
+ * Corresponding tag taking reference parameter is NUTAG_URL_REF()
+ */
+#define NUTAG_URL(x) nutag_url, urltag_url_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_url;
+
+#define NUTAG_URL_REF(x) nutag_url_ref, urltag_url_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_url_ref;
+
+/** Address as a string
+ *
+ * @deprecated Not used.
+ *
+ * @par Parameter type
+ * char const *
+ *
+ * @par Values
+ * String in form "name <url>"
+ *
+ * Corresponding tag taking reference parameter is
+ * NUTAG_ADDRESS_REF()
+ */
+#define NUTAG_ADDRESS(x) nutag_address, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_address;
+
+#define NUTAG_ADDRESS_REF(x) nutag_address_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_address_ref;
+
+/**Specify request to respond to.
+ *
+ * @par Used with
+ * nua_respond()
+ *
+ * @par Parameter type
+ * msg_t *
+ *
+ * @par Values
+ * Pointer to a request message.
+ *
+ * @NEW_1_12_4.
+ *
+ * @sa NUTAG_WITH_THIS(), NUTAG_WITH_SAVED()
+ */
+#define NUTAG_WITH(x) nutag_with, tag_ptr_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_with;
+
+/**Specify request to respond to.
+ *
+ * @par Used with
+ * nua_respond()
+ *
+ * @par Parameter type
+ * nua_t *
+ *
+ * @par Values
+ * Pointer to the nua agent instance object.
+ *
+ * @NEW_1_12_4.
+ *
+ * @sa nua_save_event(), NUTAG_WITH(), NUTAG_WITH_SAVED()
+ */
+#define NUTAG_WITH_THIS(nua) nutag_with, tag_ptr_v(nua_current_request((nua)))
+
+/**Specify request to respond to.
+ *
+ * @par Used with
+ * nua_respond()
+ *
+ * @par Parameter type
+ * msg_t *
+ *
+ * @par Values
+ * Pointer to a saved event.
+ *
+ * @NEW_1_12_4.
+ *
+ * @sa nua_save_event(), NUTAG_WITH(), NUTAG_WITH_THIS()
+ */
+#define NUTAG_WITH_SAVED(e) nutag_with, tag_ptr_v(nua_saved_event_request((e)))
+
+/**Set request retry count.
+ *
+ * Retry count determines how many times stack will automatically retry
+ * after an recoverable error response, like 302, 401 or 407.
+ *
+ * @par Used with
+ * nua_set_params(), nua_set_hparams() \n
+ * nua_get_params(), nua_get_hparams() \n
+ * nua_invite(), nua_ack()
+ *
+ * @par Parameter type
+ * unsigned
+ *
+ * @par Values
+ * @c 0 Never retry automatically \n
+ *
+ * @NEW_1_12_4.
+ *
+ * Corresponding tag taking reference parameter is NUTAG_RETRY_COUNT_REF()
+ */
+#define NUTAG_RETRY_COUNT(x) nutag_retry_count, tag_uint_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_retry_count;
+
+#define NUTAG_RETRY_COUNT_REF(x) nutag_retry_count_ref, tag_uint_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_retry_count_ref;
+
+/** Extension method name.
+ *
+ * Specify extension method name with nua_method() function.
+ *
+ * @par Used with
+ * nua_method() \n
+ *
+ * @par Parameter type
+ * char const *
+ *
+ * @par Values
+ * Extension method name (e.g., "SERVICE")
+ *
+ * Corresponding tag taking reference parameter is NUTAG_METHOD_REF()
+ *
+ * @sa nua_method(), SIP_METHOD_UNKNOWN()
+ *
+ * @since New in @VERSION_1_12_4.
+ */
+#define NUTAG_METHOD(x) nutag_method, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_method;
+
+#define NUTAG_METHOD_REF(x) nutag_method_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_method_ref;
+
+/**Set maximum number of simultaneous subscribers per single event server.
+ *
+ * Determines how many subscribers can simultaneously subscribe to a single
+ * event.
+ *
+ * @par Used with
+ * nua_set_params() \n
+ * nua_get_params()
+ *
+ * @par Parameter type
+ * unsigned
+ *
+ * @par Values
+ * @c 0 Do not allow any subscriptions \n
+ *
+ * @sa nua_notifier(), nua_authorize()
+ *
+ * Corresponding tag taking reference parameter is
+ * NUTAG_MAX_SUBSCRIPTIONS_REF()
+ */
+#define NUTAG_MAX_SUBSCRIPTIONS(x) nutag_max_subscriptions, tag_uint_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_max_subscriptions;
+
+#define NUTAG_MAX_SUBSCRIPTIONS_REF(x) \
+nutag_max_subscriptions_ref, tag_uint_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_max_subscriptions_ref;
+
+/** Intentionally undocumented. */
+#define NUTAG_UICC(x) nutag_uicc, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_uicc;
+
+#define NUTAG_UICC_REF(x) nutag_uicc_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_uicc_ref;
+
+/** Ask NUA to create dialog for this handle
+ *
+ * @par Used with nua calls that send a SIP request
+ *
+ * @par Parameter type
+ * int
+ *
+ * @par Values
+ * @c False (zero) \n
+ * @c True (nonzero)
+ *
+ * Corresponding tag taking reference parameter is NUTAG_USE_DIALOG_REF()
+ */
+#define NUTAG_USE_DIALOG(x) nutag_use_dialog, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_use_dialog;
+
+#define NUTAG_USE_DIALOG_REF(x) nutag_use_dialog_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_use_dialog_ref;
+
+
+/* Protocol engine parameters,
+ * set by nua_set_params(), get by nua_get_params() */
+
+#if 0
+
+/**Pointer to a SDP Offer-Answer session object.
+ *
+ * Pointer to the media session object.
+ *
+ * @par Used with nua_create(), nua_handle().
+ *
+ * @par Parameter type
+ * void * (actually soa_session_t *)
+ *
+ * @par Values
+ * Pointer to MSS media session.
+ *
+ * Corresponding tag taking reference parameter is NUTAG_SOA_SESSION_REF.
+ */
+#define NUTAG_SOA_SESSION(x) nutag_soa_session, tag_ptr_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_soa_session;
+
+#define NUTAG_SOA_SESSION_REF(x) \
+ nutag_soa_session_ref, tag_ptr_vr(&(x),(x))
+SOFIAPUBVAR tag_typedef_t nutag_soa_session_ref;
+
+#endif
+
+/**Name for SDP Offer-Answer session object.
+ *
+ * SDP Offer-Answer session object name.
+ *
+ * @par Used with nua_create(), nua_handle().
+ *
+ * @par Parameter type
+ * void * (actually soa_session_t *)
+ *
+ * @par Values
+ * Pointer to MSS media session.
+ *
+ * Corresponding tag taking reference parameter is NUTAG_SOA_SESSION_REF.
+ */
+#define NUTAG_SOA_NAME(x) nutag_soa_name, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_soa_name;
+
+#define NUTAG_SOA_NAME_REF(x) \
+ nutag_soa_name_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_soa_name_ref;
+
+/**Establish early media session using 100rel, 183 responses and PRACK.
+ *
+ * @par Used with
+ * nua_set_params() \n
+ * nua_get_params() \n
+ * nua_set_hparams() \n
+ * nua_get_hparams() \n
+ * nua_invite() \n
+ * nua_respond() \n
+ *
+ * @par Parameter type
+ * int (boolean)
+ *
+ * @par Values
+ * @c 0 False \n
+ * @c !=0 True
+ *
+ * @sa NUTAG_EARLY_ANWER()
+ *
+ * Corresponding tag taking reference parameter is NUTAG_EARLY_MEDIA_REF()
+ */
+#define NUTAG_EARLY_MEDIA(x) nutag_early_media, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_early_media;
+
+#define NUTAG_EARLY_MEDIA_REF(x) nutag_early_media_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_early_media_ref;
+
+/**Respond only 183 with 100rel.
+ *
+ * If this parameter is set, stack uses 100rel only with 183: otherwise, all
+ * 1XX responses (except <i>100 Trying</i>) uses 100rel.
+ *
+ * @par Used with
+ * nua_set_params() \n
+ * nua_get_params() \n
+ * nua_set_hparams() \n
+ * nua_get_hparams() \n
+ * nua_invite() \n
+ * nua_respond()
+ *
+ * @par Parameter type
+ * int (boolean)
+ *
+ * @par Values
+ * @c 0 False \n
+ * @c !=0 True
+ *
+ * Corresponding tag taking reference parameter is NUTAG_ONLY183_100REL_REF()
+*/
+#define NUTAG_ONLY183_100REL(x) nutag_only183_100rel, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_only183_100rel;
+
+#define NUTAG_ONLY183_100REL_REF(x) nutag_only183_100rel_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_only183_100rel_ref;
+
+/**Establish early media session by including SDP answer in 1XX response.
+ *
+ * @par Used with
+ * nua_respond(), nua_set_params(), nua_set_hparams()
+ *
+ * @par Parameter type
+ * int (boolean)
+ *
+ * @par Values
+ * @c 0 False \n
+ * @c !=0 True
+ *
+ * Corresponding tag taking reference parameter is NUTAG_EARLY_ANSWER_REF().
+ *
+ * @note Requires that @soa is enabled with NUTAG_MEDIA_ENABLE(1).
+ *
+ * @sa NUTAG_EARLY_MEDIA(), NUTAG_AUTOALERT(), NUTAG_MEDIA_ENABLE()
+ *
+ * @since New in @VERSION_1_12_2.
+ */
+#define NUTAG_EARLY_ANSWER(x) nutag_early_answer, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_early_answer;
+
+#define NUTAG_EARLY_ANSWER_REF(x) nutag_early_answer_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_early_answer_ref;
+
+/**Include an extra copy of SDP answer in the response.
+ *
+ * When NUTAG_INCLUDE_EXTRA_SDP(1) is included in nua_respond() tags, stack
+ * will include in the response a copy of the SDP offer/answer that was last
+ * sent to the client. This tag should be used only when you know that the
+ * remote end requires the extra SDP, for example, some versions of Cisco
+ * SIPGateway need a copy of answer in 200 OK even when they indicate
+ * support for 100rel.
+ *
+ * @par Used with
+ * nua_respond()
+ *
+ * @par Parameter type
+ * int (boolean)
+ *
+ * @par Values
+ * @c 0 False \n
+ * @c !=0 True
+ *
+ * Corresponding tag taking reference parameter is
+ * NUTAG_INCLUDE_EXTRA_SDP_REF().
+ *
+ * @note Requires that @soa is enabled with NUTAG_MEDIA_ENABLE(1).
+ *
+ * @sa NUTAG_EARLY_ANSWER(), NUTAG_EARLY_MEDIA(), NUTAG_AUTOALERT(),
+ * NUTAG_MEDIA_ENABLE(), @RFC3264, @RFC3264
+ *
+ * @since New in @VERSION_1_12_4.
+ */
+#define NUTAG_INCLUDE_EXTRA_SDP(x) nutag_include_extra_sdp, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_include_extra_sdp;
+
+#define NUTAG_INCLUDE_EXTRA_SDP_REF(x) \
+ nutag_include_extra_sdp_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_include_extra_sdp_ref;
+
+/** Timer for outstanding INVITE in seconds.
+ *
+ * INVITE will be canceled if no answer is received before timer expires.
+ *
+ * @par Used with
+ * nua_invite() \n
+ * nua_set_params() \n
+ * nua_get_params()
+ *
+ * @par Parameter type
+ * int (enum nua_af)
+ *
+ * @par Values
+ * @c 0 no timer \n
+ * @c >0 timer in seconds
+ *
+ * Corresponding tag taking reference parameter is NUTAG_INVITE_TIMER_REF()
+ */
+#define NUTAG_INVITE_TIMER(x) nutag_invite_timer, tag_uint_v((x))
+SOFIAPUBVAR tag_typedef_t nutag_invite_timer;
+
+#define NUTAG_INVITE_TIMER_REF(x) nutag_invite_timer_ref, tag_uint_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_invite_timer_ref;
+
+/**Default session timer in seconds.
+ *
+ * Set default session timer in seconds when using session timer extension.
+ * The value given here is the proposed session expiration time in seconds.
+ * Note that the session timer extension is ponly used
+ *
+ * @par Sending INVITE and UPDATE Requests
+ *
+ * If NUTAG_SESSION_TIMER() is used with non-zero value, the value is
+ * used in the @SessionExpires header included in the INVITE or UPDATE
+ * requests. The intermediate proxies or the ultimate destination can lower
+ * the interval in @SessionExpires header. If the value is too low, they can
+ * reject the request with the status code <i>422 Session Timer Too
+ * Small</i>. When Re-INVITE will be sent in given intervals. In that case,
+ * @b nua retries the request automatically.
+ *
+ * @par Returning Response to the INVITE and UPDATE Requests
+ *
+ * The NUTAG_SESSION_TIMER() value is also used when sending the final
+ * response to the INVITE or UPDATE requests. If the NUTAG_SESSION_TIMER()
+ * value is 0 or the value in the @SessionExpires header of the requeast is
+ * lower than the value in NUTAG_SESSION_TIMER(), the value from the
+ * incoming @SessionExpires header is used. However, if the value in
+ * @SessionExpires is lower than the minimal acceptable session expiration
+ * interval specified with the tag NUTAG_MIN_SE() the request is
+ * automatically rejected with <i>422 Session Timer Too Small</i>.
+ *
+ * @par When to Use NUTAG_SESSION_TIMER()?
+ *
+ * The session time extension is enabled ("timer" feature tag is included in
+ * @Supported header) but not activated by default (no @SessionExpires
+ * header is included in the requests or responses by default). Using
+ * non-zero value with NUTAG_SESSION_TIMER() activates it. When the
+ * extension is activated, @nua refreshes the call state by sending periodic
+ * re-INVITE or UPDATE requests unless the remote end indicated that it will
+ * take care of refreshes.
+ *
+ * The session timer extension is mainly useful for proxies or back-to-back
+ * user agents that keep call state. The call state is "soft" meaning that
+ * if no call-related SIP messages are processed for certain time the state
+ * will be destroyed. An ordinary user-agent can also make use of session
+ * timer if it cannot get any activity feedback from RTP or other media.
+ *
+ * @par Used with
+ * nua_invite(), nua_update(), nua_respond() \n
+ * nua_set_params() or nua_set_hparams() \n
+ * nua_get_params() or nua_get_hparams()
+ *
+ * See nua_set_hparams() for a complete list of the the nua operations that
+ * accept this tag.
+ *
+ * @par Parameter type
+ * unsigned int
+ *
+ * @par Values
+ * @c 0 disable \n
+ * @c >0 interval in seconds
+ *
+ * Corresponding tag taking reference parameter is NUTAG_SESSION_TIMER_REF()
+ *
+ * @sa NUTAG_SUPPORTED(), NUTAG_MIN_SE(), NUTAG_SESSION_REFRESHER(),
+ * nua_invite(), #nua_r_invite, #nua_i_invite, nua_update(), #nua_r_update,
+ * #nua_i_update,
+ * NUTAG_UPDATE_REFRESH(), @RFC4028, @SessionExpires, @MinSE
+ */
+#define NUTAG_SESSION_TIMER(x) nutag_session_timer, tag_uint_v((x))
+SOFIAPUBVAR tag_typedef_t nutag_session_timer;
+
+#define NUTAG_SESSION_TIMER_REF(x) nutag_session_timer_ref, tag_uint_vr((&(x)))
+SOFIAPUBVAR tag_typedef_t nutag_session_timer_ref;
+
+/** Minimum acceptable refresh interval for session.
+ *
+ * Specifies the value of @MinSE header in seconds. The @b Min-SE header is
+ * used to specify minimum acceptable refresh interval for session timer
+ * extension.
+ *
+ * @par Used with
+ * nua_handle(), nua_invite(), nua_update(), nua_respond() \n
+ * nua_set_params() or nua_set_hparams() \n
+ * nua_get_params() or nua_get_hparams()
+ *
+ * See nua_set_hparams() for a complete list of the nua operations that
+ * accept this tag.
+ *
+ * @par Parameter type
+ * unsigned int
+ *
+ * @par Values
+ * interval in seconds.
+ *
+ * Corresponding tag taking reference parameter is NUTAG_MIN_SE_REF()
+ *
+ * @sa NUTAG_SESSION_TIMER(), NUTAG_SESSION_REFRESHER(),
+ * NUTAG_UPDATE_REFRESH(), @RFC4028, @MinSE, @SessionExpires
+ */
+#define NUTAG_MIN_SE(x) nutag_min_se, tag_uint_v((x))
+SOFIAPUBVAR tag_typedef_t nutag_min_se;
+
+#define NUTAG_MIN_SE_REF(x) nutag_min_se_ref, tag_uint_vr((&(x)))
+SOFIAPUBVAR tag_typedef_t nutag_min_se_ref;
+
+enum nua_session_refresher {
+ nua_no_refresher, /**< Disable session timer. */
+ nua_local_refresher, /**< Session refresh by local end. */
+ nua_remote_refresher, /**< Session refresh by remote end. */
+ nua_any_refresher /**< No preference (default). */
+};
+
+/**Specify the preferred refresher.
+ *
+ * Specify for session timer extension which party is the preferred refresher.
+ *
+ * @par Used with
+ * nua_handle(), nua_invite(), nua_update(), nua_respond() \n
+ * nua_set_params() or nua_set_hparams() \n
+ * nua_get_params() or nua_get_hparams()
+ *
+ * See nua_set_hparams() for a complete list of all the nua operations that
+ * accept this tag.
+ *
+ * @par Parameter type
+ * enum { #nua_no_refresher, #nua_local_refresher, #nua_remote_refresher,
+ * #nua_any_refresher }
+ *
+ * @par Values
+ * @c nua_no_refresher (session timers are disabled) \n
+ * @c nua_local_refresher \n
+ * @c nua_remote_refresher \n
+ * @c nua_any_refresher (default) \n
+ *
+ * Corresponding tag taking reference parameter is
+ * NUTAG_SESSION_REFRESHER_REF()
+ *
+ * @sa NUTAG_SESSION_TIMER(), NUTAG_MIN_SE_REF(),
+ * NUTAG_UPDATE_REFRESH(), @RFC4028, @SessionExpires, @MinSE
+ */
+#define NUTAG_SESSION_REFRESHER(x) nutag_session_refresher, tag_int_v((x))
+SOFIAPUBVAR tag_typedef_t nutag_session_refresher;
+
+#define NUTAG_SESSION_REFRESHER_REF(x) nutag_session_refresher_ref, tag_int_vr((&(x)))
+SOFIAPUBVAR tag_typedef_t nutag_session_refresher_ref;
+
+/** Use UPDATE as refresh method.
+ *
+ * If this parameter is true and the remote endpoint has included UPDATE in
+ * Allow header, the nua stack uses UPDATE instead of INVITE to refresh the
+ * session when using the session timer extension.
+ *
+ * Note that the session timer headers @SessionExpires and @MinSE are always
+ * included in the UPDATE request and responses regardless of the value of
+ * this tag.
+ *
+ * @par Used with
+ * nua_handle(), nua_invite(), nua_update(), nua_respond() \n
+ * nua_set_params() or nua_set_hparams() \n
+ * nua_get_params() or nua_get_hparams()
+ *
+ * See nua_set_hparams() for a complete list of all the nua operations that
+ * accept this tag.
+ *
+ * @par Parameter type
+ * boolean
+ *
+ * @par Values
+ * @c 1 Use UPDATE \n
+ * @c 0 Use INVITE
+ *
+ * Corresponding tag taking reference parameter is NUTAG_UPDATE_REFRESH_REF()
+ *
+ * @sa #nua_r_update, NUTAG_SESSION_TIMER(), NUTAG_MIN_SE_REF(),
+ * NUTAG_UPDATE_REFRESH(), @RFC4028, @SessionExpires, @MinSE
+ */
+#define NUTAG_UPDATE_REFRESH(x) nutag_update_refresh, tag_bool_v((x))
+SOFIAPUBVAR tag_typedef_t nutag_update_refresh;
+
+#define NUTAG_UPDATE_REFRESH_REF(x) nutag_update_refresh_ref, tag_bool_vr((&(x)))
+SOFIAPUBVAR tag_typedef_t nutag_update_refresh_ref;
+
+/** Send alerting (180 Ringing) automatically
+ *
+ * @par Used with
+ * nua_set_params() \n
+ * nua_get_params()
+ *
+ * @par Parameter type
+ * int
+ *
+ * @par Values
+ * @c 0 No automatic sending of "180 Ringing" \n
+ * @c !=0 "180 Ringing" sent automatically
+ *
+ * Corresponding tag taking reference parameter is NUTAG_AUTOALERT_REF()
+ */
+#define NUTAG_AUTOALERT(x) nutag_autoalert, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_autoalert;
+
+#define NUTAG_AUTOALERT_REF(x) nutag_autoalert_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_autoalert_ref;
+
+/** ACK automatically
+ *
+ * If this parameter is true, ACK is sent automatically after receiving 2XX
+ * series response to INVITE. Note that ACK is always sent automatically by
+ * lower layers of the stack after receiving an error response 3XX, 4XX, 5XX
+ * or 6XX.
+ *
+ * @par Used with
+ * nua_set_params(), nua_set_hparams(), \n
+ * nua_get_params(), nua_get_hparams(), \n
+ * nua_invite(), nua_ack(), nua_respond(), nua_update() \n
+ * nua_respond()
+ *
+ * @par Parameter type
+ * int
+ *
+ * @par Values
+ * @c 0 No automatic sending of ACK \n
+ * @c !=0 ACK sent automatically
+ *
+ * Default value is NUTAG_AUTOACK(1).
+ *
+ * Corresponding tag taking reference parameter is NUTAG_AUTOACK_REF()
+ */
+#define NUTAG_AUTOACK(x) nutag_autoack, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_autoack;
+
+#define NUTAG_AUTOACK_REF(x) nutag_autoack_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_autoack_ref;
+
+/** Answer (with 200 Ok) automatically to incoming call.
+ *
+ * @par Used with
+ * nua_set_params(), nua_set_hparams() \n
+ * nua_get_params(), nua_get_hparams() \n
+ * nua_invite() \n
+ * nua_respond()
+ *
+ * @par Parameter type
+ * int (boolean)
+ *
+ * @par Values
+ * @c 0 No automatic sending of "200 Ok" \n
+ * @c !=0 "200 Ok" sent automatically
+ *
+ * Corresponding tag taking reference parameter is NUTAG_AUTOANSWER_REF()
+ *
+ * @note Requires that @soa is enabled with NUTAG_MEDIA_ENABLE(1).
+ *
+ * @par Auto-Answer to Re-INVITE requests
+ * By default, NUA tries to auto answer the re-INVITEs used to refresh the
+ * session when the media is enabled. Set NUTAG_AUTOANSWER(0) on the call
+ * handle (e.g., include the tag with nua_invite(), nua_respond()) in order
+ * to disable the auto answer on re-INVITEs.
+ *
+ * @bug If the re-INVITE modifies the session (e.g., SDP contains offer that
+ * adds video stream to the session), NUA auto-answers it if
+ * NUTAG_AUTOANSWER(0) has not been set on the handle. It accepts or rejects
+ * media based on the existing user SDP (set with SOATAG_USER_SDP(), for
+ * example). It should auto-answer only session refresh request and let
+ * application decide how to handle requests to modify the session.
+ *
+ * @sa NUTAG_MEDIA_ENABLE(), NUTAG_AUTOALERT(), NUTAG_AUTOACK().
+ */
+#define NUTAG_AUTOANSWER(x) nutag_autoanswer, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_autoanswer;
+
+#define NUTAG_AUTOANSWER_REF(x) nutag_autoanswer_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_autoanswer_ref;
+
+/** Enable incoming INVITE
+ *
+ * @par Used with
+ * nua_set_params() \n
+ * nua_get_params()
+ *
+ * @par Parameter type
+ * int
+ *
+ * @par Values
+ * @c 0 Incoming INVITE not enabled. NUA answers 403 Forbidden \n
+ * @c !=0 Incoming INVITE enabled
+ *
+ * Corresponding tag taking reference parameter is NUTAG_ENABLEINVITE_REF()
+ */
+#define NUTAG_ENABLEINVITE(x) nutag_enableinvite, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_enableinvite;
+
+#define NUTAG_ENABLEINVITE_REF(x) nutag_enableinvite_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_enableinvite_ref;
+
+/** Enable incoming MESSAGE
+ *
+ * @par Used with
+ * nua_set_params() \n
+ * nua_get_params()
+ *
+ * @par Parameter type
+ * int
+ *
+ * @par Values
+ * @c 0 Incoming MESSAGE not enabled. NUA answers 403 Forbidden \n
+ * @c !=0 Incoming MESSAGE enabled
+ *
+ * Corresponding tag taking reference parameter is NUTAG_ENABLEMESSAGE_REF()
+ */
+#define NUTAG_ENABLEMESSAGE(x) nutag_enablemessage, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_enablemessage;
+
+#define NUTAG_ENABLEMESSAGE_REF(x) nutag_enablemessage_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_enablemessage_ref;
+
+/** Enable incoming MESSAGE with To tag.
+ *
+ * Set this parameter if you want to chat with Windows Messenger.
+ *
+ * @par Used with
+ * nua_set_params() \n
+ * nua_get_params()
+ *
+ * @par Parameter type
+ * int
+ *
+ * @par Values
+ * @c 0 False \n
+ * @c !=0 True
+ *
+ * Corresponding tag taking reference parameter is NUTAG_ENABLEMESSENGER_REF()
+ */
+#define NUTAG_ENABLEMESSENGER(x) nutag_enablemessenger, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_enablemessenger;
+
+#define NUTAG_ENABLEMESSENGER_REF(x) \
+ nutag_enablemessenger_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_enablemessenger_ref;
+
+/* Start NRC Boston */
+
+/** Enable S/MIME
+ *
+ * @par Used with
+ * nua_create() \n
+ * nua_set_params() \n
+ * nua_get_params()
+ *
+ * @par Parameter type
+ * boolean
+ *
+ * @par Values
+ * @c 0 S/MIME is Disabled \n
+ * @c !=0 S/MIME is Enabled
+ *
+ * Corresponding tag taking reference parameter is NUTAG_SMIME_ENABLE_REF()
+ */
+#define NUTAG_SMIME_ENABLE(x) nutag_smime_enable, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_smime_enable;
+
+#define NUTAG_SMIME_ENABLE_REF(x) nutag_smime_enable_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_smime_enable_ref;
+
+/** S/MIME Options
+ *
+ * This tag specifies the type of S/MIME security services requested
+ * by the user.
+ *
+ * @par Used with
+ * nua_set_params() \n
+ * nua_get_params() \n
+ * nua_message()
+ *
+ * @par Parameter type
+ * int
+ *
+ * @par Values
+ * @c -1 (SM_ID_NULL) No security service needed \n
+ * @c 0 (SM_ID_CLEAR_SIGN) Clear signing \n
+ * @c 1 (SM_ID_SIGN) S/MIME signing \n
+ * @c 2 (SM_ID_ENCRYPT) S/MIME encryption
+ *
+ * Corresponding tag taking reference parameter is NUTAG_SMIME_OPT_REF()
+ */
+#define NUTAG_SMIME_OPT(x) nutag_smime_opt, tag_int_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_smime_opt;
+
+#define NUTAG_SMIME_OPT_REF(x) nutag_smime_opt_ref, tag_int_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_smime_opt_ref;
+
+/* End NRC Boston */
+
+/** S/MIME protection mode
+ *
+ * This tag specifies the protection mode of the SIP message by
+ * S/MIME as requested by the user
+ *
+ * @par Used with
+ * nua_set_params() \n
+ * nua_get_params()
+ *
+ * @par Parameter type
+ * unsigned int
+ *
+ * @par Values
+ * @c -1 (SM_MODE_NULL) Unspecified \n
+ * @c 0 (SM_MODE_PAYLOAD_ONLY) SIP payload only \n
+ * @c 1 (SM_MODE_TUNNEL) SIP tunneling mode \n
+ * @c 2 (SM_MODE_SIPFRAG) SIPfrag protection
+ *
+ * Corresponding tag taking reference parameter is NUTAG_SMIME_PROTECTION_MODE_REF()
+ */
+#define NUTAG_SMIME_PROTECTION_MODE(x) nutag_smime_protection_mode, tag_uint_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_smime_protection_mode;
+
+#define NUTAG_SMIME_PROTECTION_MODE_REF(x) \
+ nutag_smime_protection_mode_ref, tag_uint_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_smime_protection_mode_ref;
+
+/** S/MIME digest algorithm
+ *
+ * This tag specifies the message digest algorithm to be used in S/MIME.
+ *
+ * @par Used with
+ * To be implemented
+ *
+ * @par Parameter type
+ * char const *
+ *
+ * @par Values
+ *
+ * Corresponding tag taking reference parameter is NUTAG_SMIME_MESSAGE_DIGEST_REF()
+ */
+#define NUTAG_SMIME_MESSAGE_DIGEST(x) nutag_smime_message_digest, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_smime_message_digest;
+
+#define NUTAG_SMIME_MESSAGE_DIGEST_REF(x) \
+ nutag_smime_message_digest_ref, tag_str_vr((&x))
+SOFIAPUBVAR tag_typedef_t nutag_smime_message_digest_ref;
+
+/** S/MIME signature algorithm
+ *
+ * This tag specifies the signature algorithm to be used in S/MIME.
+ *
+ * @par Used with
+ * To be implemented.
+ *
+ * @par Parameter type
+ * char const *
+ *
+ * @par Values
+ *
+ * Corresponding tag taking reference parameter is NUTAG_SMIME_SIGNATURE_REF()
+ */
+#define NUTAG_SMIME_SIGNATURE(x) nutag_smime_signature, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_smime_signature;
+
+#define NUTAG_SMIME_SIGNATURE_REF(x) \
+ nutag_smime_signature_ref, tag_str_vr((&x))
+SOFIAPUBVAR tag_typedef_t nutag_smime_signature_ref;
+
+/** S/MIME key encryption algorithm
+ *
+ * This tag specifies the key encryption algorithm to be used by S/MIME.
+ *
+ * @par Used with
+ * To be implemented
+ *
+ * @par Parameter type
+ * char const *
+ *
+ * @par Values
+ *
+ * Corresponding tag taking reference parameter is NUTAG_SMIME_KEY_ENCRYPTION_REF()
+ */
+#define NUTAG_SMIME_KEY_ENCRYPTION(x) nutag_smime_key_encryption, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_smime_key_encryption;
+
+#define NUTAG_SMIME_KEY_ENCRYPTION_REF(x) \
+ nutag_smime_key_encryption_ref, tag_str_vr((&x))
+SOFIAPUBVAR tag_typedef_t nutag_smime_key_encryption_ref;
+
+/** S/MIME message encryption algorithm
+ *
+ * This tag specifies the message encryption algorithm to be used in S/MIME.
+ *
+ * @par Used with
+ * To be implemented.
+ *
+ * @par Parameter type
+ * char const *
+ *
+ * @par Values
+ *
+ * Corresponding tag taking reference parameter is NUTAG_SMIME_MESSAGE_ENCRYPTION_REF()
+ */
+#define NUTAG_SMIME_MESSAGE_ENCRYPTION(x) nutag_smime_message_encryption, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_smime_message_encryption;
+
+#define NUTAG_SMIME_MESSAGE_ENCRYPTION_REF(x) \
+ nutag_smime_message_encryption_ref, tag_str_vr((&x))
+SOFIAPUBVAR tag_typedef_t nutag_smime_message_encryption_ref;
+
+/** x.500 certificate directory
+ *
+ * @par Used with
+ * nua_create()
+ *
+ * @par Parameter type
+ * char const *
+ *
+ * @par Values
+ * NULL terminated pathname of directory containing agent.pem and cafile.pem files.
+ *
+ * Corresponding tag taking reference parameter is NUTAG_CERTIFICATE_DIR_REF()
+ */
+#define NUTAG_CERTIFICATE_DIR(x) nutag_certificate_dir, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_certificate_dir;
+
+#define NUTAG_CERTIFICATE_DIR_REF(x) \
+ nutag_certificate_dir_ref, tag_str_vr((&x))
+SOFIAPUBVAR tag_typedef_t nutag_certificate_dir_ref;
+
+/** Certificate phrase
+ *
+ * @par Used with
+ * Currently not processed by NUA
+ *
+ * @par Parameter type
+ * char const *
+ *
+ * @par Values
+ *
+ * Corresponding tag taking reference parameter is NUTAG_CERTIFICATE_PHRASE_REF()
+ */
+#define NUTAG_CERTIFICATE_PHRASE(x) nutag_certificate_phrase, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_certificate_phrase;
+
+#define NUTAG_CERTIFICATE_PHRASE_REF(x) \
+ nutag_certificate_phrase_ref, tag_str_vr((&x))
+SOFIAPUBVAR tag_typedef_t nutag_certificate_phrase_ref;
+
+/** Local SIPS url.
+ *
+ * The application can specify an alternative local address for
+ * NUA user agent engine. Usually the alternative address is a
+ * secure SIP URI (SIPS) used with TLS transport.
+ *
+ * @par Used with
+ * nua_create()
+ *
+ * @par Parameter type
+ * char const *
+ *
+ * @par Values
+ *
+ * Corresponding tag taking reference parameter is NUTAG_SIPS_URL_REF()
+ */
+#define NUTAG_SIPS_URL(x) nutag_sips_url, urltag_url_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_sips_url;
+
+#define NUTAG_SIPS_URL_REF(x) nutag_sips_url_ref, urltag_url_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_sips_url_ref;
+
+/** Outbound proxy URL
+ *
+ * Same tag as NTATAG_DEFAULT_PROXY()
+ *
+ * @par Used with
+ * nua_set_params() \n
+ * nua_get_params() \n
+ * nua_create()
+ *
+ * @par Parameter type
+ * url_string_t const * (either char const * or url_t *)
+ *
+ * @par Values
+ *
+ * Corresponding tag taking reference parameter is NUTAG_PROXY_REF()
+ */
+#define NUTAG_PROXY(x) NTATAG_DEFAULT_PROXY(x)
+#define NUTAG_PROXY_REF(x) NTATAG_DEFAULT_PROXY_REF(x)
+#define nutag_proxy ntatag_default_proxy
+
+/** Registrar URL
+ *
+ * @par Used with
+ * nua_register() \n
+ * nua_set_params() \n
+ * nua_get_params()
+ *
+ * @par Parameter type
+ * url_string_t const * (either char const * or url_t *)
+ *
+ * @par Values
+ *
+ * Corresponding tag taking reference parameter is NUTAG_REGISTRAR_REF()
+ */
+#define NUTAG_REGISTRAR(x) nutag_registrar, urltag_url_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_registrar;
+
+#define NUTAG_REGISTRAR_REF(x) nutag_registrar_ref, urltag_url_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_registrar_ref;
+
+/** Outbound option string.
+ *
+ * The outbound option string can specify how the NAT traversal is handled.
+ * The option tokens are as follows:
+ * - "gruuize": try to generate a GRUU
+ * - "outbound": use SIP outbound extension (off by default)
+ * - "validate": validate registration behind a NAT by sending OPTIONS to self
+ * - "natify": try to traverse NAT
+ * - "use-rport": use rport to traverse NAT
+ * - "options-keepalive": send periodic OPTIONS requests as keepalive messages
+ *
+ * An option token with "no-" or "not-" prefix turns the option off. For
+ * example, if you want to try to traverse NATs but not to use OPTIONS
+ * keepalive, use NUTAG_OUTBOUND("natify no-options-keepalive").
+ *
+ * @note
+ * Options string is used so that no new tags need to be added when the
+ * outbound functionality changes.
+ *
+ * @par Used with
+ * nua_register() \n
+ * nua_set_params() \n
+ * nua_get_params()
+ * nua_set_hparams() \n
+ * nua_get_hparams()
+ *
+ * @par Parameter type
+ * char const *
+ *
+ * @par Values
+ *
+ * Corresponding tag taking reference parameter is NUTAG_OUTBOUND_REF()
+ */
+#define NUTAG_OUTBOUND(x) nutag_outbound, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_outbound;
+
+#define NUTAG_OUTBOUND_REF(x) nutag_outbound_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_outbound_ref;
+
+#if notyet
+
+/** Outbound proxy set 1.
+ *
+ * @par Used with
+ * nua_register() \n
+ * nua_set_params() \n
+ * nua_get_params()
+ * nua_set_hparams() \n
+ * nua_get_hparams()
+ *
+ * @par Parameter type
+ * char const *
+ *
+ * @par Values
+ *
+ * Corresponding tag taking reference parameter is NUTAG_OUTBOUND_SET1_REF()
+ */
+#define NUTAG_OUTBOUND_SET1(x) nutag_outbound_set1, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_outbound_set1;
+
+#define NUTAG_OUTBOUND_SET1_REF(x) nutag_outbound_set1_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_outbound_set1_ref;
+
+/** Outbound proxy set 2.
+ *
+ * @par Used with
+ * nua_register() \n
+ * nua_set_params() \n
+ * nua_get_params()
+ * nua_set_hparams() \n
+ * nua_get_hparams()
+ *
+ * @par Parameter type
+ * char const *
+ *
+ * @par Values
+ *
+ * Corresponding tag taking reference parameter is NUTAG_OUTBOUND_SET2_REF()
+ */
+#define NUTAG_OUTBOUND_SET2(x) nutag_outbound_set2, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_outbound_set2;
+
+#define NUTAG_OUTBOUND_SET2_REF(x) nutag_outbound_set2_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_outbound_set2_ref;
+
+/** Outbound proxy set 3.
+ *
+ * @par Used with
+ * nua_register() \n
+ * nua_set_params() \n
+ * nua_get_params()
+ * nua_set_hparams() \n
+ * nua_get_hparams()
+ *
+ * @par Parameter type
+ * char const *
+ *
+ * @par Values
+ *
+ * Corresponding tag taking reference parameter is NUTAG_OUTBOUND_SET3_REF()
+ */
+#define NUTAG_OUTBOUND_SET3(x) nutag_outbound_set3, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_outbound_set3;
+
+#define NUTAG_OUTBOUND_SET3_REF(x) nutag_outbound_set3_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_outbound_set3_ref;
+
+/** Outbound proxy set 4.
+ *
+ * @par Used with
+ * nua_register() \n
+ * nua_set_params() \n
+ * nua_get_params()
+ * nua_set_hparams() \n
+ * nua_get_hparams()
+ *
+ * @par Parameter type
+ * char const *
+ *
+ * @par Values
+ *
+ * Corresponding tag taking reference parameter is NUTAG_OUTBOUND_SET4_REF()
+ */
+#define NUTAG_OUTBOUND_SET4(x) nutag_outbound_set4, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_outbound_set4;
+
+#define NUTAG_OUTBOUND_SET4_REF(x) nutag_outbound_set4_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_outbound_set4_ref;
+
+#endif /* ...notyet */
+
+/** Pointer to SIP parser structure
+ *
+ * @par Used with
+ * nua_create()
+ *
+ * @par Parameter type
+ * msg_mclass_t *
+ *
+ * @par Values
+ * Pointer to an extended SIP parser.
+ *
+ * @sa msg_mclass_clone(), msg_mclass_insert_header()
+ *
+ * Corresponding tag taking reference parameter is NUTAG_SIP_PARSER_REF().
+ */
+#define NUTAG_SIP_PARSER(x) NTATAG_MCLASS(x)
+#define NUTAG_SIP_PARSER_REF(x) NTATAG_MCLASS_REF(x)
+
+/** Authentication data ("scheme" "realm" "user" "password")
+ *
+ * @par Used with
+ * nua_authenticate()
+ *
+ * @par Parameter type
+ * char const *
+ *
+ * @par Values
+ * NULL terminated string of format: \n
+ * basic digest scheme:"realm":user:password \n
+ * @b NOTE the double quotes around realm!
+ * For example: \n
+ * \code Digest:"nokia proxy":xyz:secret \endcode
+ *
+ * Corresponding tag taking reference parameter is NUTAG_AUTH_REF()
+ */
+#define NUTAG_AUTH(x) nutag_auth, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_auth;
+
+#define NUTAG_AUTH_REF(x) nutag_auth_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_auth_ref;
+
+/** Keepalive interval in milliseconds.
+ *
+ * @par Used with
+ * nua_register() \n
+ * nua_set_params() \n
+ * nua_get_params()
+ * nua_set_hparams() \n
+ * nua_get_hparams()
+ *
+ * @par Parameter type
+ * unsigned int
+ *
+ * @par Values
+ * - 0 - disable keepalives
+ * - 120000 - default value (120000 milliseconds, 120 seconds)
+ *
+ * Corresponding tag taking reference parameter is
+ * NUTAG_KEEPALIVE_REF()
+ */
+#define NUTAG_KEEPALIVE(x) nutag_keepalive, tag_uint_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_keepalive;
+
+#define NUTAG_KEEPALIVE_REF(x) nutag_keepalive_ref, tag_uint_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_keepalive_ref;
+
+/** Transport-level keepalive interval for streams.
+ *
+ * @par Used with
+ * nua_register() \n
+ * nua_set_params() \n
+ * nua_get_params()
+ * nua_set_hparams() \n
+ * nua_get_hparams()
+ *
+ * @par Parameter type
+ * unsigned int
+ *
+ * @par Values
+ *
+ * Transport-level keepalive interval for streams in milliseconds. If this
+ * parameter specified, it takes presedence over value given in
+ * NUTAG_KEEPALIVE().
+ *
+ * Corresponding tag taking reference parameter is
+ * NUTAG_KEEPALIVE_STREAM_REF()
+ *
+ * @todo Actually pass NUTAG_KEEPALIVE_STREAM() to transport layer.
+ */
+#define NUTAG_KEEPALIVE_STREAM(x) nutag_keepalive_stream, tag_uint_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_keepalive_stream;
+
+#define NUTAG_KEEPALIVE_STREAM_REF(x) \
+nutag_keepalive_stream_ref, tag_uint_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_keepalive_stream_ref;
+
+/** Lifetime of authentication data in seconds.
+ *
+ * @par Used with
+ * Currently not processed by NUA
+ *
+ * @par Parameter type
+ * unsigned int
+ *
+ * @par Values
+ * @c 0 Use authentication data only for this handle \n
+ * @c !=0 Lifetime in seconds
+ *
+ * Corresponding tag taking reference parameter is NUTAG_AUTHTIME_REF()
+ */
+#define NUTAG_AUTHTIME(x) nutag_authtime, tag_uint_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_authtime;
+
+#define NUTAG_AUTHTIME_REF(x) nutag_authtime_ref, tag_uint_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_authtime_ref;
+
+/**Display name for @Contact.
+ *
+ * Specify display name for the Contact header URI generated for
+ * registration request and dialog-creating requests/responses.
+ *
+ * Note that display name is not included the request-URI when proxy
+ * forwards the request towards user-agent.
+ *
+ * @par Used with
+ * nua_register(), nua_set_hparams(), nua_set_params().
+ *
+ * @par Parameter type
+ * string (char *)
+ *
+ * @par Values
+ * Valid display name.
+ *
+ * @sa NUTAG_M_USERNAME(), NUTAG_M_PARAMS(), NUTAG_M_FEATURES(),
+ * NUTAG_CALLEE_CAPS().
+ *
+ * Corresponding tag taking reference parameter is NUTAG_M_DISPLAY_REF().
+ *
+ * @since New in @VERSION_1_12_2.
+ */
+#define NUTAG_M_DISPLAY(x) nutag_m_display, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_m_display;
+
+#define NUTAG_M_DISPLAY_REF(x) nutag_m_display_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_m_display_ref;
+
+/**Username prefix for @Contact.
+ *
+ * Specify username part for the Contact header URI generated for
+ * registration request and dialog-creating requests/responses.
+ *
+ * Using username, application can make multiple registrations using
+ * multiple identities, or it can distinguish between different logical
+ * destinations.
+ *
+ * @par Used with
+ * nua_register(), nua_set_hparams(), nua_set_params().
+ *
+ * @par Parameter type
+ * string (char *)
+ *
+ * @par Values
+ * Valid SIP username.
+ *
+ * @sa NUTAG_M_DISPLAY(), NUTAG_M_PARAMS(), NUTAG_M_FEATURES(),
+ * NUTAG_CALLEE_CAPS().
+ *
+ * Corresponding tag taking reference parameter is NUTAG_M_USERNAME_REF().
+ *
+ * @since New in @VERSION_1_12_2.
+ */
+#define NUTAG_M_USERNAME(x) nutag_m_username, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_m_username;
+
+#define NUTAG_M_USERNAME_REF(x) nutag_m_username_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_m_username_ref;
+
+/**URL parameters for @Contact.
+ *
+ * Specify URL parameters for the Contact header URI generated for
+ * registration request and dialog-creating requests/responses.
+ *
+ * Please note that some proxies may remove even the non-transport
+ * parameters from the request-URI when they forward the request towards
+ * user-agent.
+ *
+ * @par Used with
+ * nua_register(), nua_set_hparams(), nua_set_params().
+ *
+ * @par Parameter type
+ * string (char *)
+ *
+ * @par Values
+ * Semicolon-separated URL parameters.
+ *
+ * @sa NUTAG_M_DISPLAY(), NUTAG_M_USERNAME(), NUTAG_M_FEATURES(),
+ * NUTAG_CALLEE_CAPS().
+ *
+ * Corresponding tag taking reference parameter is NUTAG_M_PARAMS_REF().
+ *
+ * @since New in @VERSION_1_12_2.
+ */
+#define NUTAG_M_PARAMS(x) nutag_m_params, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_m_params;
+
+#define NUTAG_M_PARAMS_REF(x) nutag_m_params_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_m_params_ref;
+
+/**Header parameters for registration @Contact.
+ *
+ * Specify header parameters for the @Contact header generated for
+ * registration request and dialog-creating requests/responses. Such header
+ * parameters include "q", indicating preference for the @Contact URI, and
+ * "expires", indicating the desired expiration time for the registration.
+ *
+ * Additional header parameters are typically media feature tags, specified in
+ * @RFC3840. If NUTAG_CALLEE_CAPS(1) is specified, additional @Contact header
+ * parameters are generated based on SDP capabilities and SIP @Allow header.
+ *
+ * When using the "outbound" extension option, the stack will also add
+ * "+sip.instance" and "reg-id" header parameters to the @Contact.
+ *
+ * @par Used with
+ * nua_register(), nua_set_hparams(), nua_set_params()
+ *
+ * @par Parameter type
+ * string (char *)
+ *
+ * @par Values
+ * Semicolon-separated SIP header parameters.
+ *
+ * @sa NUTAG_M_DISPLAY(), NUTAG_M_USERNAME(), NUTAG_M_PARAMS(),
+ * NUTAG_CALLEE_CAPS(), NUTAG_IDENTITY().
+ *
+ * Corresponding tag taking reference parameter is NUTAG_M_FEATURES_REF().
+ *
+ * @since New in @VERSION_1_12_2.
+ */
+#define NUTAG_M_FEATURES(x) nutag_m_features, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_m_features;
+
+#define NUTAG_M_FEATURES_REF(x) nutag_m_features_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_m_features_ref;
+
+/**NUA event.
+ *
+ * @deprecated
+ *
+ * @par Parameter type
+ * enum nua_event_e
+ *
+ * @par Values
+ *
+ * Corresponding tag taking reference parameter is NUTAG_EVENT_REF()
+ */
+#define NUTAG_EVENT(x) nutag_event, tag_int_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_event;
+
+#define NUTAG_EVENT_REF(x) nutag_event_ref, tag_int_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_event_ref;
+
+/** Response status code
+ *
+ * @deprecated
+ *
+ * @par Parameter type
+ * unsigned int
+ *
+ * @par Values
+ * 100 - preliminary response, request is being processed by next hop \n
+ * 1XX - preliminary response, request is being processed by UAS \n
+ * 2XX - successful final response \n
+ * 3XX - redirection error response \n
+ * 4XX - client error response \n
+ * 5XX - server error response \n
+ * 6XX - global error response \n
+ *
+ * Corresponding tag taking reference parameter is NUTAG_STATUS_REF()
+ */
+#define NUTAG_STATUS(x) nutag_status, tag_uint_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_status;
+
+#define NUTAG_STATUS_REF(x) nutag_status_ref, tag_uint_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_status_ref;
+
+/** Response phrase
+ *
+ * @deprecated
+ *
+ * @par Parameter type
+ * char const *
+ *
+ * @par Values.
+ *
+ * Corresponding tag taking reference parameter is NUTAG_PHRASE_REF()
+ */
+#define NUTAG_PHRASE(x) nutag_phrase, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_phrase;
+
+#define NUTAG_PHRASE_REF(x) nutag_phrase_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_phrase_ref;
+
+/** NUA Handle
+ *
+ * @deprecated
+ *
+ * @par Parameter type
+ * nua_handle_t *
+ *
+ * @par Values
+ *
+ * Corresponding tag taking reference parameter is NUTAG_HANDLE_REF()
+ */
+#define NUTAG_HANDLE(x) nutag_handle, nutag_handle_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_handle;
+
+#define NUTAG_HANDLE_REF(x) nutag_handle_ref, nutag_handle_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_handle_ref;
+
+/** Registration handle (used with requests and nua_respond()) (NOT YET IMPLEMENTED)
+ *
+ * When a new request is made or new call is responded, a new identity can
+ * be selected with NUTAG_IDENTITY(). The identity comprises of @b From
+ * header, initial route set, local contact header and media tags associated
+ * with it, soa handle and so on. User can make multiple registrations using
+ * multiple identities.
+ *
+ * @par Used with
+ * nua_invite()
+ *
+ * @par Parameter type
+ * nua_handle_t *
+ *
+ * @par Values
+ *
+ * Corresponding tag taking reference parameter is NUTAG_IDENTITY_REF()
+*/
+#define NUTAG_IDENTITY(x) nutag_identity, nutag_handle_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_identity;
+
+#define NUTAG_IDENTITY_REF(x) nutag_identity_ref, nutag_handle_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_identity_ref;
+
+/**Intance identifier.
+ *
+ * @par Used with
+ * nua_create(), nua_set_params(), nua_get_params(),
+ * nua_register()
+ *
+ * @par Parameter type
+ * char const *
+ *
+ * @par Value
+ * urn:uuid string, a globally unique identifier for this user-agent
+ * instance.
+ *
+ * Corresponding tag taking reference parameter is NUTAG_INSTANCE_REF()
+ */
+#define NUTAG_INSTANCE(x) nutag_instance, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_instance;
+
+#define NUTAG_INSTANCE_REF(x) nutag_instance_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_instance_ref;
+
+/** Refer reply handle (used with refer)
+ *
+ * When making a call in response to a REFER request [RFC3515] with
+ * nua_invite(), the application can ask NUA to automatically generate
+ * notifications about the call progress to the referrer. In order to
+ * do that the application should pass to the stack the handle, which
+ * it used to receive the REFER request. It should also pass the event
+ * header object along with the handle using NUTAG_REFER_EVENT().
+ *
+ * @par Used with
+ * nua_invite()
+ *
+ * @par Parameter type
+ * nua_handle_t *
+ *
+ * @par Values
+ *
+ * Corresponding tag taking reference parameter is NUTAG_NOTIFY_REFER_REF()
+*/
+#define NUTAG_NOTIFY_REFER(x) nutag_notify_refer, nutag_handle_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_notify_refer;
+
+#define NUTAG_NOTIFY_REFER_REF(x) nutag_notify_refer_ref, nutag_handle_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_notify_refer_ref;
+
+/** Event used with automatic refer notifications.
+ *
+ * When creating a call in response to a REFER request [RFC3515]
+ * the application can ask NUA to automatically generate notifications
+ * about the call progress to the referrer. The #nua_i_refer event will
+ * contain a suitable SIP event header for the notifications in the
+ * NUTAG_REFER_EVENT() tag. The application should store the SIP event
+ * header and when it makes the referred call, it should pass it back
+ * to the stack again using the NUTAG_REFER_EVENT() tag.
+ *
+ * @par Used with
+ *
+ * @par Parameter type
+ * sip_event_t *
+ *
+ * @par Values
+ *
+ * Corresponding tag taking reference parameter is NUTAG_REFER_EVENT_REF()
+ */
+#define NUTAG_REFER_EVENT(x) nutag_refer_event, siptag_event_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_refer_event;
+
+#define NUTAG_REFER_EVENT_REF(x) nutag_refer_event_ref, siptag_event_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_refer_event_ref;
+
+/** Invite pauses referrer's handle.
+ *
+ * When creating a call in response to a REFER [RFC3515] request,
+ * the application can ask that the original call will be muted
+ * when the new call is connected by specifying NUTAG_REFER_PAUSE()
+ * along with NUTAG_NOTIFY_REFER() as a parameter to nua_invite() call.
+ *
+ * @par Used with
+ * nua_invite()
+ *
+ * @par Parameter type
+ * int
+ *
+ * @par Values
+ * @c 0 False \n
+ * @c !=0 True
+ *
+ * Corresponding tag taking reference parameter is NUTAG_REFER_PAUSE_REF()
+ *
+ * @deprecated Not implemented.
+ */
+#define NUTAG_REFER_PAUSE(x) nutag_refer_pause, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_refer_pause;
+
+#define NUTAG_REFER_PAUSE_REF(x) nutag_refer_pause_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_refer_pause_ref;
+
+/**User-Agent string.
+ *
+ * Indicate the User-Agent header used by the stack. The value set with this
+ * tag is concatenated with the value indicating the stack name and version,
+ * e.g., "sofia-sip/1.12.1" unless the stack name "sofia-sip" followed by
+ * slash is already included in the string. The concatenated value is
+ * returned in SIPTAG_USER_AGENT_STR() and NUTAG_USER_AGENT() when
+ * nua_get_params() is called.
+ *
+ * If you want to set the complete string, use SIPTAG_USER_AGENT_STR() or
+ * SIPTAG_USER_AGENT().
+ *
+ * @par Used with
+ * nua_set_params(), nua_set_hparams() \n
+ * nua_get_params(), nua_get_hparams(), #nua_r_get_params \n
+ * any handle-specific nua call
+ *
+ * @par Parameter type
+ * char const *
+ *
+ * @par Values
+ * See @RFC3261 \n
+ * If NULL, stack uses default string which of format "sofia-sip/1.12".
+ *
+ * Corresponding tag taking reference parameter is NUTAG_USER_AGENT_REF()
+ */
+#define NUTAG_USER_AGENT(x) nutag_user_agent, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_user_agent;
+
+#define NUTAG_USER_AGENT_REF(x) nutag_user_agent_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_user_agent_ref;
+
+/** Allow a method (or methods).
+ *
+ * This tag is used to add a new method to the already existing set of
+ * allowed methods. If you want to ignore the existing set of allowed
+ * methods, use SIPTAG_ALLOW_STR() or SIPTAG_ALLOW().
+ *
+ * The set of allowed methods is added to the @Allow header in the response
+ * or request messages. For incoming request, an error response <i>405
+ * Method Not Allowed</i> is automatically returned if the incoming method
+ * is not included in the set.
+ *
+ * @par Used with
+ * nua_set_params() \n
+ * nua_set_hparams() \n
+ * any handle-specific nua call
+ *
+ * @par Parameter type
+ * char const *
+ *
+ * @par Values
+ * Valid method name, or comma-separated list of them.
+ *
+ * Corresponding tag taking reference parameter is NUTAG_ALLOW_REF()
+ */
+#define NUTAG_ALLOW(x) nutag_allow, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_allow;
+
+#define NUTAG_ALLOW_REF(x) nutag_allow_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_allow_ref;
+
+
+/** Indicate that a method (or methods) are handled by application.
+ *
+ * This tag is used to add a new method to the already existing set of
+ * methods handled by application, or clear the set. If you want to
+ * determine the set explicitly, include NUTAG_APPL_METHOD() twice,
+ * first with NULL and then with your supported set.
+ *
+ * The default set of application methods now include INVITE, REGISTER,
+ * PUBLISH and SUBSCRIBE.
+ *
+ * If the request method is in the set of methods handled by application,
+ * the nua stack does not automatically respond to the incoming request nor
+ * it will automatically send such a request. Note if the application adds
+ * the PRACK and UPDATE requests to the set of application methods it must
+ * also take care for sending the PRACK and UPDATE requests during the call
+ * setup when necessary.
+ *
+ * @par Used with
+ * nua_set_params() \n
+ * nua_set_hparams() \n
+ * any handle-specific nua call
+ *
+ * @par Parameter type
+ * char const *
+ *
+ * @par Values
+ * Valid method name, or comma-separated list of them.
+ *
+ * Corresponding tag taking reference parameter is NUTAG_APPL_METHOD_REF()
+ *
+ * @since Working since @VERSION_1_12_5.
+ */
+#define NUTAG_APPL_METHOD(x) nutag_appl_method, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_appl_method;
+
+#define NUTAG_APPL_METHOD_REF(x) nutag_appl_method_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_appl_method_ref;
+
+
+/** Support a feature.
+ *
+ * This tag is used to add a new feature to the existing set of supported
+ * SIP features. If you want to ignore the existing set of supported
+ * features, use SIPTAG_SUPPORTED_STR() or SIPTAG_SUPPORTED().
+ *
+ * The set of supported features is added to the @Supported header in the
+ * response or request messages. For incoming requests, an error response
+ * <i>420 Bad Extension </i> is automatically returned if the request
+ * requires features that are not included in the supported feature set.
+ *
+ * @par Used with
+ * nua_set_params() \n
+ * nua_set_hparams() \n
+ * any handle-specific nua call
+ *
+ * @par Parameter type
+ * char const *
+ *
+ * @par Values
+ * Feature name, or comma-separated list of them.
+ *
+ * Corresponding tag taking reference parameter is NUTAG_SUPPORTED_REF()
+ *
+ * @since New in @VERSION_1_12_2.
+ */
+#define NUTAG_SUPPORTED(x) nutag_supported, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_supported;
+
+#define NUTAG_SUPPORTED_REF(x) nutag_supported_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_supported_ref;
+
+/** Allow an event or events.
+ *
+ * This tag is used to add a new event to the already existing set of
+ * allowed events. If you want to ignore the existing set of allowed events,
+ * set the allowed event set with SIPTAG_ALLOW_EVENTS_STR() or
+ * SIPTAG_ALLOW_EVENTS().
+ *
+ * The set of allowed methods is added to the @AllowEvents header in the
+ * response to the SUBSCRIBE or PUBLISH requests. For incoming SUBSCRIBE or
+ * PUBLISH request, an error response <i>489 Bad Event</i> is automatically
+ * returned if the incoming method is not included in the set.
+ *
+ * @par Used with
+ * nua_set_params() \n
+ * nua_set_hparams() \n
+ * any handle-specific nua call
+ *
+ * @par Parameter type
+ * char const *
+ *
+ * @par Values
+ * Valid event name, or comma-separated list of them.
+ *
+ * @sa @AllowEvents, @RFC3265, @RFC3903, #nua_i_subscribe, #nua_i_publish,
+ * nua_subscribe(), nua_publish(), SIPTAG_ALLOW_EVENTS(),
+ * SIPTAG_ALLOW_EVENTS_STR()
+ *
+ * @NEW_1_12_4.
+ *
+ * Corresponding tag taking reference parameter is NUTAG_ALLOW_EVENTS_REF()
+ */
+#define NUTAG_ALLOW_EVENTS(x) nutag_allow_events, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_allow_events;
+
+#define NUTAG_ALLOW_EVENTS_REF(x) nutag_allow_events_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_allow_events_ref;
+
+/** Call state
+ *
+ * @par Used with
+ * #nua_i_state
+ *
+ * @par Parameter type
+ * int
+ *
+ * @par Values
+ * - #nua_callstate_init - Initial state
+ * - #nua_callstate_authenticating - 401/407 received
+ * - #nua_callstate_calling - INVITE sent
+ * - #nua_callstate_proceeding - 18X received
+ * - #nua_callstate_completing - 2XX received
+ * - #nua_callstate_received - INVITE received (and 100 Trying sent)
+ * - #nua_callstate_early - 18X sent
+ * - #nua_callstate_completed - 2XX sent
+ * - #nua_callstate_ready - 2XX and ACK received/sent
+ * - #nua_callstate_terminating - BYE sent
+ * - #nua_callstate_terminated - BYE complete
+ *
+ * Corresponding tag taking reference parameter is NUTAG_CALLSTATE_REF()
+ */
+#define NUTAG_CALLSTATE(x) nutag_callstate, tag_int_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_callstate;
+
+#define NUTAG_CALLSTATE_REF(x) nutag_callstate_ref, tag_int_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_callstate_ref;
+
+enum nua_callstate {
+ nua_callstate_init, /**< Initial state */
+ nua_callstate_authenticating, /**< 401/407 received */
+ nua_callstate_calling, /**< INVITE sent */
+ nua_callstate_proceeding, /**< 18X received */
+ nua_callstate_completing, /**< 2XX received */
+ nua_callstate_received, /**< INVITE received */
+ nua_callstate_early, /**< 18X sent (w/SDP) */
+ nua_callstate_completed, /**< 2XX sent */
+ nua_callstate_ready, /**< 2XX received, ACK sent, or vice versa */
+ nua_callstate_terminating, /**< BYE sent */
+ nua_callstate_terminated /**< BYE complete */
+};
+
+/** Get name for NUA call state */
+SOFIAPUBFUN char const *nua_callstate_name(enum nua_callstate state);
+
+/** Subscription state
+ *
+ * @par Used with
+ * #nua_r_subscribe \n
+ * #nua_i_notify
+ *
+ * @par Parameter type
+ * int
+ *
+ * @par Values
+ * @c nua_substate_embryonic (0) \n
+ * @c nua_substate_pending (1) \n
+ * @c nua_substate_active (2) \n
+ * @c nua_substate_terminated (3) \n
+ *
+ * see
+ * <a href="http://www.ietf.org/rfc/rfc3265.txt">RFC 3265</a>
+ *
+ * Corresponding tag taking reference parameter is NUTAG_SUBSTATE_REF()
+*/
+#define NUTAG_SUBSTATE(x) nutag_substate, tag_int_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_substate;
+
+#define NUTAG_SUBSTATE_REF(x) nutag_substate_ref, tag_int_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_substate_ref;
+
+/** Parameter type of NUTAG_SUBSTATE() */
+enum nua_substate {
+ /** Extended state, considered as active. */
+ nua_substate_extended = nea_extended,
+ /** Embryonic subscription: SUBSCRIBE sent */
+ nua_substate_embryonic = nea_embryonic,
+ nua_substate_pending = nea_pending, /**< Pending subscription */
+ nua_substate_active = nea_active, /**< Active subscription */
+ nua_substate_terminated = nea_terminated /**< Terminated subscription */
+};
+
+/**Default lifetime for implicit subscriptions created by REFER.
+ *
+ * Default expiration time in seconds for implicit subscriptions created by
+ * REFER.
+ *
+ * @par Used with
+ * nua_set_params() \n
+ * nua_get_params() \n
+ * nua_set_hparams() \n
+ * nua_get_hparams() \n
+ *
+ * @par Parameter type
+ * unsigned int
+ *
+ * @par Values
+ * @c 0 disable \n
+ * @c >0 interval in seconds
+ *
+ * Corresponding tag taking reference parameter is NUTAG_REFER_EXPIRES()
+ */
+#define NUTAG_REFER_EXPIRES(x) nutag_refer_expires, tag_uint_v((x))
+SOFIAPUBVAR tag_typedef_t nutag_refer_expires;
+
+#define NUTAG_REFER_EXPIRES_REF(x) nutag_refer_expires_ref, tag_uint_vr((&(x)))
+SOFIAPUBVAR tag_typedef_t nutag_refer_expires_ref;
+
+/**Always use id parameter with refer event.
+ *
+ * When an incoming REFER creates an implicit subscription, the event header
+ * in the NOTIFY request may have an id parameter. The id parameter can be
+ * either always included (default behavior), or the parameter can be used
+ * only for the second and subsequent REFER requests received in a given
+ * dialog.
+ *
+ * Note that once the subscription is created, the event header should not
+ * be modified. Therefore this tag has no effect on already established
+ * subscriptions, and its use makes sense largely on nua_set_params() only.
+ *
+ * @par Used with
+ * nua_set_params() (nua_set_hparams(), nua_invite(), nua_respond(),
+ * nua_update()).
+ *
+ * @par Parameter type
+ * int (boolean)
+ *
+ * @par Values
+ * 0 (false, do not use id with subscription created with first REFER request) \n
+ * 1 (true, use id with all subscriptions created with REFER request) \n
+ *
+ * Corresponding tag taking reference parameter is NUTAG_REFER_WITH_ID_REF().
+ *
+ * @since New in @VERSION_1_12_2.
+ */
+#define NUTAG_REFER_WITH_ID(x) nutag_refer_with_id, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_refer_with_id;
+
+#define NUTAG_REFER_WITH_ID_REF(x) nutag_refer_with_id_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_refer_with_id_ref;
+
+/**Add media tags from our offer to Accept-Contact headers.
+ *
+ * Automatically generate @AcceptContact headers for caller
+ * preference processing according to our the media capabilities in @a soa.
+ *
+ * @par Used with
+ * nua_invite() \n
+ * nua_update() \n
+ * nua_set_params() \n
+ * nua_get_params()
+ *
+ * @par Parameter type
+ * int
+ *
+ * @par Values
+ * @c 0 Do not add media tags \n
+ * @c !=0 Add media tags
+ *
+ * Corresponding tag taking reference parameter is NUTAG_MEDIA_FEATURES_REF()
+ *
+ * @sa nua_invite(), SOATAG_USER_SDP(), SIPTAG_ACCEPT_CONTACT(),
+ * NUTAG_CALLEE_CAPS()
+ */
+#define NUTAG_MEDIA_FEATURES(x) nutag_media_features, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_media_features;
+
+#define NUTAG_MEDIA_FEATURES_REF(x) \
+ nutag_media_features_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_media_features_ref;
+
+/** Add methods and media tags to Contact headers. */
+#define NUTAG_CALLEE_CAPS(x) nutag_callee_caps, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_callee_caps;
+
+#define NUTAG_CALLEE_CAPS_REF(x) \
+ nutag_callee_caps_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_callee_caps_ref;
+
+/** If true, add "path" to Supported in REGISTER.
+ *
+ * @sa <a href="http://www.ietf.org/rfc/rfc3327.txt">RFC 3327</a>,
+ * <i>"SIP Extension Header Field for Registering Non-Adjacent Contacts"</i>,
+ * D. Willis, B. Hoeneisen,
+ * December 2002.
+ */
+#define NUTAG_PATH_ENABLE(x) nutag_path_enable, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_path_enable;
+
+#define NUTAG_PATH_ENABLE_REF(x) nutag_path_enable_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_path_enable_ref;
+
+/** Use route from Service-Route header in response to REGISTER.
+ *
+ * @sa <a href="http://www.ietf.org/rfc/rfc3327.txt">RFC 3327</a>,
+ * <i>"SIP Extension Header Field for Registering Non-Adjacent Contacts"</i>,
+ * D. Willis, B. Hoeneisen,
+ * December 2002.
+ */
+#define NUTAG_SERVICE_ROUTE_ENABLE(x) nutag_service_route_enable, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_service_route_enable;
+
+#define NUTAG_SERVICE_ROUTE_ENABLE_REF(x) \
+ nutag_service_route_enable_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_service_route_enable_ref;
+
+/** Enable built-in media session handling
+ *
+ * The built-in media session object @soa takes care of most details
+ * of offer-answer negotiation.
+ *
+ * @par Used with
+ * nua_create()
+ *
+ * @par Parameter type
+ * int
+ *
+ * @par Values
+ * @c 0 False \n
+ * @c !=0 True
+ *
+ * Corresponding tag taking reference parameter is NUTAG_MEDIA_ENABLE_REF()
+*/
+#define NUTAG_MEDIA_ENABLE(x) nutag_media_enable, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_media_enable;
+
+#define NUTAG_MEDIA_ENABLE_REF(x) \
+ nutag_media_enable_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_media_enable_ref;
+
+/** Indicate that SDP offer has been received.
+ *
+ * @par Used with
+ * #nua_i_state
+ *
+ * @par Parameter type
+ * boolean
+ *
+ * Corresponding tag taking reference parameter is NUTAG_OFFER_RECV_REF()
+ */
+#define NUTAG_OFFER_RECV(x) nutag_offer_recv, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_offer_recv;
+
+#define NUTAG_OFFER_RECV_REF(x) nutag_offer_recv_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_offer_recv_ref;
+
+/** Indicate that SDP answer has been received.
+ *
+ * @par Used with
+ * #nua_i_state
+ *
+ * @par Parameter type
+ * boolean
+ *
+ * Corresponding tag taking reference parameter is NUTAG_ANSWER_RECV_REF()
+ */
+#define NUTAG_ANSWER_RECV(x) nutag_answer_recv, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_answer_recv;
+
+#define NUTAG_ANSWER_RECV_REF(x) nutag_answer_recv_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_answer_recv_ref;
+
+/** Indicate that SDP offer has been sent.
+ *
+ * @par Used with
+ * #nua_i_state
+ *
+ * @par Parameter type
+ * boolean
+ *
+ * Corresponding tag taking reference parameter is NUTAG_OFFER_SENT_REF()
+ */
+#define NUTAG_OFFER_SENT(x) nutag_offer_sent, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_offer_sent;
+
+#define NUTAG_OFFER_SENT_REF(x) nutag_offer_sent_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_offer_sent_ref;
+
+/** Indicate that SDP answer has been sent.
+ *
+ * @par Used with
+ * #nua_i_state
+ *
+ * @par Parameter type
+ * int (boolean: nonzero is true, zero is false)
+ *
+ * Corresponding tag taking reference parameter is NUTAG_ANSWER_SENT_REF()
+ */
+#define NUTAG_ANSWER_SENT(x) nutag_answer_sent, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_answer_sent;
+
+#define NUTAG_ANSWER_SENT_REF(x) nutag_answer_sent_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_answer_sent_ref;
+
+/**Enable detection of local IP address updates.
+ *
+ * @par Used with
+ * nua_create() \n
+ * nua_set_params() \n
+ * nua_get_params()
+ *
+ * @par Parameter type
+ * int (enum nua_nw_detector_e aka #nua_nw_detector_t)
+ *
+ * @sa #nua_i_network_changed, #nua_nw_detector_t
+ *
+ * Corresponding tag taking reference parameter is
+ * NUTAG_DETECT_NETWORK_UPDATES_REF().
+ *
+ * @since New in @VERSION_1_12_2.
+ */
+#define NUTAG_DETECT_NETWORK_UPDATES(x) \
+ nutag_detect_network_updates, tag_int_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_detect_network_updates;
+
+#define NUTAG_DETECT_NETWORK_UPDATES_REF(x) \
+ nutag_detect_network_updates_ref, tag_int_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_detect_network_updates_ref;
+
+/* Pass nua handle as tagged argument */
+#if SU_HAVE_INLINE
+su_inline tag_value_t nutag_handle_v(nua_handle_t *v) { return (tag_value_t)v; }
+su_inline tag_value_t nutag_handle_vr(nua_handle_t **vp) {return(tag_value_t)vp;}
+#else
+#define nutag_handle_v(v) (tag_value_t)(v)
+#define nutag_handle_vr(v) (tag_value_t)(v)
+#endif
+
+/* Tags for compatibility */
+
+#define NUTAG_USE_LEG(x) NUTAG_USE_DIALOG(x)
+#define NUTAG_USE_LEG_REF(x) NUTAG_USE_DIALOG_REF(x)
+
+#define NUTAG_AF(x) SOATAG_AF((x))
+#define NUTAG_AF_REF(x) SOATAG_AF_REF((x))
+
+enum nua_af {
+ nutag_af_any = SOA_AF_ANY,
+ nutag_af_ip4_only = SOA_AF_IP4_ONLY,
+ nutag_af_ip6_only = SOA_AF_IP6_ONLY,
+ nutag_af_ip4_ip6 = SOA_AF_IP4_IP6,
+ nutag_af_ip6_ip4 = SOA_AF_IP6_IP4
+};
+
+#define NUTAG_AF_ANY nutag_af_any
+#define NUTAG_AF_IP4_ONLY nutag_af_ip4_only
+#define NUTAG_AF_IP6_ONLY nutag_af_ip6_only
+#define NUTAG_AF_IP4_IP6 nutag_af_ip4_ip6
+#define NUTAG_AF_IP6_IP4 nutag_af_ip6_ip4
+
+#define NUTAG_MEDIA_ADDRESS(x) SOATAG_ADDRESS((x))
+#define NUTAG_MEDIA_ADDRESS_REF(x) SOATAG_ADDRESS_REF((x))
+
+#define NUTAG_HOLD(x) SOATAG_HOLD((x) ? "*" : NULL)
+
+#define NUTAG_ACTIVE_AUDIO(x) SOATAG_ACTIVE_AUDIO((x))
+#define NUTAG_ACTIVE_AUDIO_REF(x) SOATAG_ACTIVE_AUDIO_REF((x))
+#define NUTAG_ACTIVE_VIDEO(x) SOATAG_ACTIVE_VIDEO((x))
+#define NUTAG_ACTIVE_VIDEO_REF(x) SOATAG_ACTIVE_VIDEO_REF((x))
+#define NUTAG_ACTIVE_IMAGE(x) SOATAG_ACTIVE_IMAGE((x))
+#define NUTAG_ACTIVE_IMAGE_REF(x) SOATAG_ACTIVE_IMAGE_REF((x))
+#define NUTAG_ACTIVE_CHAT(x) SOATAG_ACTIVE_CHAT((x))
+#define NUTAG_ACTIVE_CHAT_REF(x) SOATAG_ACTIVE_CHAT_REF((x))
+
+enum {
+ nua_active_rejected = SOA_ACTIVE_REJECTED,
+ nua_active_disabled = SOA_ACTIVE_DISABLED,
+ nua_active_inactive = SOA_ACTIVE_INACTIVE,
+ nua_active_sendonly = SOA_ACTIVE_SENDONLY,
+ nua_active_recvonly = SOA_ACTIVE_RECVONLY,
+ nua_active_sendrecv = SOA_ACTIVE_SENDRECV
+};
+
+#define NUTAG_SRTP_ENABLE(x) SOATAG_SRTP_ENABLE((x))
+#define NUTAG_SRTP_ENABLE_REF(x) SOATAG_SRTP_ENABLE_REF((x))
+#define NUTAG_SRTP_CONFIDENTIALITY(x) SOATAG_SRTP_CONFIDENTIALITY((x))
+#define NUTAG_SRTP_CONFIDENTIALITY_REF(x) SOATAG_SRTP_CONFIDENTIALITY_REF((x))
+#define NUTAG_SRTP_INTEGRITY_PROTECTION(x) SOATAG_SRTP_INTEGRITY((x))
+#define NUTAG_SRTP_INTEGRITY_PROTECTION_REF(x) SOATAG_SRTP_INTEGRITY_REF((x))
+
+SOFIA_END_DECLS
+
+#endif
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_100rel.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_100rel.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1594 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_nua_100rel.c
+ * @brief NUA-10 tests: early session, PRACK, UPDATE, precondition.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ *
+ * @date Created: Wed Aug 17 12:12:12 EEST 2005 ppessi
+ */
+
+#include "config.h"
+
+#include "test_nua.h"
+#include <sofia-sip/auth_common.h>
+#include <sofia-sip/su_tag_class.h>
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+#define __func__ "test_call_hold"
+#endif
+
+/* ======================================================================== */
+
+/*
+ X accept_pracked ep
+ |-------INVITE------>|
+ | (sdp) |
+ | |
+ |<----100 Trying-----|
+ | |
+ |<-------180---------|
+ | (sdp) |
+ |-------PRACK------->|
+ |<-------200---------|
+ | |
+ |<------200 OK-------|
+ |--------ACK-------->|
+ | |
+*/
+int accept_pracked(CONDITION_PARAMS)
+{
+ if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+ return 0;
+
+ save_event_in_list(ctx, event, ep, call);
+
+ switch (event) {
+ case nua_i_prack:
+ if (200 <= status && status < 300) {
+ RESPOND(ep, call, nh, SIP_200_OK, TAG_END());
+ ep->next_condition = until_ready;
+ }
+ default:
+ break;
+ }
+
+ switch (callstate(tags)) {
+ case nua_callstate_received:
+ RESPOND(ep, call, nh, SIP_180_RINGING,
+ TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)),
+ TAG_END());
+ return 0;
+ case nua_callstate_terminated:
+ if (call)
+ nua_handle_destroy(call->nh), call->nh = NULL;
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+int accept_pracked2(CONDITION_PARAMS)
+{
+ if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+ return 0;
+
+ save_event_in_list(ctx, event, ep, call);
+
+ switch (event) {
+ case nua_i_prack:
+ if (200 <= status && status < 300) {
+ RESPOND(ep, call, nh, SIP_200_OK,
+ NUTAG_INCLUDE_EXTRA_SDP(1),
+ TAG_END());
+ ep->next_condition = until_ready;
+ }
+ default:
+ break;
+ }
+
+ switch (callstate(tags)) {
+ case nua_callstate_received:
+ RESPOND(ep, call, nh, SIP_180_RINGING,
+ TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)),
+ TAG_END());
+ return 0;
+ case nua_callstate_terminated:
+ if (call)
+ nua_handle_destroy(call->nh), call->nh = NULL;
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+
+int test_180rel(struct context *ctx)
+{
+ BEGIN();
+
+ struct endpoint *a = &ctx->a, *b = &ctx->b;
+ struct call *a_call = a->call, *b_call = b->call;
+ struct event *e;
+ sip_t *sip;
+
+ if (print_headings)
+ printf("TEST NUA-10.1.1: Call with 100rel and 180\n");
+
+/* Test for 100rel:
+
+ A B
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ | |
+ |<-------180---------|
+ |-------PRACK------->|
+ |<-------200---------|
+ | |
+ |<------200 OK-------|
+ |--------ACK-------->|
+ | |
+ |<-------BYE---------|
+ |-------200 OK-------|
+ | |
+
+*/
+
+ a_call->sdp = "m=audio 5008 RTP/AVP 8";
+ b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
+
+ nua_set_params(ctx->a.nua,
+ NUTAG_EARLY_MEDIA(1),
+ TAG_END());
+ run_a_until(ctx, nua_r_set_params, until_final_response);
+
+ nua_set_params(ctx->b.nua,
+ NUTAG_EARLY_MEDIA(1),
+ TAG_END());
+ run_b_until(ctx, nua_r_set_params, until_final_response);
+
+ TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+ INVITE(a, a_call, a_call->nh,
+ TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+ SOATAG_USER_SDP_STR(a_call->sdp),
+ TAG_END());
+
+ run_ab_until(ctx, -1, until_ready, -1, accept_pracked2);
+
+ /* Client transitions:
+ INIT -(C1)-> CALLING: nua_invite(), nua_i_state
+ CALLING -(C2)-> PROCEEDING: nua_r_invite, nua_i_state, nua_r_prack
+ PROCEEDING -(C3+C4)-> READY: nua_r_invite, nua_i_state
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+ TEST_1(is_offer_sent(e->data->e_tags));
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 180);
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
+ TEST_1(is_answer_recv(e->data->e_tags));
+ TEST_1(!is_offer_sent(e->data->e_tags));
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_prack);
+ TEST(e->data->e_status, 200);
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 200);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(sip->sip_content_type);
+ TEST_S(sip->sip_content_type->c_type, "application/sdp");
+ TEST_1(sip->sip_payload);
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+ TEST_1(!is_offer_answer_done(e->data->e_tags));
+ TEST_1(!e->next);
+ free_events_in_list(ctx, a->events);
+
+ /*
+ Server transitions:
+ INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
+ RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state
+ EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state
+ COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+ TEST(e->data->e_status, 100);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+ TEST_1(is_offer_recv(e->data->e_tags));
+
+ /* Responded with 180 Ringing */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+ TEST_1(is_answer_sent(e->data->e_tags));
+
+ /* 180 is PRACKed */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_prack);
+ /* Does not have effect on call state */
+
+ /* Respond with 200 OK */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+ TEST_1(!is_offer_answer_done(e->data->e_tags));
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+ TEST_1(!is_offer_answer_done(e->data->e_tags));
+ TEST_1(!e->next);
+ free_events_in_list(ctx, b->events);
+
+ if (print_headings)
+ printf("TEST NUA-10.1.1: PASSED\n");
+
+ if (print_headings)
+ printf("TEST NUA-10.1.2: terminate call\n");
+
+ BYE(b, b_call, b_call->nh, TAG_END());
+ run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
+
+ /* B transitions:
+ READY --(T2)--> TERMINATING: nua_bye()
+ TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_r_bye);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+ free_events_in_list(ctx, b->events);
+
+ /* A: READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_bye);
+ TEST(e->data->e_status, 200);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+ free_events_in_list(ctx, a->events);
+
+ nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+ nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+ if (print_headings)
+ printf("TEST NUA-10.1.2: PASSED\n");
+
+ END();
+}
+
+/*
+ X INVITE
+ | |
+ |-------INVITE------>|
+ |<--------200--------|
+ |---------ACK------->|
+*/
+int authenticate_until_ready(CONDITION_PARAMS)
+{
+ if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+ return 0;
+
+ save_event_in_list(ctx, event, ep, call);
+
+ if (status == 401 || status == 407) {
+ AUTHENTICATE(ep, call, nh,
+ NUTAG_AUTH("Digest:\"test-proxy\":charlie:secret"),
+ TAG_END());
+ }
+
+ switch (callstate(tags)) {
+ case nua_callstate_ready:
+ return 1;
+ case nua_callstate_terminated:
+ if (call)
+ nua_handle_destroy(call->nh), call->nh = NULL;
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+/** Test authentication for PRACK */
+int test_prack_auth(struct context *ctx)
+{
+ if (!ctx->proxy_tests)
+ return 0;
+
+ BEGIN();
+
+ struct endpoint *c = &ctx->c, *b = &ctx->b;
+ struct call *c_call = c->call, *b_call = b->call;
+ struct event *e;
+ sip_t *sip;
+ sip_proxy_authenticate_t *au;
+ char const *md5 = NULL, *md5sess = NULL;
+
+ if (print_headings)
+ printf("TEST NUA-10.1.1: Call with 100rel and 180\n");
+
+/* Test for authentication during 100rel
+
+ C B
+ |-------INVITE--\ |
+ |<-------407----/ |
+ | |
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ | |
+ |<-------180---------|
+ |-------PRACK---\ |
+ |<-------407----/ |
+ |-------PRACK------->|
+ |<-------200---------|
+ | |
+ |<------200 OK-------|
+ |--------ACK-------->|
+ | |
+ |<-------BYE---------|
+ |-------200 OK-------|
+ | |
+
+*/
+
+ c_call->sdp = "m=audio 5008 RTP/AVP 8";
+ b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
+
+ nua_set_params(ctx->c.nua,
+ NUTAG_EARLY_MEDIA(1),
+ TAG_END());
+ run_c_until(ctx, nua_r_set_params, until_final_response);
+
+ nua_set_params(ctx->b.nua,
+ NUTAG_EARLY_MEDIA(1),
+ TAG_END());
+ run_b_until(ctx, nua_r_set_params, until_final_response);
+
+ TEST_1(c_call->nh = nua_handle(c->nua, c_call, SIPTAG_TO(b->to), TAG_END()));
+
+ INVITE(c, c_call, c_call->nh,
+ TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+ SOATAG_USER_SDP_STR(c_call->sdp),
+ TAG_END());
+
+ run_bc_until(ctx, -1, accept_pracked, -1, authenticate_until_ready);
+
+ /* Client transitions:
+ INIT -(C1)-> CALLING: nua_invite(), nua_i_state
+ CALLING -(C2)-> PROCEEDING: nua_r_invite, nua_i_state, nua_r_prack
+ PROCEEDING -(C3+C4)-> READY: nua_r_invite, nua_i_state
+ */
+ TEST_1(e = c->events->head); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+ TEST_1(is_offer_sent(e->data->e_tags));
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 407);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(au = sip->sip_proxy_authenticate);
+ TEST_1(auth_get_params(NULL, au->au_params,
+ "algorithm=md5", &md5,
+ "algorithm=md5-sess", &md5sess,
+ NULL) > 0);
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+ TEST_1(is_offer_sent(e->data->e_tags));
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 180);
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
+ TEST_1(is_answer_recv(e->data->e_tags));
+ TEST_1(!is_offer_sent(e->data->e_tags));
+
+ if (md5 && !md5sess) {
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_prack);
+ TEST(e->data->e_status, 407);
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
+ TEST_1(!is_answer_recv(e->data->e_tags));
+ TEST_1(!is_offer_sent(e->data->e_tags));
+ }
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_prack);
+ TEST(e->data->e_status, 200);
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 200);
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+ TEST_1(!is_offer_answer_done(e->data->e_tags));
+ TEST_1(!e->next);
+ free_events_in_list(ctx, c->events);
+
+ /*
+ Server transitions:
+ INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
+ RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state
+ EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state
+ COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+ TEST(e->data->e_status, 100);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+ TEST_1(is_offer_recv(e->data->e_tags));
+
+ /* Responded with 180 Ringing */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+ TEST_1(is_answer_sent(e->data->e_tags));
+
+ /* 180 is PRACKed */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_prack);
+ /* Does not have effect on call state */
+
+ /* Respond with 200 OK */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+ TEST_1(!is_offer_answer_done(e->data->e_tags));
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+ TEST_1(!is_offer_answer_done(e->data->e_tags));
+ TEST_1(!e->next);
+ free_events_in_list(ctx, b->events);
+
+ if (print_headings)
+ printf("TEST NUA-10.1.1: PASSED\n");
+
+ if (print_headings)
+ printf("TEST NUA-10.1.2: terminate call\n");
+
+ BYE(b, b_call, b_call->nh, TAG_END());
+ run_bc_until(ctx, -1, until_terminated, -1, until_terminated);
+
+ /* B transitions:
+ READY --(T2)--> TERMINATING: nua_bye()
+ TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_r_bye);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+ free_events_in_list(ctx, b->events);
+
+ /* C: READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state */
+ TEST_1(e = c->events->head); TEST_E(e->data->e_event, nua_i_bye);
+ TEST(e->data->e_status, 200);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+ free_events_in_list(ctx, c->events);
+
+ nua_handle_destroy(c_call->nh), c_call->nh = NULL;
+ nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+ if (print_headings)
+ printf("TEST NUA-10.1.2: PASSED\n");
+
+ END();
+}
+
+/*
+ X ringing_pracked ep
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ | |
+ |<-------183---------|
+ |-------PRACK------->|
+ |<-------200---------|
+ | |
+ |<-------180---------|
+ |-------PRACK------->|
+ |<-------200---------|
+ | |
+ |<------200 OK-------|
+ |--------ACK-------->|
+ | |
+*/
+int ringing_pracked(CONDITION_PARAMS)
+{
+ if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+ return 0;
+
+ save_event_in_list(ctx, event, ep, call);
+
+ switch (event) {
+ case nua_i_prack:
+ if (200 <= status && status < 300) {
+ RESPOND(ep, call, nh, SIP_180_RINGING, TAG_END());
+ ep->next_condition = accept_pracked;
+ }
+ default:
+ break;
+ }
+
+ switch (callstate(tags)) {
+ case nua_callstate_received:
+ RESPOND(ep, call, nh, SIP_183_SESSION_PROGRESS,
+ TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)),
+ TAG_END());
+ return 0;
+ case nua_callstate_terminated:
+ if (call)
+ nua_handle_destroy(call->nh), call->nh = NULL;
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+int test_183rel(struct context *ctx)
+{
+ BEGIN();
+
+ struct endpoint *a = &ctx->a, *b = &ctx->b;
+ struct call *a_call = a->call, *b_call = b->call;
+ struct event *e;
+
+ if (print_headings)
+ printf("TEST NUA-10.2.1: Call with 100rel, 183 and 180\n");
+
+ TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+ INVITE(a, a_call, a_call->nh,
+ TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+ SOATAG_USER_SDP_STR(a_call->sdp),
+ TAG_END());
+
+ run_ab_until(ctx, -1, until_ready, -1, ringing_pracked);
+
+ /* Client transitions:
+ INIT -(C1)-> CALLING: nua_invite(), nua_i_state
+ CALLING -(C2)-> PROCEEDING: nua_r_invite, nua_i_state, nua_r_prack
+ PROCEEDING -(C2)-> PROCEEDING: nua_r_invite, nua_i_state, nua_r_prack
+ PROCEEDING -(C3+C4)-> READY: nua_r_invite, nua_i_state
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+ TEST_1(is_offer_sent(e->data->e_tags));
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 183);
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
+ TEST_1(is_answer_recv(e->data->e_tags));
+ TEST_1(!is_offer_sent(e->data->e_tags));
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_prack);
+ TEST(e->data->e_status, 200);
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 180);
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
+ TEST_1(!is_offer_answer_done(e->data->e_tags));
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_prack);
+ TEST(e->data->e_status, 200);
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 200);
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+ TEST_1(!is_offer_answer_done(e->data->e_tags));
+ TEST_1(!e->next);
+ free_events_in_list(ctx, a->events);
+
+ /*
+ Server transitions:
+ INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
+ RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state
+ EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state
+ COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+ TEST(e->data->e_status, 100);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+ TEST_1(is_offer_recv(e->data->e_tags));
+
+ /* Responded with 183 Session Progress */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(e->data->e_status, 183);
+ TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+ TEST_1(is_answer_sent(e->data->e_tags));
+
+ /* 183 is PRACKed */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_prack);
+ /* Does not have effect on call state */
+
+ /* Responded with 180 Ringing */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(e->data->e_status, 180);
+ TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+ TEST_1(!is_offer_answer_done(e->data->e_tags));
+
+ /* 180 is PRACKed */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_prack);
+ /* Does not have effect on call state */
+
+ /* Respond with 200 OK */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(e->data->e_status, 200);
+ TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+ TEST_1(!is_offer_answer_done(e->data->e_tags));
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+ TEST_1(!is_offer_answer_done(e->data->e_tags));
+ TEST_1(!e->next);
+ free_events_in_list(ctx, b->events);
+
+ if (print_headings)
+ printf("TEST NUA-10.2.1: PASSED\n");
+
+ if (print_headings)
+ printf("TEST NUA-10.2.2: terminate call\n");
+
+ BYE(b, b_call, b_call->nh, TAG_END());
+ run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
+
+ /* B transitions:
+ READY --(T2)--> TERMINATING: nua_bye()
+ TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_r_bye);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+ free_events_in_list(ctx, b->events);
+
+ /* A: READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_bye);
+ TEST(e->data->e_status, 200);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+ free_events_in_list(ctx, a->events);
+
+ nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+ nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+ if (print_headings)
+ printf("TEST NUA-10.2.2: PASSED\n");
+
+ END();
+}
+
+/*
+ X ringing_updated ep
+ |-------INVITE------>|
+ | (sdp) |
+ |<----100 Trying-----|
+ | |
+ |<-------183---------|
+ | (sdp) |
+ |-------PRACK------->|
+ | (sdp) |
+ |<-------200---------|
+ | (sdp) |
+ | |
+ |-------UPDATE------>|
+ | (sdp) |
+ |<-------200---------|
+ | (sdp) |
+ | |
+<using acccept_pracked>
+ | |
+ |<-------180---------|
+ |-------PRACK------->|
+ |<-------200---------|
+ | |
+ |<------200 OK-------|
+ |--------ACK-------->|
+ | |
+*/
+int ringing_updated(CONDITION_PARAMS)
+{
+ if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+ return 0;
+
+ save_event_in_list(ctx, event, ep, call);
+
+ switch (event) {
+ case nua_i_update:
+ if (200 <= status && status < 300) {
+ RESPOND(ep, call, nh, SIP_180_RINGING, TAG_END());
+ ep->next_condition = accept_pracked;
+ }
+ return 0;
+ default:
+ break;
+ }
+
+ switch (callstate(tags)) {
+ case nua_callstate_received:
+ RESPOND(ep, call, nh, SIP_183_SESSION_PROGRESS,
+ SIPTAG_REQUIRE_STR("100rel"),
+ TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)),
+ TAG_END());
+ return 0;
+ case nua_callstate_early:
+ return 0;
+ case nua_callstate_ready:
+ return 1;
+ case nua_callstate_terminated:
+ if (call)
+ nua_handle_destroy(call->nh), call->nh = NULL;
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+int test_preconditions(struct context *ctx)
+{
+ BEGIN();
+
+ struct endpoint *a = &ctx->a, *b = &ctx->b;
+ struct call *a_call = a->call, *b_call = b->call;
+ struct event *e;
+ sip_t *sip;
+
+ if (print_headings)
+ printf("TEST NUA-10.3.1: Call with 100rel and preconditions\n");
+
+/* Test for precondition:
+
+ A B
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ | |
+ |<-------183---------|
+ |-------PRACK------->|
+ |<-------200---------|
+ | |
+ |-------UPDATE------>|
+ |<-------200---------|
+ | |
+ |<-------180---------|
+ |-------PRACK------->|
+ |<-------200---------|
+ | |
+ |<------200 OK-------|
+ |--------ACK-------->|
+ | |
+ |<-------BYE---------|
+ |-------200 OK-------|
+ | |
+
+*/
+
+ a_call->sdp = "m=audio 5008 RTP/AVP 8";
+ b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
+
+ nua_set_params(ctx->a.nua,
+ NUTAG_EARLY_MEDIA(1),
+ SIPTAG_SUPPORTED_STR("100rel, precondition"),
+ TAG_END());
+ run_a_until(ctx, nua_r_set_params, until_final_response);
+
+ nua_set_params(ctx->b.nua,
+ NUTAG_EARLY_MEDIA(0),
+ SIPTAG_SUPPORTED_STR("100rel, precondition, timer"),
+ TAG_END());
+ run_b_until(ctx, nua_r_set_params, until_final_response);
+
+ TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+ INVITE(a, a_call, a_call->nh,
+ TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+ SOATAG_USER_SDP_STR(a_call->sdp),
+ SIPTAG_SUPPORTED_STR("100rel"),
+ SIPTAG_REQUIRE_STR("precondition"),
+ TAG_END());
+
+ run_ab_until(ctx, -1, until_ready, -1, ringing_updated);
+
+ /* Client transitions:
+ INIT -(C1)-> CALLING: nua_invite(), nua_i_state
+ CALLING -(C2)-> PROCEEDING: nua_r_invite, nua_i_state
+ PROCEEDING --> PROCEEDING: nua_r_prack, nua_i_state
+ PROCEEDING --> PROCEEDING: nua_r_update, nua_i_state
+ PROCEEDING -(C3+C4)-> READY: nua_r_invite, nua_i_state
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+ TEST_1(is_offer_sent(e->data->e_tags));
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 183);
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
+ TEST_1(is_answer_recv(e->data->e_tags));
+ TEST_1(is_offer_sent(e->data->e_tags));
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_prack);
+ TEST(e->data->e_status, 200);
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
+ TEST_1(is_answer_recv(e->data->e_tags));
+ TEST_1(!is_offer_sent(e->data->e_tags));
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
+ TEST_1(!is_answer_recv(e->data->e_tags));
+ TEST_1(is_offer_sent(e->data->e_tags));
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_update);
+ TEST(e->data->e_status, 200);
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
+ TEST_1(is_answer_recv(e->data->e_tags));
+ TEST_1(!is_offer_sent(e->data->e_tags));
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 180);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
+ TEST_1(!is_offer_answer_done(e->data->e_tags));
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_prack);
+ TEST(e->data->e_status, 200);
+ /* Does not have effect on call state */
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 200);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ if (ctx->proxy_tests) {
+ TEST_1(sip->sip_session_expires);
+ TEST_S(sip->sip_session_expires->x_refresher, "uas");
+ TEST_1(!sip_has_supported(sip->sip_require, "timer"));
+ }
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+ TEST_1(!is_offer_answer_done(e->data->e_tags));
+ TEST_1(!e->next);
+ free_events_in_list(ctx, a->events);
+
+ /*
+ Server transitions:
+ INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
+ RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state
+ EARLY --> EARLY: nua_i_prack, nua_i_state
+ EARLY --> EARLY: nua_i_update, nua_i_state
+ EARLY --> EARLY: nua_r_update, nua_i_state
+ EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state
+ COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+ TEST(e->data->e_status, 100);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+
+ /* Responded with 183 Session Progress */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(e->data->e_status, 183);
+ TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+ TEST_1(is_answer_sent(e->data->e_tags));
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_prack);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+ TEST_1(is_offer_recv(e->data->e_tags));
+ TEST_1(is_answer_sent(e->data->e_tags));
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_update);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+ TEST_1(!is_offer_sent(e->data->e_tags));
+ TEST_1(is_offer_recv(e->data->e_tags));
+ TEST_1(is_answer_sent(e->data->e_tags));
+ TEST_1(!is_answer_recv(e->data->e_tags));
+
+ /* Responded with 180 Ringing */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(e->data->e_status, 180);
+ TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+ TEST_1(!is_offer_answer_done(e->data->e_tags));
+
+ /* 180 PRACKed */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_prack);
+ /* Does not have effect on call state */
+
+ /* Responded with 200 OK */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(e->data->e_status, 200);
+ TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+ TEST_1(!is_offer_answer_done(e->data->e_tags));
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+ TEST_1(!is_offer_answer_done(e->data->e_tags));
+ TEST_1(!e->next);
+ free_events_in_list(ctx, b->events);
+
+ if (print_headings)
+ printf("TEST NUA-10.3.1: PASSED\n");
+
+ if (print_headings)
+ printf("TEST NUA-10.3.2: terminate call\n");
+
+ BYE(b, b_call, b_call->nh, TAG_END());
+ run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
+
+ /* B transitions:
+ READY --(T2)--> TERMINATING: nua_bye()
+ TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_r_bye);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+ free_events_in_list(ctx, b->events);
+
+ /* A: READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_bye);
+ TEST(e->data->e_status, 200);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+ free_events_in_list(ctx, a->events);
+
+ nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+ nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+ if (print_headings)
+ printf("TEST NUA-10.3.2: PASSED\n");
+
+ END();
+}
+
+/*
+ X accept_updated ep
+ |-------INVITE------>|
+ | (sdp) |
+ |<----100 Trying-----|
+ | |
+ |<-------183---------|
+ | (sdp) |
+ |-------PRACK------->|
+ | (sdp) |
+ |<-------200---------|
+ | (sdp) |
+ | |
+ |-------UPDATE------>|
+ | (sdp) |
+ |<-------200---------|
+ | (sdp) |
+ | |
+ | |
+ |<-------180---------|
+ | |
+ |<------200 OK-------|
+ |--------ACK-------->|
+ | |
+*/
+int accept_updated(CONDITION_PARAMS)
+{
+ if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+ return 0;
+
+ save_event_in_list(ctx, event, ep, call);
+
+ switch (event) {
+ case nua_i_update:
+ if (200 <= status && status < 300) {
+ RESPOND(ep, call, nh, SIP_180_RINGING, TAG_END());
+ }
+ return 0;
+ default:
+ break;
+ }
+
+ switch (callstate(tags)) {
+ case nua_callstate_received:
+ RESPOND(ep, call, nh, SIP_183_SESSION_PROGRESS,
+ SIPTAG_REQUIRE_STR("100rel"),
+ TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)),
+ TAG_END());
+ return 0;
+ case nua_callstate_early:
+ if (status == 180)
+ RESPOND(ep, call, nh, SIP_200_OK, TAG_END());
+ return 0;
+ case nua_callstate_ready:
+ return 1;
+ case nua_callstate_terminated:
+ if (call)
+ nua_handle_destroy(call->nh), call->nh = NULL;
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+
+int test_preconditions2(struct context *ctx)
+{
+ BEGIN();
+
+ struct endpoint *a = &ctx->a, *b = &ctx->b;
+ struct call *a_call = a->call, *b_call = b->call;
+ struct event *e;
+
+ if (print_headings)
+ printf("TEST NUA-10.4.1: Call with preconditions and non-100rel 180\n");
+
+/* Test 100rel and preconditions with NUTAG_ONLY183_100REL(1):
+
+ A B
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ | |
+ |<-------183---------|
+ |-------PRACK------->|
+ |<-------200---------|
+ | |
+ |<-------180---------|
+ | |
+ |<------200 OK-------|
+ |--------ACK-------->|
+ | |
+ |<-------BYE---------|
+ |-------200 OK-------|
+ | |
+
+*/
+
+ a_call->sdp = "m=audio 5008 RTP/AVP 8";
+ b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
+
+ nua_set_params(ctx->a.nua,
+ NUTAG_EARLY_MEDIA(1),
+ SIPTAG_SUPPORTED_STR("100rel, precondition"),
+ TAG_END());
+ run_a_until(ctx, nua_r_set_params, until_final_response);
+
+ nua_set_params(ctx->b.nua,
+ NUTAG_EARLY_MEDIA(1),
+ NUTAG_ONLY183_100REL(1),
+ SIPTAG_SUPPORTED_STR("100rel, precondition"),
+ TAG_END());
+ run_b_until(ctx, nua_r_set_params, until_final_response);
+
+ TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+ INVITE(a, a_call, a_call->nh,
+ TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+ SOATAG_USER_SDP_STR(a_call->sdp),
+ SIPTAG_SUPPORTED_STR("100rel"),
+ SIPTAG_REQUIRE_STR("precondition"),
+ TAG_END());
+
+ run_ab_until(ctx, -1, until_ready, -1, accept_updated);
+
+ /* Client transitions:
+ INIT -(C1)-> CALLING: nua_invite(), nua_i_state
+ CALLING -(C2)-> PROCEEDING: nua_r_invite, nua_i_state
+ PROCEEDING -(C3+C4)-> READY: nua_r_invite, nua_i_state
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+ TEST_1(is_offer_sent(e->data->e_tags));
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 183);
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
+ TEST_1(is_answer_recv(e->data->e_tags));
+ TEST_1(is_offer_sent(e->data->e_tags));
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_prack);
+ TEST(e->data->e_status, 200);
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
+ TEST_1(is_answer_recv(e->data->e_tags));
+ TEST_1(!is_offer_sent(e->data->e_tags));
+
+ /* Send UPDATE */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
+ TEST_1(!is_answer_recv(e->data->e_tags));
+ TEST_1(is_offer_sent(e->data->e_tags));
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_update);
+ TEST(e->data->e_status, 200);
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
+ TEST_1(is_answer_recv(e->data->e_tags));
+ TEST_1(!is_offer_sent(e->data->e_tags));
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 180);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
+ TEST_1(!is_offer_answer_done(e->data->e_tags));
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 200);
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+ TEST_1(!is_offer_answer_done(e->data->e_tags));
+ TEST_1(!e->next);
+ free_events_in_list(ctx, a->events);
+
+ /*
+ Server transitions:
+ INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
+ RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state
+ EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state
+ COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+ TEST(e->data->e_status, 100);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+
+ /* Responded with 183 Session Progress */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+ TEST_1(is_answer_sent(e->data->e_tags));
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_prack);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+ TEST_1(is_offer_recv(e->data->e_tags));
+ TEST_1(is_answer_sent(e->data->e_tags));
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_update);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+ TEST_1(is_offer_recv(e->data->e_tags));
+ TEST_1(is_answer_sent(e->data->e_tags));
+
+ /* Responded with 180 Ringing */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+ TEST_1(!is_offer_answer_done(e->data->e_tags));
+
+ /* Responded with 200 OK */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+ TEST_1(!is_offer_answer_done(e->data->e_tags));
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+ TEST_1(!is_offer_answer_done(e->data->e_tags));
+ TEST_1(!e->next);
+ free_events_in_list(ctx, b->events);
+
+ if (print_headings)
+ printf("TEST NUA-10.4.1: PASSED\n");
+
+ if (print_headings)
+ printf("TEST NUA-10.4.2: terminate call\n");
+
+ BYE(b, b_call, b_call->nh, TAG_END());
+ run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
+
+ /* B transitions:
+ READY --(T2)--> TERMINATING: nua_bye()
+ TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_r_bye);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+ free_events_in_list(ctx, b->events);
+
+ /* A: READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_bye);
+ TEST(e->data->e_status, 200);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+ free_events_in_list(ctx, a->events);
+
+ nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+ nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+ if (print_headings)
+ printf("TEST NUA-10.4.2: PASSED\n");
+
+ END();
+}
+
+/*
+ X ringing_updated2 ep
+ |-------INVITE------>|
+ | (sdp) |
+ |<----100 Trying-----|
+ | |
+ |<-------183---------|
+ | (sdp) |
+ |-------PRACK------->|
+ | (sdp) |
+ |<-------200---------|
+ | (sdp) |
+ | |
+ |-------UPDATE------>|
+ | (sdp) |
+ |<-------200---------|
+ | (sdp) |
+ | |
+ |<------UPDATE-------|
+ | (sdp) |
+ |--------200-------->|
+ | (sdp) |
+ | |
+<using acccept_pracked>
+ | |
+ |<-------180---------|
+ |-------PRACK------->|
+ |<-------200---------|
+ | |
+ |<------200 OK-------|
+ |--------ACK-------->|
+ | |
+*/
+int ringing_updated2(CONDITION_PARAMS)
+{
+ if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+ return 0;
+
+ save_event_in_list(ctx, event, ep, call);
+
+ switch (event) {
+ case nua_i_update:
+ if (200 <= status && status < 300) {
+ UPDATE(ep, call, nh, TAG_END());
+ }
+ return 0;
+ case nua_r_update:
+ if (200 <= status && status < 300) {
+ RESPOND(ep, call, nh, SIP_180_RINGING,
+ SIPTAG_REQUIRE_STR("100rel"),
+ TAG_END());
+ ep->next_condition = accept_pracked;
+ }
+ else if (300 <= status) {
+ RESPOND(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
+ }
+ return 0;
+ default:
+ break;
+ }
+
+ switch (callstate(tags)) {
+ case nua_callstate_received:
+ RESPOND(ep, call, nh, SIP_183_SESSION_PROGRESS,
+ SIPTAG_REQUIRE_STR("100rel"),
+ TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)),
+ TAG_END());
+ return 0;
+ case nua_callstate_early:
+ return 0;
+ case nua_callstate_ready:
+ return 1;
+ case nua_callstate_terminated:
+ if (call)
+ nua_handle_destroy(call->nh), call->nh = NULL;
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+int test_update_by_uas(struct context *ctx)
+{
+ BEGIN();
+
+ struct endpoint *a = &ctx->a, *b = &ctx->b;
+ struct call *a_call = a->call, *b_call = b->call;
+ struct event *e;
+ sip_t *sip;
+
+ /* -------------------------------------------------------------------- */
+
+ if (print_headings)
+ printf("TEST NUA-10.5.1: Call with dual UPDATE\n");
+
+/* Test for precondition:
+
+ A B
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ | |
+ |<-------183---------|
+ |-------PRACK------->|
+ |<-------200---------|
+ | |
+ |-------UPDATE------>|
+ |<-------200---------|
+ | |
+ |<------UPDATE-------|
+ |--------200-------->|
+ | |
+ |<-------180---------|
+ |-------PRACK------->|
+ |<-------200---------|
+ | |
+ |<------200 OK-------|
+ |--------ACK-------->|
+ | |
+ |<-------BYE---------|
+ |-------200 OK-------|
+ | |
+
+*/
+
+ a_call->sdp = "m=audio 5008 RTP/AVP 8";
+ b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
+
+ nua_set_params(ctx->a.nua,
+ NUTAG_EARLY_MEDIA(1),
+ SIPTAG_SUPPORTED_STR("100rel, precondition"),
+ TAG_END());
+ run_a_until(ctx, nua_r_set_params, until_final_response);
+
+ nua_set_params(ctx->b.nua,
+ NUTAG_EARLY_MEDIA(0),
+ SIPTAG_SUPPORTED_STR("100rel, precondition, timer"),
+ TAG_END());
+ run_b_until(ctx, nua_r_set_params, until_final_response);
+
+ TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+ INVITE(a, a_call, a_call->nh,
+ TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+ SOATAG_USER_SDP_STR(a_call->sdp),
+ SIPTAG_SUPPORTED_STR("100rel"),
+ SIPTAG_REQUIRE_STR("precondition"),
+ TAG_END());
+
+ run_ab_until(ctx, -1, until_ready, -1, ringing_updated2);
+
+ /* Client transitions:
+ INIT -(C1)-> CALLING: nua_invite(), nua_i_state
+ CALLING -(C2)-> PROCEEDING: nua_r_invite, nua_i_state
+ PROCEEDING: nua_r_prack, nua_i_state
+ PROCEEDING: nua_r_update, nua_i_state
+ PROCEEDING: nua_i_update, nua_i_state
+ PROCEEDING -(C3+C4)-> READY: nua_r_invite, nua_i_state
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+ TEST_1(is_offer_sent(e->data->e_tags));
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 183);
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
+ TEST_1(is_answer_recv(e->data->e_tags));
+ TEST_1(is_offer_sent(e->data->e_tags));
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_prack);
+ TEST(e->data->e_status, 200);
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
+ TEST_1(is_answer_recv(e->data->e_tags));
+ TEST_1(!is_offer_sent(e->data->e_tags));
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
+ TEST_1(!is_answer_recv(e->data->e_tags));
+ TEST_1(is_offer_sent(e->data->e_tags));
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_update);
+ TEST(e->data->e_status, 200);
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
+ TEST_1(is_answer_recv(e->data->e_tags));
+ TEST_1(!is_offer_sent(e->data->e_tags));
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_update);
+ TEST(e->data->e_status, 200);
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
+ TEST_1(is_offer_recv(e->data->e_tags));
+ TEST_1(is_answer_sent(e->data->e_tags));
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 180);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
+ TEST_1(!is_offer_answer_done(e->data->e_tags));
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_prack);
+ TEST(e->data->e_status, 200);
+ /* Does not have effect on call state */
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 200);
+ if (ctx->proxy_tests) {
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(sip->sip_session_expires);
+ TEST_S(sip->sip_session_expires->x_refresher, "uas");
+ TEST_1(!sip_has_supported(sip->sip_require, "timer"));
+ }
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+ TEST_1(!is_offer_answer_done(e->data->e_tags));
+ TEST_1(!e->next);
+ free_events_in_list(ctx, a->events);
+
+ /*
+ Server transitions:
+ INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
+ RECEIVED -(S2a)-> EARLY: nua_respond(183), nua_i_state
+ EARLY --> EARLY: nua_i_prack, nua_i_state
+ EARLY --> EARLY: nua_i_update, nua_i_state
+ EARLY --> EARLY: nua_update(), nua_i_state
+ EARLY --> EARLY: nua_r_update, nua_i_state
+ EARLY --> EARLY: nua_respond(180), nua_i_state
+ EARLY --> EARLY: nua_i_prack, nua_i_state
+ EARLY -(S3b)-> COMPLETED: nua_respond(200), nua_i_state
+ COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+ TEST(e->data->e_status, 100);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+
+ /* Responded with 183 Session Progress */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(e->data->e_status, 183);
+ TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+ TEST_1(is_answer_sent(e->data->e_tags));
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_prack);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+ TEST_1(is_offer_recv(e->data->e_tags));
+ TEST_1(is_answer_sent(e->data->e_tags));
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_update);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+ TEST_1(is_offer_recv(e->data->e_tags));
+ TEST_1(is_answer_sent(e->data->e_tags));
+
+ /* sent UPDATE */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+ TEST_1(is_offer_sent(e->data->e_tags));
+ TEST_1(!is_offer_recv(e->data->e_tags));
+ TEST_1(!is_answer_sent(e->data->e_tags));
+ TEST_1(!is_answer_recv(e->data->e_tags));
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_update);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+ TEST_1(!is_offer_sent(e->data->e_tags));
+ TEST_1(!is_offer_recv(e->data->e_tags));
+ TEST_1(!is_answer_sent(e->data->e_tags));
+ TEST_1(is_answer_recv(e->data->e_tags));
+
+ /* Responded with 180 Ringing */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(e->data->e_status, 180);
+ TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+ TEST_1(!is_offer_answer_done(e->data->e_tags));
+
+ /* 180 PRACKed */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_prack);
+ /* Does not have effect on call state */
+
+ /* Responded with 200 OK */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(e->data->e_status, 200);
+ TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+ TEST_1(!is_offer_answer_done(e->data->e_tags));
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+ TEST_1(!is_offer_answer_done(e->data->e_tags));
+ TEST_1(!e->next);
+ free_events_in_list(ctx, b->events);
+
+ if (print_headings)
+ printf("TEST NUA-10.5.1: PASSED\n");
+
+ if (print_headings)
+ printf("TEST NUA-10.5.2: terminate call\n");
+
+ BYE(b, b_call, b_call->nh, TAG_END());
+ run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
+
+ /* B transitions:
+ READY --(T2)--> TERMINATING: nua_bye()
+ TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_r_bye);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+ free_events_in_list(ctx, b->events);
+
+ /* A: READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_bye);
+ TEST(e->data->e_status, 200);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+ free_events_in_list(ctx, a->events);
+
+ nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+ nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+ if (print_headings)
+ printf("TEST NUA-10.5.2: PASSED\n");
+
+ END();
+}
+
+
+int test_100rel(struct context *ctx)
+{
+ int retval;
+
+ retval = test_180rel(ctx); RETURN_ON_SINGLE_FAILURE(retval);
+ retval = test_prack_auth(ctx); RETURN_ON_SINGLE_FAILURE(retval);
+ retval = test_183rel(ctx); RETURN_ON_SINGLE_FAILURE(retval);
+ retval = test_preconditions(ctx); RETURN_ON_SINGLE_FAILURE(retval);
+ retval = test_preconditions2(ctx); RETURN_ON_SINGLE_FAILURE(retval);
+ retval = test_update_by_uas(ctx); RETURN_ON_SINGLE_FAILURE(retval);
+
+ return retval;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_basic_call.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_basic_call.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,509 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_nua_basic_call.c
+ * @brief Test basic call.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti Mela at nokia.com>
+ *
+ * @date Created: Wed Aug 17 12:12:12 EEST 2005 ppessi
+ */
+
+#include "config.h"
+
+#include "test_nua.h"
+#include <sofia-sip/su_tag_class.h>
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+#define __func__ "test_basic_call"
+#endif
+
+/* ======================================================================== */
+
+int until_terminated(CONDITION_PARAMS)
+{
+ if (!check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR))
+ return 0;
+
+ save_event_in_list(ctx, event, ep, call);
+
+ return event == nua_i_state && callstate(tags) == nua_callstate_terminated;
+}
+
+/*
+ X accept_call ep
+ | |
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ | |
+ |<----180 Ringing----|
+ | |
+ |<--------200--------|
+ |---------ACK------->|
+*/
+int accept_call(CONDITION_PARAMS)
+{
+ if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+ return 0;
+
+ save_event_in_list(ctx, event, ep, call);
+
+ switch (callstate(tags)) {
+ case nua_callstate_received:
+ RESPOND(ep, call, nh, SIP_180_RINGING,
+ TAG_END());
+ return 0;
+ case nua_callstate_early:
+ RESPOND(ep, call, nh, SIP_200_OK,
+ TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)),
+ TAG_END());
+ return 0;
+ case nua_callstate_ready:
+ return 1;
+ case nua_callstate_terminated:
+ if (call)
+ nua_handle_destroy(call->nh), call->nh = NULL;
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+
+/*
+ X accept_call ep
+ | |
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ | |
+ |<----180 Ringing----|
+ | |
+ |<--------200--------|
+ |---------ACK------->|
+*/
+int accept_call_with_early_sdp(CONDITION_PARAMS)
+{
+ if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+ return 0;
+
+ save_event_in_list(ctx, event, ep, call);
+
+ switch (callstate(tags)) {
+ case nua_callstate_received:
+ RESPOND(ep, call, nh, SIP_180_RINGING,
+ TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)),
+ TAG_END());
+ return 0;
+ case nua_callstate_early:
+ RESPOND(ep, call, nh, SIP_200_OK,
+ TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)),
+ TAG_END());
+ return 0;
+ case nua_callstate_ready:
+ return 1;
+ case nua_callstate_terminated:
+ if (call)
+ nua_handle_destroy(call->nh), call->nh = NULL;
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+
+/*
+ X INVITE
+ | |
+ |-------INVITE------>|
+ |<--------200--------|
+ |---------ACK------->|
+*/
+int until_ready(CONDITION_PARAMS)
+{
+ if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+ return 0;
+
+ save_event_in_list(ctx, event, ep, call);
+
+ switch (callstate(tags)) {
+ case nua_callstate_ready:
+ return 1;
+ case nua_callstate_terminated:
+ if (call)
+ nua_handle_destroy(call->nh), call->nh = NULL;
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+/* ======================================================================== */
+
+/* Basic call:
+
+ A B
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ | |
+ |<----180 Ringing----|
+ | |
+ |<------200 OK-------|
+ |--------ACK-------->|
+ | |
+ |<-------BYE---------|
+ |-------200 OK------>|
+ | |
+
+ Client transitions:
+ INIT -(C1)-> CALLING -(C2a)-> PROCEEDING -(C3+C4)-> READY
+ Server transitions:
+ INIT -(S1)-> RECEIVED -(S2a)-> EARLY -(S3b)-> COMPLETED -(S4)-> READY
+
+ B sends BYE:
+ READY -(T2)-> TERMINATING -(T3)-> TERMINATED
+ A receives BYE:
+ READY -(T1)-> TERMINATED
+
+ See @page nua_call_model in nua.docs for more information
+*/
+
+int test_basic_call_1(struct context *ctx)
+{
+ BEGIN();
+
+ struct endpoint *a = &ctx->a, *b = &ctx->b;
+ struct call *a_call = a->call, *b_call = b->call;
+ struct event *e;
+ sip_t *sip;
+ sip_replaces_t *repa, *repb;
+ nua_handle_t *nh;
+
+ if (print_headings)
+ printf("TEST NUA-3.1: Basic call\n");
+
+ a_call->sdp = "m=audio 5008 RTP/AVP 8";
+ b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
+
+ TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+ TEST_1(!nua_handle_has_active_call(a_call->nh));
+ TEST_1(!nua_handle_has_call_on_hold(a_call->nh));
+
+ INVITE(a, a_call, a_call->nh,
+ TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+ SOATAG_USER_SDP_STR(a_call->sdp),
+ TAG_END());
+
+ run_ab_until(ctx, -1, until_ready, -1, accept_call_with_early_sdp);
+
+ TEST_1(nua_handle_has_active_call(a_call->nh));
+ TEST_1(!nua_handle_has_call_on_hold(a_call->nh));
+
+ TEST_1(nua_handle_has_active_call(b_call->nh));
+ TEST_1(!nua_handle_has_call_on_hold(b_call->nh));
+
+ TEST_1(repa = nua_handle_make_replaces(a_call->nh, nua_handle_home(a_call->nh), 0));
+ TEST_1(repb = nua_handle_make_replaces(b_call->nh, nua_handle_home(b_call->nh), 0));
+
+ TEST_S(repa->rp_call_id, repb->rp_call_id);
+
+ TEST_1(!nua_handle_by_replaces(a->nua, repa));
+ TEST_1(!nua_handle_by_replaces(b->nua, repb));
+
+ TEST_1(nh = nua_handle_by_replaces(a->nua, repb));
+ TEST_P(nh, a_call->nh);
+ nua_handle_unref(nh);
+
+ TEST_1(nh = nua_handle_by_replaces(b->nua, repa));
+ TEST_P(nh, b_call->nh);
+ nua_handle_unref(nh);
+
+ /* Client transitions:
+ INIT -(C1)-> CALLING: nua_invite(), nua_i_state
+ CALLING -(C2)-> PROCEEDING: nua_r_invite, nua_i_state
+ PROCEEDING -(C3+C4)-> READY: nua_r_invite, nua_i_state
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+ TEST_1(is_offer_sent(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 180);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_S(sip->sip_call_id->i_id, repb->rp_call_id);
+ TEST_S(sip->sip_from->a_tag, repb->rp_to_tag);
+ TEST_S(sip->sip_to->a_tag, repb->rp_from_tag);
+ TEST_1(sip->sip_payload);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
+ TEST_1(is_answer_recv(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 200);
+ TEST_1(sip->sip_payload);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ /* Test that B uses application-specific contact */
+ if (ctx->proxy_tests)
+ TEST_1(sip->sip_contact->m_url->url_user);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+ TEST_1(!e->next);
+ free_events_in_list(ctx, a->events);
+
+ /*
+ Server transitions:
+ INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
+ RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state
+ EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state
+ COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+ TEST(e->data->e_status, 100);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+ TEST_1(is_offer_recv(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+ TEST_1(is_answer_sent(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+ TEST_1(is_answer_sent(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_S(sip->sip_call_id->i_id, repa->rp_call_id);
+ TEST_S(sip->sip_from->a_tag, repa->rp_from_tag);
+ TEST_S(sip->sip_to->a_tag, repa->rp_to_tag);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+ TEST_1(!e->next);
+ free_events_in_list(ctx, b->events);
+
+ BYE(b, b_call, b_call->nh, TAG_END());
+ run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
+
+ /* B transitions:
+ READY --(T2)--> TERMINATING: nua_bye()
+ TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_r_bye);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+ free_events_in_list(ctx, b->events);
+
+ TEST_1(!nua_handle_has_active_call(b_call->nh));
+
+ /* A transitions:
+ READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_bye);
+ TEST(e->data->e_status, 200);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+ free_events_in_list(ctx, a->events);
+
+ TEST_1(!nua_handle_has_active_call(a_call->nh));
+
+ nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+ nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+ if (print_headings)
+ printf("TEST NUA-3.1: PASSED\n");
+
+ END();
+}
+
+/*
+ accept_early_answer
+ X ep
+ | |
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ | |
+ |<----180 Ringing----|
+ | |
+ |<--------200--------|
+ |---------ACK------->|
+*/
+int accept_early_answer(CONDITION_PARAMS)
+{
+ if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+ return 0;
+
+ save_event_in_list(ctx, event, ep, call);
+
+ switch (callstate(tags)) {
+ case nua_callstate_received:
+ RESPOND(ep, call, nh, SIP_180_RINGING,
+ NUTAG_EARLY_ANSWER(1),
+ TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)),
+ TAG_END());
+ return 0;
+ case nua_callstate_early:
+ RESPOND(ep, call, nh, SIP_200_OK,
+ TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)),
+ TAG_END());
+ return 0;
+ case nua_callstate_ready:
+ return 1;
+ case nua_callstate_terminated:
+ if (call)
+ nua_handle_destroy(call->nh), call->nh = NULL;
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+int test_basic_call_2(struct context *ctx)
+{
+ BEGIN();
+
+ struct endpoint *a = &ctx->a, *b = &ctx->b;
+ struct call *a_call = a->call, *b_call = b->call;
+ struct event *e;
+ sip_t const *sip;
+
+ if (print_headings)
+ printf("TEST NUA-3.2: Basic call with SDP in 180\n");
+
+ a_call->sdp = "m=audio 5008 RTP/AVP 8";
+ b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
+
+ TEST_1(a_call->nh = nua_handle(a->nua, a_call,
+ SIPTAG_TO_STR("<sip:b at x.org>"),
+ TAG_END()));
+
+ TEST_1(!nua_handle_has_active_call(a_call->nh));
+ TEST_1(!nua_handle_has_call_on_hold(a_call->nh));
+
+ INVITE(a, a_call, a_call->nh,
+ NUTAG_URL(b->contact->m_url),
+ SOATAG_USER_SDP_STR(a_call->sdp),
+ TAG_END());
+
+ run_ab_until(ctx, -1, until_ready, -1, accept_early_answer);
+
+ /* Client transitions:
+ INIT -(C1)-> CALLING: nua_invite(), nua_i_state
+ CALLING -(C2)-> PROCEEDING: nua_r_invite, nua_i_state
+ PROCEEDING -(C3+C4)-> READY: nua_r_invite, nua_i_state
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+ TEST_1(is_offer_sent(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 180);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
+ TEST_1(is_answer_recv(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 200);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(sip->sip_content_type);
+ TEST_S(sip->sip_content_type->c_type, "application/sdp");
+ TEST_1(sip->sip_payload); /* there is sdp in 200 OK */
+ TEST_1(sip->sip_contact);
+ /* Test that B does not use application-specific contact */
+ TEST_1(!sip->sip_contact->m_url->url_user);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+ TEST_1(!is_answer_recv(e->data->e_tags)); /* but it is ignored */
+ TEST_1(!e->next);
+ free_events_in_list(ctx, a->events);
+
+ TEST_1(nua_handle_has_active_call(a_call->nh));
+ TEST_1(!nua_handle_has_call_on_hold(a_call->nh));
+
+ /*
+ Server transitions:
+ INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
+ RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state
+ EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state
+ COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+ TEST(e->data->e_status, 100);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+ TEST_1(is_offer_recv(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+ TEST_1(is_answer_sent(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+ TEST_1(is_answer_sent(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+ TEST_1(!e->next);
+ free_events_in_list(ctx, b->events);
+
+ TEST_1(nua_handle_has_active_call(b_call->nh));
+ TEST_1(!nua_handle_has_call_on_hold(b_call->nh));
+
+ BYE(b, b_call, b_call->nh, TAG_END());
+ run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
+
+ /* B transitions:
+ READY --(T2)--> TERMINATING: nua_bye()
+ TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_r_bye);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+ free_events_in_list(ctx, b->events);
+
+ TEST_1(!nua_handle_has_active_call(b_call->nh));
+
+ /* A transitions:
+ READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_bye);
+ TEST(e->data->e_status, 200);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+ free_events_in_list(ctx, a->events);
+
+ TEST_1(!nua_handle_has_active_call(a_call->nh));
+
+ nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+ nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+ if (print_headings)
+ printf("TEST NUA-3.2: PASSED\n");
+
+ END();
+}
+
+
+int test_basic_call(struct context *ctx)
+{
+ return test_basic_call_1(ctx) || test_basic_call_2(ctx);
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_call_hold.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_call_hold.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,803 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_call_hold.c
+ * @brief Test re-INVITE, call hold, un-hold.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti Mela at nokia.com>
+ *
+ * @date Created: Wed Aug 17 12:12:12 EEST 2005 ppessi
+ */
+
+#include "config.h"
+
+#include "test_nua.h"
+#include <sofia-sip/su_tag_class.h>
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+#define __func__ "test_call_hold"
+#endif
+
+int ack_when_completing(CONDITION_PARAMS);
+
+/* ======================================================================== */
+/* test_call_hold message sequence looks like this:
+
+ A B
+ | |
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ | |
+ |<----180 Ringing----|
+ | |
+ |<--------200--------|
+ |---------ACK------->|
+ : :
+ |--INVITE(sendonly)->|
+ |<---200(recvonly)---|
+ |---------ACK------->|
+ : :
+ |<-INVITE(inactive)--|
+ |----200(inactive)-->|
+ |<--------ACK--------|
+ : :
+ |--INVITE(recvonly)->|
+ |<---200(sendonly)---|
+ |---------ACK------->|
+ : :
+ |<-INVITE(sendrecv)--|
+ |----200(sendrecv)-->|
+ |<--------ACK--------|
+ : :
+ |--------INFO------->|
+ |<--------200--------|
+ : :
+ |---------BYE------->|
+ |<--------200--------|
+*/
+
+int test_call_hold(struct context *ctx)
+{
+ BEGIN();
+
+ struct endpoint *a = &ctx->a, *b = &ctx->b;
+ struct call *a_call = a->call, *b_call = b->call;
+ struct event *e;
+
+ a_call->sdp =
+ "m=audio 5008 RTP/AVP 0 8\n"
+ "m=video 6008 RTP/AVP 30\n";
+ b_call->sdp =
+ "m=audio 5010 RTP/AVP 8\n"
+ "a=rtcp:5011\n"
+ "m=video 6010 RTP/AVP 30\n"
+ "a=rtcp:6011\n";
+
+ TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+ INVITE(a, a_call, a_call->nh,
+ TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+ SOATAG_USER_SDP_STR(a_call->sdp),
+ TAG_END());
+
+ run_ab_until(ctx, -1, until_ready, -1, accept_call);
+
+ /*
+ Client transitions:
+ INIT -(C1)-> CALLING: nua_invite(), nua_i_state
+ CALLING -(C2)-> PROCEEDING: nua_r_invite, nua_i_state
+ PROCEEDING -(C3+C4)-> READY: nua_r_invite, nua_i_state
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+ TEST_1(is_offer_sent(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+ TEST_1(is_answer_recv(e->data->e_tags));
+ TEST(audio_activity(e->data->e_tags), SOA_ACTIVE_SENDRECV);
+ TEST_1(!e->next);
+ free_events_in_list(ctx, a->events);
+
+ TEST_1(nua_handle_has_active_call(a_call->nh));
+ TEST_1(!nua_handle_has_call_on_hold(a_call->nh));
+
+ /*
+ Server transitions:
+ INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
+ RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state
+ EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state
+ COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+ TEST(e->data->e_status, 100);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+ TEST_1(is_offer_recv(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+ TEST_1(is_answer_sent(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+ TEST(audio_activity(e->data->e_tags), SOA_ACTIVE_SENDRECV);
+ TEST_1(!e->next);
+
+ TEST_1(nua_handle_has_active_call(b_call->nh));
+ TEST_1(!nua_handle_has_call_on_hold(b_call->nh));
+
+ free_events_in_list(ctx, b->events);
+
+ /*
+ : :
+ |--INVITE(sendonly)->|
+ |<---200(recvonly)---|
+ |---------ACK------->|
+ : :
+ */
+
+ if (print_headings)
+ printf("TEST NUA-7.1: put B on hold\n");
+
+ /* Put B on hold */
+ INVITE(a, a_call, a_call->nh, SOATAG_HOLD("audio"),
+ SIPTAG_SUBJECT_STR("hold b"),
+ TAG_END());
+ run_ab_until(ctx, -1, until_ready, -1, until_ready);
+
+ /* Client transitions:
+ READY -(C1)-> CALLING: nua_invite(), nua_i_state
+ CALLING -(C3a+C4)-> READY: nua_r_invite, nua_i_state
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+ TEST_1(is_offer_sent(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+ TEST_1(is_answer_recv(e->data->e_tags));
+ TEST(audio_activity(e->data->e_tags), SOA_ACTIVE_SENDONLY);
+ TEST_1(!e->next);
+
+ TEST_1(nua_handle_has_active_call(a_call->nh));
+ TEST_1(nua_handle_has_call_on_hold(a_call->nh));
+
+ free_events_in_list(ctx, a->events);
+
+ /*
+ Server transitions:
+ READY -(S3a)-> COMPLETED: nua_i_invite, <auto-answer>, nua_i_state
+ COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+ TEST(e->data->e_status, 200);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+ TEST_1(is_answer_sent(e->data->e_tags));
+ TEST(audio_activity(e->data->e_tags), SOA_ACTIVE_RECVONLY);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+ TEST(audio_activity(e->data->e_tags), SOA_ACTIVE_RECVONLY);
+ TEST_1(!e->next);
+
+ TEST_1(nua_handle_has_active_call(b_call->nh));
+ TEST_1(!nua_handle_has_call_on_hold(b_call->nh));
+
+ free_events_in_list(ctx, b->events);
+
+ if (print_headings)
+ printf("TEST NUA-7.1: PASSED\n");
+
+ /* ------------------------------------------------------------------------ */
+ /*
+ : :
+ |<-INVITE(inactive)--|
+ |----200(inactive)-->|
+ |<--------ACK--------|
+ : :
+ */
+
+ if (print_headings)
+ printf("TEST NUA-7.2: put A on hold\n");
+
+ /* Put A on hold, too. */
+ INVITE(b, b_call, b_call->nh, SOATAG_HOLD("audio"),
+ SIPTAG_SUBJECT_STR("hold a"),
+ TAG_END());
+ run_ab_until(ctx, -1, until_ready, -1, until_ready);
+
+ /* Client transitions:
+ READY -(C1)-> CALLING: nua_invite(), nua_i_state
+ CALLING -(C3a+C4)-> READY: nua_r_invite, nua_i_state
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+ TEST_1(is_offer_sent(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+ TEST_1(is_answer_recv(e->data->e_tags));
+ TEST(audio_activity(e->data->e_tags), SOA_ACTIVE_INACTIVE);
+ TEST(video_activity(e->data->e_tags), SOA_ACTIVE_SENDRECV);
+ TEST_1(!e->next);
+
+ TEST_1(nua_handle_has_active_call(b_call->nh));
+ TEST_1(nua_handle_has_call_on_hold(b_call->nh));
+
+ free_events_in_list(ctx, b->events);
+
+ /*
+ Server transitions:
+ READY -(S3a)-> COMPLETED: nua_i_invite, <auto-answer>, nua_i_state
+ COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_invite);
+ TEST(e->data->e_status, 200);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+ TEST_1(is_answer_sent(e->data->e_tags));
+ TEST(audio_activity(e->data->e_tags), SOA_ACTIVE_INACTIVE);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+ TEST(audio_activity(e->data->e_tags), SOA_ACTIVE_INACTIVE);
+ TEST(video_activity(e->data->e_tags), SOA_ACTIVE_SENDRECV);
+ TEST_1(!e->next);
+
+ TEST_1(nua_handle_has_active_call(a_call->nh));
+ TEST_1(nua_handle_has_call_on_hold(a_call->nh));
+
+ free_events_in_list(ctx, a->events);
+
+ if (print_headings)
+ printf("TEST NUA-7.2: PASSED\n");
+
+ /* ------------------------------------------------------------------------ */
+ /*
+ : :
+ |--INVITE(recvonly)->|
+ |<---200(sendonly)---|
+ |---------ACK------->|
+ : :
+ */
+
+ if (print_headings)
+ printf("TEST NUA-7.3: resume B\n");
+
+ /* Resume B from hold */
+ INVITE(a, a_call, a_call->nh, SOATAG_HOLD(NULL),
+ SIPTAG_SUBJECT_STR("resume b"),
+ TAG_END());
+ run_ab_until(ctx, -1, until_ready, -1, until_ready);
+
+ /* Client transitions:
+ READY -(C1)-> CALLING: nua_invite(), nua_i_state
+ CALLING -(C3a+C4)-> READY: nua_r_invite, nua_i_state
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+ TEST_1(is_offer_sent(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+ TEST_1(is_answer_recv(e->data->e_tags));
+ TEST(audio_activity(e->data->e_tags), SOA_ACTIVE_RECVONLY);
+ TEST(video_activity(e->data->e_tags), SOA_ACTIVE_SENDRECV);
+ TEST_1(!e->next);
+ free_events_in_list(ctx, a->events);
+
+ TEST_1(nua_handle_has_active_call(a_call->nh));
+ TEST_1(!nua_handle_has_call_on_hold(a_call->nh));
+
+ /*
+ Server transitions:
+ READY -(S3a)-> COMPLETED: nua_i_invite, <auto-answer>, nua_i_state
+ COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+ TEST(e->data->e_status, 200);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+ TEST_1(is_answer_sent(e->data->e_tags));
+ TEST(audio_activity(e->data->e_tags), SOA_ACTIVE_SENDONLY);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+ TEST(audio_activity(e->data->e_tags), SOA_ACTIVE_SENDONLY);
+ TEST(video_activity(e->data->e_tags), SOA_ACTIVE_SENDRECV);
+ TEST_1(!e->next);
+
+ TEST_1(nua_handle_has_active_call(b_call->nh));
+ TEST_1(nua_handle_has_call_on_hold(b_call->nh));
+
+ free_events_in_list(ctx, b->events);
+
+ if (print_headings)
+ printf("TEST NUA-7.3: PASSED\n");
+
+ /* ------------------------------------------------------------------------ */
+ /*
+ : :
+ |<-INVITE(sendrecv)--|
+ |----200(sendrecv)-->|
+ |<--------ACK--------|
+ : :
+ */
+
+ if (print_headings)
+ printf("TEST NUA-7.4: resume A\n");
+
+ /* Resume A on hold, too. */
+ INVITE(b, b_call, b_call->nh, SOATAG_HOLD(""),
+ SIPTAG_SUBJECT_STR("TEST NUA-7.4: resume A"),
+ TAG_END());
+ run_ab_until(ctx, -1, until_ready, -1, until_ready);
+
+ /* Client transitions:
+ READY -(C1)-> CALLING: nua_invite(), nua_i_state
+ CALLING -(C3a+C4)-> READY: nua_r_invite, nua_i_state
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+ TEST_1(is_offer_sent(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+ TEST_1(is_answer_recv(e->data->e_tags));
+ TEST(audio_activity(e->data->e_tags), SOA_ACTIVE_SENDRECV);
+ TEST(video_activity(e->data->e_tags), SOA_ACTIVE_SENDRECV);
+ TEST_1(!e->next);
+ free_events_in_list(ctx, b->events);
+
+ TEST_1(nua_handle_has_active_call(a_call->nh));
+ TEST_1(!nua_handle_has_call_on_hold(a_call->nh));
+
+ /*
+ Server transitions:
+ READY -(S3a)-> COMPLETED: nua_i_invite, <auto-answer>, nua_i_state
+ COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_invite);
+ TEST(e->data->e_status, 200);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+ TEST_1(is_answer_sent(e->data->e_tags));
+ TEST(audio_activity(e->data->e_tags), SOA_ACTIVE_SENDRECV);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+ TEST(audio_activity(e->data->e_tags), SOA_ACTIVE_SENDRECV);
+ TEST(video_activity(e->data->e_tags), SOA_ACTIVE_SENDRECV);
+ TEST_1(!e->next);
+
+ TEST_1(nua_handle_has_active_call(b_call->nh));
+ TEST_1(!nua_handle_has_call_on_hold(b_call->nh));
+
+ free_events_in_list(ctx, a->events);
+
+ if (print_headings)
+ printf("TEST NUA-7.4: PASSED\n");
+
+ /* ---------------------------------------------------------------------- */
+ /*
+ A B
+ |--------INFO------->|
+ |<--------200--------|
+ */
+ if (print_headings)
+ printf("TEST NUA-7.5: send INFO\n");
+
+ INFO(a, a_call, a_call->nh, TAG_END());
+ run_a_until(ctx, -1, save_until_final_response);
+ /* XXX - B should get a nua_i_info event with 405 */
+
+ /* A sent INFO, receives 405 */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_info);
+ TEST(e->data->e_status, 405);
+ TEST_1(!e->next);
+ free_events_in_list(ctx, a->events);
+
+#if 0 /* XXX */
+ /* B received INFO */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_info);
+ TEST(e->data->e_status, 405);
+ TEST_1(!e->next);
+ free_events_in_list(ctx, b->events);
+#endif
+
+ /* Add INFO to allowed methods */
+ nua_set_hparams(b_call->nh, NUTAG_ALLOW("INFO, PUBLISH"), TAG_END());
+ run_b_until(ctx, nua_r_set_params, until_final_response);
+
+ INFO(a, a_call, a_call->nh, TAG_END());
+ run_ab_until(ctx, -1, save_until_final_response, -1, save_until_received);
+
+ /* A sent INFO, receives 200 */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_info);
+ TEST(e->data->e_status, 200);
+ TEST_1(!e->next);
+ free_events_in_list(ctx, a->events);
+
+ /* B received INFO */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_info);
+ TEST(e->data->e_status, 200);
+ TEST_1(!e->next);
+ free_events_in_list(ctx, b->events);
+
+ if (print_headings)
+ printf("TEST NUA-7.5: PASSED\n");
+
+ /* ------------------------------------------------------------------------ */
+ /*
+ : :
+ |<------INVITE-------|
+ |--------200-------->|
+ |<--------ACK--------|
+ : :
+ */
+
+ if (print_headings)
+ printf("TEST NUA-7.6: re-INVITE without auto-ack\n");
+
+ /* Turn off auto-ack */
+ nua_set_hparams(b_call->nh, NUTAG_AUTOACK(0), TAG_END());
+ run_b_until(ctx, nua_r_set_params, until_final_response);
+
+ INVITE(b, b_call, b_call->nh, SOATAG_HOLD(""),
+ SIPTAG_SUBJECT_STR("TEST NUA-7.6: re-INVITE without auto-ack"),
+ TAG_END());
+ run_ab_until(ctx, -1, until_ready, -1, ack_when_completing);
+
+ /* Client transitions:
+ READY -(C1)-> CALLING: nua_invite(), nua_i_state
+ CALLING -(C3a)-> COMPLETING: nua_r_invite, nua_i_state
+ COMPLETING -(C4)-> READY: nua_ack(), nua_i_state
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+ TEST_1(is_offer_sent(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_completing); /* COMPLETING */
+ TEST_1(is_answer_recv(e->data->e_tags));
+ TEST(audio_activity(e->data->e_tags), SOA_ACTIVE_SENDRECV);
+ TEST(video_activity(e->data->e_tags), SOA_ACTIVE_SENDRECV);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+ TEST_1(!e->next);
+ free_events_in_list(ctx, b->events);
+
+ /*
+ Server transitions:
+ READY -(S3a)-> COMPLETED: nua_i_invite, <auto-answer>, nua_i_state
+ COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_invite);
+ TEST(e->data->e_status, 200);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+ TEST_1(is_answer_sent(e->data->e_tags));
+ TEST(audio_activity(e->data->e_tags), SOA_ACTIVE_SENDRECV);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+ TEST(audio_activity(e->data->e_tags), SOA_ACTIVE_SENDRECV);
+ TEST(video_activity(e->data->e_tags), SOA_ACTIVE_SENDRECV);
+ TEST_1(!e->next);
+ free_events_in_list(ctx, a->events);
+
+ if (print_headings)
+ printf("TEST NUA-7.6: PASSED\n");
+
+
+ /* ---------------------------------------------------------------------- */
+ /*
+ A B
+ |---------BYE------->|
+ |<--------200--------|
+ */
+
+ if (print_headings)
+ printf("TEST NUA-7.6: terminate call\n");
+
+ BYE(a, a_call, a_call->nh, TAG_END());
+ run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
+
+ /*
+ Transitions of A:
+ READY --(T2)--> TERMINATING: nua_bye()
+ TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_bye);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+ free_events_in_list(ctx, a->events);
+
+ /* Transitions of B:
+ READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_bye);
+ TEST(e->data->e_status, 200);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+ free_events_in_list(ctx, b->events);
+
+ if (print_headings)
+ printf("TEST NUA-7.6: PASSED\n");
+
+ nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+ nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+ END();
+}
+
+/*
+ INVITE without auto-ack
+ X
+ | |
+ |-------INVITE------>|
+ |<--------200--------|
+ | |
+ |---------ACK------->|
+*/
+int ack_when_completing(CONDITION_PARAMS)
+{
+ if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+ return 0;
+
+ save_event_in_list(ctx, event, ep, call);
+
+ switch (callstate(tags)) {
+ case nua_callstate_completing:
+ ACK(ep, call, nh, TAG_END());
+ return 0;
+ case nua_callstate_ready:
+ return 1;
+ case nua_callstate_terminated:
+ if (call)
+ nua_handle_destroy(call->nh), call->nh = NULL;
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+/* ======================================================================== */
+/* test_reinvite message sequence looks like this:
+
+ A B
+ | |
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ | |
+ |<----180 Ringing----|
+ | |
+ |<--------200--------|
+ |---------ACK------->|
+ : :
+ |<----re-INVITE------|
+ |<-------BYE---------|
+ |--------200-------->|
+ |-----487-INVITE---->|
+ |<--------ACK--------|
+*/
+
+int accept_no_save(CONDITION_PARAMS);
+int ringing_until_terminated(CONDITION_PARAMS);
+int bye_when_ringing(CONDITION_PARAMS);
+
+int test_reinvite(struct context *ctx)
+{
+ BEGIN();
+
+ struct endpoint *a = &ctx->a, *b = &ctx->b;
+ struct call *a_call = a->call, *b_call = b->call;
+
+ if (print_headings)
+ printf("TEST NUA-7.7: Test re-INVITE and BYE\n");
+
+ a_call->sdp = "m=audio 5008 RTP/AVP 0 8\n";
+ b_call->sdp = "m=audio 5010 RTP/AVP 8\n";
+
+ TEST_1(a_call->nh =
+ nua_handle(a->nua, a_call,
+ SIPTAG_FROM_STR("Alice <sip:alice at example.com>"),
+ SIPTAG_TO(b->to),
+ NUTAG_AUTOANSWER(0),
+ TAG_END()));
+ INVITE(a, a_call, a_call->nh,
+ TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+ SOATAG_USER_SDP_STR(a_call->sdp),
+ TAG_END());
+
+ run_ab_until(ctx, -1, accept_no_save, -1, accept_no_save);
+
+ TEST_1(nua_handle_has_active_call(a_call->nh));
+ TEST_1(nua_handle_has_active_call(b_call->nh));
+
+ free_events_in_list(ctx, a->events);
+ free_events_in_list(ctx, b->events);
+
+/*
+ A B
+ |<----re-INVITE------|
+ |<------CANCEL-------|
+ |<-------BYE---------|
+ |-----200-CANCEL---->|
+ |------200-BYE------>|
+ |-----487-INVITE---->|
+ |<--------ACK--------|
+*/
+
+ /* re-INVITE A, send BYE after receiving 180 */
+ INVITE(b, b_call, b_call->nh,
+ SIPTAG_SUBJECT_STR("re-INVITE"),
+ TAG_END());
+ /* Run until both a and b has terminated their call */
+ run_ab_until(ctx, -1, ringing_until_terminated, -1, bye_when_ringing);
+
+#if notyet
+ struct event *e;
+
+ /* XXX - check events later - now we are happy that calls get terminated */
+ /* Client events:
+ READY -(C1)-> CALLING: nua_invite(), nua_i_state
+ CALLING --(C2)--> PROCEEDING: nua_r_invite, nua_i_state, nua_bye()
+ PROCEEDING--((C3a+C4)-> READY: nua_r_invite, nua_i_state
+ READY --(T2)--> TERMINATING: nua_bye()
+ TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+ TEST_1(is_offer_sent(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 180);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminating); /* READY */
+ /* Now we can receive events, in any possible order */
+ /* XXX */
+ TEST_1(e = e->next);
+
+ TEST_1(!nua_handle_has_active_call(a_call->nh));
+
+ /*
+ Server transitions:
+ READY --(T2)--> CTERMINATING: nua_bye()
+ TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
+ READY -(S3a)-> COMPLETED: nua_i_invite, <auto-answer>, nua_i_state
+ COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+ TEST(e->data->e_status, 200);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+ TEST_1(is_answer_sent(e->data->e_tags));
+ TEST(audio_activity(e->data->e_tags), SOA_ACTIVE_RECVONLY);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+ TEST(audio_activity(e->data->e_tags), SOA_ACTIVE_RECVONLY);
+ TEST_1(!e->next);
+
+ TEST_1(nua_handle_has_active_call(b_call->nh));
+ TEST_1(!nua_handle_has_call_on_hold(b_call->nh));
+
+#endif
+
+ if (print_headings)
+ printf("TEST NUA-7.7: PASSED\n");
+
+ free_events_in_list(ctx, a->events);
+ free_events_in_list(ctx, b->events);
+
+ nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+ nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+ if (print_headings)
+ printf("TEST NUA-7.8: PASSED\n");
+
+ END();
+}
+
+/*
+ Accept INVITE
+ X
+ | |
+ |-------INVITE------>|
+ |<--------200--------|
+ | |
+ |---------ACK------->|
+*/
+int accept_no_save(CONDITION_PARAMS)
+{
+ if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+ return 0;
+
+ switch (callstate(tags)) {
+ case nua_callstate_received:
+ RESPOND(ep, call, nh, SIP_200_OK,
+ TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)),
+ TAG_END());
+ return 0;
+ case nua_callstate_ready:
+ return 1;
+ case nua_callstate_terminated:
+ if (call)
+ nua_handle_destroy(call->nh), call->nh = NULL;
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+int ringing_until_terminated(CONDITION_PARAMS)
+{
+ if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+ return 0;
+
+ save_event_in_list(ctx, event, ep, call);
+
+ switch (callstate(tags)) {
+ case nua_callstate_received:
+ RESPOND(ep, call, nh, SIP_180_RINGING, TAG_END());
+ return 0;
+ case nua_callstate_ready:
+ return 0;
+ case nua_callstate_terminated:
+ if (call)
+ nua_handle_destroy(call->nh), call->nh = NULL;
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+int test_reinvites(struct context *ctx)
+{
+ int retval = 0;
+
+ if (print_headings)
+ printf("TEST NUA-7: Test call hold and re-INVITEs\n");
+
+ retval = test_call_hold(ctx);
+
+ if (retval == 0)
+ retval |= test_reinvite(ctx);
+
+ if (print_headings && retval == 0)
+ printf("TEST NUA-7: PASSED\n");
+
+ return retval;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_call_reject.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_call_reject.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,946 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_call_reject.c
+ * @brief NUA-4 tests: call reject cases
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti Mela at nokia.com>
+ *
+ * @date Created: Wed Aug 17 12:12:12 EEST 2005 ppessi
+ */
+
+#include "config.h"
+
+#include "test_nua.h"
+#include <sofia-sip/su_tag_class.h>
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+#define __func__ "test_reject"
+#endif
+
+/* ======================================================================== */
+/*
+ A reject-1 B
+ | |
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ | |
+ |<--------486--------|
+ |---------ACK------->|
+*/
+int reject_1(CONDITION_PARAMS)
+{
+ if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+ return 0;
+
+ save_event_in_list(ctx, event, ep, call);
+
+ switch (callstate(tags)) {
+ case nua_callstate_received:
+ RESPOND(ep, call, nh, SIP_486_BUSY_HERE, TAG_END());
+ return 0;
+ case nua_callstate_terminated:
+ if (call)
+ nua_handle_destroy(call->nh), call->nh = NULL;
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+
+int test_reject_a(struct context *ctx)
+{
+ BEGIN();
+
+ struct endpoint *a = &ctx->a, *b = &ctx->b;
+ struct call *a_call = a->call, *b_call = b->call;
+ struct event *e;
+ sip_t const *sip;
+
+ if (print_headings)
+ printf("TEST NUA-4.1: reject before ringing\n");
+
+ /*
+ A reject-1 B
+ | |
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ | |
+ |<--------486--------|
+ |---------ACK------->|
+ */
+
+ a_call->sdp = "m=audio 5008 RTP/AVP 8";
+ b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
+
+ TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+ INVITE(a, a_call, a_call->nh,
+ TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+ SIPTAG_SUBJECT_STR("reject-1"),
+ SIPTAG_CONTACT_STR("sip:a at 127.0.0.1"),
+ SOATAG_USER_SDP_STR(a_call->sdp),
+ TAG_END());
+ run_ab_until(ctx, -1, until_terminated, -1, reject_1);
+
+ /*
+ Client transitions in reject-1:
+ INIT -(C1)-> CALLING -(C6a)-> TERMINATED
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+ TEST_1(is_offer_sent(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 486);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+
+ /*
+ Server transitions in reject-1:
+ INIT -(S1)-> RECEIVED -(S6a)-> TERMINATED
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+ TEST(e->data->e_status, 100);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(sip->sip_contact); TEST_1(!sip->sip_contact->m_next);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+ TEST_1(is_offer_recv(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, a->events);
+ nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+ free_events_in_list(ctx, b->events);
+ nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+ if (print_headings)
+ printf("TEST NUA-4.1: PASSED\n");
+
+ END();
+}
+
+/*
+ A reject-2 B
+ | |
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ | |
+ |<----180 Ringing----|
+ | |
+ |<--------602--------|
+ |---------ACK------->|
+*/
+int reject_2(CONDITION_PARAMS)
+{
+ if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+ return 0;
+
+ save_event_in_list(ctx, event, ep, call);
+
+ switch (callstate(tags)) {
+ case nua_callstate_received:
+ RESPOND(ep, call, nh, SIP_180_RINGING, TAG_END());
+ return 0;
+ case nua_callstate_early:
+ RESPOND(ep, call, nh, 602, "Rejected 2", TAG_END());
+ return 0;
+ case nua_callstate_terminated:
+ if (call)
+ nua_handle_destroy(call->nh), call->nh = NULL;
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+int test_reject_b(struct context *ctx)
+{
+ BEGIN();
+
+ struct endpoint *a = &ctx->a, *b = &ctx->b;
+ struct call *a_call = a->call, *b_call = b->call;
+ struct event *e;
+
+ /* ------------------------------------------------------------------------ */
+ /*
+ A reject-2 B
+ | |
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ | |
+ |<----180 Ringing----|
+ | |
+ |<--------602--------|
+ |---------ACK------->|
+ */
+
+ if (print_headings)
+ printf("TEST NUA-4.2: reject after ringing\n");
+
+ a_call->sdp = "m=audio 5008 RTP/AVP 8";
+ b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
+
+ /* Make call reject-2 */
+ TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+ INVITE(a, a_call, a_call->nh,
+ TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+ SIPTAG_SUBJECT_STR("reject-2"),
+ SOATAG_USER_SDP_STR(a_call->sdp),
+ TAG_END());
+ run_ab_until(ctx, -1, until_terminated, -1, reject_2);
+
+ /*
+ Client transitions in reject-2:
+ INIT -(C1)-> CALLING -(C2)-> PROCEEDING -(C6b)-> TERMINATED
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+ TEST_1(is_offer_sent(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 602);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+
+ /*
+ Server transitions in reject-2:
+ INIT -(S1)-> RECEIVED -(S2)-> EARLY -(S6a)-> TERMINATED
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+ TEST(e->data->e_status, 100);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+ TEST_1(is_offer_recv(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, a->events);
+ nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+ free_events_in_list(ctx, b->events);
+ nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+ if (print_headings)
+ printf("TEST NUA-4.2: PASSED\n");
+
+ END();
+}
+
+/* ------------------------------------------------------------------------ */
+
+int reject_302(CONDITION_PARAMS);
+int reject_604(CONDITION_PARAMS);
+
+/*
+ A reject-302 B
+ | |
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ | |
+ |<-----302 Other-----|
+ |--------ACK-------->|
+ | |
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ | |
+ |<----180 Ringing----|
+ | |
+ |<---604 Nowhere-----|
+ |--------ACK-------->|
+*/
+int reject_302(CONDITION_PARAMS)
+{
+ if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+ return 0;
+
+ save_event_in_list(ctx, event, ep, call);
+
+ switch (callstate(tags)) {
+ case nua_callstate_received:
+ {
+ sip_contact_t m[1];
+ *m = *ep->contact;
+ m->m_url->url_user = "302";
+ RESPOND(ep, call, nh, SIP_302_MOVED_TEMPORARILY,
+ SIPTAG_CONTACT(m), TAG_END());
+ }
+ return 0;
+ case nua_callstate_terminated:
+ if (call)
+ nua_handle_destroy(call->nh), call->nh = NULL;
+ ep->next_condition = reject_604;
+ return 0;
+ default:
+ return 0;
+ }
+}
+
+int reject_604(CONDITION_PARAMS)
+{
+ if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+ return 0;
+
+ save_event_in_list(ctx, event, ep, call);
+
+ switch (callstate(tags)) {
+ case nua_callstate_received:
+ RESPOND(ep, call, nh, SIP_180_RINGING, TAG_END());
+ return 0;
+ case nua_callstate_early:
+ RESPOND(ep, call, nh, SIP_604_DOES_NOT_EXIST_ANYWHERE, TAG_END());
+ return 0;
+ case nua_callstate_terminated:
+ if (call)
+ nua_handle_destroy(call->nh), call->nh = NULL;
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+int test_reject_302(struct context *ctx)
+{
+ BEGIN();
+
+ struct endpoint *a = &ctx->a, *b = &ctx->b;
+ struct call *a_call = a->call, *b_call = b->call;
+ struct event *e;
+
+ /* Make call reject-3 */
+ if (print_headings)
+ printf("TEST NUA-4.3: redirect then reject\n");
+
+ a_call->sdp = "m=audio 5008 RTP/AVP 8";
+ b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
+
+ TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+ INVITE(a, a_call, a_call->nh,
+ TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+ SIPTAG_SUBJECT_STR("reject-3"),
+ SOATAG_USER_SDP_STR(a_call->sdp),
+ TAG_END());
+ run_ab_until(ctx, -1, until_terminated, -1, reject_302);
+
+ /*
+ A reject-3 B
+ | |
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ | |
+ |<-----302 Other-----|
+ |--------ACK-------->|
+ | |
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ | |
+ |<----180 Ringing----|
+ | |
+ |<---604 Nowhere-----|
+ |--------ACK-------->|
+ */
+
+ /*
+ Client transitions in reject-3:
+ INIT -(C1)-> PROCEEDING -(C6a)-> TERMINATED/INIT
+ INIT -(C1)-> CALLING -(C2)-> PROCEEDING -(C6b)-> TERMINATED
+ */
+
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+ TEST_1(is_offer_sent(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 100);
+ TEST(sip_object(e->data->e_msg)->sip_status->st_status, 302);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+ TEST_1(is_offer_sent(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 180);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 604);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+
+ /*
+ Server transitions:
+ INIT -(S1)-> RECEIVED -(S6a)-> TERMINATED/INIT
+ INIT -(S1)-> RECEIVED -(S2)-> EARLY -(S6b)-> TERMINATED
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+ TEST(e->data->e_status, 100);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+ TEST_1(is_offer_recv(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_invite);
+ TEST(e->data->e_status, 100);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+ TEST_1(is_offer_recv(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, a->events);
+ nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+ free_events_in_list(ctx, b->events);
+ nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+ if (print_headings)
+ printf("TEST NUA-4.3: PASSED\n");
+
+ END();
+}
+
+/* ------------------------------------------------------------------------ */
+
+/* Reject call with 407, then 401 */
+
+int reject_407(CONDITION_PARAMS);
+int reject_401(CONDITION_PARAMS);
+int authenticate_call(CONDITION_PARAMS);
+int reject_403(CONDITION_PARAMS);
+
+/*
+ A reject-401 B
+ | |
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ |<--------407--------|
+ |---------ACK------->|
+ | |
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ | |
+ |<----180 Ringing----|
+ | |
+ |<--------401--------|
+ |---------ACK------->|
+ | |
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ |<-------403---------|
+ |--------ACK-------->|
+*/
+
+int reject_407(CONDITION_PARAMS)
+{
+ if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+ return 0;
+
+ save_event_in_list(ctx, event, ep, call);
+
+ switch (callstate(tags)) {
+ case nua_callstate_received:
+ RESPOND(ep, call, nh, SIP_407_PROXY_AUTH_REQUIRED,
+ SIPTAG_PROXY_AUTHENTICATE_STR("Digest realm=\"test_nua\", "
+ "nonce=\"nsdhfuds\", algorithm=MD5, "
+ "qop=\"auth-int\""),
+ TAG_END());
+ return 0;
+ case nua_callstate_terminated:
+ if (call)
+ nua_handle_destroy(call->nh), call->nh = NULL;
+ ep->next_condition = reject_401;
+ return 0;
+ default:
+ return 0;
+ }
+}
+
+int reject_401(CONDITION_PARAMS)
+{
+ if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+ return 0;
+
+ save_event_in_list(ctx, event, ep, call);
+
+ switch (callstate(tags)) {
+ case nua_callstate_received:
+ RESPOND(ep, call, nh, SIP_180_RINGING, TAG_END());
+ return 0;
+ case nua_callstate_early:
+ RESPOND(ep, call, nh, SIP_401_UNAUTHORIZED,
+ SIPTAG_WWW_AUTHENTICATE_STR("Digest realm=\"test_nua\", "
+ "nonce=\"nsdhfuds\", algorithm=MD5, "
+ "qop=\"auth\""),
+ TAG_END());
+ return 0;
+ case nua_callstate_terminated:
+ if (call)
+ nua_handle_destroy(call->nh), call->nh = NULL;
+ ep->next_condition = reject_403;
+ return 0;
+ default:
+ return 0;
+ }
+}
+
+int reject_403(CONDITION_PARAMS)
+{
+ if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+ return 0;
+
+ save_event_in_list(ctx, event, ep, call);
+
+ switch (callstate(tags)) {
+ case nua_callstate_received:
+ RESPOND(ep, call, nh, SIP_403_FORBIDDEN, TAG_END());
+ return 0;
+ case nua_callstate_terminated:
+ if (call)
+ nua_handle_destroy(call->nh), call->nh = NULL;
+ ep->next_condition = NULL;
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+int authenticate_call(CONDITION_PARAMS)
+{
+ if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+ return 0;
+
+ save_event_in_list(ctx, event, ep, call);
+
+ if (event == nua_r_invite && status == 401) {
+ AUTHENTICATE(ep, call, nh, NUTAG_AUTH("Digest:\"test_nua\":jaska:secret"),
+ SIPTAG_SUBJECT_STR("Got 401"),
+ TAG_END());
+ return 0;
+ }
+
+ if (event == nua_r_invite && status == 407) {
+ AUTHENTICATE(ep, call, nh, NUTAG_AUTH("Digest:\"test_nua\":erkki:secret"),
+ SIPTAG_SUBJECT_STR("Got 407"),
+ TAG_END());
+ return 0;
+ }
+
+ switch (callstate(tags)) {
+ case nua_callstate_terminated:
+ if (call)
+ nua_handle_destroy(call->nh), call->nh = NULL;
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+int test_reject_401(struct context *ctx)
+{
+ BEGIN();
+
+ struct endpoint *a = &ctx->a, *b = &ctx->b;
+ struct call *a_call = a->call, *b_call = b->call;
+ struct event const *e;
+ sip_t const *sip;
+
+ if (print_headings)
+ printf("TEST NUA-4.4: challenge then reject\n");
+
+ a_call->sdp = "m=audio 5008 RTP/AVP 8";
+ b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
+
+ TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+ INVITE(a, a_call, a_call->nh,
+ TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+ SIPTAG_SUBJECT_STR("reject-401"),
+ SOATAG_USER_SDP_STR(a_call->sdp),
+ TAG_END());
+ run_ab_until(ctx, -1, authenticate_call, -1, reject_407);
+
+ /*
+ Client transitions in reject-3:
+ INIT -(C1)-> CALLING -(C2)-> PROCEEDING -(C6b)-> TERMINATED/INIT
+ INIT -(C1)-> CALLING -(C6a)-> TERMINATED
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+ TEST_1(is_offer_sent(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(sip_object(e->data->e_msg)->sip_status->st_status, 407);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+ TEST_1(is_offer_sent(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 180);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 401);
+ TEST(sip_object(e->data->e_msg)->sip_status->st_status, 401);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+ TEST_1(is_offer_sent(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 403);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, a->events);
+
+ /*
+ Server transitions:
+ INIT -(S1)-> RECEIVED -(S6a)-> TERMINATED/INIT
+ INIT -(S1)-> RECEIVED -(S2)-> EARLY -(S6b)-> TERMINATED/INIT
+ INIT -(S1)-> RECEIVED -(S6a)-> TERMINATED
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(sip->sip_subject);
+ TEST_S(sip->sip_subject->g_value, "reject-401");
+ TEST(e->data->e_status, 100);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+ TEST_1(is_offer_recv(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_invite);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(sip->sip_subject);
+ TEST_S(sip->sip_subject->g_value, "Got 407");
+ TEST_1(sip->sip_proxy_authorization);
+ TEST(e->data->e_status, 100);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+ TEST_1(is_offer_recv(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_invite);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(sip->sip_subject);
+ TEST_S(sip->sip_subject->g_value, "Got 401");
+ TEST_1(sip->sip_authorization);
+ TEST_1(sip->sip_proxy_authorization);
+ TEST(e->data->e_status, 100);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+ TEST_1(is_offer_recv(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, b->events);
+
+ nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+ nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+ if (print_headings)
+ printf("TEST NUA-4.4: PASSED\n");
+
+ END();
+}
+
+/* ------------------------------------------------------------------------ */
+
+/* Reject call with 401 and bad challenge */
+
+/*
+ A reject-401-aka B
+ | |
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ |<--------401--------|
+ |---------ACK------->|
+*/
+
+int reject_401_aka(CONDITION_PARAMS)
+{
+ if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+ return 0;
+
+ save_event_in_list(ctx, event, ep, call);
+
+ switch (callstate(tags)) {
+ case nua_callstate_received:
+ RESPOND(ep, call, nh, SIP_401_UNAUTHORIZED,
+ /* Send a challenge that we do not grok */
+ SIPTAG_WWW_AUTHENTICATE_STR("Digest realm=\"test_nua\", "
+ "nonce=\"nsdhfuds\", algorithm=SHA0-AKAv6, "
+ "qop=\"auth\""),
+ TAG_END());
+ return 0;
+ case nua_callstate_terminated:
+ if (call)
+ nua_handle_destroy(call->nh), call->nh = NULL;
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+int test_reject_401_aka(struct context *ctx)
+{
+ BEGIN();
+
+ struct endpoint *a = &ctx->a, *b = &ctx->b;
+ struct call *a_call = a->call, *b_call = b->call;
+ struct event const *e;
+ sip_t const *sip;
+
+ if (print_headings)
+ printf("TEST NUA-4.6: invalid challenge \n");
+
+ a_call->sdp = "m=audio 5008 RTP/AVP 8";
+ b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
+
+ TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+ INVITE(a, a_call, a_call->nh,
+ TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+ SIPTAG_SUBJECT_STR("reject-401-aka"),
+ SOATAG_USER_SDP_STR(a_call->sdp),
+ TAG_END());
+
+ run_ab_until(ctx, -1, until_terminated, -1, reject_401_aka);
+
+ /*
+ Client transitions
+ INIT -(C1)-> CALLING -(C6a)-> TERMINATED/INIT
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+ TEST_1(is_offer_sent(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(sip_object(e->data->e_msg)->sip_status->st_status, 401);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, a->events);
+
+ /*
+ Server transitions:
+ INIT -(S1)-> RECEIVED -(S6a)-> TERMINATED
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST(e->data->e_status, 100);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+ TEST_1(is_offer_recv(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, b->events);
+
+ nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+ nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+ if (print_headings)
+ printf("TEST NUA-4.6: PASSED\n");
+
+ END();
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+int test_mime_negotiation(struct context *ctx)
+{
+ BEGIN();
+
+ struct endpoint *a = &ctx->a, *b = &ctx->b;
+ struct call *a_call = a->call, *b_call = b->call;
+ struct event *e;
+ sip_t const *sip;
+
+ /* Make call reject-3 */
+ if (print_headings)
+ printf("TEST NUA-4.5: check for rejections of invalid requests\n");
+
+ a_call->sdp = "m=audio 5008 RTP/AVP 8";
+ b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
+
+ TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+ if (print_headings)
+ printf("TEST NUA-4.5.1: invalid Content-Type\n");
+
+ INVITE(a, a_call, a_call->nh,
+ TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+ SIPTAG_SUBJECT_STR("reject-3"),
+ SOATAG_USER_SDP_STR(a_call->sdp),
+ SIPTAG_CONTENT_TYPE_STR("application/xyzzy+xml"),
+ SIPTAG_CONTENT_DISPOSITION_STR("session;required"),
+ SIPTAG_PAYLOAD_STR("m=audio 5008 RTP/AVP 8\n"),
+ TAG_END());
+ run_ab_until(ctx, -1, until_terminated, -1, NULL);
+
+ /*
+ A reject-5.1 B
+ | |
+ |-------INVITE------>|
+ |<-------415---------|
+ |--------ACK-------->|
+ */
+
+ /*
+ Client transitions in reject-3:
+ INIT -(C1)-> CALLING -(C6a)-> TERMINATED
+ */
+
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 415);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST(sip->sip_status->st_status, 415);
+ TEST_1(sip->sip_accept);
+ TEST_S(sip->sip_accept->ac_type, "application/sdp");
+ TEST_1(sip->sip_accept_encoding);
+ /* No content-encoding is supported */
+ TEST_S(sip->sip_accept_encoding->aa_value, "");
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* CALLING */
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, a->events);
+
+ if (print_headings)
+ printf("TEST NUA-4.5.1: PASSED\n");
+
+ if (print_headings)
+ printf("TEST NUA-4.5.2: invalid Content-Encoding\n");
+
+ /*
+ A reject-5.2 B
+ | |
+ |-------INVITE------>|
+ |<-------415---------|
+ |--------ACK-------->|
+ */
+
+ INVITE(a, a_call, a_call->nh,
+ TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+ SIPTAG_SUBJECT_STR("reject-5"),
+ SOATAG_USER_SDP_STR(a_call->sdp),
+ SIPTAG_CONTENT_ENCODING_STR("zyxxy"),
+ TAG_END());
+ run_ab_until(ctx, -1, until_terminated, -1, NULL);
+
+ /*
+ Client transitions in reject-3:
+ INIT -(C1)-> CALLING -(C6a)-> TERMINATED
+ */
+
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+ TEST_1(is_offer_sent(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 415);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST(sip->sip_status->st_status, 415);
+ TEST_1(sip->sip_accept);
+ TEST_S(sip->sip_accept->ac_type, "application/sdp");
+ TEST_1(sip->sip_accept_encoding);
+ /* No content-encoding is supported */
+ TEST_S(sip->sip_accept_encoding->aa_value, "");
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, a->events);
+
+ if (print_headings)
+ printf("TEST NUA-4.5.2: PASSED\n");
+
+ if (print_headings)
+ printf("TEST NUA-4.5.3: invalid Accept\n");
+
+ INVITE(a, a_call, a_call->nh,
+ TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+ SIPTAG_SUBJECT_STR("reject-3"),
+ SOATAG_USER_SDP_STR(a_call->sdp),
+ SIPTAG_ACCEPT_STR("application/xyzzy+xml"),
+ TAG_END());
+ run_ab_until(ctx, -1, until_terminated, -1, NULL);
+
+
+ /*
+ A reject-5.3 B
+ | |
+ |-------INVITE------>|
+ |<-------406---------|
+ |--------ACK-------->|
+ */
+
+ /*
+ Client transitions in reject-3:
+ INIT -(C1)-> PROCEEDING -(C6a)-> TERMINATED
+ */
+
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+ TEST_1(is_offer_sent(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 406);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST(sip->sip_status->st_status, 406);
+ TEST_1(sip->sip_accept);
+ TEST_S(sip->sip_accept->ac_type, "application/sdp");
+ TEST_1(sip->sip_accept_encoding);
+ /* No content-encoding is supported */
+ TEST_S(sip->sip_accept_encoding->aa_value, "");
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* CALLING */
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, a->events);
+
+ if (print_headings)
+ printf("TEST NUA-4.5.3: PASSED\n");
+
+ nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+ free_events_in_list(ctx, b->events);
+
+ if (print_headings)
+ printf("TEST NUA-4.5: PASSED\n");
+
+ END();
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_cancel_bye.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_cancel_bye.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,811 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_cancel_bye.c
+ * @brief Test CANCEL, weird BYE and handle destroy
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti Mela at nokia.com>
+ *
+ * @date Created: Wed Aug 17 12:12:12 EEST 2005 ppessi
+ */
+
+#include "config.h"
+
+#include "test_nua.h"
+#include <sofia-sip/su_tag_class.h>
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+#define __func__ "test_cancel_bye"
+#endif
+
+/* ======================================================================== */
+
+/* Cancel cases:
+
+
+ A B
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ | |
+ |------CANCEL------->|
+ |<------200 OK-------|
+ | |
+ |<-------487---------|
+ |--------ACK-------->|
+ | |
+ | |
+
+ Client transitions:
+ INIT -(C1)-> CALLING -(C6a)-> TERMINATED
+
+ Server transitions:
+ INIT -(S1)-> RECEIVED -(S6a)-> TERMINATED
+
+ A B
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ | |
+ |<----180 Ringing----|
+ | |
+ |------CANCEL------->|
+ |<------200 OK-------|
+ | |
+ |<-------487---------|
+ |--------ACK-------->|
+ | |
+ | |
+
+ Client transitions:
+ INIT -(C1)-> CALLING -(C2)-> PROCEEDING -(C6b)-> TERMINATED
+
+ Server transitions:
+ INIT -(S1)-> RECEIVED -(S2a)-> EARLY -(S6b)-> TERMINATED
+
+*/
+
+int cancel_when_calling(CONDITION_PARAMS)
+{
+ if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+ return 0;
+
+ save_event_in_list(ctx, event, ep, call);
+
+ switch (callstate(tags)) {
+ case nua_callstate_calling:
+ CANCEL(ep, call, nh, TAG_END());
+ return 0;
+ case nua_callstate_terminated:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+
+int cancel_when_ringing(CONDITION_PARAMS)
+{
+ if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+ return 0;
+
+ save_event_in_list(ctx, event, ep, call);
+
+ switch (callstate(tags)) {
+ case nua_callstate_proceeding:
+ CANCEL(ep, call, nh, TAG_END());
+ return 0;
+ case nua_callstate_terminated:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+
+int alert_call(CONDITION_PARAMS)
+{
+ if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+ return 0;
+
+ save_event_in_list(ctx, event, ep, call);
+
+ switch (callstate(tags)) {
+ case nua_callstate_received:
+ RESPOND(ep, call, nh, SIP_180_RINGING, TAG_END());
+ return 0;
+ case nua_callstate_terminated:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+
+int test_call_cancel(struct context *ctx)
+{
+ BEGIN();
+
+ struct endpoint *a = &ctx->a, *b = &ctx->b;
+ struct call *a_call = a->call, *b_call = b->call;
+ struct event *e;
+
+ a_call->sdp = "m=audio 5008 RTP/AVP 8";
+ b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
+
+ if (print_headings)
+ printf("TEST NUA-5.1: cancel call\n");
+
+ TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+ INVITE(a, a_call, a_call->nh,
+ TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+ SOATAG_USER_SDP_STR(a_call->sdp),
+ TAG_END());
+
+ run_ab_until(ctx, -1, cancel_when_calling, -1, until_terminated);
+
+ /* Client transitions:
+ INIT -(C1)-> CALLING: nua_invite(), nua_i_state, nua_cancel()
+ CALLING -(C6a)-> TERMINATED: nua_r_invite(487), nua_i_state
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+ TEST_1(is_offer_sent(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_cancel);
+ TEST(e->data->e_status, 200);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 487);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+
+ /*
+ Server transitions:
+ INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
+ RECEIVED -(S6a)--> TERMINATED: nua_i_cancel, nua_i_state
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+ TEST(e->data->e_status, 100);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+ TEST_1(is_offer_recv(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_cancel);
+ TEST(e->data->e_status, 200);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, a->events);
+ nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+ free_events_in_list(ctx, b->events);
+ nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+ if (print_headings)
+ printf("TEST NUA-5.1: PASSED\n");
+
+ /* ------------------------------------------------------------------------ */
+
+ if (print_headings)
+ printf("TEST NUA-5.2: cancel call when ringing\n");
+
+ TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+ INVITE(a, a_call, a_call->nh,
+ TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+ SOATAG_USER_SDP_STR(a_call->sdp),
+ /*SIPTAG_REJECT_CONTACT_STR("*;audio=FALSE"),*/
+ TAG_END());
+
+ run_ab_until(ctx, -1, cancel_when_ringing, -1, alert_call);
+
+ /* Client transitions:
+ INIT -(C1)-> CALLING: nua_invite(), nua_i_state
+ CALLING -(C2)-> PROCEEDING: nua_r_invite(180, nua_i_state, nua_cancel()
+ PROCEEDING -(C6b)-> TERMINATED: nua_r_invite(487), nua_i_state
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+ TEST_1(is_offer_sent(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 180);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_cancel);
+ TEST(e->data->e_status, 200);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 487);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+
+ /*
+ Server transitions:
+ INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
+ RECEIVED -(S2a)-> EARLY: nua_respond(180), nua_i_state
+ EARLY -(S6b)--> TERMINATED: nua_i_cancel, nua_i_state
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+ TEST(e->data->e_status, 100);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+ TEST_1(is_offer_recv(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_cancel);
+ TEST(e->data->e_status, 200);
+ /* Check for bug #1326727 */
+ TEST_1(e->data->e_msg);
+#if 0
+ TEST_1(sip_object(e->data->e_msg)->sip_reject_contact);
+ TEST_1(sip_object(e->data->e_msg)->sip_reject_contact->cp_params &&
+ sip_object(e->data->e_msg)->sip_reject_contact->cp_params[0]);
+ TEST_S(sip_object(e->data->e_msg)->sip_reject_contact->cp_params[0],
+ "audio=FALSE");
+#endif
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, a->events);
+ nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+ free_events_in_list(ctx, b->events);
+ nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+ if (print_headings)
+ printf("TEST NUA-5.2: PASSED\n");
+
+ END();
+}
+
+/* ======================================================================== */
+/* Destroy call handle */
+
+int destroy_when_calling(CONDITION_PARAMS)
+{
+ if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+ return 0;
+
+ save_event_in_list(ctx, event, ep, call);
+
+ switch (callstate(tags)) {
+ case nua_callstate_calling:
+ DESTROY(ep, call, nh);
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+int destroy_when_completing(CONDITION_PARAMS)
+{
+ if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+ return 0;
+
+ save_event_in_list(ctx, event, ep, call);
+
+ switch (callstate(tags)) {
+ case nua_callstate_completing:
+ DESTROY(ep, call, nh);
+ return 1;
+ case nua_callstate_ready:
+ return 1;
+ case nua_callstate_terminated:
+ if (call)
+ nua_handle_destroy(call->nh), call->nh = NULL;
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+int test_call_destroy_1(struct context *ctx)
+{
+ BEGIN();
+
+ struct endpoint *a = &ctx->a, *b = &ctx->b;
+ struct call *a_call = a->call, *b_call = b->call;
+ struct event *e;
+
+ if (print_headings)
+ printf("TEST NUA-5.3: destroy when calling\n");
+
+ TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+ INVITE(a, a_call, a_call->nh,
+ TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+ SOATAG_USER_SDP_STR(a_call->sdp),
+ TAG_END());
+
+ run_ab_until(ctx, -1, destroy_when_calling, -1, until_terminated);
+
+ /* Client transitions:
+ INIT -(C1)-> CALLING: nua_invite(), ...
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+ TEST_1(is_offer_sent(e->data->e_tags));
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, a->events);
+ nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+ /*
+ Server transitions:
+ INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
+ RECEIVED -(S6a)--> TERMINATED: nua_i_cancel, nua_i_state
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+ TEST(e->data->e_status, 100);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+ TEST_1(is_offer_recv(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_cancel);
+ TEST(e->data->e_status, 200);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, b->events);
+ nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+ if (print_headings)
+ printf("TEST NUA-5.3: PASSED\n");
+
+ END();
+}
+
+int accept_until_terminated(CONDITION_PARAMS)
+{
+ if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+ return 0;
+
+ save_event_in_list(ctx, event, ep, call);
+
+ switch (callstate(tags)) {
+ case nua_callstate_received:
+ RESPOND(ep, call, nh, SIP_180_RINGING, TAG_END());
+ return 0;
+ case nua_callstate_early:
+ RESPOND(ep, call, nh, SIP_200_OK,
+ TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)),
+ TAG_END());
+ return 0;
+ case nua_callstate_completed:
+ case nua_callstate_ready:
+ return 0;
+ case nua_callstate_terminated:
+ if (call)
+ nua_handle_destroy(call->nh), call->nh = NULL;
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+int test_call_destroy_2(struct context *ctx)
+{
+ BEGIN();
+
+ struct endpoint *a = &ctx->a, *b = &ctx->b;
+ struct call *a_call = a->call, *b_call = b->call;
+ struct event *e;
+
+ if (print_headings)
+ printf("TEST NUA-5.4: destroy when completing\n");
+
+ TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+ INVITE(a, a_call, a_call->nh,
+ TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+ NUTAG_AUTOACK(0),
+ SOATAG_USER_SDP_STR(a_call->sdp),
+ TAG_END());
+
+ run_ab_until(ctx, -1, destroy_when_completing, -1, accept_until_terminated);
+
+ /* Client transitions:
+ INIT -(C1)-> CALLING: nua_invite(), ...
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+ TEST_1(is_offer_sent(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 180);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 200);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_completing); /* COMPLETING */
+ TEST_1(is_answer_recv(e->data->e_tags));
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, a->events);
+ nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+ /*
+ Server transitions:
+ INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
+ RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state
+ EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state
+ COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+ TEST(e->data->e_status, 100);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+ TEST_1(is_offer_recv(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+ TEST_1(is_answer_sent(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_bye);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, b->events);
+ nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+ if (print_headings)
+ printf("TEST NUA-5.4: PASSED\n");
+
+ END();
+}
+
+int destroy_when_early(CONDITION_PARAMS)
+{
+ if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+ return 0;
+
+ save_event_in_list(ctx, event, ep, call);
+
+ switch (callstate(tags)) {
+ case nua_callstate_received:
+ RESPOND(ep, call, nh, SIP_180_RINGING, TAG_END());
+ return 0;
+ case nua_callstate_early:
+ if (call)
+ nua_handle_destroy(call->nh), call->nh = NULL;
+ return 1;
+ case nua_callstate_completed:
+ case nua_callstate_ready:
+ case nua_callstate_terminated:
+ if (call)
+ nua_handle_destroy(call->nh), call->nh = NULL;
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+int test_call_destroy_3(struct context *ctx)
+{
+ BEGIN();
+
+ struct endpoint *a = &ctx->a, *b = &ctx->b;
+ struct call *a_call = a->call, *b_call = b->call;
+ struct event *e;
+
+ if (print_headings)
+ printf("TEST NUA-5.5: destroy when early\n");
+
+ TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+ INVITE(a, a_call, a_call->nh,
+ TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+ NUTAG_AUTOACK(0),
+ SOATAG_USER_SDP_STR(a_call->sdp),
+ TAG_END());
+
+ run_ab_until(ctx, -1, until_terminated, -1, destroy_when_early);
+
+ /* Client transitions:
+ INIT -(C1)-> CALLING: nua_invite(), ...
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+ TEST_1(is_offer_sent(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 180);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 480);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, a->events);
+ nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+ /*
+ Server transitions:
+ INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
+ RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state
+ EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state ... DESTROY
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+ TEST(e->data->e_status, 100);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+ TEST_1(is_offer_recv(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, b->events);
+ nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+ if (print_headings)
+ printf("TEST NUA-5.5: PASSED\n");
+
+ END();
+}
+
+int destroy_when_completed(CONDITION_PARAMS)
+{
+ if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+ return 0;
+
+ save_event_in_list(ctx, event, ep, call);
+
+ switch (callstate(tags)) {
+ case nua_callstate_received:
+ RESPOND(ep, call, nh, SIP_180_RINGING, TAG_END());
+ return 0;
+ case nua_callstate_early:
+ RESPOND(ep, call, nh, SIP_200_OK,
+ TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)),
+ TAG_END());
+ return 0;
+ case nua_callstate_completed:
+ case nua_callstate_ready:
+ case nua_callstate_terminated:
+ if (call)
+ nua_handle_destroy(call->nh), call->nh = NULL;
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+int test_call_destroy_4(struct context *ctx)
+{
+ BEGIN();
+
+ struct endpoint *a = &ctx->a, *b = &ctx->b;
+ struct call *a_call = a->call, *b_call = b->call;
+ struct event *e;
+
+ if (print_headings)
+ printf("TEST NUA-5.6: destroy when completed\n");
+
+ TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+ INVITE(a, a_call, a_call->nh,
+ TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+ NUTAG_AUTOACK(0),
+ SOATAG_USER_SDP_STR(a_call->sdp),
+ TAG_END());
+
+ run_ab_until(ctx, -1, until_terminated, -1, destroy_when_completed);
+
+ /* Client transitions:
+ INIT -(C1)-> CALLING: nua_invite(), ...
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+ TEST_1(is_offer_sent(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 180);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 200);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_completing); /* COMPLETING */
+ TEST_1(is_answer_recv(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_bye);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, a->events);
+ nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+ /*
+ Server transitions:
+ INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
+ RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state
+ EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state ... DESTROY
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+ TEST(e->data->e_status, 100);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+ TEST_1(is_offer_recv(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+ TEST_1(is_answer_sent(e->data->e_tags));
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, b->events);
+ nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+ if (print_headings)
+ printf("TEST NUA-5.6: PASSED\n");
+
+ END();
+}
+
+int test_call_destroy(struct context *ctx)
+{
+ struct endpoint *a = &ctx->a, *b = &ctx->b;
+ struct call *a_call = a->call, *b_call = b->call;
+
+ a_call->sdp = "m=audio 5008 RTP/AVP 8";
+ b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
+
+ return
+ test_call_destroy_1(ctx) ||
+ test_call_destroy_2(ctx) ||
+ test_call_destroy_3(ctx) ||
+ test_call_destroy_4(ctx);
+}
+
+/* ======================================================================== */
+/* Early BYE
+
+ A B
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ | |
+ |<----180 Ringing----|
+ | |
+ |--------BYE-------->|
+ |<------200 OK-------|
+ | |
+ |<-------487---------|
+ |--------ACK-------->|
+ | |
+ | |
+
+ Client transitions:
+ INIT -(C1)-> CALLING -(C2)-> PROCEEDING -(8)-> TERMINATING -> TERMINATED
+
+ Server transitions:
+ INIT -(S1)-> RECEIVED -(S2a)-> EARLY -(S8)-> TERMINATED
+
+*/
+
+int bye_when_ringing(CONDITION_PARAMS)
+{
+ if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+ return 0;
+
+ save_event_in_list(ctx, event, ep, call);
+
+ switch (callstate(tags)) {
+ case nua_callstate_proceeding:
+ BYE(ep, call, nh, TAG_END());
+ return 0;
+ case nua_callstate_terminated:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+int test_early_bye(struct context *ctx)
+{
+ BEGIN();
+ struct endpoint *a = &ctx->a, *b = &ctx->b;
+ struct call *a_call = a->call, *b_call = b->call;
+ struct event *e;
+
+ if (print_headings)
+ printf("TEST NUA-6.1: BYE call when ringing\n");
+
+ TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+ INVITE(a, a_call, a_call->nh,
+ TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+ SOATAG_USER_SDP_STR(a_call->sdp),
+ TAG_END());
+
+ run_ab_until(ctx, -1, bye_when_ringing, -1, alert_call);
+
+ /* Client transitions:
+ INIT -(C1)-> CALLING: nua_invite(), nua_i_state
+ CALLING -(C2)-> PROCEEDING: nua_r_invite(180, nua_i_state, nua_cancel()
+ PROCEEDING -(C6b)-> TERMINATED: nua_r_invite(487), nua_i_state
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+ TEST_1(is_offer_sent(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 180);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
+ TEST_1(e = e->next);
+ if (e->data->e_event == nua_r_bye) {
+ /* We might receive this before or after response to INVITE */
+ /* If afterwards, it will come after nua_i_state and we just ignore it */
+ TEST_E(e->data->e_event, nua_r_bye); TEST(e->data->e_status, 200);
+ TEST_1(e->data->e_msg);
+ /* Forking has not been enabled, so this should be actually a CANCEL */
+ TEST(sip_object(e->data->e_msg)->sip_cseq->cs_method, sip_method_cancel);
+ TEST_1(e = e->next);
+ }
+ TEST_E(e->data->e_event, nua_r_invite); TEST(e->data->e_status, 487);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+
+ /*
+ Server transitions:
+ INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
+ RECEIVED -(S2a)-> EARLY: nua_respond(180), nua_i_state
+ EARLY -(S6b)--> TERMINATED: nua_i_cancel, nua_i_state
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+ TEST(e->data->e_status, 100);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+ TEST_1(is_offer_recv(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+ /* Forking has not been enabled, so this should be actually a CANCEL */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_cancel);
+ TEST(e->data->e_status, 200);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, a->events);
+ nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+ free_events_in_list(ctx, b->events);
+ nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+ if (print_headings)
+ printf("TEST NUA-6.1: PASSED\n");
+
+ END();
+}
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_extension.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_extension.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,173 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_extension.c
+ * @brief NUA-12: Test extension methods.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Mon Nov 13 15:37:05 EET 2006
+ */
+
+#include "config.h"
+
+#include "test_nua.h"
+
+#include <sofia-sip/su_tag_class.h>
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+#define __func__ "test_extension"
+#endif
+
+
+int respond_to_extension(CONDITION_PARAMS)
+{
+ msg_t *with = nua_current_request(nua);
+
+ if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+ return 0;
+
+ save_event_in_list(ctx, event, ep, call);
+
+ switch (event) {
+ case nua_i_method:
+ RESPOND(ep, call, nh, SIP_200_OK,
+ NUTAG_WITH(with),
+ SIPTAG_SUBJECT_STR("extended"),
+ TAG_END());
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+int test_extension(struct context *ctx)
+{
+ BEGIN();
+
+ struct endpoint *a = &ctx->a, *b = &ctx->b;
+ struct call *a_call = a->call, *b_call = b->call;
+ struct event *e;
+ sip_t const *sip;
+
+
+/* Test for EXTENSION
+
+ A B
+ |------EXTENSION---->|
+ |<--------501--------| (method not recognized)
+ | |
+ |------EXTENSION---->|
+ |<-------200---------| (method allowed, responded)
+ | |
+*/
+
+ if (print_headings)
+ printf("TEST NUA-13.1: EXTENSION\n");
+
+
+ TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+ /* Test first without NUTAG_METHOD() */
+ METHOD(a, a_call, a_call->nh,
+ TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+ TAG_END());
+
+ run_ab_until(ctx, -1, save_until_final_response, -1, NULL);
+
+ /* Client events:
+ nua_method(), nua_r_method
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_method);
+ TEST(e->data->e_status, 900); /* Internal error */
+ TEST_1(!e->data->e_msg);
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, a->events);
+ nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+ TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+ METHOD(a, a_call, a_call->nh,
+ TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+ NUTAG_METHOD("EXTENSION"),
+ TAG_END());
+
+ run_ab_until(ctx, -1, save_until_final_response, -1, NULL);
+
+ /* Client events:
+ nua_method(), nua_r_method
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_method);
+ TEST(e->data->e_status, 501);
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, a->events);
+ nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+ free_events_in_list(ctx, b->events);
+ nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+ nua_set_params(b->nua, NUTAG_ALLOW("EXTENSION"), TAG_END());
+
+ run_b_until(ctx, nua_r_set_params, until_final_response);
+
+ TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+ METHOD(a, a_call, a_call->nh,
+ TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+ NUTAG_METHOD("EXTENSION"),
+ TAG_END());
+
+ run_ab_until(ctx, -1, save_until_final_response, -1, respond_to_extension);
+
+ /* Client events:
+ nua_method(), nua_r_method
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_method);
+ TEST(e->data->e_status, 200);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(!e->next);
+
+ /*
+ Server events:
+ nua_i_method
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_method);
+ TEST(e->data->e_status, 100);
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, a->events);
+ nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+ free_events_in_list(ctx, b->events);
+ nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+ if (print_headings)
+ printf("TEST NUA-13.1: PASSED\n");
+ END();
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_init.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_init.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,349 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_init.c
+ * @brief Init nua test context
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti Mela at nokia.com>
+ *
+ * @date Created: Wed Aug 17 12:12:12 EEST 2005 ppessi
+ */
+
+#include "config.h"
+
+#include "test_nua.h"
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+#define __func__ name
+#endif
+
+static char passwd_name[] = "tmp_sippasswd.XXXXXX";
+
+static void remove_tmp(void)
+{
+ if (passwd_name[0])
+ unlink(passwd_name);
+}
+
+static char const passwd[] =
+ "alice:secret:\n"
+ "bob:secret:\n"
+ "charlie:secret:\n";
+
+int test_nua_init(struct context *ctx,
+ int start_proxy,
+ url_t const *o_proxy,
+ int start_nat,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ BEGIN();
+ struct event *e;
+ sip_contact_t const *m = NULL;
+ sip_from_t const *sipaddress = NULL;
+ url_t const *p_uri, *a_uri; /* Proxy URI */
+ char const *a_bind, *a_bind2;
+
+ a_bind = a_bind2 = "sip:0.0.0.0:*";
+
+#if SU_HAVE_OSX_CF_API
+ if (ctx->osx_runloop)
+ ctx->root = su_root_osx_runloop_create(NULL);
+ else
+#endif
+ ctx->root = su_root_create(NULL);
+ TEST_1(ctx->root);
+
+ /* Disable threading by command line switch -s */
+ su_root_threading(ctx->root, ctx->threading);
+
+ if (start_proxy && !o_proxy) {
+ int temp;
+
+ if (print_headings)
+ printf("TEST NUA-2.1.1: init proxy P\n");
+
+#ifndef _WIN32
+ temp = mkstemp(passwd_name);
+#else
+ temp = open(passwd_name, O_WRONLY|O_CREAT|O_TRUNC, 666);
+#endif
+ TEST_1(temp != -1);
+ atexit(remove_tmp); /* Make sure temp file is unlinked */
+
+ TEST_SIZE(write(temp, passwd, strlen(passwd)), strlen(passwd));
+
+ TEST_1(close(temp) == 0);
+
+ ctx->p = test_proxy_create(ctx->root,
+ AUTHTAG_METHOD("Digest"),
+ AUTHTAG_REALM("test-proxy"),
+ AUTHTAG_OPAQUE("kuik"),
+ AUTHTAG_DB(passwd_name),
+ AUTHTAG_QOP("auth-int"),
+ AUTHTAG_ALGORITHM("md5-sess"),
+ TAG_END());
+
+ ctx->proxy_tests = ctx->p != NULL;
+
+ if (print_headings)
+ printf("TEST NUA-2.1.1: PASSED\n");
+ }
+
+ p_uri = a_uri = test_proxy_uri(ctx->p);
+
+ if (start_nat && p_uri == NULL)
+ p_uri = url_hdup(ctx->home, (void *)o_proxy);
+
+ if (start_nat && p_uri != NULL) {
+ int family = 0;
+ su_sockaddr_t su[1];
+ socklen_t sulen = sizeof su;
+ char b[64];
+ size_t len;
+ ta_list ta;
+
+ if (print_headings)
+ printf("TEST NUA-2.1.2: creating test NAT\n");
+
+ /* Try to use different family than proxy. */
+ if (p_uri->url_host[0] == '[')
+ family = AF_INET;
+#if defined(SU_HAVE_IN6)
+ else
+ family = AF_INET6;
+#endif
+
+ ta_start(ta, tag, value);
+ ctx->nat = test_nat_create(ctx->root, family, ta_tags(ta));
+ ta_end(ta);
+
+ /*
+ * NAT thingy works so that we set the outgoing proxy URI to point
+ * towards its "private" address and give the real address of the proxy
+ * as its "public" address. If we use different IP families here, we may
+ * even manage to test real connectivity problems as proxy and endpoint
+ * can not talk to each other.
+ */
+
+ if (test_nat_private(ctx->nat, su, &sulen) < 0) {
+ printf("%s:%u: NUA-2.1.2: failed to get private NAT address\n",
+ __FILE__, __LINE__);
+ }
+
+#if defined(SU_HAVE_IN6)
+ else if (su->su_family == AF_INET6) {
+ a_uri = (void *)
+ su_sprintf(ctx->home, "sip:[%s]:%u",
+ inet_ntop(su->su_family, SU_ADDR(su), b, sizeof b),
+ ntohs(su->su_port));
+ a_bind = "sip:[::]:*";
+ }
+#endif
+ else if (su->su_family == AF_INET) {
+ a_uri = (void *)
+ su_sprintf(ctx->home, "sip:%s:%u",
+ inet_ntop(su->su_family, SU_ADDR(su), b, sizeof b),
+ ntohs(su->su_port));
+ }
+
+#if defined(SU_HAVE_IN6)
+ if (p_uri->url_host[0] == '[') {
+ su->su_len = sulen = (sizeof su->su_sin6), su->su_family = AF_INET6;
+ len = strcspn(p_uri->url_host + 1, "]"); assert(len < sizeof b);
+ memcpy(b, p_uri->url_host + 1, len); b[len] = '\0';
+ inet_pton(su->su_family, b, SU_ADDR(su));
+ }
+ else {
+ su->su_len = sulen = (sizeof su->su_sin), su->su_family = AF_INET;
+ inet_pton(su->su_family, p_uri->url_host, SU_ADDR(su));
+ }
+#else
+ su->su_len = sulen = (sizeof su->su_sin), su->su_family = AF_INET;
+ inet_pton(su->su_family, p_uri->url_host, SU_ADDR(su));
+#endif
+
+ su->su_port = htons(strtoul(url_port(p_uri), NULL, 10));
+
+ if (test_nat_public(ctx->nat, su, sulen) < 0) {
+ printf("%s:%u: NUA-2.1.2: failed to set public address\n",
+ __FILE__, __LINE__);
+ a_uri = NULL;
+ }
+
+ if (print_headings) {
+ if (ctx->nat && a_uri) {
+ printf("TEST NUA-2.1.2: PASSED\n");
+ } else {
+ printf("TEST NUA-2.1.2: FAILED\n");
+ }
+ }
+ }
+
+ if (print_headings)
+ printf("TEST NUA-2.2.1: init endpoint A\n");
+
+ if (a_uri == NULL)
+ a_uri = p_uri;
+
+ ctx->a.instance = nua_generate_instance_identifier(ctx->home);
+
+ ctx->a.nua = nua_create(ctx->root, a_callback, ctx,
+ NUTAG_PROXY(a_uri ? a_uri : o_proxy),
+ SIPTAG_FROM_STR("sip:alice at example.com"),
+ NUTAG_URL(a_bind),
+ TAG_IF(a_bind != a_bind2, NUTAG_SIPS_URL(a_bind2)),
+ SOATAG_USER_SDP_STR("m=audio 5004 RTP/AVP 0 8"),
+ NTATAG_SIP_T1X64(4000),
+ NUTAG_INSTANCE(ctx->a.instance),
+ TAG_END());
+ TEST_1(ctx->a.nua);
+
+ nua_get_params(ctx->a.nua, TAG_ANY(), TAG_END());
+ run_a_until(ctx, nua_r_get_params, save_until_final_response);
+ TEST_1(e = ctx->a.events->head);
+ TEST(tl_gets(e->data->e_tags,
+ NTATAG_CONTACT_REF(m),
+ SIPTAG_FROM_REF(sipaddress),
+ TAG_END()), 2); TEST_1(m);
+ TEST_1(ctx->a.contact = sip_contact_dup(ctx->home, m));
+ TEST_1(ctx->a.to = sip_to_dup(ctx->home, sipaddress));
+
+ free_events_in_list(ctx, ctx->a.events);
+
+ if (print_headings)
+ printf("TEST NUA-2.2.1: PASSED\n");
+
+ if (print_headings)
+ printf("TEST NUA-2.2.2: init endpoint B\n");
+
+ ctx->b.instance = nua_generate_instance_identifier(ctx->home);
+
+ ctx->b.nua = nua_create(ctx->root, b_callback, ctx,
+ NUTAG_PROXY(p_uri ? p_uri : o_proxy),
+ SIPTAG_FROM_STR("sip:bob at example.org"),
+ NUTAG_URL("sip:0.0.0.0:*"),
+ SOATAG_USER_SDP_STR("m=audio 5006 RTP/AVP 8 0"),
+ NUTAG_INSTANCE(ctx->b.instance),
+ TAG_END());
+ TEST_1(ctx->b.nua);
+
+ nua_get_params(ctx->b.nua, TAG_ANY(), TAG_END());
+ run_b_until(ctx, nua_r_get_params, save_until_final_response);
+ TEST_1(e = ctx->b.events->head);
+ TEST(tl_gets(e->data->e_tags,
+ NTATAG_CONTACT_REF(m),
+ SIPTAG_FROM_REF(sipaddress),
+ TAG_END()), 2); TEST_1(m);
+ TEST_1(ctx->b.contact = sip_contact_dup(ctx->home, m));
+ TEST_1(ctx->b.to = sip_to_dup(ctx->home, sipaddress));
+ free_events_in_list(ctx, ctx->b.events);
+
+ if (print_headings)
+ printf("TEST NUA-2.2.2: PASSED\n");
+
+ if (print_headings)
+ printf("TEST NUA-2.2.3: init endpoint C\n");
+
+ /* ctx->c.instance = nua_generate_instance_identifier(ctx->home); */
+
+ ctx->c.nua = nua_create(ctx->root, c_callback, ctx,
+ NUTAG_PROXY(p_uri ? p_uri : o_proxy),
+ SIPTAG_FROM_STR("sip:charlie at example.net"),
+ NUTAG_URL("sip:0.0.0.0:*"),
+ SOATAG_USER_SDP_STR("m=audio 5400 RTP/AVP 8 0"),
+ NUTAG_INSTANCE(ctx->c.instance),
+ TAG_END());
+ TEST_1(ctx->c.nua);
+
+ nua_get_params(ctx->c.nua, TAG_ANY(), TAG_END());
+ run_c_until(ctx, nua_r_get_params, save_until_final_response);
+ TEST_1(e = ctx->c.events->head);
+ TEST(tl_gets(e->data->e_tags,
+ NTATAG_CONTACT_REF(m),
+ SIPTAG_FROM_REF(sipaddress),
+ TAG_END()), 2); TEST_1(m);
+ TEST_1(ctx->c.contact = sip_contact_dup(ctx->home, m));
+ TEST_1(ctx->c.to = sip_to_dup(ctx->home, sipaddress));
+ free_events_in_list(ctx, ctx->c.events);
+
+ if (print_headings)
+ printf("TEST NUA-2.2.3: PASSED\n");
+
+ END();
+}
+
+
+/* ====================================================================== */
+
+int test_deinit(struct context *ctx)
+{
+ BEGIN();
+
+ struct call *call;
+
+ if (!ctx->threading)
+ su_root_step(ctx->root, 100);
+
+ if (ctx->a.nua) {
+ for (call = ctx->a.call; call; call = call->next)
+ nua_handle_destroy(call->nh), call->nh = NULL;
+
+ nua_shutdown(ctx->a.nua);
+ run_a_until(ctx, nua_r_shutdown, until_final_response);
+ free_events_in_list(ctx, ctx->a.specials);
+ nua_destroy(ctx->a.nua), ctx->a.nua = NULL;
+ }
+
+ if (ctx->b.nua) {
+ for (call = ctx->b.call; call; call = call->next)
+ nua_handle_destroy(call->nh), call->nh = NULL;
+
+ nua_shutdown(ctx->b.nua);
+ run_b_until(ctx, nua_r_shutdown, until_final_response);
+ free_events_in_list(ctx, ctx->b.specials);
+ nua_destroy(ctx->b.nua), ctx->b.nua = NULL;
+ }
+
+ if (ctx->c.nua) {
+ for (call = ctx->c.call; call; call = call->next)
+ nua_handle_destroy(call->nh), call->nh = NULL;
+
+ nua_shutdown(ctx->c.nua);
+ run_c_until(ctx, nua_r_shutdown, until_final_response);
+ free_events_in_list(ctx, ctx->c.specials);
+ nua_destroy(ctx->c.nua), ctx->c.nua = NULL;
+ }
+
+ test_proxy_destroy(ctx->p), ctx->p = NULL;
+
+ test_nat_destroy(ctx->nat), ctx->nat = NULL;
+
+ su_root_destroy(ctx->root);
+
+ END();
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nat.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nat.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,884 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_nat.c
+ * @brief Simulated NAT for testing
+ *
+ * NAT thing works so that we set the outgoing proxy URI to point
+ * towards its "private" address and give the real address of the proxy
+ * as its "public" address. If we use different IP families here, we may
+ * even manage to test real connectivity problems as proxy and endpoint
+ * can not talk to each other.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Mar 8 19:54:28 EET 2006
+ */
+
+#include "config.h"
+
+struct nat;
+struct binding;
+
+#define SU_ROOT_MAGIC_T struct nat
+#define SU_WAKEUP_ARG_T struct binding
+
+#include <sofia-sip/su.h>
+#include <sofia-sip/su_errno.h>
+#include <sofia-sip/su_wait.h>
+#include <sofia-sip/su_tagarg.h>
+#include <sofia-sip/su_localinfo.h>
+#include <sofia-sip/su_log.h>
+
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+#define LIST_PROTOS(STORAGE, PREFIX, T) \
+STORAGE void PREFIX ##_insert(T **list, T *node), \
+ PREFIX ##_remove(T *node)
+
+#define LIST_BODIES(STORAGE, PREFIX, T, NEXT, PREV) \
+STORAGE void PREFIX ##_insert(T **list, T *node) \
+{ \
+ if ((node->NEXT = *list)) { \
+ node->PREV = node->NEXT->PREV; \
+ node->NEXT->PREV = &node->NEXT; \
+ } \
+ else \
+ node->PREV = list; \
+ *list = node; \
+} \
+STORAGE void PREFIX ##_remove(T *node) \
+{ \
+ if (node->PREV) \
+ if ((*node->PREV = node->NEXT)) \
+ node->NEXT->PREV = node->PREV; \
+ node->PREV = NULL; \
+} \
+extern int LIST_DUMMY_VARIABLE
+
+#include <test_nat.h>
+
+struct nat {
+ su_home_t home[1];
+ su_root_t *parent;
+ su_clone_r clone;
+ tagi_t *tags;
+
+ su_root_t *root;
+
+ struct binding *bindings;
+
+ /* True if we act in symmetric way */
+ int symmetric;
+ /* True if we do logging */
+ int logging;
+
+ /* Everything sent to in_address will be forwarded to out_address */
+ su_sockaddr_t in_address[1], out_address[1];
+ socklen_t in_addrlen, out_addrlen;
+
+ int family; /* Preferred private family */
+
+ /* ...but source address will be "fake" */
+ su_localinfo_t *localinfo, *private, *fake;
+
+ su_socket_t udp_socket, tcp_socket;
+ int udp_register, tcp_register;
+
+ char buffer[65536];
+};
+
+LIST_PROTOS(static, nat_binding, struct binding);
+
+struct binding
+{
+ struct binding *next, **prev;
+ struct nat *nat; /* backpointer */
+ int socktype, protocol;
+ su_socket_t in_socket, out_socket;
+ int in_register, out_register;
+ int in_closed, out_closed;
+ char in_name[64], out_name[64];
+};
+
+static struct binding *nat_binding_new(struct nat *nat,
+ char const *protoname,
+ int socktype, int protocol,
+ int connected,
+ su_socket_t in_socket,
+ su_sockaddr_t *from,
+ socklen_t fromlen);
+static void nat_binding_destroy(struct binding *);
+
+static int binding_init(struct binding *b,
+ char const *protoname,
+ int connected,
+ su_localinfo_t *li,
+ su_sockaddr_t *from,
+ socklen_t fromlen);
+
+static void flush_bindings(struct nat *nat);
+static int invalidate_bindings(void *nat);
+
+static int new_udp(struct nat *, su_wait_t *wait, struct binding *dummy);
+static int udp_in_to_out(struct nat *, su_wait_t *wait, struct binding *);
+static int udp_out_to_in(struct nat *, su_wait_t *wait, struct binding *);
+
+static int new_tcp(struct nat *, su_wait_t *wait, struct binding *dummy);
+static int tcp_in_to_out(struct nat *, su_wait_t *wait, struct binding *);
+static int tcp_out_to_in(struct nat *, su_wait_t *wait, struct binding *);
+
+static int invalidate_binding(struct binding *b);
+
+/* nat entry point */
+static int
+test_nat_init(su_root_t *root, struct nat *nat)
+{
+ su_localinfo_t *li, hints[1] = {{ 0 }};
+ int error;
+ unsigned port = 0, port0 = 0;
+ su_sockaddr_t su[1];
+ socklen_t sulen;
+ su_wait_t wait[1];
+
+ nat->root = root;
+ nat->udp_socket = INVALID_SOCKET, nat->tcp_socket = INVALID_SOCKET;
+
+ tl_gets(nat->tags,
+ TESTNATTAG_SYMMETRIC_REF(nat->symmetric),
+ TESTNATTAG_LOGGING_REF(nat->logging),
+ TAG_END());
+
+ hints->li_scope = LI_SCOPE_HOST | LI_SCOPE_SITE | LI_SCOPE_GLOBAL;
+
+ error = su_getlocalinfo(hints, &nat->localinfo);
+ if (error) {
+ fprintf(stderr, "test_nat: su_getlocalinfo: %s\n", su_gli_strerror(error));
+ return -1;
+ }
+
+ /* We must have two different IP addresses. */
+ if (!nat->localinfo || !nat->localinfo->li_next) {
+ fprintf(stderr, "test_nat: only one IP address available\n");
+ return -1;
+ }
+
+ for (li = nat->localinfo; li; li = li->li_next) {
+ if (nat->family == 0 || nat->family == li->li_family)
+ break;
+ }
+ if (li == NULL)
+ li = nat->localinfo;
+
+ memcpy(su, li->li_addr, sulen = li->li_addrlen);
+ memset(SU_ADDR(su), 0, SU_ADDRLEN(su));
+
+ nat->private = li;
+
+ /* Bind TCP and UDP to same port */
+ for (;;) {
+ nat->udp_socket = su_socket(li->li_family, SOCK_DGRAM, IPPROTO_UDP);
+ if (nat->udp_socket == INVALID_SOCKET)
+ return -1;
+
+ if (bind(nat->udp_socket, (void *)su, sulen) < 0) {
+ if (port0 == 0) {
+ su_perror("nat: bind(udp_socket)");
+ return -1;
+ }
+
+ fprintf(stderr, "test_nat: port %u: %s\n",
+ port, su_strerror(su_errno()));
+ su_close(nat->udp_socket);
+
+ nat->udp_socket = INVALID_SOCKET;
+
+ if (++port > 65535)
+ port = 1024;
+ if (port == port0) {
+ fprintf(stderr, "test_nat: could not find free port pairt\n");
+ return -1;
+ }
+
+ continue;
+ }
+
+ if (getsockname(nat->udp_socket, (void *)su, &sulen) < 0) {
+ su_perror("nat: getsockname(udp_socket)");
+ return -1;
+ }
+
+ if (port0 == 0) {
+ port = port0 = ntohs(su->su_port);
+ if (port0 == 0) {
+ fprintf(stderr, "test_nat: bind did not return port\n");
+ return -1;
+ }
+ }
+
+ nat->tcp_socket = su_socket(li->li_family, SOCK_STREAM, IPPROTO_TCP);
+ if (nat->tcp_socket == INVALID_SOCKET)
+ return -1;
+
+ if (bind(nat->tcp_socket, (void *)su, sulen) < 0) {
+ su_close(nat->tcp_socket);
+ nat->tcp_socket = INVALID_SOCKET;
+
+ fprintf(stderr, "test_nat: port %u: %s\n",
+ port, su_strerror(su_errno()));
+
+ if (++port > 65535)
+ port = 1024;
+ if (port == port0) {
+ fprintf(stderr, "test_nat: could not find free port pair\n");
+ return -1;
+ }
+
+ continue;
+ }
+
+ break;
+ }
+
+ memcpy(nat->in_address, li->li_addr, nat->in_addrlen = li->li_addrlen);
+ nat->in_address->su_port = su->su_port;
+
+ if (su_setreuseaddr(nat->udp_socket, 1) < 0) {
+ su_perror("nat: su_setreuseaddr(udp_socket)");
+ return -1;
+ }
+
+ if (listen(nat->tcp_socket, 5) < 0) {
+ su_perror("nat: listen(tcp_socket)");
+ return -1;
+ }
+
+ if (su_wait_create(wait, nat->udp_socket, SU_WAIT_IN) < 0) {
+ su_perror("nat: su_wait_create");
+ return -1;
+ }
+
+ nat->udp_register = su_root_register(root, wait, new_udp, NULL, 0);
+ if (nat->udp_register < 0) {
+ su_perror("nat: su_root_register");
+ return -1;
+ }
+
+ if (su_wait_create(wait, nat->tcp_socket, SU_WAIT_IN) < 0) {
+ su_perror("nat: su_wait_create");
+ return -1;
+ }
+
+ nat->tcp_register = su_root_register(root, wait, new_tcp, NULL, 0);
+ if (nat->tcp_register < 0) {
+ su_perror("nat: su_root_register");
+ return -1;
+ }
+
+ return 0;
+}
+
+static void
+test_nat_deinit(su_root_t *root, struct nat *nat)
+{
+ flush_bindings(nat);
+
+ if (nat->tcp_register)
+ su_root_deregister(root, nat->tcp_register);
+ if (nat->udp_register)
+ su_root_deregister(root, nat->udp_register);
+
+ if (nat->udp_socket != INVALID_SOCKET)
+ su_close(nat->udp_socket);
+ if (nat->tcp_socket != INVALID_SOCKET)
+ su_close(nat->tcp_socket);
+
+ su_freelocalinfo(nat->localinfo);
+
+ free(nat->tags);
+}
+
+struct nat *test_nat_create(su_root_t *root,
+ int family,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ struct nat *nat = su_home_new(sizeof *nat);
+
+ if (nat) {
+ ta_list ta;
+
+ nat->parent = root;
+ nat->family = family;
+
+ ta_start(ta, tag, value);
+ nat->tags = tl_llist(ta_tags(ta));
+ ta_end(ta);
+
+ if (su_clone_start(root,
+ nat->clone,
+ nat,
+ test_nat_init,
+ test_nat_deinit) == -1)
+ su_home_unref(nat->home), nat = NULL;
+ }
+
+ return nat;
+}
+
+void test_nat_destroy(struct nat *nat)
+{
+ if (nat) {
+ su_clone_wait(nat->parent, nat->clone);
+ su_home_unref(nat->home);
+ }
+}
+
+/** Get "private" address. */
+int test_nat_private(struct nat *nat, void *address, socklen_t *return_addrlen)
+{
+ if (nat == NULL || address == NULL || return_addrlen == NULL)
+ return su_seterrno(EFAULT);
+
+ if (*return_addrlen < nat->in_addrlen)
+ return su_seterrno(EINVAL);
+
+ memcpy(address, nat->in_address, *return_addrlen = nat->in_addrlen);
+
+ return 0;
+}
+
+/** Set "public" address. */
+int test_nat_public(struct nat *nat, void const *address, int addrlen)
+{
+ su_sockaddr_t const *su = address;
+ su_localinfo_t *li;
+
+ if (nat == NULL)
+ return su_seterrno(EFAULT);
+
+ if (address == NULL) {
+ nat->fake = NULL;
+ return 0;
+ }
+
+ if ((size_t)addrlen > sizeof nat->out_address)
+ return su_seterrno(EINVAL);
+
+ for (li = nat->localinfo; li; li = li->li_next) {
+ if (li != nat->private &&
+ li->li_scope == LI_SCOPE_HOST &&
+ li->li_family == su->su_family)
+ break;
+ }
+
+ if (li == NULL)
+ for (li = nat->localinfo; li; li = li->li_next) {
+ if (li != nat->private && li->li_family == su->su_family)
+ break;
+ }
+
+ if (li == NULL)
+ return su_seterrno(EADDRNOTAVAIL);
+
+ su_clone_pause(nat->clone);
+ memcpy(nat->out_address, address, nat->out_addrlen = addrlen);
+ nat->fake = li;
+ su_clone_resume(nat->clone);
+
+ return 0;
+}
+
+int test_nat_flush(struct nat *nat)
+{
+ if (nat == NULL)
+ return su_seterrno(EFAULT);
+
+ return su_task_execute(su_clone_task(nat->clone),
+ invalidate_bindings, nat, NULL);
+}
+
+/* ====================================================================== */
+
+struct binding *nat_binding_new(struct nat *nat,
+ char const *protoname,
+ int socktype,
+ int protocol,
+ int connected,
+ su_socket_t in_socket,
+ su_sockaddr_t *from,
+ socklen_t fromlen)
+{
+ struct binding *b;
+
+ if (nat->fake == NULL) { /* Xyzzy */
+ fprintf(stderr, "test_nat: fake address missing\n");
+ su_close(in_socket);
+ return NULL;
+ }
+
+ b = su_zalloc(nat->home, sizeof *b);
+ if (b == NULL) {
+ su_perror("nat_binding_new: su_zalloc");
+ su_close(in_socket);
+ return 0;
+ }
+
+ b->nat = nat;
+ b->socktype = socktype;
+ b->protocol = protocol;
+ b->in_socket = in_socket, b->out_socket = INVALID_SOCKET;
+ b->in_register = -1, b->out_register = -1;
+
+ if (binding_init(b, protoname, connected, nat->fake, from, fromlen) < 0)
+ nat_binding_destroy(b), b = NULL;
+
+ return b;
+}
+
+static int binding_init(struct binding *b,
+ char const *protoname,
+ int connected,
+ su_localinfo_t *li,
+ su_sockaddr_t *from,
+ socklen_t fromlen)
+{
+ struct nat *nat = b->nat;
+ su_socket_t out_socket;
+ su_sockaddr_t addr[1];
+ socklen_t addrlen = (sizeof addr);
+ char ipname[64];
+ su_wait_t wait[1];
+ su_wakeup_f in_to_out, out_to_in;
+
+ if (b->socktype == SOCK_STREAM)
+ in_to_out = tcp_in_to_out, out_to_in = tcp_out_to_in;
+ else
+ in_to_out = udp_in_to_out, out_to_in = udp_out_to_in;
+
+ if (b->in_socket == INVALID_SOCKET) {
+ int in_socket;
+
+ in_socket = su_socket(from->su_family, b->socktype, b->protocol);
+ if (in_socket == INVALID_SOCKET) {
+ su_perror("nat_binding_new: socket");
+ return -1;
+ }
+ b->in_socket = in_socket;
+ if (su_setreuseaddr(in_socket, 1) < 0) {
+ su_perror("nat_binding_new: su_setreuseaddr(in_socket)");
+ return -1;
+ }
+ if (bind(in_socket, (void *)nat->in_address, nat->in_addrlen) < 0) {
+ su_perror("nat_binding_new: bind(in_socket)");
+ return -1;
+ }
+ if (connect(in_socket, (void *)from, fromlen) < 0) {
+ su_perror("nat_binding_new: connect(in_socket)");
+ return -1;
+ }
+ }
+
+ out_socket = su_socket(li->li_family, b->socktype, b->protocol);
+ if (out_socket == INVALID_SOCKET) {
+ su_perror("nat_binding_new: socket");
+ return -1;
+ }
+ b->out_socket = out_socket;
+
+ if (bind(out_socket, (void *)li->li_addr, li->li_addrlen) < 0) {
+ su_perror("nat_binding_new: bind(to)");
+ return -1;
+ }
+
+ if (connected)
+ if (connect(out_socket, (void *)nat->out_address, nat->out_addrlen) < 0) {
+ su_perror("nat_binding_new: connect(to)");
+ return -1;
+ }
+
+ getpeername(b->in_socket, (void *)addr, &addrlen);
+ inet_ntop(addr->su_family, SU_ADDR(addr), ipname, sizeof ipname);
+ snprintf(b->in_name, sizeof b->in_name,
+ addr->su_family == AF_INET6 ? "[%s]:%u" : "%s:%u",
+ ipname, ntohs(addr->su_port));
+
+ getsockname(out_socket, (void *)addr, &addrlen);
+ inet_ntop(addr->su_family, SU_ADDR(addr), ipname, sizeof ipname);
+ snprintf(b->out_name, sizeof b->out_name,
+ addr->su_family == AF_INET6 ? "[%s]:%u" : "%s:%u",
+ ipname, ntohs(addr->su_port));
+
+ if (su_wait_create(wait, b->in_socket, SU_WAIT_IN) < 0) {
+ su_perror("nat_binding_new: su_wait_create");
+ return -1;
+ }
+ b->in_register = su_root_register(nat->root, wait, in_to_out, b, 0);
+ if (b->in_register < 0) {
+ su_perror("nat_binding_new: su_root_register");
+ su_wait_destroy(wait);
+ return -1;
+ }
+
+ if (su_wait_create(wait, out_socket, SU_WAIT_IN) < 0) {
+ su_perror("nat_binding_new: su_wait_create");
+ return -1;
+ }
+ b->out_register = su_root_register(nat->root, wait, out_to_in, b, 0);
+ if (b->out_register < 0) {
+ su_perror("nat_binding_new: su_root_register");
+ su_wait_destroy(wait);
+ return -1;
+ }
+
+ nat_binding_insert(&nat->bindings, b);
+
+ if (nat->logging)
+ printf("nat: new %s binding %s <=> %s\n",
+ protoname, b->in_name, b->out_name);
+
+ return 0;
+}
+
+static void nat_binding_destroy(struct binding *b)
+{
+ nat_binding_remove(b);
+ if (b->in_register != -1)
+ su_root_deregister(b->nat->root, b->in_register);
+ if (b->out_register != -1)
+ su_root_deregister(b->nat->root, b->out_register);
+ su_close(b->in_socket), su_close(b->out_socket);
+}
+
+static void flush_bindings(struct nat *nat)
+{
+ struct binding *b;
+
+ for (b = nat->bindings; b; b = b->next) {
+ if (b->in_register)
+ su_root_deregister(nat->root, b->in_register);
+ su_close(b->in_socket);
+ if (b->out_register)
+ su_root_deregister(nat->root, b->out_register);
+ su_close(b->out_socket);
+ }
+}
+
+static int invalidate_bindings(void *arg)
+{
+ struct nat *nat = arg;
+ struct binding *b;
+
+ for (b = nat->bindings; b; b = b->next) {
+ invalidate_binding(b);
+ }
+ return 0;
+}
+
+#if 0
+static struct binding *nat_binding_find(struct nat *nat,
+ su_sockaddr_t *from,
+ int fromlen)
+{
+ char name[64], ipname[64];
+ size_t namelen;
+ struct binding *b;
+
+ inet_ntop(from->su_family, SU_ADDR(from), ipname, sizeof ipname);
+ snprintf(name, sizeof name,
+ from->su_family == AF_INET6 ? "[%s]:%u" : "%s:%u",
+ ipname, ntohs(from->su_port));
+ namelen = strlen(name) + 1;
+
+ for (b = nat->bindings; b; b = b->next) {
+ if (memcmp(name, b->in_name, namelen) == 0)
+ return b;
+ }
+
+ if (b == NULL)
+ b = nat_binding_new(nat, "UDP", SOCK_DGRAM, IPPROTO_UDP, nat->symmetric,
+ INVALID_SOCKET, from, fromlen);
+
+ return b;
+}
+#endif
+
+/* ====================================================================== */
+
+LIST_BODIES(static, nat_binding, struct binding, next, prev);
+
+/* ====================================================================== */
+
+static int new_udp(struct nat *nat, su_wait_t *wait, struct binding *dummy)
+{
+ int events;
+ su_sockaddr_t from[1];
+ socklen_t fromlen = (sizeof from);
+ struct binding *b;
+ ssize_t n, m;
+
+ events = su_wait_events(wait, nat->udp_socket);
+
+ n = su_recvfrom(nat->udp_socket, nat->buffer, sizeof nat->buffer, 0,
+ from, &fromlen);
+ if (n < 0) {
+ su_perror("new_udp: recvfrom");
+ return 0;
+ }
+
+ b = nat_binding_new(nat, "UDP", SOCK_DGRAM, IPPROTO_UDP, nat->symmetric,
+ INVALID_SOCKET, from, fromlen);
+ if (b == NULL)
+ return 0;
+
+ if (nat->symmetric)
+ m = su_send(b->out_socket, nat->buffer, n, 0);
+ else
+ m = su_sendto(b->out_socket, nat->buffer, n, 0,
+ nat->out_address, nat->out_addrlen);
+
+ if (nat->logging)
+ printf("nat: udp out %d/%d %s => %s\n",
+ (int)m, (int)n, b->in_name, b->out_name);
+
+ return 0;
+}
+
+static int udp_in_to_out(struct nat *nat, su_wait_t *wait, struct binding *b)
+{
+ int events;
+ ssize_t n, m;
+
+ events = su_wait_events(wait, b->in_socket);
+
+ n = su_recv(b->in_socket, nat->buffer, sizeof nat->buffer, 0);
+ if (n < 0) {
+ su_perror("udp_in_to_out: recv");
+ return 0;
+ }
+
+ if (nat->symmetric)
+ m = su_send(b->out_socket, nat->buffer, n, 0);
+ else
+ m = su_sendto(b->out_socket, nat->buffer, n, 0,
+ nat->out_address, nat->out_addrlen);
+
+ if (nat->logging)
+ printf("nat: udp out %d/%d %s => %s\n",
+ (int)m, (int)n, b->in_name, b->out_name);
+
+ return 0;
+}
+
+static int udp_out_to_in(struct nat *nat, su_wait_t *wait, struct binding *b)
+{
+ int events;
+ ssize_t n, m;
+
+ events = su_wait_events(wait, b->out_socket);
+
+ n = su_recv(b->out_socket, nat->buffer, sizeof nat->buffer, 0);
+ if (n < 0) {
+ su_perror("udp_out_to_out: recv");
+ return 0;
+ }
+
+ m = su_send(b->in_socket, nat->buffer, n, 0);
+
+ if (nat->logging)
+ printf("nat: udp in %d/%d %s => %s\n",
+ (int)m, (int)n, b->out_name, b->in_name);
+
+ return 0;
+}
+
+/* ====================================================================== */
+
+static int new_tcp(struct nat *nat, su_wait_t *wait, struct binding *dummy)
+{
+ int events;
+ su_socket_t in_socket;
+ su_sockaddr_t from[1];
+ socklen_t fromlen = (sizeof from);
+ struct binding *b;
+
+ events = su_wait_events(wait, nat->tcp_socket);
+
+ in_socket = accept(nat->tcp_socket, (void *)from, &fromlen);
+ if (in_socket == INVALID_SOCKET) {
+ su_perror("new_tcp: accept");
+ return 0;
+ }
+
+ b = nat_binding_new(nat, "TCP", SOCK_STREAM, IPPROTO_TCP, 1,
+ in_socket, from, fromlen);
+ if (b == NULL)
+ return 0;
+
+ return 0;
+}
+
+static int tcp_in_to_out(struct nat *nat, su_wait_t *wait, struct binding *b)
+{
+ int events;
+ ssize_t n, m, o;
+
+ events = su_wait_events(wait, b->in_socket);
+
+ n = su_recv(b->in_socket, nat->buffer, sizeof nat->buffer, 0);
+ if (n < 0) {
+ su_perror("tcp_in_to_out: recv");
+ return 0;
+ }
+
+ if (n == 0) {
+ if (nat->logging)
+ printf("nat: tcp out FIN %s => %s\n", b->in_name, b->out_name);
+ shutdown(b->out_socket, 1);
+ su_root_eventmask(nat->root, b->in_register, b->in_socket, 0);
+ b->in_closed = 1;
+ if (b->out_closed && b->in_closed)
+ nat_binding_destroy(b);
+ return 0;
+ }
+
+ for (m = 0; m < n; m += o) {
+ o = su_send(b->out_socket, nat->buffer + m, n - m, 0);
+ if (o < 0) {
+ su_perror("tcp_in_to_out: send");
+ break;
+ }
+ }
+
+ if (nat->logging)
+ printf("nat: tcp out %d/%d %s => %s\n",
+ (int)m, (int)n, b->in_name, b->out_name);
+
+ return 0;
+}
+
+static int tcp_out_to_in(struct nat *nat, su_wait_t *wait, struct binding *b)
+{
+ int events;
+ ssize_t n, m, o;
+
+ events = su_wait_events(wait, b->out_socket);
+
+ n = su_recv(b->out_socket, nat->buffer, sizeof nat->buffer, 0);
+ if (n < 0) {
+ su_perror("tcp_out_to_in: recv");
+ return 0;
+ }
+
+ if (n == 0) {
+ if (nat->logging)
+ printf("nat: tcp out FIN %s => %s\n", b->out_name, b->in_name);
+ shutdown(b->in_socket, 1);
+ su_root_eventmask(nat->root, b->in_register, b->out_socket, 0);
+ b->out_closed = 1;
+ if (b->out_closed && b->in_closed)
+ nat_binding_destroy(b);
+ return 0;
+ }
+
+ for (m = 0; m < n; m += o) {
+ o = su_send(b->in_socket, nat->buffer + m, n - m, 0);
+ if (o < 0) {
+ if (su_errno() != EPIPE)
+ su_perror("tcp_in_to_out: send");
+ break;
+ }
+ }
+
+ if (nat->logging)
+ printf("nat: tcp in %d/%d %s => %s\n",
+ (int)m, (int)n, b->out_name, b->in_name);
+
+ return 0;
+}
+
+static int invalidate_binding(struct binding *b)
+{
+ struct nat *nat = b->nat;
+ su_sockaddr_t addr[1];
+ socklen_t addrlen = (sizeof addr);
+ su_socket_t out;
+ int out_register;
+ su_wait_t wout[1];
+ char name[64];
+
+ out = su_socket(nat->fake->li_family, b->socktype, 0);
+ if (out == INVALID_SOCKET) {
+ su_perror("new_udp: socket");
+ return -1;
+ }
+ if (bind(out, (void *)nat->fake->li_addr, nat->fake->li_addrlen) < 0) {
+ su_perror("new_udp: bind(to)");
+ su_close(out);
+ return -1;
+ }
+
+ if (nat->symmetric)
+ if (connect(out, (void *)nat->out_address, nat->out_addrlen) < 0) {
+ su_perror("new_udp: connect(to)");
+ su_close(out);
+ return -1;
+ }
+
+ if (su_wait_create(wout, out, SU_WAIT_IN) < 0) {
+ su_perror("new_udp: su_wait_create");
+ su_close(out);
+ return -1;
+ }
+
+ if (b->socktype == SOCK_DGRAM)
+ out_register = su_root_register(nat->root, wout, udp_out_to_in, b, 0);
+ else
+ out_register = su_root_register(nat->root, wout, tcp_out_to_in, b, 0);
+
+ if (out_register < 0) {
+ su_perror("new_udp: su_root_register");
+ su_wait_destroy(wout);
+ su_close(out);
+ return -1;
+ }
+
+ su_root_deregister(nat->root, b->out_register);
+ su_close(b->out_socket);
+
+ b->out_socket = out;
+ b->out_register = out_register;
+
+ getsockname(out, (void *)addr, &addrlen);
+ inet_ntop(addr->su_family, SU_ADDR(addr), name, sizeof name);
+ snprintf(b->out_name, sizeof b->out_name,
+ addr->su_family == AF_INET6 ? "[%s]:%u" : "%s:%u",
+ name, ntohs(addr->su_port));
+
+ if (nat->logging)
+ printf("nat: flushed binding %s <=> %s\n", b->in_name, b->out_name);
+
+ return 0;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nat.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nat.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,61 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef TEST_NAT_H
+#define TEST_NAT_H
+
+#include <sofia-sip/su_wait.h>
+#include <sofia-sip/nta.h>
+
+SOFIA_BEGIN_DECLS
+
+struct nat;
+
+struct nat *test_nat_create(su_root_t *, int family,
+ tag_type_t, tag_value_t, ...);
+
+void test_nat_destroy(struct nat *);
+
+int test_nat_private(struct nat *nat, void *address, socklen_t *return_addrlen);
+int test_nat_public(struct nat *nat, void const *address, int addrlen);
+
+int test_nat_flush(struct nat *nat);
+
+/* Tags */
+
+/** If true, act as symmetric nat. */
+#define TESTNATTAG_SYMMETRIC(x) testnattag_symmetric, tag_bool_v((x))
+#define TESTNATTAG_SYMMETRIC_REF(x) testnattag_symmetric_ref, tag_bool_vr(&(x))
+extern tag_typedef_t testnattag_symmetric;
+extern tag_typedef_t testnattag_symmetric_ref;
+
+/** If true, print information about connections. */
+#define TESTNATTAG_LOGGING(x) testnattag_logging, tag_bool_v((x))
+#define TESTNATTAG_LOGGING_REF(x) testnattag_logging_ref, tag_bool_vr(&(x))
+extern tag_typedef_t testnattag_logging;
+extern tag_typedef_t testnattag_logging_ref;
+
+SOFIA_END_DECLS
+
+#endif
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nat_tags.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nat_tags.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,40 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_nat_tags.c
+ * @brief Tags for simulated NAT
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Mar 8 19:54:28 EET 2006
+ */
+
+#include "config.h"
+
+#include "test_nat.h"
+
+tag_typedef_t testnattag_symmetric = BOOLTAG_TYPEDEF(symmetric);
+tag_typedef_t testnattag_symmetric_ref = REFTAG_TYPEDEF(testnattag_symmetric);
+tag_typedef_t testnattag_logging = BOOLTAG_TYPEDEF(symmetric);
+tag_typedef_t testnattag_logging_ref = REFTAG_TYPEDEF(testnattag_logging);
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nua.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nua.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,312 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_nua.c
+ * @brief High-level tester for Sofia SIP User Agent Engine
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti Mela at nokia.com>
+ *
+ * @date Created: Wed Aug 17 12:12:12 EEST 2005 ppessi
+ */
+
+#include "config.h"
+
+#include "test_nua.h"
+
+#if HAVE_ALARM
+#include <signal.h>
+#endif
+
+#if defined(_WIN32)
+#include <fcntl.h>
+#endif
+
+SOFIAPUBVAR su_log_t nua_log[];
+SOFIAPUBVAR su_log_t soa_log[];
+SOFIAPUBVAR su_log_t nea_log[];
+SOFIAPUBVAR su_log_t nta_log[];
+SOFIAPUBVAR su_log_t tport_log[];
+SOFIAPUBVAR su_log_t su_log_default[];
+
+char const name[] = "test_nua";
+int print_headings = 1;
+int tstflags = 0;
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+#define __func__ name
+#endif
+
+#if HAVE_ALARM
+static RETSIGTYPE sig_alarm(int s)
+{
+ fprintf(stderr, "%s: FAIL! test timeout!\n", name);
+ exit(1);
+}
+#endif
+
+static char const options_usage[] =
+ " -v | --verbose be verbose\n"
+ " -q | --quiet be quiet\n"
+ " -s use only single thread\n"
+ " -l level set logging level (0 by default)\n"
+ " -e | --events print nua events\n"
+ " -A print nua events for A\n"
+ " -B print nua events for B\n"
+ " -C print nua events for C\n"
+ " --attach print pid, wait for a debugger to be attached\n"
+ " --no-proxy do not use internal proxy\n"
+ " --no-nat do not use internal \"nat\"\n"
+ " --symmetric run internal \"nat\" in symmetric mode\n"
+ " -N print events from internal \"nat\"\n"
+ " --no-alarm don't ask for guard ALARM\n"
+ " -p uri specify uri of outbound proxy (implies --no-proxy)\n"
+ " --proxy-tests run tests involving proxy, too\n"
+ " -k do not exit after first error\n"
+ ;
+
+void usage(int exitcode)
+{
+ fprintf(stderr, "usage: %s OPTIONS\n where OPTIONS are\n%s",
+ name, options_usage);
+ exit(exitcode);
+}
+
+int main(int argc, char *argv[])
+{
+ int retval = 0;
+ int i, o_quiet = 0, o_attach = 0, o_alarm = 1;
+ int o_events_init = 0, o_events_a = 0, o_events_b = 0, o_events_c = 0;
+ int o_iproxy = 1, o_inat = 1;
+ int o_inat_symmetric = 0, o_inat_logging = 0, o_expensive = 0;
+ url_t const *o_proxy = NULL;
+ int level = 0;
+
+ struct context ctx[1] = {{{ SU_HOME_INIT(ctx) }}};
+
+ if (getenv("EXPENSIVE_CHECKS"))
+ o_expensive = 1;
+
+ ctx->threading = 1;
+ ctx->quit_on_single_failure = 1;
+
+ endpoint_init(ctx, &ctx->a, 'a');
+ endpoint_init(ctx, &ctx->b, 'b');
+ endpoint_init(ctx, &ctx->c, 'c');
+
+ for (i = 1; argv[i]; i++) {
+ if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--verbose") == 0)
+ tstflags |= tst_verbatim;
+ else if (strcmp(argv[i], "-a") == 0 || strcmp(argv[i], "--abort") == 0)
+ tstflags |= tst_abort;
+ else if (strcmp(argv[i], "-q") == 0 || strcmp(argv[i], "--quiet") == 0)
+ tstflags &= ~tst_verbatim, o_quiet = 1;
+ else if (strcmp(argv[i], "-k") == 0)
+ ctx->quit_on_single_failure = 0;
+ else if (strncmp(argv[i], "-l", 2) == 0) {
+ char *rest = NULL;
+
+ if (argv[i][2])
+ level = strtol(argv[i] + 2, &rest, 10);
+ else if (argv[i + 1])
+ level = strtol(argv[i + 1], &rest, 10), i++;
+ else
+ level = 3, rest = "";
+
+ if (rest == NULL || *rest)
+ usage(1);
+
+ su_log_set_level(nua_log, level);
+ su_log_soft_set_level(soa_log, level);
+ su_log_soft_set_level(nea_log, level);
+ su_log_soft_set_level(nta_log, level);
+ su_log_soft_set_level(tport_log, level);
+ }
+ else if (strcmp(argv[i], "-e") == 0 || strcmp(argv[i], "--events") == 0) {
+ o_events_init = o_events_a = o_events_b = o_events_c = 1;
+ }
+ else if (strcmp(argv[i], "-I") == 0) {
+ o_events_init = 1;
+ }
+ else if (strcmp(argv[i], "-A") == 0) {
+ o_events_a = 1;
+ }
+ else if (strcmp(argv[i], "-B") == 0) {
+ o_events_b = 1;
+ }
+ else if (strcmp(argv[i], "-C") == 0) {
+ o_events_c = 1;
+ }
+ else if (strcmp(argv[i], "-s") == 0) {
+ ctx->threading = 0;
+ }
+ else if (strcmp(argv[i], "--attach") == 0) {
+ o_attach = 1;
+ }
+ else if (strncmp(argv[i], "-p", 2) == 0) {
+ if (argv[i][2])
+ o_proxy = URL_STRING_MAKE(argv[i] + 2)->us_url;
+ else if (!argv[++i] || argv[i][0] == '-')
+ usage(1);
+ else
+ o_proxy = URL_STRING_MAKE(argv[i])->us_url;
+ }
+ else if (strcmp(argv[i], "--proxy-tests") == 0) {
+ ctx->proxy_tests = 1;
+ }
+ else if (strcmp(argv[i], "--no-proxy") == 0) {
+ o_iproxy = 0;
+ }
+ else if (strcmp(argv[i], "--no-nat") == 0) {
+ o_inat = 0;
+ }
+ else if (strcmp(argv[i], "--nat") == 0) {
+ o_inat = 1;
+ }
+ else if (strcmp(argv[i], "--symmetric") == 0) {
+ o_inat_symmetric = 1;
+ }
+ else if (strcmp(argv[i], "-N") == 0) {
+ o_inat_logging = 1;
+ }
+ else if (strcmp(argv[i], "--expensive") == 0) {
+ o_expensive = 1;
+ }
+ else if (strcmp(argv[i], "--no-alarm") == 0) {
+ o_alarm = 0;
+ }
+#if SU_HAVE_OSX_CF_API /* If compiled with CoreFoundation events */
+ else if (strcmp(argv[i], "--osx-runloop") == 0) {
+ ctx->osx_runloop = 1;
+ }
+#endif
+ else if (strcmp(argv[i], "-") == 0) {
+ i++; break;
+ }
+ else if (argv[i][0] != '-') {
+ break;
+ }
+ else
+ usage(1);
+ }
+
+ if (o_attach) {
+ char line[10], *l;
+ printf("%s: pid %lu\n", name, (unsigned long)getpid());
+ printf("<Press RETURN to continue>\n");
+ l = fgets(line, sizeof line, stdin);
+ }
+#if HAVE_ALARM
+ else if (o_alarm) {
+ alarm(o_expensive ? 60 : 120);
+ signal(SIGALRM, sig_alarm);
+ }
+#endif
+
+ su_init();
+
+ if (!(TSTFLAGS & tst_verbatim)) {
+ if (level == 0 && !o_quiet)
+ level = 1;
+ su_log_soft_set_level(nua_log, level);
+ su_log_soft_set_level(soa_log, level);
+ su_log_soft_set_level(nea_log, level);
+ su_log_soft_set_level(nta_log, level);
+ su_log_soft_set_level(tport_log, level);
+ }
+
+ if (!o_quiet || (TSTFLAGS & tst_verbatim)
+ || o_events_a || o_events_b || o_events_c)
+ print_headings = 1;
+
+#define SINGLE_FAILURE_CHECK() \
+ do { fflush(stdout); \
+ if (retval && ctx->quit_on_single_failure) { \
+ su_deinit(); return retval; } \
+ } while(0)
+
+ ctx->a.printer = o_events_init ? print_event : NULL;
+
+ retval |= test_nua_api_errors(ctx); SINGLE_FAILURE_CHECK();
+ retval |= test_tag_filter(); SINGLE_FAILURE_CHECK();
+ retval |= test_nua_params(ctx); SINGLE_FAILURE_CHECK();
+
+ retval |= test_nua_init(ctx, o_iproxy, o_proxy, o_inat,
+ TESTNATTAG_SYMMETRIC(o_inat_symmetric),
+ TESTNATTAG_LOGGING(o_inat_logging),
+ TAG_END());
+
+ ctx->expensive = o_expensive;
+
+ if (retval == 0) {
+ ctx->a.printer = o_events_a ? print_event : NULL;
+ if (o_events_b)
+ ctx->b.printer = print_event;
+ if (o_events_c)
+ ctx->c.printer = print_event;
+
+ retval |= test_stack_errors(ctx); SINGLE_FAILURE_CHECK();
+
+ retval |= test_register(ctx);
+
+ if (retval == 0)
+ retval |= test_connectivity(ctx);
+
+ if (retval == 0 && o_inat)
+ retval |= test_nat_timeout(ctx);
+
+ if (retval == 0) {
+ retval |= test_extension(ctx); SINGLE_FAILURE_CHECK();
+ retval |= test_basic_call(ctx); SINGLE_FAILURE_CHECK();
+ retval |= test_reject_a(ctx); SINGLE_FAILURE_CHECK();
+ retval |= test_reject_b(ctx); SINGLE_FAILURE_CHECK();
+ retval |= test_reject_302(ctx); SINGLE_FAILURE_CHECK();
+ retval |= test_reject_401(ctx); SINGLE_FAILURE_CHECK();
+ retval |= test_mime_negotiation(ctx); SINGLE_FAILURE_CHECK();
+ retval |= test_reject_401_aka(ctx); SINGLE_FAILURE_CHECK();
+ retval |= test_call_cancel(ctx); SINGLE_FAILURE_CHECK();
+ retval |= test_call_destroy(ctx); SINGLE_FAILURE_CHECK();
+ retval |= test_early_bye(ctx); SINGLE_FAILURE_CHECK();
+ retval |= test_reinvites(ctx); SINGLE_FAILURE_CHECK();
+ retval |= test_session_timer(ctx); SINGLE_FAILURE_CHECK();
+ retval |= test_refer(ctx); SINGLE_FAILURE_CHECK();
+ retval |= test_100rel(ctx); SINGLE_FAILURE_CHECK();
+ retval |= test_simple(ctx); SINGLE_FAILURE_CHECK();
+ retval |= test_events(ctx); SINGLE_FAILURE_CHECK();
+ }
+
+ if (ctx->proxy_tests && (retval == 0 || !ctx->p))
+ retval |= test_unregister(ctx); SINGLE_FAILURE_CHECK();
+ }
+ retval |= test_deinit(ctx);
+
+ su_home_deinit(ctx->home);
+
+ su_deinit();
+
+ return retval;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nua.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nua.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,338 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_nua.h
+ * @brief High-level tester framework for Sofia SIP User Agent Engine
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti Mela at nokia.com>
+ *
+ * @date Created: Wed Aug 17 12:12:12 EEST 2005 ppessi
+ */
+
+#ifndef TEST_NUA_H
+#define TEST_NUA_H
+
+struct context;
+#define NUA_MAGIC_T struct context
+
+struct call;
+#define NUA_HMAGIC_T struct call
+
+#include "sofia-sip/nua.h"
+#include "sofia-sip/sip_status.h"
+
+#include <sofia-sip/sdp.h>
+#include <sofia-sip/sip_header.h>
+
+#include <sofia-sip/su_log.h>
+#include <sofia-sip/su_tagarg.h>
+#include <sofia-sip/su_tag_io.h>
+
+#if __APPLE_CC__
+#include <sofia-sip/su_osx_runloop.h>
+#endif
+
+#include <test_proxy.h>
+#include <test_nat.h>
+#include <sofia-sip/auth_module.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <assert.h>
+#include <unistd.h>
+
+extern char const name[];
+
+extern int print_headings;
+extern int tstflags;
+#define TSTFLAGS tstflags
+
+#include <sofia-sip/tstdef.h>
+
+#define TEST_E(a, b) TEST_S(nua_event_name(a), nua_event_name(b))
+
+#define NONE ((void*)-1)
+
+struct endpoint;
+
+typedef
+int condition_function(nua_event_t event,
+ int status, char const *phrase,
+ nua_t *nua, struct context *ctx,
+ struct endpoint *ep,
+ nua_handle_t *nh, struct call *call,
+ sip_t const *sip,
+ tagi_t tags[]);
+
+typedef
+void printer_function(nua_event_t event,
+ char const *operation,
+ int status, char const *phrase,
+ nua_t *nua, struct context *ctx,
+ struct endpoint *ep,
+ nua_handle_t *nh, struct call *call,
+ sip_t const *sip,
+ tagi_t tags[]);
+
+struct proxy_transaction;
+struct registration_entry;
+
+enum { event_is_extra, event_is_normal, event_is_special };
+
+struct eventlist
+{
+ nua_event_t kind;
+ struct event *head, **tail;
+};
+
+struct event
+{
+ struct event *next, **prev;
+ struct call *call;
+ nua_saved_event_t saved_event[1];
+ nua_event_data_t const *data;
+};
+
+
+struct context
+{
+ su_home_t home[1];
+ su_root_t *root;
+
+ int threading, proxy_tests, expensive, quit_on_single_failure, osx_runloop;
+ char const *external_proxy;
+
+ struct endpoint {
+ char name[4];
+ struct context *ctx; /* Backpointer */
+
+ int running;
+
+ condition_function *next_condition;
+ nua_event_t next_event, last_event;
+ nua_t *nua;
+ sip_contact_t *contact;
+ sip_from_t *to;
+
+ printer_function *printer;
+
+ char const *instance;
+
+ /* Per-call stuff */
+ struct call {
+ struct call *next;
+ nua_handle_t *nh;
+ char const *sdp;
+ struct eventlist *events;
+ } call[1], reg[1];
+
+ int (*is_special)(nua_event_t e);
+
+ /* Normal events are saved here */
+ struct eventlist events[1];
+ /* Special events are saved here */
+ struct eventlist specials[1];
+
+ /* State flags for complex scenarios */
+ union {
+ struct {
+ unsigned bit0:1, bit1:1, bit2:1, bit3:1;
+ unsigned bit4:1, bit5:1, bit6:1, bit7:1;
+ } b;
+ unsigned n;
+ } flags;
+
+ } a, b, c;
+
+ struct proxy *p;
+ struct nat *nat;
+};
+
+#define RETURN_ON_SINGLE_FAILURE(retval) \
+ do { \
+ fflush(stdout); \
+ if (retval && ctx->quit_on_single_failure) { return retval; } \
+ } while(0)
+
+
+int save_event_in_list(struct context *,
+ nua_event_t nevent,
+ struct endpoint *,
+ struct call *);
+void free_events_in_list(struct context *,
+ struct eventlist *);
+
+#define CONDITION_PARAMS \
+ nua_event_t event, \
+ int status, char const *phrase, \
+ nua_t *nua, struct context *ctx, \
+ struct endpoint *ep, \
+ nua_handle_t *nh, struct call *call, \
+ sip_t const *sip, \
+ tagi_t tags[]
+
+int save_events(CONDITION_PARAMS);
+int until_final_response(CONDITION_PARAMS);
+int save_until_final_response(CONDITION_PARAMS);
+int save_until_received(CONDITION_PARAMS);
+int save_until_special(CONDITION_PARAMS);
+
+int until_terminated(CONDITION_PARAMS);
+int until_ready(CONDITION_PARAMS);
+int accept_call(CONDITION_PARAMS);
+
+void a_callback(nua_event_t event,
+ int status, char const *phrase,
+ nua_t *nua, struct context *ctx,
+ nua_handle_t *nh, struct call *call,
+ sip_t const *sip,
+ tagi_t tags[]);
+void b_callback(nua_event_t event,
+ int status, char const *phrase,
+ nua_t *nua, struct context *ctx,
+ nua_handle_t *nh, struct call *call,
+ sip_t const *sip,
+ tagi_t tags[]);
+void c_callback(nua_event_t event,
+ int status, char const *phrase,
+ nua_t *nua, struct context *ctx,
+ nua_handle_t *nh, struct call *call,
+ sip_t const *sip,
+ tagi_t tags[]);
+
+void run_abc_until(struct context *ctx,
+ nua_event_t a_event, condition_function *a_condition,
+ nua_event_t b_event, condition_function *b_condition,
+ nua_event_t c_event, condition_function *c_condition);
+
+void run_ab_until(struct context *ctx,
+ nua_event_t a_event, condition_function *a_condition,
+ nua_event_t b_event, condition_function *b_condition);
+
+void run_bc_until(struct context *ctx,
+ nua_event_t b_event, condition_function *b_condition,
+ nua_event_t c_event, condition_function *c_condition);
+
+int run_a_until(struct context *, nua_event_t, condition_function *);
+int run_b_until(struct context *, nua_event_t, condition_function *);
+int run_c_until(struct context *, nua_event_t, condition_function *);
+
+typedef int operation_f(struct endpoint *ep, struct call *call,
+ nua_handle_t *nh, tag_type_t tag, tag_value_t value,
+ ...);
+
+operation_f INVITE, ACK, BYE, CANCEL, AUTHENTICATE, UPDATE, INFO, PRACK,
+ REFER, MESSAGE, METHOD, OPTIONS, PUBLISH, UNPUBLISH, REGISTER, UNREGISTER,
+ SUBSCRIBE, UNSUBSCRIBE, NOTIFY, NOTIFIER, TERMINATE, AUTHORIZE;
+
+int RESPOND(struct endpoint *ep,
+ struct call *call,
+ nua_handle_t *nh,
+ int status, char const *phrase,
+ tag_type_t tag, tag_value_t value,
+ ...);
+
+int DESTROY(struct endpoint *ep,
+ struct call *call,
+ nua_handle_t *nh);
+
+struct call *check_handle(struct endpoint *ep,
+ struct call *call,
+ nua_handle_t *nh,
+ int status, char const *phrase);
+
+int is_special(nua_event_t e);
+int callstate(tagi_t const *tags);
+int is_offer_sent(tagi_t const *tags);
+int is_answer_sent(tagi_t const *tags);
+int is_offer_recv(tagi_t const *tags);
+int is_answer_recv(tagi_t const *tags);
+int is_offer_answer_done(tagi_t const *tags);
+int audio_activity(tagi_t const *tags);
+int video_activity(tagi_t const *tags);
+
+void print_event(nua_event_t event,
+ char const *operation,
+ int status, char const *phrase,
+ nua_t *nua, struct context *ctx,
+ struct endpoint *ep,
+ nua_handle_t *nh, struct call *call,
+ sip_t const *sip,
+ tagi_t tags[]);
+
+static inline
+void eventlist_init(struct eventlist *list)
+{
+ list->tail = &list->head;
+}
+
+static inline
+void call_init(struct call *call)
+{
+}
+
+void endpoint_init(struct context *ctx, struct endpoint *e, char id);
+
+int test_nua_init(struct context *ctx,
+ int start_proxy,
+ url_t const *o_proxy,
+ int start_nat,
+ tag_type_t tag, tag_value_t value, ...);
+
+int test_deinit(struct context *ctx);
+
+int test_nua_api_errors(struct context *ctx);
+int test_stack_errors(struct context *ctx);
+int test_tag_filter(void);
+int test_nua_params(struct context *ctx);
+
+int test_register(struct context *ctx);
+int test_connectivity(struct context *ctx);
+int test_nat_timeout(struct context *ctx);
+int test_unregister(struct context *ctx);
+
+int test_basic_call(struct context *ctx);
+int test_reject_a(struct context *ctx);
+int test_reject_b(struct context *ctx);
+int test_reject_302(struct context *ctx);
+int test_reject_401(struct context *ctx);
+int test_mime_negotiation(struct context *ctx);
+int test_reject_401_aka(struct context *ctx);
+int test_call_cancel(struct context *ctx);
+int test_call_destroy(struct context *ctx);
+int test_early_bye(struct context *ctx);
+int test_call_hold(struct context *ctx);
+int test_reinvites(struct context *ctx);
+int test_session_timer(struct context *ctx);
+int test_refer(struct context *ctx);
+int test_100rel(struct context *ctx);
+int test_simple(struct context *ctx);
+int test_events(struct context *ctx);
+
+int test_extension(struct context *ctx);
+
+#endif
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nua_api.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nua_api.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,280 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_nua_api.c
+ * @brief NUA API tester.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti Mela at nokia.com>
+ *
+ * @date Created: Wed Aug 17 12:12:12 EEST 2005 ppessi
+ */
+
+#include "config.h"
+
+#include "test_nua.h"
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+#define __func__ "test_nua_api_errors"
+#endif
+
+/* ------------------------------------------------------------------------ */
+/* API tests */
+
+SOFIAPUBVAR su_log_t nua_log[];
+
+int check_set_status(int status, char const *phrase)
+{
+ return status == 200 && strcmp(phrase, sip_200_OK) == 0;
+}
+
+int test_nua_api_errors(struct context *ctx)
+{
+ BEGIN();
+
+ /* Invoke every API function with invalid arguments */
+
+ int level;
+
+ int status; char const *phrase;
+
+ if (print_headings)
+ printf("TEST NUA-1.0: test API\n");
+
+ /* This is a nasty macro. Test it. */
+#define SET_STATUS1(x) ((status = x), status), (phrase = ((void)x))
+ TEST_1(check_set_status(SET_STATUS1(SIP_200_OK)));
+ TEST(status, 200); TEST_S(phrase, sip_200_OK);
+
+ su_log_init(nua_log);
+ if (!(tstflags & tst_verbatim))
+ su_log_set_level(nua_log, 0); /* Log at level 0 by default */
+ level = nua_log->log_level;
+
+ TEST_1(!nua_create(NULL, NULL, NULL, TAG_END()));
+ TEST_VOID(nua_shutdown(NULL));
+ TEST_VOID(nua_destroy(NULL));
+ TEST_VOID(nua_set_params(NULL, TAG_END()));
+ TEST_VOID(nua_get_params(NULL, TAG_END()));
+ TEST_1(!nua_default(NULL));
+ TEST_1(!nua_handle(NULL, NULL, TAG_END()));
+ TEST_VOID(nua_handle_destroy(NULL));
+ TEST_VOID(nua_handle_bind(NULL, NULL));
+ TEST_1(!nua_handle_has_invite(NULL));
+ TEST_1(!nua_handle_has_subscribe(NULL));
+ TEST_1(!nua_handle_has_register(NULL));
+ TEST_1(!nua_handle_has_active_call(NULL));
+ TEST_1(!nua_handle_has_call_on_hold(NULL));
+ TEST_1(!nua_handle_has_events(NULL));
+ TEST_1(!nua_handle_has_registrations(NULL));
+ TEST_1(!nua_handle_remote(NULL));
+ TEST_1(!nua_handle_local(NULL));
+ TEST_S(nua_event_name(-1), "NUA_UNKNOWN");
+ TEST_VOID(nua_register(NULL, TAG_END()));
+ TEST_VOID(nua_unregister(NULL, TAG_END()));
+ TEST_VOID(nua_invite(NULL, TAG_END()));
+ TEST_VOID(nua_ack(NULL, TAG_END()));
+ TEST_VOID(nua_prack(NULL, TAG_END()));
+ TEST_VOID(nua_options(NULL, TAG_END()));
+ TEST_VOID(nua_publish(NULL, TAG_END()));
+ TEST_VOID(nua_message(NULL, TAG_END()));
+ TEST_VOID(nua_chat(NULL, TAG_END()));
+ TEST_VOID(nua_info(NULL, TAG_END()));
+ TEST_VOID(nua_subscribe(NULL, TAG_END()));
+ TEST_VOID(nua_unsubscribe(NULL, TAG_END()));
+ TEST_VOID(nua_notify(NULL, TAG_END()));
+ TEST_VOID(nua_notifier(NULL, TAG_END()));
+ TEST_VOID(nua_terminate(NULL, TAG_END()));
+ TEST_VOID(nua_refer(NULL, TAG_END()));
+ TEST_VOID(nua_update(NULL, TAG_END()));
+ TEST_VOID(nua_bye(NULL, TAG_END()));
+ TEST_VOID(nua_cancel(NULL, TAG_END()));
+ TEST_VOID(nua_authenticate(NULL, TAG_END()));
+ TEST_VOID(nua_redirect(NULL, TAG_END()));
+ TEST_VOID(nua_respond(NULL, 0, "", TAG_END()));
+
+ TEST_1(!nua_handle_home(NULL));
+ TEST_1(!nua_save_event(NULL, NULL));
+ TEST_1(!nua_event_data(NULL));
+ TEST_VOID(nua_destroy_event(NULL));
+
+ {
+ nua_saved_event_t event[1];
+
+ memset(event, 0, sizeof event);
+
+ TEST_1(!nua_save_event(NULL, event));
+ TEST_1(!nua_event_data(event));
+ TEST_VOID(nua_destroy_event(event));
+ }
+
+ su_log_set_level(nua_log, level);
+
+ if (print_headings)
+ printf("TEST NUA-1.0: PASSED\n");
+
+ END();
+}
+
+/* ======================================================================== */
+
+int test_stack_errors(struct context *ctx)
+{
+ BEGIN();
+
+ struct endpoint *a = &ctx->a, *b = &ctx->b;
+ struct call *a_call = a->call;
+ struct event *e;
+
+ int internal_error = 900;
+
+ if (print_headings)
+ printf("TEST NUA-1.2: Stack error handling\n");
+
+ if (print_headings)
+ printf("TEST NUA-1.2.1: CANCEL without INVITE\n");
+
+ TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+ CANCEL(a, a_call, a_call->nh, TAG_END());
+
+ run_a_until(ctx, -1, save_until_final_response);
+
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_cancel);
+ TEST(e->data->e_status, 481);
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, a->events);
+ nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+ if (print_headings)
+ printf("TEST NUA-1.2.1: PASSED\n");
+
+ /* -BYE without INVITE--------------------------------------------------- */
+
+ if (print_headings)
+ printf("TEST NUA-1.2.2: BYE without INVITE\n");
+
+ TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+ BYE(a, a_call, a_call->nh, TAG_END());
+
+ run_a_until(ctx, -1, save_until_final_response);
+
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_bye);
+ TEST(e->data->e_status, internal_error);
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, a->events);
+ nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+ if (print_headings)
+ printf("TEST NUA-1.2.2: PASSED\n");
+
+ if (!ctx->proxy_tests)
+ goto nua_1_2_5;
+
+ /* -Un-register without REGISTER--------------------------------------- */
+
+ if (print_headings)
+ printf("TEST NUA-1.2.3: unregister without register\n");
+
+ TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(a->to), TAG_END()));
+
+ UNREGISTER(a, a_call, a_call->nh, TAG_END());
+
+ run_a_until(ctx, -1, save_until_final_response);
+
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_unregister);
+ TEST(e->data->e_status, 401);
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, a->events);
+ nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+ if (print_headings)
+ printf("TEST NUA-1.2.3: PASSED\n");
+
+ /* -Un-publish without publish--------------------------------------- */
+
+ if (print_headings)
+ printf("TEST NUA-1.2.4: unpublish without publish\n");
+
+ TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+ UNPUBLISH(a, a_call, a_call->nh, TAG_END());
+
+ run_a_until(ctx, -1, save_until_final_response);
+
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_unpublish);
+ TEST(e->data->e_status, 404);
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, a->events);
+ nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+ if (print_headings)
+ printf("TEST NUA-1.2.4: PASSED\n");
+
+ /* -terminate without notifier--------------------------------------- */
+
+ nua_1_2_5:
+ if (print_headings)
+ printf("TEST NUA-1.2.5: terminate without notifier\n");
+
+ TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+ TERMINATE(a, a_call, a_call->nh, TAG_END());
+
+ run_a_until(ctx, -1, save_until_final_response);
+
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_terminate);
+ TEST(e->data->e_status, internal_error);
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, a->events);
+
+ AUTHORIZE(a, a_call, a_call->nh, TAG_END());
+
+ run_a_until(ctx, -1, save_until_final_response);
+
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_authorize);
+ TEST(e->data->e_status, internal_error);
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, a->events);
+
+ nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+ if (print_headings)
+ printf("TEST NUA-1.2.5: PASSED\n");
+
+ if (print_headings)
+ printf("TEST NUA-1.2: PASSED\n");
+
+ END();
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nua_params.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nua_params.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,598 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_nua_params.c
+ * @brief Test NUA parameter handling.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti Mela at nokia.com>
+ *
+ * @date Created: Wed Aug 17 12:12:12 EEST 2005 ppessi
+ */
+
+#include "config.h"
+
+#include "test_nua.h"
+#include <sofia-sip/su_tag_class.h>
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+#define __func__ "test_nua_params"
+#endif
+
+int test_tag_filter(void)
+{
+ BEGIN();
+
+#undef TAG_NAMESPACE
+#define TAG_NAMESPACE "test"
+ tag_typedef_t tag_a = STRTAG_TYPEDEF(a);
+#define TAG_A(s) tag_a, tag_str_v((s))
+ tag_typedef_t tag_b = STRTAG_TYPEDEF(b);
+#define TAG_B(s) tag_b, tag_str_v((s))
+
+ tagi_t filter[2] = {{ NUTAG_ANY() }, { TAG_END() }};
+
+ tagi_t *lst, *result;
+
+ lst = tl_list(TAG_A("X"),
+ TAG_SKIP(2),
+ NUTAG_URL((void *)"urn:foo"),
+ TAG_B("Y"),
+ NUTAG_URL((void *)"urn:bar"),
+ TAG_NULL());
+
+ TEST_1(lst);
+
+ result = tl_afilter(NULL, filter, lst);
+
+ TEST_1(result);
+ TEST_P(result[0].t_tag, nutag_url);
+ TEST_P(result[1].t_tag, nutag_url);
+
+ tl_vfree(lst);
+ free(result);
+
+ END();
+}
+
+int test_nua_params(struct context *ctx)
+{
+ BEGIN();
+
+ char const Alice[] = "Alice <sip:a at wonderland.org>";
+ sip_from_t const *from;
+ su_home_t tmphome[SU_HOME_AUTO_SIZE(16384)];
+ nua_handle_t *nh;
+ struct event *e;
+ tagi_t const *t;
+ int n;
+
+ su_home_auto(tmphome, sizeof(tmphome));
+
+ if (print_headings)
+ printf("TEST NUA-1.1: PARAMETERS\n");
+
+#if SU_HAVE_OSX_CF_API
+ if (ctx->osx_runloop)
+ ctx->root = su_root_osx_runloop_create(NULL);
+ else
+#endif
+ ctx->root = su_root_create(NULL);
+ TEST_1(ctx->root);
+
+ /* Disable threading by command line switch? */
+ su_root_threading(ctx->root, ctx->threading);
+
+ ctx->a.nua = nua_create(ctx->root, a_callback, ctx,
+ SIPTAG_FROM_STR("sip:alice at example.com"),
+ NUTAG_URL("sip:0.0.0.0:*;transport=udp"),
+ TAG_END());
+
+ TEST_1(ctx->a.nua);
+
+ nua_get_params(ctx->a.nua, TAG_ANY(), TAG_END());
+ run_a_until(ctx, nua_r_get_params, save_until_final_response);
+
+ TEST_1(e = ctx->a.events->head);
+ TEST_E(e->data->e_event, nua_r_get_params);
+ for (n = 0, t = e->data->e_tags; t; n++, t = tl_next(t))
+ ;
+ TEST_1(n > 32);
+ free_events_in_list(ctx, ctx->a.events);
+
+ nh = nua_handle(ctx->a.nua, NULL, TAG_END()); TEST_1(nh);
+ nua_handle_unref(nh);
+
+ nh = nua_handle(ctx->a.nua, NULL, TAG_END()); TEST_1(nh);
+ nua_handle_destroy(nh);
+
+ from = sip_from_make(tmphome, Alice);
+
+ nh = nua_handle(ctx->a.nua, NULL, TAG_END());
+
+ nua_set_hparams(nh, NUTAG_INVITE_TIMER(90), TAG_END());
+ run_a_until(ctx, nua_r_set_params, until_final_response);
+
+ /* Modify all pointer values */
+ nua_set_params(ctx->a.nua,
+ SIPTAG_FROM_STR(Alice),
+
+ NUTAG_MEDIA_ENABLE(0),
+ NUTAG_SOA_NAME("test"),
+
+ NUTAG_REGISTRAR("sip:openlaboratory.net"),
+
+ SIPTAG_SUPPORTED_STR("test"),
+ SIPTAG_ALLOW_STR("DWIM, OPTIONS, INFO"),
+ SIPTAG_ALLOW_EVENTS_STR("reg"),
+ SIPTAG_USER_AGENT_STR("test_nua/1.0"),
+
+ SIPTAG_ORGANIZATION_STR("Open Laboratory"),
+
+ NUTAG_M_DISPLAY("XXX"),
+ NUTAG_M_USERNAME("xxx"),
+ NUTAG_M_PARAMS("user=ip"),
+ NUTAG_M_FEATURES("language=\"fi\""),
+ NUTAG_INSTANCE("urn:uuid:3eb007b1-6d7f-472e-8b64-29e482795da8"),
+ NUTAG_OUTBOUND("bar"),
+
+ TAG_END());
+
+ run_a_until(ctx, nua_r_set_params, until_final_response);
+
+ /* Modify everything from their default value */
+ nua_set_params(ctx->a.nua,
+ SIPTAG_FROM(from),
+ NUTAG_RETRY_COUNT(9),
+ NUTAG_MAX_SUBSCRIPTIONS(6),
+
+ NUTAG_ENABLEINVITE(0),
+ NUTAG_AUTOALERT(1),
+ NUTAG_EARLY_MEDIA(1),
+ NUTAG_AUTOANSWER(1),
+ NUTAG_AUTOACK(0),
+ NUTAG_INVITE_TIMER(60),
+
+ NUTAG_SESSION_TIMER(600),
+ NUTAG_MIN_SE(35),
+ NUTAG_SESSION_REFRESHER(nua_remote_refresher),
+ NUTAG_UPDATE_REFRESH(1),
+
+ NUTAG_ENABLEMESSAGE(0),
+ NUTAG_ENABLEMESSENGER(1),
+ /* NUTAG_MESSAGE_AUTOANSWER(0), */
+
+ NUTAG_CALLEE_CAPS(1),
+ NUTAG_MEDIA_FEATURES(1),
+ NUTAG_SERVICE_ROUTE_ENABLE(0),
+ NUTAG_PATH_ENABLE(0),
+ NUTAG_REFER_EXPIRES(333),
+ NUTAG_REFER_WITH_ID(0),
+ NUTAG_SUBSTATE(nua_substate_pending),
+
+ NUTAG_KEEPALIVE(66),
+ NUTAG_KEEPALIVE_STREAM(33),
+
+ NUTAG_INSTANCE("urn:uuid:97701ad9-39df-1229-1083-dbc0a85f029c"),
+ NUTAG_M_DISPLAY("Joe"),
+ NUTAG_M_USERNAME("joe"),
+ NUTAG_M_PARAMS("user=phone"),
+ NUTAG_M_FEATURES("language=\"en\""),
+ NUTAG_OUTBOUND("foo"),
+ SIPTAG_SUPPORTED(sip_supported_make(tmphome, "foo")),
+ NUTAG_SUPPORTED("foo, bar"),
+ SIPTAG_SUPPORTED_STR(",baz,"),
+
+ SIPTAG_ALLOW_STR("OPTIONS"),
+ SIPTAG_ALLOW(sip_allow_make(tmphome, "INFO")),
+ NUTAG_ALLOW("ACK, INFO"),
+
+ SIPTAG_ALLOW_EVENTS_STR("reg"),
+ SIPTAG_ALLOW_EVENTS(sip_allow_events_make(tmphome, "presence")),
+ NUTAG_ALLOW_EVENTS("presence.winfo"),
+
+ SIPTAG_USER_AGENT(sip_user_agent_make(tmphome, "test_nua")),
+
+ SIPTAG_ORGANIZATION(sip_organization_make(tmphome, "Pussy Galore's Flying Circus")),
+
+ NUTAG_MEDIA_ENABLE(0),
+ NUTAG_REGISTRAR(url_hdup(tmphome, (url_t *)"sip:sip.wonderland.org")),
+
+ TAG_END());
+
+ run_a_until(ctx, nua_r_set_params, until_final_response);
+
+ /* Modify something... */
+ nua_set_params(ctx->a.nua,
+ NUTAG_RETRY_COUNT(5),
+ TAG_END());
+ run_a_until(ctx, nua_r_set_params, until_final_response);
+
+ {
+ sip_from_t const *from = NONE;
+ char const *from_str = "NONE";
+
+ unsigned retry_count = (unsigned)-1;
+ unsigned max_subscriptions = (unsigned)-1;
+
+ char const *soa_name = "NONE";
+ int media_enable = -1;
+ int invite_enable = -1;
+ int auto_alert = -1;
+ int early_media = -1;
+ int only183_100rel = -1;
+ int auto_answer = -1;
+ int auto_ack = -1;
+ unsigned invite_timeout = (unsigned)-1;
+
+ unsigned session_timer = (unsigned)-1;
+ unsigned min_se = (unsigned)-1;
+ int refresher = -1;
+ int update_refresh = -1;
+
+ int message_enable = -1;
+ int win_messenger_enable = -1;
+ int message_auto_respond = -1;
+
+ int callee_caps = -1;
+ int media_features = -1;
+ int service_route_enable = -1;
+ int path_enable = -1;
+ unsigned refer_expires = (unsigned)-1;
+ int refer_with_id = -1;
+ int substate = -1;
+
+ sip_allow_t const *allow = NONE;
+ char const *allow_str = "NONE";
+ sip_allow_events_t const *allow_events = NONE;
+ char const *allow_events_str = "NONE";
+ sip_supported_t const *supported = NONE;
+ char const *supported_str = "NONE";
+ sip_user_agent_t const *user_agent = NONE;
+ char const *user_agent_str = "NONE";
+ char const *ua_name = "NONE";
+ sip_organization_t const *organization = NONE;
+ char const *organization_str = "NONE";
+
+ char const *outbound = "NONE";
+ char const *m_display = "NONE";
+ char const *m_username = "NONE";
+ char const *m_params = "NONE";
+ char const *m_features = "NONE";
+ char const *instance = "NONE";
+
+ url_string_t const *registrar = NONE;
+ unsigned keepalive = (unsigned)-1, keepalive_stream = (unsigned)-1;
+
+ nua_get_params(ctx->a.nua, TAG_ANY(), TAG_END());
+ run_a_until(ctx, nua_r_get_params, save_until_final_response);
+
+ TEST_1(e = ctx->a.events->head);
+ TEST_E(e->data->e_event, nua_r_get_params);
+
+ n = tl_gets(e->data->e_tags,
+ SIPTAG_FROM_REF(from),
+ SIPTAG_FROM_STR_REF(from_str),
+
+ NUTAG_RETRY_COUNT_REF(retry_count),
+ NUTAG_MAX_SUBSCRIPTIONS_REF(max_subscriptions),
+
+ NUTAG_SOA_NAME_REF(soa_name),
+ NUTAG_MEDIA_ENABLE_REF(media_enable),
+ NUTAG_ENABLEINVITE_REF(invite_enable),
+ NUTAG_AUTOALERT_REF(auto_alert),
+ NUTAG_EARLY_MEDIA_REF(early_media),
+ NUTAG_ONLY183_100REL_REF(only183_100rel),
+ NUTAG_AUTOANSWER_REF(auto_answer),
+ NUTAG_AUTOACK_REF(auto_ack),
+ NUTAG_INVITE_TIMER_REF(invite_timeout),
+
+ NUTAG_SESSION_TIMER_REF(session_timer),
+ NUTAG_MIN_SE_REF(min_se),
+ NUTAG_SESSION_REFRESHER_REF(refresher),
+ NUTAG_UPDATE_REFRESH_REF(update_refresh),
+
+ NUTAG_ENABLEMESSAGE_REF(message_enable),
+ NUTAG_ENABLEMESSENGER_REF(win_messenger_enable),
+ /* NUTAG_MESSAGE_AUTOANSWER(message_auto_respond), */
+
+ NUTAG_CALLEE_CAPS_REF(callee_caps),
+ NUTAG_MEDIA_FEATURES_REF(media_features),
+ NUTAG_SERVICE_ROUTE_ENABLE_REF(service_route_enable),
+ NUTAG_PATH_ENABLE_REF(path_enable),
+ NUTAG_REFER_EXPIRES_REF(refer_expires),
+ NUTAG_REFER_WITH_ID_REF(refer_with_id),
+ NUTAG_SUBSTATE_REF(substate),
+
+ SIPTAG_SUPPORTED_REF(supported),
+ SIPTAG_SUPPORTED_STR_REF(supported_str),
+ SIPTAG_ALLOW_REF(allow),
+ SIPTAG_ALLOW_STR_REF(allow_str),
+ SIPTAG_ALLOW_EVENTS_REF(allow_events),
+ SIPTAG_ALLOW_EVENTS_STR_REF(allow_events_str),
+ SIPTAG_USER_AGENT_REF(user_agent),
+ SIPTAG_USER_AGENT_STR_REF(user_agent_str),
+ NUTAG_USER_AGENT_REF(ua_name),
+
+ SIPTAG_ORGANIZATION_REF(organization),
+ SIPTAG_ORGANIZATION_STR_REF(organization_str),
+
+ NUTAG_REGISTRAR_REF(registrar),
+ NUTAG_KEEPALIVE_REF(keepalive),
+ NUTAG_KEEPALIVE_STREAM_REF(keepalive_stream),
+
+ NUTAG_OUTBOUND_REF(outbound),
+ NUTAG_M_DISPLAY_REF(m_display),
+ NUTAG_M_USERNAME_REF(m_username),
+ NUTAG_M_PARAMS_REF(m_params),
+ NUTAG_M_FEATURES_REF(m_features),
+ NUTAG_INSTANCE_REF(instance),
+
+ TAG_END());
+ TEST(n, 46);
+
+ TEST_S(sip_header_as_string(tmphome, (void *)from), Alice);
+ TEST_S(from_str, Alice);
+
+ TEST(retry_count, 5);
+ TEST(max_subscriptions, 6);
+
+ TEST_S(soa_name, "test");
+ TEST(media_enable, 0);
+ TEST(invite_enable, 0);
+ TEST(auto_alert, 1);
+ TEST(early_media, 1);
+ TEST(auto_answer, 1);
+ TEST(auto_ack, 0);
+ TEST(invite_timeout, 60);
+
+ TEST(session_timer, 600);
+ TEST(min_se, 35);
+ TEST(refresher, nua_remote_refresher);
+ TEST(update_refresh, 1);
+
+ TEST(message_enable, 0);
+ TEST(win_messenger_enable, 1);
+ TEST(message_auto_respond, -1); /* XXX */
+
+ TEST(callee_caps, 1);
+ TEST(media_features, 1);
+ TEST(service_route_enable, 0);
+ TEST(path_enable, 0);
+ TEST(refer_expires, 333);
+ TEST(refer_with_id, 0);
+ TEST(substate, nua_substate_pending);
+
+ TEST_S(sip_header_as_string(tmphome, (void *)allow), "OPTIONS, INFO, ACK");
+ TEST_S(allow_str, "OPTIONS, INFO, ACK");
+ TEST_S(sip_header_as_string(tmphome, (void *)allow_events),
+ "reg, presence, presence.winfo");
+ TEST_S(allow_events_str, "reg, presence, presence.winfo");
+ TEST_S(sip_header_as_string(tmphome, (void *)supported),
+ "foo, bar, baz");
+ TEST_S(supported_str, "foo, bar, baz");
+ TEST_S(sip_header_as_string(tmphome, (void *)user_agent), "test_nua");
+ TEST_S(user_agent_str, "test_nua");
+ TEST_S(sip_header_as_string(tmphome, (void *)organization),
+ "Pussy Galore's Flying Circus");
+ TEST_S(organization_str, "Pussy Galore's Flying Circus");
+
+ TEST_S(url_as_string(tmphome, registrar->us_url),
+ "sip:sip.wonderland.org");
+ TEST(keepalive, 66);
+ TEST(keepalive_stream, 33);
+
+ TEST_S(instance, "urn:uuid:97701ad9-39df-1229-1083-dbc0a85f029c");
+ TEST_S(m_display, "Joe");
+ TEST_S(m_username, "joe");
+ TEST_S(m_params, "user=phone");
+ { char const *expect_m_features = "language=\"en\"";
+ TEST_S(m_features, expect_m_features); }
+ TEST_S(outbound, "foo");
+
+ free_events_in_list(ctx, ctx->a.events);
+ }
+
+ /* Test that only those tags that have been set per handle are returned by nua_get_hparams() */
+
+ {
+ sip_from_t const *from = NONE;
+ char const *from_str = "NONE";
+
+ unsigned retry_count = (unsigned)-1;
+ unsigned max_subscriptions = (unsigned)-1;
+
+ int invite_enable = -1;
+ int auto_alert = -1;
+ int early_media = -1;
+ int auto_answer = -1;
+ int auto_ack = -1;
+ unsigned invite_timeout = (unsigned)-1;
+
+ unsigned session_timer = (unsigned)-1;
+ unsigned min_se = (unsigned)-1;
+ int refresher = -1;
+ int update_refresh = -1;
+
+ int message_enable = -1;
+ int win_messenger_enable = -1;
+ int message_auto_respond = -1;
+
+ int callee_caps = -1;
+ int media_features = -1;
+ int service_route_enable = -1;
+ int path_enable = -1;
+ unsigned refer_expires = (unsigned)-1;
+ int refer_with_id = -1;
+ int substate = -1;
+
+ sip_allow_t const *allow = NONE;
+ char const *allow_str = "NONE";
+ sip_supported_t const *supported = NONE;
+ char const *supported_str = "NONE";
+ sip_user_agent_t const *user_agent = NONE;
+ char const *user_agent_str = "NONE";
+ sip_organization_t const *organization = NONE;
+ char const *organization_str = "NONE";
+
+ url_string_t const *registrar = NONE;
+
+ char const *outbound = "NONE";
+ char const *m_display = "NONE";
+ char const *m_username = "NONE";
+ char const *m_params = "NONE";
+ char const *m_features = "NONE";
+ char const *instance = "NONE";
+
+ int n;
+ struct event *e;
+
+ nua_get_hparams(nh, TAG_ANY(), TAG_END());
+ run_a_until(ctx, nua_r_get_params, save_until_final_response);
+
+ TEST_1(e = ctx->a.events->head);
+ TEST_E(e->data->e_event, nua_r_get_params);
+
+ n = tl_gets(e->data->e_tags,
+ SIPTAG_FROM_REF(from),
+ SIPTAG_FROM_STR_REF(from_str),
+
+ NUTAG_RETRY_COUNT_REF(retry_count),
+ NUTAG_MAX_SUBSCRIPTIONS_REF(max_subscriptions),
+
+ NUTAG_ENABLEINVITE_REF(invite_enable),
+ NUTAG_AUTOALERT_REF(auto_alert),
+ NUTAG_EARLY_MEDIA_REF(early_media),
+ NUTAG_AUTOANSWER_REF(auto_answer),
+ NUTAG_AUTOACK_REF(auto_ack),
+ NUTAG_INVITE_TIMER_REF(invite_timeout),
+
+ NUTAG_SESSION_TIMER_REF(session_timer),
+ NUTAG_MIN_SE_REF(min_se),
+ NUTAG_SESSION_REFRESHER_REF(refresher),
+ NUTAG_UPDATE_REFRESH_REF(update_refresh),
+
+ NUTAG_ENABLEMESSAGE_REF(message_enable),
+ NUTAG_ENABLEMESSENGER_REF(win_messenger_enable),
+ /* NUTAG_MESSAGE_AUTOANSWER(message_auto_respond), */
+
+ NUTAG_CALLEE_CAPS_REF(callee_caps),
+ NUTAG_MEDIA_FEATURES_REF(media_features),
+ NUTAG_SERVICE_ROUTE_ENABLE_REF(service_route_enable),
+ NUTAG_PATH_ENABLE_REF(path_enable),
+ NUTAG_SUBSTATE_REF(substate),
+
+ SIPTAG_SUPPORTED_REF(supported),
+ SIPTAG_SUPPORTED_STR_REF(supported_str),
+ SIPTAG_ALLOW_REF(allow),
+ SIPTAG_ALLOW_STR_REF(allow_str),
+ SIPTAG_USER_AGENT_REF(user_agent),
+ SIPTAG_USER_AGENT_STR_REF(user_agent_str),
+
+ SIPTAG_ORGANIZATION_REF(organization),
+ SIPTAG_ORGANIZATION_STR_REF(organization_str),
+
+ NUTAG_OUTBOUND_REF(outbound),
+ NUTAG_M_DISPLAY_REF(m_display),
+ NUTAG_M_USERNAME_REF(m_username),
+ NUTAG_M_PARAMS_REF(m_params),
+ NUTAG_M_FEATURES_REF(m_features),
+ NUTAG_INSTANCE_REF(instance),
+
+ NUTAG_REGISTRAR_REF(registrar),
+
+ TAG_END());
+ TEST(n, 3);
+
+ TEST(invite_timeout, 90);
+
+ TEST_1(from != NULL && from != NONE);
+ TEST_1(strcmp(from_str, "NONE"));
+
+ /* Nothing else should be set */
+ TEST(retry_count, (unsigned)-1);
+ TEST(max_subscriptions, (unsigned)-1);
+
+ TEST(invite_enable, -1);
+ TEST(auto_alert, -1);
+ TEST(early_media, -1);
+ TEST(auto_answer, -1);
+ TEST(auto_ack, -1);
+
+ TEST(session_timer, (unsigned)-1);
+ TEST(min_se, (unsigned)-1);
+ TEST(refresher, -1);
+ TEST(update_refresh, -1);
+
+ TEST(message_enable, -1);
+ TEST(win_messenger_enable, -1);
+ TEST(message_auto_respond, -1); /* XXX */
+
+ TEST(callee_caps, -1);
+ TEST(media_features, -1);
+ TEST(service_route_enable, -1);
+ TEST(path_enable, -1);
+ TEST(refer_expires, (unsigned)-1);
+ TEST(refer_with_id, -1);
+ TEST(substate, -1);
+
+ TEST_P(allow, NONE);
+ TEST_S(allow_str, "NONE");
+ TEST_P(supported, NONE);
+ TEST_S(supported_str, "NONE");
+ TEST_P(user_agent, NONE);
+ TEST_S(user_agent_str, "NONE");
+ TEST_P(organization, NONE);
+ TEST_S(organization_str, "NONE");
+
+ TEST_S(outbound, "NONE");
+ TEST_S(m_display, "NONE");
+ TEST_S(m_username, "NONE");
+ TEST_S(m_params, "NONE");
+ TEST_S(m_features, "NONE");
+ TEST_S(instance, "NONE");
+
+ TEST_P(registrar->us_url, NONE);
+
+ free_events_in_list(ctx, ctx->a.events);
+ }
+
+ nua_handle_destroy(nh);
+
+ nua_shutdown(ctx->a.nua);
+ run_a_until(ctx, nua_r_shutdown, until_final_response);
+ nua_destroy(ctx->a.nua), ctx->a.nua = NULL;
+
+ su_root_destroy(ctx->root), ctx->root = NULL;
+
+ su_home_deinit(tmphome);
+
+ if (print_headings)
+ printf("TEST NUA-1.1: PASSED\n");
+
+ END();
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_ops.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_ops.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,493 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_ops.c
+ * @brief High-level test framework for Sofia SIP User Agent Engine
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti Mela at nokia.com>
+ *
+ * @date Created: Wed Aug 17 12:12:12 EEST 2005 ppessi
+ */
+
+#include "config.h"
+
+#include "test_nua.h"
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+#define __func__ name
+#endif
+
+int save_events(CONDITION_PARAMS)
+{
+ return save_event_in_list(ctx, event, ep, ep->call) == event_is_normal;
+}
+
+int until_final_response(CONDITION_PARAMS)
+{
+ return status >= 200;
+}
+
+int save_until_final_response(CONDITION_PARAMS)
+{
+ save_event_in_list(ctx, event, ep, ep->call);
+ return event >= nua_r_set_params && status >= 200;
+}
+
+/** Save events.
+ *
+ * Terminate when a event is saved.
+ */
+int save_until_received(CONDITION_PARAMS)
+{
+ return save_event_in_list(ctx, event, ep, ep->call) == event_is_normal;
+}
+
+/** Save events until nua_i_outbound is received. */
+int save_until_special(CONDITION_PARAMS)
+{
+ return save_event_in_list(ctx, event, ep, ep->call) == event_is_special;
+}
+
+/* Return call state from event tag list */
+int callstate(tagi_t const *tags)
+{
+ tagi_t const *ti = tl_find(tags, nutag_callstate);
+ return ti ? ti->t_value : -1;
+}
+
+/* Return true if offer is sent */
+int is_offer_sent(tagi_t const *tags)
+{
+ tagi_t const *ti = tl_find(tags, nutag_offer_sent);
+ return ti ? ti->t_value : 0;
+}
+
+/* Return true if answer is sent */
+int is_answer_sent(tagi_t const *tags)
+{
+ tagi_t const *ti = tl_find(tags, nutag_answer_sent);
+ return ti ? ti->t_value : 0;
+}
+
+/* Return true if offer is recv */
+int is_offer_recv(tagi_t const *tags)
+{
+ tagi_t const *ti = tl_find(tags, nutag_offer_recv);
+ return ti ? ti->t_value : 0;
+}
+
+/* Return true if answer is recv */
+int is_answer_recv(tagi_t const *tags)
+{
+ tagi_t const *ti = tl_find(tags, nutag_answer_recv);
+ return ti ? ti->t_value : 0;
+}
+
+/* Return true if offer/answer is sent/recv */
+int is_offer_answer_done(tagi_t const *tags)
+{
+ tagi_t const *ti;
+
+ return
+ ((ti = tl_find(tags, nutag_answer_recv)) && ti->t_value) ||
+ ((ti = tl_find(tags, nutag_offer_sent)) && ti->t_value) ||
+ ((ti = tl_find(tags, nutag_offer_recv)) && ti->t_value) ||
+ ((ti = tl_find(tags, nutag_answer_sent)) && ti->t_value);
+}
+
+/* Return audio state from event tag list */
+int audio_activity(tagi_t const *tags)
+{
+ tagi_t const *ti = tl_find(tags, soatag_active_audio);
+ return ti ? ti->t_value : -1;
+}
+
+/* Return video state from event tag list */
+int video_activity(tagi_t const *tags)
+{
+ tagi_t const *ti = tl_find(tags, soatag_active_video);
+ return ti ? ti->t_value : -1;
+}
+
+void print_event(nua_event_t event,
+ char const *operation,
+ int status, char const *phrase,
+ nua_t *nua, struct context *ctx,
+ struct endpoint *ep,
+ nua_handle_t *nh, struct call *call,
+ sip_t const *sip,
+ tagi_t tags[])
+{
+ if (event == nua_i_state) {
+ fprintf(stderr, "%s.nua(%p): event %s %s\n",
+ ep->name, nh, nua_event_name(event),
+ nua_callstate_name(callstate(tags)));
+ }
+ else if ((int)event >= nua_r_set_params) {
+ fprintf(stderr, "%s.nua(%p): event %s status %u %s\n",
+ ep->name, nh, nua_event_name(event), status, phrase);
+ }
+ else if ((int)event >= 0) {
+ fprintf(stderr, "%s.nua(%p): event %s %s\n",
+ ep->name, nh, nua_event_name(event), phrase);
+ }
+ else if (status > 0) {
+ fprintf(stderr, "%s.nua(%p): call %s() with status %u %s\n",
+ ep->name, nh, operation, status, phrase);
+ }
+ else {
+ tagi_t const *t;
+ t = tl_find(tags, siptag_subject_str);
+ if (t && t->t_value) {
+ char const *subject = (char const *)t->t_value;
+ fprintf(stderr, "%s.nua(%p): call %s() \"%s\"\n",
+ ep->name, nh, operation, subject);
+ }
+ else
+ fprintf(stderr, "%s.nua(%p): call %s()\n",
+ ep->name, nh, operation);
+ }
+
+ if ((tstflags & tst_verbatim) && tags)
+ tl_print(stderr, "", tags);
+}
+
+void ep_callback(nua_event_t event,
+ int status, char const *phrase,
+ nua_t *nua, struct context *ctx,
+ struct endpoint *ep,
+ nua_handle_t *nh, struct call *call,
+ sip_t const *sip,
+ tagi_t tags[])
+{
+ if (ep->printer)
+ ep->printer(event, "", status, phrase, nua, ctx, ep, nh, call, sip, tags);
+
+ if (call == NULL && nh) {
+ for (call = ep->call; call; call = call->next) {
+ if (!call->nh)
+ break;
+ if (nh == call->nh)
+ break;
+ }
+
+ if (call && call->nh == NULL) {
+ call->nh = nh;
+ nua_handle_bind(nh, call);
+ }
+ }
+
+ if ((ep->next_event == -1 || ep->next_event == event) &&
+ (ep->next_condition == NULL ||
+ ep->next_condition(event, status, phrase,
+ nua, ctx, ep, nh, call, sip, tags)))
+ ep->running = 0;
+
+ ep->last_event = event;
+
+ if (call == NULL && nh)
+ nua_handle_destroy(nh);
+}
+
+void a_callback(nua_event_t event,
+ int status, char const *phrase,
+ nua_t *nua, struct context *ctx,
+ nua_handle_t *nh, struct call *call,
+ sip_t const *sip,
+ tagi_t tags[])
+{
+ ep_callback(event, status, phrase, nua, ctx, &ctx->a, nh, call, sip, tags);
+}
+
+void b_callback(nua_event_t event,
+ int status, char const *phrase,
+ nua_t *nua, struct context *ctx,
+ nua_handle_t *nh, struct call *call,
+ sip_t const *sip,
+ tagi_t tags[])
+{
+ ep_callback(event, status, phrase, nua, ctx, &ctx->b, nh, call, sip, tags);
+}
+
+void c_callback(nua_event_t event,
+ int status, char const *phrase,
+ nua_t *nua, struct context *ctx,
+ nua_handle_t *nh, struct call *call,
+ sip_t const *sip,
+ tagi_t tags[])
+{
+ ep_callback(event, status, phrase, nua, ctx, &ctx->c, nh, call, sip, tags);
+}
+
+void run_abc_until(struct context *ctx,
+ nua_event_t a_event, condition_function *a_condition,
+ nua_event_t b_event, condition_function *b_condition,
+ nua_event_t c_event, condition_function *c_condition)
+{
+ struct endpoint *a = &ctx->a, *b = &ctx->b, *c = &ctx->c;
+
+ a->next_event = a_event;
+ a->next_condition = a_condition;
+ a->last_event = -1;
+ a->running = a_condition != NULL && a_condition != save_events;
+ a->running |= a_event != -1;
+ a->flags.n = 0;
+
+ b->next_event = b_event;
+ b->next_condition = b_condition;
+ b->last_event = -1;
+ b->running = b_condition != NULL && b_condition != save_events;
+ b->running |= b_event != -1;
+ b->flags.n = 0;
+
+ c->next_event = c_event;
+ c->next_condition = c_condition;
+ c->last_event = -1;
+ c->running = c_condition != NULL && c_condition != save_events;
+ c->running |= c_event != -1;
+ c->flags.n = 0;
+
+ for (; a->running || b->running || c->running;) {
+ su_root_step(ctx->root, 1000);
+ }
+}
+
+void run_ab_until(struct context *ctx,
+ nua_event_t a_event, condition_function *a_condition,
+ nua_event_t b_event, condition_function *b_condition)
+{
+ run_abc_until(ctx, a_event, a_condition, b_event, b_condition, -1, NULL);
+}
+
+void run_bc_until(struct context *ctx,
+ nua_event_t b_event, condition_function *b_condition,
+ nua_event_t c_event, condition_function *c_condition)
+{
+ run_abc_until(ctx, -1, NULL, b_event, b_condition, c_event, c_condition);
+}
+
+int run_a_until(struct context *ctx,
+ nua_event_t a_event,
+ condition_function *a_condition)
+{
+ run_abc_until(ctx, a_event, a_condition, -1, NULL, -1, NULL);
+ return ctx->a.last_event;
+}
+
+int run_b_until(struct context *ctx,
+ nua_event_t b_event,
+ condition_function *b_condition)
+{
+ run_abc_until(ctx, -1, NULL, b_event, b_condition, -1, NULL);
+ return ctx->b.last_event;
+}
+
+int run_c_until(struct context *ctx,
+ nua_event_t event,
+ condition_function *condition)
+{
+ run_abc_until(ctx, -1, NULL, -1, NULL, event, condition);
+ return ctx->c.last_event;
+}
+
+#define OPERATION(X, x) \
+int X(struct endpoint *ep, \
+ struct call *call, nua_handle_t *nh, \
+ tag_type_t tag, tag_value_t value, \
+ ...) \
+{ \
+ ta_list ta; \
+ ta_start(ta, tag, value); \
+\
+ if (ep->printer) \
+ ep->printer(-1, "nua_" #x, 0, "", ep->nua, ep->ctx, ep, \
+ nh, call, NULL, ta_args(ta)); \
+\
+ nua_##x(nh, ta_tags(ta)); \
+\
+ ta_end(ta); \
+ return 0; \
+} extern int dummy
+
+OPERATION(INVITE, invite);
+OPERATION(ACK, ack);
+OPERATION(BYE, bye);
+OPERATION(CANCEL, cancel);
+OPERATION(AUTHENTICATE, authenticate);
+OPERATION(UPDATE, update);
+OPERATION(INFO, info);
+OPERATION(PRACK, prack);
+OPERATION(REFER, refer);
+OPERATION(MESSAGE, message);
+OPERATION(METHOD, method);
+OPERATION(OPTIONS, options);
+OPERATION(PUBLISH, publish);
+OPERATION(UNPUBLISH, unpublish);
+OPERATION(REGISTER, register);
+OPERATION(UNREGISTER, unregister);
+OPERATION(SUBSCRIBE, subscribe);
+OPERATION(UNSUBSCRIBE, unsubscribe);
+OPERATION(NOTIFY, notify);
+OPERATION(NOTIFIER, notifier);
+OPERATION(TERMINATE, terminate);
+OPERATION(AUTHORIZE, authorize);
+
+/* Respond via endpoint and handle */
+int RESPOND(struct endpoint *ep,
+ struct call *call,
+ nua_handle_t *nh,
+ int status, char const *phrase,
+ tag_type_t tag, tag_value_t value,
+ ...)
+{
+ ta_list ta;
+
+ ta_start(ta, tag, value);
+
+ if (ep->printer)
+ ep->printer(-1, "nua_respond", status, phrase, ep->nua, ep->ctx, ep,
+ nh, call, NULL, ta_args(ta));
+
+ nua_respond(nh, status, phrase, ta_tags(ta));
+ ta_end(ta);
+
+ return 0;
+}
+
+/* Destroy an handle */
+int DESTROY(struct endpoint *ep,
+ struct call *call,
+ nua_handle_t *nh)
+{
+ if (ep->printer)
+ ep->printer(-1, "nua_handle_destroy", 0, "", ep->nua, ep->ctx, ep,
+ nh, call, NULL, NULL);
+
+ nua_handle_destroy(nh);
+
+ if (call->nh == nh)
+ call->nh = NULL;
+
+ return 0;
+}
+
+
+/* Reject all but currently used handles */
+struct call *check_handle(struct endpoint *ep,
+ struct call *call,
+ nua_handle_t *nh,
+ int status, char const *phrase)
+{
+ if (call)
+ return call;
+
+ if (status)
+ RESPOND(ep, call, nh, status, phrase, TAG_END());
+
+ nua_handle_destroy(nh);
+ return NULL;
+}
+
+/* Save nua event in call-specific list */
+int save_event_in_list(struct context *ctx,
+ nua_event_t nevent,
+ struct endpoint *ep,
+ struct call *call)
+
+{
+ struct eventlist *list;
+ struct event *e;
+ int action = ep->is_special(nevent);
+
+ if (action == event_is_extra)
+ return 0;
+ else if (action == event_is_special || call == NULL)
+ list = ep->specials;
+ else if (call->events)
+ list = call->events;
+ else
+ list = ep->events;
+
+ e = su_zalloc(ctx->home, sizeof *e);
+
+ if (!e) { perror("su_zalloc"), abort(); }
+
+ if (!nua_save_event(ep->nua, e->saved_event)) {
+ su_free(ctx->home, e);
+ return -1;
+ }
+
+ *(e->prev = list->tail) = e; list->tail = &e->next;
+
+ e->call = call;
+ e->data = nua_event_data(e->saved_event);
+
+ return action;
+}
+
+/* Save nua event in endpoint list */
+void free_events_in_list(struct context *ctx,
+ struct eventlist *list)
+{
+ struct event *e;
+
+ while ((e = list->head)) {
+ if ((*e->prev = e->next))
+ e->next->prev = e->prev;
+ nua_destroy_event(e->saved_event);
+ su_free(ctx->home, e);
+ }
+
+ list->tail = &list->head;
+}
+
+int is_special(nua_event_t e)
+{
+ if (e == nua_i_active || e == nua_i_terminated)
+ return event_is_extra;
+ if (e == nua_i_outbound)
+ return event_is_special;
+
+ return event_is_normal;
+}
+
+void
+endpoint_init(struct context *ctx, struct endpoint *e, char id)
+{
+ e->name[0] = id;
+ e->ctx = ctx;
+
+ e->is_special = is_special;
+
+ call_init(e->call);
+ call_init(e->reg);
+ eventlist_init(e->events);
+ eventlist_init(e->specials);
+}
+
+void nolog(void *stream, char const *fmt, va_list ap) {}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1056 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_proxy.c
+ * @brief Extremely simple proxy and registrar for testing nua
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Nov 3 22:49:46 EET 2005
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+struct proxy;
+struct proxy_transaction;
+struct registration_entry;
+struct binding;
+
+#define SU_ROOT_MAGIC_T struct proxy
+#define NTA_LEG_MAGIC_T struct proxy
+#define NTA_OUTGOING_MAGIC_T struct proxy_transaction
+#define NTA_INCOMING_MAGIC_T struct proxy_transaction
+
+#include <sofia-sip/su_wait.h>
+#include <sofia-sip/nta.h>
+#include <sofia-sip/sip_header.h>
+#include <sofia-sip/sip_status.h>
+#include <sofia-sip/sip_util.h>
+#include <sofia-sip/auth_module.h>
+#include <sofia-sip/su_tagarg.h>
+#include <sofia-sip/msg_addr.h>
+
+#include <stdlib.h>
+#include <assert.h>
+
+#define LIST_PROTOS(STORAGE, PREFIX, T) \
+STORAGE void PREFIX ##_insert(T **list, T *node), \
+ PREFIX ##_remove(T *node)
+
+#define LIST_BODIES(STORAGE, PREFIX, T, NEXT, PREV) \
+STORAGE void PREFIX ##_insert(T **list, T *node) \
+{ \
+ if ((node->NEXT = *list)) { \
+ node->PREV = node->NEXT->PREV; \
+ node->NEXT->PREV = &node->NEXT; \
+ } \
+ else \
+ node->PREV = list; \
+ *list = node; \
+} \
+STORAGE void PREFIX ##_remove(T *node) \
+{ \
+ if (node->PREV) \
+ if ((*node->PREV = node->NEXT)) \
+ node->NEXT->PREV = node->PREV; \
+ node->PREV = NULL; \
+} \
+extern int LIST_DUMMY_VARIABLE
+
+#include <test_proxy.h>
+
+struct proxy {
+ su_home_t home[1];
+ su_root_t *parent;
+ su_clone_r clone;
+ tagi_t *tags;
+
+ su_root_t *root;
+ auth_mod_t *auth;
+
+ nta_agent_t *agent;
+ url_t const *uri;
+
+ nta_leg_t *defleg;
+
+ nta_leg_t *example_net;
+ nta_leg_t *example_org;
+ nta_leg_t *example_com;
+
+ sip_contact_t *transport_contacts;
+
+ struct proxy_transaction *stateless;
+ struct proxy_transaction *transactions;
+ struct registration_entry *entries;
+
+ struct {
+ sip_time_t min_expires, expires, max_expires;
+
+ sip_time_t session_expires, min_se;
+ } prefs;
+};
+
+LIST_PROTOS(static, registration_entry, struct registration_entry);
+static struct registration_entry *registration_entry_new(struct proxy *,
+ url_t const *);
+static void registration_entry_destroy(struct registration_entry *e);
+
+
+struct registration_entry
+{
+ struct registration_entry *next, **prev;
+ struct proxy *proxy; /* backpointer */
+ url_t *aor; /* address-of-record */
+ struct binding *bindings; /* list of bindings */
+ sip_contact_t *contacts;
+};
+
+struct binding
+{
+ struct binding *next, **prev;
+ sip_contact_t *contact; /* bindings */
+ sip_time_t registered, expires; /* When registered and when expires */
+ sip_call_id_t *call_id;
+ uint32_t cseq;
+};
+
+static struct binding *binding_new(su_home_t *home,
+ sip_contact_t *contact,
+ sip_call_id_t *call_id,
+ uint32_t cseq,
+ sip_time_t registered,
+ sip_time_t expires);
+static void binding_destroy(su_home_t *home, struct binding *b);
+static int binding_is_active(struct binding const *b)
+{
+ return b->expires > sip_now();
+}
+
+LIST_PROTOS(static, proxy_transaction, struct proxy_transaction);
+struct proxy_transaction *proxy_transaction_new(struct proxy *);
+static void proxy_transaction_destroy(struct proxy_transaction *t);
+
+struct proxy_transaction
+{
+ struct proxy_transaction *next, **prev;
+
+ struct proxy *proxy; /* backpointer */
+ sip_request_t *rq; /* request line */
+ nta_incoming_t *server; /* server transaction */
+ nta_outgoing_t *client; /* client transaction */
+};
+
+static sip_contact_t *create_transport_contacts(struct proxy *p);
+
+static int proxy_request(struct proxy *proxy,
+ nta_leg_t *leg,
+ nta_incoming_t *irq,
+ sip_t const *sip);
+
+static int proxy_ack_cancel(struct proxy_transaction *t,
+ nta_incoming_t *irq,
+ sip_t const *sip);
+
+static int proxy_response(struct proxy_transaction *t,
+ nta_outgoing_t *client,
+ sip_t const *sip);
+
+static int process_register(struct proxy *proxy,
+ nta_incoming_t *irq,
+ sip_t const *sip);
+
+static int domain_request(struct proxy *proxy,
+ nta_leg_t *leg,
+ nta_incoming_t *irq,
+ sip_t const *sip);
+
+static int process_options(struct proxy *proxy,
+ nta_incoming_t *irq,
+ sip_t const *sip);
+
+static struct registration_entry *
+registration_entry_find(struct proxy const *proxy, url_t const *uri);
+
+static auth_challenger_t registrar_challenger[1];
+static auth_challenger_t proxy_challenger[1];
+
+/* Proxy entry point */
+static int
+test_proxy_init(su_root_t *root, struct proxy *proxy)
+{
+ struct proxy_transaction *t;
+
+ auth_challenger_t _proxy_challenger[1] =
+ {{
+ SIP_407_PROXY_AUTH_REQUIRED,
+ sip_proxy_authenticate_class,
+ sip_proxy_authentication_info_class
+ }};
+
+ auth_challenger_t _registrar_challenger[1] =
+ {{
+ SIP_401_UNAUTHORIZED,
+ sip_www_authenticate_class,
+ sip_authentication_info_class
+ }};
+
+ *proxy_challenger = *_proxy_challenger;
+ *registrar_challenger = *_registrar_challenger;
+
+ proxy->root = root;
+
+ proxy->auth = auth_mod_create(root, TAG_NEXT(proxy->tags));
+
+ proxy->agent = nta_agent_create(root,
+ URL_STRING_MAKE("sip:0.0.0.0:*"),
+ NULL, NULL,
+ NTATAG_UA(0),
+ NTATAG_SERVER_RPORT(1),
+ NTATAG_CLIENT_RPORT(1),
+ TAG_END());
+
+ proxy->transport_contacts = create_transport_contacts(proxy);
+
+ proxy->defleg = nta_leg_tcreate(proxy->agent,
+ proxy_request,
+ proxy,
+ NTATAG_NO_DIALOG(1),
+ TAG_END());
+
+ proxy->example_net = nta_leg_tcreate(proxy->agent,
+ domain_request,
+ proxy,
+ NTATAG_NO_DIALOG(1),
+ URLTAG_URL("sip:example.net"),
+ TAG_END());
+ proxy->example_org = nta_leg_tcreate(proxy->agent,
+ domain_request,
+ proxy,
+ NTATAG_NO_DIALOG(1),
+ URLTAG_URL("sip:example.org"),
+ TAG_END());
+ proxy->example_com = nta_leg_tcreate(proxy->agent,
+ domain_request,
+ proxy,
+ NTATAG_NO_DIALOG(1),
+ URLTAG_URL("sip:example.com"),
+ TAG_END());
+
+ proxy->prefs.min_expires = 30;
+ proxy->prefs.expires = 3600;
+ proxy->prefs.max_expires = 3600;
+
+ proxy->prefs.session_expires = 180;
+ proxy->prefs.min_se = 90;
+
+ if (!proxy->defleg ||
+ !proxy->example_net || !proxy->example_org || !proxy->example_com)
+ return -1;
+
+ t = su_zalloc(proxy->home, sizeof *t);
+
+ if (!t)
+ return -1;
+
+ proxy->stateless = t;
+ t->proxy = proxy;
+ t->server = nta_incoming_default(proxy->agent);
+ t->client = nta_outgoing_default(proxy->agent, proxy_response, t);
+
+ if (!t->client || !t->server)
+ return -1;
+
+ proxy->uri = nta_agent_contact(proxy->agent)->m_url;
+
+ return 0;
+}
+
+static void
+test_proxy_deinit(su_root_t *root, struct proxy *proxy)
+{
+ struct proxy_transaction *t;
+
+ auth_mod_destroy(proxy->auth);
+
+ if ((t = proxy->stateless)) {
+ nta_incoming_destroy(t->server), t->server = NULL;
+ nta_outgoing_destroy(t->client), t->client = NULL;
+ }
+
+ nta_agent_destroy(proxy->agent);
+
+ while (proxy->entries)
+ registration_entry_destroy(proxy->entries);
+
+ free(proxy->tags);
+}
+
+/* Create tst proxy object */
+struct proxy *test_proxy_create(su_root_t *root,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ struct proxy *p = su_home_new(sizeof *p);
+
+ if (p) {
+ ta_list ta;
+
+ p->parent = root;
+
+ ta_start(ta, tag, value);
+ p->tags = tl_llist(ta_tags(ta));
+ ta_end(ta);
+
+ if (su_clone_start(root,
+ p->clone,
+ p,
+ test_proxy_init,
+ test_proxy_deinit) == -1)
+ su_home_unref(p->home), p = NULL;
+ }
+
+ return p;
+}
+
+/* Destroy the proxy object */
+void test_proxy_destroy(struct proxy *p)
+{
+ if (p) {
+ su_clone_wait(p->parent, p->clone);
+ su_home_unref(p->home);
+ }
+}
+
+/* Return the proxy URI */
+url_t const *test_proxy_uri(struct proxy const *p)
+{
+ return p ? p->uri : NULL;
+}
+
+void test_proxy_set_expiration(struct proxy *p,
+ sip_time_t min_expires,
+ sip_time_t expires,
+ sip_time_t max_expires)
+{
+ if (p) {
+ p->prefs.min_expires = min_expires;
+ p->prefs.expires = expires;
+ p->prefs.max_expires = max_expires;
+ }
+}
+
+void test_proxy_get_expiration(struct proxy *p,
+ sip_time_t *return_min_expires,
+ sip_time_t *return_expires,
+ sip_time_t *return_max_expires)
+{
+ if (p) {
+ if (return_min_expires) *return_min_expires = p->prefs.min_expires;
+ if (return_expires) *return_expires = p->prefs.expires;
+ if (return_max_expires) *return_max_expires = p->prefs.max_expires;
+ }
+}
+
+/* ---------------------------------------------------------------------- */
+
+static sip_contact_t *create_transport_contacts(struct proxy *p)
+{
+ su_home_t *home = p->home;
+ sip_via_t *v;
+ sip_contact_t *retval = NULL, **mm = &retval;
+
+ if (!p->agent)
+ return NULL;
+
+ for (v = nta_agent_via(p->agent); v; v = v->v_next) {
+ char const *proto = v->v_protocol;
+
+ if (v->v_next &&
+ strcasecmp(v->v_host, v->v_next->v_host) == 0 &&
+ str0cmp(v->v_port, v->v_next->v_port) == 0 &&
+ ((proto == sip_transport_udp &&
+ v->v_next->v_protocol == sip_transport_tcp) ||
+ (proto == sip_transport_tcp &&
+ v->v_next->v_protocol == sip_transport_udp)))
+ /* We have udp/tcp pair, insert URL without tport parameter */
+ *mm = sip_contact_create_from_via_with_transport(home, v, NULL, NULL);
+ if (*mm) mm = &(*mm)->m_next;
+
+ *mm = sip_contact_create_from_via_with_transport(home, v, NULL, proto);
+
+ if (*mm) mm = &(*mm)->m_next;
+ }
+
+ return retval;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int challenge_request(struct proxy *, nta_incoming_t *, sip_t const *);
+
+/** Forward request */
+static
+int proxy_request(struct proxy *proxy,
+ nta_leg_t *leg,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ url_t const *request_uri, *target;
+ struct proxy_transaction *t = NULL;
+ sip_request_t *rq = NULL;
+ sip_max_forwards_t *mf;
+ sip_method_t method = sip->sip_request->rq_method;
+
+ sip_session_expires_t *x = NULL, x0[1];
+ sip_min_se_t *min_se = NULL, min_se0[1];
+
+ mf = sip->sip_max_forwards;
+
+ if (mf && mf->mf_count <= 1) {
+ if (sip->sip_request->rq_method == sip_method_options) {
+ return process_options(proxy, irq, sip);
+ }
+ nta_incoming_treply(irq, SIP_483_TOO_MANY_HOPS, TAG_END());
+ return 483;
+ }
+
+ if (method != sip_method_ack && method != sip_method_cancel &&
+ str0casecmp(sip->sip_from->a_url->url_host, "example.net") == 0) {
+ /* Challenge everything but CANCEL and ACK coming from Mr. C */
+ int status = challenge_request(proxy, irq, sip);
+ if (status)
+ return status;
+ }
+
+ if (method == sip_method_invite) {
+ if (!sip->sip_min_se ||
+ sip->sip_min_se->min_delta < proxy->prefs.min_se) {
+ min_se = sip_min_se_init(min_se0);
+ min_se->min_delta = proxy->prefs.min_se;
+ }
+
+ if (!sip->sip_session_expires) {
+ x = sip_session_expires_init(x0);
+ x->x_delta = proxy->prefs.session_expires;
+ }
+ else if (sip->sip_session_expires->x_delta < proxy->prefs.min_se
+ && sip_has_supported(sip->sip_supported, "timer")) {
+ if (min_se == NULL)
+ min_se = sip->sip_min_se; assert(min_se);
+ nta_incoming_treply(irq, SIP_422_SESSION_TIMER_TOO_SMALL,
+ SIPTAG_MIN_SE(min_se),
+ TAG_END());
+ return 422;
+ }
+ }
+
+ /* We don't do any route processing */
+ request_uri = sip->sip_request->rq_url;
+
+ if (!request_uri->url_host ||
+ (strcasecmp(request_uri->url_host, "example.org") &&
+ strcasecmp(request_uri->url_host, "example.net") &&
+ strcasecmp(request_uri->url_host, "example.com"))) {
+ target = request_uri;
+ }
+ else {
+ struct registration_entry *e;
+ struct binding *b;
+
+ if (sip->sip_request->rq_method == sip_method_register)
+ return process_register(proxy, irq, sip);
+
+ e = registration_entry_find(proxy, request_uri);
+ if (e == NULL) {
+ nta_incoming_treply(irq, SIP_404_NOT_FOUND, TAG_END());
+ return 404;
+ }
+
+ for (b = e->bindings; b; b = b->next)
+ if (binding_is_active(b))
+ break;
+
+ if (b == NULL) {
+ nta_incoming_treply(irq, SIP_480_TEMPORARILY_UNAVAILABLE, TAG_END());
+ return 480;
+ }
+
+ target = b->contact->m_url;
+ }
+
+ t = proxy_transaction_new(proxy);
+ if (t == NULL) {
+ nta_incoming_treply(irq, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
+ return 500;
+ }
+ nta_incoming_bind(t->server = irq, proxy_ack_cancel, t);
+
+ rq = sip_request_create(proxy->home,
+ sip->sip_request->rq_method,
+ sip->sip_request->rq_method_name,
+ (url_string_t *)target,
+ NULL);
+ if (rq == NULL) {
+ nta_incoming_treply(irq, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
+ proxy_transaction_destroy(t);
+ return 500;
+ }
+ t->rq = rq;
+
+ /* Forward request */
+ t->client = nta_outgoing_mcreate(proxy->agent, proxy_response, t, NULL,
+ nta_incoming_getrequest(irq),
+ /* rewrite request */
+ SIPTAG_REQUEST(rq),
+ SIPTAG_SESSION_EXPIRES(x),
+ SIPTAG_MIN_SE(min_se),
+ TAG_END());
+ if (t->client == NULL) {
+ proxy_transaction_destroy(t);
+ nta_incoming_treply(irq, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
+ return 500;
+ }
+ else if (sip->sip_request->rq_method == sip_method_ack)
+ proxy_transaction_destroy(t);
+
+ return 0;
+}
+
+static
+int challenge_request(struct proxy *p,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ int status;
+ auth_status_t *as;
+ msg_t *msg;
+
+ as = auth_status_new(p->home);
+ if (!as)
+ return 500;
+
+ as->as_method = sip->sip_request->rq_method_name;
+ msg = nta_incoming_getrequest(irq);
+ as->as_source = msg_addrinfo(msg);
+
+ as->as_user_uri = sip->sip_from->a_url;
+ as->as_display = sip->sip_from->a_display;
+
+ if (sip->sip_payload)
+ as->as_body = sip->sip_payload->pl_data,
+ as->as_bodylen = sip->sip_payload->pl_len;
+
+ auth_mod_check_client(p->auth, as, sip->sip_proxy_authorization,
+ proxy_challenger);
+
+ if ((status = as->as_status)) {
+ nta_incoming_treply(irq,
+ as->as_status, as->as_phrase,
+ SIPTAG_HEADER((void *)as->as_info),
+ SIPTAG_HEADER((void *)as->as_response),
+ TAG_END());
+ }
+ else if (as->as_match) {
+ msg_header_remove(msg, NULL, as->as_match);
+ }
+
+ msg_destroy(msg);
+ su_home_unref(as->as_home);
+
+ return status;
+}
+
+int proxy_ack_cancel(struct proxy_transaction *t,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ if (sip == NULL) {
+ proxy_transaction_destroy(t);
+ return 0;
+ }
+
+ if (sip->sip_request->rq_method == sip_method_cancel) {
+ /* We don't care about response to CANCEL (or ACK)
+ * so we give NULL as callback pointer (and nta immediately
+ * destroys transaction object or marks it disposable)
+ */
+ if (nta_outgoing_tcancel(t->client, NULL, NULL, TAG_END()))
+ return 200;
+ else
+ return 500;
+ }
+ else {
+ return 500;
+ }
+}
+
+int proxy_response(struct proxy_transaction *t,
+ nta_outgoing_t *client,
+ sip_t const *sip)
+{
+ int final;
+
+ if (sip) {
+ msg_t *response = nta_outgoing_getresponse(client);
+ final = sip->sip_status->st_status >= 200;
+ sip_via_remove(response, sip_object(response));
+ nta_incoming_mreply(t->server, response);
+ }
+ else {
+ final = 1;
+ nta_incoming_treply(t->server, SIP_408_REQUEST_TIMEOUT, TAG_END());
+ }
+
+ if (final)
+ proxy_transaction_destroy(t);
+
+ return 0;
+}
+
+struct proxy_transaction *
+proxy_transaction_new(struct proxy *proxy)
+{
+ struct proxy_transaction *t;
+
+ t = su_zalloc(proxy->home, sizeof *t);
+ if (t) {
+ t->proxy = proxy;
+ proxy_transaction_insert(&proxy->transactions, t);
+ }
+ return t;
+}
+
+static
+void proxy_transaction_destroy(struct proxy_transaction *t)
+{
+ if (t == t->proxy->stateless)
+ return;
+ proxy_transaction_remove(t);
+ nta_incoming_destroy(t->server);
+ nta_outgoing_destroy(t->client);
+ su_free(t->proxy->home, t->rq);
+ su_free(t->proxy->home, t);
+}
+
+LIST_BODIES(static, proxy_transaction, struct proxy_transaction, next, prev);
+
+/* ---------------------------------------------------------------------- */
+
+
+static
+int domain_request(struct proxy *proxy,
+ nta_leg_t *leg,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ sip_method_t method = sip->sip_request->rq_method;
+
+ if (method == sip_method_register)
+ return process_register(proxy, irq, sip);
+
+ if (method == sip_method_options)
+ return process_options(proxy, irq, sip);
+
+ return 501;
+}
+
+static
+int process_options(struct proxy *proxy,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ nta_incoming_treply(irq, SIP_200_OK,
+ SIPTAG_CONTACT(proxy->transport_contacts),
+ TAG_END());
+ return 200;
+}
+
+/* ---------------------------------------------------------------------- */
+
+
+static int process_register2(struct proxy *p, auth_status_t *as,
+ nta_incoming_t *irq, sip_t const *sip);
+
+static int set_status(auth_status_t *as, int status, char const *phrase);
+
+static int validate_contacts(struct proxy *p, auth_status_t *as,
+ sip_t const *sip);
+static int check_out_of_order(struct proxy *p, auth_status_t *as,
+ struct registration_entry *e, sip_t const *);
+static int binding_update(struct proxy *p,
+ auth_status_t *as,
+ struct registration_entry *e,
+ sip_t const *sip);
+
+sip_contact_t *binding_contacts(su_home_t *home, struct binding *bindings);
+
+int process_register(struct proxy *proxy,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ auth_status_t *as;
+ msg_t *msg;
+ int status;
+
+ as = auth_status_new(proxy->home);
+ if (!as)
+ return 500;
+
+ as->as_method = sip->sip_request->rq_method_name;
+ msg = nta_incoming_getrequest(irq);
+ as->as_source = msg_addrinfo(msg);
+ msg_destroy(msg);
+
+ as->as_user_uri = sip->sip_from->a_url;
+ as->as_display = sip->sip_from->a_display;
+
+ if (sip->sip_payload)
+ as->as_body = sip->sip_payload->pl_data,
+ as->as_bodylen = sip->sip_payload->pl_len;
+
+ process_register2(proxy, as, irq, sip);
+ assert(as->as_status >= 200);
+
+ nta_incoming_treply(irq,
+ as->as_status, as->as_phrase,
+ SIPTAG_HEADER((void *)as->as_info),
+ SIPTAG_HEADER((void *)as->as_response),
+ TAG_END());
+ status = as->as_status;
+
+ su_home_unref(as->as_home);
+
+ return status;
+}
+
+static int process_register2(struct proxy *p,
+ auth_status_t *as,
+ nta_incoming_t *irq,
+ sip_t const *sip)
+{
+ struct registration_entry *e = NULL;
+
+ auth_mod_check_client(p->auth, as, sip->sip_authorization,
+ registrar_challenger);
+ if (as->as_status)
+ return as->as_status;
+ assert(as->as_response == NULL);
+
+ if (validate_contacts(p, as, sip))
+ return as->as_status;
+
+ e = registration_entry_find(p, sip->sip_to->a_url);
+ if (!sip->sip_contact) {
+ as->as_response = (msg_header_t *)e->contacts;
+ return set_status(as, SIP_200_OK);
+ }
+
+ if (e && check_out_of_order(p, as, e, sip))
+ return as->as_status;
+
+ if (!e)
+ e = registration_entry_new(p, sip->sip_to->a_url);
+ if (!e)
+ return set_status(as, SIP_500_INTERNAL_SERVER_ERROR);
+
+ if (binding_update(p, as, e, sip))
+ return as->as_status;
+
+ msg_header_free(p->home, (void *)e->contacts);
+ e->contacts = binding_contacts(p->home, e->bindings);
+
+ as->as_response = (msg_header_t *)e->contacts;
+
+ return set_status(as, SIP_200_OK);
+}
+
+static int set_status(auth_status_t *as, int status, char const *phrase)
+{
+ return as->as_phrase = phrase, as->as_status = status;
+}
+
+static int validate_contacts(struct proxy *p,
+ auth_status_t *as,
+ sip_t const *sip)
+{
+ sip_contact_t const *m;
+ sip_time_t expires;
+ sip_time_t now = sip_now();
+
+ for (m = sip->sip_contact; m; m = m->m_next) {
+ if (m->m_url->url_type == url_any) {
+ if (!sip->sip_expires ||
+ sip->sip_expires->ex_delta ||
+ sip->sip_expires->ex_time ||
+ sip->sip_contact->m_next)
+ return set_status(as, SIP_400_BAD_REQUEST);
+ else
+ return 0;
+ }
+
+ expires = sip_contact_expires(m, sip->sip_expires, sip->sip_date,
+ p->prefs.expires, now);
+
+ if (expires > 0 && expires < p->prefs.min_expires) {
+ as->as_response = (msg_header_t *)
+ sip_min_expires_format(as->as_home, "%u",
+ (unsigned)p->prefs.min_expires);
+ return set_status(as, SIP_423_INTERVAL_TOO_BRIEF);
+ }
+ }
+
+ return 0;
+}
+
+/** Check for out-of-order register request */
+static
+int check_out_of_order(struct proxy *p,
+ auth_status_t *as,
+ struct registration_entry *e,
+ sip_t const *sip)
+{
+ struct binding const *b;
+ sip_call_id_t const *id;
+ sip_contact_t *m;
+
+ if (e == NULL || !sip->sip_contact)
+ return 0;
+
+ id = sip->sip_call_id;
+
+ /* RFC 3261 subsection 10.3 step 6 and step 7 (p. 66): */
+ /* Check for reordered register requests */
+ for (b = e->bindings; b; b = b->next) {
+ if (binding_is_active(b) &&
+ strcmp(sip->sip_call_id->i_id, b->call_id->i_id) == 0 &&
+ sip->sip_cseq->cs_seq <= b->cseq) {
+ for (m = sip->sip_contact; m; m = m->m_next) {
+ if (m->m_url->url_type == url_any ||
+ url_cmp_all(m->m_url, b->contact->m_url) == 0)
+ return set_status(as, SIP_500_INTERNAL_SERVER_ERROR);
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+static struct registration_entry *
+registration_entry_find(struct proxy const *proxy, url_t const *uri)
+{
+ struct registration_entry *e;
+
+ /* Our routing table */
+ for (e = proxy->entries; e; e = e->next) {
+ if (url_cmp(uri, e->aor) == 0)
+ return e;
+ }
+ return NULL;
+}
+
+static struct registration_entry *
+registration_entry_new(struct proxy *proxy, url_t const *aor)
+{
+ struct registration_entry *e;
+
+ e = su_zalloc(proxy->home, sizeof *e);
+ if (!e)
+ return NULL;
+
+ e->proxy = proxy;
+ e->aor = url_hdup(proxy->home, aor);
+ if (!e->aor) {
+ su_free(proxy->home, e);
+ return NULL;
+ }
+
+ registration_entry_insert(&proxy->entries, e);
+
+ return e;
+}
+
+static void
+registration_entry_destroy(struct registration_entry *e)
+{
+ if (e) {
+ registration_entry_remove(e);
+ su_free(e->proxy->home, e->aor);
+ while (e->bindings)
+ binding_destroy(e->proxy->home, e->bindings);
+ msg_header_free(e->proxy->home, (void *)e->contacts);
+ su_free(e->proxy->home, e);
+ }
+}
+
+LIST_BODIES(static, registration_entry, struct registration_entry, next, prev);
+
+/* ---------------------------------------------------------------------- */
+/* Bindings */
+
+static
+struct binding *binding_new(su_home_t *home,
+ sip_contact_t *contact,
+ sip_call_id_t *call_id,
+ uint32_t cseq,
+ sip_time_t registered,
+ sip_time_t expires)
+{
+ struct binding *b;
+
+ b = su_zalloc(home, sizeof *b);
+
+ if (b) {
+ sip_contact_t m[1];
+ *m = *contact; m->m_next = NULL;
+
+ b->contact = sip_contact_dup(home, m);
+ b->call_id = sip_call_id_dup(home, call_id);
+ b->cseq = cseq;
+ b->registered = registered;
+ b->expires = expires;
+
+ if (!b->contact || !b->call_id)
+ binding_destroy(home, b), b = NULL;
+
+ if (b)
+ msg_header_remove_param(b->contact->m_common, "expires");
+ }
+
+ return b;
+}
+
+static
+void binding_destroy(su_home_t *home, struct binding *b)
+{
+ if (b->prev) {
+ if ((*b->prev = b->next))
+ b->next->prev = b->prev;
+ }
+ msg_header_free(home, (void *)b->contact);
+ msg_header_free(home, (void *)b->call_id);
+ su_free(home, b);
+}
+
+static
+int binding_update(struct proxy *p,
+ auth_status_t *as,
+ struct registration_entry *e,
+ sip_t const *sip)
+{
+ struct binding *b, *old, *next, *last, *bindings = NULL, **bb = &bindings;
+ sip_contact_t *m;
+ sip_time_t expires;
+
+ sip_time_t now = sip_now();
+
+ assert(sip->sip_contact);
+
+ /* Create new bindings */
+ for (m = sip->sip_contact; m; m = m->m_next) {
+ if (m->m_url->url_type == url_any)
+ break;
+
+ expires = sip_contact_expires(m, sip->sip_expires, sip->sip_date,
+ p->prefs.expires, now);
+
+ if (expires > p->prefs.max_expires)
+ expires = p->prefs.max_expires;
+
+ msg_header_remove_param(m->m_common, "expires");
+
+ b = binding_new(p->home, m, sip->sip_call_id, sip->sip_cseq->cs_seq,
+ now, now + expires);
+ if (!b)
+ break;
+
+ *bb = b, b->prev = bb, bb = &b->next;
+ }
+
+ last = NULL;
+
+ if (m == NULL) {
+ /* Merge new bindings with old ones */
+ for (old = e->bindings; old; old = next) {
+ next = old->next;
+
+ for (b = bindings; b != last; b = b->next) {
+ if (url_cmp_all(old->contact->m_url, b->contact->m_url) != 0)
+ continue;
+
+ if (strcmp(old->call_id->i_id, b->call_id->i_id) == 0) {
+ b->registered = old->registered;
+ }
+ binding_destroy(p->home, old);
+ break;
+ }
+ }
+
+ for (bb = &e->bindings; *bb; bb = &(*bb)->next)
+ ;
+
+ if ((*bb = bindings))
+ bindings->prev = bb;
+ }
+ else if (m->m_url->url_type == url_any) {
+ /* Unregister all */
+ for (b = e->bindings; b; b = b->next) {
+ b->expires = now;
+ }
+ }
+ else {
+ /* Infernal error */
+
+ for (old = bindings; old; old = next) {
+ next = old->next;
+ binding_destroy(p->home, old);
+ }
+
+ return set_status(as, SIP_500_INTERNAL_SERVER_ERROR);
+ }
+
+ return 0;
+}
+
+sip_contact_t *binding_contacts(su_home_t *home, struct binding *bindings)
+{
+ sip_contact_t *retval = NULL, **mm = &retval;
+ struct binding *b;
+ sip_time_t now = sip_now();
+
+ for (b = bindings; b; b = b->next) {
+ char const *expires;
+ if (b->expires <= now)
+ continue;
+ *mm = sip_contact_copy(home, b->contact);
+ if (*mm) {
+ expires = su_sprintf(home, "expires=%u", (unsigned)(b->expires - now));
+ msg_header_add_param(home, (*mm)->m_common, expires);
+ mm = &(*mm)->m_next;
+ }
+ }
+
+ return retval;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,53 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef TEST_PROXY_H
+#define TEST_PROXY_H
+
+#include <sofia-sip/su_wait.h>
+#include <sofia-sip/nta.h>
+
+SOFIA_BEGIN_DECLS
+
+struct proxy;
+
+struct proxy *test_proxy_create(su_root_t *, tag_type_t, tag_value_t, ...);
+
+void test_proxy_destroy(struct proxy *);
+
+url_t const *test_proxy_uri(struct proxy const *);
+
+void test_proxy_set_expiration(struct proxy *,
+ sip_time_t min_expires,
+ sip_time_t expires,
+ sip_time_t max_expires);
+
+void test_proxy_get_expiration(struct proxy *,
+ sip_time_t *return_min_expires,
+ sip_time_t *return_expires,
+ sip_time_t *return_max_expires);
+
+SOFIA_END_DECLS
+
+#endif
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_refer.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_refer.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1026 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_nua_re_invite.c
+ * @brief Test re_inviteing, outbound, nat traversal.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti Mela at nokia.com>
+ *
+ * @date Created: Wed Aug 17 12:12:12 EEST 2005 ppessi
+ */
+
+#include "config.h"
+
+#include "test_nua.h"
+#include <sofia-sip/su_tag_class.h>
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+#define __func__ "test_call_hold"
+#endif
+
+int accept_call_immediately(CONDITION_PARAMS);
+
+/* ======================================================================== */
+/* NUA-9 tests: REFER */
+
+int test_refer0(struct context *ctx, int refer_with_id, char const *tests);
+int test_refer1(struct context *ctx, int refer_with_id, char const *tests);
+
+int test_refer(struct context *ctx)
+{
+ /* test twice, once without id and once with id */
+ return
+ test_refer0(ctx, 0, "NUA-9.1") ||
+ test_refer0(ctx, 1, "NUA-9.2") ||
+ test_refer1(ctx, 0, "NUA-9.3");
+}
+
+/* Referred call:
+
+ A B
+ | |
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ | |
+ |<----180 Ringing----|
+ | |
+ |<------200 OK-------|
+ |--------ACK-------->|
+ | |
+ |<------REFER--------|
+ |-------200 OK------>| C
+ [|-------NOTIFY------>|] |
+ [|<------200 OK-------|] |
+ | | |
+ | | |
+ |<-----SUBSCRIBE-----| |
+ |-------200 OK------>| |
+ | | |
+ | | |
+ |-----------------INVITE-------------------->|
+ | | |
+ |<------------------180----------------------|
+ |-------NOTIFY------>| |
+ |<------200 OK-------| |
+ | | |
+ |<------------------200----------------------|
+ |-------NOTIFY------>| |
+ |<------200 OK-------| |
+ |-------------------ACK--------------------->|
+ | | |
+ |--------BYE-------->| |
+ |<------200 OK-------| |
+ | X |
+ | |
+ |-------------------BYE--------------------->|
+ |<------------------200----------------------|
+ | |
+
+*/
+
+int test_refer0(struct context *ctx, int refer_with_id, char const *tests)
+{
+ BEGIN();
+
+ struct endpoint *a = &ctx->a, *b = &ctx->b, *c = &ctx->c;
+ struct call *a_call = a->call, *b_call = b->call, *c_call = c->call;
+ struct call *a_c2;
+ struct event *e;
+ sip_t const *sip;
+ sip_event_t const *a_event, *b_event;
+ sip_refer_to_t const *refer_to;
+ sip_referred_by_t const *referred_by;
+
+ sip_refer_to_t r0[1];
+ sip_to_t to[1];
+
+ su_home_t tmphome[SU_HOME_AUTO_SIZE(16384)];
+
+ su_home_auto(tmphome, sizeof(tmphome));
+
+ if (print_headings)
+ printf("TEST %s: REFER: refer A to C\n", tests);
+
+ if (print_headings)
+ printf("TEST %s.1: REFER: make a call between A and B\n", tests);
+
+ /* Do (not) include id with first implicit Event: refer */
+ nua_set_params(ctx->a.nua, NUTAG_REFER_WITH_ID(refer_with_id), TAG_END());
+ run_a_until(ctx, nua_r_set_params, until_final_response);
+
+ TEST_1(a_c2 = calloc(1, (sizeof *a_c2) + (sizeof *a_c2->events)));
+ call_init(a_c2);
+ a_c2->events = (void *)(a_c2 + 1);
+ eventlist_init(a_c2->events);
+
+ a_call->sdp = "m=audio 5008 RTP/AVP 8";
+ b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
+ a_c2->sdp = "m=audio 5012 RTP/AVP 8";
+ c_call->sdp = "m=audio 5014 RTP/AVP 0 8";
+
+ TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+ INVITE(a, a_call, a_call->nh,
+ TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+ SOATAG_USER_SDP_STR(a_call->sdp),
+ TAG_END());
+
+ run_ab_until(ctx, -1, until_ready, -1, accept_call);
+
+ /* Client transitions:
+ INIT -(C1)-> CALLING: nua_invite(), nua_i_state
+ CALLING -(C2)-> PROCEEDING: nua_r_invite, nua_i_state
+ PROCEEDING -(C3+C4)-> READY: nua_r_invite, nua_i_state
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+ TEST_1(is_offer_sent(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 180);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+ TEST_1(is_answer_recv(e->data->e_tags));
+ TEST_1(!e->next);
+ free_events_in_list(ctx, a->events);
+
+ /*
+ Server transitions:
+ INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
+ RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state
+ EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state
+ COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+ TEST(e->data->e_status, 100);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+ TEST_1(is_offer_recv(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+ TEST_1(is_answer_sent(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+ TEST_1(!e->next);
+ free_events_in_list(ctx, b->events);
+
+ if (print_headings)
+ printf("TEST %s.1: PASSED\n", tests);
+
+ /* ---------------------------------------------------------------------- */
+ /* REFER (initial NOTIFY is no more sent)
+ A B
+ |<------REFER--------|
+ |-------200 OK------>|
+ [|-------NOTIFY------>|] |
+ [|<------200 OK-------|] |
+ */
+
+ if (print_headings)
+ printf("TEST %s.2: refer A to C\n", tests);
+
+ *sip_refer_to_init(r0)->r_url = *c->contact->m_url;
+ r0->r_url->url_headers = "subject=referred";
+ r0->r_display = "C";
+
+ REFER(b, b_call, b_call->nh, SIPTAG_REFER_TO(r0), TAG_END());
+ run_ab_until(ctx, -1, save_until_received,
+ -1, save_until_final_response);
+
+ /*
+ Events in A:
+ nua_i_refer
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_refer);
+ TEST(e->data->e_status, 202);
+ a_event = NULL;
+ TEST(tl_gets(e->data->e_tags,
+ NUTAG_REFER_EVENT_REF(a_event),
+ TAG_END()), 1);
+ TEST_1(a_event); TEST_1(a_event = sip_event_dup(tmphome, a_event));
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(sip->sip_refer_to);
+ TEST_1(refer_to = sip_refer_to_dup(tmphome, sip->sip_refer_to));
+ TEST_1(sip->sip_referred_by);
+ TEST_1(referred_by = sip_referred_by_dup(tmphome, sip->sip_referred_by));
+ if (e->next) {
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_notify);
+ TEST_1(!e->next);
+ }
+ free_events_in_list(ctx, a->events);
+
+ /*
+ Events in B after nua_refer():
+ nua_r_refer
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_r_refer);
+ TEST(e->data->e_status, 100);
+ TEST(tl_gets(e->data->e_tags,
+ NUTAG_REFER_EVENT_REF(b_event),
+ TAG_END()), 1);
+ TEST_1(b_event); TEST_1(b_event->o_id);
+ TEST_1(b_event = sip_event_dup(tmphome, b_event));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_refer);
+ TEST(e->data->e_status, 202);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_SIZE(strtoul(b_event->o_id, NULL, 10), sip->sip_cseq->cs_seq);
+#if 0
+ if (!e->next)
+ run_b_until(ctx, -1, save_until_received);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_notify);
+ TEST(e->data->e_status, 200);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(sip->sip_event);
+ if (refer_with_id)
+ TEST_S(sip->sip_event->o_id, b_event->o_id);
+ TEST_1(sip->sip_subscription_state);
+ TEST_S(sip->sip_subscription_state->ss_substate, "pending");
+ TEST_1(sip->sip_payload && sip->sip_payload->pl_data);
+ TEST_S(sip->sip_payload->pl_data, "SIP/2.0 100 Trying\r\n");
+ TEST_1(!e->next);
+#endif
+ free_events_in_list(ctx, b->events);
+
+ if (print_headings)
+ printf("TEST %s.2: PASSED\n", tests);
+
+#if 0
+ /* ---------------------------------------------------------------------- */
+ /*
+ A B
+ |<-----SUBSCRIBE-----|
+ |-------200 OK------>|
+ |-------NOTIFY------>| |
+ |<------200 OK-------| |
+ */
+
+ if (print_headings)
+ printf("TEST %s.3: extend expiration time for implied subscription\n", tests);
+
+ SUBSCRIBE(b, b_call, b_call->nh,
+ SIPTAG_EVENT(b_event),
+ SIPTAG_EXPIRES_STR("3600"),
+ TAG_END());
+ run_ab_until(ctx, -1, save_until_final_response,
+ -1, save_until_final_response);
+
+ /*
+ Events in A:
+ nua_i_subscribe, nua_r_notify
+ */
+ TEST_1(e = a->events->head);
+ if (e->data->e_event == nua_r_notify)
+ TEST_1(e = e->next);
+ TEST_E(e->data->e_event, nua_i_subscribe);
+ TEST(e->data->e_status, 202);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(sip->sip_event);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_notify);
+ TEST_1(!e->next);
+ free_events_in_list(ctx, a->events);
+
+ /*
+ Events in B after nua_subscribe():
+ nua_r_subscribe, nua_i_notify
+ */
+ TEST_1(e = b->events->head);
+ if (e->data->e_event == nua_i_notify) {
+ TEST(e->data->e_status, 200);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(sip->sip_event);
+ if (refer_with_id)
+ TEST_S(sip->sip_event->o_id, b_event->o_id);
+ TEST_1(sip->sip_subscription_state);
+ TEST_S(sip->sip_subscription_state->ss_substate, "pending");
+ TEST_1(sip->sip_payload && sip->sip_payload->pl_data);
+ TEST_S(sip->sip_payload->pl_data, "SIP/2.0 100 Trying\r\n");
+ TEST_1(e = e->next);
+ }
+ TEST_E(e->data->e_event, nua_r_subscribe);
+ TEST(e->data->e_status, 202);
+ if (!e->next)
+ run_b_until(ctx, -1, save_until_received);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_notify);
+ TEST(e->data->e_status, 200);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(sip->sip_event);
+ if (refer_with_id)
+ TEST_S(sip->sip_event->o_id, b_event->o_id);
+ TEST_1(sip->sip_subscription_state);
+ TEST_S(sip->sip_subscription_state->ss_substate, "pending");
+ TEST_1(!e->next);
+ free_events_in_list(ctx, b->events);
+
+ if (print_headings)
+ printf("TEST %s.3: PASSED\n", tests);
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /*
+ A B C
+ | | |
+ |-----------------INVITE-------------------->|
+ | | |
+ XXX | |
+ | | |
+ |<------------------180----------------------|
+ |-------NOTIFY------>| |
+ |<------200 OK-------| |
+ | | |
+ XXX | |
+ | | |
+ |<------------------200----------------------|
+ |-------NOTIFY------>| |
+ |<------200 OK-------| |
+ |-------------------ACK--------------------->|
+ */
+
+ if (print_headings)
+ printf("TEST %s.4: A invites C\n", tests);
+
+ *sip_to_init(to)->a_url = *refer_to->r_url;
+ to->a_display = refer_to->r_display;
+
+ a->call->next = a_c2;
+
+ TEST_1(a_c2->nh = nua_handle(a->nua, a_c2, SIPTAG_TO(to), TAG_END()));
+
+ INVITE(a, a_c2, a_c2->nh, /* NUTAG_URL(refer_to->r_url), */
+ NUTAG_REFER_EVENT(a_event),
+ NUTAG_NOTIFY_REFER(a_call->nh),
+ SOATAG_USER_SDP_STR(a_c2->sdp),
+ SIPTAG_REFERRED_BY(referred_by),
+ TAG_END());
+
+ run_abc_until(ctx,
+ -1, until_ready,
+ -1, save_until_received,
+ -1, accept_call_immediately);
+ /* XXX - we should use accept_call instead of accept_call_immediately but
+ nua has a problem with automatically generated NOTIFYs:
+ 3rd NOTIFY is not sent because 2nd is still in progress
+ */
+
+ /* Client A transitions:
+ INIT -(C1)-> CALLING: nua_invite(), nua_i_state
+ CALLING -(C2a+C4)-> READY: nua_r_invite, nua_i_state
+ nua_i_notify
+
+ XXX should be:
+ CALLING -(C2+C4)-> PROCEEDING: nua_r_invite, nua_i_state
+ optional: nua_i_notify
+ PROCEEDING -(C3+C4)-> READY: nua_r_invite, nua_i_state
+ nua_i_notify
+ optional: nua_i_notify
+ */
+ TEST_1(e = a_c2->events->head); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+ TEST_1(is_offer_sent(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 200);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+ TEST_1(is_answer_recv(e->data->e_tags));
+ TEST_1(!e->next);
+ free_events_in_list(ctx, a_c2->events);
+
+ if (a->events->head == NULL)
+ run_a_until(ctx, -1, save_until_received);
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_notify);
+ TEST_1(!e->next);
+ free_events_in_list(ctx, a->events);
+
+ /*
+ Events in B after nua_refer():
+ nua_i_notify
+ */
+ if (b->events->head == NULL)
+ run_b_until(ctx, -1, save_until_received);
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_notify);
+ TEST(e->data->e_status, 200);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(sip->sip_subscription_state);
+ TEST_S(sip->sip_subscription_state->ss_substate, "terminated");
+ TEST_1(sip->sip_payload && sip->sip_payload->pl_data);
+ TEST_S(sip->sip_payload->pl_data, "SIP/2.0 200 OK\r\n");
+ TEST_1(sip->sip_event);
+ if (refer_with_id)
+ TEST_S(sip->sip_event->o_id, b_event->o_id);
+ TEST_1(!e->next);
+ free_events_in_list(ctx, b->events);
+
+ /*
+ C transitions:
+ INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
+ RECEIVED -(S3b)-> COMPLETED: nua_respond(), nua_i_state
+ COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
+ */
+ TEST_1(e = c->events->head); TEST_E(e->data->e_event, nua_i_invite);
+ TEST(e->data->e_status, 100);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+ TEST_1(is_offer_recv(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+ TEST_1(is_answer_sent(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+ TEST_1(!e->next);
+ free_events_in_list(ctx, c->events);
+
+ if (print_headings)
+ printf("TEST %s.4: PASSED\n", tests);
+
+ /* ---------------------------------------------------------------------- */
+ /*
+ A B
+ |---------BYE------->|
+ |<--------200--------|
+ */
+
+ if (print_headings)
+ printf("TEST %s.5.1: terminate call between A and B\n", tests);
+
+ BYE(a, a_call, a_call->nh, TAG_END());
+ run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
+
+ /*
+ Transitions of A:
+ READY --(T2)--> TERMINATING: nua_bye()
+ TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_bye);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+ free_events_in_list(ctx, a->events);
+
+ /* Transitions of B:
+ READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_bye);
+ TEST(e->data->e_status, 200);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+ free_events_in_list(ctx, b->events);
+
+ if (print_headings)
+ printf("TEST %s.5.1: PASSED\n", tests);
+
+ nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+ nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+
+ /* ---------------------------------------------------------------------- */
+ /*
+ A C
+ |-------------------BYE--------------------->|
+ |<------------------200----------------------|
+ */
+
+ if (print_headings)
+ printf("TEST %s.5.2: terminate call between A and C\n", tests);
+
+ BYE(a, a_c2, a_c2->nh, TAG_END());
+ run_abc_until(ctx, -1, until_terminated, -1, NULL, -1, until_terminated);
+
+ /*
+ Transitions of A:
+ READY --(T2)--> TERMINATING: nua_bye()
+ TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
+ */
+ TEST_1(e = a_c2->events->head); TEST_E(e->data->e_event, nua_r_bye);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+ free_events_in_list(ctx, a_c2->events);
+
+ /* Transitions of B:
+ READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state
+ */
+ TEST_1(e = c->events->head); TEST_E(e->data->e_event, nua_i_bye);
+ TEST(e->data->e_status, 200);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+ free_events_in_list(ctx, c->events);
+
+ if (print_headings)
+ printf("TEST %s.5.2: PASSED\n", tests);
+
+ nua_handle_destroy(a_c2->nh), a_c2->nh = NULL;
+ a->call->next = NULL; free(a_c2);
+
+ nua_handle_destroy(c_call->nh), c_call->nh = NULL;
+
+ if (print_headings)
+ printf("TEST %s: PASSED\n", tests);
+
+ su_home_deinit(tmphome);
+
+ END();
+}
+
+
+/*
+ accept_call_immediately
+ X
+ | |
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ | |
+ |<--------200--------|
+ |---------ACK------->|
+*/
+int accept_call_immediately(CONDITION_PARAMS)
+{
+ if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+ return 0;
+
+ save_event_in_list(ctx, event, ep, call);
+
+ switch (callstate(tags)) {
+ case nua_callstate_received:
+ RESPOND(ep, call, nh, SIP_200_OK,
+ TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)),
+ TAG_END());
+ return 0;
+ case nua_callstate_ready:
+ return 1;
+ case nua_callstate_terminated:
+ if (call)
+ nua_handle_destroy(call->nh), call->nh = NULL;
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+/*
+ X INVITE
+ | |
+ |-----------------INVITE-------------------->|
+ | | |
+ | | |
+ |<------------------200----------------------|
+ |-------NOTIFY------>| |
+ |--------BYE-------->| |
+ |-------------------ACK--------------------->|
+
+*/
+int notify_until_terminated(CONDITION_PARAMS)
+{
+ if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+ return 0;
+
+ save_event_in_list(ctx, event, ep, call);
+
+ if (event == nua_r_invite) {
+ sip_status_t *st = sip->sip_status;
+ sip_payload_t *pl;
+
+ pl = sip_payload_format(NULL, "SIP/2.0 %u %s\r\n",
+ st->st_status, st->st_phrase);
+
+ NOTIFY(ep, ep->call, ep->call->nh,
+ SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
+ SIPTAG_PAYLOAD(pl),
+ TAG_IF(st->st_status >= 200,
+ NUTAG_SUBSTATE(nua_substate_terminated)),
+ TAG_END());
+
+ BYE(ep, ep->call, ep->call->nh, TAG_END());
+ return 0;
+ }
+
+ if (call != ep->call)
+ return 0;
+
+ switch (callstate(tags)) {
+ case nua_callstate_terminated:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+/* Referred call - NOTIFY and BYE are overlapped
+
+ A B
+ | |
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ | |
+ |<----180 Ringing----|
+ | |
+ |<------200 OK-------|
+ |--------ACK-------->|
+ | |
+ |<------REFER--------|
+ |-------200 OK------>| C
+ [|-------NOTIFY------>|] |
+ [|<------200 OK-------|] |
+ | | |
+ | | |
+ |<-----SUBSCRIBE-----| |
+ |-------200 OK------>| |
+ | | |
+ | | |
+ |-----------------INVITE-------------------->|
+ | | |
+ | | |
+ |<------------------200----------------------|
+ |-------NOTIFY------>| |
+ |--------BYE-------->| |
+ |-------------------ACK--------------------->|
+ |<------200 OK-------| |
+ |<------200 OK-------| |
+ | X |
+ | |
+ |-------------------BYE--------------------->|
+ |<------------------200----------------------|
+ | |
+
+*/
+
+int test_refer1(struct context *ctx, int refer_with_id, char const *tests)
+{
+ BEGIN();
+
+ struct endpoint *a = &ctx->a, *b = &ctx->b, *c = &ctx->c;
+ struct call *a_call = a->call, *b_call = b->call, *c_call = c->call;
+ struct call *a_c2;
+ struct event *e;
+ sip_t const *sip;
+ sip_event_t const *a_event, *b_event;
+ sip_refer_to_t const *refer_to;
+ sip_referred_by_t const *referred_by;
+
+ sip_refer_to_t r0[1];
+ sip_to_t to[1];
+
+ su_home_t tmphome[SU_HOME_AUTO_SIZE(16384)];
+
+ su_home_auto(tmphome, sizeof(tmphome));
+
+ if (print_headings)
+ printf("TEST %s: REFER: refer A to C\n", tests);
+
+ if (print_headings)
+ printf("TEST %s.1: REFER: make a call between A and B\n", tests);
+
+ /* Do (not) include id with first implicit Event: refer */
+ nua_set_params(ctx->a.nua, NUTAG_REFER_WITH_ID(refer_with_id), TAG_END());
+ run_a_until(ctx, nua_r_set_params, until_final_response);
+
+ TEST_1(a_c2 = calloc(1, (sizeof *a_c2) + (sizeof *a_c2->events)));
+ call_init(a_c2);
+ a_c2->events = (void *)(a_c2 + 1);
+ eventlist_init(a_c2->events);
+
+ a_call->sdp = "m=audio 5008 RTP/AVP 8";
+ b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
+ a_c2->sdp = "m=audio 5012 RTP/AVP 8";
+ c_call->sdp = "m=audio 5014 RTP/AVP 0 8";
+
+ TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+ INVITE(a, a_call, a_call->nh,
+ TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+ SOATAG_USER_SDP_STR(a_call->sdp),
+ TAG_END());
+
+ run_ab_until(ctx, -1, until_ready, -1, accept_call);
+
+ /* Client transitions:
+ INIT -(C1)-> CALLING: nua_invite(), nua_i_state
+ CALLING -(C2)-> PROCEEDING: nua_r_invite, nua_i_state
+ PROCEEDING -(C3+C4)-> READY: nua_r_invite, nua_i_state
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+ TEST_1(is_offer_sent(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 180);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+ TEST_1(is_answer_recv(e->data->e_tags));
+ TEST_1(!e->next);
+ free_events_in_list(ctx, a->events);
+
+ /*
+ Server transitions:
+ INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
+ RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state
+ EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state
+ COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+ TEST(e->data->e_status, 100);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+ TEST_1(is_offer_recv(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+ TEST_1(is_answer_sent(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+ TEST_1(!e->next);
+ free_events_in_list(ctx, b->events);
+
+ if (print_headings)
+ printf("TEST %s.1: PASSED\n", tests);
+
+ /* ---------------------------------------------------------------------- */
+ /* REFER (initial NOTIFY is no more sent)
+ A B
+ |<------REFER--------|
+ |-------200 OK------>|
+ [|-------NOTIFY------>|] |
+ [|<------200 OK-------|] |
+ */
+
+ if (print_headings)
+ printf("TEST %s.2: refer A to C\n", tests);
+
+ *sip_refer_to_init(r0)->r_url = *c->contact->m_url;
+ r0->r_url->url_headers = "subject=referred";
+ r0->r_display = "C";
+
+ REFER(b, b_call, b_call->nh, SIPTAG_REFER_TO(r0), TAG_END());
+ run_ab_until(ctx, -1, save_until_received,
+ -1, save_until_final_response);
+
+ /*
+ Events in A:
+ nua_i_refer
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_refer);
+ TEST(e->data->e_status, 202);
+ a_event = NULL;
+ TEST(tl_gets(e->data->e_tags,
+ NUTAG_REFER_EVENT_REF(a_event),
+ TAG_END()), 1);
+ TEST_1(a_event); TEST_1(a_event = sip_event_dup(tmphome, a_event));
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(sip->sip_refer_to);
+ TEST_1(refer_to = sip_refer_to_dup(tmphome, sip->sip_refer_to));
+ TEST_1(sip->sip_referred_by);
+ TEST_1(referred_by = sip_referred_by_dup(tmphome, sip->sip_referred_by));
+ if (e->next) {
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_notify);
+ TEST_1(!e->next);
+ }
+ free_events_in_list(ctx, a->events);
+
+ /*
+ Events in B after nua_refer():
+ nua_r_refer
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_r_refer);
+ TEST(e->data->e_status, 100);
+ TEST(tl_gets(e->data->e_tags,
+ NUTAG_REFER_EVENT_REF(b_event),
+ TAG_END()), 1);
+ TEST_1(b_event); TEST_1(b_event->o_id);
+ TEST_1(b_event = sip_event_dup(tmphome, b_event));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_refer);
+ TEST(e->data->e_status, 202);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_SIZE(strtoul(b_event->o_id, NULL, 10), sip->sip_cseq->cs_seq);
+#if 0
+ if (!e->next)
+ run_b_until(ctx, -1, save_until_received);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_notify);
+ TEST(e->data->e_status, 200);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(sip->sip_event);
+ if (refer_with_id)
+ TEST_S(sip->sip_event->o_id, b_event->o_id);
+ TEST_1(sip->sip_subscription_state);
+ TEST_S(sip->sip_subscription_state->ss_substate, "pending");
+ TEST_1(sip->sip_payload && sip->sip_payload->pl_data);
+ TEST_S(sip->sip_payload->pl_data, "SIP/2.0 100 Trying\r\n");
+ TEST_1(!e->next);
+#endif
+ free_events_in_list(ctx, b->events);
+
+ if (print_headings)
+ printf("TEST %s.2: PASSED\n", tests);
+
+
+ /* ---------------------------------------------------------------------- */
+ /*
+ A B C
+ | | |
+ |-----------------INVITE-------------------->|
+ | | |
+ XXX | |
+ | | |
+ |<------------------200----------------------|
+ |-------NOTIFY------>| |
+ |---------BYE------->| |
+ |-------------------ACK--------------------->|
+ |<--------200--------| |
+ |<------200 OK-------| |
+ | X
+ */
+
+ if (print_headings)
+ printf("TEST %s.4: A invites C\n", tests);
+
+ *sip_to_init(to)->a_url = *refer_to->r_url;
+ to->a_display = refer_to->r_display;
+
+ a->call->next = a_c2;
+
+ TEST_1(a_c2->nh = nua_handle(a->nua, a_c2, SIPTAG_TO(to), TAG_END()));
+
+ INVITE(a, a_c2, a_c2->nh, /* NUTAG_URL(refer_to->r_url), */
+ NUTAG_REFER_EVENT(a_event),
+ /* NUTAG_NOTIFY_REFER(a_call->nh), */
+ SOATAG_USER_SDP_STR(a_c2->sdp),
+ SIPTAG_REFERRED_BY(referred_by),
+ TAG_END());
+
+ run_abc_until(ctx,
+ -1, notify_until_terminated,
+ -1, until_terminated,
+ -1, accept_call_immediately);
+
+ /* XXX - we should use accept_call instead of accept_call_immediately but
+ nua has a problem with automatically generated NOTIFYs:
+ 3rd NOTIFY is not sent because 2nd is still in progress
+ */
+
+ /* Client A transitions:
+ INIT -(C1)-> CALLING: nua_invite(), nua_i_state
+ CALLING -(C2a+C4)-> READY: nua_r_invite, nua_i_state
+ nua_r_notify
+
+ Transitions of first call:
+ READY --(T2)--> TERMINATING: nua_bye()
+ TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
+
+ XXX should be:
+ CALLING -(C2+C4)-> PROCEEDING: nua_r_invite, nua_i_state
+ optional: nua_i_notify
+ PROCEEDING -(C3+C4)-> READY: nua_r_invite, nua_i_state
+ nua_i_notify
+ optional: nua_i_notify
+ */
+ TEST_1(e = a_c2->events->head); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+ TEST_1(is_offer_sent(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 200);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+ TEST_1(is_answer_recv(e->data->e_tags));
+ TEST_1(!e->next);
+ free_events_in_list(ctx, a_c2->events);
+
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_notify);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_bye);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ free_events_in_list(ctx, a->events);
+
+ nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+ /*
+ Events in B after nua_refer():
+ nua_i_notify
+ READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state
+ */
+ if (b->events->head == NULL)
+ run_b_until(ctx, -1, save_until_received);
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_notify);
+ TEST(e->data->e_status, 200);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(sip->sip_subscription_state);
+ TEST_S(sip->sip_subscription_state->ss_substate, "terminated");
+ TEST_1(sip->sip_payload && sip->sip_payload->pl_data);
+ TEST_S(sip->sip_payload->pl_data, "SIP/2.0 200 OK\r\n");
+ TEST_1(sip->sip_event);
+ if (refer_with_id)
+ TEST_S(sip->sip_event->o_id, b_event->o_id);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_bye);
+ TEST(e->data->e_status, 200);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+ free_events_in_list(ctx, b->events);
+
+ nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+ /*
+ C transitions:
+ INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
+ RECEIVED -(S3b)-> COMPLETED: nua_respond(), nua_i_state
+ COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
+ */
+ TEST_1(e = c->events->head); TEST_E(e->data->e_event, nua_i_invite);
+ TEST(e->data->e_status, 100);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+ TEST_1(is_offer_recv(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+ TEST_1(is_answer_sent(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+ TEST_1(!e->next);
+ free_events_in_list(ctx, c->events);
+
+ if (print_headings)
+ printf("TEST %s.4: PASSED\n", tests);
+
+ /* ---------------------------------------------------------------------- */
+ /*
+ A C
+ |-------------------BYE--------------------->|
+ |<------------------200----------------------|
+ */
+
+ if (print_headings)
+ printf("TEST %s.5.2: terminate call between A and C\n", tests);
+
+ BYE(a, a_c2, a_c2->nh, TAG_END());
+ run_abc_until(ctx, -1, until_terminated, -1, NULL, -1, until_terminated);
+
+ /*
+ Transitions of A:
+ READY --(T2)--> TERMINATING: nua_bye()
+ TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
+ */
+ TEST_1(e = a_c2->events->head); TEST_E(e->data->e_event, nua_r_bye);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+ free_events_in_list(ctx, a_c2->events);
+
+ /* Transitions of B:
+ READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state
+ */
+ TEST_1(e = c->events->head); TEST_E(e->data->e_event, nua_i_bye);
+ TEST(e->data->e_status, 200);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+ free_events_in_list(ctx, c->events);
+
+ if (print_headings)
+ printf("TEST %s.5.2: PASSED\n", tests);
+
+ nua_handle_destroy(a_c2->nh), a_c2->nh = NULL;
+ a->call->next = NULL; free(a_c2);
+
+ nua_handle_destroy(c_call->nh), c_call->nh = NULL;
+
+ if (print_headings)
+ printf("TEST %s: PASSED\n", tests);
+
+ su_home_deinit(tmphome);
+
+ END();
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_register.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_register.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,703 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_register.c
+ * @brief Test registering, outbound, nat traversal.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti Mela at nokia.com>
+ *
+ * @date Created: Wed Aug 17 12:12:12 EEST 2005 ppessi
+ */
+
+#include "config.h"
+
+#include "test_nua.h"
+#include <sofia-sip/su_tag_class.h>
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+#define __func__ "test_register"
+#endif
+
+/* ======================================================================== */
+/* Test REGISTER */
+
+int test_register_to_proxy(struct context *ctx)
+{
+ BEGIN();
+
+ struct endpoint *a = &ctx->a, *b = &ctx->b, *c = &ctx->c, *x;
+ struct call *a_reg = a->reg, *b_reg = b->reg, *c_reg = c->reg;
+ struct event *e;
+ sip_t const *sip;
+ sip_cseq_t cseq[1];
+
+ if (ctx->p)
+ test_proxy_set_expiration(ctx->p, 5, 5, 10);
+
+ if (print_headings)
+ printf("TEST NUA-2.3.0.1: un-REGISTER a\n");
+
+ TEST_1(a_reg->nh = nua_handle(a->nua, a_reg, TAG_END()));
+ UNREGISTER(a, a_reg, a_reg->nh, SIPTAG_TO(a->to),
+ SIPTAG_CONTACT_STR("*"),
+ TAG_END());
+ run_a_until(ctx, -1, until_final_response);
+ AUTHENTICATE(a, a_reg, a_reg->nh,
+ NUTAG_AUTH("Digest:\"test-proxy\":alice:secret"), TAG_END());
+ run_a_until(ctx, -1, until_final_response);
+ nua_handle_destroy(a_reg->nh);
+
+ if (print_headings)
+ printf("TEST NUA-2.3.0.1: PASSED\n");
+
+ if (print_headings)
+ printf("TEST NUA-2.3.0.2: un-REGISTER b\n");
+
+ TEST_1(b_reg->nh = nua_handle(b->nua, b_reg, TAG_END()));
+ UNREGISTER(b, b_reg, b_reg->nh, SIPTAG_TO(b->to),
+ SIPTAG_CONTACT_STR("*"),
+ TAG_END());
+ run_b_until(ctx, -1, until_final_response);
+ AUTHENTICATE(b, b_reg, b_reg->nh,
+ NUTAG_AUTH("Digest:\"test-proxy\":bob:secret"), TAG_END());
+ run_b_until(ctx, -1, until_final_response);
+ nua_handle_destroy(b_reg->nh);
+
+ if (print_headings)
+ printf("TEST NUA-2.3.0.2: PASSED\n");
+
+ if (print_headings)
+ printf("TEST NUA-2.3.0.3: un-REGISTER c\n");
+
+ TEST_1(c_reg->nh = nua_handle(c->nua, c_reg, TAG_END()));
+ UNREGISTER(c, c_reg, c_reg->nh, SIPTAG_TO(c->to),
+ SIPTAG_CONTACT_STR("*"),
+ TAG_END());
+ run_c_until(ctx, -1, until_final_response);
+ AUTHENTICATE(c, c_reg, c_reg->nh,
+ NUTAG_AUTH("Digest:\"test-proxy\":charlie:secret"), TAG_END());
+ run_c_until(ctx, -1, until_final_response);
+ nua_handle_destroy(c_reg->nh);
+
+ if (print_headings)
+ printf("TEST NUA-2.3.0.3: PASSED\n");
+
+
+/* REGISTER test
+
+ A B
+ |------REGISTER----->|
+ |<-------401---------|
+ |------REGISTER----->|
+ |<-------200---------|
+ | |
+
+*/
+
+ if (print_headings)
+ printf("TEST NUA-2.3.1: REGISTER a\n");
+
+ TEST_1(a_reg->nh = nua_handle(a->nua, a_reg, TAG_END()));
+
+ sip_cseq_init(cseq)->cs_seq = 12;
+ cseq->cs_method = sip_method_register;
+ cseq->cs_method_name = sip_method_name_register;
+
+ REGISTER(a, a_reg, a_reg->nh, SIPTAG_TO(a->to),
+ NUTAG_OUTBOUND("natify options-keepalive validate"),
+ NUTAG_KEEPALIVE(1000),
+ NUTAG_M_DISPLAY("A&A"),
+ NUTAG_M_USERNAME("a"),
+ SIPTAG_CSEQ(cseq),
+ TAG_END());
+ run_a_until(ctx, -1, save_until_final_response);
+
+ TEST_1(e = a->events->head);
+ TEST_E(e->data->e_event, nua_r_register);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST(e->data->e_status, 401);
+ TEST(sip->sip_status->st_status, 401);
+ TEST(sip->sip_cseq->cs_seq, 13);
+ TEST_1(!sip->sip_contact);
+ TEST_1(!e->next);
+ free_events_in_list(ctx, a->events);
+
+ AUTHENTICATE(a, a_reg, a_reg->nh,
+ NUTAG_AUTH("Digest:\"test-proxy\":alice:secret"), TAG_END());
+ run_a_until(ctx, -1, save_until_final_response);
+
+ TEST_1(e = a->events->head);
+ TEST_E(e->data->e_event, nua_r_register);
+ TEST(e->data->e_status, 200);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(sip->sip_contact);
+ { char const *expect_m_display = "\"A&A\"";
+ /* VC does not dig \" with TEST_S() */
+ TEST_S(sip->sip_contact->m_display, expect_m_display); }
+ TEST_S(sip->sip_contact->m_url->url_user, "a");
+ TEST(sip->sip_cseq->cs_seq, 14);
+
+ if (ctx->nat) {
+ TEST_1(e = a->specials->head);
+ }
+
+ if (print_headings)
+ printf("TEST NUA-2.3.1: PASSED\n");
+
+ if (print_headings)
+ printf("TEST NUA-2.3.2: REGISTER b\n");
+
+ TEST_1(b_reg->nh = nua_handle(b->nua, b_reg, TAG_END()));
+
+ /* Test application-supplied contact */
+ {
+ sip_contact_t m[1];
+ sip_contact_init(m)->m_url[0] = b->contact->m_url[0];
+
+ m->m_display = "B";
+ m->m_url->url_user = "b";
+
+ REGISTER(b, b_reg, b_reg->nh, SIPTAG_TO(b->to),
+ SIPTAG_CONTACT(m),
+ TAG_END());
+ }
+ run_ab_until(ctx, -1, save_events, -1, save_until_final_response);
+
+ TEST_1(e = b->events->head);
+ TEST_E(e->data->e_event, nua_r_register);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST(e->data->e_status, 401);
+ TEST(sip->sip_status->st_status, 401);
+ TEST_1(!sip->sip_contact);
+ TEST_1(!e->next);
+ free_events_in_list(ctx, b->events);
+
+ AUTHENTICATE(b, b_reg, b_reg->nh,
+ NUTAG_AUTH("Digest:\"test-proxy\":bob:secret"), TAG_END());
+ run_ab_until(ctx, -1, save_events, -1, save_until_final_response);
+
+ TEST_1(e = b->events->head);
+ TEST_E(e->data->e_event, nua_r_register);
+ TEST(e->data->e_status, 200);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(sip->sip_contact);
+ TEST_S(sip->sip_contact->m_display, "B");
+ TEST_S(sip->sip_contact->m_url->url_user, "b");
+
+ if (print_headings)
+ printf("TEST NUA-2.3.2: PASSED\n");
+
+ if (ctx->p)
+ test_proxy_set_expiration(ctx->p, 600, 3600, 36000);
+
+ if (print_headings)
+ printf("TEST NUA-2.3.3: REGISTER c\n");
+
+ TEST_1(c_reg->nh = nua_handle(c->nua, c_reg, TAG_END()));
+
+ REGISTER(c, c_reg, c_reg->nh, SIPTAG_TO(c->to),
+ NUTAG_M_DISPLAY("C"),
+ NUTAG_M_USERNAME("c"),
+ SIPTAG_EXPIRES_STR("5"), /* Test 423 negotiation */
+ TAG_END());
+ run_abc_until(ctx, -1, save_events, -1, save_events,
+ -1, save_until_final_response);
+
+ TEST_1(e = c->events->head);
+ TEST_E(e->data->e_event, nua_r_register);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST(e->data->e_status, 401);
+ TEST(sip->sip_status->st_status, 401);
+ TEST_1(!sip->sip_contact);
+ TEST_1(!e->next);
+ free_events_in_list(ctx, c->events);
+
+ AUTHENTICATE(c, c_reg, c_reg->nh,
+ NUTAG_AUTH("Digest:\"test-proxy\":charlie:secret"), TAG_END());
+ run_abc_until(ctx, -1, save_events, -1, save_events,
+ -1, save_until_final_response);
+
+ TEST_1(e = c->events->head);
+ TEST_E(e->data->e_event, nua_r_register);
+ TEST(e->data->e_status, 100);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST(sip->sip_status->st_status, 423);
+ TEST_1(e = e->next);
+ TEST(e->data->e_status, 200);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(sip->sip_contact);
+ TEST_S(sip->sip_contact->m_display, "C");
+ TEST_S(sip->sip_contact->m_url->url_user, "c");
+ TEST_1(!e->next);
+ free_events_in_list(ctx, c->events);
+
+ if (print_headings)
+ printf("TEST NUA-2.3.3: PASSED\n");
+
+ if (!ctx->p) {
+ free_events_in_list(ctx, a->events);
+ free_events_in_list(ctx, b->events);
+ return 0;
+ }
+
+ if (print_headings)
+ printf("TEST NUA-2.3.4: refresh REGISTER\n");
+
+ /* Wait for A and B to refresh their registrations */
+
+ /*
+ * Avoid race condition: if X has already refreshed registration
+ * with expiration time of 3600 seconds, do not wait for new refresh
+ */
+ a->next_condition = save_until_final_response;
+ b->next_condition = save_until_final_response;
+
+ for (x = a; x; x = x == a ? b : NULL) {
+ for (e = x->events->head; e; e = e->next) {
+ if (e->data->e_event == nua_r_register &&
+ e->data->e_status == 200 &&
+ (sip = sip_object(e->data->e_msg)) &&
+ sip->sip_contact &&
+ sip->sip_contact->m_expires &&
+ strcmp(sip->sip_contact->m_expires, "3600") == 0) {
+ x->next_condition = NULL;
+ break;
+ }
+ }
+ }
+
+ run_ab_until(ctx, -1, a->next_condition, -1, b->next_condition);
+
+ for (e = a->events->head; e; e = e->next) {
+ TEST_E(e->data->e_event, nua_r_register);
+ TEST(e->data->e_status, 200);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(sip->sip_contact);
+ if (!e->next)
+ break;
+ }
+ TEST_1(e);
+ TEST_S(sip->sip_contact->m_expires, "3600");
+ TEST_1(!e->next);
+ free_events_in_list(ctx, a->events);
+
+ for (e = b->events->head; e; e = e->next) {
+ TEST_E(e->data->e_event, nua_r_register);
+ TEST(e->data->e_status, 200);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(sip->sip_contact);
+ if (!e->next)
+ break;
+ }
+ TEST_1(e);
+ TEST_S(sip->sip_contact->m_expires, "3600");
+ TEST_1(!e->next);
+ free_events_in_list(ctx, b->events);
+
+ if (print_headings)
+ printf("TEST NUA-2.3.4: PASSED\n");
+
+ END();
+}
+
+int registrar_299(CONDITION_PARAMS)
+{
+ msg_t *request = nua_current_request(nua);
+
+ save_event_in_list(ctx, event, ep, ep->call);
+
+ if (event == nua_i_register) {
+ RESPOND(ep, call, nh, 299, "YES", NUTAG_WITH(request), TAG_END());
+ return 1;
+ }
+
+ return 0;
+}
+
+int test_register_to_c(struct context *ctx)
+{
+ BEGIN();
+
+ struct endpoint *b = &ctx->b, *c = &ctx->c;
+ struct call *b_call = b->call, *c_call = c->call;
+ struct event *e;
+ sip_t const *sip;
+
+ if (print_headings)
+ printf("TEST NUA-2.3.2: REGISTER b to c\n");
+
+ nua_set_params(ctx->c.nua,
+ NUTAG_ALLOW("REGISTER"),
+ TAG_END());
+ run_c_until(ctx, nua_r_set_params, until_final_response);
+
+ TEST_1(b_call->nh = nua_handle(b->nua, b_call, TAG_END()));
+
+ REGISTER(b, b_call, b_call->nh,
+ NUTAG_REGISTRAR((url_string_t *)c->contact->m_url),
+ SIPTAG_TO(b->to),
+ NUTAG_OUTBOUND(NULL),
+ SIPTAG_CONTACT_STR(NULL),
+ TAG_END());
+ run_bc_until(ctx, -1, save_until_final_response, -1, registrar_299);
+
+ TEST_1(e = b->events->head);
+ TEST_E(e->data->e_event, nua_r_register);
+ TEST(e->data->e_status, 299);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(!sip->sip_contact);
+
+ if (print_headings)
+ printf("TEST NUA-2.6.1: PASSED\n");
+
+ free_events_in_list(ctx, b->events);
+ nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+ TEST_1(e = c->events->head);
+ TEST_E(e->data->e_event, nua_i_register);
+ TEST(e->data->e_status, 100);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(!sip->sip_contact);
+
+ free_events_in_list(ctx, c->events);
+ nua_handle_destroy(c_call->nh), c_call->nh = NULL;
+
+ if (print_headings)
+ printf("TEST NUA-2.3.4: PASSED\n");
+
+ END();
+}
+
+
+int test_register(struct context *ctx)
+{
+ if (test_register_to_c(ctx))
+ return 1;
+
+ if (ctx->proxy_tests)
+ if (test_register_to_proxy(ctx)) return 1;
+
+ return 0;
+}
+
+
+int test_connectivity(struct context *ctx)
+{
+ if (!ctx->proxy_tests)
+ return 0; /* No proxy */
+
+ BEGIN();
+
+ struct endpoint *a = &ctx->a, *b = &ctx->b, *c = &ctx->c;
+ struct call *a_call = a->call, *b_call = b->call, *c_call = c->call;
+ struct event *e;
+ sip_t const *sip;
+
+ /* Connectivity test using OPTIONS */
+
+ if (print_headings)
+ printf("TEST NUA-2.4.1: OPTIONS from A to B\n");
+
+ TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+ OPTIONS(a, a_call, a_call->nh,
+ TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+ NUTAG_ALLOW("OPTIONS"),
+ TAG_END());
+
+ run_ab_until(ctx, -1, save_until_final_response, -1, save_until_received);
+
+ /* Client events: nua_options(), nua_r_options */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_options);
+ TEST(e->data->e_status, 200);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(sip->sip_allow); TEST_1(sip->sip_accept); TEST_1(sip->sip_supported);
+ /* TEST_1(sip->sip_content_type); */
+ /* TEST_1(sip->sip_payload); */
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, a->events);
+ nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+ /* Server events: nua_i_options */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_options);
+ TEST(e->data->e_status, 200);
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, b->events);
+ nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+ if (print_headings)
+ printf("TEST NUA-2.4.1: PASSED\n");
+
+ if (print_headings)
+ printf("TEST NUA-2.4.2: OPTIONS from B to C\n");
+
+ TEST_1(b_call->nh = nua_handle(b->nua, b_call, SIPTAG_TO(c->to), TAG_END()));
+
+ OPTIONS(b, b_call, b_call->nh,
+ TAG_IF(!ctx->proxy_tests, NUTAG_URL(c->contact->m_url)),
+ TAG_END());
+
+ run_abc_until(ctx, -1, NULL,
+ -1, save_until_final_response,
+ -1, save_until_received);
+
+ /* Client events: nua_options(), nua_r_options */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_r_options);
+ TEST(e->data->e_status, 200);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(sip->sip_allow); TEST_1(sip->sip_accept); TEST_1(sip->sip_supported);
+ /* TEST_1(sip->sip_content_type); */
+ /* TEST_1(sip->sip_payload); */
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, b->events);
+ nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+ /* Server events: nua_i_options */
+ TEST_1(e = c->events->head); TEST_E(e->data->e_event, nua_i_options);
+ TEST(e->data->e_status, 200);
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, c->events);
+ nua_handle_destroy(c_call->nh), c_call->nh = NULL;
+
+ if (print_headings)
+ printf("TEST NUA-2.4.2: PASSED\n");
+
+ if (print_headings)
+ printf("TEST NUA-2.4.3: OPTIONS from C to A\n");
+
+ TEST_1(c_call->nh = nua_handle(c->nua, c_call, SIPTAG_TO(a->to), TAG_END()));
+
+ OPTIONS(c, c_call, c_call->nh,
+ TAG_IF(!ctx->proxy_tests, NUTAG_URL(a->contact->m_url)),
+ TAG_END());
+
+ if (ctx->proxy_tests) {
+ run_abc_until(ctx, -1, NULL, -1, NULL, -1, save_until_final_response);
+
+ /* Client events: nua_options(), nua_r_options */
+ TEST_1(e = c->events->head); TEST_E(e->data->e_event, nua_r_options);
+ TEST(e->data->e_status, 407);
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, c->events);
+
+ AUTHENTICATE(c, c_call, c_call->nh,
+ NUTAG_AUTH("Digest:\"test-proxy\":charlie:secret"),
+ TAG_END());
+ }
+
+ run_abc_until(ctx, -1, save_until_received,
+ -1, NULL,
+ -1, save_until_final_response);
+
+ /* Client events: nua_options(), nua_r_options */
+ TEST_1(e = c->events->head); TEST_E(e->data->e_event, nua_r_options);
+ TEST(e->data->e_status, 200);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(sip->sip_allow); TEST_1(sip->sip_accept); TEST_1(sip->sip_supported);
+ /* TEST_1(sip->sip_content_type); */
+ /* TEST_1(sip->sip_payload); */
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, c->events);
+ nua_handle_destroy(c_call->nh), c_call->nh = NULL;
+
+ /* Server events: nua_i_options */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_options);
+ TEST(e->data->e_status, 200);
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, a->events);
+ nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+ if (print_headings)
+ printf("TEST NUA-2.4.3: PASSED\n");
+
+ END();
+}
+
+int test_nat_timeout(struct context *ctx)
+{
+ if (!ctx->proxy_tests || !ctx->nat)
+ return 0; /* No proxy */
+
+ BEGIN();
+
+ struct endpoint *a = &ctx->a, *b = &ctx->b, *c = &ctx->c;
+ struct event *e;
+ sip_t const *sip;
+
+ /* Test what happens when NAT bindings go away */
+
+ if (print_headings)
+ printf("TEST NUA-2.5.1: NAT binding change\n");
+
+ free_events_in_list(ctx, a->specials);
+
+ test_nat_flush(ctx->nat); /* Break our connections */
+
+ /* Run until we get final response to REGISTER */
+ run_a_until(ctx, -1, save_until_final_response);
+
+ TEST_1(e = a->specials->head);
+ TEST_E(e->data->e_event, nua_i_outbound);
+ TEST(e->data->e_status, 102);
+ TEST_S(e->data->e_phrase, "NAT binding changed");
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, a->specials);
+
+ TEST_1(e = a->events->head);
+ TEST_E(e->data->e_event, nua_r_register);
+ TEST(e->data->e_status, 200);
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, a->events);
+
+ if (print_headings)
+ printf("TEST NUA-2.5.1: PASSED\n");
+
+ (void)b; (void)c; (void)sip;
+
+ END();
+}
+
+int test_unregister(struct context *ctx)
+{
+ if (!ctx->proxy_tests)
+ return 0; /* No proxy */
+
+ BEGIN();
+
+ struct endpoint *a = &ctx->a, *b = &ctx->b, *c = &ctx->c;
+ struct event *e;
+ sip_t const *sip;
+
+/* un-REGISTER test
+
+ A B
+ |----un-REGISTER---->|
+ |<-------200---------|
+ | |
+
+*/
+ if (print_headings)
+ printf("TEST NUA-13.1: un-REGISTER a\n");
+
+ if (a->reg->nh) {
+ free_events_in_list(ctx, a->events);
+ UNREGISTER(a, NULL, a->reg->nh, TAG_END());
+ run_a_until(ctx, -1, save_until_final_response);
+ TEST_1(e = a->events->head);
+ TEST_E(e->data->e_event, nua_r_unregister);
+ TEST(e->data->e_status, 200);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(!sip->sip_contact);
+ TEST_1(!e->next);
+ free_events_in_list(ctx, a->events);
+ nua_handle_destroy(a->reg->nh), a->reg->nh = NULL;
+ }
+
+ if (print_headings)
+ printf("TEST NUA-13.1: PASSED\n");
+
+ if (print_headings)
+ printf("TEST NUA-13.2: un-REGISTER b\n");
+
+ if (b->reg->nh) {
+ free_events_in_list(ctx, b->events);
+ UNREGISTER(b, NULL, b->reg->nh, TAG_END());
+ run_b_until(ctx, -1, save_until_final_response);
+ TEST_1(e = b->events->head);
+ TEST_E(e->data->e_event, nua_r_unregister);
+ TEST(e->data->e_status, 200);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(!sip->sip_contact);
+ TEST_1(!e->next);
+ free_events_in_list(ctx, b->events);
+ nua_handle_destroy(b->reg->nh), b->reg->nh = NULL;
+ }
+ if (print_headings)
+ printf("TEST NUA-13.2: PASSED\n");
+
+ if (print_headings)
+ printf("TEST NUA-13.3: un-REGISTER c\n");
+
+ /* Unregister using another handle */
+ free_events_in_list(ctx, c->events);
+ TEST_1(c->call->nh = nua_handle(c->nua, c->call, TAG_END()));
+ UNREGISTER(c, c->call, c->call->nh, SIPTAG_TO(c->to),
+ NUTAG_M_DISPLAY("C"),
+ NUTAG_M_USERNAME("c"),
+ TAG_END());
+ run_c_until(ctx, -1, save_until_final_response);
+
+ TEST_1(e = c->events->head);
+ TEST_E(e->data->e_event, nua_r_unregister);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST(e->data->e_status, 401);
+ TEST(sip->sip_status->st_status, 401);
+ TEST_1(!sip->sip_contact);
+ TEST_1(!e->next);
+ free_events_in_list(ctx, c->events);
+
+ AUTHENTICATE(c, c->call, c->call->nh,
+ NUTAG_AUTH("Digest:\"test-proxy\":charlie:secret"), TAG_END());
+ run_c_until(ctx, -1, save_until_final_response);
+
+ TEST_1(e = c->events->head);
+ TEST_E(e->data->e_event, nua_r_unregister);
+ TEST(e->data->e_status, 200);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(!sip->sip_contact);
+ TEST_1(!e->next);
+ free_events_in_list(ctx, c->events);
+ nua_handle_destroy(c->call->nh), c->call->nh = NULL;
+
+ if (c->reg->nh) {
+ UNREGISTER(c, NULL, c->reg->nh, TAG_END());
+ run_c_until(ctx, -1, save_until_final_response);
+ TEST_1(e = c->events->head);
+ TEST_E(e->data->e_event, nua_r_unregister);
+ TEST(e->data->e_status, 200);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(!sip->sip_contact);
+ TEST_1(!e->next);
+ free_events_in_list(ctx, c->events);
+ nua_handle_destroy(c->reg->nh), c->reg->nh = NULL;
+ }
+
+ if (print_headings)
+ printf("TEST NUA-13.3: PASSED\n");
+
+ END();
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_session_timer.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_session_timer.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,319 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_nua_re_invite.c
+ * @brief NUA-8 tests: Session timer, UPDATE
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti Mela at nokia.com>
+ *
+ * @date Created: Wed Aug 17 12:12:12 EEST 2005 ppessi
+ */
+
+#include "config.h"
+
+#include "test_nua.h"
+#include <sofia-sip/su_tag_class.h>
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+#define __func__ "test_call_hold"
+#endif
+
+/* ======================================================================== */
+
+int test_session_timer(struct context *ctx)
+{
+ BEGIN();
+
+ struct endpoint *a = &ctx->a, *b = &ctx->b;
+ struct call *a_call = a->call, *b_call = b->call;
+ struct event *e;
+ sip_t const *sip;
+
+/* Session timer test:
+
+ A P B
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ | |
+ |<----180 Ringing----|
+ | |
+ |<------200 OK-------|
+ |------------------->|
+ | |
+ | |
+ |--INVITE->| |
+ |<--422----| |
+ |---ACK--->| |
+ | |
+ |-------INVITE------>|
+ |<-------422---------|
+ |--------ACK-------->|
+ | |
+ |-------INVITE------>|
+ |<----100 Trying-----|
+ | |
+ |<----180 Ringing----|
+ | |
+ |<------200 OK-------|
+ |--------ACK-------->|
+ | |
+ |<-------BYE---------|
+ |-------200 OK-------|
+ | |
+
+*/
+
+ if (print_headings)
+ printf("TEST NUA-8.1.1: Session timers\n");
+
+ a_call->sdp = "m=audio 5008 RTP/AVP 8";
+ b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
+
+ nua_set_params(ctx->b.nua,
+ NUTAG_SESSION_REFRESHER(nua_any_refresher),
+ TAG_END());
+
+ run_b_until(ctx, nua_r_set_params, until_final_response);
+
+ TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+ INVITE(a, a_call, a_call->nh,
+ TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+ SOATAG_USER_SDP_STR(a_call->sdp),
+ SIPTAG_SUPPORTED_STR("100rel"),
+ TAG_END());
+
+ run_ab_until(ctx, -1, until_ready, -1, accept_call);
+
+ /* Client transitions:
+ INIT -(C1)-> CALLING: nua_i_state
+ CALLING -(C2)-> PROCEEDING: nua_r_invite, nua_i_state
+ PROCEEDING -(C3+C4)-> READY: nua_r_invite, nua_i_state
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+ TEST_1(is_offer_sent(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 180);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 200);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(sip->sip_session_expires);
+ TEST_S(sip->sip_session_expires->x_refresher, "uas");
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+ TEST_1(is_answer_recv(e->data->e_tags));
+ TEST_1(!e->next);
+ free_events_in_list(ctx, a->events);
+
+ /*
+ Server transitions:
+ INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
+ RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state
+ EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state
+ COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+ TEST(e->data->e_status, 100);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+ TEST_1(is_offer_recv(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+ TEST_1(is_answer_sent(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+ TEST_1(!e->next);
+ free_events_in_list(ctx, b->events);
+
+ if (print_headings)
+ printf("TEST NUA-8.1.1: PASSED\n");
+
+ if (print_headings)
+ printf("TEST NUA-8.1.2: Session timers negotiation\n");
+
+ nua_set_hparams(b_call->nh,
+ NUTAG_AUTOANSWER(0),
+ NUTAG_MIN_SE(120),
+ TAG_END());
+
+ run_b_until(ctx, nua_r_set_params, until_final_response);
+
+
+ INVITE(a, a_call, a_call->nh,
+ TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+ SOATAG_USER_SDP_STR(a_call->sdp),
+ SIPTAG_SUPPORTED_STR("100rel, timer"),
+ NUTAG_SESSION_TIMER(15),
+ NUTAG_MIN_SE(5),
+ TAG_END());
+
+ run_ab_until(ctx, -1, until_ready, -1, accept_call);
+
+ /* Client transitions:
+ INIT -(C1)-> CALLING: nua_invite(), nua_i_state
+ CALLING -(C6a)-> (TERMINATED/INIT): nua_r_invite
+ when testing with proxy, second 422 when call reaches UAS:
+ (INIT) -(C1)-> CALLING: nua_i_state
+ CALLING -(C6a)-> (TERMINATED/INIT): nua_r_invite
+ (INIT) -(C1)-> CALLING: nua_i_state
+ CALLING -(C2)-> PROCEEDING: nua_r_invite, nua_i_state
+ PROCEEDING -(C3+C4)-> READY: nua_r_invite, nua_i_state
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+ TEST_1(is_offer_sent(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 100);
+ TEST(sip_object(e->data->e_msg)->sip_status->st_status, 422);
+
+ if (ctx->proxy_tests) {
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+ TEST_1(is_offer_sent(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 100);
+ TEST(sip_object(e->data->e_msg)->sip_status->st_status, 422);
+ }
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
+ TEST_1(is_offer_sent(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 180);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+ TEST(e->data->e_status, 200);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(sip->sip_session_expires);
+ TEST(sip->sip_session_expires->x_delta, 120);
+ TEST_S(sip->sip_session_expires->x_refresher, "uac");
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+ TEST_1(is_answer_recv(e->data->e_tags));
+ TEST_1(!e->next);
+ free_events_in_list(ctx, a->events);
+
+ /*
+ Server transitions:
+ INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
+ RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state
+ EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state
+ COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+ TEST(e->data->e_status, 100);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(sip->sip_session_expires);
+ TEST_1(!sip->sip_session_expires->x_refresher);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
+ TEST_1(is_offer_recv(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
+ TEST_1(is_answer_sent(e->data->e_tags));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+ TEST_1(!e->next);
+ free_events_in_list(ctx, b->events);
+
+ if (print_headings)
+ printf("TEST NUA-8.1: PASSED\n");
+
+ if (print_headings)
+ printf("TEST NUA-8.2: use UPDATE\n");
+
+ UPDATE(b, b_call, b_call->nh, TAG_END());
+ run_ab_until(ctx, -1, until_ready, -1, until_ready);
+
+ /* Events from B (who sent UPDATE) */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+ TEST_1(is_offer_sent(e->data->e_tags));
+ if (!e->next)
+ run_b_until(ctx, -1, until_ready);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_update);
+ TEST(e->data->e_status, 200);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(sip->sip_session_expires);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+ TEST_1(is_answer_recv(e->data->e_tags));
+ TEST_1(!e->next);
+ free_events_in_list(ctx, b->events);
+
+ /* Events from A (who received UPDATE) */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_update);
+ TEST(e->data->e_status, 200);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(sip->sip_session_expires);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+ TEST_1(is_offer_recv(e->data->e_tags));
+ TEST_1(is_answer_sent(e->data->e_tags));
+ TEST_1(!e->next);
+ free_events_in_list(ctx, a->events);
+
+ BYE(b, b_call, b_call->nh, TAG_END());
+ run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
+
+ /* B transitions:
+ READY --(T2)--> TERMINATING: nua_bye()
+ TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_r_bye);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+ free_events_in_list(ctx, b->events);
+
+ /* A: READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_bye);
+ TEST(e->data->e_status, 200);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+ TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+ TEST_1(!e->next);
+ free_events_in_list(ctx, a->events);
+
+ nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+ nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+ if (print_headings)
+ printf("TEST NUA-8.2: PASSED\n");
+
+ END();
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_simple.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_simple.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,632 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_nua_simple.c
+ * @brief NUA-11: Test SIMPLE methods: MESSAGE, PUBLISH and SUBSCRIBE/NOTIFY.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti Mela at nokia.com>
+ *
+ * @date Created: Wed Aug 17 12:12:12 EEST 2005 ppessi
+ */
+
+#include "config.h"
+
+#include "test_nua.h"
+#include <sofia-sip/su_tag_class.h>
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+#define __func__ "test_simple"
+#endif
+
+int test_message(struct context *ctx)
+{
+ BEGIN();
+
+ struct endpoint *a = &ctx->a, *b = &ctx->b;
+ struct call *a_call = a->call, *b_call = b->call;
+ struct event *e;
+ sip_t const *sip;
+ url_t url[1];
+
+/* Message test
+
+ A B
+ |-------MESSAGE----->|
+ |<-------200---------|
+ | |
+
+*/
+ if (print_headings)
+ printf("TEST NUA-11.1: MESSAGE\n");
+
+ if (ctx->proxy_tests)
+ *url = *b->to->a_url;
+ else
+ *url = *b->contact->m_url;
+
+ /* Test that query part is included in request sent to B */
+ url->url_headers = "organization=United%20Testers";
+
+ TEST_1(a_call->nh = nua_handle(a->nua, a_call, TAG_END()));
+
+ MESSAGE(a, a_call, a_call->nh,
+ NUTAG_URL(url),
+ SIPTAG_SUBJECT_STR("NUA-11.1"),
+ SIPTAG_CONTENT_TYPE_STR("text/plain"),
+ SIPTAG_PAYLOAD_STR("Hello hellO!\n"),
+ TAG_END());
+
+ run_ab_until(ctx, -1, save_until_final_response, -1, save_until_received);
+
+ /* Client events:
+ nua_message(), nua_r_message
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_message);
+ TEST(e->data->e_status, 200);
+ TEST_1(!e->next);
+
+ /*
+ Server events:
+ nua_i_message
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_message);
+ TEST(e->data->e_status, 200);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(sip->sip_subject && sip->sip_subject->g_string);
+ TEST_S(sip->sip_subject->g_string, "NUA-11.1");
+ TEST_1(sip->sip_organization);
+ TEST_S(sip->sip_organization->g_string, "United Testers");
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, a->events);
+ nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+ free_events_in_list(ctx, b->events);
+ nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+ if (print_headings)
+ printf("TEST NUA-11.1: PASSED\n");
+
+
+/* Message test
+
+ A
+ |-------MESSAGE--\
+ |<---------------/
+ |--------200-----\
+ |<---------------/
+ |
+
+*/
+ if (print_headings)
+ printf("TEST NUA-11.2: MESSAGE to myself\n");
+
+ TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(a->to), TAG_END()));
+
+ MESSAGE(a, a_call, a_call->nh,
+ /* We cannot reach us by using our contact! */
+ NUTAG_URL(!ctx->p && !ctx->proxy_tests ? a->contact->m_url : NULL),
+ SIPTAG_SUBJECT_STR("NUA-11.1b"),
+ SIPTAG_CONTENT_TYPE_STR("text/plain"),
+ SIPTAG_PAYLOAD_STR("Hello hellO!\n"),
+ TAG_END());
+
+ run_a_until(ctx, -1, save_until_final_response);
+
+ /* Events:
+ nua_message(), nua_i_message, nua_r_message
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_message);
+ TEST(e->data->e_status, 200);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(sip->sip_subject && sip->sip_subject->g_string);
+ TEST_S(sip->sip_subject->g_string, "NUA-11.1b");
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_message);
+ TEST(e->data->e_status, 200);
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, a->events);
+ nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+ if (print_headings)
+ printf("TEST NUA-11.2: PASSED\n");
+
+ END();
+}
+
+int respond_with_etag(CONDITION_PARAMS)
+{
+ msg_t *with = nua_current_request(nua);
+
+ if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+ return 0;
+
+ save_event_in_list(ctx, event, ep, call);
+
+ switch (event) {
+ char const *etag;
+ case nua_i_publish:
+ etag = sip->sip_if_match ? sip->sip_if_match->g_value : NULL;
+ if (sip->sip_if_match && (etag == NULL || strcmp(etag, "tagtag"))) {
+ RESPOND(ep, call, nh, SIP_412_PRECONDITION_FAILED,
+ NUTAG_WITH(with),
+ TAG_END());
+ }
+ else {
+ RESPOND(ep, call, nh, SIP_200_OK,
+ NUTAG_WITH(with),
+ SIPTAG_ETAG_STR("tagtag"),
+ SIPTAG_EXPIRES_STR("3600"),
+ SIPTAG_EXPIRES(sip->sip_expires), /* overrides 3600 */
+ TAG_END());
+ }
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+int test_publish(struct context *ctx)
+{
+ BEGIN();
+
+ struct endpoint *a = &ctx->a, *b = &ctx->b;
+ struct call *a_call = a->call, *b_call = b->call;
+ struct event *e;
+ sip_t const *sip;
+
+
+/* PUBLISH test
+
+ A B
+ |-------PUBLISH----->|
+ |<-------405---------| (method not allowed by default)
+ | |
+ |-------PUBLISH----->|
+ |<-------501---------| (no events allowed)
+ | |
+ |-------PUBLISH----->|
+ |<-------489---------| (event not allowed by default)
+ | |
+ |-------PUBLISH----->|
+ |<-------200---------| (event allowed, responded)
+ | |
+ |-----un-PUBLISH---->|
+ |<-------200---------| (event allowed, responded)
+
+*/
+ if (print_headings)
+ printf("TEST NUA-11.3: PUBLISH\n");
+
+ TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+ PUBLISH(a, a_call, a_call->nh,
+ TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+ SIPTAG_EVENT_STR("presence"),
+ SIPTAG_CONTENT_TYPE_STR("text/urllist"),
+ SIPTAG_PAYLOAD_STR("sip:example.com\n"),
+ TAG_END());
+
+ run_ab_until(ctx, -1, save_until_final_response, -1, NULL);
+
+ /* Client events:
+ nua_publish(), nua_r_publish
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_publish);
+ TEST(e->data->e_status, 405);
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, a->events);
+ nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+ free_events_in_list(ctx, b->events);
+ nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+ nua_set_params(b->nua, NUTAG_ALLOW("PUBLISH"), TAG_END());
+
+ run_b_until(ctx, nua_r_set_params, until_final_response);
+
+ TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+ PUBLISH(a, a_call, a_call->nh,
+ TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+ SIPTAG_EVENT_STR("presence"),
+ SIPTAG_CONTENT_TYPE_STR("text/urllist"),
+ SIPTAG_PAYLOAD_STR("sip:example.com\n"),
+ TAG_END());
+
+ run_a_until(ctx, -1, save_until_final_response);
+
+ /* Client events:
+ nua_publish(), nua_r_publish
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_publish);
+ TEST(e->data->e_status, 501); /* Not implemented */
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, a->events);
+ nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+ /* Allow presence event */
+
+ nua_set_params(b->nua, NUTAG_ALLOW_EVENTS("presence"), TAG_END());
+
+ run_b_until(ctx, nua_r_set_params, until_final_response);
+
+ TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+ PUBLISH(a, a_call, a_call->nh,
+ TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+ SIPTAG_EVENT_STR("reg"),
+ SIPTAG_CONTENT_TYPE_STR("text/urllist"),
+ SIPTAG_PAYLOAD_STR("sip:example.com\n"),
+ TAG_END());
+
+ run_a_until(ctx, -1, save_until_final_response);
+
+ /* Client events:
+ nua_publish(), nua_r_publish
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_publish);
+ TEST(e->data->e_status, 489); /* Bad Event */
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, a->events);
+ nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+ TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+ PUBLISH(a, a_call, a_call->nh,
+ TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+ SIPTAG_EVENT_STR("presence"),
+ SIPTAG_CONTENT_TYPE_STR("text/urllist"),
+ SIPTAG_PAYLOAD_STR("sip:example.com\n"),
+ TAG_END());
+
+ run_ab_until(ctx, -1, save_until_final_response, -1, respond_with_etag);
+
+ /* Client events:
+ nua_publish(), nua_r_publish
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_publish);
+ TEST(e->data->e_status, 200);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(sip->sip_etag);
+ TEST_S(sip->sip_etag->g_string, "tagtag");
+ TEST_1(!e->next);
+
+ /*
+ Server events:
+ nua_i_publish
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_publish);
+ TEST(e->data->e_status, 100);
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, a->events);
+ free_events_in_list(ctx, b->events);
+ nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+ UNPUBLISH(a, a_call, a_call->nh, TAG_END());
+
+ run_ab_until(ctx, -1, save_until_final_response, -1, respond_with_etag);
+
+ /* Client events:
+ nua_publish(), nua_r_publish
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_unpublish);
+ TEST(e->data->e_status, 200);
+ TEST_1(!e->next);
+
+ /*
+ Server events:
+ nua_i_publish
+ */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_publish);
+ TEST(e->data->e_status, 100);
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, a->events);
+ free_events_in_list(ctx, b->events);
+
+ nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+ nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+ if (print_headings)
+ printf("TEST NUA-11.3: PASSED\n");
+ END();
+}
+
+static char const presence_open[] =
+ "<?xml version='1.0' encoding='UTF-8'?>\n"
+ "<presence xmlns='urn:ietf:params:xml:ns:cpim-pidf' \n"
+ " entity='pres:bob at example.org'>\n"
+ " <tuple id='ksac9udshce'>\n"
+ " <status><basic>open</basic></status>\n"
+ " <contact priority='1.0'>sip:bob at example.org</contact>\n"
+ " </tuple>\n"
+ "</presence>\n";
+
+static char const presence_closed[] =
+ "<?xml version='1.0' encoding='UTF-8'?>\n"
+ "<presence xmlns='urn:ietf:params:xml:ns:cpim-pidf' \n"
+ " entity='pres:bob at example.org'>\n"
+ " <tuple id='ksac9udshce'>\n"
+ " <status><basic>closed</basic></status>\n"
+ " </tuple>\n"
+ "</presence>\n";
+
+
+int accept_and_notify(CONDITION_PARAMS)
+{
+ msg_t *with = nua_current_request(nua);
+
+ if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+ return 0;
+
+ save_event_in_list(ctx, event, ep, call);
+
+ switch (event) {
+ case nua_i_subscribe:
+ if (status < 200) {
+ RESPOND(ep, call, nh, SIP_202_ACCEPTED,
+ NUTAG_WITH(with),
+ SIPTAG_EXPIRES_STR("360"),
+ TAG_END());
+ NOTIFY(ep, call, nh,
+ SIPTAG_EVENT(sip->sip_event),
+ SIPTAG_CONTENT_TYPE_STR("application/pidf+xml"),
+ SIPTAG_PAYLOAD_STR(presence_closed),
+ NUTAG_SUBSTATE(nua_substate_pending),
+ TAG_END());
+ }
+ return 0;
+
+ case nua_r_notify:
+ return status >= 200;
+
+ default:
+ return 0;
+ }
+}
+
+extern int save_until_notified_and_responded(CONDITION_PARAMS);
+extern int save_until_notified(CONDITION_PARAMS);
+
+int test_subscribe_notify(struct context *ctx)
+{
+ BEGIN();
+
+ struct endpoint *a = &ctx->a, *b = &ctx->b;
+ struct call *a_call = a->call, *b_call = b->call;
+ struct event *e;
+ sip_t const *sip;
+ tagi_t const *n_tags, *r_tags;
+
+ if (print_headings)
+ printf("TEST NUA-11.4: establishing subscription without notifier\n");
+
+ TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+ SUBSCRIBE(a, a_call, a_call->nh, NUTAG_URL(b->contact->m_url),
+ SIPTAG_EVENT_STR("presence"),
+ SIPTAG_ACCEPT_STR("application/xpidf, application/pidf+xml"),
+ TAG_END());
+
+ run_ab_until(ctx, -1, save_until_notified_and_responded,
+ -1, accept_and_notify);
+
+ /* Client events:
+ nua_subscribe(), nua_i_notify/nua_r_subscribe
+ */
+ TEST_1(e = a->events->head);
+ if (e->data->e_event == nua_i_notify) {
+ TEST_E(e->data->e_event, nua_i_notify);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ n_tags = e->data->e_tags;
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_subscribe);
+ r_tags = e->data->e_tags;
+ TEST_1(tl_find(r_tags, nutag_substate));
+ TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_pending);
+ }
+ else {
+ TEST_E(e->data->e_event, nua_r_subscribe);
+ TEST(e->data->e_status, 202);
+ r_tags = e->data->e_tags;
+ TEST_1(tl_find(r_tags, nutag_substate));
+ TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_embryonic);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_notify);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ n_tags = e->data->e_tags;
+ }
+ TEST_1(sip->sip_event); TEST_S(sip->sip_event->o_type, "presence");
+ TEST_1(sip->sip_content_type);
+ TEST_S(sip->sip_content_type->c_type, "application/pidf+xml");
+ TEST_1(sip->sip_subscription_state);
+ TEST_S(sip->sip_subscription_state->ss_substate, "pending");
+ TEST_1(sip->sip_subscription_state->ss_expires);
+ TEST_1(tl_find(n_tags, nutag_substate));
+ TEST(tl_find(n_tags, nutag_substate)->t_value, nua_substate_pending);
+ TEST_1(!e->next);
+ free_events_in_list(ctx, a->events);
+
+ /* Server events: nua_i_subscribe, nua_r_notify */
+ TEST_1(e = b->events->head);
+ TEST_E(e->data->e_event, nua_i_subscribe);
+ TEST_E(e->data->e_status, 100);
+ TEST_1(sip = sip_object(e->data->e_msg));
+
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_notify);
+ r_tags = e->data->e_tags;
+ TEST_1(tl_find(r_tags, nutag_substate));
+ TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_pending);
+
+ free_events_in_list(ctx, b->events);
+
+ if (print_headings)
+ printf("TEST NUA-11.4: PASSED\n");
+
+ /* ---------------------------------------------------------------------- */
+
+/* NOTIFY with updated content
+
+ A B
+ | |
+ |<------NOTIFY-------|
+ |-------200 OK------>|
+ | |
+*/
+ if (print_headings)
+ printf("TEST NUA-11.5: send NOTIFY\n");
+
+ /* Update presence data */
+
+ NOTIFY(b, b_call, b_call->nh,
+ NUTAG_SUBSTATE(nua_substate_active),
+ SIPTAG_EVENT_STR("presence"),
+ SIPTAG_CONTENT_TYPE_STR("application/pidf+xml"),
+ SIPTAG_PAYLOAD_STR(presence_open),
+ TAG_END());
+
+ run_ab_until(ctx, -1, save_until_notified,
+ -1, save_until_final_response);
+
+ /* subscriber events:
+ nua_i_notify
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_notify);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(sip->sip_event); TEST_S(sip->sip_event->o_type, "presence");
+ TEST_1(sip->sip_content_type);
+ TEST_S(sip->sip_content_type->c_type, "application/pidf+xml");
+ TEST_1(sip->sip_subscription_state);
+ TEST_S(sip->sip_subscription_state->ss_substate, "active");
+ TEST_1(sip->sip_subscription_state->ss_expires);
+ n_tags = e->data->e_tags;
+ TEST_1(tl_find(n_tags, nutag_substate));
+ TEST(tl_find(n_tags, nutag_substate)->t_value, nua_substate_active);
+ TEST_1(!e->next);
+ free_events_in_list(ctx, a->events);
+
+ /* Notifier events: nua_r_notify */
+ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_r_notify);
+ r_tags = e->data->e_tags;
+ TEST_1(tl_find(r_tags, nutag_substate));
+ TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_active);
+
+ free_events_in_list(ctx, b->events);
+
+ if (print_headings)
+ printf("TEST NUA-11.5: PASSED\n");
+
+ /* ---------------------------------------------------------------------- */
+
+/* un-SUBSCRIBE
+
+ A B
+ | |
+ |------SUBSCRIBE---->|
+ |<--------202--------|
+ |<------NOTIFY-------|
+ |-------200 OK------>|
+ | |
+*/
+ if (print_headings)
+ printf("TEST NUA-11.6: un-SUBSCRIBE\n");
+
+ UNSUBSCRIBE(a, a_call, a_call->nh, TAG_END());
+
+ run_ab_until(ctx, -1, save_until_final_response,
+ -1, save_until_final_response);
+
+ /* Client events:
+ nua_unsubscribe(), nua_i_notify/nua_r_unsubscribe
+ */
+ TEST_1(e = a->events->head);
+ if (e->data->e_event == nua_i_notify) {
+ TEST_E(e->data->e_event, nua_i_notify);
+ n_tags = e->data->e_tags;
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(sip->sip_event);
+ TEST_1(sip->sip_subscription_state);
+ TEST_S(sip->sip_subscription_state->ss_substate, "terminated");
+ TEST_1(!sip->sip_subscription_state->ss_expires);
+ TEST_1(tl_find(n_tags, nutag_substate));
+ TEST(tl_find(n_tags, nutag_substate)->t_value, nua_substate_terminated);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_unsubscribe);
+ TEST(e->data->e_status, 200);
+ r_tags = e->data->e_tags;
+ TEST_1(tl_find(r_tags, nutag_substate));
+ TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_terminated);
+ }
+ else {
+ TEST_E(e->data->e_event, nua_r_unsubscribe);
+ TEST(e->data->e_status, 200);
+ r_tags = e->data->e_tags;
+ TEST_1(tl_find(r_tags, nutag_substate));
+ TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_terminated);
+ }
+ TEST_1(!e->next);
+ free_events_in_list(ctx, a->events);
+
+ /* Notifier events: nua_r_notify */
+ TEST_1(e = b->events->head);
+ TEST_E(e->data->e_event, nua_i_subscribe);
+ TEST(e->data->e_status, 200);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(tl_find(e->data->e_tags, nutag_substate));
+ TEST(tl_find(e->data->e_tags, nutag_substate)->t_value,
+ nua_substate_terminated);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_notify);
+ TEST_1(e->data->e_status >= 200);
+ r_tags = e->data->e_tags;
+ TEST_1(tl_find(r_tags, nutag_substate));
+ TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_terminated);
+
+ free_events_in_list(ctx, b->events);
+
+ nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+ nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+ if (print_headings)
+ printf("TEST NUA-11.6: PASSED\n");
+
+ END();
+}
+
+/* ======================================================================== */
+/* Test simple methods: MESSAGE, PUBLISH, SUBSCRIBE/NOTIFY */
+
+int test_simple(struct context *ctx)
+{
+ return
+ test_message(ctx)
+ || test_publish(ctx)
+ || test_subscribe_notify(ctx)
+ ;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_sip_events.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_sip_events.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,523 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_sip_events.c
+ * @brief NUA-12 tests: SUBSCRIBE/NOTIFY.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti Mela at nokia.com>
+ *
+ * @date Created: Wed Aug 17 12:12:12 EEST 2005 ppessi
+ */
+
+#include "config.h"
+
+#include "test_nua.h"
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/nea.h>
+
+#if !HAVE_MEMMEM
+void *memmem(const void *haystack, size_t haystacklen,
+ const void *needle, size_t needlelen);
+#endif
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+#define __func__ "test_sip_events"
+#endif
+
+/* ======================================================================== */
+/* Test events methods: SUBSCRIBE/NOTIFY */
+
+/**Terminate until received notify.
+ * Save events (except nua_i_active or terminated).
+ */
+int save_until_notified(CONDITION_PARAMS)
+{
+ save_event_in_list(ctx, event, ep, call);
+ return event == nua_i_notify;
+}
+
+int save_until_notified_and_responded(CONDITION_PARAMS)
+{
+ save_event_in_list(ctx, event, ep, call);
+ if (event == nua_i_notify) ep->flags.b.bit0 = 1;
+ if (event == nua_r_subscribe || event == nua_r_unsubscribe) {
+ if (status >= 300)
+ return 1;
+ else if (status >= 200)
+ ep->flags.b.bit1 = 1;
+ }
+
+ return ep->flags.b.bit0 && ep->flags.b.bit1;
+}
+
+
+int save_until_subscription(CONDITION_PARAMS)
+{
+ save_event_in_list(ctx, event, ep, call);
+ return event == nua_i_subscription;
+}
+
+
+int test_events(struct context *ctx)
+{
+ BEGIN();
+
+ struct endpoint *a = &ctx->a, *b = &ctx->b;
+ struct call *a_call = a->call, *b_call = b->call;
+ struct event *e;
+ sip_t const *sip;
+ tagi_t const *n_tags, *r_tags;
+ url_t b_url[1];
+ nea_sub_t *sub = NULL;
+
+ char const open[] =
+ "<?xml version='1.0' encoding='UTF-8'?>\n"
+ "<presence xmlns='urn:ietf:params:xml:ns:cpim-pidf' \n"
+ " entity='pres:bob at example.org'>\n"
+ " <tuple id='ksac9udshce'>\n"
+ " <status><basic>open</basic></status>\n"
+ " <contact priority='1.0'>sip:bob at example.org</contact>\n"
+ " </tuple>\n"
+ "</presence>\n";
+
+ char const closed[] =
+ "<?xml version='1.0' encoding='UTF-8'?>\n"
+ "<presence xmlns='urn:ietf:params:xml:ns:cpim-pidf' \n"
+ " entity='pres:bob at example.org'>\n"
+ " <tuple id='ksac9udshce'>\n"
+ " <status><basic>closed</basic></status>\n"
+ " </tuple>\n"
+ "</presence>\n";
+
+
+/* SUBSCRIBE test
+
+ A B
+ |------SUBSCRIBE---->|
+ |<--------405--------|
+ | |
+
+*/
+ if (print_headings)
+ printf("TEST NUA-12.1: SUBSCRIBE without notifier\n");
+
+ nua_set_params(b->nua, SIPTAG_ALLOW_EVENTS(NULL), TAG_END());
+ run_b_until(ctx, nua_r_set_params, until_final_response);
+
+ TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+ SUBSCRIBE(a, a_call, a_call->nh, NUTAG_URL(b->contact->m_url),
+ SIPTAG_EVENT_STR("presence"),
+ TAG_END());
+
+ run_ab_until(ctx, -1, save_until_final_response,
+ -1, NULL /* XXX save_until_received */);
+
+ /* Client events:
+ nua_subscribe(), nua_r_subscribe
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_subscribe);
+ TEST(e->data->e_status, 489);
+ TEST_1(!e->next);
+
+#if 0 /* XXX */
+ /*
+ Server events:
+ nua_i_subscribe
+ */
+ TEST_1(e = b->events->head);
+ TEST_E(e->data->e_event, nua_i_subscribe);
+ TEST(e->data->e_status, 405);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(sip->sip_event);
+ TEST_S(sip->sip_event->o_type, "presence");
+ TEST_1(!e->next);
+#endif
+
+ free_events_in_list(ctx, a->events);
+ free_events_in_list(ctx, b->events);
+ nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+ if (print_headings)
+ printf("TEST NUA-12.1: PASSED\n");
+
+ /* ---------------------------------------------------------------------- */
+
+/* SUBSCRIBE test using notifier and establishing subscription
+
+ A B
+ | |
+ |------SUBSCRIBE---->|
+ |<--------202--------|
+ |<------NOTIFY-------|
+ |-------200 OK------>|
+ | |
+*/
+
+ if (print_headings)
+ printf("TEST NUA-12.2: using notifier and establishing subscription\n");
+
+ TEST_1(b_call->nh = nua_handle(b->nua, b_call, TAG_END()));
+
+ *b_url = *b->contact->m_url;
+
+ NOTIFIER(b, b_call, b_call->nh,
+ NUTAG_URL(b_url),
+ SIPTAG_EVENT_STR("presence"),
+ SIPTAG_CONTENT_TYPE_STR("application/pidf+xml"),
+ SIPTAG_PAYLOAD_STR(closed),
+ NEATAG_THROTTLE(1),
+ TAG_END());
+ run_b_until(ctx, nua_r_notifier, until_final_response);
+
+ SUBSCRIBE(a, a_call, a_call->nh, NUTAG_URL(b->contact->m_url),
+ SIPTAG_EVENT_STR("presence"),
+ SIPTAG_ACCEPT_STR("application/xpidf, application/pidf+xml"),
+ TAG_END());
+
+ run_ab_until(ctx, -1, save_until_notified_and_responded,
+ -1, NULL /* XXX save_until_received */);
+
+ /* Client events:
+ nua_subscribe(), nua_i_notify/nua_r_subscribe
+ */
+ TEST_1(e = a->events->head);
+ if (e->data->e_event == nua_i_notify) {
+ TEST_E(e->data->e_event, nua_i_notify);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ n_tags = e->data->e_tags;
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_subscribe);
+ r_tags = e->data->e_tags;
+ TEST_1(tl_find(r_tags, nutag_substate));
+ TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_active);
+ }
+ else {
+ TEST_E(e->data->e_event, nua_r_subscribe);
+ TEST(e->data->e_status, 202);
+ r_tags = e->data->e_tags;
+ TEST_1(tl_find(r_tags, nutag_substate));
+ TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_embryonic);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_notify);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ n_tags = e->data->e_tags;
+ }
+ TEST_1(sip->sip_event); TEST_S(sip->sip_event->o_type, "presence");
+ TEST_1(sip->sip_content_type);
+ TEST_S(sip->sip_content_type->c_type, "application/pidf+xml");
+ TEST_1(sip->sip_subscription_state);
+ TEST_S(sip->sip_subscription_state->ss_substate, "active");
+ TEST_1(sip->sip_subscription_state->ss_expires);
+ TEST_1(tl_find(n_tags, nutag_substate));
+ TEST(tl_find(n_tags, nutag_substate)->t_value, nua_substate_active);
+ TEST_1(!e->next);
+ free_events_in_list(ctx, a->events);
+
+ if (print_headings)
+ printf("TEST NUA-12.2: PASSED\n");
+
+ /* ---------------------------------------------------------------------- */
+
+/* NOTIFY with updated content
+
+ A B
+ | |
+ |<------NOTIFY-------|
+ |-------200 OK------>|
+ | |
+*/
+ if (print_headings)
+ printf("TEST NUA-12.3: update notifier\n");
+
+ /* Update presence data */
+
+ NOTIFIER(b, b_call, b_call->nh,
+ SIPTAG_EVENT_STR("presence"),
+ SIPTAG_CONTENT_TYPE_STR("application/pidf+xml"),
+ SIPTAG_PAYLOAD_STR(open),
+ TAG_END());
+
+ run_ab_until(ctx, -1, save_until_notified,
+ -1, NULL /* XXX save_until_received */);
+
+ /* subscriber events:
+ nua_i_notify
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_notify);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(sip->sip_event); TEST_S(sip->sip_event->o_type, "presence");
+ TEST_1(sip->sip_content_type);
+ TEST_S(sip->sip_content_type->c_type, "application/pidf+xml");
+ TEST_1(sip->sip_subscription_state);
+ TEST_S(sip->sip_subscription_state->ss_substate, "active");
+ TEST_1(sip->sip_subscription_state->ss_expires);
+ n_tags = e->data->e_tags;
+ TEST_1(tl_find(n_tags, nutag_substate));
+ TEST(tl_find(n_tags, nutag_substate)->t_value,
+ nua_substate_active);
+ TEST_1(!e->next);
+ free_events_in_list(ctx, a->events);
+
+ if (print_headings)
+ printf("TEST NUA-12.3: PASSED\n");
+
+ /* ---------------------------------------------------------------------- */
+
+/* un-SUBSCRIBE
+
+ A B
+ | |
+ |------SUBSCRIBE---->|
+ |<--------202--------|
+ |<------NOTIFY-------|
+ |-------200 OK------>|
+ | |
+*/
+ if (print_headings)
+ printf("TEST NUA-12.5: un-SUBSCRIBE\n");
+
+ UNSUBSCRIBE(a, a_call, a_call->nh, TAG_END());
+
+ run_ab_until(ctx, -1, save_until_notified_and_responded,
+ -1, NULL /* XXX save_until_received */);
+
+ /* Client events:
+ nua_unsubscribe(), nua_i_notify/nua_r_unsubscribe
+ */
+ TEST_1(e = a->events->head);
+ if (e->data->e_event == nua_i_notify) {
+ TEST_E(e->data->e_event, nua_i_notify);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ n_tags = e->data->e_tags;
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_unsubscribe);
+ TEST_1(tl_find(e->data->e_tags, nutag_substate));
+ TEST(tl_find(e->data->e_tags, nutag_substate)->t_value,
+ nua_substate_terminated);
+ }
+ else {
+ TEST_E(e->data->e_event, nua_r_unsubscribe);
+ TEST(e->data->e_status, 202);
+ TEST_1(tl_find(e->data->e_tags, nutag_substate));
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_notify);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ n_tags = e->data->e_tags;
+ }
+ TEST_1(sip->sip_event);
+ TEST_1(sip->sip_subscription_state);
+ TEST_S(sip->sip_subscription_state->ss_substate, "terminated");
+ TEST_1(!sip->sip_subscription_state->ss_expires);
+ TEST_1(tl_find(n_tags, nutag_substate));
+ TEST(tl_find(n_tags, nutag_substate)->t_value, nua_substate_terminated);
+ TEST_1(!e->next);
+ free_events_in_list(ctx, a->events);
+
+ if (print_headings)
+ printf("TEST NUA-12.5: PASSED\n");
+
+ /* ---------------------------------------------------------------------- */
+/* 2nd SUBSCRIBE with event id
+
+ A B
+ | |
+ |------SUBSCRIBE---->|
+ |<--------202--------|
+ |<------NOTIFY-------|
+ |-------200 OK------>|
+ | |
+*/
+ /* XXX - we should do this before unsubscribing first one */
+ if (print_headings)
+ printf("TEST NUA-12.4: establishing 2nd subscription\n");
+
+ NOTIFIER(b, b_call, b_call->nh,
+ SIPTAG_EVENT_STR("presence"),
+ SIPTAG_CONTENT_TYPE_STR("application/xpidf+xml"),
+ SIPTAG_PAYLOAD_STR(open),
+ NEATAG_THROTTLE(1),
+ NUTAG_SUBSTATE(nua_substate_pending),
+ TAG_END());
+ run_b_until(ctx, nua_r_notifier, until_final_response);
+
+ NOTIFIER(b, b_call, b_call->nh,
+ SIPTAG_EVENT_STR("presence"),
+ SIPTAG_CONTENT_TYPE_STR("application/xpidf+xml"),
+ SIPTAG_PAYLOAD_STR(closed),
+ NEATAG_THROTTLE(1),
+ NEATAG_FAKE(1),
+ NUTAG_SUBSTATE(nua_substate_pending),
+ TAG_END());
+ run_b_until(ctx, nua_r_notifier, until_final_response);
+
+ SUBSCRIBE(a, a_call, a_call->nh, NUTAG_URL(b->contact->m_url),
+ SIPTAG_EVENT_STR("presence;id=1"),
+ SIPTAG_ACCEPT_STR("application/xpidf+xml"),
+ TAG_END());
+
+ run_ab_until(ctx, -1, save_until_notified_and_responded,
+ -1, save_until_subscription);
+
+ /* Client events:
+ nua_subscribe(), nua_i_notify/nua_r_subscribe
+ */
+ TEST_1(e = a->events->head);
+ if (e->data->e_event == nua_i_notify) {
+ TEST_E(e->data->e_event, nua_i_notify);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ n_tags = e->data->e_tags;
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_subscribe);
+ TEST_1(tl_find(e->data->e_tags, nutag_substate));
+ TEST(tl_find(e->data->e_tags, nutag_substate)->t_value,
+ nua_substate_pending);
+ }
+ else {
+ TEST_E(e->data->e_event, nua_r_subscribe);
+ TEST(e->data->e_status, 202);
+ TEST_1(tl_find(e->data->e_tags, nutag_substate));
+ TEST(tl_find(e->data->e_tags, nutag_substate)->t_value,
+ nua_substate_embryonic);
+ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_notify);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ n_tags = e->data->e_tags;
+ }
+ TEST_1(sip->sip_event); TEST_S(sip->sip_event->o_type, "presence");
+ TEST_S(sip->sip_event->o_id, "1");
+ TEST_1(sip->sip_content_type);
+ TEST_S(sip->sip_content_type->c_type, "application/xpidf+xml");
+ TEST_1(sip->sip_payload && sip->sip_payload->pl_data);
+ /* Check that we really got "fake" content */
+ TEST_1(memmem(sip->sip_payload->pl_data, sip->sip_payload->pl_len,
+ "<basic>closed</basic>", strlen("<basic>closed</basic>")));
+ TEST_1(sip->sip_subscription_state);
+ TEST_S(sip->sip_subscription_state->ss_substate, "pending");
+ TEST_1(sip->sip_subscription_state->ss_expires);
+ TEST_1(tl_find(n_tags, nutag_substate));
+ TEST(tl_find(n_tags, nutag_substate)->t_value,
+ nua_substate_pending);
+ TEST_1(!e->next);
+ free_events_in_list(ctx, a->events);
+
+ /*
+ Server events:
+ nua_i_subscription
+ */
+ TEST_1(e = b->events->head);
+ TEST_E(e->data->e_event, nua_i_subscription);
+ TEST(tl_gets(e->data->e_tags, NEATAG_SUB_REF(sub), TAG_END()), 1);
+ TEST_1(sub);
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, b->events);
+
+ /* Authorize user A */
+ AUTHORIZE(b, b_call, b_call->nh,
+ NUTAG_SUBSTATE(nua_substate_active),
+ NEATAG_SUB(sub),
+ NEATAG_FAKE(0),
+ TAG_END());
+
+ run_ab_until(ctx, -1, save_until_notified,
+ -1, save_until_final_response);
+
+ /* subscriber events:
+ nua_i_notify with NUTAG_SUBSTATE(nua_substate_active)
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_notify);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(sip->sip_event); TEST_S(sip->sip_event->o_type, "presence");
+ TEST_1(sip->sip_content_type);
+ TEST_S(sip->sip_content_type->c_type, "application/xpidf+xml");
+ TEST_1(sip->sip_payload && sip->sip_payload->pl_data);
+ /* Check that we really got real content */
+ TEST_1(memmem(sip->sip_payload->pl_data, sip->sip_payload->pl_len,
+ "<basic>open</basic>", strlen("<basic>open</basic>")));
+ TEST_1(sip->sip_subscription_state);
+ TEST_S(sip->sip_subscription_state->ss_substate, "active");
+ TEST_1(sip->sip_subscription_state->ss_expires);
+ n_tags = e->data->e_tags;
+ TEST_1(tl_find(n_tags, nutag_substate));
+ TEST(tl_find(n_tags, nutag_substate)->t_value, nua_substate_active);
+ TEST_1(!e->next);
+ free_events_in_list(ctx, a->events);
+
+ /*
+ Server events:
+ nua_r_authorize
+ */
+ TEST_1(e = b->events->head);
+ TEST_E(e->data->e_event, nua_r_authorize);
+ TEST_1(!e->next);
+
+ free_events_in_list(ctx, b->events);
+
+ if (print_headings)
+ printf("TEST NUA-12.4: PASSED\n");
+
+ /* ---------------------------------------------------------------------- */
+
+/* NOTIFY terminating subscription
+
+ A B
+ | |
+ |<------NOTIFY-------|
+ |-------200 OK------>|
+ | |
+*/
+
+ if (print_headings)
+ printf("TEST NUA-12.6: terminate notifier\n");
+
+ TERMINATE(b, b_call, b_call->nh, TAG_END());
+
+ run_ab_until(ctx, -1, save_until_notified, -1, until_final_response);
+
+ /* Client events:
+ nua_i_notify
+ */
+ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_notify);
+ TEST_1(sip = sip_object(e->data->e_msg));
+ TEST_1(sip->sip_event); TEST_S(sip->sip_event->o_type, "presence");
+ TEST_S(sip->sip_event->o_id, "1");
+ TEST_1(sip->sip_subscription_state);
+ TEST_S(sip->sip_subscription_state->ss_substate, "terminated");
+ TEST_1(!sip->sip_subscription_state->ss_expires);
+ n_tags = e->data->e_tags;
+ TEST_1(tl_find(n_tags, nutag_substate));
+ TEST(tl_find(n_tags, nutag_substate)->t_value, nua_substate_terminated);
+ TEST_1(!e->next);
+ free_events_in_list(ctx, a->events);
+
+ if (print_headings)
+ printf("TEST NUA-12.6: PASSED\n");
+
+ /* ---------------------------------------------------------------------- */
+
+
+ nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+ nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+ END(); /* test_events */
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/ChangeLog Thu Dec 21 01:30:28 2006
@@ -0,0 +1,55 @@
+2005-10-17 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * In sdp_rtpmap_cmp() use default value "1" for rm_param.
+
+ M ./libsofia-sip-ua/sdp/sdp.c -3 +30
+
+2005-10-03 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Fixed documentation of sdp_parsing_error() and sdp_parsing_error()
+ contradicting with implementation. Use sdp_session() and sdp_message() to
+ check for error.
+
+ M ./libsofia-sip-ua/sdp/sdp.docs -2 +8
+
+2005-10-03 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * sdp_print.c (sdp_printing_error): Fixed return
+ for success to be NULL as defined in function
+ documentation.
+
+2005-09-29 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Added SDPTAG_TYPEDEF().
+
+ M ./libsofia-sip-ua/sdp/sdp_tag.h +3
+
+ * Not including <sdp.h>.
+
+ M ./libsofia-sip-ua/sdp/sdp_tag.h -7 +12
+
+2005-09-28 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Handle mode attributes (inactive, sendonly, recvonly, sendrecv).
+
+ M ./libsofia-sip-ua/sdp/sdp.h -1 +5
+ M ./libsofia-sip-ua/sdp/sdp_parse.c -12 +44
+ M ./libsofia-sip-ua/sdp/sdp_print.c -5 +54
+
+ * Setting mode flags on config sdp, too.
+
+ M ./libsofia-sip-ua/sdp/sdp_parse.c -3 +3
+
+ * Added sdp_media_match*(), sdp_media_count*()
+
+ M ./libsofia-sip-ua/sdp/sdp.c +91
+ M ./libsofia-sip-ua/sdp/sdp.h +20
+
+ * Added sdp_list_cmp() and sdp_rtpmap_cmp().
+
+ M ./libsofia-sip-ua/sdp/sdp.c -9 +54
+ M ./libsofia-sip-ua/sdp/sdp.h +6
+
+2005-07-18 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * Initial import of the module to Sofia-SIP tree.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/Doxyfile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/Doxyfile Thu Dec 21 01:30:28 2006
@@ -0,0 +1,11 @@
+PROJECT_NAME = "sdp"
+OUTPUT_DIRECTORY = ../docs/html/sdp
+
+INPUT = sdp.docs . sofia-sip
+
+ at INCLUDE = ../docs/Doxyfile.conf
+
+TAGFILES += ../docs/su.doxytags=../su
+GENERATE_TAGFILE = ../docs/sdp.doxytags
+
+ALIASES +=
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/Makefile.am Thu Dec 21 01:30:28 2006
@@ -0,0 +1,61 @@
+#
+# Makefile.am for sdp module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+INCLUDES = -I$(srcdir)/../su -I../su
+
+# ----------------------------------------------------------------------
+# Build targets
+
+noinst_LTLIBRARIES = libsdp.la
+
+check_PROGRAMS = torture_sdp test_sdp
+
+dist_noinst_SCRIPTS = run_test_sdp
+
+TESTS = torture_sdp run_test_sdp
+
+BUILT_SOURCES = sdp_tag_ref.c
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+
+nobase_include_sofia_HEADERS = \
+ sofia-sip/sdp.h sofia-sip/sdp_tag.h
+
+libsdp_la_SOURCES = sdp.c sdp_parse.c sdp_print.c \
+ sdp_tag.c sdp_tag_ref.c
+
+COVERAGE_INPUT = $(libsdp_la_SOURCES) $(include_sofia_HEADERS)
+
+LDADD = libsdp.la \
+ ../su/libsu.la
+
+test_sdp_LDFLAGS = -static
+torture_sdp_LDFLAGS = -static
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+
+EXTRA_DIST = Doxyfile sdp.docs $(BUILT_SOURCES) \
+ tests/message-1.sdp \
+ tests/message-2.sdp \
+ tests/message-3.sdp \
+ tests/message-4.sdp \
+ tests/message-5.sdp \
+ tests/message-6.sdp \
+ tests/message-7.sdp \
+ tests/message-8.sdp \
+ tests/message-9.sdp \
+ tests/message-10.sdp
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+
+include ../sofia.am
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/Makefile.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1,722 @@
+# 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.
+
+ at SET_MAKE@
+
+#
+# Makefile.am for sdp module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+# common Makefile targets for libsofia-sip-ua modules
+# ---------------------------------------------------
+
+
+
+SOURCES = $(libsdp_la_SOURCES) test_sdp.c torture_sdp.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 = torture_sdp$(EXEEXT) test_sdp$(EXEEXT)
+DIST_COMMON = README $(dist_noinst_SCRIPTS) \
+ $(nobase_include_sofia_HEADERS) $(srcdir)/../sofia.am \
+ $(srcdir)/Makefile.am $(srcdir)/Makefile.in ChangeLog
+subdir = libsofia-sip-ua/sdp
+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 =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libsdp_la_LIBADD =
+am_libsdp_la_OBJECTS = sdp.lo sdp_parse.lo sdp_print.lo sdp_tag.lo \
+ sdp_tag_ref.lo
+libsdp_la_OBJECTS = $(am_libsdp_la_OBJECTS)
+test_sdp_SOURCES = test_sdp.c
+test_sdp_OBJECTS = test_sdp.$(OBJEXT)
+test_sdp_LDADD = $(LDADD)
+test_sdp_DEPENDENCIES = libsdp.la ../su/libsu.la
+torture_sdp_SOURCES = torture_sdp.c
+torture_sdp_OBJECTS = torture_sdp.$(OBJEXT)
+torture_sdp_LDADD = $(LDADD)
+torture_sdp_DEPENDENCIES = libsdp.la ../su/libsu.la
+SCRIPTS = $(dist_noinst_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 = $(libsdp_la_SOURCES) test_sdp.c torture_sdp.c
+DIST_SOURCES = $(libsdp_la_SOURCES) test_sdp.c torture_sdp.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|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(include_sofiadir)"
+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)/../su -I../su
+
+# ----------------------------------------------------------------------
+# Build targets
+noinst_LTLIBRARIES = libsdp.la
+dist_noinst_SCRIPTS = run_test_sdp
+TESTS = torture_sdp run_test_sdp
+BUILT_SOURCES = sdp_tag_ref.c
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+nobase_include_sofia_HEADERS = \
+ sofia-sip/sdp.h sofia-sip/sdp_tag.h
+
+libsdp_la_SOURCES = sdp.c sdp_parse.c sdp_print.c \
+ sdp_tag.c sdp_tag_ref.c
+
+COVERAGE_INPUT = $(libsdp_la_SOURCES) $(include_sofia_HEADERS)
+LDADD = libsdp.la \
+ ../su/libsu.la
+
+test_sdp_LDFLAGS = -static
+torture_sdp_LDFLAGS = -static
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+EXTRA_DIST = Doxyfile sdp.docs $(BUILT_SOURCES) \
+ tests/message-1.sdp \
+ tests/message-2.sdp \
+ tests/message-3.sdp \
+ tests/message-4.sdp \
+ tests/message-5.sdp \
+ tests/message-6.sdp \
+ tests/message-7.sdp \
+ tests/message-8.sdp \
+ tests/message-9.sdp \
+ tests/message-10.sdp
+
+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
+
+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/sdp/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu libsofia-sip-ua/sdp/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-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
+libsdp.la: $(libsdp_la_OBJECTS) $(libsdp_la_DEPENDENCIES)
+ $(LINK) $(libsdp_la_LDFLAGS) $(libsdp_la_OBJECTS) $(libsdp_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
+test_sdp$(EXEEXT): $(test_sdp_OBJECTS) $(test_sdp_DEPENDENCIES)
+ @rm -f test_sdp$(EXEEXT)
+ $(LINK) $(test_sdp_LDFLAGS) $(test_sdp_OBJECTS) $(test_sdp_LDADD) $(LIBS)
+torture_sdp$(EXEEXT): $(torture_sdp_OBJECTS) $(torture_sdp_DEPENDENCIES)
+ @rm -f torture_sdp$(EXEEXT)
+ $(LINK) $(torture_sdp_LDFLAGS) $(torture_sdp_OBJECTS) $(torture_sdp_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sdp.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sdp_parse.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sdp_print.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sdp_tag.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sdp_tag_ref.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_sdp.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/torture_sdp.Po at am__quote@
+
+.c.o:
+ at am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+ at am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ at am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at 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 $(distdir)/tests
+ @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 $(LTLIBRARIES) $(SCRIPTS) $(HEADERS)
+installdirs:
+ for dir in "$(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-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-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-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-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-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-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) $<
+
+ at ENABLE_COVERAGE_TRUE@coverage:
+ at 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)
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+# 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:
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/README
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/README Thu Dec 21 01:30:28 2006
@@ -0,0 +1,11 @@
+SDP Parser and Printer
+======================
+
+ This directory contains SDP parser and printer code. Parser takes an
+ message and returns a corresponding C structure. Printer takes a C
+ structure and returns a SDP message.
+
+ There is an incomplete documentation in sdp.html on usage of
+ parser and printer.
+
+ Please refer to RFC 2327 for further information.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/errata
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/errata Thu Dec 21 01:30:28 2006
@@ -0,0 +1,14 @@
+RFC 2327 omissions and errors:
+
+* "z=" omitted from zone-adjustments
+
+* protocol on media-field is restricted to alpha-numeric,
+ but example (RTP/AVP!) contains also "/"
+
+* bwtype is restricted to alpha-numeric, but the RFC text discusses
+ extensions like b=x-y:100
+
+* att-field is restricted to alpha-numeric, but the RFC text discusses
+ extensions like a=x-nokia-foo
+
+* The BNF defintions "key-data" and "safe" are incomplete.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/rfc2327.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/rfc2327.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,2355 @@
+
+
+
+
+
+
+Network Working Group M. Handley
+Request for Comments: 2327 V. Jacobson
+Category: Standards Track ISI/LBNL
+ April 1998
+
+
+ SDP: Session Description Protocol
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (1998). All Rights Reserved.
+
+Abstract
+
+ This document defines the Session Description Protocol, SDP. SDP is
+ intended for describing multimedia sessions for the purposes of
+ session announcement, session invitation, and other forms of
+ multimedia session initiation.
+
+ This document is a product of the Multiparty Multimedia Session
+ Control (MMUSIC) working group of the Internet Engineering Task
+ Force. Comments are solicited and should be addressed to the working
+ group's mailing list at confctrl at isi.edu and/or the authors.
+
+1. Introduction
+
+ On the Internet multicast backbone (Mbone), a session directory tool
+ is used to advertise multimedia conferences and communicate the
+ conference addresses and conference tool-specific information
+ necessary for participation. This document defines a session
+ description protocol for this purpose, and for general real-time
+ multimedia session description purposes. This memo does not describe
+ multicast address allocation or the distribution of SDP messages in
+ detail. These are described in accompanying memos. SDP is not
+ intended for negotiation of media encodings.
+
+
+
+
+
+
+
+
+Handley & Jacobson Standards Track [Page 1]
+
+RFC 2327 SDP April 1998
+
+
+2. Background
+
+ The Mbone is the part of the internet that supports IP multicast, and
+ thus permits efficient many-to-many communication. It is used
+ extensively for multimedia conferencing. Such conferences usually
+ have the property that tight coordination of conference membership is
+ not necessary; to receive a conference, a user at an Mbone site only
+ has to know the conference's multicast group address and the UDP
+ ports for the conference data streams.
+
+ Session directories assist the advertisement of conference sessions
+ and communicate the relevant conference setup information to
+ prospective participants. SDP is designed to convey such information
+ to recipients. SDP is purely a format for session description - it
+ does not incorporate a transport protocol, and is intended to use
+ different transport protocols as appropriate including the Session
+ Announcement Protocol [4], Session Initiation Protocol [11], Real-
+ Time Streaming Protocol [12], electronic mail using the MIME
+ extensions, and the Hypertext Transport Protocol.
+
+ SDP is intended to be general purpose so that it can be used for a
+ wider range of network environments and applications than just
+ multicast session directories. However, it is not intended to
+ support negotiation of session content or media encodings - this is
+ viewed as outside the scope of session description.
+
+3. Glossary of Terms
+
+ The following terms are used in this document, and have specific
+ meaning within the context of this document.
+
+ Conference
+ A multimedia conference is a set of two or more communicating users
+ along with the software they are using to communicate.
+
+ Session
+ A multimedia session is a set of multimedia senders and receivers
+ and the data streams flowing from senders to receivers. A
+ multimedia conference is an example of a multimedia session.
+
+ Session Advertisement
+ See session announcement.
+
+ Session Announcement
+ A session announcement is a mechanism by which a session
+ description is conveyed to users in a proactive fashion, i.e., the
+ session description was not explicitly requested by the user.
+
+
+
+
+Handley & Jacobson Standards Track [Page 2]
+
+RFC 2327 SDP April 1998
+
+
+ Session Description
+ A well defined format for conveying sufficient information to
+ discover and participate in a multimedia session.
+
+3.1. Terminology
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+ document are to be interpreted as described in RFC 2119.
+
+4. SDP Usage
+
+4.1. Multicast Announcements
+
+ SDP is a session description protocol for multimedia sessions. A
+ common mode of usage is for a client to announce a conference session
+ by periodically multicasting an announcement packet to a well known
+ multicast address and port using the Session Announcement Protocol
+ (SAP).
+
+ SAP packets are UDP packets with the following format:
+
+ |--------------------|
+ | SAP header |
+ |--------------------|
+ | text payload |
+ |//////////
+
+
+ The header is the Session Announcement Protocol header. SAP is
+ described in more detail in a companion memo [4]
+
+ The text payload is an SDP session description, as described in this
+ memo. The text payload should be no greater than 1 Kbyte in length.
+ If announced by SAP, only one session announcement is permitted in a
+ single packet.
+
+4.2. Email and WWW Announcements
+
+ Alternative means of conveying session descriptions include
+ electronic mail and the World Wide Web. For both email and WWW
+ distribution, the use of the MIME content type "application/sdp"
+ should be used. This enables the automatic launching of applications
+ for participation in the session from the WWW client or mail reader
+ in a standard manner.
+
+
+
+
+
+
+Handley & Jacobson Standards Track [Page 3]
+
+RFC 2327 SDP April 1998
+
+
+ Note that announcements of multicast sessions made only via email or
+ the World Wide Web (WWW) do not have the property that the receiver
+ of a session announcement can necessarily receive the session because
+ the multicast sessions may be restricted in scope, and access to the
+ WWW server or reception of email is possible outside this scope. SAP
+ announcements do not suffer from this mismatch.
+
+5. Requirements and Recommendations
+
+ The purpose of SDP is to convey information about media streams in
+ multimedia sessions to allow the recipients of a session description
+ to participate in the session. SDP is primarily intended for use in
+ an internetwork, although it is sufficiently general that it can
+ describe conferences in other network environments.
+
+ A multimedia session, for these purposes, is defined as a set of
+ media streams that exist for some duration of time. Media streams
+ can be many-to-many. The times during which the session is active
+ need not be continuous.
+
+ Thus far, multicast based sessions on the Internet have differed from
+ many other forms of conferencing in that anyone receiving the traffic
+ can join the session (unless the session traffic is encrypted). In
+ such an environment, SDP serves two primary purposes. It is a means
+ to communicate the existence of a session, and is a means to convey
+ sufficient information to enable joining and participating in the
+ session. In a unicast environment, only the latter purpose is likely
+ to be relevant.
+
+ Thus SDP includes:
+
+ o Session name and purpose
+
+ o Time(s) the session is active
+
+ o The media comprising the session
+
+ o Information to receive those media (addresses, ports, formats and
+ so on)
+
+ As resources necessary to participate in a session may be limited,
+ some additional information may also be desirable:
+
+ o Information about the bandwidth to be used by the conference
+
+ o Contact information for the person responsible for the session
+
+
+
+
+
+Handley & Jacobson Standards Track [Page 4]
+
+RFC 2327 SDP April 1998
+
+
+ In general, SDP must convey sufficient information to be able to join
+ a session (with the possible exception of encryption keys) and to
+ announce the resources to be used to non-participants that may need
+ to know.
+
+5.1. Media Information
+
+ SDP includes:
+
+ o The type of media (video, audio, etc)
+
+ o The transport protocol (RTP/UDP/IP, H.320, etc)
+
+ o The format of the media (H.261 video, MPEG video, etc)
+
+ For an IP multicast session, the following are also conveyed:
+
+ o Multicast address for media
+
+ o Transport Port for media
+
+ This address and port are the destination address and destination
+ port of the multicast stream, whether being sent, received, or both.
+
+ For an IP unicast session, the following are conveyed:
+
+ o Remote address for media
+
+ o Transport port for contact address
+
+ The semantics of this address and port depend on the media and
+ transport protocol defined. By default, this is the remote address
+ and remote port to which data is sent, and the remote address and
+ local port on which to receive data. However, some media may define
+ to use these to establish a control channel for the actual media
+ flow.
+
+5.2. Timing Information
+
+ Sessions may either be bounded or unbounded in time. Whether or not
+ they are bounded, they may be only active at specific times.
+
+ SDP can convey:
+
+ o An arbitrary list of start and stop times bounding the session
+
+ o For each bound, repeat times such as "every Wednesday at 10am for
+ one hour"
+
+
+
+Handley & Jacobson Standards Track [Page 5]
+
+RFC 2327 SDP April 1998
+
+
+ This timing information is globally consistent, irrespective of local
+ time zone or daylight saving time.
+
+5.3. Private Sessions
+
+ It is possible to create both public sessions and private sessions.
+ Private sessions will typically be conveyed by encrypting the session
+ description to distribute it. The details of how encryption is
+ performed are dependent on the mechanism used to convey SDP - see [4]
+ for how this is done for session announcements.
+
+ If a session announcement is private it is possible to use that
+ private announcement to convey encryption keys necessary to decode
+ each of the media in a conference, including enough information to
+ know which encryption scheme is used for each media.
+
+5.4. Obtaining Further Information about a Session
+
+ A session description should convey enough information to decide
+ whether or not to participate in a session. SDP may include
+ additional pointers in the form of Universal Resources Identifiers
+ (URIs) for more information about the session.
+
+5.5. Categorisation
+
+ When many session descriptions are being distributed by SAP or any
+ other advertisement mechanism, it may be desirable to filter
+ announcements that are of interest from those that are not. SDP
+ supports a categorisation mechanism for sessions that is capable of
+ being automated.
+
+5.6. Internationalization
+
+ The SDP specification recommends the use of the ISO 10646 character
+ sets in the UTF-8 encoding (RFC 2044) to allow many different
+ languages to be represented. However, to assist in compact
+ representations, SDP also allows other character sets such as ISO
+ 8859-1 to be used when desired. Internationalization only applies to
+ free-text fields (session name and background information), and not
+ to SDP as a whole.
+
+6. SDP Specification
+
+ SDP session descriptions are entirely textual using the ISO 10646
+ character set in UTF-8 encoding. SDP field names and attributes names
+ use only the US-ASCII subset of UTF-8, but textual fields and
+ attribute values may use the full ISO 10646 character set. The
+ textual form, as opposed to a binary encoding such as ASN/1 or XDR,
+
+
+
+Handley & Jacobson Standards Track [Page 6]
+
+RFC 2327 SDP April 1998
+
+
+ was chosen to enhance portability, to enable a variety of transports
+ to be used (e.g, session description in a MIME email message) and to
+ allow flexible, text-based toolkits (e.g., Tcl/Tk ) to be used to
+ generate and to process session descriptions. However, since the
+ total bandwidth allocated to all SAP announcements is strictly
+ limited, the encoding is deliberately compact. Also, since
+ announcements may be transported via very unreliable means (e.g.,
+ email) or damaged by an intermediate caching server, the encoding was
+ designed with strict order and formatting rules so that most errors
+ would result in malformed announcements which could be detected
+ easily and discarded. This also allows rapid discarding of encrypted
+ announcements for which a receiver does not have the correct key.
+
+ An SDP session description consists of a number of lines of text of
+ the form <type>=<value> <type> is always exactly one character and is
+ case-significant. <value> is a structured text string whose format
+ depends on <type>. It also will be case-significant unless a
+ specific field defines otherwise. Whitespace is not permitted either
+ side of the `=' sign. In general <value> is either a number of fields
+ delimited by a single space character or a free format string.
+
+ A session description consists of a session-level description
+ (details that apply to the whole session and all media streams) and
+ optionally several media-level descriptions (details that apply onto
+ to a single media stream).
+
+ An announcement consists of a session-level section followed by zero
+ or more media-level sections. The session-level part starts with a
+ `v=' line and continues to the first media-level section. The media
+ description starts with an `m=' line and continues to the next media
+ description or end of the whole session description. In general,
+ session-level values are the default for all media unless overridden
+ by an equivalent media-level value.
+
+ When SDP is conveyed by SAP, only one session description is allowed
+ per packet. When SDP is conveyed by other means, many SDP session
+ descriptions may be concatenated together (the `v=' line indicating
+ the start of a session description terminates the previous
+ description). Some lines in each description are required and some
+ are optional but all must appear in exactly the order given here (the
+ fixed order greatly enhances error detection and allows for a simple
+ parser). Optional items are marked with a `*'.
+
+Session description
+ v= (protocol version)
+ o= (owner/creator and session identifier).
+ s= (session name)
+ i=* (session information)
+
+
+
+Handley & Jacobson Standards Track [Page 7]
+
+RFC 2327 SDP April 1998
+
+
+ u=* (URI of description)
+ e=* (email address)
+ p=* (phone number)
+ c=* (connection information - not required if included in all media)
+ b=* (bandwidth information)
+ One or more time descriptions (see below)
+ z=* (time zone adjustments)
+ k=* (encryption key)
+ a=* (zero or more session attribute lines)
+ Zero or more media descriptions (see below)
+
+Time description
+ t= (time the session is active)
+ r=* (zero or more repeat times)
+
+Media description
+ m= (media name and transport address)
+ i=* (media title)
+ c=* (connection information - optional if included at session-level)
+ b=* (bandwidth information)
+ k=* (encryption key)
+ a=* (zero or more media attribute lines)
+
+ The set of `type' letters is deliberately small and not intended to
+ be extensible -- SDP parsers must completely ignore any announcement
+ that contains a `type' letter that it does not understand. The
+ `attribute' mechanism ("a=" described below) is the primary means for
+ extending SDP and tailoring it to particular applications or media.
+ Some attributes (the ones listed in this document) have a defined
+ meaning but others may be added on an application-, media- or
+ session-specific basis. A session directory must ignore any
+ attribute it doesn't understand.
+
+ The connection (`c=') and attribute (`a=') information in the
+ session-level section applies to all the media of that session unless
+ overridden by connection information or an attribute of the same name
+ in the media description. For instance, in the example below, each
+ media behaves as if it were given a `recvonly' attribute.
+
+ An example SDP description is:
+
+ v=0
+ o=mhandley 2890844526 2890842807 IN IP4 126.16.64.4
+ s=SDP Seminar
+ i=A Seminar on the session description protocol
+ u=http://www.cs.ucl.ac.uk/staff/M.Handley/sdp.03.ps
+ e=mjh at isi.edu (Mark Handley)
+ c=IN IP4 224.2.17.12/127
+
+
+
+Handley & Jacobson Standards Track [Page 8]
+
+RFC 2327 SDP April 1998
+
+
+ t=2873397496 2873404696
+ a=recvonly
+ m=audio 49170 RTP/AVP 0
+ m=video 51372 RTP/AVP 31
+ m=application 32416 udp wb
+ a=orient:portrait
+
+ Text records such as the session name and information are bytes
+ strings which may contain any byte with the exceptions of 0x00 (Nul),
+ 0x0a (ASCII newline) and 0x0d (ASCII carriage return). The sequence
+ CRLF (0x0d0a) is used to end a record, although parsers should be
+ tolerant and also accept records terminated with a single newline
+ character. By default these byte strings contain ISO-10646
+ characters in UTF-8 encoding, but this default may be changed using
+ the `charset' attribute.
+
+ Protocol Version
+
+ v=0
+
+ The "v=" field gives the version of the Session Description Protocol.
+ There is no minor version number.
+
+ Origin
+
+ o=<username> <session id> <version> <network type> <address type>
+ <address>
+
+ The "o=" field gives the originator of the session (their username
+ and the address of the user's host) plus a session id and session
+ version number.
+
+ <username> is the user's login on the originating host, or it is "-"
+ if the originating host does not support the concept of user ids.
+ <username> must not contain spaces. <session id> is a numeric string
+ such that the tuple of <username>, <session id>, <network type>,
+ <address type> and <address> form a globally unique identifier for
+ the session.
+
+ The method of <session id> allocation is up to the creating tool, but
+ it has been suggested that a Network Time Protocol (NTP) timestamp be
+ used to ensure uniqueness [1].
+
+ <version> is a version number for this announcement. It is needed
+ for proxy announcements to detect which of several announcements for
+ the same session is the most recent. Again its usage is up to the
+
+
+
+
+
+Handley & Jacobson Standards Track [Page 9]
+
+RFC 2327 SDP April 1998
+
+
+ creating tool, so long as <version> is increased when a modification
+ is made to the session data. Again, it is recommended (but not
+ mandatory) that an NTP timestamp is used.
+
+ <network type> is a text string giving the type of network.
+ Initially "IN" is defined to have the meaning "Internet". <address
+ type> is a text string giving the type of the address that follows.
+ Initially "IP4" and "IP6" are defined. <address> is the globally
+ unique address of the machine from which the session was created.
+ For an address type of IP4, this is either the fully-qualified domain
+ name of the machine, or the dotted-decimal representation of the IP
+ version 4 address of the machine. For an address type of IP6, this
+ is either the fully-qualified domain name of the machine, or the
+ compressed textual representation of the IP version 6 address of the
+ machine. For both IP4 and IP6, the fully-qualified domain name is
+ the form that SHOULD be given unless this is unavailable, in which
+ case the globally unique address may be substituted. A local IP
+ address MUST NOT be used in any context where the SDP description
+ might leave the scope in which the address is meaningful.
+
+ In general, the "o=" field serves as a globally unique identifier for
+ this version of this session description, and the subfields excepting
+ the version taken together identify the session irrespective of any
+ modifications.
+
+ Session Name
+
+ s=<session name>
+
+ The "s=" field is the session name. There must be one and only one
+ "s=" field per session description, and it must contain ISO 10646
+ characters (but see also the `charset' attribute below).
+
+ Session and Media Information
+
+ i=<session description>
+
+ The "i=" field is information about the session. There may be at
+ most one session-level "i=" field per session description, and at
+ most one "i=" field per media. Although it may be omitted, this is
+ discouraged for session announcements, and user interfaces for
+ composing sessions should require text to be entered. If it is
+ present it must contain ISO 10646 characters (but see also the
+ `charset' attribute below).
+
+ A single "i=" field can also be used for each media definition. In
+ media definitions, "i=" fields are primarily intended for labeling
+ media streams. As such, they are most likely to be useful when a
+
+
+
+Handley & Jacobson Standards Track [Page 10]
+
+RFC 2327 SDP April 1998
+
+
+ single session has more than one distinct media stream of the same
+ media type. An example would be two different whiteboards, one for
+ slides and one for feedback and questions.
+
+ URI
+
+ u=<URI>
+
+ o A URI is a Universal Resource Identifier as used by WWW clients
+
+ o The URI should be a pointer to additional information about the
+ conference
+
+ o This field is optional, but if it is present it should be specified
+ before the first media field
+
+ o No more than one URI field is allowed per session description
+
+
+ Email Address and Phone Number
+
+ e=<email address>
+ p=<phone number>
+
+ o These specify contact information for the person responsible for
+ the conference. This is not necessarily the same person that
+ created the conference announcement.
+
+ o Either an email field or a phone field must be specified.
+ Additional email and phone fields are allowed.
+
+ o If these are present, they should be specified before the first
+ media field.
+
+ o More than one email or phone field can be given for a session
+ description.
+
+ o Phone numbers should be given in the conventional international
+
+ format - preceded by a "+ and the international country code.
+ There must be a space or a hyphen ("-") between the country code
+ and the rest of the phone number. Spaces and hyphens may be used
+ to split up a phone field to aid readability if desired. For
+ example:
+
+ p=+44-171-380-7777 or p=+1 617 253 6011
+
+
+
+
+
+Handley & Jacobson Standards Track [Page 11]
+
+RFC 2327 SDP April 1998
+
+
+ o Both email addresses and phone numbers can have an optional free
+ text string associated with them, normally giving the name of the
+ person who may be contacted. This should be enclosed in
+ parenthesis if it is present. For example:
+
+ e=mjh at isi.edu (Mark Handley)
+
+ The alternative RFC822 name quoting convention is also allowed for
+ both email addresses and phone numbers. For example,
+
+ e=Mark Handley <mjh at isi.edu>
+
+ The free text string should be in the ISO-10646 character set with
+ UTF-8 encoding, or alternatively in ISO-8859-1 or other encodings
+ if the appropriate charset session-level attribute is set.
+
+ Connection Data
+
+ c=<network type> <address type> <connection address>
+
+ The "c=" field contains connection data.
+
+ A session announcement must contain one "c=" field in each media
+ description (see below) or a "c=" field at the session-level. It may
+ contain a session-level "c=" field and one additional "c=" field per
+ media description, in which case the per-media values override the
+ session-level settings for the relevant media.
+
+ The first sub-field is the network type, which is a text string
+ giving the type of network. Initially "IN" is defined to have the
+ meaning "Internet".
+
+ The second sub-field is the address type. This allows SDP to be used
+ for sessions that are not IP based. Currently only IP4 is defined.
+
+ The third sub-field is the connection address. Optional extra
+ subfields may be added after the connection address depending on the
+ value of the <address type> field.
+
+ For IP4 addresses, the connection address is defined as follows:
+
+ o Typically the connection address will be a class-D IP multicast
+
+ group address. If the session is not multicast, then the
+ connection address contains the fully-qualified domain name or the
+ unicast IP address of the expected data source or data relay or
+ data sink as determined by additional attribute fields. It is not
+ expected that fully-qualified domain names or unicast addresses
+
+
+
+Handley & Jacobson Standards Track [Page 12]
+
+RFC 2327 SDP April 1998
+
+
+ will be given in a session description that is communicated by a
+ multicast announcement, though this is not prohibited. If a
+ unicast data stream is to pass through a network address
+ translator, the use of a fully-qualified domain name rather than an
+ unicast IP address is RECOMMENDED. In other cases, the use of an
+ IP address to specify a particular interface on a multi-homed host
+ might be required. Thus this specification leaves the decision as
+ to which to use up to the individual application, but all
+ applications MUST be able to cope with receiving both formats.
+
+ o Conferences using an IP multicast connection address must also have
+ a time to live (TTL) value present in addition to the multicast
+ address. The TTL and the address together define the scope with
+ which multicast packets sent in this conference will be sent. TTL
+ values must be in the range 0-255.
+
+ The TTL for the session is appended to the address using a slash as
+ a separator. An example is:
+
+ c=IN IP4 224.2.1.1/127
+
+ Hierarchical or layered encoding schemes are data streams where the
+ encoding from a single media source is split into a number of
+ layers. The receiver can choose the desired quality (and hence
+ bandwidth) by only subscribing to a subset of these layers. Such
+ layered encodings are normally transmitted in multiple multicast
+ groups to allow multicast pruning. This technique keeps unwanted
+ traffic from sites only requiring certain levels of the hierarchy.
+ For applications requiring multiple multicast groups, we allow the
+ following notation to be used for the connection address:
+
+ <base multicast address>/<ttl>/<number of addresses>
+
+ If the number of addresses is not given it is assumed to be one.
+ Multicast addresses so assigned are contiguously allocated above
+ the base address, so that, for example:
+
+ c=IN IP4 224.2.1.1/127/3
+
+ would state that addresses 224.2.1.1, 224.2.1.2 and 224.2.1.3 are
+ to be used at a ttl of 127. This is semantically identical to
+ including multiple "c=" lines in a media description:
+
+ c=IN IP4 224.2.1.1/127
+ c=IN IP4 224.2.1.2/127
+ c=IN IP4 224.2.1.3/127
+
+
+
+
+
+Handley & Jacobson Standards Track [Page 13]
+
+RFC 2327 SDP April 1998
+
+
+ Multiple addresses or "c=" lines can only be specified on a per-
+ media basis, and not for a session-level "c=" field.
+
+ It is illegal for the slash notation described above to be used for
+ IP unicast addresses.
+
+ Bandwidth
+
+ b=<modifier>:<bandwidth-value>
+
+ o This specifies the proposed bandwidth to be used by the session or
+ media, and is optional.
+
+ o <bandwidth-value> is in kilobits per second
+
+ o <modifier> is a single alphanumeric word giving the meaning of the
+ bandwidth figure.
+
+ o Two modifiers are initially defined:
+
+ CT Conference Total: An implicit maximum bandwidth is associated with
+ each TTL on the Mbone or within a particular multicast
+ administrative scope region (the Mbone bandwidth vs. TTL limits are
+ given in the MBone FAQ). If the bandwidth of a session or media in
+ a session is different from the bandwidth implicit from the scope,
+ a `b=CT:...' line should be supplied for the session giving the
+ proposed upper limit to the bandwidth used. The primary purpose of
+ this is to give an approximate idea as to whether two or more
+ conferences can co-exist simultaneously.
+
+ AS Application-Specific Maximum: The bandwidth is interpreted to be
+ application-specific, i.e., will be the application's concept of
+ maximum bandwidth. Normally this will coincide with what is set on
+ the application's "maximum bandwidth" control if applicable.
+
+ Note that CT gives a total bandwidth figure for all the media at
+ all sites. AS gives a bandwidth figure for a single media at a
+ single site, although there may be many sites sending
+ simultaneously.
+
+ o Extension Mechanism: Tool writers can define experimental bandwidth
+ modifiers by prefixing their modifier with "X-". For example:
+
+ b=X-YZ:128
+
+ SDP parsers should ignore bandwidth fields with unknown modifiers.
+ Modifiers should be alpha-numeric and, although no length limit is
+ given, they are recommended to be short.
+
+
+
+Handley & Jacobson Standards Track [Page 14]
+
+RFC 2327 SDP April 1998
+
+
+ Times, Repeat Times and Time Zones
+
+ t=<start time> <stop time>
+
+ o "t=" fields specify the start and stop times for a conference
+ session. Multiple "t=" fields may be used if a session is active
+ at multiple irregularly spaced times; each additional "t=" field
+ specifies an additional period of time for which the session will
+ be active. If the session is active at regular times, an "r="
+ field (see below) should be used in addition to and following a
+ "t=" field - in which case the "t=" field specifies the start and
+ stop times of the repeat sequence.
+
+ o The first and second sub-fields give the start and stop times for
+ the conference respectively. These values are the decimal
+ representation of Network Time Protocol (NTP) time values in
+ seconds [1]. To convert these values to UNIX time, subtract
+ decimal 2208988800.
+
+ o If the stop-time is set to zero, then the session is not bounded,
+ though it will not become active until after the start-time. If
+ the start-time is also zero, the session is regarded as permanent.
+
+ User interfaces should strongly discourage the creation of
+ unbounded and permanent sessions as they give no information about
+ when the session is actually going to terminate, and so make
+ scheduling difficult.
+
+ The general assumption may be made, when displaying unbounded
+ sessions that have not timed out to the user, that an unbounded
+ session will only be active until half an hour from the current
+ time or the session start time, whichever is the later. If
+ behaviour other than this is required, an end-time should be given
+ and modified as appropriate when new information becomes available
+ about when the session should really end.
+
+ Permanent sessions may be shown to the user as never being active
+ unless there are associated repeat times which state precisely when
+ the session will be active. In general, permanent sessions should
+ not be created for any session expected to have a duration of less
+ than 2 months, and should be discouraged for sessions expected to
+ have a duration of less than 6 months.
+
+ r=<repeat interval> <active duration> <list of offsets from start-
+ time>
+
+ o "r=" fields specify repeat times for a session. For example, if
+ a session is active at 10am on Monday and 11am on Tuesday for one
+
+
+
+Handley & Jacobson Standards Track [Page 15]
+
+RFC 2327 SDP April 1998
+
+
+ hour each week for three months, then the <start time> in the
+ corresponding "t=" field would be the NTP representation of 10am on
+ the first Monday, the <repeat interval> would be 1 week, the
+ <active duration> would be 1 hour, and the offsets would be zero
+ and 25 hours. The corresponding "t=" field stop time would be the
+ NTP representation of the end of the last session three months
+ later. By default all fields are in seconds, so the "r=" and "t="
+ fields might be:
+
+ t=3034423619 3042462419
+ r=604800 3600 0 90000
+
+ To make announcements more compact, times may also be given in units
+ of days, hours or minutes. The syntax for these is a number
+ immediately followed by a single case-sensitive character.
+ Fractional units are not allowed - a smaller unit should be used
+ instead. The following unit specification characters are allowed:
+
+ d - days (86400 seconds)
+ h - minutes (3600 seconds)
+ m - minutes (60 seconds)
+ s - seconds (allowed for completeness but not recommended)
+
+ Thus, the above announcement could also have been written:
+
+ r=7d 1h 0 25h
+
+ Monthly and yearly repeats cannot currently be directly specified
+ with a single SDP repeat time - instead separate "t" fields should
+ be used to explicitly list the session times.
+
+ z=<adjustment time> <offset> <adjustment time> <offset> ....
+
+ o To schedule a repeated session which spans a change from daylight-
+ saving time to standard time or vice-versa, it is necessary to
+ specify offsets from the base repeat times. This is required
+ because different time zones change time at different times of day,
+ different countries change to or from daylight time on different
+ dates, and some countries do not have daylight saving time at all.
+
+ Thus in order to schedule a session that is at the same time winter
+ and summer, it must be possible to specify unambiguously by whose
+ time zone a session is scheduled. To simplify this task for
+ receivers, we allow the sender to specify the NTP time that a time
+ zone adjustment happens and the offset from the time when the
+ session was first scheduled. The "z" field allows the sender to
+ specify a list of these adjustment times and offsets from the base
+ time.
+
+
+
+Handley & Jacobson Standards Track [Page 16]
+
+RFC 2327 SDP April 1998
+
+
+ An example might be:
+
+ z=2882844526 -1h 2898848070 0
+
+ This specifies that at time 2882844526 the time base by which the
+ session's repeat times are calculated is shifted back by 1 hour,
+ and that at time 2898848070 the session's original time base is
+ restored. Adjustments are always relative to the specified start
+ time - they are not cumulative.
+
+ o If a session is likely to last several years, it is expected
+ that
+ the session announcement will be modified periodically rather than
+ transmit several years worth of adjustments in one announcement.
+
+ Encryption Keys
+
+ k=<method>
+ k=<method>:<encryption key>
+
+ o The session description protocol may be used to convey encryption
+ keys. A key field is permitted before the first media entry (in
+ which case it applies to all media in the session), or for each
+ media entry as required.
+
+ o The format of keys and their usage is outside the scope of this
+ document, but see [3].
+
+ o The method indicates the mechanism to be used to obtain a usable
+ key by external means, or from the encoded encryption key given.
+
+ The following methods are defined:
+
+ k=clear:<encryption key>
+ The encryption key (as described in [3] for RTP media streams
+ under the AV profile) is included untransformed in this key
+ field.
+
+ k=base64:<encoded encryption key>
+ The encryption key (as described in [3] for RTP media streams
+ under the AV profile) is included in this key field but has been
+ base64 encoded because it includes characters that are
+ prohibited in SDP.
+
+ k=uri:<URI to obtain key>
+ A Universal Resource Identifier as used by WWW clients is
+ included in this key field. The URI refers to the data
+ containing the key, and may require additional authentication
+
+
+
+Handley & Jacobson Standards Track [Page 17]
+
+RFC 2327 SDP April 1998
+
+
+ before the key can be returned. When a request is made to the
+ given URI, the MIME content-type of the reply specifies the
+ encoding for the key in the reply. The key should not be
+ obtained until the user wishes to join the session to reduce
+ synchronisation of requests to the WWW server(s).
+
+ k=prompt
+ No key is included in this SDP description, but the session or
+ media stream referred to by this key field is encrypted. The
+ user should be prompted for the key when attempting to join the
+ session, and this user-supplied key should then be used to
+ decrypt the media streams.
+
+ Attributes
+
+ a=<attribute>
+ a=<attribute>:<value>
+
+ Attributes are the primary means for extending SDP. Attributes may
+ be defined to be used as "session-level" attributes, "media-level"
+ attributes, or both.
+
+ A media description may have any number of attributes ("a=" fields)
+ which are media specific. These are referred to as "media-level"
+ attributes and add information about the media stream. Attribute
+ fields can also be added before the first media field; these
+ "session-level" attributes convey additional information that applies
+ to the conference as a whole rather than to individual media; an
+ example might be the conference's floor control policy.
+
+ Attribute fields may be of two forms:
+
+ o property attributes. A property attribute is simply of the form
+ "a=<flag>". These are binary attributes, and the presence of the
+ attribute conveys that the attribute is a property of the session.
+ An example might be "a=recvonly".
+
+ o value attributes. A value attribute is of the form
+ "a=<attribute>:<value>". An example might be that a whiteboard
+ could have the value attribute "a=orient:landscape"
+
+ Attribute interpretation depends on the media tool being invoked.
+ Thus receivers of session descriptions should be configurable in
+ their interpretation of announcements in general and of attributes in
+ particular.
+
+ Attribute names must be in the US-ASCII subset of ISO-10646/UTF-8.
+
+
+
+
+Handley & Jacobson Standards Track [Page 18]
+
+RFC 2327 SDP April 1998
+
+
+ Attribute values are byte strings, and MAY use any byte value except
+ 0x00 (Nul), 0x0A (LF), and 0x0D (CR). By default, attribute values
+ are to be interpreted as in ISO-10646 character set with UTF-8
+ encoding. Unlike other text fields, attribute values are NOT
+ normally affected by the `charset' attribute as this would make
+ comparisons against known values problematic. However, when an
+ attribute is defined, it can be defined to be charset-dependent, in
+ which case it's value should be interpreted in the session charset
+ rather than in ISO-10646.
+
+ Attributes that will be commonly used can be registered with IANA
+ (see Appendix B). Unregistered attributes should begin with "X-" to
+ prevent inadvertent collision with registered attributes. In either
+ case, if an attribute is received that is not understood, it should
+ simply be ignored by the receiver.
+
+ Media Announcements
+
+ m=<media> <port> <transport> <fmt list>
+
+ A session description may contain a number of media descriptions.
+ Each media description starts with an "m=" field, and is terminated
+ by either the next "m=" field or by the end of the session
+ description. A media field also has several sub-fields:
+
+ o The first sub-field is the media type. Currently defined media are
+ "audio", "video", "application", "data" and "control", though this
+ list may be extended as new communication modalities emerge (e.g.,
+ telepresense). The difference between "application" and "data" is
+ that the former is a media flow such as whiteboard information, and
+ the latter is bulk-data transfer such as multicasting of program
+ executables which will not typically be displayed to the user.
+ "control" is used to specify an additional conference control
+ channel for the session.
+
+ o The second sub-field is the transport port to which the media
+ stream will be sent. The meaning of the transport port depends on
+ the network being used as specified in the relevant "c" field and
+ on the transport protocol defined in the third sub-field. Other
+ ports used by the media application (such as the RTCP port, see
+ [2]) should be derived algorithmically from the base media port.
+
+ Note: For transports based on UDP, the value should be in the range
+ 1024 to 65535 inclusive. For RTP compliance it should be an even
+ number.
+
+
+
+
+
+
+Handley & Jacobson Standards Track [Page 19]
+
+RFC 2327 SDP April 1998
+
+
+ For applications where hierarchically encoded streams are being
+ sent to a unicast address, it may be necessary to specify multiple
+ transport ports. This is done using a similar notation to that
+ used for IP multicast addresses in the "c=" field:
+
+ m=<media> <port>/<number of ports> <transport> <fmt list>
+
+ In such a case, the ports used depend on the transport protocol.
+ For RTP, only the even ports are used for data and the
+ corresponding one-higher odd port is used for RTCP. For example:
+
+ m=video 49170/2 RTP/AVP 31
+
+ would specify that ports 49170 and 49171 form one RTP/RTCP pair and
+ 49172 and 49173 form the second RTP/RTCP pair. RTP/AVP is the
+ transport protocol and 31 is the format (see below).
+
+ It is illegal for both multiple addresses to be specified in the
+ "c=" field and for multiple ports to be specified in the "m=" field
+ in the same session description.
+
+ o The third sub-field is the transport protocol. The transport
+ protocol values are dependent on the address-type field in the "c="
+ fields. Thus a "c=" field of IP4 defines that the transport
+ protocol runs over IP4. For IP4, it is normally expected that most
+ media traffic will be carried as RTP over UDP. The following
+ transport protocols are preliminarily defined, but may be extended
+ through registration of new protocols with IANA:
+
+ - RTP/AVP - the IETF's Realtime Transport Protocol using the
+ Audio/Video profile carried over UDP.
+
+ - udp - User Datagram Protocol
+
+ If an application uses a single combined proprietary media format
+ and transport protocol over UDP, then simply specifying the
+ transport protocol as udp and using the format field to distinguish
+ the combined protocol is recommended. If a transport protocol is
+ used over UDP to carry several distinct media types that need to be
+ distinguished by a session directory, then specifying the transport
+ protocol and media format separately is necessary. RTP is an
+ example of a transport-protocol that carries multiple payload
+ formats that must be distinguished by the session directory for it
+ to know how to start appropriate tools, relays, mixers or
+ recorders.
+
+
+
+
+
+
+Handley & Jacobson Standards Track [Page 20]
+
+RFC 2327 SDP April 1998
+
+
+ The main reason to specify the transport-protocol in addition to
+ the media format is that the same standard media formats may be
+ carried over different transport protocols even when the network
+ protocol is the same - a historical example is vat PCM audio and
+ RTP PCM audio. In addition, relays and monitoring tools that are
+ transport-protocol-specific but format-independent are possible.
+
+ For RTP media streams operating under the RTP Audio/Video Profile
+ [3], the protocol field is "RTP/AVP". Should other RTP profiles be
+ defined in the future, their profiles will be specified in the same
+ way. For example, the protocol field "RTP/XYZ" would specify RTP
+ operating under a profile whose short name is "XYZ".
+
+ o The fourth and subsequent sub-fields are media formats. For audio
+ and video, these will normally be a media payload type as defined
+ in the RTP Audio/Video Profile.
+
+ When a list of payload formats is given, this implies that all of
+ these formats may be used in the session, but the first of these
+ formats is the default format for the session.
+
+ For media whose transport protocol is not RTP or UDP the format
+ field is protocol specific. Such formats should be defined in an
+ additional specification document.
+
+ For media whose transport protocol is RTP, SDP can be used to
+ provide a dynamic binding of media encoding to RTP payload type.
+ The encoding names in the RTP AV Profile do not specify unique
+ audio encodings (in terms of clock rate and number of audio
+ channels), and so they are not used directly in SDP format fields.
+ Instead, the payload type number should be used to specify the
+ format for static payload types and the payload type number along
+ with additional encoding information should be used for dynamically
+ allocated payload types.
+
+ An example of a static payload type is u-law PCM coded single
+ channel audio sampled at 8KHz. This is completely defined in the
+ RTP Audio/Video profile as payload type 0, so the media field for
+ such a stream sent to UDP port 49232 is:
+
+ m=video 49232 RTP/AVP 0
+
+ An example of a dynamic payload type is 16 bit linear encoded
+ stereo audio sampled at 16KHz. If we wish to use dynamic RTP/AVP
+ payload type 98 for such a stream, additional information is
+ required to decode it:
+
+ m=video 49232 RTP/AVP 98
+
+
+
+Handley & Jacobson Standards Track [Page 21]
+
+RFC 2327 SDP April 1998
+
+
+ a=rtpmap:98 L16/16000/2
+
+ The general form of an rtpmap attribute is:
+
+ a=rtpmap:<payload type> <encoding name>/<clock rate>[/<encoding
+ parameters>]
+
+ For audio streams, <encoding parameters> may specify the number of
+ audio channels. This parameter may be omitted if the number of
+ channels is one provided no additional parameters are needed. For
+ video streams, no encoding parameters are currently specified.
+
+ Additional parameters may be defined in the future, but
+ codecspecific parameters should not be added. Parameters added to
+ an rtpmap attribute should only be those required for a session
+ directory to make the choice of appropriate media too to
+ participate in a session. Codec-specific parameters should be
+ added in other attributes.
+
+ Up to one rtpmap attribute can be defined for each media format
+ specified. Thus we might have:
+
+ m=audio 49230 RTP/AVP 96 97 98
+ a=rtpmap:96 L8/8000
+ a=rtpmap:97 L16/8000
+ a=rtpmap:98 L16/11025/2
+
+ RTP profiles that specify the use of dynamic payload types must
+ define the set of valid encoding names and/or a means to register
+ encoding names if that profile is to be used with SDP.
+
+ Experimental encoding formats can also be specified using rtpmap.
+ RTP formats that are not registered as standard format names must
+ be preceded by "X-". Thus a new experimental redundant audio
+ stream called GSMLPC using dynamic payload type 99 could be
+ specified as:
+
+ m=video 49232 RTP/AVP 99
+ a=rtpmap:99 X-GSMLPC/8000
+
+ Such an experimental encoding requires that any site wishing to
+ receive the media stream has relevant configured state in its
+ session directory to know which tools are appropriate.
+
+ Note that RTP audio formats typically do not include information
+ about the number of samples per packet. If a non-default (as
+ defined in the RTP Audio/Video Profile) packetisation is required,
+ the "ptime" attribute is used as given below.
+
+
+
+Handley & Jacobson Standards Track [Page 22]
+
+RFC 2327 SDP April 1998
+
+
+ For more details on RTP audio and video formats, see [3].
+
+ o Formats for non-RTP media should be registered as MIME content
+ types as described in Appendix B. For example, the LBL whiteboard
+ application might be registered as MIME content-type application/wb
+ with encoding considerations specifying that it operates over UDP,
+ with no appropriate file format. In SDP this would then be
+ expressed using a combination of the "media" field and the "fmt"
+ field, as follows:
+
+ m=application 32416 udp wb
+
+ Suggested Attributes
+
+ The following attributes are suggested. Since application writers
+ may add new attributes as they are required, this list is not
+ exhaustive.
+
+ a=cat:<category>
+ This attribute gives the dot-separated hierarchical category of
+ the session. This is to enable a receiver to filter unwanted
+ sessions by category. It would probably have been a compulsory
+ separate field, except for its experimental nature at this time.
+ It is a session-level attribute, and is not dependent on charset.
+
+ a=keywds:<keywords>
+ Like the cat attribute, this is to assist identifying wanted
+ sessions at the receiver. This allows a receiver to select
+ interesting session based on keywords describing the purpose of
+ the session. It is a session-level attribute. It is a charset
+ dependent attribute, meaning that its value should be interpreted
+ in the charset specified for the session description if one is
+ specified, or by default in ISO 10646/UTF-8.
+
+ a=tool:<name and version of tool>
+ This gives the name and version number of the tool used to create
+ the session description. It is a session-level attribute, and is
+ not dependent on charset.
+
+ a=ptime:<packet time>
+ This gives the length of time in milliseconds represented by the
+ media in a packet. This is probably only meaningful for audio
+ data. It should not be necessary to know ptime to decode RTP or
+ vat audio, and it is intended as a recommendation for the
+ encoding/packetisation of audio. It is a media attribute, and is
+ not dependent on charset.
+
+
+
+
+
+Handley & Jacobson Standards Track [Page 23]
+
+RFC 2327 SDP April 1998
+
+
+ a=recvonly
+ This specifies that the tools should be started in receive-only
+ mode where applicable. It can be either a session or media
+ attribute, and is not dependent on charset.
+
+ a=sendrecv
+ This specifies that the tools should be started in send and
+ receive mode. This is necessary for interactive conferences with
+ tools such as wb which defaults to receive only mode. It can be
+ either a session or media attribute, and is not dependent on
+ charset.
+
+ a=sendonly
+ This specifies that the tools should be started in send-only
+ mode. An example may be where a different unicast address is to
+ be used for a traffic destination than for a traffic source. In
+ such a case, two media descriptions may be use, one sendonly and
+ one recvonly. It can be either a session or media attribute, but
+ would normally only be used as a media attribute, and is not
+ dependent on charset.
+
+ a=orient:<whiteboard orientation>
+ Normally this is only used in a whiteboard media specification.
+ It specifies the orientation of a the whiteboard on the screen.
+ It is a media attribute. Permitted values are `portrait',
+ `landscape' and `seascape' (upside down landscape). It is not
+ dependent on charset
+
+ a=type:<conference type>
+ This specifies the type of the conference. Suggested values are
+ `broadcast', `meeting', `moderated', `test' and `H332'.
+ `recvonly' should be the default for `type:broadcast' sessions,
+ `type:meeting' should imply `sendrecv' and `type:moderated'
+ should indicate the use of a floor control tool and that the
+ media tools are started so as to "mute" new sites joining the
+ conference.
+
+ Specifying the attribute type:H332 indicates that this loosely
+ coupled session is part of a H.332 session as defined in the ITU
+ H.332 specification [10]. Media tools should be started
+ `recvonly'.
+
+ Specifying the attribute type:test is suggested as a hint that,
+ unless explicitly requested otherwise, receivers can safely avoid
+ displaying this session description to users.
+
+ The type attribute is a session-level attribute, and is not
+ dependent on charset.
+
+
+
+Handley & Jacobson Standards Track [Page 24]
+
+RFC 2327 SDP April 1998
+
+
+ a=charset:<character set>
+ This specifies the character set to be used to display the
+ session name and information data. By default, the ISO-10646
+ character set in UTF-8 encoding is used. If a more compact
+ representation is required, other character sets may be used such
+ as ISO-8859-1 for Northern European languages. In particular,
+ the ISO 8859-1 is specified with the following SDP attribute:
+
+ a=charset:ISO-8859-1
+
+ This is a session-level attribute; if this attribute is present,
+ it must be before the first media field. The charset specified
+ MUST be one of those registered with IANA, such as ISO-8859-1.
+ The character set identifier is a US-ASCII string and MUST be
+ compared against the IANA identifiers using a case-insensitive
+ comparison. If the identifier is not recognised or not
+ supported, all strings that are affected by it SHOULD be regarded
+ as byte strings.
+
+ Note that a character set specified MUST still prohibit the use
+ of bytes 0x00 (Nul), 0x0A (LF) and 0x0d (CR). Character sets
+ requiring the use of these characters MUST define a quoting
+ mechanism that prevents these bytes appearing within text fields.
+
+ a=sdplang:<language tag>
+ This can be a session level attribute or a media level attribute.
+ As a session level attribute, it specifies the language for the
+ session description. As a media level attribute, it specifies
+ the language for any media-level SDP information field associated
+ with that media. Multiple sdplang attributes can be provided
+ either at session or media level if multiple languages in the
+ session description or media use multiple languages, in which
+ case the order of the attributes indicates the order of
+ importance of the various languages in the session or media from
+ most important to least important.
+
+ In general, sending session descriptions consisting of multiple
+ languages should be discouraged. Instead, multiple descriptions
+ should be sent describing the session, one in each language.
+ However this is not possible with all transport mechanisms, and
+ so multiple sdplang attributes are allowed although not
+ recommended.
+
+ The sdplang attribute value must be a single RFC 1766 language
+ tag in US-ASCII. It is not dependent on the charset attribute.
+ An sdplang attribute SHOULD be specified when a session is of
+
+
+
+
+
+Handley & Jacobson Standards Track [Page 25]
+
+RFC 2327 SDP April 1998
+
+
+ sufficient scope to cross geographic boundaries where the
+ language of recipients cannot be assumed, or where the session is
+ in a different language from the locally assumed norm.
+
+ a=lang:<language tag>
+ This can be a session level attribute or a media level attribute.
+ As a session level attribute, it specifies the default language
+ for the session being described. As a media level attribute, it
+ specifies the language for that media, overriding any session-
+ level language specified. Multiple lang attributes can be
+ provided either at session or media level if multiple languages
+ if the session description or media use multiple languages, in
+ which case the order of the attributes indicates the order of
+ importance of the various languages in the session or media from
+ most important to least important.
+
+ The lang attribute value must be a single RFC 1766 language tag
+ in US-ASCII. It is not dependent on the charset attribute. A
+ lang attribute SHOULD be specified when a session is of
+ sufficient scope to cross geographic boundaries where the
+ language of recipients cannot be assumed, or where the session is
+ in a different language from the locally assumed norm.
+
+ a=framerate:<frame rate>
+ This gives the maximum video frame rate in frames/sec. It is
+ intended as a recommendation for the encoding of video data.
+ Decimal representations of fractional values using the notation
+ "<integer>.<fraction>" are allowed. It is a media attribute, is
+ only defined for video media, and is not dependent on charset.
+
+ a=quality:<quality>
+ This gives a suggestion for the quality of the encoding as an
+ integer value.
+
+ The intention of the quality attribute for video is to specify a
+ non-default trade-off between frame-rate and still-image quality.
+ For video, the value in the range 0 to 10, with the following
+ suggested meaning:
+
+ 10 - the best still-image quality the compression scheme can
+ give.
+
+ 5 - the default behaviour given no quality suggestion.
+
+ 0 - the worst still-image quality the codec designer thinks is
+ still usable.
+
+ It is a media attribute, and is not dependent on charset.
+
+
+
+Handley & Jacobson Standards Track [Page 26]
+
+RFC 2327 SDP April 1998
+
+
+ a=fmtp:<format> <format specific parameters>
+ This attribute allows parameters that are specific to a
+ particular format to be conveyed in a way that SDP doesn't have
+ to understand them. The format must be one of the formats
+ specified for the media. Format-specific parameters may be any
+ set of parameters required to be conveyed by SDP and given
+ unchanged to the media tool that will use this format.
+
+ It is a media attribute, and is not dependent on charset.
+
+6.1. Communicating Conference Control Policy
+
+ There is some debate over the way conference control policy should be
+ communicated. In general, the authors believe that an implicit
+ declarative style of specifying conference control is desirable where
+ possible.
+
+ A simple declarative style uses a single conference attribute field
+ before the first media field, possibly supplemented by properties
+ such as `recvonly' for some of the media tools. This conference
+ attribute conveys the conference control policy. An example might be:
+
+ a=type:moderated
+
+ In some cases, however, it is possible that this may be insufficient
+ to communicate the details of an unusual conference control policy.
+ If this is the case, then a conference attribute specifying external
+ control might be set, and then one or more "media" fields might be
+ used to specify the conference control tools and configuration data
+ for those tools. An example is an ITU H.332 session:
+
+ c=IN IP4 224.5.6.7
+ a=type:H332
+ m=audio 49230 RTP/AVP 0
+ m=video 49232 RTP/AVP 31
+ m=application 12349 udp wb
+ m=control 49234 H323 mc
+ c=IN IP4 134.134.157.81
+
+ In this example, a general conference attribute (type:H332) is
+ specified stating that conference control will be provided by an
+ external H.332 tool, and a contact addresses for the H.323 session
+ multipoint controller is given.
+
+ In this document, only the declarative style of conference control
+ declaration is specified. Other forms of conference control should
+ specify an appropriate type attribute, and should define the
+ implications this has for control media.
+
+
+
+Handley & Jacobson Standards Track [Page 27]
+
+RFC 2327 SDP April 1998
+
+
+7. Security Considerations
+
+ SDP is a session description format that describes multimedia
+ sessions. A session description should not be trusted unless it has
+ been obtained by an authenticated transport protocol from a trusted
+ source. Many different transport protocols may be used to distribute
+ session description, and the nature of the authentication will differ
+ from transport to transport.
+
+ One transport that will frequently be used to distribute session
+ descriptions is the Session Announcement Protocol (SAP). SAP
+ provides both encryption and authentication mechanisms but due to the
+ nature of session announcements it is likely that there are many
+ occasions where the originator of a session announcement cannot be
+ authenticated because they are previously unknown to the receiver of
+ the announcement and because no common public key infrastructure is
+ available.
+
+ On receiving a session description over an unauthenticated transport
+ mechanism or from an untrusted party, software parsing the session
+ should take a few precautions. Session description contain
+ information required to start software on the receivers system.
+ Software that parses a session description MUST not be able to start
+ other software except that which is specifically configured as
+ appropriate software to participate in multimedia sessions. It is
+ normally considered INAPPROPRIATE for software parsing a session
+ description to start, on a user's system, software that is
+ appropriate to participate in multimedia sessions, without the user
+ first being informed that such software will be started and giving
+ their consent. Thus a session description arriving by session
+ announcement, email, session invitation, or WWW page SHOULD not
+ deliver the user into an {it interactive} multimedia session without
+ the user being aware that this will happen. As it is not always
+ simple to tell whether a session is interactive or not, applications
+ that are unsure should assume sessions are interactive.
+
+ In this specification, there are no attributes which would allow the
+ recipient of a session description to be informed to start multimedia
+ tools in a mode where they default to transmitting. Under some
+ circumstances it might be appropriate to define such attributes. If
+ this is done an application parsing a session description containing
+ such attributes SHOULD either ignore them, or inform the user that
+ joining this session will result in the automatic transmission of
+ multimedia data. The default behaviour for an unknown attribute is
+ to ignore it.
+
+
+
+
+
+
+Handley & Jacobson Standards Track [Page 28]
+
+RFC 2327 SDP April 1998
+
+
+ Session descriptions may be parsed at intermediate systems such as
+ firewalls for the purposes of opening a hole in the firewall to allow
+ the participation in multimedia sessions. It is considered
+ INAPPROPRIATE for a firewall to open such holes for unicast data
+ streams unless the session description comes in a request from inside
+ the firewall.
+
+ For multicast sessions, it is likely that local administrators will
+ apply their own policies, but the exclusive use of "local" or "site-
+ local" administrative scope within the firewall and the refusal of
+ the firewall to open a hole for such scopes will provide separation
+ of global multicast sessions from local ones.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Handley & Jacobson Standards Track [Page 29]
+
+RFC 2327 SDP April 1998
+
+
+Appendix A: SDP Grammar
+
+ This appendix provides an Augmented BNF grammar for SDP. ABNF is
+ defined in RFC 2234.
+
+
+ announcement = proto-version
+ origin-field
+ session-name-field
+ information-field
+ uri-field
+ email-fields
+ phone-fields
+ connection-field
+ bandwidth-fields
+ time-fields
+ key-field
+ attribute-fields
+ media-descriptions
+
+ proto-version = "v=" 1*DIGIT CRLF
+ ;this memo describes version 0
+
+ origin-field = "o=" username space
+ sess-id space sess-version space
+ nettype space addrtype space
+ addr CRLF
+
+ session-name-field = "s=" text CRLF
+
+ information-field = ["i=" text CRLF]
+
+ uri-field = ["u=" uri CRLF]
+
+ email-fields = *("e=" email-address CRLF)
+
+ phone-fields = *("p=" phone-number CRLF)
+
+
+ connection-field = ["c=" nettype space addrtype space
+ connection-address CRLF]
+ ;a connection field must be present
+ ;in every media description or at the
+ ;session-level
+
+
+ bandwidth-fields = *("b=" bwtype ":" bandwidth CRLF)
+
+
+
+
+Handley & Jacobson Standards Track [Page 30]
+
+RFC 2327 SDP April 1998
+
+
+ time-fields = 1*( "t=" start-time space stop-time
+ *(CRLF repeat-fields) CRLF)
+ [zone-adjustments CRLF]
+
+
+ repeat-fields = "r=" repeat-interval space typed-time
+ 1*(space typed-time)
+
+
+ zone-adjustments = time space ["-"] typed-time
+ *(space time space ["-"] typed-time)
+
+
+ key-field = ["k=" key-type CRLF]
+
+
+ key-type = "prompt" |
+ "clear:" key-data |
+ "base64:" key-data |
+ "uri:" uri
+
+
+ key-data = email-safe | "~" | "
+
+
+ attribute-fields = *("a=" attribute CRLF)
+
+
+ media-descriptions = *( media-field
+ information-field
+ *(connection-field)
+ bandwidth-fields
+ key-field
+ attribute-fields )
+
+
+ media-field = "m=" media space port ["/" integer]
+ space proto 1*(space fmt) CRLF
+
+
+ media = 1*(alpha-numeric)
+ ;typically "audio", "video", "application"
+ ;or "data"
+
+ fmt = 1*(alpha-numeric)
+ ;typically an RTP payload type for audio
+ ;and video media
+
+
+
+
+Handley & Jacobson Standards Track [Page 31]
+
+RFC 2327 SDP April 1998
+
+
+ proto = 1*(alpha-numeric)
+ ;typically "RTP/AVP" or "udp" for IP4
+
+
+ port = 1*(DIGIT)
+ ;should in the range "1024" to "65535" inclusive
+ ;for UDP based media
+
+
+ attribute = (att-field ":" att-value) | att-field
+
+
+ att-field = 1*(alpha-numeric)
+
+
+ att-value = byte-string
+
+
+ sess-id = 1*(DIGIT)
+ ;should be unique for this originating username/host
+
+
+ sess-version = 1*(DIGIT)
+ ;0 is a new session
+
+
+ connection-address = multicast-address
+ | addr
+
+
+ multicast-address = 3*(decimal-uchar ".") decimal-uchar "/" ttl
+ [ "/" integer ]
+ ;multicast addresses may be in the range
+ ;224.0.0.0 to 239.255.255.255
+
+ ttl = decimal-uchar
+
+ start-time = time | "0"
+
+ stop-time = time | "0"
+
+ time = POS-DIGIT 9*(DIGIT)
+ ;sufficient for 2 more centuries
+
+
+ repeat-interval = typed-time
+
+
+
+
+
+Handley & Jacobson Standards Track [Page 32]
+
+RFC 2327 SDP April 1998
+
+
+ typed-time = 1*(DIGIT) [fixed-len-time-unit]
+
+
+ fixed-len-time-unit = "d" | "h" | "m" | "s"
+
+
+ bwtype = 1*(alpha-numeric)
+
+ bandwidth = 1*(DIGIT)
+
+
+ username = safe
+ ;pretty wide definition, but doesn't include space
+
+
+ email-address = email | email "(" email-safe ")" |
+ email-safe "<" email ">"
+
+
+ email = ;defined in RFC822
+
+
+ uri = ;defined in RFC1630
+
+
+ phone-number = phone | phone "(" email-safe ")" |
+ email-safe "<" phone ">"
+
+
+ phone = "+" POS-DIGIT 1*(space | "-" | DIGIT)
+ ;there must be a space or hyphen between the
+ ;international code and the rest of the number.
+
+
+ nettype = "IN"
+ ;list to be extended
+
+
+ addrtype = "IP4" | "IP6"
+ ;list to be extended
+
+
+ addr = FQDN | unicast-address
+
+
+ FQDN = 4*(alpha-numeric|"-"|".")
+ ;fully qualified domain name as specified in RFC1035
+
+
+
+
+Handley & Jacobson Standards Track [Page 33]
+
+RFC 2327 SDP April 1998
+
+
+ unicast-address = IP4-address | IP6-address
+
+
+ IP4-address = b1 "." decimal-uchar "." decimal-uchar "." b4
+ b1 = decimal-uchar
+ ;less than "224"; not "0" or "127"
+ b4 = decimal-uchar
+ ;not "0"
+
+ IP6-address = ;to be defined
+
+
+ text = byte-string
+ ;default is to interpret this as IS0-10646 UTF8
+ ;ISO 8859-1 requires a "a=charset:ISO-8859-1"
+ ;session-level attribute to be used
+
+
+ byte-string = 1*(0x01..0x09|0x0b|0x0c|0x0e..0xff)
+ ;any byte except NUL, CR or LF
+
+
+ decimal-uchar = DIGIT
+ | POS-DIGIT DIGIT
+ | ("1" 2*(DIGIT))
+ | ("2" ("0"|"1"|"2"|"3"|"4") DIGIT)
+ | ("2" "5" ("0"|"1"|"2"|"3"|"4"|"5"))
+
+
+ integer = POS-DIGIT *(DIGIT)
+
+
+ alpha-numeric = ALPHA | DIGIT
+
+
+ DIGIT = "0" | POS-DIGIT
+
+
+ POS-DIGIT = "1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9"
+
+
+ ALPHA = "a"|"b"|"c"|"d"|"e"|"f"|"g"|"h"|"i"|"j"|"k"|
+ "l"|"m"|"n"|"o "|"p"|"q"|"r"|"s"|"t"|"u"|"v"|
+ "w"|"x"|"y"|"z"|"A"|"B"|"C "|"D"|"E"|"F"|"G"|
+ "H"|"I"|"J"|"K"|"L"|"M"|"N"|"O"|"P"|" Q"|"R"|
+ "S"|"T"|"U"|"V"|"W"|"X"|"Y"|"Z"
+
+
+
+
+
+Handley & Jacobson Standards Track [Page 34]
+
+RFC 2327 SDP April 1998
+
+
+ email-safe = safe | space | tab
+
+
+ safe = alpha-numeric |
+ "'" | "'" | "-" | "." | "/" | ":" | "?" | """ |
+ "#" | "$" | "&" | "*" | ";" | "=" | "@" | "[" |
+ "]" | "^" | "_" | "`" | "{" | "|" | "}" | "+" |
+ "~" | "
+
+
+ space = %d32
+ tab = %d9
+ CRLF = %d13.10
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Handley & Jacobson Standards Track [Page 35]
+
+RFC 2327 SDP April 1998
+
+
+Appendix B: Guidelines for registering SDP names with IANA
+
+ There are seven field names that may be registered with IANA. Using
+ the terminology in the SDP specification BNF, they are "media",
+ "proto", "fmt", "att-field", "bwtype", "nettype" and "addrtype".
+
+ "media" (eg, audio, video, application, data).
+
+ Packetized media types, such as those used by RTP, share the
+ namespace used by media types registry [RFC 2048] (i.e. "MIME
+ types"). The list of valid media names is the set of top-level
+ MIME content types. The set of media is intended to be small and
+ not to be extended except under rare circumstances. (The MIME
+ subtype corresponds to the "fmt" parameter below).
+
+ "proto"
+
+ In general this should be an IETF standards-track transport
+ protocol identifier such as RTP/AVP (rfc 1889 under the rfc 1890
+ profile).
+
+ However, people will want to invent their own proprietary
+ transport protocols. Some of these should be registered as a
+ "fmt" using "udp" as the protocol and some of which probably
+ can't be.
+
+ Where the protocol and the application are intimately linked,
+ such as with the LBL whiteboard wb which used a proprietary and
+ special purpose protocol over UDP, the protocol name should be
+ "udp" and the format name that should be registered is "wb". The
+ rules for formats (see below) apply to such registrations.
+
+ Where the proprietary transport protocol really carries many
+ different data formats, it is possible to register a new protocol
+ name with IANA. In such a case, an RFC MUST be produced
+ describing the protocol and referenced in the registration. Such
+ an RFC MAY be informational, although it is preferable if it is
+ standards-track.
+
+ "fmt"
+
+ The format namespace is dependent on the context of the "proto"
+ field, so a format cannot be registered without specifying one or
+ more transport protocols that it applies to.
+
+ Formats cover all the possible encodings that might want to be
+ transported in a multimedia session.
+
+
+
+
+Handley & Jacobson Standards Track [Page 36]
+
+RFC 2327 SDP April 1998
+
+
+ For RTP formats that have been assigned static payload types, the
+ payload type number is used. For RTP formats using a dynamic
+ payload type number, the dynamic payload type number is given as
+ the format and an additional "rtpmap" attribute specifies the
+ format and parameters.
+
+ For non-RTP formats, any unregistered format name may be
+ registered through the MIME-type registration process [RFC 2048].
+ The type given here is the MIME subtype only (the top-level MIME
+ content type is specified by the media parameter). The MIME type
+ registration SHOULD reference a standards-track RFC which
+ describes the transport protocol for this media type. If there
+ is an existing MIME type for this format, the MIME registration
+ should be augmented to reference the transport specification for
+ this media type. If there is not an existing MIME type for this
+ format, and there exists no appropriate file format, this should
+ be noted in the encoding considerations as "no appropriate file
+ format".
+
+ "att-field" (Attribute names)
+
+ Attribute field names MAY be registered with IANA, although this
+ is not compulsory, and unknown attributes are simply ignored.
+
+ When an attribute is registered, it must be accompanied by a
+ brief specification stating the following:
+
+ o contact name, email address and telephone number
+
+ o attribute-name (as it will appear in SDP)
+
+ o long-form attribute name in English
+
+ o type of attribute (session level, media level, or both)
+
+ o whether the attribute value is subject to the charset
+ attribute.
+
+ o a one paragraph explanation of the purpose of the attribute.
+
+ o a specification of appropriate attribute values for this
+ attribute.
+
+ IANA will not sanity check such attribute registrations except to
+ ensure that they do not clash with existing registrations.
+
+
+
+
+
+
+Handley & Jacobson Standards Track [Page 37]
+
+RFC 2327 SDP April 1998
+
+
+ Although the above is the minimum that IANA will accept, if the
+ attribute is expected to see widespread use and interoperability
+ is an issue, authors are encouraged to produce a standards-track
+ RFC that specifies the attribute more precisely.
+
+ Submitters of registrations should ensure that the specification
+ is in the spirit of SDP attributes, most notably that the
+ attribute is platform independent in the sense that it makes no
+ implicit assumptions about operating systems and does not name
+ specific pieces of software in a manner that might inhibit
+ interoperability.
+
+ "bwtype" (bandwidth specifiers)
+
+ A proliferation of bandwidth specifiers is strongly discouraged.
+
+ New bandwidth specifiers may be registered with IANA. The
+ submission MUST reference a standards-track RFC specifying the
+ semantics of the bandwidth specifier precisely, and indicating
+ when it should be used, and why the existing registered bandwidth
+ specifiers do not suffice.
+
+ "nettype" (Network Type)
+
+ New network types may be registered with IANA if SDP needs to be
+ used in the context of non-internet environments. Whilst these
+ are not normally the preserve of IANA, there may be circumstances
+ when an Internet application needs to interoperate with a non-
+ internet application, such as when gatewaying an internet
+ telephony call into the PSTN. The number of network types should
+ be small and should be rarely extended. A new network type
+ cannot be registered without registering at least one address
+ type to be used with that network type. A new network type
+ registration MUST reference an RFC which gives details of the
+ network type and address type and specifies how and when they
+ would be used. Such an RFC MAY be Informational.
+
+ "addrtype" (Address Type)
+
+ New address types may be registered with IANA. An address type
+ is only meaningful in the context of a network type, and any
+ registration of an address type MUST specify a registered network
+ type, or be submitted along with a network type registration. A
+ new address type registration MUST reference an RFC giving
+ details of the syntax of the address type. Such an RFC MAY be
+ Informational. Address types are not expected to be registered
+ frequently.
+
+
+
+
+Handley & Jacobson Standards Track [Page 38]
+
+RFC 2327 SDP April 1998
+
+
+ Registration Procedure
+
+ To register a name the above guidelines should be followed regarding
+ the required level of documentation that is required. The
+ registration itself should be sent to IANA. Attribute registrations
+ should include the information given above. Other registrations
+ should include the following additional information:
+
+ o contact name, email address and telephone number
+
+ o name being registered (as it will appear in SDP)
+
+ o long-form name in English
+
+ o type of name ("media", "proto", "fmt", "bwtype", "nettype", or
+ "addrtype")
+
+ o a one paragraph explanation of the purpose of the registered name.
+
+ o a reference to the specification (eg RFC number) of the registered
+ name.
+
+ IANA may refer any registration to the IESG or to any appropriate
+ IETF working group for review, and may request revisions to be made
+ before a registration will be made.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Handley & Jacobson Standards Track [Page 39]
+
+RFC 2327 SDP April 1998
+
+
+Appendix C: Authors' Addresses
+
+ Mark Handley
+ Information Sciences Institute
+ c/o MIT Laboratory for Computer Science
+ 545 Technology Square
+ Cambridge, MA 02139
+ United States
+ electronic mail: mjh at isi.edu
+
+ Van Jacobson
+ MS 46a-1121
+ Lawrence Berkeley Laboratory
+ Berkeley, CA 94720
+ United States
+ electronic mail: van at ee.lbl.gov
+
+Acknowledgments
+
+ Many people in the IETF MMUSIC working group have made comments and
+ suggestions contributing to this document. In particular, we would
+ like to thank Eve Schooler, Steve Casner, Bill Fenner, Allison
+ Mankin, Ross Finlayson, Peter Parnes, Joerg Ott, Carsten Bormann, Rob
+ Lanphier and Steve Hanna.
+
+References
+
+ [1] Mills, D., "Network Time Protocol (version 3) specification and
+ implementation", RFC 1305, March 1992.
+
+ [2] Schulzrinne, H., Casner, S., Frederick, R. and V. Jacobson, "RTP:
+ A Transport Protocol for Real-Time Applications", RFC 1889, January
+ 1996.
+
+ [3] Schulzrinne, H., "RTP Profile for Audio and Video Conferences
+ with Minimal Control", RFC 1890, January 1996
+
+ [4] Handley, M., "SAP - Session Announcement Protocol", Work in
+ Progress.
+
+ [5] V. Jacobson, S. McCanne, "vat - X11-based audio teleconferencing
+ tool" vat manual page, Lawrence Berkeley Laboratory, 1994.
+
+ [6] The Unicode Consortium, "The Unicode Standard -- Version 2.0",
+ Addison-Wesley, 1996.
+
+
+
+
+
+
+Handley & Jacobson Standards Track [Page 40]
+
+RFC 2327 SDP April 1998
+
+
+ [7] ISO/IEC 10646-1:1993. International Standard -- Information
+ technol- ogy -- Universal Multiple-Octet Coded Character Set (UCS) --
+ Part 1: Architecture and Basic Multilingual Plane. Five amendments
+ and a techn- ical corrigendum have been published up to now. UTF-8
+ is described in Annex R, published as Amendment 2.
+
+ [8] Goldsmith, D., and M. Davis, "Using Unicode with MIME", RFC 1641,
+ July 1994.
+
+ [9] Yergeau, F., "UTF-8, a transformation format of Unicode and ISO
+ 10646", RFC 2044, October 1996.
+
+ [10] ITU-T Recommendation H.332 (1998): "Multimedia Terminal for
+ Receiving Internet-based H.323 Conferences", ITU, Geneva.
+
+ [11] Handley, M., Schooler, E., and H. Schulzrinne, "Session
+ Initiation Protocol (SIP)", Work in Progress.
+
+ [12] Schulzrinne, H., Rao, A., and R. Lanphier, "Real Time Streaming
+ Protocol (RTSP)", RFC 2326, April 1998.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Handley & Jacobson Standards Track [Page 41]
+
+RFC 2327 SDP April 1998
+
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (1998). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Handley & Jacobson Standards Track [Page 42]
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/run_test_sdp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/run_test_sdp Thu Dec 21 01:30:28 2006
@@ -0,0 +1,22 @@
+#! /bin/sh
+#
+# Run the sdp tests
+#
+# usage: run_test_sdp [test_program] [test-directory]
+#
+
+test_sdp="${1:-./test_sdp}"
+tests="${2:-tests}"
+
+if test -r $tests/message-1.sdp ; then
+
+for n in 1 2 3 4 5 6 7 8 9 10;
+do
+ echo -n "$n: "
+ "$test_sdp" < "$tests/message-$n.sdp" && echo OK
+done
+
+else
+ echo "sdp run-tests: no tests found, skipping."
+fi
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sdp.bnf
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sdp.bnf Thu Dec 21 01:30:28 2006
@@ -0,0 +1,249 @@
+ ; BNF from RFC 2327
+
+ announcement = proto-version
+ origin-field
+ session-name-field
+ information-field
+ uri-field
+ email-fields
+ phone-fields
+ connection-field
+ bandwidth-fields
+ time-fields
+ key-field
+ attribute-fields
+ media-descriptions
+
+ proto-version = "v=" 1*DIGIT CRLF
+ ;this memo describes version 0
+
+ origin-field = "o=" username space
+ sess-id space sess-version space
+ nettype space addrtype space
+ addr CRLF
+
+ session-name-field = "s=" text CRLF
+
+ information-field = ["i=" text CRLF]
+
+ uri-field = ["u=" uri CRLF]
+
+ email-fields = *("e=" email-address CRLF)
+
+ phone-fields = *("p=" phone-number CRLF)
+
+
+ connection-field = ["c=" nettype space addrtype space
+ connection-address CRLF]
+ ;a connection field must be present
+ ;in every media description or at the
+ ;session-level
+
+
+ bandwidth-fields = *("b=" bwtype ":" bandwidth CRLF)
+
+
+ time-fields = 1*( "t=" start-time space stop-time
+ *(CRLF repeat-fields) CRLF)
+ [zone-adjustments CRLF]
+
+
+ repeat-fields = "r=" repeat-interval space typed-time
+ 1*(space typed-time)
+
+
+ zone-adjustments = "z=" time space ["-"] typed-time
+ *(space time space ["-"] typed-time)
+
+
+ key-field = ["k=" key-type CRLF]
+
+
+ key-type = "prompt" |
+ "clear:" key-data |
+ "base64:" key-data |
+ "uri:" uri
+
+
+ key-data = email-safe | "~" | "
+
+
+ attribute-fields = *("a=" attribute CRLF)
+
+
+ media-descriptions = *( media-field
+ information-field
+ *(connection-field)
+ bandwidth-fields
+ key-field
+ attribute-fields )
+
+
+ media-field = "m=" media space port ["/" integer]
+ space proto 1*(space fmt) CRLF
+
+
+ media = 1*(alpha-numeric)
+ ;typically "audio", "video", "application"
+ ;or "data"
+
+ fmt = 1*(alpha-numeric)
+ ;typically an RTP payload type for audio
+ ;and video media
+
+ proto = 1*(alpha-numeric | "/") ; PPe
+ ;typically "RTP/AVP" or "udp" for IP4
+
+
+ port = 1*(DIGIT)
+ ;should in the range "1024" to "65535" inclusive
+ ;for UDP based media
+
+
+ attribute = (att-field ":" att-value) | att-field
+
+
+ att-field = 1*(alpha-numeric)
+
+
+ att-value = byte-string
+
+
+ sess-id = 1*(DIGIT)
+ ;should be unique for this originating username/host
+
+
+ sess-version = 1*(DIGIT)
+ ;0 is a new session
+
+
+ connection-address = multicast-address
+ | addr
+
+
+ multicast-address = 3*(decimal-uchar ".") decimal-uchar "/" ttl
+ [ "/" integer ]
+ ;multicast addresses may be in the range
+ ;224.0.0.0 to 239.255.255.255
+
+ ttl = decimal-uchar
+
+ start-time = time | "0"
+
+ stop-time = time | "0"
+
+ time = POS-DIGIT 9*(DIGIT)
+ ;sufficient for 2 more centuries
+
+
+ repeat-interval = typed-time
+
+ typed-time = 1*(DIGIT) [fixed-len-time-unit]
+
+
+ fixed-len-time-unit = "d" | "h" | "m" | "s"
+
+
+ bwtype = 1*(alpha-numeric)
+
+ bandwidth = 1*(DIGIT)
+
+
+ username = safe
+ ;pretty wide definition, but doesn't include space
+
+
+ email-address = email | email "(" email-safe ")" |
+ email-safe "<" email ">"
+
+
+ email = ;defined in RFC822
+
+
+ uri= ;defined in RFC1630
+
+
+ phone-number = phone | phone "(" email-safe ")" |
+ email-safe "<" phone ">"
+
+
+ phone = "+" POS-DIGIT 1*(space | "-" | DIGIT)
+ ;there must be a space or hyphen between the
+ ;international code and the rest of the number.
+
+
+ nettype = "IN"
+ ;list to be extended
+
+
+ addrtype = "IP4" | "IP6"
+ ;list to be extended
+
+
+ addr = FQDN | unicast-address
+
+
+ FQDN = 4*(alpha-numeric|"-"|".")
+ ;fully qualified domain name as specified in RFC1035
+
+ unicast-address = IP4-address | IP6-address
+
+
+ IP4-address = b1 "." decimal-uchar "." decimal-uchar "." b4
+ b1 = decimal-uchar
+ ;less than "224"; not "0" or "127"
+ b4 = decimal-uchar
+ ;not "0"
+
+ IP6-address = ;to be defined
+
+
+ text = byte-string
+ ;default is to interpret this as IS0-10646 UTF8
+ ;ISO 8859-1 requires a "a=charset:ISO-8859-1"
+ ;session-level attribute to be used
+
+
+ byte-string = 1*(0x01..0x09|0x0b|0x0c|0x0e..0xff)
+ ;any byte except NUL, CR or LF
+
+
+ decimal-uchar = DIGIT
+ | POS-DIGIT DIGIT
+ | ("1" 2*(DIGIT))
+ | ("2" ("0"|"1"|"2"|"3"|"4") DIGIT)
+ | ("2" "5" ("0"|"1"|"2"|"3"|"4"|"5"))
+
+
+ integer = POS-DIGIT *(DIGIT)
+
+
+ alpha-numeric = ALPHA | DIGIT
+
+
+ DIGIT = "0" | POS-DIGIT
+
+
+ POS-DIGIT = "1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9"
+
+
+ ALPHA = "a"|"b"|"c"|"d"|"e"|"f"|"g"|"h"|"i"|"j"|"k"|
+ "l"|"m"|"n"|"o "|"p"|"q"|"r"|"s"|"t"|"u"|"v"|
+ "w"|"x"|"y"|"z"|"A"|"B"|"C "|"D"|"E"|"F"|"G"|
+ "H"|"I"|"J"|"K"|"L"|"M"|"N"|"O"|"P"|" Q"|"R"|
+ "S"|"T"|"U"|"V"|"W"|"X"|"Y"|"Z"
+
+
+ email-safe = safe | space | tab
+
+
+ safe = alpha-numeric |
+ "'" | "'" | "-" | "." | "/" | ":" | "?" | """ |
+ "#" | "$" | "&" | "*" | ";" | "=" | "@" | "[" |
+ "]" | "^" | "_" | "`" | "{" | "|" | "}" | "+" |
+ "~" | "
+
+
+ space = %d32
+ tab = %d9
+ CRLF = %d13.10
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sdp.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sdp.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1877 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE sdp.c Simple SDP interface.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Kai Vehmanen <kai.vehmanen at nokia.com>
+ *
+ * @date Created: Fri Feb 18 10:25:08 2000 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include <sofia-sip/su_alloc.h>
+#include <sofia-sip/su_types.h>
+
+#include "sofia-sip/sdp.h"
+
+struct align { void *_a; char _b; };
+
+#define ALIGN(v, n) ((n - (intptr_t)(v)) & (n - 1))
+#define STRUCT_ALIGN_ (sizeof(struct align) - offsetof(struct align, _b))
+#define STRUCT_ALIGN(v) ALIGN(v, sizeof(void *))
+#define ASSERT_STRUCT_ALIGN(p) \
+ (STRUCT_ALIGN(p) ? (void)assert(!"STRUCT_ALIGNED(" #p ")") : (void)0)
+
+const unsigned sdp_struct_align_ = sizeof(void *) - STRUCT_ALIGN_;
+
+#define STR_XTRA(rv, s) ((s) ? rv += strlen((s)) + 1 : 0)
+#define PTR_XTRA(rv, p, f) \
+ ((p) ? (rv += STRUCT_ALIGN(rv) + f(p)) : 0)
+#define LST_XTRA(rv, l, f) \
+ ((l) ? (rv += STRUCT_ALIGN(rv) + list_xtra_all((xtra_f*)f, l)) : 0)
+
+
+#define STRUCT_DUP(p, dst, src) \
+ ASSERT_STRUCT_ALIGN(p); assert(*(int*)(src) >= (int)sizeof(*src)); \
+ ((*(int*)(src) >= (int)sizeof(*src) \
+ ? (dst = memcpy((p), (src), sizeof(*src))) \
+ : (dst = memcpy((p), (src), *(int*)(src))), \
+ memset((p)+*(int*)(src), 0, sizeof(*src) - *(int*)(src))), \
+ ((p) += sizeof(*src)))
+
+#define STRUCT_DUP2(p, dst, src) \
+ ASSERT_STRUCT_ALIGN(p); assert(*(int*)(src) >= (int)sizeof(*src)); \
+ (dst = memcpy((p), (src), *(int*)(src)), ((p) += *(int*)(src)))
+
+#define STR_DUP(p, dst, src, m) \
+ ((src->m) ? ((dst->m) = strcpy((p), (src->m)), (p) += strlen((p)) + 1) \
+ : ((dst->m) = 0))
+#define PTR_DUP(p, dst, src, m, dup) \
+ ((dst->m) = (src->m)?((p += STRUCT_ALIGN(p)), ((dup)(&(p), (src->m)))): 0)
+#define LST_DUP(p, dst, src, m, dup) \
+ ((dst->m) = (src->m)?((p += STRUCT_ALIGN(p)),\
+ list_dup_all((dup_f*)(dup), &(p), src->m)) : 0)
+#define MED_XTRA_EX(rv, l, c) \
+ ((l) ? (rv += STRUCT_ALIGN(rv) + media_xtra_ex(l, c)) : 0)
+#define MED_DUP_EX(p, dst, src, m, dst_c, src_c) \
+ ((dst->m) = (src->m)?((p += STRUCT_ALIGN(p)),\
+ media_dup_all(&(p), src->m, dst, dst_c, src_c)) : 0)
+
+#define MED_XTRA_ALL(rv, m) \
+ ((m) ? (rv += STRUCT_ALIGN(rv) + media_xtra_all(m)) : 0)
+#define MED_DUP_ALL(p, dst, src, m) \
+ ((dst->m) = (src->m)?((p += STRUCT_ALIGN(p)),\
+ media_dup_all(&(p), src->m, dst)) : 0)
+
+typedef size_t xtra_f(void const *);
+typedef void *dup_f(char **bb, void const *src);
+
+static size_t list_xtra_all(xtra_f *xtra, void const *v);
+static void *list_dup_all(dup_f *dup, char **bb, void const *vsrc);
+
+static size_t session_xtra(sdp_session_t const *o);
+static sdp_session_t *session_dup(char **pp, sdp_session_t const *o);
+
+static size_t origin_xtra(sdp_origin_t const *o);
+static sdp_origin_t *origin_dup(char **pp, sdp_origin_t const *o);
+
+static size_t connection_xtra(sdp_connection_t const *o);
+static sdp_connection_t *connection_dup(char **pp, sdp_connection_t const *o);
+
+static size_t bandwidth_xtra(sdp_bandwidth_t const *o);
+static sdp_bandwidth_t *bandwidth_dup(char **pp, sdp_bandwidth_t const *o);
+
+static size_t time_xtra(sdp_time_t const *o);
+static sdp_time_t *time_dup(char **pp, sdp_time_t const *o);
+
+static size_t repeat_xtra(sdp_repeat_t const *o);
+static sdp_repeat_t *repeat_dup(char **pp, sdp_repeat_t const *o);
+
+static size_t zone_xtra(sdp_zone_t const *o);
+static sdp_zone_t *zone_dup(char **pp, sdp_zone_t const *o);
+
+static size_t key_xtra(sdp_key_t const *o);
+static sdp_key_t *key_dup(char **pp, sdp_key_t const *o);
+
+static size_t attribute_xtra(sdp_attribute_t const *o);
+static sdp_attribute_t *attribute_dup(char **pp, sdp_attribute_t const *o);
+
+static size_t list_xtra(sdp_list_t const *o);
+static sdp_list_t *list_dup(char **pp, sdp_list_t const *o);
+
+static size_t rtpmap_xtra(sdp_rtpmap_t const *o);
+static sdp_rtpmap_t *rtpmap_dup(char **pp, sdp_rtpmap_t const *o);
+
+static size_t media_xtra(sdp_media_t const *o);
+static sdp_media_t *media_dup(char **pp,
+ sdp_media_t const *o,
+ sdp_session_t *sdp);
+#ifdef nomore
+static size_t media_xtra_ex(sdp_media_t const *o,
+ sdp_connection_t const *c);
+static sdp_media_t *media_dup_ex(char **pp,
+ sdp_media_t const *o,
+ sdp_session_t *sdp,
+ sdp_connection_t *dst_c,
+ sdp_connection_t const *src_c);
+#endif
+static size_t media_xtra_all(sdp_media_t const *o);
+static sdp_media_t *media_dup_all(char **pp,
+ sdp_media_t const *o,
+ sdp_session_t *sdp);
+
+
+/** Define a function body duplicating an SDP structure. */
+#define SDP_DUP(type, name) \
+ sdp_##type##_t *rv; size_t size; char *p, *end; \
+ if (!name) return NULL; \
+ size = type##_xtra(name); \
+ p = su_alloc(h, size); end = p + size; \
+ rv = type##_dup(&p, name); \
+ assert(p == end); \
+ return rv;
+
+/** Define a function body duplicating a list of SDP structures. */
+#define SDP_LIST_DUP(type, name) \
+ sdp_##type##_t *rv; size_t size; char *p, *end; \
+ if (!name) return NULL; \
+ size = list_xtra_all((xtra_f*)type##_xtra, name); \
+ rv = su_alloc(h, size); p = (char *)rv; end = p + size; \
+ list_dup_all((dup_f*)type##_dup, &p, name); \
+ assert(p == end); \
+ return rv;
+
+/**Duplicate an SDP origin description.
+ *
+ * The function sdp_origin_dup() duplicates (deeply copies) an SDP origin
+ * description @a o allocating memory using memory @a home.
+ *
+ * @param h Memory home
+ * @param o SDP origin description to be duplicated
+ *
+ * @return
+ * If successful, a pointer to newly allocated sdp_origin_t structure is
+ * returned, otherwise NULL is returned.
+ */
+sdp_origin_t *sdp_origin_dup(su_home_t *h, sdp_origin_t const *o)
+{
+ SDP_DUP(origin, o);
+}
+
+/**Duplicate an SDP connection description.
+ *
+ * The function sdp_connection_dup() duplicates (deeply copies) an SDP
+ * connection description @a c allocating memory using memory @a home.
+ *
+ * @param h Memory home
+ * @param c SDP connection description to be duplicated
+ *
+ * @return
+ * If successful, a pointer to newly allocated sdp_connection_t structure is
+ * returned, otherwise NULL is returned.
+ */
+sdp_connection_t *sdp_connection_dup(su_home_t *h, sdp_connection_t const *c)
+{
+ SDP_LIST_DUP(connection, c);
+}
+
+/**Duplicate an SDP bandwidth description.
+ *
+ * The function sdp_bandwidth_dup() duplicates (deeply copies) an SDP
+ * bandwidth description @a b allocating memory using memory @a home.
+ *
+ * @param h Memory home
+ * @param b SDP bandwidth description to be duplicated
+ *
+ * @return
+ * If successful, a pointer to newly allocated sdp_bandwidth_t structure is
+ * returned, otherwise NULL is returned.
+ */
+sdp_bandwidth_t *sdp_bandwidth_dup(su_home_t *h, sdp_bandwidth_t const *b)
+{
+ SDP_LIST_DUP(bandwidth, b);
+}
+
+/**Duplicate an SDP time description.
+ *
+ * The function sdp_time_dup() duplicates (deeply copies) an SDP time
+ * description @a t allocating memory using memory @a home.
+ *
+ * @param h Memory home
+ * @param t SDP time description to be duplicated
+ *
+ * @return
+ * If successful, a pointer to newly allocated sdp_time_t structure is
+ * returned, otherwise NULL is returned.
+ */
+sdp_time_t *sdp_time_dup(su_home_t *h, sdp_time_t const *t)
+{
+ SDP_LIST_DUP(time, t);
+}
+
+/**Duplicate an SDP repeat description.
+ *
+ * The function sdp_repeat_dup() duplicates (deeply copies) an SDP repeat
+ * description @a r allocating memory using memory @a home.
+ *
+ * @param h Memory home
+ * @param r SDP repeat description to be duplicated
+ *
+ * @return
+ * If successful, a pointer to newly allocated sdp_repeat_t structure is
+ * returned, otherwise NULL is returned.
+ */
+sdp_repeat_t *sdp_repeat_dup(su_home_t *h, sdp_repeat_t const *r)
+{
+ SDP_DUP(repeat, r);
+}
+
+/**Duplicate an SDP zone description.
+ *
+ * The function sdp_zone_dup() duplicates (deeply copies) an SDP zone
+ * description @a z allocating memory using memory @a home.
+ *
+ * @param h Memory home
+ * @param z SDP zone description to be duplicated
+ *
+ * @return
+ * If successful, a pointer to newly allocated sdp_zone_t structure is
+ * returned, otherwise NULL is returned.
+ */
+sdp_zone_t *sdp_zone_dup(su_home_t *h, sdp_zone_t const *z)
+{
+ SDP_DUP(zone, z);
+}
+
+/**Duplicate an SDP key description.
+ *
+ * The function sdp_key_dup() duplicates (deeply copies) an SDP key
+ * description @a k allocating memory using memory @a home.
+ *
+ * @param h Memory home
+ * @param k SDP key description to be duplicated
+ *
+ * @return
+ * If successful, a pointer to newly allocated sdp_key_t structure is
+ * returned, otherwise NULL is returned.
+ */
+sdp_key_t *sdp_key_dup(su_home_t *h, sdp_key_t const *k)
+{
+ SDP_DUP(key, k);
+}
+
+/**Duplicate an SDP attribute list.
+ *
+ * The function sdp_attribute_dup() duplicates (deeply copies) an SDP
+ * attribute list @a a allocating memory using memory @a home.
+ *
+ * @param h Memory home
+ * @param a SDP attribute description to be duplicated
+ *
+ * @return
+ * If successful, a pointer to newly allocated sdp_attribute_t structure is
+ * returned, otherwise NULL is returned.
+ */
+sdp_attribute_t *sdp_attribute_dup(su_home_t *h, sdp_attribute_t const *a)
+{
+ SDP_LIST_DUP(attribute, a);
+}
+
+/**Duplicate an SDP list of text.
+ *
+ * The function sdp_list_dup() duplicates (deeply copies) an SDP text
+ * list @a l allocating memory using memory @a home.
+ *
+ * @param h Memory home
+ * @param l SDP list description to be duplicated
+ *
+ * @return
+ * If successful, a pointer to newly allocated sdp_list_t structure is
+ * returned, otherwise NULL is returned.
+ */
+sdp_list_t *sdp_list_dup(su_home_t *h, sdp_list_t const *l)
+{
+ SDP_LIST_DUP(list, l);
+}
+
+/**Duplicate an SDP rtpmap list.
+ *
+ * The function sdp_rtpmap_dup() duplicates (deeply copies) an SDP rtpmap
+ * list @a rm allocating memory using memory @a home.
+ *
+ * @param h Memory home
+ * @param rm SDP rtpmap description to be duplicated
+ *
+ * @return
+ * If successful, a pointer to newly allocated sdp_rtpmap_t structure is
+ * returned, otherwise NULL is returned.
+ */
+sdp_rtpmap_t *sdp_rtpmap_dup(su_home_t *h, sdp_rtpmap_t const *rm)
+{
+ SDP_LIST_DUP(rtpmap, rm);
+}
+
+/**Duplicate an SDP media description.
+ *
+ * The function sdp_media_dup() duplicates (deeply copies) an SDP media
+ * description @a m allocating memory using memory @a home.
+ *
+ * @param h Memory home
+ * @param m SDP media description to be duplicated
+ * @param sdp SDP session description to which the newly allocated
+ * media description is linked
+ *
+ * @return
+ * If successful, a pointer to newly allocated sdp_media_t structure is
+ * returned, otherwise NULL is returned.
+ */
+sdp_media_t *sdp_media_dup(su_home_t *h, sdp_media_t const *m,
+ sdp_session_t *sdp)
+{
+ sdp_media_t *rv; size_t size; char *p, *end;
+ size = media_xtra(m);
+ p = su_alloc(h, size); end = p + size;
+ rv = media_dup(&p, m, sdp);
+ assert(p == end);
+ return rv;
+}
+
+/**Duplicate an SDP media description.
+ *
+ * The function sdp_media_dup_all() duplicates (deeply copies) a list of SDP
+ * media descriptions @a m allocating memory using memory @a home.
+ *
+ * @param h Memory home
+ * @param m list of SDP media descriptions to be duplicated
+ * @param sdp SDP session description to which the newly allocated
+ * media descriptions are linked
+ *
+ * @return
+ * If successful, a pointer to a newly allocated list of sdp_media_t
+ * structures is returned, otherwise NULL is returned.
+ */
+sdp_media_t *sdp_media_dup_all(su_home_t *h, sdp_media_t const *m,
+ sdp_session_t *sdp)
+{
+ sdp_media_t *rv; size_t size; char *p, *end;
+ size = media_xtra_all(m);
+ p = su_alloc(h, size); end = p + size;
+ rv = media_dup_all(&p, m, sdp);
+ assert(p == end);
+ return rv;
+}
+
+#ifdef nomore /* really deprecated */
+/**Duplicate media description with common address.
+ *
+ * This function is provided in order to avoid duplicate @c c= lines. If
+ * the @c c= line in media description equals to @a src_c, it is not
+ * duplicated but replaced with @a dst_c instead.
+ *
+ * @param home Memory home
+ * @param src SDP media description to be duplicated
+ * @param sdp SDP session description to which the newly allocated
+ * media description is linked
+ * @param dst_c Connection description used instead of duplicate of @a src_c.
+ * @param src_c Connection description not to be duplicated
+
+ * @return
+ * If successful, a pointer to newly allocated sdp_media_t structure is
+ * returned, otherwise NULL is returned.
+ *
+ * @deprecated
+ * This function is deprecated. Use sdp_media_dup() instead.
+ */
+sdp_media_t *sdp_media_dup_ex(su_home_t *home,
+ sdp_media_t const *src,
+ sdp_session_t *sdp,
+ sdp_connection_t *dst_c,
+ sdp_connection_t const *src_c)
+{
+ sdp_media_t *rv; size_t size; char *p, *end;
+ size = media_xtra_all(src, src_c);
+ p = su_alloc(home, size); end = p + size;
+ rv = media_dup_all(&p, src, sdp, dst_c, src_c);
+ assert(p == end);
+ return rv;
+}
+#endif
+
+/* ---------------------------------------------------------------------- */
+
+static size_t origin_xtra(sdp_origin_t const *o)
+{
+ size_t rv = sizeof(*o);
+ STR_XTRA(rv, o->o_username);
+ PTR_XTRA(rv, o->o_address, connection_xtra);
+ return rv;
+}
+
+static
+sdp_origin_t *origin_dup(char **pp, sdp_origin_t const *src)
+{
+ char *p;
+ sdp_origin_t *o;
+
+ p = *pp;
+ STRUCT_DUP(p, o, src);
+ STR_DUP(p, o, src, o_username);
+ PTR_DUP(p, o, src, o_address, connection_dup);
+
+ assert((size_t)(p - *pp) == origin_xtra(src));
+ *pp = p;
+ return o;
+}
+
+static size_t connection_xtra(sdp_connection_t const *c)
+{
+ size_t rv = sizeof(*c);
+ STR_XTRA(rv, c->c_address);
+ return rv;
+}
+
+static
+sdp_connection_t *connection_dup(char **pp, sdp_connection_t const *src)
+{
+ char *p;
+ sdp_connection_t *c;
+
+ p = *pp;
+ STRUCT_DUP(p, c, src);
+ c->c_next = NULL;
+ STR_DUP(p, c, src, c_address);
+
+ assert((size_t)(p - *pp) == connection_xtra(src));
+ *pp = p;
+ return c;
+}
+
+static size_t bandwidth_xtra(sdp_bandwidth_t const *b)
+{
+ size_t rv = sizeof(*b);
+ STR_XTRA(rv, b->b_modifier_name);
+ return rv;
+}
+
+static
+sdp_bandwidth_t *bandwidth_dup(char **pp, sdp_bandwidth_t const *src)
+{
+ char *p;
+ sdp_bandwidth_t *b;
+
+ p = *pp;
+ STRUCT_DUP(p, b, src);
+ b->b_next = NULL;
+ STR_DUP(p, b, src, b_modifier_name);
+
+ assert((size_t)(p - *pp) == bandwidth_xtra(src));
+ *pp = p;
+ return b;
+}
+
+
+static size_t time_xtra(sdp_time_t const *t)
+{
+ size_t rv = sizeof(*t);
+ PTR_XTRA(rv, t->t_repeat, repeat_xtra);
+ PTR_XTRA(rv, t->t_zone, zone_xtra);
+ return rv;
+}
+
+static
+sdp_time_t *time_dup(char **pp, sdp_time_t const *src)
+{
+ char *p;
+ sdp_time_t *t;
+
+ p = *pp;
+ STRUCT_DUP(p, t, src);
+ t->t_next = NULL;
+ PTR_DUP(p, t, src, t_repeat, repeat_dup);
+ PTR_DUP(p, t, src, t_zone, zone_dup);
+
+ assert((size_t)(p - *pp) == time_xtra(src));
+ *pp = p;
+ return t;
+}
+
+
+static size_t repeat_xtra(sdp_repeat_t const *r)
+{
+ return (size_t)r->r_size;
+}
+
+static
+sdp_repeat_t *repeat_dup(char **pp, sdp_repeat_t const *src)
+{
+ char *p;
+ sdp_repeat_t *r;
+
+ p = *pp;
+ STRUCT_DUP2(p, r, src);
+
+ assert((size_t)(p - *pp) == repeat_xtra(src));
+ *pp = p;
+ return r;
+}
+
+
+static size_t zone_xtra(sdp_zone_t const *z)
+{
+ return z->z_size;
+}
+
+static
+sdp_zone_t *zone_dup(char **pp, sdp_zone_t const *src)
+{
+ char *p;
+ sdp_zone_t *z;
+
+ p = *pp;
+ STRUCT_DUP2(p, z, src);
+
+ assert((size_t)(p - *pp) == zone_xtra(src));
+ *pp = p;
+ return z;
+}
+
+
+static size_t key_xtra(sdp_key_t const *k)
+{
+ size_t rv = sizeof(*k);
+ STR_XTRA(rv, k->k_method_name);
+ STR_XTRA(rv, k->k_material);
+ return rv;
+}
+
+static
+sdp_key_t *key_dup(char **pp, sdp_key_t const *src)
+{
+ char *p;
+ sdp_key_t *k;
+
+ p = *pp;
+ STRUCT_DUP(p, k, src);
+ STR_DUP(p, k, src, k_method_name);
+ STR_DUP(p, k, src, k_material);
+
+ assert((size_t)(p - *pp) == key_xtra(src));
+ *pp = p;
+ return k;
+}
+
+
+static size_t attribute_xtra(sdp_attribute_t const *a)
+{
+ size_t rv = sizeof(*a);
+ STR_XTRA(rv, a->a_name);
+ STR_XTRA(rv, a->a_value);
+ return rv;
+}
+
+static
+sdp_attribute_t *attribute_dup(char **pp, sdp_attribute_t const *src)
+{
+ char *p;
+ sdp_attribute_t *a;
+
+ p = *pp;
+ STRUCT_DUP(p, a, src);
+ a->a_next = NULL;
+ STR_DUP(p, a, src, a_name);
+ STR_DUP(p, a, src, a_value);
+
+ assert((size_t)(p - *pp) == attribute_xtra(src));
+ *pp = p;
+ return a;
+}
+
+
+static size_t media_xtra(sdp_media_t const *m)
+{
+ size_t rv = sizeof(*m);
+
+ STR_XTRA(rv, m->m_type_name);
+ STR_XTRA(rv, m->m_proto_name);
+ LST_XTRA(rv, m->m_format, list_xtra);
+ LST_XTRA(rv, m->m_rtpmaps, rtpmap_xtra);
+ STR_XTRA(rv, m->m_information);
+ LST_XTRA(rv, m->m_connections, connection_xtra);
+ LST_XTRA(rv, m->m_bandwidths, bandwidth_xtra);
+ PTR_XTRA(rv, m->m_key, key_xtra);
+ LST_XTRA(rv, m->m_attributes, attribute_xtra);
+
+ return rv;
+}
+
+static
+sdp_media_t *media_dup(char **pp,
+ sdp_media_t const *src,
+ sdp_session_t *sdp)
+{
+ char *p;
+ sdp_media_t *m;
+
+ p = *pp;
+ STRUCT_DUP(p, m, src);
+ m->m_next = NULL;
+
+ STR_DUP(p, m, src, m_type_name);
+ STR_DUP(p, m, src, m_proto_name);
+ LST_DUP(p, m, src, m_format, list_dup);
+ LST_DUP(p, m, src, m_rtpmaps, rtpmap_dup);
+ STR_DUP(p, m, src, m_information);
+ LST_DUP(p, m, src, m_connections, connection_dup);
+ LST_DUP(p, m, src, m_bandwidths, bandwidth_dup);
+ PTR_DUP(p, m, src, m_key, key_dup);
+ LST_DUP(p, m, src, m_attributes, attribute_dup);
+
+ /* note! we must not implicitly use 'src->m_session' as it
+ might point to a temporary session */
+ m->m_session = sdp;
+
+ m->m_rejected = src->m_rejected;
+ m->m_mode = src->m_mode;
+
+ assert((size_t)(p - *pp) == media_xtra(src));
+ *pp = p;
+ return m;
+}
+
+#ifdef nomore
+static
+int media_xtra_ex(sdp_media_t const *m, sdp_connection_t const *c)
+{
+ int rv = 0;
+
+ for (; m; m = m->m_next) {
+ rv += STRUCT_ALIGN(rv);
+ rv += sizeof(*m);
+
+ STR_XTRA(rv, m->m_type_name);
+ STR_XTRA(rv, m->m_proto_name);
+ LST_XTRA(rv, m->m_format, list_xtra);
+ LST_XTRA(rv, m->m_rtpmaps, rtpmap_xtra);
+ STR_XTRA(rv, m->m_information);
+ if (c != m->m_connections)
+ LST_XTRA(rv, m->m_connections, connection_xtra);
+ LST_XTRA(rv, m->m_bandwidths, bandwidth_xtra);
+ PTR_XTRA(rv, m->m_key, key_xtra);
+ LST_XTRA(rv, m->m_attributes, attribute_xtra);
+ }
+
+ return rv;
+}
+
+static
+sdp_media_t *media_dup_ex(char **pp,
+ sdp_media_t const *src,
+ sdp_session_t *sdp,
+ sdp_connection_t *dst_c,
+ sdp_connection_t const *src_c)
+{
+ char *p;
+ sdp_media_t *retval = NULL, *m, **mm = &retval;
+ int xtra = media_xtra_ex(src, src_c);
+
+ p = *pp;
+
+ for (; src; src = src->m_next) {
+ p += STRUCT_ALIGN(p);
+ STRUCT_DUP(p, m, src);
+ m->m_next = NULL;
+
+ STR_DUP(p, m, src, m_type_name);
+ STR_DUP(p, m, src, m_proto_name);
+ LST_DUP(p, m, src, m_format, list_dup);
+ LST_DUP(p, m, src, m_rtpmaps, rtpmap_dup);
+ STR_DUP(p, m, src, m_information);
+ if (src_c != src->m_connections)
+ LST_DUP(p, m, src, m_connections, connection_dup);
+ else
+ m->m_connections = dst_c;
+ LST_DUP(p, m, src, m_bandwidths, bandwidth_dup);
+ PTR_DUP(p, m, src, m_key, key_dup);
+ LST_DUP(p, m, src, m_attributes, attribute_dup);
+
+ /* note! we must not implicitly use 'src->m_session' as it
+ might point to a temporary session */
+ m->m_session = sdp;
+
+ m->m_rejected = src->m_rejected;
+ m->m_mode = src->m_mode;
+
+ assert(m);
+ *mm = m; mm = &m->m_next;
+ }
+
+ assert(p - *pp == xtra);
+
+
+ *pp = p;
+
+ return retval;
+}
+#endif
+
+static size_t media_xtra_all(sdp_media_t const *m)
+{
+ size_t rv = 0;
+
+ for (; m; m = m->m_next) {
+ rv += STRUCT_ALIGN(rv);
+ rv += media_xtra(m);
+ }
+
+ return rv;
+}
+
+static
+sdp_media_t *media_dup_all(char **pp,
+ sdp_media_t const *src,
+ sdp_session_t *sdp)
+{
+ char *p;
+ sdp_media_t *retval = NULL, *m, **mm = &retval;
+
+ p = *pp;
+
+ for (; src; src = src->m_next) {
+ p += STRUCT_ALIGN(p);
+ m = media_dup(&p, src, sdp);
+ assert(m);
+ *mm = m; mm = &m->m_next;
+ }
+
+ *pp = p;
+
+ return retval;
+}
+
+static size_t list_xtra(sdp_list_t const *l)
+{
+ size_t rv = sizeof(*l);
+ rv += strlen(l->l_text) + 1;
+ return rv;
+}
+
+static
+sdp_list_t *list_dup(char **pp, sdp_list_t const *src)
+{
+ char *p;
+ sdp_list_t *l;
+
+ p = *pp;
+ STRUCT_DUP(p, l, src);
+ l->l_next = NULL;
+ STR_DUP(p, l, src, l_text);
+
+ assert((size_t)(p - *pp) == list_xtra(src));
+ *pp = p;
+ return l;
+}
+
+
+static size_t rtpmap_xtra(sdp_rtpmap_t const *rm)
+{
+ size_t rv = sizeof(*rm);
+ STR_XTRA(rv, rm->rm_encoding);
+ STR_XTRA(rv, rm->rm_params);
+ STR_XTRA(rv, rm->rm_fmtp);
+ return rv;
+}
+
+static
+sdp_rtpmap_t *rtpmap_dup(char **pp, sdp_rtpmap_t const *src)
+{
+ char *p;
+ sdp_rtpmap_t *rm;
+
+ p = *pp;
+ STRUCT_DUP(p, rm, src);
+ rm->rm_next = NULL;
+ STR_DUP(p, rm, src, rm_encoding);
+ STR_DUP(p, rm, src, rm_params);
+ STR_DUP(p, rm, src, rm_fmtp);
+
+ assert((size_t)(p - *pp) == rtpmap_xtra(src));
+ *pp = p;
+ return rm;
+}
+
+/** Return total size of a list, including size of all nodes */
+static size_t list_xtra_all(xtra_f *xtra, void const *v)
+{
+ size_t rv = 0;
+ sdp_list_t const *l;
+
+ for (l = v; l; l = l->l_next) {
+ rv += STRUCT_ALIGN(rv);
+ rv += xtra(l);
+ }
+
+ return rv;
+}
+
+static
+void *list_dup_all(dup_f *dup, char **pp, void const *vsrc)
+{
+ char *p;
+ sdp_list_t const *src;
+ sdp_list_t *retval = NULL, *l, **ll = &retval;
+
+ p = *pp;
+
+ for (src = vsrc; src; src = src->l_next) {
+ p += STRUCT_ALIGN(p);
+ l = dup(&p, src);
+ assert(l);
+ *ll = l; ll = &l->l_next;
+ }
+
+ *pp = p;
+
+ return retval;
+}
+
+#if 0
+static size_t XXX_xtra(sdp_XXX_t const *YYY)
+{
+ size_t rv = sizeof(*YYY);
+ rv += strlen(YYY->YYY_encoding) + 1;
+ if (YYY->YYY_params);
+ rv += strlen(YYY->YYY_params) + 1;
+ return rv;
+}
+
+static
+sdp_XXX_t *XXX_dup(char **pp, sdp_XXX_t const *src)
+{
+ char *p;
+ sdp_XXX_t *YYY;
+
+ p = *pp; ASSERT_STRUCT_ALIGN(p);
+ YYY = memcpy(p, src, src->YYY_size);
+ p += src->YYY_size;
+ YYY->YYY_next = NULL;
+ ZZZ
+ *pp = p;
+ return YYY;
+}
+
+#endif
+
+static size_t session_xtra(sdp_session_t const *sdp)
+{
+ size_t rv = sizeof(*sdp);
+
+ PTR_XTRA(rv, sdp->sdp_origin, origin_xtra);
+ STR_XTRA(rv, sdp->sdp_subject);
+ STR_XTRA(rv, sdp->sdp_information);
+ STR_XTRA(rv, sdp->sdp_uri);
+ LST_XTRA(rv, sdp->sdp_emails, list_xtra);
+ LST_XTRA(rv, sdp->sdp_phones, list_xtra);
+ LST_XTRA(rv, sdp->sdp_connection, connection_xtra);
+ LST_XTRA(rv, sdp->sdp_bandwidths, bandwidth_xtra);
+ LST_XTRA(rv, sdp->sdp_time, time_xtra);
+ PTR_XTRA(rv, sdp->sdp_key, key_xtra);
+ LST_XTRA(rv, sdp->sdp_attributes, attribute_xtra);
+ STR_XTRA(rv, sdp->sdp_charset);
+ MED_XTRA_ALL(rv, sdp->sdp_media);
+
+ return rv;
+}
+
+static
+sdp_session_t *session_dup(char **pp, sdp_session_t const *src)
+{
+ char *p;
+ sdp_session_t *sdp;
+
+ p = *pp;
+ STRUCT_DUP(p, sdp, src);
+ sdp->sdp_next = NULL;
+
+ PTR_DUP(p, sdp, src, sdp_origin, origin_dup);
+ STR_DUP(p, sdp, src, sdp_subject);
+ STR_DUP(p, sdp, src, sdp_information);
+ STR_DUP(p, sdp, src, sdp_uri);
+ LST_DUP(p, sdp, src, sdp_emails, list_dup);
+ LST_DUP(p, sdp, src, sdp_phones, list_dup);
+ LST_DUP(p, sdp, src, sdp_connection, connection_dup);
+ LST_DUP(p, sdp, src, sdp_bandwidths, bandwidth_dup);
+ LST_DUP(p, sdp, src, sdp_time, time_dup);
+ PTR_DUP(p, sdp, src, sdp_key, key_dup);
+ LST_DUP(p, sdp, src, sdp_attributes, attribute_dup);
+ STR_DUP(p, sdp, src, sdp_charset);
+ MED_DUP_ALL(p, sdp, src, sdp_media);
+
+ assert((size_t)(p - *pp) == session_xtra(src));
+ *pp = p;
+ return sdp;
+}
+
+/**Duplicate an SDP session description.
+ *
+ * The function sdp_session_dup() duplicates (deeply copies) an SDP
+ * session description @a sdp allocating memory using memory @a home.
+ *
+ * @param h Memory home
+ * @param sdp SDP session description to be duplicated
+ *
+ * @return
+ * If successful, a pointer to newly allocated sdp_session_t structure is
+ * returned, otherwise NULL is returned.
+ */
+
+sdp_session_t *sdp_session_dup(su_home_t *h, sdp_session_t const *sdp)
+{
+ SDP_DUP(session, sdp);
+}
+
+/* ---------------------------------------------------------------------- */
+
+static size_t session_without_media_xtra(sdp_session_t const *sdp)
+{
+ size_t rv = sizeof(*sdp);
+
+ PTR_XTRA(rv, sdp->sdp_origin, origin_xtra);
+ STR_XTRA(rv, sdp->sdp_subject);
+ STR_XTRA(rv, sdp->sdp_information);
+ STR_XTRA(rv, sdp->sdp_uri);
+ LST_XTRA(rv, sdp->sdp_emails, list_xtra);
+ LST_XTRA(rv, sdp->sdp_phones, list_xtra);
+ LST_XTRA(rv, sdp->sdp_connection, connection_xtra);
+ LST_XTRA(rv, sdp->sdp_bandwidths, bandwidth_xtra);
+ LST_XTRA(rv, sdp->sdp_time, time_xtra);
+ PTR_XTRA(rv, sdp->sdp_key, key_xtra);
+ LST_XTRA(rv, sdp->sdp_attributes, attribute_xtra);
+ STR_XTRA(rv, sdp->sdp_charset);
+
+ return rv;
+}
+
+static
+sdp_session_t *session_without_media_dup(char **pp, sdp_session_t const *src)
+{
+ char *p;
+ sdp_session_t *sdp;
+
+ p = *pp;
+ STRUCT_DUP(p, sdp, src);
+ sdp->sdp_next = NULL;
+
+ PTR_DUP(p, sdp, src, sdp_origin, origin_dup);
+ STR_DUP(p, sdp, src, sdp_subject);
+ STR_DUP(p, sdp, src, sdp_information);
+ STR_DUP(p, sdp, src, sdp_uri);
+ LST_DUP(p, sdp, src, sdp_emails, list_dup);
+ LST_DUP(p, sdp, src, sdp_phones, list_dup);
+ LST_DUP(p, sdp, src, sdp_connection, connection_dup);
+ LST_DUP(p, sdp, src, sdp_bandwidths, bandwidth_dup);
+ LST_DUP(p, sdp, src, sdp_time, time_dup);
+ PTR_DUP(p, sdp, src, sdp_key, key_dup);
+ LST_DUP(p, sdp, src, sdp_attributes, attribute_dup);
+ STR_DUP(p, sdp, src, sdp_charset);
+
+ sdp->sdp_media = NULL;
+
+ assert((size_t)(p - *pp) == session_without_media_xtra(src));
+ *pp = p;
+ return sdp;
+}
+
+/* SDP_DUP macro requires this */
+typedef sdp_session_t sdp_session_without_media_t;
+
+/**Duplicate an SDP session description without media descriptions.
+ *
+ * The function sdp_session_dup() duplicates (deeply copies) an SDP session
+ * description @a sdp allocating memory using memory @a home. It does not
+ * copy the media descriptions, however.
+ *
+ * @param h memory h
+ * @param sdp SDP session description to be duplicated
+ *
+ * @return
+ * If successful, a pointer to newly allocated sdp_session_t structure is
+ * returned, otherwise NULL is returned.
+ */
+
+sdp_session_t *sdp_session_dup_without_media(su_home_t *h,
+ sdp_session_t const *sdp)
+{
+ SDP_DUP(session_without_media, sdp);
+}
+
+/* ---------------------------------------------------------------------- */
+/* SDP Tag classes */
+
+#include <sofia-sip/su_tag_class.h>
+
+size_t sdptag_session_xtra(tagi_t const *t, size_t offset)
+{
+ sdp_session_t const *sdp = (sdp_session_t *)t->t_value;
+
+ if (sdp)
+ return STRUCT_ALIGN(offset) + session_xtra(sdp);
+ else
+ return 0;
+}
+
+tagi_t *sdptag_session_dup(tagi_t *dst, tagi_t const *src, void **bb)
+{
+ sdp_session_t *sdp;
+ sdp_session_t const *srcsdp;
+ char *b;
+
+ assert(src); assert(*bb);
+
+ b = *bb;
+ b += STRUCT_ALIGN(b);
+ srcsdp = (sdp_session_t *)src->t_value;
+
+ sdp = session_dup(&b, srcsdp);
+
+ dst->t_tag = src->t_tag;
+ dst->t_value = (tag_value_t)sdp;
+
+ *bb = b;
+
+ return dst + 1;
+}
+
+int sdptag_session_snprintf(tagi_t const *t, char b[], size_t size)
+{
+ sdp_session_t const *sdp;
+ sdp_printer_t *print;
+ size_t retval;
+
+ assert(t);
+
+ if (!t || !t->t_value) {
+ if (size && b) b[0] = 0;
+ return 0;
+ }
+
+ sdp = (sdp_session_t const *)t->t_value;
+
+ print = sdp_print(NULL, sdp, b, size, 0);
+
+ retval = sdp_message_size(print);
+
+ sdp_printer_free(print);
+
+ return (int)retval;
+}
+
+/** Tag class for SDP tags. @HIDE */
+tag_class_t sdptag_session_class[1] =
+ {{
+ sizeof(sdptag_session_class),
+ /* tc_next */ NULL,
+ /* tc_len */ NULL,
+ /* tc_move */ NULL,
+ /* tc_xtra */ sdptag_session_xtra,
+ /* tc_dup */ sdptag_session_dup,
+ /* tc_free */ NULL,
+ /* tc_find */ NULL,
+ /* tc_snprintf */ sdptag_session_snprintf,
+ /* tc_filter */ NULL /* msgtag_str_filter */,
+ /* tc_ref_set */ t_ptr_ref_set,
+ }};
+
+
+/* ---------------------------------------------------------------------- */
+
+/* Compare two string pointers */
+static inline
+int str0cmp(char const *a, char const *b)
+{
+ if (a == NULL) a = "";
+ if (b == NULL) b = "";
+ return strcmp(a, b);
+}
+
+/* Compare two string pointers ignoring case. */
+static inline
+int str0casecmp(char const *a, char const *b)
+{
+ if (a == NULL) a = "";
+ if (b == NULL) b = "";
+ return strcasecmp(a, b);
+}
+
+/** Compare two session descriptions
+ */
+int sdp_session_cmp(sdp_session_t const *a, sdp_session_t const *b)
+{
+ int rv;
+ sdp_bandwidth_t const *ab, *bb;
+ sdp_attribute_t const *aa, *ba;
+ sdp_media_t const *am, *bm;
+
+ if ((rv = (a != NULL) - (b != NULL)))
+ return rv;
+ if (a == b)
+ return 0;
+ if ((rv = (a->sdp_version[0] - b->sdp_version[0])))
+ return rv;
+ if ((rv = sdp_origin_cmp(a->sdp_origin, b->sdp_origin)))
+ return rv;
+ if ((rv = str0cmp(a->sdp_subject, b->sdp_subject)))
+ return rv;
+ if ((rv = str0cmp(a->sdp_information, b->sdp_information)))
+ return rv;
+ if ((rv = str0cmp(a->sdp_uri, b->sdp_uri)))
+ return rv;
+ if ((rv = sdp_list_cmp(a->sdp_emails, b->sdp_emails)))
+ return rv;
+ if ((rv = sdp_list_cmp(a->sdp_phones, b->sdp_phones)))
+ return rv;
+ if ((rv = sdp_connection_cmp(a->sdp_connection, b->sdp_connection)))
+ return rv;
+
+ for (ab = a->sdp_bandwidths, bb = b->sdp_bandwidths;
+ ab || bb;
+ ab = ab->b_next, bb = bb->b_next)
+ if ((rv = sdp_bandwidth_cmp(a->sdp_bandwidths, b->sdp_bandwidths)))
+ return rv;
+
+ if ((rv = sdp_time_cmp(a->sdp_time, b->sdp_time)))
+ return rv;
+ if ((rv = sdp_key_cmp(a->sdp_key, b->sdp_key)))
+ return rv;
+
+ for (aa = a->sdp_attributes, ba = b->sdp_attributes;
+ aa || bb;
+ aa = aa->a_next, ba = ba->a_next)
+ if ((rv = sdp_attribute_cmp(aa, ba)))
+ return rv;
+
+ for (am = a->sdp_media, bm = b->sdp_media;
+ am || bb;
+ am = am->m_next, bm = bm->m_next)
+ if ((rv = sdp_media_cmp(am, bm)))
+ return rv;
+
+ return 0;
+}
+
+/** Compare two origin fields
+ */
+int sdp_origin_cmp(sdp_origin_t const *a, sdp_origin_t const *b)
+{
+ int rv;
+
+ if ((rv = (a != NULL) - (b != NULL)))
+ return rv;
+ if (a == b)
+ return 0;
+ if (a->o_version != b->o_version)
+ return a->o_version < b->o_version ? -1 : 1;
+ if (a->o_id != b->o_id)
+ return a->o_id < b->o_id ? -1 : 1;
+ if ((rv = strcasecmp(a->o_username, b->o_username)))
+ return rv;
+ if ((rv = strcasecmp(a->o_address->c_address, b->o_address->c_address)))
+ return rv;
+
+ return 0;
+}
+
+/** Compare two connection fields
+ */
+int sdp_connection_cmp(sdp_connection_t const *a, sdp_connection_t const *b)
+{
+ if (a == b)
+ return 0;
+ if ((a != NULL) != (b != NULL))
+ return (a != NULL) < (b != NULL) ? -1 : 1;
+
+ if (a->c_nettype != b->c_nettype)
+ return a->c_nettype < b->c_nettype ? -1 : 1;
+ if (a->c_addrtype != b->c_addrtype)
+ return a->c_addrtype < b->c_addrtype ? -1 : 1;
+ if (a->c_ttl != b->c_ttl)
+ return a->c_ttl < b->c_ttl ? -1 : 1;
+ if (a->c_groups != b->c_groups)
+ return a->c_groups < b->c_groups ? -1 : 1;
+
+ return strcmp(a->c_address, b->c_address);
+}
+
+/** Compare two bandwidth (b=) fields */
+int sdp_bandwidth_cmp(sdp_bandwidth_t const *a, sdp_bandwidth_t const *b)
+{
+ int rv;
+
+ if (a == b)
+ return 0;
+ if ((a != NULL) != (b != NULL))
+ return (a != NULL) < (b != NULL) ? -1 : 1;
+
+ if (a->b_modifier != b->b_modifier)
+ return a->b_modifier < b->b_modifier ? -1 : 1;
+ if (a->b_modifier == sdp_bw_x &&
+ (rv = strcmp(a->b_modifier_name, b->b_modifier_name)))
+ return rv;
+
+ if (a->b_value != b->b_value)
+ return a->b_value < b->b_value ? -1 : 1;
+
+ return 0;
+}
+
+/** Compare two time fields */
+int sdp_time_cmp(sdp_time_t const *a, sdp_time_t const *b)
+{
+ int rv;
+
+ if ((rv = (a != NULL) - (b != NULL)))
+ return rv;
+ if (a == b)
+ return 0;
+ if (a->t_start != b->t_start)
+ return a->t_start < b->t_start ? -1 : 1;
+ if (a->t_stop != b->t_stop)
+ return a->t_stop < b->t_stop ? -1 : 1;
+ if ((rv = sdp_zone_cmp(a->t_zone, b->t_zone)))
+ return rv;
+ if ((rv = sdp_repeat_cmp(a->t_repeat, b->t_repeat)))
+ return rv;
+ return 0;
+}
+
+/** Compare two repeat (r=) fields */
+int sdp_repeat_cmp(sdp_repeat_t const *a, sdp_repeat_t const *b)
+{
+ int i, n;
+
+ if (a == b)
+ return 0;
+ if ((a != NULL) != (b != NULL))
+ return (a != NULL) < (b != NULL) ? -1 : 1;
+
+ if (a->r_interval != b->r_interval)
+ return a->r_interval < b->r_interval ? -1 : 1;
+ if (a->r_duration != b->r_duration)
+ return a->r_duration < b->r_duration ? -1 : 1;
+ n = a->r_number_of_offsets < b->r_number_of_offsets
+ ? a->r_number_of_offsets : b->r_number_of_offsets;
+ for (i = 0; i < n; i++)
+ if (a->r_offsets[i] != b->r_offsets[i])
+ return a->r_offsets[i] < b->r_offsets[i] ? -1 : 1;
+
+ if (a->r_number_of_offsets != b->r_number_of_offsets)
+ return a->r_number_of_offsets < b->r_number_of_offsets ? -1 : 1;
+
+ return 0;
+ }
+
+/** Compare two zone (z=) fields */
+int sdp_zone_cmp(sdp_zone_t const *a, sdp_zone_t const *b)
+{
+ int i, n;
+
+ if (a == b)
+ return 0;
+ if ((a != NULL) != (b != NULL))
+ return (a != NULL) < (b != NULL) ? -1 : 1;
+
+ n = a->z_number_of_adjustments < b->z_number_of_adjustments
+ ? a->z_number_of_adjustments : b->z_number_of_adjustments;
+ for (i = 0; i < n; i++) {
+ if (a->z_adjustments[i].z_at != b->z_adjustments[i].z_at)
+ return a->z_adjustments[i].z_at < b->z_adjustments[i].z_at ? -1 : 1;
+ if (a->z_adjustments[i].z_offset != b->z_adjustments[i].z_offset)
+ return a->z_adjustments[i].z_offset < b->z_adjustments[i].z_offset
+ ? -1 : 1;
+ }
+
+ if (a->z_number_of_adjustments != b->z_number_of_adjustments)
+ return a->z_number_of_adjustments < b->z_number_of_adjustments ? -1 : 1;
+
+ return 0;
+}
+
+/** Compare two key (k=) fields */
+int sdp_key_cmp(sdp_key_t const *a, sdp_key_t const *b)
+{
+ int rv;
+
+ if (a == b)
+ return 0;
+ if ((a != NULL) != (b != NULL))
+ return (a != NULL) < (b != NULL) ? -1 : 1;
+
+ if (a->k_method != b->k_method)
+ return a->k_method < b->k_method ? -1 : 1;
+ if (a->k_method == sdp_key_x &&
+ (rv = str0cmp(a->k_method_name, b->k_method_name)))
+ return rv;
+ return str0cmp(a->k_material, b->k_material);
+}
+
+/** Compare two attribute (a=) fields */
+int sdp_attribute_cmp(sdp_attribute_t const *a, sdp_attribute_t const *b)
+{
+ int rv;
+
+ if (a == b)
+ return 0;
+ if ((a != NULL) != (b != NULL))
+ return (a != NULL) < (b != NULL) ? -1 : 1;
+
+ if ((rv = str0cmp(a->a_name, b->a_name)))
+ return rv;
+ return str0cmp(a->a_value, b->a_value);
+}
+
+/** Compare two rtpmap structures. */
+int sdp_rtpmap_cmp(sdp_rtpmap_t const *a, sdp_rtpmap_t const *b)
+{
+ int rv;
+
+ if (a == b)
+ return 0;
+ if ((a != NULL) != (b != NULL))
+ return (a != NULL) < (b != NULL) ? -1 : 1;
+
+ if (a->rm_pt != b->rm_pt)
+ return a->rm_pt < b->rm_pt ? -1 : 1;
+
+ /* Case insensitive encoding */
+ if ((rv = str0cmp(a->rm_encoding, b->rm_encoding)))
+ return rv;
+ /* Rate */
+ if (a->rm_rate != b->rm_rate)
+ return a->rm_rate < b->rm_rate ? -1 : 1;
+
+ {
+ char const *a_param = "1", *b_param = "1";
+
+ if (a->rm_params)
+ a_param = a->rm_params;
+ if (b->rm_params)
+ b_param = b->rm_params;
+
+ rv = strcasecmp(a_param, b_param);
+
+ if (rv)
+ return rv;
+ }
+
+ return str0casecmp(a->rm_fmtp, b->rm_fmtp);
+}
+
+/** Compare two lists. */
+int sdp_list_cmp(sdp_list_t const *a, sdp_list_t const *b)
+{
+ int rv;
+
+ for (;a || b; a = a->l_next, b = b->l_next) {
+ if (a == b)
+ return 0;
+ if ((a != NULL) != (b != NULL))
+ return (a != NULL) < (b != NULL) ? -1 : 1;
+ if ((rv = str0cmp(a->l_text, b->l_text)))
+ return rv;
+ }
+
+ return 0;
+}
+
+/** Compare two media (m=) fields */
+int sdp_media_cmp(sdp_media_t const *a, sdp_media_t const *b)
+{
+ int rv;
+
+ sdp_connection_t const *ac, *bc;
+ sdp_bandwidth_t const *ab, *bb;
+ sdp_rtpmap_t const *arm, *brm;
+ sdp_attribute_t const *aa, *ba;
+
+ if (a == b)
+ return 0;
+ if ((rv = (a != NULL) - (b != NULL)))
+ return rv;
+
+ if (a->m_type != b->m_type)
+ return a->m_type < b->m_type ? -1 : 1;
+ if (a->m_type == sdp_media_x)
+ if ((rv = str0cmp(a->m_type_name, b->m_type_name)))
+ return rv;
+ if (a->m_port != b->m_port)
+ return a->m_port < b->m_port ? -1 : 1;
+
+ if (a->m_port == 0 /* && b->m_port == 0 */)
+ /* Ignore transport protocol and media list if media has been rejected */
+ return 0;
+
+ if (a->m_number_of_ports != b->m_number_of_ports)
+ return a->m_number_of_ports < b->m_number_of_ports ? -1 : 1;
+
+ if (a->m_proto != b->m_proto)
+ return a->m_proto < b->m_proto ? -1 : 1;
+ if (a->m_proto == sdp_media_x)
+ if ((rv = str0cmp(a->m_proto_name, b->m_proto_name)))
+ return rv;
+
+ if (a->m_mode != b->m_mode)
+ return a->m_mode < b->m_mode ? -1 : 1;
+
+ for (arm = a->m_rtpmaps, brm = b->m_rtpmaps;
+ arm || brm;
+ arm = arm->rm_next, brm = brm->rm_next)
+ if ((rv = sdp_rtpmap_cmp(arm, brm)))
+ return rv;
+
+ if ((rv = sdp_list_cmp(a->m_format, b->m_format)))
+ return rv;
+
+ if ((rv = str0cmp(a->m_information, b->m_information)))
+ return rv;
+
+ for (ac = a->m_connections, bc = b->m_connections;
+ ac || bc;
+ ac = ac->c_next, bc = bc->c_next)
+ if ((rv = sdp_connection_cmp(ac, bc)))
+ return rv;
+
+ for (ab = a->m_bandwidths, bb = b->m_bandwidths;
+ ab || bb;
+ ab = ab->b_next, bb = bb->b_next)
+ if ((rv = sdp_bandwidth_cmp(a->m_bandwidths, b->m_bandwidths)))
+ return rv;
+
+ if ((rv = sdp_key_cmp(a->m_key, b->m_key)))
+ return rv;
+
+ for (aa = a->m_attributes, ba = b->m_attributes;
+ aa || bb;
+ aa = aa->a_next, ba = ba->a_next)
+ if ((rv = sdp_attribute_cmp(aa, ba)))
+ return rv;
+
+ return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+sdp_connection_t *sdp_media_connections(sdp_media_t const *m)
+{
+ if (m) {
+ if (m->m_connections)
+ return m->m_connections;
+ if (m->m_session)
+ return m->m_session->sdp_connection;
+ }
+ return NULL;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/** Find named attribute from given list. */
+sdp_attribute_t *sdp_attribute_find(sdp_attribute_t const *a, char const *name)
+{
+ for (; a; a = a->a_next) {
+ if (strcasecmp(a->a_name, name) == 0)
+ break;
+ }
+
+ return (sdp_attribute_t *)a;
+}
+
+/** Find named attribute from given lists (a or a2). */
+sdp_attribute_t *sdp_attribute_find2(sdp_attribute_t const *a,
+ sdp_attribute_t const *a2,
+ char const *name)
+{
+ for (; a; a = a->a_next) {
+ if (strcasecmp(a->a_name, name) == 0)
+ break;
+ }
+
+ if (a == 0)
+ for (a = a2; a; a = a->a_next) {
+ if (strcasecmp(a->a_name, name) == 0)
+ break;
+ }
+
+ return (sdp_attribute_t *)a;
+}
+
+/** Get session mode from attribute list. */
+sdp_mode_t sdp_attribute_mode(sdp_attribute_t const *a, sdp_mode_t defmode)
+{
+ for (; a; a = a->a_next) {
+ if (strcasecmp(a->a_name, "sendrecv") == 0)
+ return sdp_sendrecv;
+ if (strcasecmp(a->a_name, "inactive") == 0)
+ return sdp_inactive;
+ if (strcasecmp(a->a_name, "recvonly") == 0)
+ return sdp_recvonly;
+ if (strcasecmp(a->a_name, "sendonly") == 0)
+ return sdp_sendonly;
+ }
+
+ return defmode;
+}
+
+/** Convert session mode as #sdp_attribute_t structure. */
+sdp_attribute_t *sdp_attribute_by_mode(su_home_t *home, sdp_mode_t mode)
+{
+ sdp_attribute_t *a;
+ char const *name;
+
+ if (mode == sdp_inactive)
+ name = "inactive";
+ else if (mode == sdp_sendonly)
+ name = "sendonly";
+ else if (mode == sdp_recvonly)
+ name = "recvonly";
+ else if (mode == sdp_sendrecv)
+ name = "sendrecv";
+ else
+ return NULL;
+
+ a = su_salloc(home, sizeof(*a));
+ if (a)
+ a->a_name = name;
+
+ return a;
+}
+
+/** Find a mapped attribute.
+ *
+ * A mapped attribute has form 'a=<name>:<pt> <value>' where pt is a RTP
+ * payload type, integer in range 0..127. For example, "a=atmmap" [@RFC3108]
+ * is a mapped attribute. Note that common mapped attributes, "a=rtpmap" and
+ * "a=fmtp" are already parsed as list of #sdp_rtpmap_t in #sdp_media_t.
+ *
+ * @param a pointer to first attribute in the list
+ * @param name name of the attribute
+ * @param pt payload type number (must be 0..127)
+ * @param return_result return value parameter for mapped attribute value
+ *
+ * @return Pointer to a matching attribute structure, or NULL.
+ *
+ * If a matching attribute is found, @a return_result will point to part of
+ * the attribute after the payload type and whitespace.
+ */
+sdp_attribute_t *sdp_attribute_mapped_find(sdp_attribute_t const *a,
+ char const *name,
+ int pt, char **return_result)
+{
+ char pt_value[4];
+ size_t pt_len;
+
+ if (return_result)
+ *return_result = NULL;
+
+ if (0 > pt || pt > 127)
+ return NULL;
+
+ snprintf(pt_value, sizeof(pt_value), "%u", (unsigned)pt);
+ pt_len = strlen(pt_value);
+
+ for (; (a = sdp_attribute_find(a, name)); a = a->a_next) {
+ char const *value = a->a_value;
+ size_t wlen;
+
+ if (strncmp(value, pt_value, pt_len))
+ continue;
+
+ wlen = strspn(value + pt_len, " \t");
+
+ if (wlen == 0 || value[pt_len + wlen] == '\0')
+ continue;
+
+ if (return_result)
+ *return_result = (char *)value + pt_len + wlen;
+
+ return (sdp_attribute_t *)a;
+ }
+
+ return NULL;
+}
+
+/** Append a (list of) attribute(s) to a list of attributes. */
+void sdp_attribute_append(sdp_attribute_t **list,
+ sdp_attribute_t const *a)
+{
+ assert(list);
+
+ if (list == NULL || a == NULL)
+ return;
+
+ for (;*list; list = &(*list)->a_next)
+ ;
+
+ *list = (sdp_attribute_t *)a;
+}
+
+/**Replace or append a attribute within a list of attributes.
+ *
+ * @retval 1 if replaced existing attribute
+ * @retval 0 if attribute was appended
+ * @retval -1 upon an error
+ */
+int sdp_attribute_replace(sdp_attribute_t **list,
+ sdp_attribute_t *a,
+ sdp_attribute_t **return_replaced)
+{
+ sdp_attribute_t *replaced;
+
+ assert(list);
+
+ if (return_replaced)
+ *return_replaced = NULL;
+
+ if (list == NULL || a == NULL)
+ return -1;
+
+ assert(a->a_name != NULL); assert(a->a_next == NULL);
+
+ for (; *list; list = &(*list)->a_next) {
+ if (strcasecmp((*list)->a_name, a->a_name) == 0)
+ break;
+ }
+
+ replaced = *list, *list = a;
+
+ if (replaced) {
+ a->a_next = replaced->a_next;
+ replaced->a_next = NULL;
+
+ if (return_replaced)
+ *return_replaced = replaced;
+
+ return 1;
+ }
+
+ return 0;
+}
+
+/** Remove a named attribute from a list of attributes. */
+sdp_attribute_t *sdp_attribute_remove(sdp_attribute_t **list,
+ char const *name)
+{
+ sdp_attribute_t *a;
+
+ assert(list);
+
+ if (list == NULL)
+ return NULL;
+ if (name == NULL)
+ return NULL;
+
+ for (a = *list; a; list = &a->a_next, a = *list) {
+ if (strcasecmp(name, a->a_name) == 0)
+ break;
+ }
+
+ if (a) {
+ *list = a->a_next;
+ a->a_next = NULL;
+ }
+
+ return a;
+}
+
+/* Return 1 if m= line struct matches with given type and name */
+unsigned sdp_media_match(sdp_media_t const *m,
+ sdp_media_e type,
+ sdp_text_t *type_name,
+ sdp_proto_e proto,
+ sdp_text_t *proto_name)
+{
+ if (m == NULL)
+ return 0;
+
+ if (type == sdp_media_any || m->m_type == sdp_media_any)
+ return 1;
+
+ if (type_name == NULL)
+ type_name = "";
+
+ if (type != m->m_type ||
+ (type == sdp_media_x && strcasecmp(m->m_type_name, type_name)))
+ return 0;
+
+ if (proto == sdp_proto_any || m->m_proto == sdp_proto_any)
+ return 1;
+
+ if (proto_name == NULL)
+ proto_name = "";
+
+ if (proto != m->m_proto ||
+ (proto == sdp_proto_x && strcasecmp(m->m_proto_name, proto_name)))
+ return 0;
+
+ return 1;
+}
+
+/* Return 1 if media type and protocol of m= line structs matches */
+unsigned sdp_media_match_with(sdp_media_t const *a,
+ sdp_media_t const *b)
+{
+ if (a == NULL || b == NULL)
+ return a == b;
+
+ if (a->m_type == sdp_media_any || b->m_type == sdp_media_any)
+ return 1;
+
+ if (a->m_type != b->m_type ||
+ (a->m_type == sdp_media_x &&
+ strcasecmp(b->m_type_name, a->m_type_name)))
+ return 0;
+
+ if (a->m_proto == sdp_proto_any || b->m_proto == sdp_proto_any)
+ return 1;
+
+ if (a->m_proto != b->m_proto ||
+ (a->m_proto == sdp_proto_x &&
+ strcasecmp(b->m_proto_name, a->m_proto_name)))
+ return 0;
+
+ return 1;
+}
+
+
+/** Count matching media lines in SDP. */
+unsigned sdp_media_count(sdp_session_t const *sdp,
+ sdp_media_e type,
+ sdp_text_t *type_name,
+ sdp_proto_e proto,
+ sdp_text_t *proto_name)
+{
+ unsigned count = 0;
+ sdp_media_t const *m;
+
+ if (sdp != NULL)
+ for (m = sdp->sdp_media; m; m = m->m_next)
+ count += sdp_media_match(m, type, type_name, proto, proto_name);
+
+ return count;
+}
+
+/** Count matching media lines in SDP. */
+unsigned sdp_media_count_with(sdp_session_t const *sdp,
+ sdp_media_t const *m0)
+{
+ unsigned count = 0;
+ sdp_media_t const *m;
+
+ if (sdp != NULL)
+ for (m = sdp->sdp_media; m; m = m->m_next)
+ count += sdp_media_match_with(m, m0);
+
+ return count;
+}
+
+/** Return true if media uses RTP */
+int sdp_media_uses_rtp(sdp_media_t const *m)
+{
+ return m &&
+ (m->m_proto == sdp_proto_rtp ||
+ m->m_proto == sdp_proto_srtp ||
+ (m->m_proto == sdp_proto_x && m->m_proto_name &&
+ strncasecmp(m->m_proto_name, "RTP/", 4) == 0));
+}
+
+/** Check if payload type, rtp rate and parameters match in rtpmaps*/
+int sdp_rtpmap_match(sdp_rtpmap_t const *a, sdp_rtpmap_t const *b)
+{
+ char const *aparam, *bparam;
+
+ if (a == b)
+ return 1;
+
+ if (a == 0 || b == 0)
+ return 0;
+
+ if (a->rm_rate != b->rm_rate)
+ return 0;
+
+ if (strcasecmp(a->rm_encoding, b->rm_encoding))
+ return 0;
+
+ aparam = a->rm_params; bparam = b->rm_params;
+
+ if (aparam == bparam)
+ return 1;
+
+ if (!aparam) aparam = "1"; if (!bparam) bparam = "1";
+
+ if (strcasecmp(aparam, bparam))
+ return 0;
+
+ return 1;
+}
+
+/** Search for matching rtpmap from list.
+ *
+ * @note
+ * The a=fmtp: for the codecs are not compared.
+ */
+sdp_rtpmap_t *sdp_rtpmap_find_matching(sdp_rtpmap_t const *list,
+ sdp_rtpmap_t const *rm)
+{
+ char const *lparam, *rparam;
+
+ if (rm == NULL)
+ return NULL;
+
+ for (; list; list = list->rm_next) {
+ if (rm->rm_rate != list->rm_rate)
+ continue;
+
+ if (strcasecmp(rm->rm_encoding, list->rm_encoding) != 0)
+ continue;
+
+ lparam = rm->rm_params; rparam = list->rm_params;
+
+ if (lparam == rparam)
+ break;
+
+ if (!lparam) lparam = "1"; if (!rparam) rparam = "1";
+ if (strcasecmp(lparam, rparam))
+ continue;
+
+ break;
+ }
+
+ return (sdp_rtpmap_t *)list;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sdp.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sdp.docs Thu Dec 21 01:30:28 2006
@@ -0,0 +1,120 @@
+/* -*- c -*- */
+
+/**@MODULEPAGE "sdp" - SDP Module
+
+ at section sdp_meta Module Meta Information
+
+The @b sdp module provides a simple "C" parser interface for SDP [@RFC2327],
+<em>Session Description Protocol</em>. The parser also implements support
+for IPv6 addresses as per @RFC3266. The @RFC4566 should be supported, but we
+have not checked since draft-eitf-mmusic-sdp-new-17 or so.
+
+ at CONTACT Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ at STATUS @SofiaSIP Core library
+
+ at LICENSE LGPL
+
+Contributor(s):
+- Pekka Pessi <Pekka.Pessi at nokia.com>
+- Jari Selin <Jari.Selin at nokia.com>
+
+ at section sdp_parser SDP Parser
+
+SDP parser parses an SDP message and converts it to internally used SDP
+structure #sdp_session_t.
+
+Typically, the SDP parser is used as follows:
+
+ at code
+ sdp_parser_t *parser = sdp_parse(home, message, len, 0);
+
+ if (!sdp_session(parser)) {
+ show(sdp_parsing_error(parser));
+ } else {
+ sdp_session_t *sdp = sdp_session(parser);
+ at endcode
+ Act upon session description, then free the parser:
+ at code
+ }
+ sdp_parser_free(parser);
+ at endcode
+
+There are various flags indicating what kind of SDP variants the sdp_parse()
+accepts. The sanity check run after parsing can be disabled by including
+flag #sdp_f_insane. The parser can be used to parse syntactically vague
+configuration files when using flag #sdp_f_config. The parser will then
+accept * for media, protocol and port, for instance.
+
+ at section sdp_printer SDP Printer
+
+SDP printer converts internally used SDP structure #sdp_session_t to the
+standard SDP format.
+
+Typically, the SDP printer is used as follows:
+ at code
+ char buffer[512];
+ sdp_printer_t *printer = sdp_print(home, session, buffer, sizeof(buffer), 0);
+
+ if (sdp_message(printer)) {
+ char const *msg = sdp_message(printer);
+ size_t msgsize = sdp_message_size(printer);
+ at endcode
+
+At this point, application can use the SDP message contents, e.g., it can
+send them to network, and then free the message:
+ at code
+ }
+ else {
+ show_critical_error(sdp_printing_error(printer));
+ }
+ sdp_printer_free(printer);
+ at endcode
+
+ at section sdp_example Example
+
+Examples on using SDP parser can be found from test_sdp.c and soa.c. Here is
+an simple example, which decodes an SDP text in @a original, increments the
+version number in the origin line, and encodes the SDP description again to
+ at a buf.
+
+ at code
+size_t increment_sdp_version(char buf[], size_t bsize,
+ char const *original, size_t osize)
+{
+ su_home_t home[1] = { SU_HOME_INIT(home) };
+ sdp_parser_t *parser = sdp_parse(home, original, osize, 0);
+ sdp_printer_t *printer;
+ size_t retval = 0;
+
+ if (sdp_session(parser)) {
+ sdp_session_t *sdp = sdp_session(parser);
+
+ sdp->sdp_origin->o_version++;
+
+ printer = sdp_print(home, sdp, buf, bsize, 0);
+
+ if (sdp_message(printer)) {
+ retval = sdp_message_size(printer);
+ }
+ else {
+ fprintf(stderr, "increment_sdp_version: %s\n",
+ sdp_printing_error(printer));
+ }
+
+ sdp_printer_free(printer);
+ }
+ else {
+ fprintf(stderr, "increment_sdp_version: %s\n",
+ sdp_parsing_error(p));
+ }
+
+ sdp_parser_free(parser);
+
+ su_home_deinit(home);
+
+ return retval;
+}
+ at endcode
+
+*/
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_parse.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_parse.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1887 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup sdp_parser
+ * @CFILE sdp_parse.c
+ * @brief Simple SDP parser interface.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Kai Vehmanen <kai.vehmanen at nokia.com>
+ *
+ * @date Created: Fri Feb 18 10:25:08 2000 ppessi
+ */
+
+#include "config.h"
+
+#include <sofia-sip/su_alloc.h>
+
+#include "sofia-sip/sdp.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <limits.h>
+#include <assert.h>
+
+/** @typedef struct sdp_parser_s sdp_parser_t;
+ *
+ * SDP parser handle.
+ *
+ * The SDP parser handle is returned by sdp_parse(). It contains either
+ * successfully parse SDP session #sdp_session_t or an error message.
+ * If sdp_session() returns non-NULL, parsing was successful.
+ *
+ * @sa #sdp_session_t, sdp_parse(), sdp_session(), sdp_parsing_error(),
+ * sdp_sanity_check(), sdp_parser_home(), sdp_parser_free().
+ */
+
+struct sdp_parser_s {
+ su_home_t pr_home[1];
+ union {
+ char pru_error[128];
+ sdp_session_t pru_session[1];
+ } pr_output;
+ char *pr_message;
+
+ sdp_mode_t pr_session_mode;
+
+ unsigned pr_ok : 1;
+
+ unsigned pr_strict : 1;
+ unsigned pr_anynet : 1;
+ unsigned pr_mode_0000 : 1;
+ unsigned pr_mode_manual : 1;
+ unsigned pr_insane : 1;
+ unsigned pr_c_missing : 1;
+ unsigned pr_config : 1;
+};
+
+#define is_posdigit(c) ((c) >= '1' && (c) <= '9')
+#define is_digit(c) ((c) >= '0' && (c) <= '9')
+#define is_space(c) ((c) == ' ')
+#define is_tab(c) ((c) == '\t')
+
+#define pr_error pr_output.pru_error
+#define pr_session pr_output.pru_session
+
+#define STRICT(pr) (pr->pr_strict)
+
+/* Static parser object used when running out of memory */
+static const struct sdp_parser_s no_mem_error =
+{
+ { SU_HOME_INIT(no_mem_error) },
+ { "sdp: not enough memory" }
+};
+
+/* Internal prototypes */
+static void parse_message(sdp_parser_t *p);
+static void parsing_error(sdp_parser_t *p, char const *fmt, ...);
+
+/** Parse an SDP message.
+ *
+ * The function sdp_parse() parses an SDP message @a msg of size @a
+ * msgsize. Parsing is done according to the given @a flags. The SDP message
+ * may not contain a NUL.
+ *
+ * The parsing result is stored to an #sdp_session_t structure.
+ *
+ * @param home memory home
+ * @param msg pointer to message
+ * @param msgsize size of the message (excluding final NUL, if any)
+ * @param flags flags affecting the parsing.
+ *
+ * The following flags are used by parser:
+ *
+ * @li #sdp_f_strict Parser should accept only messages conforming strictly
+ * to the specification.
+ * @li #sdp_f_anynet Parser accepts unknown network or address types.
+ * @li #sdp_f_insane Do not run sanity check.
+ * @li #sdp_f_c_missing Sanity check does not require c= for each m= line
+ * @li #sdp_f_mode_0000 Parser regards "c=IN IP4 0.0.0.0" as "a=inactive"
+ * (likewise with c=IN IP6 ::)
+ * @li #sdp_f_mode_manual Do not generate or parse SDP mode
+ * @li #sdp_f_config Parse config files (any line can be missing)
+ *
+ * @return
+ * Always a valid parser handle.
+ *
+ * @todo Parser accepts some non-conforming SDP even with #sdp_f_strict.
+ */
+sdp_parser_t *
+sdp_parse(su_home_t *home, char const msg[], issize_t msgsize, int flags)
+{
+ sdp_parser_t *p;
+ char *b;
+ size_t len;
+
+ if (msgsize == -1 || msg == NULL) {
+ p = su_home_clone(home, sizeof(*p));
+ if (p)
+ parsing_error(p, "invalid input message");
+ else
+ p = (sdp_parser_t*)&no_mem_error;
+ return p;
+ }
+
+ if (msgsize == -1 && msg)
+ len = strlen(msg);
+ else
+ len = msgsize;
+
+ if (len > ISSIZE_MAX)
+ len = ISSIZE_MAX;
+
+ p = su_home_clone(home, sizeof(*p) + len + 1);
+
+ if (p) {
+ b = strncpy((void *)(p + 1), msg, len);
+ b[len] = 0;
+
+ p->pr_message = b;
+ p->pr_strict = (flags & sdp_f_strict) != 0;
+ p->pr_anynet = (flags & sdp_f_anynet) != 0;
+ p->pr_mode_0000 = (flags & sdp_f_mode_0000) != 0;
+ p->pr_insane = (flags & sdp_f_insane) != 0;
+ p->pr_c_missing = (flags & sdp_f_c_missing) != 0;
+ if (flags & sdp_f_config)
+ p->pr_c_missing = 1, p->pr_config = 1;
+ p->pr_mode_manual = (flags & sdp_f_mode_manual) != 0;
+ p->pr_session_mode = sdp_sendrecv;
+
+ parse_message(p);
+
+ return p;
+ }
+
+ if (p)
+ sdp_parser_free(p);
+
+ return (sdp_parser_t*)&no_mem_error;
+}
+
+
+/** Obtain memory home used by parser */
+su_home_t *sdp_parser_home(sdp_parser_t *parser)
+{
+ if (parser != &no_mem_error)
+ return parser->pr_home;
+ else
+ return NULL;
+}
+
+/** Retrieve an SDP session structure.
+ *
+ * The function sdp_session() returns a pointer to the SDP session
+ * structure associated with the SDP parser @a p. The pointer and all the
+ * data in the structure are valid until sdp_parser_free() is called.
+ *
+ * @param p SDP parser
+ *
+ * @return
+ * The function sdp_session() returns a pointer to an parsed SDP message
+ * or NULL, if an error has occurred. */
+sdp_session_t *
+sdp_session(sdp_parser_t *p)
+{
+ return p && p->pr_ok ? p->pr_session : NULL;
+}
+
+/** Get a parsing error message.
+ *
+ * The function sdp_parsing_error() returns the error message associated
+ * with an SDP parser @a p.
+ *
+ * @param p SDP parser
+ *
+ * @return
+ * The function sdp_parsing_error() returns a C string describing parsing
+ * error, or NULL if no error occurred.
+ */
+char const *sdp_parsing_error(sdp_parser_t *p)
+{
+ return !p->pr_ok ? p->pr_error : NULL;
+}
+
+/** Free an SDP parser.
+ *
+ * The function sdp_parser_free() frees an SDP parser object along with
+ * the memory blocks associated with it.
+ *
+ * @param p pointer to the SDP parser to be freed
+ */
+void sdp_parser_free(sdp_parser_t *p)
+{
+ if (p && p != &no_mem_error)
+ su_home_unref(p->pr_home);
+}
+
+/* ========================================================================= */
+
+/* =========================================================================
+ * Private part
+ */
+
+/* Parsing tokens */
+#define SPACE " "
+#define TAB "\011"
+#define CRLF "\015\012"
+#define ALPHA "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+#define DIGIT "0123456789"
+
+/* ========================================================================= */
+/* Parsing functions */
+
+static void post_session(sdp_parser_t *p, sdp_session_t *sdp);
+static void parse_origin(sdp_parser_t *p, char *r, sdp_origin_t **result);
+static void parse_subject(sdp_parser_t *p, char *r, sdp_text_t **result);
+static void parse_information(sdp_parser_t *p, char *r, sdp_text_t **result);
+static void parse_uri(sdp_parser_t *p, char *r, sdp_text_t **result);
+static void parse_email(sdp_parser_t *p, char *r, sdp_list_t **result);
+static void parse_phone(sdp_parser_t *p, char *r, sdp_list_t **result);
+static void parse_connection(sdp_parser_t *p, char *r, sdp_connection_t **result);
+static void parse_bandwidth(sdp_parser_t *p, char *r, sdp_bandwidth_t **result);
+static void parse_time(sdp_parser_t *p, char *r, sdp_time_t **result);
+static void parse_repeat(sdp_parser_t *p, char *r, sdp_repeat_t **result);
+static void parse_zone(sdp_parser_t *p, char *r, sdp_zone_t **result);
+static void parse_key(sdp_parser_t *p, char *r, sdp_key_t **result);
+static void parse_session_attr(sdp_parser_t *p, char *r, sdp_attribute_t **result);
+static void parse_media(sdp_parser_t *p, char *r, sdp_media_t **result);
+static void parse_payload(sdp_parser_t *p, char *r, sdp_rtpmap_t **result);
+static void parse_media_attr(sdp_parser_t *p, char *r, sdp_media_t *m,
+ sdp_attribute_t **result);
+static int parse_rtpmap(sdp_parser_t *p, char *r, sdp_media_t *m);
+static int parse_fmtp(sdp_parser_t *p, char *r, sdp_media_t *m);
+static void parse_text_list(sdp_parser_t *p, char *r, sdp_list_t **result);
+
+static void parse_descs(sdp_parser_t *p, char *r, char *m, sdp_media_t **result);
+
+static int parse_ul(sdp_parser_t *p, char **r, unsigned long *result,
+ unsigned long max_value);
+static int parse_ull(sdp_parser_t *p, char **r, uint64_t *result,
+ uint64_t max_value);
+static void parse_alloc_error(sdp_parser_t *p, const char *typename);
+static char *next(char **message, const char *sep, const char *strip);
+static char *token(char **message, const char *sep, const char *legal,
+ const char *strip);
+#if 0
+static void check_mandatory(sdp_parser_t *p, sdp_session_t *sdp);
+#endif
+
+/* -------------------------------------------------------------------------
+ * Macro PARSE_ALLOC
+ *
+ * Description:
+ * This macro declares a pointer (v) of given type (t). It then allocates
+ * an structure of given type (t). If allocation was succesful, it assigns
+ * the XX_size member with appropriate value.
+ */
+#define PARSE_ALLOC(p, t, v) \
+ t *v = su_salloc(p->pr_home, sizeof(*v)); \
+ if (!v && (parse_alloc_error(p, #t), 1)) return;
+
+/* -------------------------------------------------------------------------
+ * Macro PARSE_CHECK_REST
+ *
+ * Description:
+ * This macro check if there is extra data at the end of field.
+ */
+#define PARSE_CHECK_REST(p, s, n)\
+ if (*s && (parsing_error(p, "extra data after %s (\"%.04s\")", n, s), 1)) \
+ return
+
+/* -------------------------------------------------------------------------
+ * Function parse_message() - parse an SDP message
+ *
+ * Description:
+ * This function parses an SDP message, which is copied into the
+ * p->pr_message. The p->pr_message is modified during the parsing,
+ * and parts of it are returned in p->pr_session.
+ *
+ * Parameters:
+ * p - pointer to SDP parser object
+ */
+static void parse_message(sdp_parser_t *p)
+{
+/*
+ announcement = proto-version
+ origin-field
+ session-name-field
+ information-field
+ uri-field
+ email-fields
+ phone-fields
+ connection-field
+ bandwidth-fields
+ time-fields
+ key-field
+ attribute-fields
+ media-descriptions
+*/
+
+ sdp_session_t *sdp = p->pr_session;
+ char *record, *rest;
+ char const *strip;
+ char *message = p->pr_message;
+ char field = '\0';
+ sdp_list_t **emails = &sdp->sdp_emails;
+ sdp_list_t **phones = &sdp->sdp_phones;
+ sdp_bandwidth_t **bandwidths = &sdp->sdp_bandwidths;
+ sdp_time_t **times = &sdp->sdp_time;
+ sdp_repeat_t **repeats = NULL;
+ sdp_zone_t **zones = NULL;
+ sdp_attribute_t **attributes = &sdp->sdp_attributes;
+
+ if (!STRICT(p))
+ strip = SPACE TAB; /* skip initial whitespace */
+ else
+ strip = NULL;
+
+ p->pr_ok = 1;
+ p->pr_session->sdp_size = sizeof(p->pr_session);
+
+ /* Require that version comes first */
+ record = next(&message, CRLF, strip);
+
+ if (!record || strcmp(record, "v=0")) {
+ if (!p->pr_config || !record || record[1] != '=') {
+ parsing_error(p, "bad SDP message");
+ return;
+ }
+ }
+ else {
+ record = next(&message, CRLF, strip);
+ }
+
+ /*
+ XXX - the lines in SDP are in certain order, which we don't check here.
+ For stricter parsing we might want to parse o= and s= next.
+ */
+
+ for (;
+ record && p->pr_ok;
+ record = next(&message, CRLF, strip)) {
+ field = record[0];
+
+ rest = record + 2; rest += strspn(rest, strip);
+
+ if (record[1] != '=') {
+ parsing_error(p, "bad line \"%s\"", record);
+ return;
+ }
+
+ switch (field) {
+ case 'o':
+ parse_origin(p, rest, &sdp->sdp_origin);
+ break;
+
+ case 's':
+ parse_subject(p, rest, &sdp->sdp_subject);
+ break;
+
+ case 'i':
+ parse_information(p, rest, &sdp->sdp_information);
+ break;
+
+ case 'u':
+ parse_uri(p, rest, &sdp->sdp_uri);
+ break;
+
+ case 'e':
+ parse_email(p, rest, emails);
+ emails = &(*emails)->l_next;
+ break;
+
+ case 'p':
+ parse_phone(p, rest, phones);
+ phones = &(*phones)->l_next;
+ break;
+
+ case 'c':
+ parse_connection(p, rest, &sdp->sdp_connection);
+ break;
+
+ case 'b':
+ parse_bandwidth(p, rest, bandwidths);
+ bandwidths = &(*bandwidths)->b_next;
+ break;
+
+ case 't':
+ parse_time(p, rest, times);
+ repeats = &(*times)->t_repeat;
+ zones = &(*times)->t_zone;
+ times = &(*times)->t_next;
+ break;
+
+ case 'r':
+ if (repeats)
+ parse_repeat(p, rest, repeats);
+ else
+ parsing_error(p, "repeat field without time field");
+ break;
+
+ case 'z':
+ if (zones)
+ parse_zone(p, rest, zones), zones = NULL;
+ else
+ parsing_error(p, "zone field without time field");
+ break;
+
+ case 'k':
+ parse_key(p, rest, &sdp->sdp_key);
+ break;
+
+ case 'a':
+ parse_session_attr(p, rest, attributes);
+ if (*attributes)
+ attributes = &(*attributes)->a_next;
+ break;
+
+ case 'm':
+ parse_descs(p, record, message, &sdp->sdp_media);
+ post_session(p, sdp);
+ return;
+
+ default:
+ parsing_error(p, "unknown field \"%s\"", record);
+ return;
+ }
+ }
+
+ post_session(p, sdp);
+}
+
+int sdp_connection_is_inaddr_any(sdp_connection_t const *c)
+{
+ return
+ c &&
+ c->c_nettype == sdp_net_in &&
+ ((c->c_addrtype == sdp_addr_ip4 && strcmp(c->c_address, "0.0.0.0")) ||
+ (c->c_addrtype == sdp_addr_ip6 && strcmp(c->c_address, "::")));
+}
+
+/**Postprocess session description.
+ *
+ * The function post_session() postprocesses the session description. The
+ * postprocessing includes setting the session backpointer for each media.
+ */
+static void post_session(sdp_parser_t *p, sdp_session_t *sdp)
+{
+ sdp_media_t *m;
+ sdp_connection_t const *c;
+
+ if (!p->pr_ok)
+ return;
+
+ /* Set session back-pointer */
+ for (m = sdp->sdp_media; m; m = m->m_next) {
+ m->m_session = sdp;
+ }
+
+ if (p->pr_config) {
+ if (sdp->sdp_version[0] != 0)
+ parsing_error(p, "Incorrect version");
+ return;
+ }
+
+ /* Go through all media and set mode */
+ for (m = sdp->sdp_media; m; m = m->m_next) {
+ if (m->m_port == 0) {
+ m->m_mode = sdp_inactive;
+ m->m_rejected = 1;
+ continue;
+ }
+
+ c = sdp_media_connections(m);
+
+ if (p->pr_mode_0000 && c) {
+ if (c->c_nettype == sdp_net_in &&
+ c->c_addrtype == sdp_addr_ip4 &&
+ strcmp(c->c_address, "0.0.0.0") == 0)
+ /* Reset recvonly flag */
+ m->m_mode &= ~sdp_recvonly;
+ }
+ }
+
+ if (p->pr_insane)
+ return;
+
+ /* Verify that all mandatory fields are present */
+ if (sdp_sanity_check(p) < 0)
+ return;
+}
+
+/** Validates that all mandatory fields exist
+ *
+ * Checks that all necessary fields (v=, o=) exists in the parsed sdp. If
+ * strict, check that all mandatory fields (c=, o=, s=, t=) are present.
+ * This function also goes through all media, marks rejected media as such,
+ * and updates the mode accordingly.
+ *
+ * @retval 0 if parsed SDP description is valid
+ * @retval -1 if some SDP line is missing
+ * @retval -2 if c= line is missing
+ */
+int sdp_sanity_check(sdp_parser_t *p)
+{
+ sdp_session_t *sdp = p->pr_session;
+ sdp_media_t *m;
+
+ if (!p || !p->pr_ok)
+ ;
+ else if (sdp->sdp_version[0] != 0)
+ parsing_error(p, "Incorrect version");
+ else if (!sdp->sdp_origin)
+ parsing_error(p, "No o= present");
+ else if (p->pr_strict && !sdp->sdp_subject)
+ parsing_error(p, "No s= present");
+ else if (p->pr_strict && !sdp->sdp_time)
+ parsing_error(p, "No t= present");
+
+ if (!p->pr_ok)
+ return -1;
+
+ /* If there is no session level c= check that one exists for all media */
+ /* c= line may be missing if this is a RTSP description */
+ if (!p->pr_c_missing && !sdp->sdp_connection) {
+ for (m = sdp->sdp_media ; m ; m = m->m_next) {
+ if (!m->m_connections && !m->m_rejected) {
+ parsing_error(p, "No c= on either session level or all mediums");
+ return -2;
+ }
+ }
+ }
+
+ return 0;
+}
+
+#if 0
+/**
+ * Parse a "v=" field
+ *
+ * The function parser_version() parses the SDP version field.
+ *
+ * @param p pointer to SDP parser object
+ * @param r pointer to record data
+ * @param result pointer to which parsed record is assigned
+ */
+static void parse_version(sdp_parser_t *p, char *r, sdp_version_t *result)
+{
+ /*
+ proto-version = "v=" 1*DIGIT CRLF
+ ;[RFC2327] describes version 0
+ */
+ if (parse_ul(p, &r, result, 0))
+ parsing_error(p, "version \"%s\" is invalid", r);
+ else if (*result > 0)
+ parsing_error(p, "unknown version v=%s", r);
+}
+#endif
+
+/* -------------------------------------------------------------------------
+ * Function parse_origin() - parse an "o=" field
+ *
+ * Description:
+ * This function parses an SDP origin field.
+ *
+ * Parameters:
+ * p - pointer to SDP parser object
+ * r - pointer to record data
+ * result - pointer to which parsed record is assigned
+ */
+static void parse_origin(sdp_parser_t *p, char *r, sdp_origin_t **result)
+{
+ /*
+ origin-field = "o=" username space
+ sess-id space sess-version space
+ nettype space addrtype space
+ addr CRLF
+
+ username = safe
+ ;pretty wide definition, but doesn't include space
+
+ sess-id = 1*(DIGIT)
+ ;should be unique for this originating username/host
+
+ sess-version = 1*(DIGIT)
+ ;0 is a new session
+
+
+ */
+ PARSE_ALLOC(p, sdp_origin_t, o);
+
+ *result = o;
+
+ o->o_username = token(&r, SPACE TAB, NULL, SPACE TAB);
+ if (!o->o_username) {
+ parsing_error(p, "invalid username");
+ return;
+ }
+ if (parse_ull(p, &r, &o->o_id, 0)) {
+ parsing_error(p, "invalid session id");
+ return;
+ }
+
+ if (parse_ull(p, &r, &o->o_version, 0)) {
+ parsing_error(p, "invalid session version");
+ return;
+ }
+
+ parse_connection(p, r, &o->o_address);
+}
+
+/* -------------------------------------------------------------------------
+ * Function parse_subject() - parse an "s=" field
+ *
+ * Description:
+ * This function parses an SDP subject field.
+ *
+ * Parameters:
+ * p - pointer to SDP parser object
+ * r - pointer to record data
+ * result - pointer to which parsed record is assigned
+ */
+static void parse_subject(sdp_parser_t *p, char *r, sdp_text_t **result)
+{
+ /*
+ session-name-field = "s=" text CRLF
+ text = byte-string
+ */
+ *result = r;
+}
+
+/* -------------------------------------------------------------------------
+ * Function parse_information() - parse an "i=" field
+ *
+ * Description:
+ * This function parses an SDP information field.
+ *
+ * Parameters:
+ * p - pointer to SDP parser object
+ * r - pointer to record data
+ * result - pointer to which parsed record is assigned
+ */
+static void parse_information(sdp_parser_t *p, char *r, sdp_text_t **result)
+{
+ /*
+ information-field = ["i=" text CRLF]
+ */
+ *result = r;
+}
+
+/* -------------------------------------------------------------------------
+ * Function parse_uri() - parse an "u=" field
+ *
+ * Description:
+ * This function parses an SDP URI field.
+ *
+ * Parameters:
+ * p - pointer to SDP parser object
+ * r - pointer to record data
+ * result - pointer to which parsed record is assigned
+ */
+static void parse_uri(sdp_parser_t *p, char *r, sdp_text_t **result)
+{
+ /*
+ uri-field = ["u=" uri CRLF]
+
+ uri= ;defined in RFC1630
+ */
+ /* XXX - no syntax checking here */
+ *result = r;
+}
+
+/* -------------------------------------------------------------------------
+ * Function parse_email() - parse an "e=" field
+ *
+ * Description:
+ * This function parses an SDP email field.
+ *
+ * Parameters:
+ * p - pointer to SDP parser object
+ * r - pointer to record data
+ * result - pointer to which parsed record is assigned
+ */
+static void parse_email(sdp_parser_t *p, char *r, sdp_list_t **result)
+{
+ /*
+ email-fields = *("e=" email-address CRLF)
+
+ email-address = email | email "(" email-safe ")" |
+ email-safe "<" email ">"
+
+ email = ;defined in RFC822 */
+ parse_text_list(p, r, result);
+}
+
+/* -------------------------------------------------------------------------
+ * Function parse_phone() - parse an "p=" field
+ *
+ * Description:
+ * This function parses an SDP phone field.
+ *
+ * Parameters:
+ * p - pointer to SDP parser object
+ * r - pointer to record data
+ * result - pointer to which parsed record is assigned
+ */
+static void parse_phone(sdp_parser_t *p, char *r, sdp_list_t **result)
+{
+ /*
+ phone-fields = *("p=" phone-number CRLF)
+
+ phone-number = phone | phone "(" email-safe ")" |
+ email-safe "<" phone ">"
+
+ phone = "+" POS-DIGIT 1*(space | "-" | DIGIT)
+ ;there must be a space or hyphen between the
+ ;international code and the rest of the number.
+ */
+ parse_text_list(p, r, result);
+}
+
+/* -------------------------------------------------------------------------
+ * Function parse_connection() - parse an "c=" field
+ *
+ * Description:
+ * This function parses an SDP connection field.
+ *
+ * Parameters:
+ * p - pointer to SDP parser object
+ * r - pointer to record data
+ * result - pointer to which parsed record is assigned
+ */
+static void parse_connection(sdp_parser_t *p, char *r, sdp_connection_t **result)
+{
+ /*
+ connection-field = ["c=" nettype space addrtype space
+ connection-address CRLF]
+ ;a connection field must be present
+ ;in every media description or at the
+ ;session-level
+
+ nettype = "IN"
+ ;list to be extended
+
+ addrtype = "IP4" | "IP6"
+ ;list to be extended
+
+ connection-address = multicast-address
+ | addr
+
+ multicast-address = 3*(decimal-uchar ".") decimal-uchar "/" ttl
+ [ "/" integer ]
+ ;multicast addresses may be in the range
+ ;224.0.0.0 to 239.255.255.255
+
+ ttl = decimal-uchar
+
+ addr = FQDN | unicast-address
+
+ FQDN = 4*(alpha-numeric|"-"|".")
+ ;fully qualified domain name as specified in RFC1035
+
+ unicast-address = IP4-address | IP6-address
+
+ IP4-address = b1 "." decimal-uchar "." decimal-uchar "." b4
+ b1 = decimal-uchar
+ ;less than "224"; not "0" or "127"
+ b4 = decimal-uchar
+ ;not "0"
+
+ IP6-address = ;to be defined
+ */
+ PARSE_ALLOC(p, sdp_connection_t, c);
+
+ *result = c;
+
+ if (strncasecmp(r, "IN", 2) == 0) {
+ char *s;
+
+ /* nettype is internet */
+ c->c_nettype = sdp_net_in;
+ s = token(&r, SPACE TAB, NULL, NULL);
+
+ /* addrtype */
+ s = token(&r, SPACE TAB, NULL, NULL);
+ if (s && strcasecmp(s, "IP4") == 0)
+ c->c_addrtype = sdp_addr_ip4;
+ else if (s && strcasecmp(s, "IP6") == 0)
+ c->c_addrtype = sdp_addr_ip6;
+ else {
+ parsing_error(p, "unknown IN address type: %s", s);
+ return;
+ }
+
+ /* address */
+ s = next(&r, SPACE TAB, SPACE TAB);
+ c->c_address = s;
+ if (!s || !*s) {
+ parsing_error(p, "invalid address");
+ return;
+ }
+
+ /* ttl */
+ s = strchr(s, '/');
+ if (s) {
+ unsigned long value;
+ *s++ = 0;
+ if (parse_ul(p, &s, &value, 256) ||
+ (*s && *s != '/')) {
+ parsing_error(p, "invalid ttl");
+ return;
+ }
+ c->c_ttl = value;
+ c->c_mcast = 1;
+
+ /* multiple groups */
+ value = 1;
+ if (*s++ == '/')
+ if (parse_ul(p, &s, &value, 0) || *s) {
+ parsing_error(p, "invalid number of multicast groups");
+ return;
+ }
+ c->c_groups = value;
+ }
+ else
+ c->c_groups = 1;
+ }
+ else if (p->pr_anynet) {
+ c->c_nettype = sdp_net_x;
+ c->c_addrtype = sdp_addr_x;
+ c->c_address = r;
+ c->c_ttl = 0;
+ c->c_groups = 1;
+ }
+ else
+ parsing_error(p, "invalid address");
+}
+
+/* -------------------------------------------------------------------------
+ * Function parse_bandwidth() - parse an "b=" field
+ *
+ * Description:
+ * This function parses an SDP bandwidth field.
+ *
+ * Parameters:
+ * p - pointer to SDP parser object
+ * r - pointer to record data
+ * result - pointer to which parsed record is assigned
+ */
+static void parse_bandwidth(sdp_parser_t *p, char *r, sdp_bandwidth_t **result)
+{
+ /*
+ bandwidth-fields = *("b=" bwtype ":" bandwidth CRLF)
+
+ bwtype = 1*(alpha-numeric)
+ ; CT or AS
+ bandwidth = 1*(DIGIT)
+ */
+ /* NOTE: bwtype can also be like X-barf */
+ sdp_bandwidth_e modifier;
+ char *name;
+ unsigned long value;
+
+ name = token(&r, ":", ALPHA DIGIT "-", SPACE TAB);
+
+ if (name == NULL || parse_ul(p, &r, &value, 0)) {
+ parsing_error(p, "invalid bandwidth");
+ return;
+ }
+
+ if (strcmp(name, "CT") == 0)
+ modifier = sdp_bw_ct, name = NULL;
+ else if (strcmp(name, "AS") == 0)
+ modifier = sdp_bw_as, name = NULL;
+ else
+ modifier = sdp_bw_x;
+
+ if (STRICT(p))
+ PARSE_CHECK_REST(p, r, "b");
+
+ {
+ PARSE_ALLOC(p, sdp_bandwidth_t, b);
+ *result = b;
+ b->b_modifier = modifier;
+ b->b_modifier_name = name;
+ b->b_value = value;
+ }
+}
+
+/* -------------------------------------------------------------------------
+ * Function parse_time() - parse an "t=" field
+ *
+ * Description:
+ * This function parses an SDP time field.
+ *
+ * Parameters:
+ * p - pointer to SDP parser object
+ * r - pointer to record data
+ * result - pointer to which parsed record is assigned
+ */
+static void parse_time(sdp_parser_t *p, char *r, sdp_time_t **result)
+{
+ /*
+ time-fields = 1*( "t=" start-time space stop-time
+ *(CRLF repeat-fields) CRLF)
+ [zone-adjustments CRLF]
+
+ start-time = time | "0"
+
+ stop-time = time | "0"
+
+ time = POS-DIGIT 9*(DIGIT)
+ ;sufficient for 2 more centuries
+ */
+ PARSE_ALLOC(p, sdp_time_t, t);
+ *result = t;
+ if (parse_ul(p, &r, &t->t_start, 0) ||
+ parse_ul(p, &r, &t->t_stop, 0))
+ parsing_error(p, "invalid time");
+ else if (STRICT(p)) {
+ PARSE_CHECK_REST(p, r, "t");
+ }
+}
+
+/**
+ * Parse an "r=" field
+ *
+ * The function parse_repeat() parses an SDP repeat field.
+ *
+ * @param p pointer to SDP parser object
+ * @param r pointer to record data
+ * @param result pointer to which parsed record is assigned
+ *
+ */
+static void parse_repeat(sdp_parser_t *p, char *d, sdp_repeat_t **result)
+{
+ /*
+ repeat-fields = "r=" repeat-interval space typed-time
+ 1*(space typed-time)
+
+ repeat-interval = typed-time
+
+ typed-time = 1*(DIGIT) [fixed-len-time-unit]
+
+ fixed-len-time-unit = "d" | "h" | "m" | "s"
+ */
+
+ unsigned long tt, *interval;
+ size_t i;
+ int n, N;
+ char *s;
+ sdp_repeat_t *r;
+
+ /** Count number of intervals */
+ for (N = 0, s = d; *s; ) {
+ if (!(is_posdigit(*s) || (!STRICT(p) && (*s) == '0')))
+ break;
+ do { s++; } while (is_digit(*s));
+ if (*s && strchr("dhms", *s))
+ s++;
+ N++;
+ if (!(i = STRICT(p) ? is_space(*s) : strspn(s, SPACE TAB)))
+ break;
+ s += i;
+ }
+
+ PARSE_CHECK_REST(p, s, "r");
+ if (N < 2) {
+ parsing_error(p, "invalid repeat");
+ return;
+ }
+ if (!(r = su_salloc(p->pr_home, offsetof(sdp_repeat_t, r_offsets[N - 1])))) {
+ parse_alloc_error(p, "sdp_repeat_t");
+ return;
+ }
+
+ r->r_number_of_offsets = N - 2;
+ r->r_offsets[N - 2] = 0;
+
+ for (n = 0, interval = &r->r_interval; n < N; n++) {
+ tt = strtoul(d, &d, 10);
+
+ switch (*d) {
+ case 'd': tt *= 24;
+ case 'h': tt *= 60;
+ case 'm': tt *= 60;
+ case 's': d++;
+ break;
+ }
+
+ interval[n] = tt;
+
+ while (is_space(*d))
+ d++;
+ }
+
+ *result = r;
+}
+
+/* -------------------------------------------------------------------------
+ * Function parse_zone() - parse an "z=" field
+ *
+ * Description:
+ * This function parses an SDP time zone field.
+ *
+ * Parameters:
+ * p - pointer to SDP parser object
+ * r - pointer to record data
+ * result - pointer to which parsed record is assigned
+ *
+ */
+static void parse_zone(sdp_parser_t *p, char *r, sdp_zone_t **result)
+{
+ char *s;
+ size_t i;
+ int n, N;
+ sdp_zone_t *z;
+
+ /*
+ zone-adjustments = time space ["-"] typed-time
+ *(space time space ["-"] typed-time)
+ */
+
+ /** Count number of timezones, check syntax */
+ for (N = 0, s = r; *s;) {
+ if (!(is_posdigit(*s) || (!STRICT(p) && (*s) == '0')))
+ break;
+ do { s++; } while (is_digit(*s));
+ if (!(i = STRICT(p) ? is_space(*s) : strspn(s, SPACE TAB)))
+ break;
+ s += i;
+ if (!(*s == '-' || is_posdigit(*s) || (!STRICT(p) && (*s) == '0')))
+ break;
+ do { s++; } while (is_digit(*s));
+ if (*s && strchr("dhms", *s))
+ s++;
+ N++;
+ if (!(i = STRICT(p) ? is_space(*s) : strspn(s, SPACE TAB)))
+ break;
+ s += i;
+ }
+
+ PARSE_CHECK_REST(p, s, "z");
+
+ if (N < 1) {
+ parsing_error(p, "invalid timezone");
+ return;
+ }
+ if (!(z = su_salloc(p->pr_home, offsetof(sdp_zone_t, z_adjustments[N])))) {
+ parse_alloc_error(p, "sdp_zone_t");
+ return;
+ }
+
+ z->z_number_of_adjustments = N;
+
+ for (n = 0; n < N; n++) {
+ unsigned long at = strtoul(r, &r, 10);
+ long offset = strtol(r, &r, 10);
+ switch (*r) {
+ case 'd': offset *= 24;
+ case 'h': offset *= 60;
+ case 'm': offset *= 60;
+ case 's': r++;
+ break;
+ }
+
+ z->z_adjustments[n].z_at = at;
+ z->z_adjustments[n].z_offset = offset;
+ }
+
+ *result = z;
+}
+
+/* -------------------------------------------------------------------------
+ * Function parse_key() - parse an "k=" field
+ *
+ * Description:
+ * This function parses an SDP key field.
+ *
+ * Parameters:
+ * p - pointer to SDP parser object
+ * r - pointer to record data
+ * result - pointer to which parsed record is assigned
+ *
+ */
+static void parse_key(sdp_parser_t *p, char *r, sdp_key_t **result)
+{
+ char *s;
+ /*
+ key-field = ["k=" key-type CRLF]
+
+
+ key-type = "prompt" |
+ "clear:" key-data |
+ "base64:" key-data |
+ "uri:" uri
+
+
+ key-data = email-safe | "~" | "
+ */
+
+ s = token(&r, ":", ALPHA DIGIT "-", SPACE TAB);
+ if (!s) {
+ parsing_error(p, "invalid key method");
+ return;
+ }
+
+ {
+ PARSE_ALLOC(p, sdp_key_t, k);
+ *result = k;
+
+ if (strcasecmp(s, "clear") == 0)
+ k->k_method = sdp_key_clear, k->k_method_name = "clear";
+ else if (strcasecmp(s, "base64") == 0)
+ k->k_method = sdp_key_base64, k->k_method_name = "base64";
+ else if (strcasecmp(s, "uri") == 0)
+ k->k_method = sdp_key_uri, k->k_method_name = "uri";
+ else if (strcasecmp(s, "prompt") == 0)
+ k->k_method = sdp_key_prompt, k->k_method_name = "prompt";
+ else
+ k->k_method = sdp_key_x, k->k_method_name = s;
+
+ k->k_material = r;
+ }
+}
+
+/* -------------------------------------------------------------------------
+ * Function parse_session_attr() - parse a session "a=" field
+ *
+ * Description:
+ * This function parses an SDP attribute field regarding whole session.
+ *
+ * Parameters:
+ * p - pointer to SDP parser object
+ * r - pointer to record data
+ * result - pointer to which parsed record is assigned
+ */
+static void parse_session_attr(sdp_parser_t *p, char *r, sdp_attribute_t **result)
+{
+ /*
+ attribute-fields = *("a=" attribute CRLF)
+
+ attribute = (att-field ":" att-value) | att-field
+
+ att-field = 1*(alpha-numeric)
+
+ att-value = byte-string
+ */
+
+ char *name = NULL, *value = NULL;
+
+ if (!(name = token(&r, ":", ALPHA DIGIT "-", SPACE TAB))) {
+ parsing_error(p,"invalid attribute name");
+ return;
+ }
+
+ if (*r)
+ value = r;
+ else
+ PARSE_CHECK_REST(p, r, "a");
+
+ if (strcasecmp(name, "charset") == 0) {
+ p->pr_session->sdp_charset = value;
+ return;
+ }
+
+ if (p->pr_mode_manual)
+ ;
+ else if (strcasecmp(name, "inactive") == 0)
+ p->pr_session_mode = sdp_inactive;
+ else if (strcasecmp(name, "sendonly") == 0)
+ p->pr_session_mode = sdp_sendonly;
+ else if (strcasecmp(name, "recvonly") == 0)
+ p->pr_session_mode = sdp_recvonly;
+ else if (strcasecmp(name, "sendrecv") == 0)
+ p->pr_session_mode = sdp_sendrecv;
+
+ {
+ PARSE_ALLOC(p, sdp_attribute_t, a);
+ *result = a;
+
+ a->a_name = name;
+ a->a_value = value;
+ }
+}
+
+/* -------------------------------------------------------------------------
+ * Function parse_media() - parse an "m=" field
+ *
+ * Description:
+ * This function parses an SDP media field.
+ *
+ * Parameters:
+ * p - pointer to SDP parser object
+ * r - pointer to record data
+ * result - pointer to which parsed record is assigned
+ */
+static void parse_media(sdp_parser_t *p, char *r, sdp_media_t **result)
+{
+ /*
+ media-descriptions = *( media-field
+ information-field
+ *(connection-field)
+ bandwidth-fields
+ key-field
+ attribute-fields )
+
+ media-field = "m=" media space port ["/" integer]
+ space proto 1*(space fmt) CRLF
+
+ media = 1*(alpha-numeric)
+ ;typically "audio", "video", "application"
+ ;or "data"
+
+ fmt = 1*(alpha-numeric)
+ ;typically an RTP payload type for audio
+ ;and video media
+
+ proto = 1*(alpha-numeric)
+ ;typically "RTP/AVP" or "udp" for IP4
+
+ port = 1*(DIGIT)
+ ;should in the range "1024" to "65535" inclusive
+ */
+ char *s;
+ unsigned long value;
+ PARSE_ALLOC(p, sdp_media_t, m);
+
+ *result = m;
+
+ m->m_mode = sdp_sendrecv;
+
+ s = token(&r, SPACE, ALPHA DIGIT, NULL);
+ if (s == NULL && p->pr_config)
+ s = token(&r, SPACE, "*", NULL);
+ if (!s) {
+ parsing_error(p, "m= invalid media field");
+ return;
+ }
+
+ sdp_media_type(m, s);
+
+ /* Accept m=* in configuration file */
+ if (p->pr_config && m->m_type == sdp_media_any) {
+ r += strspn(r, SPACE TAB);
+ if (r[0] == '\0') {
+ m->m_proto = sdp_proto_any, m->m_proto_name = "*";
+ return;
+ }
+ }
+
+ if (parse_ul(p, &r, &value, 0)) {
+ parsing_error(p, "m= invalid port number");
+ return;
+ }
+ m->m_port = value;
+
+ if (*r == '/') {
+ r++;
+ if (parse_ul(p, &r, &value, 0)) {
+ parsing_error(p, "m= invalid port specification");
+ return;
+ }
+ m->m_number_of_ports = value;
+ }
+
+ /* alpha-numeric and "/" */
+ s = token(&r, SPACE, ALPHA DIGIT "/", SPACE);
+ if (s == NULL && p->pr_config)
+ s = token(&r, SPACE, "*", SPACE);
+ if (s == NULL) {
+ parsing_error(p, "m= missing protocol");
+ return;
+ }
+
+ if (!STRICT(p) && strcasecmp(s, "RTP") == 0)
+ m->m_proto = sdp_proto_rtp, m->m_proto_name = "RTP/AVP";
+ else
+ sdp_media_transport(m, s);
+
+ /* RTP format list */
+ if (*r && sdp_media_has_rtp(m)) {
+ parse_payload(p, r, &m->m_rtpmaps);
+ return;
+ }
+
+ /* "normal" format list */
+ if (*r) {
+ sdp_list_t **fmt = &m->m_format;
+
+ while (r && *r) {
+ PARSE_ALLOC(p, sdp_list_t, l);
+ *fmt = l;
+ l->l_text = next(&r, SPACE TAB, SPACE TAB);
+ fmt = &l->l_next;
+ }
+ }
+}
+
+/** Set media type */
+void sdp_media_type(sdp_media_t *m, char const *s)
+{
+ if (strcmp(s, "*") == 0)
+ m->m_type = sdp_media_any, m->m_type_name = "*";
+ else if (strcasecmp(s, "audio") == 0)
+ m->m_type = sdp_media_audio, m->m_type_name = "audio";
+ else if (strcasecmp(s, "video") == 0)
+ m->m_type = sdp_media_video, m->m_type_name = "video";
+ else if (strcasecmp(s, "application") == 0)
+ m->m_type = sdp_media_application, m->m_type_name = "application";
+ else if (strcasecmp(s, "data") == 0)
+ m->m_type = sdp_media_data, m->m_type_name = "data";
+ else if (strcasecmp(s, "control") == 0)
+ m->m_type = sdp_media_control, m->m_type_name = "control";
+ else if (strcasecmp(s, "message") == 0)
+ m->m_type = sdp_media_message, m->m_type_name = "message";
+ else if (strcasecmp(s, "image") == 0)
+ m->m_type = sdp_media_image, m->m_type_name = "image";
+ else if (strcasecmp(s, "red") == 0)
+ m->m_type = sdp_media_red, m->m_type_name = "red";
+ else
+ m->m_type = sdp_media_x, m->m_type_name = s;
+}
+
+void sdp_media_transport(sdp_media_t *m, char const *s)
+{
+ if (strcasecmp(s, "*") == 0)
+ m->m_proto = sdp_proto_any, m->m_proto_name = "*";
+ else if (strcasecmp(s, "RTP/AVP") == 0)
+ m->m_proto = sdp_proto_rtp, m->m_proto_name = "RTP/AVP";
+ else if (strcasecmp(s, "RTP/SAVP") == 0)
+ m->m_proto = sdp_proto_srtp, m->m_proto_name = "RTP/SAVP";
+ else if (strcasecmp(s, "UDPTL") == 0)
+ m->m_proto = sdp_proto_udptl, m->m_proto_name = "UDPTL";
+ else if (strcasecmp(s, "UDP") == 0)
+ m->m_proto = sdp_proto_udp, m->m_proto_name = "UDP";
+ else if (strcasecmp(s, "TCP") == 0)
+ m->m_proto = sdp_proto_tcp, m->m_proto_name = "TCP";
+ else if (strcasecmp(s, "TLS") == 0)
+ m->m_proto = sdp_proto_tls, m->m_proto_name = "TLS";
+ else
+ m->m_proto = sdp_proto_x, m->m_proto_name = s;
+}
+
+/** Check if media uses RTP as its transport protocol. */
+int sdp_media_has_rtp(sdp_media_t const *m)
+{
+ return m && (m->m_proto == sdp_proto_rtp || m->m_proto == sdp_proto_srtp);
+}
+
+#define RTPMAP(pt, encoding, rate, params) \
+ { sizeof(sdp_rtpmap_t), NULL, encoding, rate, (char *)params, NULL, 1, pt, 0 }
+
+/* rtpmaps for well-known codecs */
+static sdp_rtpmap_t const
+ sdp_rtpmap_pcmu = RTPMAP(0, "PCMU", 8000, 0),
+ sdp_rtpmap_1016 = RTPMAP(1, "1016", 8000, 0),
+ sdp_rtpmap_g721 = RTPMAP(2, "G721", 8000, 0),
+ sdp_rtpmap_gsm = RTPMAP(3, "GSM", 8000, 0),
+ sdp_rtpmap_g723 = RTPMAP(4, "G723", 8000, 0),
+ sdp_rtpmap_dvi4_8000 = RTPMAP(5, "DVI4", 8000, 0),
+ sdp_rtpmap_dvi4_16000 = RTPMAP(6, "DVI4", 16000, 0),
+ sdp_rtpmap_lpc = RTPMAP(7, "LPC", 8000, 0),
+ sdp_rtpmap_pcma = RTPMAP(8, "PCMA", 8000, 0),
+ sdp_rtpmap_g722 = RTPMAP(9, "G722", 8000, 0),
+ sdp_rtpmap_l16_2 = RTPMAP(10, "L16", 44100, "2"),
+ sdp_rtpmap_l16 = RTPMAP(11, "L16", 44100, 0),
+ sdp_rtpmap_qcelp = RTPMAP(12, "QCELP", 8000, 0),
+ sdp_rtpmap_cn = RTPMAP(13, "CN", 8000, 0),
+ sdp_rtpmap_mpa = RTPMAP(14, "MPA", 90000, 0),
+ sdp_rtpmap_g728 = RTPMAP(15, "G728", 8000, 0),
+ sdp_rtpmap_dvi4_11025 = RTPMAP(16, "DVI4", 11025, 0),
+ sdp_rtpmap_dvi4_22050 = RTPMAP(17, "DVI4", 22050, 0),
+ sdp_rtpmap_g729 = RTPMAP(18, "G729", 8000, 0),
+ sdp_rtpmap_reserved_cn = RTPMAP(19, "CN", 8000, 0),
+ /* video codecs */
+ sdp_rtpmap_celb = RTPMAP(25, "CelB", 90000, 0),
+ sdp_rtpmap_jpeg = RTPMAP(26, "JPEG", 90000, 0),
+ sdp_rtpmap_nv = RTPMAP(28, "nv", 90000, 0),
+ sdp_rtpmap_h261 = RTPMAP(31, "H261", 90000, 0),
+ sdp_rtpmap_mpv = RTPMAP(32, "MPV", 90000, 0),
+ sdp_rtpmap_mp2t = RTPMAP(33, "MP2T", 90000, 0),
+ sdp_rtpmap_h263 = RTPMAP(34, "H263", 90000, 0);
+
+/** Table of rtpmap structures by payload type numbers.
+ *
+ * The table of reserved payload numbers is constructed from @RFC3551
+ * and @RFC1890. Note the clock rate of G722.
+ *
+ * Use sdp_rtpmap_dup() to copy these structures.
+ */
+sdp_rtpmap_t const * const sdp_rtpmap_well_known[128] =
+{
+ &sdp_rtpmap_pcmu, /* 0 */
+ &sdp_rtpmap_1016, /* 1 */
+ &sdp_rtpmap_g721, /* 2 */
+ &sdp_rtpmap_gsm, /* 3 */
+ &sdp_rtpmap_g723, /* 4 */
+ &sdp_rtpmap_dvi4_8000, /* 5 */
+ &sdp_rtpmap_dvi4_16000, /* 6 */
+ &sdp_rtpmap_lpc, /* 7 */
+ &sdp_rtpmap_pcma, /* 8 */
+ &sdp_rtpmap_g722, /* 9 */
+ &sdp_rtpmap_l16_2, /* 10 */
+ &sdp_rtpmap_l16, /* 11 */
+ &sdp_rtpmap_qcelp, /* 12 */
+ &sdp_rtpmap_cn, /* 13 */
+ &sdp_rtpmap_mpa, /* 14 */
+ &sdp_rtpmap_g728, /* 15 */
+ &sdp_rtpmap_dvi4_11025, /* 16 */
+ &sdp_rtpmap_dvi4_22050, /* 17 */
+ &sdp_rtpmap_g729, /* 18 */
+ &sdp_rtpmap_reserved_cn, /* 19 */
+ NULL, /* 20 */
+ NULL, /* 21 */
+ NULL, /* 22 */
+ NULL, /* 23 */
+ NULL, /* 24 */
+ &sdp_rtpmap_celb, /* 25 */
+ &sdp_rtpmap_jpeg, /* 26 */
+ NULL, /* 27 */
+ &sdp_rtpmap_nv, /* 28 */
+ NULL, /* 29 */
+ NULL, /* 30 */
+ &sdp_rtpmap_h261, /* 31 */
+ &sdp_rtpmap_mpv, /* 32 */
+ &sdp_rtpmap_mp2t, /* 33 */
+ &sdp_rtpmap_h263, /* 34 */
+ NULL,
+};
+
+/**
+ * The function parse_payload() parses an RTP payload type list, and
+ * creates an rtpmap structure for each payload type.
+ *
+ * @param p pointer to SDP parser object
+ * @param r pointer to record data
+ * @param result pointer to which parsed record is assigned
+ */
+static void parse_payload(sdp_parser_t *p, char *r, sdp_rtpmap_t **result)
+{
+ while (*r) {
+ unsigned long value;
+
+ if (parse_ul(p, &r, &value, 128) == 0) {
+ PARSE_ALLOC(p, sdp_rtpmap_t, rm);
+
+ assert(0 <= value && value < 128);
+
+ *result = rm; result = &rm->rm_next;
+
+ if (sdp_rtpmap_well_known[value]) {
+ *rm = *sdp_rtpmap_well_known[value];
+ }
+ else {
+ rm->rm_predef = 1;
+ rm->rm_pt = value;
+ rm->rm_encoding = "";
+ rm->rm_rate = 0;
+ }
+ }
+ else if (p->pr_config && r[0] == '*' && (r[1] == ' ' || r[1] == '\0')) {
+ PARSE_ALLOC(p, sdp_rtpmap_t, rm);
+
+ *result = rm; result = &rm->rm_next;
+
+ rm->rm_predef = 1;
+ rm->rm_any = 1;
+ rm->rm_encoding = "*";
+ rm->rm_rate = 0;
+
+ return;
+ }
+ else {
+ parsing_error(p, "m= invalid format for RTP/AVT");
+
+ return;
+ }
+ }
+}
+
+/* -------------------------------------------------------------------------
+ * Function parse_media_attr() - parse a media-specific "a=" field
+ *
+ * Description:
+ * This function parses a media-specific attribute field.
+ *
+ * Parameters:
+ * p - pointer to SDP parser object
+ * r - pointer to record data
+ * result - pointer to which parsed record is assigned
+ */
+static void parse_media_attr(sdp_parser_t *p, char *r, sdp_media_t *m,
+ sdp_attribute_t **result)
+{
+ /*
+ attribute-fields = *("a=" attribute CRLF)
+
+ attribute = (att-field ":" att-value) | att-field
+
+ att-field = 1*(alpha-numeric)
+
+ att-value = byte-string
+
+ a=rtpmap:<payload type> <encoding name>/<clock rate>[/<encoding parameters>]
+ a=fmtp:<payload type> <parameters>
+ */
+ int rtp = sdp_media_has_rtp(m);
+ char *name = NULL, *value = NULL;
+ int n;
+
+ if (!(name = token(&r, ":", ALPHA DIGIT "-", SPACE TAB))) {
+ parsing_error(p,"invalid attribute name");
+ return;
+ }
+
+ if (*r)
+ value = r;
+ else
+ PARSE_CHECK_REST(p, r, "a");
+
+ if (p->pr_mode_manual)
+ ;
+ else if (strcasecmp(name, "inactive") == 0) {
+ m->m_mode = sdp_inactive;
+ return;
+ }
+ else if (strcasecmp(name, "sendonly") == 0) {
+ m->m_mode = sdp_sendonly;
+ return;
+ }
+ else if (strcasecmp(name, "recvonly") == 0) {
+ m->m_mode = sdp_recvonly;
+ return;
+ }
+ else if (strcasecmp(name, "sendrecv") == 0) {
+ m->m_mode = sdp_sendrecv;
+ return;
+ }
+
+ if (rtp && strcasecmp(name, "rtpmap") == 0) {
+ if ((n = parse_rtpmap(p, r, m)) == 0 || n < -1)
+ return;
+ }
+ else if (rtp && strcasecmp(name, "fmtp") == 0) {
+ if ((n = parse_fmtp(p, r, m)) == 0 || n < -1)
+ return;
+ }
+ else {
+ PARSE_ALLOC(p, sdp_attribute_t, a);
+ *result = a;
+
+ a->a_name = name;
+ a->a_value = value;
+ }
+}
+
+/** Parse rtpmap attribute.
+ *
+ * a=rtpmap:<payload type> <encoding name>/<clock rate>[/<encoding parameters>]
+ */
+static int parse_rtpmap(sdp_parser_t *p, char *r, sdp_media_t *m)
+{
+ unsigned long pt, rate;
+ char *encoding, *params;
+ sdp_rtpmap_t *rm;
+
+ int strict = STRICT(p);
+
+ if (parse_ul(p, &r, &pt, 128)) {
+ if (strict)
+ parsing_error(p, "a=rtpmap: invalid payload type");
+ return -1;
+ }
+
+ for (rm = m->m_rtpmaps; rm; rm = rm->rm_next)
+ if (rm->rm_pt == pt)
+ break;
+
+ if (!rm) {
+ if (strict)
+ parsing_error(p, "a=rtpmap:%lu: unknown payload type", pt);
+ return -1;
+ }
+
+ encoding = token(&r, "/", ALPHA DIGIT "-", NULL);
+ if (!r) {
+ parsing_error(p, "a=rtpmap:%lu: missing <clock rate>", pt);
+ return -2;
+ }
+ if (parse_ul(p, &r, &rate, 0)) {
+ parsing_error(p, "a=rtpmap:%lu %s: invalid <clock rate>", pt, encoding);
+ return -2;
+ }
+
+ if (*r == '/')
+ params = ++r;
+ else
+ params = 0;
+
+ rm->rm_predef = 0;
+ rm->rm_encoding = encoding;
+ rm->rm_rate = rate;
+ rm->rm_params = params;
+
+ return 0;
+}
+
+/** Parse fmtp attribute.
+ *
+ * a=fmtp:<payload type> <parameters>
+ */
+static int parse_fmtp(sdp_parser_t *p, char *r, sdp_media_t *m)
+{
+ unsigned long pt;
+ sdp_rtpmap_t *rm;
+
+ int strict = STRICT(p);
+
+ if (parse_ul(p, &r, &pt, 128)) {
+ if (strict)
+ parsing_error(p, "a=rtpmap: invalid payload type");
+ return -1;
+ }
+
+ for (rm = m->m_rtpmaps; rm; rm = rm->rm_next)
+ if (rm->rm_pt == pt)
+ break;
+
+ if (!rm) {
+ if (strict)
+ parsing_error(p, "a=fmtp:%lu: unknown payload type", pt);
+ return -1;
+ }
+
+ rm->rm_fmtp = r;
+ return 0;
+}
+
+/* -------------------------------------------------------------------------
+ * Function parse_descs() - parse media descriptors
+ *
+ * Description:
+ * This function parses media descriptors at the end of SDP message.
+ *
+ * Parameters:
+ * p - pointer to SDP parser object
+ * record - pointer to first media field
+ * message - pointer to rest
+ * medias - pointer to which parsed media structures are assigned
+ */
+static void parse_descs(sdp_parser_t *p,
+ char *record,
+ char *message,
+ sdp_media_t **medias)
+{
+ char *rest;
+ const char *strip;
+ sdp_media_t *m = NULL;
+ sdp_connection_t **connections = NULL;
+ sdp_bandwidth_t **bandwidths = NULL;
+ sdp_attribute_t **attributes = NULL;
+
+ if (!STRICT(p))
+ strip = SPACE TAB; /* skip initial whitespace */
+ else
+ strip = NULL;
+
+ for (;
+ record && p->pr_ok;
+ record = next(&message, CRLF, strip)) {
+ char field = record[0];
+
+ rest = record + 2; rest += strspn(rest, strip);
+
+ if (record[1] == '=') switch (field) {
+ case 'c':
+ assert(connections);
+ parse_connection(p, rest, connections);
+ connections = &(*connections)->c_next;
+ break;
+
+ case 'b':
+ assert(bandwidths);
+ parse_bandwidth(p, rest, bandwidths);
+ bandwidths = &(*bandwidths)->b_next;
+ break;
+
+ case 'k':
+ parse_key(p, rest, &m->m_key);
+ break;
+
+ case 'a':
+ assert(attributes);
+ parse_media_attr(p, rest, m, attributes);
+ if (*attributes)
+ attributes = &(*attributes)->a_next;
+ break;
+
+ case 'm':
+ parse_media(p, rest, medias);
+ m = *medias;
+ if (m) {
+ m->m_mode = p->pr_session_mode;
+ medias = &m->m_next;
+ connections = &m->m_connections;
+ bandwidths = &m->m_bandwidths;
+ attributes = &m->m_attributes;
+ }
+ }
+ }
+}
+
+static void parse_text_list(sdp_parser_t *p, char *r, sdp_list_t **result)
+{
+ PARSE_ALLOC(p, sdp_list_t, l);
+
+ *result = l;
+
+ l->l_text = r;
+}
+
+/*
+ * parse_ul: parse an unsigned long
+ */
+static int parse_ul(sdp_parser_t *p, char **r,
+ unsigned long *result, unsigned long max)
+{
+ char *ul = *r;
+
+ ul += strspn(ul, SPACE TAB);
+
+ *result = strtoul(ul, r, 10);
+ if (ul != *r && !(max && max <= *result)) {
+ *r += strspn(*r, SPACE TAB);
+ return 0;
+ }
+
+ return -1;
+}
+
+#if !HAVE_STRTOULL
+unsigned longlong strtoull(char const *string, char **return_end, int base);
+#endif
+
+/*
+ * parse_ull: parse an unsigned long long
+ */
+static int parse_ull(sdp_parser_t *p, char **r,
+ uint64_t *result, uint64_t max)
+{
+ unsigned longlong ull;
+
+ char *s = *r;
+
+ s += strspn(s, SPACE TAB);
+
+ ull = strtoull(s, r, 10);
+
+ if (s != *r && !(max && max <= ull)) {
+ *result = (uint64_t)ull;
+ *r += strspn(*r, SPACE TAB);
+ return 0;
+ }
+
+ return -1;
+}
+
+static char *token(char **message,
+ const char *sep,
+ const char *legal,
+ const char *strip)
+{
+ size_t n;
+ char *retval = *message;
+
+ if (strip)
+ retval += strspn(retval, strip);
+
+ if (legal)
+ n = strspn(retval, legal);
+ else
+ n = strcspn(retval, sep);
+
+ if (n == 0)
+ return NULL;
+
+ if (retval[n]) {
+ retval[n++] = '\0';
+ n += strspn(retval + n, sep);
+ }
+
+ *message = retval + n;
+
+ if (*retval == '\0')
+ return NULL;
+
+ return retval;
+}
+
+static char *next(char **message, const char *sep, const char *strip)
+{
+ size_t n;
+ char *retval = *message;
+
+ if (strip)
+ retval += strspn(retval, strip);
+
+ n = strcspn(retval, sep);
+
+ if (n == 0)
+ return NULL;
+
+ if (retval[n]) {
+ retval[n++] = '\0';
+ n += strspn(retval + n, sep);
+ }
+
+ *message = retval + n;
+
+ if (*retval == '\0')
+ return NULL;
+
+ return retval;
+}
+
+static void parsing_error(sdp_parser_t *p, char const *fmt, ...)
+{
+ int n;
+ va_list ap;
+ va_start(ap, fmt);
+
+ memset(p->pr_error, 0, sizeof(p->pr_error));
+ n = vsnprintf(p->pr_error, sizeof(p->pr_error), fmt, ap);
+ va_end(ap);
+
+ p->pr_ok = 0;
+}
+
+static void parse_alloc_error(sdp_parser_t *p, const char *typename)
+{
+ parsing_error(p, "memory exhausted (while allocating memory for %s)",
+ typename);
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_print.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_print.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,734 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup sdp_printer
+ *
+ * @CFILE sdp_print.c Simple SDP printer interface.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Fri Feb 18 10:25:08 2000 ppessi
+ */
+
+#include "config.h"
+
+#include <sofia-sip/su_alloc.h>
+
+#include "sofia-sip/sdp.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <assert.h>
+
+/* ========================================================================= */
+/* Printing API */
+/* */
+
+#define SDP_BLOCK (512)
+
+#define CRLF "\015\012"
+
+typedef unsigned longlong ull;
+
+/** @typedef struct sdp_printer_s sdp_printer_t
+ *
+ * SDP printer handle.
+ *
+ * @sa #sdp_session_t, sdp_print(), sdp_printing_error(),
+ * sdp_message(), sdp_message_size(), sdp_printer_free()
+ */
+
+struct sdp_printer_s {
+ int pr_size;
+ su_home_t *pr_home;
+ char *pr_buffer;
+ size_t pr_bsiz;
+ size_t pr_used;
+ /* various flags */
+ unsigned pr_ok : 1;
+ unsigned pr_strict : 1;
+ unsigned pr_owns_buffer:1;
+ unsigned pr_may_realloc:1;
+ unsigned pr_all_rtpmaps:1;
+ unsigned pr_mode_manual:1;
+ unsigned pr_mode_always:1;
+};
+
+static struct sdp_printer_s printer_memory_error = {
+ sizeof(printer_memory_error),
+ NULL,
+ "memory exhausted",
+ sizeof(printer_memory_error.pr_buffer),
+ sizeof(printer_memory_error.pr_buffer)
+};
+
+static void print_session(sdp_printer_t *p, sdp_session_t const *session);
+
+/** Print a SDP description.
+ *
+ * Encode the contents of the SDP session structure #sdp_session_t
+ * to the @a msgbuf. The @a msgbuf has size @a msgsize
+ * bytes. If @a msgbuf is @c NULL, the sdp_print() function allocates the
+ * required buffer from the @a home heap.
+ *
+ * @param home Memory home (may be NULL).
+ * @param session SDP session description structure to be encoded.
+ * @param msgbuf Buffer to which encoding is stored (may be NULL).
+ * @param msgsize Size of @a msgbuf.
+ * @param flags Flags specifying the encoding options.
+ *
+ * The @a flags specify encoding options as follows:
+ *
+ * @li #sdp_f_strict - Printer should only emit messages conforming strictly
+ * to the * specification.
+ *
+ * @li #sdp_f_realloc - If this flag is specified, and @a msgbuf is too
+ * small for the resulting SDP message, @c sdp_print() may allocate a new
+ * buffer for it from the heap.
+ *
+ * @li #sdp_f_print_prefix - The buffer provided by caller already contains
+ * valid data. The result will concatenated to the string in the buffer.
+ *
+ * @li #sdp_f_mode_always - Always add mode attributes to media
+ *
+ * @li #sdp_f_mode_manual - Do not generate mode attributes
+ *
+ * @return
+ * Always return a handle to an #sdp_printer_t object.
+ *
+ * @sa #sdp_printer_t, #sdp_session_t, sdp_printing_error(),
+ * sdp_message(), sdp_message_size(), sdp_printer_free(),
+ * sdp_parse().
+ */
+sdp_printer_t *sdp_print(su_home_t *home,
+ sdp_session_t const *session,
+ char msgbuf[],
+ isize_t msgsize,
+ int flags)
+{
+ sdp_printer_t *p = su_salloc(home, sizeof(*p));
+
+ if (p) {
+ p->pr_size = sizeof(p);
+ p->pr_home = home;
+ p->pr_used = 0;
+ if (msgbuf) {
+ p->pr_may_realloc = (flags & sdp_f_realloc) != 0;
+ p->pr_buffer = msgbuf;
+ p->pr_bsiz = msgsize;
+ if (flags & sdp_f_print_prefix)
+ p->pr_used = strlen(msgbuf);
+ }
+ else {
+ p->pr_owns_buffer = 1;
+ p->pr_buffer = su_alloc(home, SDP_BLOCK);
+ p->pr_bsiz = SDP_BLOCK;
+ }
+ p->pr_strict = (flags & sdp_f_strict) != 0;
+ p->pr_all_rtpmaps = (flags & sdp_f_all_rtpmaps) != 0;
+ p->pr_mode_manual = (flags & sdp_f_mode_manual) != 0;
+ p->pr_mode_always = (flags & sdp_f_mode_always) != 0;
+
+ print_session(p, session);
+
+ return p;
+ }
+ else {
+ return &printer_memory_error;
+ }
+}
+
+/** @brief Get encoding error.
+ *
+ * Return a message describing the encoding error.
+ *
+ * @param p Pointer to an #sdp_printer_t object.
+ *
+ * @return
+ * Return a pointer to C string describing printing errors, or NULL if no
+ * error was encountered.
+ */
+char const *sdp_printing_error(sdp_printer_t *p)
+{
+ if (p)
+ if (!p->pr_ok)
+ return p->pr_buffer;
+ else
+ return NULL;
+ else
+ return "null sdp_printer_t*";
+}
+
+/** @brief Get encoded SDP message.
+ *
+ * Return a pointer to a C string containing the SDP message.
+ *
+ * @param p Pointer to an #sdp_printer_t object.
+ *
+ * @return
+ * Return a pointer to a C string containing the encoded SDP message, or
+ * NULL upon an error.
+ */
+char const *sdp_message(sdp_printer_t *p)
+{
+ if (p && p->pr_ok)
+ return p->pr_buffer;
+ else
+ return NULL;
+}
+
+/** @brief Get size of encoded SDP message.
+ *
+ * Return the size of the encoded SDP message.
+ *
+ * @param p Pointer to an #sdp_printer_t object.
+ *
+ * @return
+ * Number of bytes in SDP message excluding final NUL or 0 upon an error.
+ */
+isize_t sdp_message_size(sdp_printer_t *p)
+{
+ if (p && p->pr_ok)
+ return p->pr_used;
+ else
+ return 0;
+}
+
+/** Free a SDP printer.
+ *
+ * Free the printer object @a p and the message buffer possibly associated
+ * with it.
+ *
+ * @param p Pointer to an #sdp_printer_t object.
+ */
+void sdp_printer_free(sdp_printer_t *p)
+{
+ if (p && p != &printer_memory_error) {
+ if (p->pr_owns_buffer && p->pr_buffer)
+ su_free(p->pr_home, p->pr_buffer), p->pr_buffer = NULL;
+ su_free(p->pr_home, p);
+ }
+}
+
+/* ========================================================================= */
+static void print_version(sdp_printer_t *p, sdp_version_t const *v);
+static void print_origin(sdp_printer_t *p, sdp_origin_t const *o);
+static void print_subject(sdp_printer_t *p, sdp_text_t *s);
+static void print_information(sdp_printer_t *p, sdp_text_t *i);
+static void print_uri(sdp_printer_t *p, sdp_text_t *u);
+static void print_emails(sdp_printer_t *p, sdp_list_t const *e);
+static void print_phones(sdp_printer_t *p, sdp_list_t const *ph);
+static void print_connection(sdp_printer_t *p, sdp_connection_t const *c);
+static void print_connection_list(sdp_printer_t *p, sdp_connection_t const *c);
+static void print_connection2(sdp_printer_t *p, sdp_connection_t const *c);
+static void print_bandwidths(sdp_printer_t *p, sdp_bandwidth_t const *b);
+static void print_time(sdp_printer_t *p, sdp_time_t const *t);
+static void print_repeat(sdp_printer_t *p, sdp_repeat_t const *r);
+static void print_zone(sdp_printer_t *p, sdp_zone_t const *z);
+static void print_typed_time(sdp_printer_t *p, unsigned long t);
+static void print_key(sdp_printer_t *p, sdp_key_t const *k);
+static void print_attributes(sdp_printer_t *p, sdp_attribute_t const *a);
+static void print_charset(sdp_printer_t *p, sdp_text_t *charset);
+static void print_media(sdp_printer_t *p, sdp_session_t const *,
+ sdp_media_t const *m);
+
+static void print_text_list(sdp_printer_t*,
+ const char *, sdp_list_t const *l);
+
+static void sdp_printf(sdp_printer_t *p, const char *fmt, ...);
+static void printing_error(sdp_printer_t *p, const char *fmt, ...);
+
+static void print_session(sdp_printer_t *p, sdp_session_t const *sdp)
+{
+ p->pr_ok = 1;
+
+ if (!sdp)
+ printing_error(p, "NULL session description");
+ if (p->pr_ok && sdp->sdp_version)
+ print_version(p, sdp->sdp_version);
+ if (p->pr_ok && sdp->sdp_origin)
+ print_origin(p, sdp->sdp_origin);
+ if (p->pr_ok && sdp->sdp_subject)
+ print_subject(p, sdp->sdp_subject);
+ if (p->pr_ok && sdp->sdp_information)
+ print_information(p, sdp->sdp_information);
+ if (p->pr_ok && sdp->sdp_uri)
+ print_uri(p, sdp->sdp_uri);
+ if (p->pr_ok && sdp->sdp_emails)
+ print_emails(p, sdp->sdp_emails);
+ if (p->pr_ok && sdp->sdp_phones)
+ print_phones(p, sdp->sdp_phones);
+ if (p->pr_ok && sdp->sdp_connection)
+ print_connection(p, sdp->sdp_connection);
+ if (p->pr_ok && sdp->sdp_bandwidths)
+ print_bandwidths(p, sdp->sdp_bandwidths);
+ if (p->pr_ok)
+ print_time(p, sdp->sdp_time);
+ if (p->pr_ok && sdp->sdp_time) {
+ if (p->pr_ok && sdp->sdp_time->t_repeat)
+ print_repeat(p, sdp->sdp_time->t_repeat);
+ if (p->pr_ok && sdp->sdp_time->t_zone)
+ print_zone(p, sdp->sdp_time->t_zone);
+ }
+ if (p->pr_ok && sdp->sdp_key)
+ print_key(p, sdp->sdp_key);
+ if (p->pr_ok && sdp->sdp_charset)
+ print_charset(p, sdp->sdp_charset);
+ if (p->pr_ok && sdp->sdp_attributes)
+ print_attributes(p, sdp->sdp_attributes);
+ if (p->pr_ok && sdp->sdp_media)
+ print_media(p, sdp, sdp->sdp_media);
+}
+
+static void print_version(sdp_printer_t *p, sdp_version_t const *v)
+{
+ sdp_printf(p, "v=%lu" CRLF, *v);
+}
+
+static void print_origin(sdp_printer_t *p, sdp_origin_t const *o)
+{
+ if (!o->o_address ||
+ !o->o_address->c_address ||
+ o->o_address->c_ttl != 0 ||
+ o->o_address->c_groups > 1) {
+ printing_error(p, "o= address malformed");
+ return;
+ }
+
+ sdp_printf(p, "o=%s "LLU" "LLU" ",
+ o->o_username,
+ (ull)o->o_id,
+ (ull)o->o_version);
+
+ print_connection2(p, o->o_address);
+}
+
+static void print_subject(sdp_printer_t *p, sdp_text_t *subject)
+{
+ sdp_printf(p, "s=%s" CRLF, subject);
+}
+
+static void print_information(sdp_printer_t *p, sdp_text_t *information)
+{
+ sdp_printf(p, "i=%s" CRLF, information);
+}
+
+static void print_uri(sdp_printer_t *p, sdp_text_t *uri)
+{
+ sdp_printf(p, "u=%s" CRLF, uri);
+}
+
+static void print_emails(sdp_printer_t *p, sdp_list_t const *emails)
+{
+ print_text_list(p, "e=%s" CRLF, emails);
+}
+
+static void print_phones(sdp_printer_t *p, sdp_list_t const *phones)
+{
+ print_text_list(p, "p=%s" CRLF, phones);
+}
+
+static void print_connection(sdp_printer_t *p, sdp_connection_t const *c)
+{
+ sdp_printf(p, "c=");
+ print_connection2(p, c);
+}
+
+static void print_connection_list(sdp_printer_t *p, sdp_connection_t const *c)
+{
+ for (; c ; c = c->c_next) {
+ sdp_printf(p, "c=");
+ print_connection2(p, c);
+ }
+}
+
+static void print_connection2(sdp_printer_t *p, sdp_connection_t const *c)
+{
+ const char *nettype;
+ const char *addrtype;
+
+ switch (c->c_nettype) {
+ case sdp_net_x:
+ nettype = NULL;
+ break;
+ case sdp_net_in:
+ nettype = "IN ";
+ break;
+ default:
+ printing_error(p, "unknown nettype %u", c->c_nettype);
+ return;
+ }
+
+ switch (c->c_addrtype) {
+ case sdp_addr_x:
+ addrtype = NULL;
+ break;
+ case sdp_addr_ip4:
+ nettype = "IN ";
+ addrtype = "IP4 ";
+ break;
+ case sdp_addr_ip6:
+ nettype = "IN ";
+ addrtype = "IP6 ";
+ break;
+ default:
+ printing_error(p, "unknown address type %u", c->c_addrtype);
+ return;
+ }
+
+ if (c->c_address == NULL) {
+ printing_error(p, "missing address");
+ return;
+ }
+
+ sdp_printf(p, "%s%s%s", nettype, addrtype, c->c_address);
+ if (c->c_mcast || c->c_ttl) {
+ sdp_printf(p, "/%u", c->c_ttl);
+ if (c->c_groups > 1)
+ sdp_printf(p, "/%u", c->c_groups);
+ }
+ sdp_printf(p, CRLF);
+}
+
+static void print_bandwidths(sdp_printer_t *p, sdp_bandwidth_t const *b)
+{
+ for (; b ; b = b->b_next) {
+ char const *name;
+
+ switch (b->b_modifier) {
+ case sdp_bw_ct: name = "CT"; break;
+ case sdp_bw_as: name = "AS"; break;
+ default: name = b->b_modifier_name; break;
+ }
+
+ sdp_printf(p, "b=%s:%lu" CRLF, name, b->b_value);
+ }
+}
+
+static void print_time(sdp_printer_t *p, sdp_time_t const *t)
+{
+ if (t || p->pr_strict)
+ sdp_printf(p, "t=%lu %lu" CRLF, t ? t->t_start : 0L, t ? t->t_stop : 0L);
+}
+
+static void print_repeat(sdp_printer_t *p, sdp_repeat_t const *r)
+{
+ int i;
+
+ sdp_printf(p, "r=");
+ print_typed_time(p, r->r_interval);
+ sdp_printf(p, " ");
+ print_typed_time(p, r->r_duration);
+ for (i = 0; i < r->r_number_of_offsets; i++) {
+ sdp_printf(p, " ");
+ print_typed_time(p, r->r_offsets[i]);
+ }
+ sdp_printf(p, CRLF);
+}
+
+static void print_zone(sdp_printer_t *p, sdp_zone_t const *z)
+{
+ int i;
+ sdp_printf(p, "z=");
+
+ for (i = 0; i < z->z_number_of_adjustments; i++) {
+ int negative = z->z_adjustments[i].z_offset < 0L;
+ sdp_printf(p, "%s%lu %s",
+ i > 0 ? " " : "",
+ z->z_adjustments[i].z_at,
+ negative ? "-" : "");
+ if (negative)
+ print_typed_time(p, -z->z_adjustments[i].z_offset);
+ else
+ print_typed_time(p, z->z_adjustments[i].z_offset);
+ }
+
+ sdp_printf(p, CRLF);
+}
+
+static void print_typed_time(sdp_printer_t *p, unsigned long t)
+{
+ if (t % 60 || t == 0) {
+ sdp_printf(p, "%lu", t);
+ }
+ else {
+ t /= 60;
+
+ if (t % 60) {
+ sdp_printf(p, "%lum", t); /* minutes */
+ }
+ else {
+ t /= 60;
+
+ if (t % 24) {
+ sdp_printf(p, "%luh", t); /* hours */
+ }
+ else {
+ t /= 24;
+
+ sdp_printf(p, "%lud", t); /* days */
+ }
+ }
+ }
+}
+
+static void print_key(sdp_printer_t *p, sdp_key_t const *k)
+{
+ const char *method;
+ int have_material = k->k_material != NULL;
+
+ switch (k->k_method) {
+ case sdp_key_x:
+ method = k->k_method_name; break;
+ case sdp_key_clear:
+ method = "clear"; break;
+ case sdp_key_base64:
+ method = "base64"; break;
+ case sdp_key_uri:
+ method = "uri"; break;
+ case sdp_key_prompt:
+ method = "prompt"; break;
+ default:
+ printing_error(p, "unknown key method (%d)", k->k_method);
+ return;
+ }
+
+ sdp_printf(p, "k=%s%s%s" CRLF, method,
+ have_material ? ":" : "",
+ have_material ? k->k_material : "");
+}
+
+static void print_attributes(sdp_printer_t *p, sdp_attribute_t const *a)
+{
+ for (;a; a = a->a_next) {
+ char const *name = a->a_name;
+ char const *value = a->a_value;
+ sdp_printf(p, "a=%s%s%s" CRLF, name, value ? ":" : "", value ? value : "");
+ }
+}
+
+static void
+print_attributes_without_mode(sdp_printer_t *p, sdp_attribute_t const *a)
+{
+ for (;a; a = a->a_next) {
+ char const *name = a->a_name;
+ char const *value = a->a_value;
+
+ if (strcasecmp(name, "inactive") == 0 ||
+ strcasecmp(name, "sendonly") == 0 ||
+ strcasecmp(name, "recvonly") == 0 ||
+ strcasecmp(name, "sendrecv") == 0)
+ continue;
+
+ sdp_printf(p, "a=%s%s%s" CRLF, name, value ? ":" : "", value ? value : "");
+ }
+}
+
+static void print_charset(sdp_printer_t *p, sdp_text_t *charset)
+{
+ sdp_printf(p, "a=charset%s%s" CRLF, charset ? ":" : "", charset ? charset : "");
+}
+
+static void print_media(sdp_printer_t *p,
+ sdp_session_t const *sdp,
+ sdp_media_t const *m)
+{
+ char const *media, *proto;
+ sdp_rtpmap_t *rm;
+
+ sdp_mode_t session_mode = sdp_sendrecv;
+
+ if (!p->pr_mode_manual)
+ session_mode = sdp_attribute_mode(sdp->sdp_attributes, sdp_sendrecv);
+
+ for (;m ; m = m->m_next) {
+ switch (m->m_type) {
+ case sdp_media_audio: media = "audio"; break;
+ case sdp_media_video: media = "video"; break;
+ case sdp_media_application: media = "application"; break;
+ case sdp_media_data: media = "data"; break;
+ case sdp_media_control: media = "control"; break;
+ case sdp_media_message: media = "message"; break;
+ case sdp_media_image : media = "image"; break;
+ default: media = m->m_type_name;
+ }
+
+ switch (m->m_proto) {
+ case sdp_proto_tcp: proto = "tcp"; break;
+ case sdp_proto_udp: proto = "udp"; break;
+ case sdp_proto_rtp: proto = "RTP/AVP"; break;
+ case sdp_proto_srtp: proto = "RTP/SAVP"; break;
+ case sdp_proto_udptl: proto = "UDPTL"; break;
+ case sdp_proto_tls: proto = "tls"; break;
+ default: proto = m->m_proto_name; break;
+ }
+
+ if (m->m_number_of_ports <= 1)
+ sdp_printf(p, "m=%s %u %s", media, m->m_port, proto);
+ else
+ sdp_printf(p, "m=%s %u/%u %s",
+ media, m->m_port, m->m_number_of_ports, proto);
+
+ if (m->m_rtpmaps) {
+ for (rm = m->m_rtpmaps; rm; rm = rm->rm_next) {
+ if (rm->rm_any)
+ sdp_printf(p, " *");
+ else
+ sdp_printf(p, " %u", (unsigned)rm->rm_pt);
+ }
+ }
+ else if (m->m_format) {
+ sdp_list_t *l = m->m_format;
+ for (; l; l = l->l_next)
+ sdp_printf(p, " %s", l->l_text);
+ }
+ else {
+ sdp_printf(p, " 9"); /* SDP syntax requires at least one format.
+ 9 is used by nobody, right?. */
+ }
+
+
+ sdp_printf(p, CRLF);
+
+ if (m->m_information)
+ print_information(p, m->m_information);
+ if (m->m_connections)
+#ifdef nomore
+ if (m->m_connections != sdp->sdp_connection)
+#endif
+ print_connection_list(p, m->m_connections);
+ if (m->m_bandwidths)
+ print_bandwidths(p, m->m_bandwidths);
+ if (m->m_key)
+ print_key(p, m->m_key);
+
+ for (rm = m->m_rtpmaps; rm; rm = rm->rm_next) {
+ if (!rm->rm_predef || p->pr_all_rtpmaps)
+ sdp_printf(p, "a=rtpmap:%u %s/%lu%s%s" CRLF,
+ rm->rm_pt, rm->rm_encoding, rm->rm_rate,
+ rm->rm_params ? "/" : "",
+ rm->rm_params ? rm->rm_params : "");
+ if (rm->rm_fmtp)
+ sdp_printf(p, "a=fmtp:%u %s" CRLF,
+ rm->rm_pt, rm->rm_fmtp);
+ }
+
+ if (!p->pr_mode_manual && !m->m_rejected &&
+ (m->m_mode != (unsigned int)session_mode || p->pr_mode_always)) {
+ switch (m->m_mode) {
+ case sdp_inactive:
+ sdp_printf(p, "a=inactive" CRLF);
+ break;
+ case sdp_sendonly:
+ sdp_printf(p, "a=sendonly" CRLF);
+ break;
+ case sdp_recvonly:
+ sdp_printf(p, "a=recvonly" CRLF);
+ break;
+ case sdp_sendrecv:
+ sdp_printf(p, "a=sendrecv" CRLF);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (p->pr_mode_manual)
+ print_attributes(p, m->m_attributes);
+ else
+ print_attributes_without_mode(p, m->m_attributes);
+ }
+}
+
+static void print_text_list(sdp_printer_t *p,
+ const char *fmt, sdp_list_t const *l)
+{
+ for (;l; l = l->l_next) {
+ sdp_printf(p, fmt, l->l_text);
+ }
+}
+
+static void printing_error(sdp_printer_t *p, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+
+ if (p->pr_ok) {
+ int n;
+
+ n = vsnprintf(p->pr_buffer, p->pr_bsiz, fmt, ap);
+
+ p->pr_ok = 0;
+ }
+
+ va_end(ap);
+}
+
+static void sdp_printf(sdp_printer_t *p, const char *fmt, ...)
+{
+ va_list ap;
+
+ while (p->pr_ok) {
+ int n;
+
+ va_start(ap, fmt);
+ n = vsnprintf(p->pr_buffer + p->pr_used, p->pr_bsiz - p->pr_used, fmt, ap);
+ va_end(ap);
+
+ if (n > -1 && (size_t)n < p->pr_bsiz - p->pr_used) {
+ p->pr_used += n;
+ break;
+ }
+ else {
+ if (p->pr_owns_buffer) {
+ p->pr_buffer = su_realloc(p->pr_home, p->pr_buffer, 2 * p->pr_bsiz);
+ if (p->pr_buffer) {
+ p->pr_bsiz = 2 * p->pr_bsiz;
+ continue;
+ }
+ p->pr_owns_buffer = 0;
+ }
+ else if (p->pr_may_realloc) {
+ char *buffer;
+ size_t size;
+ if (p->pr_bsiz < SDP_BLOCK)
+ size = SDP_BLOCK;
+ else
+ size = 2 * p->pr_bsiz;
+ buffer = su_alloc(p->pr_home, size);
+ if (buffer) {
+ p->pr_owns_buffer = 1;
+ p->pr_buffer = memcpy(buffer, p->pr_buffer, p->pr_bsiz);
+ p->pr_bsiz = size;
+ continue;
+ }
+ }
+ p->pr_ok = 0;
+ p->pr_buffer = "Memory exhausted";
+ }
+ }
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_tag.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_tag.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,47 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**
+ * @file sdp_tag.c
+ * @brief SDP Tags
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Mon May 12 12:11:30 2003 ppessi
+ *
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+
+#define TAG_NAMESPACE "sdp"
+
+#include <sofia-sip/sdp_tag.h>
+
+tag_typedef_t sdptag_any = NSTAG_TYPEDEF(*);
+
+tag_typedef_t sdptag_session = {{
+ TAG_NAMESPACE, "session", sdptag_session_class
+}};
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sofia-sip/sdp.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sofia-sip/sdp.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,562 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SDP_H
+#define SDP_H
+/**@file sofia-sip/sdp.h Simple SDP (RFC 2327) Interface.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Kai Vehmanen <kai.vehmanen at nokia.com>
+ *
+ * @date Created: Fri Feb 18 08:54:48 2000 ppessi
+ */
+
+#ifndef SU_ALLOC_H
+#include <sofia-sip/su_alloc.h>
+#endif
+#ifndef SU_TYPES_H
+#include <sofia-sip/su_types.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** SDP session description */
+typedef struct sdp_session_s sdp_session_t;
+/** SDP version "v=" line */
+typedef unsigned long sdp_version_t;
+/** SDP origin "o=" line */
+typedef struct sdp_origin_s sdp_origin_t;
+/** SDP connection "c=" line */
+typedef struct sdp_connection_s sdp_connection_t;
+/** SDP bandwidth "b=" line */
+typedef struct sdp_bandwidth_s sdp_bandwidth_t;
+/** SDP time "t=" line */
+typedef struct sdp_time_s sdp_time_t;
+/** SDP repeat "r=" line */
+typedef struct sdp_repeat_s sdp_repeat_t;
+/** SDP timezone "z=" line */
+typedef struct sdp_zone_s sdp_zone_t;
+/** SDP encryption key "k=" line */
+typedef struct sdp_key_s sdp_key_t;
+/** SDP attribute "a=" line */
+typedef struct sdp_attribute_s sdp_attribute_t;
+/** SDP media "m=" line */
+typedef struct sdp_media_s sdp_media_t;
+/** SDP list ("e=", "p=" lines) */
+typedef struct sdp_list_s sdp_list_t;
+/** SDP rtpmap attribute */
+typedef struct sdp_rtpmap_s sdp_rtpmap_t;
+
+/** Message text */
+typedef char const sdp_text_t;
+
+#define SDP_MIME_TYPE "application/sdp"
+
+enum {
+ SDP_CURRENT_VERSION = 0
+};
+
+/** Session description */
+struct sdp_session_s
+{
+ int sdp_size; /**< sizeof sdp_session_t */
+ sdp_session_t *sdp_next; /**< Next description in list */
+ sdp_version_t sdp_version[1]; /**< SDP version */
+ sdp_origin_t *sdp_origin; /**< Owner/creator and session ID */
+ sdp_text_t *sdp_subject; /**< Session name */
+ sdp_text_t *sdp_information; /**< Session information */
+ sdp_text_t *sdp_uri; /**< URi of description */
+ sdp_list_t *sdp_emails; /**< E-mail address(s) */
+ sdp_list_t *sdp_phones; /**< Phone number(s) */
+ sdp_connection_t *sdp_connection; /**< Group (or member) address */
+ sdp_bandwidth_t *sdp_bandwidths; /**< Session bandwidth */
+ sdp_time_t *sdp_time; /**< Session active time */
+ sdp_key_t *sdp_key; /**< Session key */
+ sdp_attribute_t *sdp_attributes; /**< Session attributes */
+ sdp_text_t *sdp_charset; /**< SDP charset (default is UTF8) */
+ sdp_media_t *sdp_media; /**< Media descriptors */
+};
+
+/** Session description identification */
+struct sdp_origin_s
+{
+ int o_size; /**< sizeof sdp_origin_t */
+ sdp_text_t *o_username; /**< Username of originator */
+ uint64_t o_id; /**< Session identification */
+ uint64_t o_version; /**< Version of session description */
+ sdp_connection_t *o_address; /**< Address of originator */
+};
+
+/** Network type */
+typedef enum
+{
+ sdp_net_x = 0, /**< Unknown network type */
+ sdp_net_in = 1 /**< Internet */
+} sdp_nettype_e;
+
+/** Address type */
+typedef enum
+{
+ sdp_addr_x = 0, /**< Unknown address type */
+ sdp_addr_ip4 = 1, /**< IPv4 address */
+ sdp_addr_ip6 = 2, /**< IPv6 address */
+} sdp_addrtype_e;
+
+/** SDP connection - host or group address */
+struct sdp_connection_s
+{
+ int c_size; /**< Size fo sdp_connection_t */
+ sdp_connection_t *c_next; /**< Next connection in list */
+ sdp_nettype_e c_nettype; /**< Network type */
+ sdp_addrtype_e c_addrtype; /**< Address type */
+ sdp_text_t *c_address; /**< Host or group address */
+ unsigned c_ttl : 8; /**< Time to live (scope) */
+ unsigned c_mcast : 1; /**< True if multicast */
+ unsigned : 0;
+ unsigned c_groups; /**< Number of groups (if multiple) */
+};
+
+/** Bandwdith type */
+typedef enum
+{
+ sdp_bw_x, /**< Unknown bandwidth type */
+ sdp_bw_ct, /**< Conference total */
+ sdp_bw_as, /**< Application-specific */
+} sdp_bandwidth_e;
+
+/** Session or media bandwidth. */
+struct sdp_bandwidth_s
+{
+ int b_size; /**< Size fo sdp_bandwidth_t */
+ sdp_bandwidth_t *b_next; /**< Next bw description in list */
+ sdp_bandwidth_e b_modifier; /**< Meaning of value
+ (total, or per application). */
+ sdp_text_t *b_modifier_name; /**< Modifier if not well-known */
+ unsigned long b_value; /**< Bandwidth in kilobits per second */
+};
+
+/** Active time description. */
+struct sdp_time_s
+{
+ int t_size; /**< sizeof sdp_time_t in bytes */
+ sdp_time_t *t_next; /**< Next time description in list */
+ unsigned long t_start; /**< Start time (seconds since 1900) */
+ unsigned long t_stop; /**< Stop time (seconds since 1900) */
+ sdp_repeat_t *t_repeat; /**< Repeat information */
+ sdp_zone_t *t_zone; /**< Time Zone infromation */
+};
+
+/** Description of repetition. */
+struct sdp_repeat_s
+{
+ int r_size; /**< Size of structure including
+ * r_offsets[r_number_of_offsets]
+ */
+ int r_number_of_offsets; /**< Number of offsets in list */
+ unsigned long r_interval; /**< Time between activations */
+ unsigned long r_duration; /**< Duration of activation */
+ unsigned long r_offsets[1]; /**< List of offsets from start-time */
+};
+
+/** Timezone */
+struct sdp_zone_s
+{
+ /** Size of structure including z_adjustments[z_number_of_adjustments] */
+ int z_size;
+ int z_number_of_adjustments; /**< Number of adjustments in list */
+ struct {
+ unsigned long z_at; /**< Adjustment time */
+ long z_offset; /**< Adjustment offset */
+ } z_adjustments[1]; /**< List of timezone adjustments */
+};
+
+/** Mechanism to be used to obtain session key */
+typedef enum {
+ sdp_key_x, /**< Unknown mechanism */
+ sdp_key_clear, /**< Key is included untransformed */
+ sdp_key_base64, /**< Key is encoded with base64 */
+ sdp_key_uri, /**< URI used to obtain a key */
+ sdp_key_prompt /**< No key is included,
+ prompt user for key */
+} sdp_key_method_e;
+
+/** Session key */
+struct sdp_key_s
+{
+ int k_size; /**< sizeof sdp_key_t */
+ sdp_key_method_e k_method; /**< Mechanism used to obtain key */
+ sdp_text_t *k_method_name; /**< Mechanism if not known */
+ sdp_text_t *k_material; /**< Encryption key */
+};
+
+/** Session or media attribute */
+struct sdp_attribute_s {
+ int a_size; /**< sizeof sdp_attribute_t */
+ sdp_attribute_t *a_next; /**< Next attribute in list */
+ sdp_text_t *a_name; /**< Attribute name */
+ sdp_text_t *a_value; /**< Attribute value */
+};
+
+/** Media type @sa RFC2327 page 18. */
+typedef enum
+{
+ sdp_media_x = 0, /**< Unknown media */
+ sdp_media_any, /**< * wildcard */
+ sdp_media_audio, /**< Audio */
+ sdp_media_video, /**< Video */
+ sdp_media_application, /**< Conferencing */
+ sdp_media_data, /**< Bulk data transfer */
+ sdp_media_control, /**< Additional conference control */
+ sdp_media_message, /**< Messaging sessions*/
+ sdp_media_image, /**< Image browsing sessions for JPIP, and T.38 */
+ sdp_media_red /**< Redundancy. @NEW_1_12_4 */
+} sdp_media_e;
+
+/** Media transport protocol. */
+typedef enum
+{
+ sdp_proto_x = 0, /**< Unknown transport */
+ sdp_proto_tcp = 6, /**< TCP */
+ sdp_proto_udp = 17, /**< Plain UDP */
+ sdp_proto_rtp = 256, /**< RTP/AVP */
+ sdp_proto_srtp = 257, /**< RTP/SAVP */
+ sdp_proto_udptl = 258, /**< UDPTL. @NEW_1_12_4 */
+ sdp_proto_tls = 511, /**< TLS over TCP */
+ sdp_proto_any = 512 /**< * wildcard */
+} sdp_proto_e;
+
+/** Session mode. @note Identical to rtp_mode_t. */
+typedef enum {
+ sdp_inactive = 0,
+ sdp_sendonly = 1,
+ sdp_recvonly = 2,
+ sdp_sendrecv = sdp_sendonly | sdp_recvonly
+} sdp_mode_t;
+
+/** Media announcement.
+ *
+ * This structure describes one media type, e.g., audio. The description
+ * contains the transport address (IP address and port) used for the group,
+ * the transport protocol used, the media formats or RTP payload types, and
+ * optionally media-specific bandwidth specification, encryption key and
+ * attributes.
+ *
+ * There is a pointer (m_user) for the application data, too.
+ */
+struct sdp_media_s
+{
+ int m_size; /**< sizeof sdp_media_t */
+ sdp_media_t *m_next; /**< Next media announcement */
+ sdp_session_t *m_session; /**< Back-pointer to session level */
+
+ sdp_media_e m_type; /**< Media type */
+ sdp_text_t *m_type_name; /**< Media type name */
+ unsigned long m_port; /**< Transport port number */
+ unsigned long m_number_of_ports; /**< Number of ports (if multiple) */
+ sdp_proto_e m_proto; /**< Transport protocol */
+ sdp_text_t *m_proto_name; /**< Transport protocol name */
+ sdp_list_t *m_format; /**< List of media formats */
+ sdp_rtpmap_t *m_rtpmaps; /**< List of RTP maps */
+ sdp_text_t *m_information; /**< Media information */
+ sdp_connection_t *m_connections; /**< List of addresses used */
+ sdp_bandwidth_t *m_bandwidths; /**< Bandwidth specification */
+ sdp_key_t *m_key; /**< Media key */
+ sdp_attribute_t *m_attributes; /**< Media attributes */
+
+ void *m_user; /**< User data. */
+
+ /** Rejected media */
+ unsigned m_rejected : 1;
+ /** Inactive, recvonly, sendonly, sendrecv */
+ /* sdp_mode_t */ unsigned m_mode : 2;
+ unsigned : 0;
+};
+
+/** Text list */
+struct sdp_list_s
+{
+ int l_size; /**< sizeof sdp_list_t */
+ sdp_list_t *l_next; /**< Next text entry in list */
+ sdp_text_t *l_text; /**< Text as C string */
+};
+
+/** Mapping from RTP payload to codec.
+ *
+ * The sdp_rtpmap_t() structure defines a mapping from an RTP payload to a
+ * particular codec. In case of well-known payloads, the sdp_rtpmap_t()
+ * structure may be predefined, that is, generated by SDP parser without
+ * corresponding "a" line in the SDP. The sdp_rtpmap_t() structure may also
+ * contain the @c fmtp attribute, which is used to convey format-specific
+ * parameters.
+ */
+struct sdp_rtpmap_s {
+ int rm_size; /**< sizeof sdp_rtpmap_t */
+ sdp_rtpmap_t *rm_next; /**< Next RTP map entry */
+ sdp_text_t *rm_encoding; /**< Codec name */
+ unsigned long rm_rate; /**< Sampling rate */
+ sdp_text_t *rm_params; /**< Format-specific parameters */
+ sdp_text_t *rm_fmtp; /**< Contents of fmtp */
+ unsigned rm_predef : 1; /**< is this entry well-known? */
+ unsigned rm_pt : 7; /**< Payload type */
+ unsigned rm_any : 1; /**< Wildcard entry */
+ int :0;
+};
+
+SOFIAPUBVAR sdp_rtpmap_t const * const sdp_rtpmap_well_known[128];
+
+/** Duplicate an SDP session description structure. */
+SOFIAPUBFUN sdp_session_t *sdp_session_dup(su_home_t *, sdp_session_t const *);
+
+/** Duplicate an SDP origin structure. */
+SOFIAPUBFUN
+sdp_origin_t *sdp_origin_dup(su_home_t *, sdp_origin_t const *);
+
+/** Duplicate an SDP connection structure. */
+SOFIAPUBFUN
+sdp_connection_t *sdp_connection_dup(su_home_t *home, sdp_connection_t const *);
+
+/** Duplicate an SDP bandwidth structure. */
+SOFIAPUBFUN
+sdp_bandwidth_t *sdp_bandwidth_dup(su_home_t *home, sdp_bandwidth_t const *);
+
+/** Duplicate an SDP time structure. */
+SOFIAPUBFUN
+sdp_time_t *sdp_time_dup(su_home_t *home, sdp_time_t const *);
+
+/** Duplicate an SDP repeat structure. */
+SOFIAPUBFUN
+sdp_repeat_t *sdp_repeat_dup(su_home_t *home, sdp_repeat_t const *);
+
+/** Duplicate an SDP timezone structure. */
+SOFIAPUBFUN
+sdp_zone_t *sdp_zone_dup(su_home_t *home, sdp_zone_t const *);
+
+/** Duplicate an SDP key structure. */
+SOFIAPUBFUN
+sdp_key_t *sdp_key_dup(su_home_t *home, sdp_key_t const *);
+
+/** Duplicate an SDP attribute structure. */
+SOFIAPUBFUN
+sdp_attribute_t *sdp_attribute_dup(su_home_t *home, sdp_attribute_t const *);
+
+/** Duplicate an SDP media description structure. */
+SOFIAPUBFUN
+sdp_media_t *sdp_media_dup(su_home_t *, sdp_media_t const *,
+ sdp_session_t *);
+
+/** Duplicate a list of SDP media description structures. */
+SOFIAPUBFUN
+sdp_media_t *sdp_media_dup_all(su_home_t *, sdp_media_t const *,
+ sdp_session_t *);
+
+/** Duplicate a list structure. */
+SOFIAPUBFUN
+sdp_list_t *sdp_list_dup(su_home_t *home, sdp_list_t const *);
+
+/** Duplicate an rtpmap structure. */
+SOFIAPUBFUN
+sdp_rtpmap_t *sdp_rtpmap_dup(su_home_t *home, sdp_rtpmap_t const *);
+
+/** Compare two session descriptions. */
+SOFIAPUBFUN int sdp_session_cmp(sdp_session_t const *a,
+ sdp_session_t const *b);
+
+/** Compare two origin fields */
+SOFIAPUBFUN int sdp_origin_cmp(sdp_origin_t const *a,
+ sdp_origin_t const *b);
+
+/** Compare two connection fields */
+SOFIAPUBFUN int sdp_connection_cmp(sdp_connection_t const *,
+ sdp_connection_t const *b);
+
+/** Compare two bandwidth (b=) fields */
+SOFIAPUBFUN int sdp_bandwidth_cmp(sdp_bandwidth_t const *a,
+ sdp_bandwidth_t const *b);
+
+/** Compare two time fields */
+SOFIAPUBFUN int sdp_time_cmp(sdp_time_t const *a, sdp_time_t const *b);
+
+/* Compare two repeat (r=) fields */
+SOFIAPUBFUN int sdp_repeat_cmp(sdp_repeat_t const *a, sdp_repeat_t const *b);
+
+/* Compare two zone (z=) fields */
+SOFIAPUBFUN int sdp_zone_cmp(sdp_zone_t const *a, sdp_zone_t const *b);
+
+/** Compare two key (k=) fields. */
+SOFIAPUBFUN int sdp_key_cmp(sdp_key_t const *a, sdp_key_t const *b);
+
+/** Compare two attribute (a=) fields */
+SOFIAPUBFUN int sdp_attribute_cmp(sdp_attribute_t const *,
+ sdp_attribute_t const *);
+
+/** Compare two media (m=) descriptions */
+SOFIAPUBFUN int sdp_media_cmp(sdp_media_t const *, sdp_media_t const *);
+
+/** Compare two rtpmap structures. */
+SOFIAPUBFUN int sdp_rtpmap_cmp(sdp_rtpmap_t const *a, sdp_rtpmap_t const *b);
+
+/** Compare two text lists */
+SOFIAPUBFUN int sdp_list_cmp(sdp_list_t const *a, sdp_list_t const *b);
+
+/** Get connections of a media description */
+SOFIAPUBFUN sdp_connection_t *sdp_media_connections(sdp_media_t const *m);
+
+/** Check if media uses RTP as its transport protocol */
+SOFIAPUBFUN int sdp_media_has_rtp(sdp_media_t const *m);
+
+/** Set media type */
+SOFIAPUBFUN void sdp_media_type(sdp_media_t *m, char const *s);
+
+/** Set transport protocol */
+SOFIAPUBFUN void sdp_media_transport(sdp_media_t *m, char const *s);
+
+/** Find named attribute from given list. */
+SOFIAPUBFUN sdp_attribute_t *sdp_attribute_find(sdp_attribute_t const *a,
+ char const *name);
+
+/** Find named attribute from given lists. */
+SOFIAPUBFUN sdp_attribute_t *sdp_attribute_find2(sdp_attribute_t const *a,
+ sdp_attribute_t const *a2,
+ char const *name);
+
+/** Get session mode from attribute list. */
+SOFIAPUBFUN sdp_mode_t sdp_attribute_mode(sdp_attribute_t const *a,
+ sdp_mode_t defmode);
+
+/** Get session mode from attribute list. */
+SOFIAPUBFUN sdp_attribute_t *sdp_attribute_by_mode(su_home_t *,
+ sdp_mode_t mode);
+
+/** Find a mapped attribute. */
+SOFIAPUBFUN
+sdp_attribute_t *sdp_attribute_mapped_find(sdp_attribute_t const *a,
+ char const *name,
+ int pt, char **return_result);
+
+/** Append a attribute to a list of attributes. */
+SOFIAPUBFUN void sdp_attribute_append(sdp_attribute_t **list,
+ sdp_attribute_t const *a);
+
+/** Replace a attribute within a list of attributes. */
+SOFIAPUBFUN int sdp_attribute_replace(sdp_attribute_t **list,
+ sdp_attribute_t *a,
+ sdp_attribute_t **return_replaced);
+
+/** Remove a named attribute from a list of attributes. */
+SOFIAPUBFUN sdp_attribute_t *sdp_attribute_remove(sdp_attribute_t **list,
+ char const *name);
+
+/* Return 1 if m= line struct matches with given type and name */
+SOFIAPUBFUN unsigned sdp_media_match(sdp_media_t const *m,
+ sdp_media_e type,
+ sdp_text_t *type_name,
+ sdp_proto_e proto,
+ sdp_text_t *proto_name);
+
+SOFIAPUBFUN unsigned sdp_media_match_with(sdp_media_t const *a,
+ sdp_media_t const *b);
+
+/** Count media lines in SDP. */
+SOFIAPUBFUN unsigned sdp_media_count(sdp_session_t const *sdp,
+ sdp_media_e type,
+ sdp_text_t *type_name,
+ sdp_proto_e proto,
+ sdp_text_t *proto_name);
+
+SOFIAPUBFUN unsigned sdp_media_count_with(sdp_session_t const *sdp,
+ sdp_media_t const *m0);
+
+/** Return true if media uses RTP */
+SOFIAPUBFUN int sdp_media_uses_rtp(sdp_media_t const *m);
+
+/** Check if payload type, rtp rate and parameters match in rtpmaps*/
+SOFIAPUBFUN int sdp_rtpmap_match(sdp_rtpmap_t const *, sdp_rtpmap_t const *);
+
+/** Search for matching rtpmap from list */
+SOFIAPUBFUN sdp_rtpmap_t *sdp_rtpmap_find_matching(sdp_rtpmap_t const *list,
+ sdp_rtpmap_t const *rm);
+
+/* ======================================================================== */
+
+/** Flags given to sdp_parse()/sdp_print(). */
+enum sdp_parse_flags_e {
+ /** Accept only conforming SDP */
+ sdp_f_strict = 1,
+ /** Accept any network type. */
+ sdp_f_anynet = 2,
+ /** Reallocate message. */
+ sdp_f_realloc = 4,
+ /** Include well-known rtpmaps in message, too */
+ sdp_f_all_rtpmaps = 8,
+ /** Print buffer already contains a valid prefix */
+ sdp_f_print_prefix = 16,
+ /** Connection line with INADDR_ANY is considered equal to sendonly */
+ sdp_f_mode_0000 = 32,
+ /** Don't run sanity check */
+ sdp_f_insane = 64,
+ /** Don't require c= for each media line */
+ sdp_f_c_missing = 128,
+ /** Parse SDP config files */
+ sdp_f_config = 256,
+ /** Do not generate or parse SDP mode */
+ sdp_f_mode_manual = 512,
+ /** Always generate media-level mode attributes */
+ sdp_f_mode_always = 1024
+};
+
+/** SDP parser handle. */
+typedef struct sdp_parser_s sdp_parser_t;
+typedef sdp_parser_t *sdp_parser;
+
+SOFIAPUBFUN sdp_parser_t *sdp_parse(su_home_t *,
+ char const msg[], issize_t msgsize,
+ int flags);
+SOFIAPUBFUN char const *sdp_parsing_error(sdp_parser_t *p);
+SOFIAPUBFUN sdp_session_t *sdp_session(sdp_parser_t *p);
+SOFIAPUBFUN void sdp_parser_free(sdp_parser_t *p);
+
+SOFIAPUBFUN int sdp_sanity_check(sdp_parser_t *);
+
+SOFIAPUBFUN su_home_t *sdp_parser_home(sdp_parser_t *);
+
+/* ======================================================================== */
+
+/** SDP printer handle */
+typedef struct sdp_printer_s sdp_printer_t;
+typedef sdp_printer_t *sdp_printer;
+
+SOFIAPUBFUN sdp_printer_t *sdp_print(su_home_t *, sdp_session_t const *session,
+ char msgbuf[], isize_t maxmsgsize, int flags);
+SOFIAPUBFUN char const *sdp_printing_error(sdp_printer_t *p);
+SOFIAPUBFUN char const *sdp_message(sdp_printer_t *p);
+SOFIAPUBFUN isize_t sdp_message_size(sdp_printer_t *p);
+SOFIAPUBFUN void sdp_printer_free(sdp_printer_t *p);
+
+#define sdp_mapped_attribute_find sdp_attribute_mapped_find
+#define sdp_free_parser sdp_parser_free
+#define sdp_free_printer sdp_printer_free
+
+SOFIA_END_DECLS
+
+#endif /* SDP_H */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sofia-sip/sdp_tag.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sofia-sip/sdp_tag.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,89 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SDP_TAG_H
+/** Defined when <sofia-sip/sdp_tag.h> has been included. */
+#define SDP_TAG_H
+
+/**@file sofia-sip/sdp_tag.h
+ * @brief SDP tags
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Mon May 12 12:06:20 EEST 2003 ppessi
+ * @{
+ */
+
+#ifndef SU_TAG_H
+#include <sofia-sip/su_tag.h>
+#endif
+#ifndef SU_TAG_CLASS_H
+#include <sofia-sip/su_tag_class.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+struct sdp_session_s;
+
+/** Filter tag matching any sdp tag. */
+#define SDPTAG_ANY() sdptag_any, ((tag_value_t)0)
+SDP_DLL extern tag_typedef_t sdptag_any;
+
+/* Tags for parameters */
+
+SDP_DLL extern tag_typedef_t sdptag_session;
+/** SDP session description. @HI */
+#define SDPTAG_SESSION(x) \
+sdptag_session, sdptag_session_v((x))
+
+SDP_DLL extern tag_typedef_t sdptag_session_ref;
+#define SDPTAG_SESSION_REF(x) \
+sdptag_session_ref, sdptag_session_vr(&(x))
+
+/* Functions for typesafe parameter passing */
+
+#if SU_HAVE_INLINE
+su_inline
+tag_value_t sdptag_session_v(struct sdp_session_s const *v) {
+ return (tag_value_t)v;
+}
+su_inline
+tag_value_t sdptag_session_vr(struct sdp_session_s const **vp) {
+ return (tag_value_t)vp;
+}
+#else
+#define sdptag_session_v(v) (tag_value_t)(v)
+#define sdptag_session_vr(vp) (tag_value_t)(vp)
+#endif
+
+/* Tag classes */
+
+extern tag_class_t sdptag_session_class[];
+
+#define SDPTAG_TYPEDEF(name) \
+ {{ TAG_NAMESPACE, #name, sdptag_session_class }}
+
+SOFIA_END_DECLS
+
+#endif /* !defined(SDP_TAG_H) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/test_sdp.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/test_sdp.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,136 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@internal
+ *
+ * @CFILE test_sdp.c
+ *
+ * Simple SDP tester
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created : Fri Feb 18 10:25:08 2000 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "sofia-sip/sdp.h"
+
+int diff(const char *olds, const char *news, int *linep, int *pos)
+{
+ const char *o, *n;
+
+ *linep = 0;
+
+ for (o = olds, n = news; *o && *n && *o == *n ; o++, n++) {
+ if (*o == '\n') ++*linep;
+ }
+
+ *pos = o - olds;
+
+ return *o != *n;
+}
+
+int main(int argc, char *argv[])
+{
+ char buffer[2048];
+ int n;
+ su_home_t *home = su_home_create();
+ int exitcode = 1;
+ FILE *f;
+
+ if (argv[1] && strcmp(argv[1], "-"))
+ f = fopen(argv[1], "rb");
+ else
+ f = stdin;
+
+ n = fread(buffer, 1, sizeof(buffer) - 1, f);
+ buffer[n] = 0;
+
+ if (feof(f)) {
+ sdp_parser_t *p = sdp_parse(home, buffer, n + 1, 0);
+
+ su_home_check(home);
+ su_home_check((su_home_t *)p);
+
+ if (sdp_session(p)) {
+ sdp_session_t *sdp, *dup;
+ sdp_printer_t *printer;
+
+ sdp = sdp_session(p);
+ dup = sdp_session_dup(home, sdp);
+ su_home_check(home);
+
+ sdp_parser_free(p), p = NULL;
+ su_home_check(home);
+
+ printer = sdp_print(home, dup, NULL, 0, 0);
+ su_home_check(home);
+
+ if (sdp_message(printer)) {
+ int line, pos;
+
+ if (diff(buffer, sdp_message(printer), &line, &pos)) {
+ fprintf(stdout, "test_sdp:%d: messages differ:\n", line);
+ fputs(buffer, stdout);
+ fprintf(stdout, ">>>new message:\n");
+ fputs(sdp_message(printer), stdout);
+ }
+ else {
+ exitcode = 0;
+ }
+ }
+ else {
+ fprintf(stderr, "test_sdp: %s\n", sdp_printing_error(printer));
+ }
+ sdp_printer_free(printer);
+
+ su_home_check(home);
+ }
+ else {
+ fprintf(stderr, "test_sdp: %s\n", sdp_parsing_error(p));
+ sdp_parser_free(p);
+ exit(1);
+ }
+ }
+ else {
+ if (ferror(f)) {
+ perror("test_sdp");
+ }
+ else {
+ fprintf(stderr, "test_sdp: maximum length of sdp messages is %u bytes\n",
+ (unsigned)sizeof(buffer));
+ }
+ exit(1);
+ }
+
+ su_home_unref(home);
+
+ return exitcode;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-1.sdp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-1.sdp Thu Dec 21 01:30:28 2006
@@ -0,0 +1 @@
+v=1
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-10.sdp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-10.sdp Thu Dec 21 01:30:28 2006
@@ -0,0 +1,32 @@
+v=0
+o=ppessi 2890844526 13 IN IP4 126.16.64.4
+s=Testing sdp parser quirks
+i=A Seminar on the session description protocol
+u=http://www.cs.ucl.ac.uk/staff/M.Handley/sdp.03.ps
+e=mjh at isi.edu (Mark Handley)
+e=mjh at mail.isi.edu (Mark Handley)
+p=+358 9 4376 1
+p=+1 442 555 6782
+c=IN IP4 224.2.17.12/127/2
+b=CT:512
+t=2873397496 2873404696
+r=7d 1h 1d 1d 1d 1d 1d
+z=2882844526 -1h 2898848070 0
+k=uri:shttp://foo.bar.com/session/key
+a=recvonly
+m=audio 49230 RTP/AVP 0 96 97 98 99 100
+b=AS:360
+a=rtpmap:96 L8/8000
+a=rtpmap:97 L16/8000
+a=rtpmap:98 L16/11025/2
+a=rtpmap:99 GSM-EFR/8000
+a=rtpmap:100 X-AMR/8000
+a=fmtp:100 mode-set=4,5,6 interleaving crc vad=on use-redundancy=1
+m=video 51372/2 RTP/AVP 31
+c=IN IP4 224.2.17.12/127
+c=IN IP4 224.2.17.13/127
+b=AS:16
+a=rtpmap:31 H261/90000
+m=application 32416 udp wb
+b=AS:32
+a=orient:portrait
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-2.sdp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-2.sdp Thu Dec 21 01:30:28 2006
@@ -0,0 +1,13 @@
+v=0
+o=mhandley 2890844526 2890842807 IN IP4 126.16.64.4
+s=SDP Seminar
+i=A Seminar on the session description protocol
+u=http://www.cs.ucl.ac.uk/staff/M.Handley/sdp.03.ps
+e=mjh at isi.edu (Mark Handley)
+c=IN IP4 224.2.17.12/127
+t=2873397496 2873404696
+a=recvonly
+m=audio 49170 RTP/AVP 0
+m=video 51372 RTP/AVP 31
+m=application 32416 udp wb
+a=orient:portrait
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-3.sdp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-3.sdp Thu Dec 21 01:30:28 2006
@@ -0,0 +1,8 @@
+v=0
+o=user1 53655765 2353687637 IN IP4 128.3.4.5
+s=Mbone Audio
+i=Discussion of Mbone Engineering Issues
+e=mbone at somewhere.com
+c=IN IP4 224.2.0.1/127
+t=0 0
+m=audio 3456 RTP/AVP 0
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-4.sdp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-4.sdp Thu Dec 21 01:30:28 2006
@@ -0,0 +1,4 @@
+v=0
+o=bell 53655765 2353687637 IN IP4 128.3.4.5
+c=IN IP4 135.180.144.94
+m=audio 3456 RTP/AVP 0 3 4 5
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-5.sdp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-5.sdp Thu Dec 21 01:30:28 2006
@@ -0,0 +1,5 @@
+v=0
+o=watson 4858949 4858949 IN IP4 192.1.2.3
+s=I'm on my way
+c=IN IP4 boston.bell-tel.com
+m=audio 5004 RTP/AVP 0 3
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-6.sdp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-6.sdp Thu Dec 21 01:30:28 2006
@@ -0,0 +1,6 @@
+v=0
+s=Let's talk
+c=IN IP4 north.east.isi.edu
+b=CT:128
+m=audio 3456 RTP/AVP 5 0 7
+m=video 2232 RTP/AVP 31
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-7.sdp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-7.sdp Thu Dec 21 01:30:28 2006
@@ -0,0 +1,10 @@
+v=0
+o=alice 2890844526 2890844526 IN IP4 host.anywhere.com
+i=First example from RFC 2543 page 136
+c=IN IP4 host.anywhere.com
+m=audio 49170 RTP/AVP 0
+a=rtpmap:0 PCMU/8000
+m=video 51372 RTP/AVP 31
+a=rtpmap:31 H261/90000
+m=video 53000 RTP/AVP 32
+a=rtpmap:32 MPV/90000
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-8.sdp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-8.sdp Thu Dec 21 01:30:28 2006
@@ -0,0 +1,10 @@
+v=0
+o=bob 2890844730 2890844730 IN IP4 host.example.com
+i=First example from RFC 2543 page 136
+c=IN IP4 host.example.com
+m=audio 47920 RTP/AVP 0 1
+a=rtpmap:0 PCMU/8000
+a=rtpmap:1 1016/8000
+m=video 0 RTP/AVP 31
+m=video 53000 RTP/AVP 32
+a=rtpmap:32 MPV/90000
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-9.sdp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-9.sdp Thu Dec 21 01:30:28 2006
@@ -0,0 +1,25 @@
+v=0
+o=ppessi 2890844526 0 IN IP4 126.16.64.4
+s=Testing sdp parser quirks
+i=A Seminar on the session description protocol
+u=http://www.cs.ucl.ac.uk/staff/M.Handley/sdp.03.ps
+e=mjh at isi.edu (Mark Handley)
+c=IN IP4 224.2.17.12/127/2
+b=CT:512
+t=2873397496 2873404696
+a=recvonly
+m=audio 49230 RTP/AVP 0 96 97 98 99 100
+b=AS:360
+a=rtpmap:96 L8/8000
+a=rtpmap:97 L16/8000
+a=rtpmap:98 L16/11025/2
+a=rtpmap:99 GSM-EFR/8000
+a=rtpmap:100 X-AMR/8000
+m=video 51372/2 RTP/AVP 31
+c=IN IP4 224.2.17.12/127
+c=IN IP4 224.2.17.13/127
+b=AS:16
+a=rtpmap:31 H261/90000
+m=application 32416 udp wb
+b=AS:32
+a=orient:portrait
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/torture_sdp.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/torture_sdp.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,886 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@internal
+ *
+ * @CFILE sdp_torture.c
+ *
+ * Torture testing sdp module.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Kai Vehmanen <kai.vehmanen at nokia.com>
+ *
+ * @date Created: Tue Mar 6 18:33:42 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#include <sofia-sip/su_types.h>
+
+#include <sofia-sip/sdp.h>
+
+#include <sofia-sip/su_tag.h>
+#include <sofia-sip/su_tag_io.h>
+#include <sofia-sip/sdp_tag.h>
+
+#define TSTFLAGS tstflags
+
+#include <sofia-sip/tstdef.h>
+
+int tstflags;
+
+char const *name = "torture_sdp.c";
+
+FILE *null;
+
+static char const e0_msg[] =
+"foo";
+
+static char const e1_msg[] =
+ "v=1\n"
+ "s=/sdp_torture\n"
+ "o=sdp_torture 0 0 IN IP4 0.0.0.0\n"
+ "m=audio 0 RTP/AVP 96 97 98 10 99 8 0\n"
+ "a=rtpmap:96 X-AMR-WB/16000\n"
+ "a=rtpmap:97 X-AMR/8000\n"
+ "a=rtpmap:98 GSM-EFR/8000\n"
+ "a=rtpmap:10 L16/16000\n"
+ "a=rtpmap:99 G723/8000\n"
+ "a=rtpmap:8 PCMA/8000\n"
+ "a=rtpmap:0 PCMU/8000\n"
+ "m=video 0 *";
+
+static int test_error(void)
+{
+ su_home_t *home = su_home_create();
+ sdp_parser_t *parser;
+
+ BEGIN();
+
+ su_home_check(home); TEST0(home);
+
+ TEST_1((parser = sdp_parse(home, e0_msg, sizeof(e0_msg), 0)));
+ TEST_1(sdp_session(parser) == NULL);
+ TEST_1(sdp_parsing_error(parser));
+ sdp_parser_free(parser);
+
+ TEST_1((parser = sdp_parse(home, e1_msg, sizeof(e1_msg), 0)));
+ TEST_1(sdp_session(parser) == NULL);
+ TEST_1(sdp_parsing_error(parser));
+ sdp_parser_free(parser);
+
+
+ /* destroy the home objects */
+ su_home_check(home); su_home_zap(home);
+
+ END();
+}
+
+static char const s0_msg[] =
+ "v=0\n"
+ "s=/sdp_torture\n"
+ "o=sdp_torture 0 0 IN IP4 0.0.0.0\n"
+ "m=audio 0 RTP/AVP 96 97 98 10 99 8 0\n"
+ "a=rtpmap:96 X-AMR-WB/16000\n"
+ "a=rtpmap:97 X-AMR/8000\n"
+ "a=rtpmap:98 GSM-EFR/8000\n"
+ "a=rtpmap:10 L16/16000\n"
+ "a=rtpmap:99 G723/8000\n"
+ "a=rtpmap:8 PCMA/8000\n"
+ "a=rtpmap:0 PCMU/8000\n"
+ "m=video 0 *\n"
+ "m=* 0 RTP/AVP *\n"
+ ;
+
+static int test_session(void)
+{
+ su_home_t *home = su_home_create(), *home2 = su_home_create();
+ sdp_session_t *sdp_src, *sdp_target;
+ sdp_session_t const *sdp = NULL;
+ sdp_parser_t *parser;
+ sdp_printer_t *printer;
+ sdp_media_t *m;
+ char buffer[512];
+ tagi_t *lst, *dup;
+
+ BEGIN();
+
+ su_home_check(home);
+ TEST_1(home);
+
+ su_home_check(home2);
+ TEST_1(home2);
+
+ TEST_1((parser = sdp_parse(home, s0_msg, sizeof(s0_msg), sdp_f_config)));
+ TEST_1((sdp_src = sdp_session(parser)));
+ TEST_1(sdp_src->sdp_media);
+ TEST_1(sdp_src->sdp_media->m_session);
+ TEST_P(sdp_src->sdp_media->m_session, sdp_src);
+
+ /* clone the session using 'home2' */
+ TEST_1((sdp_target = sdp_session_dup(home2, sdp_src)));
+
+ /* Check comparing */
+ TEST(sdp_session_cmp(sdp_src, sdp_target), 0);
+
+ /* check the cloned session */
+ TEST_1(sdp_target->sdp_subject);
+ TEST_S(sdp_target->sdp_subject, "/sdp_torture");
+ strcpy((char*)sdp_target->sdp_subject, "garbage");
+ TEST_S(sdp_src->sdp_subject, "/sdp_torture");
+
+ TEST_1(sdp_target->sdp_origin);
+ TEST_1(sdp_target->sdp_origin->o_username);
+ TEST_S(sdp_target->sdp_origin->o_username, "sdp_torture");
+ strcpy((char*)sdp_target->sdp_origin->o_username, "garbage");
+ TEST_S(sdp_src->sdp_origin->o_username, "sdp_torture");
+
+ TEST_1(m = sdp_target->sdp_media);
+ TEST_P(m->m_session, sdp_target);
+ TEST_1(sdp_src->sdp_media->m_session != sdp_target->sdp_media->m_session);
+
+ TEST(m->m_type, sdp_media_audio);
+ TEST_S(m->m_type_name, "audio");
+ TEST(m->m_port, 0);
+ TEST(m->m_number_of_ports, 0);
+ TEST(m->m_proto, sdp_proto_rtp);
+ TEST_S(m->m_proto_name, "RTP/AVP");
+ /* FIXME: add more tests */
+
+ /* frees all data created by the parser including 'sdp_src' */
+ sdp_parser_free(parser);
+
+ /* destroy the first home instance */
+ su_home_check(home);
+ su_home_unref(home);
+
+ /* access all cloned data by printing it */
+ printer = sdp_print(home2, sdp_target, buffer, sizeof(buffer), 0);
+ if (printer != NULL) {
+ char const *msg = sdp_message(printer);
+
+ if (tstflags & tst_verbatim) {
+ printf("sdp_torture.c: parsed SDP message:\"%s\".\n", msg);
+ }
+
+ sdp_printer_free(printer);
+ }
+
+ TEST_1(lst = tl_list(SDPTAG_SESSION(sdp_target), TAG_NULL()));
+
+ TEST_1(dup = tl_adup(home2, lst));
+
+ if (tstflags & tst_verbatim)
+ tl_print(stdout, "dup:\n", dup);
+ else
+ tl_print(null, "dup:\n", dup);
+
+ TEST(tl_gets(dup, SDPTAG_SESSION_REF(sdp), TAG_END()), 1);
+
+ /* access all copied data by printing it */
+ printer = sdp_print(home2, sdp, buffer, sizeof(buffer), 0);
+ if (printer != NULL) {
+ char const *msg = sdp_message(printer);
+ if (tstflags & tst_verbatim) {
+ printf("sdp_torture.c: "
+ "SDP message passed through tag list:\n\"%s\".\n", msg);
+ }
+ sdp_printer_free(printer);
+ }
+
+ su_free(home2, dup);
+ tl_vfree(lst);
+
+ /* destroy the second home object */
+ su_home_check(home2);
+ su_home_unref(home2);
+
+ END();
+}
+
+static char const s1_msg[] =
+ "v=0\r\n"
+ "o=- 2435697 2435697 IN IP4 172.21.137.44\r\n"
+ "s=-\r\n"
+ "c=IN IP4 172.21.137.44\r\n"
+ "t=0 0\r\n"
+ "a=sendonly\r\n"
+ "m=video 49154 RTP/AVP 96 24 25 26 28 31 32 33 34\r\n"
+ "a=rtpmap:96 H263-1998/90000\r\n"
+ "m=audio 49152 RTP/AVP 97 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19\r\n"
+ "a=rtpmap 97 AMR/8000\r\n"
+ "a=fmtp:97 mode-set=\"0,1,2,3,4\"\r\n"
+ "a=ptime:400\r\n";
+
+static char const s2_msg[] =
+ "v=0\r\n"
+ "o=- 308519342 2 IN IP4 172.168.1.55\r\n"
+ "s=-\r\n"
+ "c=IN IP4 172.168.1.55\r\n"
+ "t=0 0\r\n"
+ "a=recvonly\r\n"
+ "m=video 59154 RTP/AVP 96\r\n"
+ "b=AS:64\r\n"
+ "a=rtpmap:96 H263-1998/90000\r\n"
+ "a=framerate:8\r\n"
+ "a=fmtp:96 QCIF=4\r\n"
+ "m=audio 59152 RTP/AVP 97\r\n"
+ "b=AS:8\r\n"
+ "a=rtpmap:97 AMR/8000\r\n"
+ "a=fmtp:97 mode-set=\"0\"\r\n"
+ "a=maxptime:500\r\n";
+
+static int test_session2(void)
+{
+ su_home_t *home = su_home_create();
+ sdp_session_t const *sdp = NULL;
+ sdp_parser_t *parser;
+ sdp_media_t *m;
+ sdp_rtpmap_t *rm;
+
+ BEGIN();
+
+ su_home_check(home); TEST_1(home);
+
+ TEST_1((parser = sdp_parse(home, s1_msg, sizeof(s1_msg), 0)));
+ TEST_1((sdp = sdp_session(parser)));
+ TEST_1(m = sdp->sdp_media);
+ TEST(m->m_mode, sdp_sendonly);
+ TEST_P(m->m_session, sdp);
+ TEST_1(rm = m->m_rtpmaps);
+ TEST(rm->rm_pt, 96);
+ TEST_S(rm->rm_encoding, "H263-1998");
+ TEST(rm->rm_rate, 90000);
+
+ {
+#define RTPMAP(pt, type, rate, params) \
+ { sizeof(sdp_rtpmap_t), NULL, type, rate, (char *)params, NULL, 1, pt, 0 }
+
+ /* rtpmaps for well-known video codecs */
+ static sdp_rtpmap_t const
+ sdp_rtpmap_celb = RTPMAP(25, "CelB", 90000, 0),
+ sdp_rtpmap_jpeg = RTPMAP(26, "JPEG", 90000, 0),
+ sdp_rtpmap_nv = RTPMAP(28, "nv", 90000, 0),
+ sdp_rtpmap_h261 = RTPMAP(31, "H261", 90000, 0),
+ sdp_rtpmap_mpv = RTPMAP(32, "MPV", 90000, 0),
+ sdp_rtpmap_mp2t = RTPMAP(33, "MP2T", 90000, 0),
+ sdp_rtpmap_h263 = RTPMAP(34, "H263", 90000, 0);
+
+
+ TEST_1(rm = rm->rm_next);
+ TEST_S(rm->rm_encoding, ""); TEST(rm->rm_rate, 0);
+ TEST_1(rm = rm->rm_next);
+ TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_celb, rm), &sdp_rtpmap_celb);
+ TEST_1(rm = rm->rm_next);
+ TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_jpeg, rm), &sdp_rtpmap_jpeg);
+ TEST_1(rm = rm->rm_next);
+ TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_nv, rm), &sdp_rtpmap_nv);
+ TEST_1(rm = rm->rm_next);
+ TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_h261, rm), &sdp_rtpmap_h261);
+ TEST_1(rm = rm->rm_next);
+ TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_mpv, rm), &sdp_rtpmap_mpv);
+ TEST_1(rm = rm->rm_next);
+ TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_mp2t, rm), &sdp_rtpmap_mp2t);
+ TEST_1(rm = rm->rm_next);
+ TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_h263, rm), &sdp_rtpmap_h263);
+ TEST_1(!rm->rm_next);
+ }
+
+ TEST_1(m = m->m_next);
+ TEST(m->m_mode, sdp_sendonly);
+ TEST_P(m->m_session, sdp);
+ TEST_1(rm = m->m_rtpmaps);
+ TEST(rm->rm_pt, 97);
+ TEST_S(rm->rm_encoding, "AMR");
+ TEST(rm->rm_rate, 8000);
+ TEST_S(rm->rm_fmtp, "mode-set=\"0,1,2,3,4\"");
+
+ {
+ /* rtpmaps for well-known audio codecs */
+ static sdp_rtpmap_t const
+ sdp_rtpmap_pcmu = RTPMAP(0, "PCMU", 8000, "1"),
+ sdp_rtpmap_1016 = RTPMAP(1, "1016", 8000, "1"),
+ sdp_rtpmap_g721 = RTPMAP(2, "G721", 8000, "1"),
+ sdp_rtpmap_gsm = RTPMAP(3, "GSM", 8000, "1"),
+ sdp_rtpmap_g723 = RTPMAP(4, "G723", 8000, "1"),
+ sdp_rtpmap_dvi4_8000 = RTPMAP(5, "DVI4", 8000, "1"),
+ sdp_rtpmap_dvi4_16000 = RTPMAP(6, "DVI4", 16000, "1"),
+ sdp_rtpmap_lpc = RTPMAP(7, "LPC", 8000, "1"),
+ sdp_rtpmap_pcma = RTPMAP(8, "PCMA", 8000, "1"),
+ sdp_rtpmap_g722 = RTPMAP(9, "G722", 8000, "1"),
+ sdp_rtpmap_l16 = RTPMAP(10, "L16", 44100, "2"),
+ sdp_rtpmap_l16_stereo = RTPMAP(11, "L16", 44100, "1"),
+ sdp_rtpmap_qcelp = RTPMAP(12, "QCELP", 8000, "1"),
+ sdp_rtpmap_cn = RTPMAP(13, "CN", 8000, "1"),
+ sdp_rtpmap_mpa = RTPMAP(14, "MPA", 90000, 0),
+ sdp_rtpmap_g728 = RTPMAP(15, "G728", 8000, "1"),
+ sdp_rtpmap_dvi4_11025 = RTPMAP(16, "DVI4", 11025, "1"),
+ sdp_rtpmap_dvi4_22050 = RTPMAP(17, "DVI4", 22050, "1"),
+ sdp_rtpmap_g729 = RTPMAP(18, "G729", 8000, "1"),
+ sdp_rtpmap_cn_reserved = RTPMAP(19, "CN", 8000, "1");
+
+ TEST_1(rm = rm->rm_next);
+ TEST_1(sdp_rtpmap_match(&sdp_rtpmap_pcmu, rm));
+ TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_pcmu, rm), &sdp_rtpmap_pcmu);
+ TEST_1(rm = rm->rm_next);
+ TEST_1(sdp_rtpmap_match(&sdp_rtpmap_1016, rm));
+ TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_1016, rm), &sdp_rtpmap_1016);
+ TEST_1(rm = rm->rm_next);
+ TEST_1(sdp_rtpmap_match(&sdp_rtpmap_g721, rm));
+ TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_g721, rm), &sdp_rtpmap_g721);
+ TEST_1(rm = rm->rm_next);
+ TEST_1(sdp_rtpmap_match(&sdp_rtpmap_gsm, rm));
+ TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_gsm, rm), &sdp_rtpmap_gsm);
+ TEST_1(rm = rm->rm_next);
+ TEST_1(sdp_rtpmap_match(&sdp_rtpmap_g723, rm));
+ TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_g723, rm), &sdp_rtpmap_g723);
+ TEST_1(rm = rm->rm_next);
+ TEST_1(sdp_rtpmap_match(&sdp_rtpmap_dvi4_8000, rm));
+ TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_dvi4_8000, rm),
+ &sdp_rtpmap_dvi4_8000);
+ TEST_1(rm = rm->rm_next);
+ TEST_1(sdp_rtpmap_match(&sdp_rtpmap_dvi4_16000, rm));
+ TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_dvi4_16000, rm),
+ &sdp_rtpmap_dvi4_16000);
+ TEST_1(rm = rm->rm_next);
+ TEST_1(sdp_rtpmap_match(&sdp_rtpmap_lpc, rm));
+ TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_lpc, rm), &sdp_rtpmap_lpc);
+ TEST_1(rm = rm->rm_next);
+ TEST_1(sdp_rtpmap_match(&sdp_rtpmap_pcma, rm));
+ TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_pcma, rm), &sdp_rtpmap_pcma);
+ TEST_1(rm = rm->rm_next);
+ TEST_1(sdp_rtpmap_match(&sdp_rtpmap_g722, rm));
+ TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_g722, rm), &sdp_rtpmap_g722);
+ TEST_1(rm = rm->rm_next);
+ TEST_1(sdp_rtpmap_match(&sdp_rtpmap_l16, rm));
+ TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_l16, rm), &sdp_rtpmap_l16);
+ TEST_1(rm = rm->rm_next);
+ TEST_1(sdp_rtpmap_match(&sdp_rtpmap_l16_stereo, rm));
+ TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_l16_stereo, rm),
+ &sdp_rtpmap_l16_stereo);
+ TEST_1(rm = rm->rm_next);
+ TEST_1(sdp_rtpmap_match(&sdp_rtpmap_qcelp, rm));
+ TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_qcelp, rm), &sdp_rtpmap_qcelp);
+ TEST_1(rm = rm->rm_next);
+ TEST_1(sdp_rtpmap_match(&sdp_rtpmap_cn, rm));
+ TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_cn, rm), &sdp_rtpmap_cn);
+ TEST_1(rm = rm->rm_next);
+ TEST_1(sdp_rtpmap_match(&sdp_rtpmap_mpa, rm));
+ TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_mpa, rm), &sdp_rtpmap_mpa);
+ TEST_1(rm = rm->rm_next);
+ TEST_1(sdp_rtpmap_match(&sdp_rtpmap_g728, rm));
+ TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_g728, rm), &sdp_rtpmap_g728);
+ TEST_1(rm = rm->rm_next);
+ TEST_1(sdp_rtpmap_match(&sdp_rtpmap_dvi4_11025, rm));
+ TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_dvi4_11025, rm),
+ &sdp_rtpmap_dvi4_11025);
+ TEST_1(rm = rm->rm_next);
+ TEST_1(sdp_rtpmap_match(&sdp_rtpmap_dvi4_22050, rm));
+ TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_dvi4_22050, rm),
+ &sdp_rtpmap_dvi4_22050);
+ TEST_1(rm = rm->rm_next);
+ TEST_1(sdp_rtpmap_match(&sdp_rtpmap_g729, rm));
+ TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_g729, rm), &sdp_rtpmap_g729);
+ TEST_1(rm = rm->rm_next);
+ TEST_1(sdp_rtpmap_match(&sdp_rtpmap_cn_reserved, rm));
+ TEST_P(sdp_rtpmap_find_matching(&sdp_rtpmap_cn_reserved, rm),
+ &sdp_rtpmap_cn_reserved);
+ TEST_1(!rm->rm_next);
+ }
+
+ TEST_1((parser = sdp_parse(home, s2_msg, sizeof (s2_msg), 0)));
+ TEST_1((sdp = sdp_session(parser)));
+ TEST_1(m = sdp->sdp_media);
+ TEST(m->m_mode, sdp_recvonly);
+ TEST_P(m->m_session, sdp);
+ TEST_1(m->m_rtpmaps);
+ TEST(m->m_rtpmaps->rm_pt, 96);
+ TEST_S(m->m_rtpmaps->rm_encoding, "H263-1998");
+ TEST(m->m_rtpmaps->rm_rate, 90000);
+ TEST_S(m->m_rtpmaps->rm_fmtp, "QCIF=4");
+ TEST_1(m = sdp->sdp_media->m_next);
+ TEST(m->m_mode, sdp_recvonly);
+ TEST_P(m->m_session, sdp);
+ TEST_1(m->m_rtpmaps);
+ TEST(m->m_rtpmaps->rm_pt, 97);
+ TEST_S(m->m_rtpmaps->rm_encoding, "AMR");
+ TEST(m->m_rtpmaps->rm_rate, 8000);
+ TEST_S(m->m_rtpmaps->rm_fmtp, "mode-set=\"0\"");
+
+ su_home_unref(home);
+
+ END();
+}
+
+static char const s3_msg[] =
+ "v=0\r\n"
+ "o=- 2435697 2435697 IN IP4 172.21.137.44\r\n"
+ "s=-\r\n"
+ "t=0 0\r\n"
+ "m=video 49154 RTP/AVP 34\r\n"
+ "c=IN IP4 172.21.137.44\r\n"
+ "m=audio 49152 RTP/AVP 8 0\r\n"
+ "c=IN IP4 172.21.137.44\r\n"
+ "m=message 0 MSRP/TCP *\r\n"
+ ;
+
+
+static int test_sanity(void)
+{
+ su_home_t *home = su_home_create();
+ sdp_parser_t *parser;
+
+ BEGIN();
+
+ su_home_check(home); TEST_1(home);
+
+ TEST_1((parser = sdp_parse(home, s3_msg, sizeof(s1_msg), 0)));
+
+ TEST_1(sdp_sanity_check(parser) == 0);
+
+ su_home_unref(home);
+
+ END();
+}
+
+static sdp_list_t const l0[1] = {{ sizeof(l0), NULL, "foo" }};
+static sdp_list_t const l1[1] = {{ sizeof(l1), (sdp_list_t *)l0, "bar" }};
+
+/** Test list things */
+int test_list(void)
+{
+ su_home_t *home = su_home_create();
+ sdp_list_t *l;
+
+ BEGIN();
+
+ su_home_check(home);
+
+ TEST_1(home);
+
+ TEST_1((l = sdp_list_dup(home, l0)));
+ TEST_P(l->l_next, NULL);
+ TEST_S(l->l_text, "foo");
+
+ TEST_1((l = sdp_list_dup(home, l1)));
+ TEST_1(l->l_next != NULL);
+ TEST_1(l->l_next->l_next == NULL);
+ TEST_S(l->l_text, "bar");
+ TEST_S(l->l_next->l_text, "foo");
+
+ su_home_check(home);
+
+ su_home_unref(home);
+
+ END();
+}
+
+static
+sdp_rtpmap_t const rm0[1] =
+ {{
+ sizeof(rm0), NULL, "AMR", 8000, "1",
+ "mode-set=4,5,6 interleaving crc use-redundancy=1",
+ 0, 96, 0
+ }};
+
+static
+sdp_rtpmap_t const rm1[1] =
+ {{
+ sizeof(rm1), (sdp_rtpmap_t *)rm0, "PCMA", 8000, "1",
+ NULL,
+ 1, 8, 0,
+ }};
+
+/** Test rtpmap-related things */
+int test_rtpmap(void)
+{
+ su_home_t *home = su_home_create();
+ sdp_rtpmap_t *rm;
+
+ BEGIN();
+
+ su_home_check(home);
+
+ TEST_1(home);
+
+ TEST_1((rm = sdp_rtpmap_dup(home, rm0)));
+ TEST_P(rm->rm_next, NULL);
+ TEST_S(rm->rm_encoding, "AMR");
+ TEST_S(rm->rm_params, "1");
+ TEST(rm->rm_pt, 96);
+ TEST_S(rm->rm_fmtp, "mode-set=4,5,6 interleaving crc use-redundancy=1");
+
+ TEST_1((rm = sdp_rtpmap_dup(home, rm1)));
+ TEST_1(rm->rm_next != NULL);
+ TEST_1(rm->rm_next->rm_next == NULL);
+ TEST_S(rm->rm_encoding, "PCMA");
+ TEST_S(rm->rm_params, "1");
+ TEST(rm->rm_pt, 8);
+
+ su_home_check(home);
+
+ su_home_unref(home);
+
+ END();
+}
+
+static sdp_attribute_t const a0[1] =
+ {{ sizeof(a0), NULL, "foo", "2"}};
+static sdp_attribute_t const a1[1] =
+ {{ sizeof(a1), (sdp_attribute_t *)a0, "bar", "1" }};
+
+static int test_attribute(void)
+{
+ su_home_t *home = su_home_create();
+ sdp_attribute_t *a, *a_new, *list, *replaced;
+
+ BEGIN();
+
+ su_home_check(home);
+
+ TEST_1(home);
+
+ TEST_1((a = sdp_attribute_dup(home, a0)));
+ TEST_P(a->a_next, NULL);
+ TEST_S(a->a_name, "foo");
+ TEST_S(a->a_value, "2");
+
+ strcpy((char *)a->a_name, "FOO");
+ TEST_S(a0->a_name, "foo");
+
+ strcpy((char *)a->a_value, "X");
+ TEST_S(a0->a_value, "2");
+
+ TEST_1((a = sdp_attribute_dup(home, a1)));
+ TEST_1(a->a_next != NULL);
+ TEST_1(a->a_next->a_next == NULL);
+ TEST_S(a->a_name, "bar");
+ TEST_S(a->a_value, "1");
+ TEST_S(a->a_next->a_name, "foo");
+ TEST_S(a->a_next->a_value, "2");
+
+ list = a;
+
+ TEST_P(sdp_attribute_remove(&list, NULL), NULL);
+ TEST_P(sdp_attribute_remove(&list, "kuik"), NULL);
+ TEST_P(sdp_attribute_remove(&list, "barf"), NULL);
+ TEST_P(sdp_attribute_remove(&list, "bar"), a);
+ TEST_1(a_new = sdp_attribute_dup(home, a));
+ replaced = (void *)-1;
+ TEST(sdp_attribute_replace(&list, NULL, &replaced), -1);
+ TEST_P(replaced, NULL);
+ TEST(sdp_attribute_replace(&list, a, &replaced), 0);
+ TEST_P(replaced, NULL);
+ TEST(sdp_attribute_replace(&list, a_new, &replaced), 1);
+ TEST_P(replaced, a);
+
+ TEST_VOID(sdp_attribute_append(&list, a));
+
+ TEST_P(sdp_attribute_remove(&list, "bAr"), a_new);
+ TEST_P(sdp_attribute_remove(&list, "BAR"), a);
+ TEST_P(sdp_attribute_remove(&list, "bar"), NULL);
+
+ su_home_check(home);
+
+ su_home_unref(home);
+
+ END();
+}
+
+static int test_connection(void)
+{
+ BEGIN();
+ END();
+}
+
+static char const media_msg[] =
+"v=0\n"
+"s=/sdp_torture\n"
+"o=sdp_torture 0 0 IN IP4 1.2.3.4\n"
+"c=IN IP4 1.2.3.4\n"
+"m=audio 0 RTP/AVP 96 97 98 10 99 8 0\n"
+"a=rtpmap:96 X-AMR-WB/16000\n"
+"a=rtpmap:97 X-AMR/8000\n"
+"a=rtpmap:98 GSM-EFR/8000\n"
+"a=rtpmap:10 L16/16000\n"
+"a=rtpmap:99 G723/8000\n"
+"a=rtpmap:8 PCMA/8000\n"
+"a=rtpmap:0 PCMU/8000\n"
+"m=video 0 RTP/AVP 31\n"
+"c=IN IP4 2.3.4.5\n";
+
+static sdp_media_t const m0[1] =
+ {{ sizeof(m0),
+ NULL,
+ NULL,
+ sdp_media_audio,
+ NULL,
+ 1234,
+ 5,
+ sdp_proto_udp,
+ "udp",
+ }};
+
+static int test_media(void)
+{
+ su_home_t *home = su_home_create();
+ sdp_media_t *media;
+ sdp_session_t *sdp;
+ sdp_parser_t *parser;
+
+ BEGIN();
+
+ su_home_check(home);
+ TEST_1(home);
+
+ TEST_1((parser = sdp_parse(home, media_msg, sizeof(media_msg), 0)));
+ TEST_1((sdp = sdp_session(parser)));
+ TEST_1((media = sdp_media_dup(home, m0, sdp)));
+ /* Check comparing */
+ TEST(sdp_media_cmp(media, m0), 0);
+
+ TEST(media->m_type, sdp_media_audio);
+ TEST(media->m_port, 1234);
+ TEST(media->m_number_of_ports, 5);
+ TEST_P(media->m_session, sdp);
+ /* FIXME: add more tests */
+
+ media->m_next = (sdp_media_t *)m0;
+ TEST_1((media = sdp_media_dup_all(home, media, sdp)));
+ TEST_P(media->m_connections, NULL);
+ TEST_1(media->m_next);
+ TEST_P(media->m_next->m_connections, NULL);
+ TEST_P(sdp_media_connections(media), sdp->sdp_connection);
+ TEST_P(sdp_media_connections(media->m_next), sdp->sdp_connection);
+
+ sdp_parser_free(parser);
+
+ su_home_check(home);
+ su_home_unref(home);
+
+ END();
+}
+
+static int test_origin(void)
+{
+ BEGIN();
+ END();
+}
+
+static int test_bandwidth(void)
+{
+ BEGIN();
+ END();
+}
+
+static char const t_msg[] =
+"v=0\n"
+"s=/sdp_torture\n"
+"o=sdp_torture 1 1 IN IP4 1.2.3.4\n"
+"c=IN IP4 1.2.3.4\n"
+"t=3309789956 3309793556\n"
+"t=3309789956 3309793557\n"
+"t=3309789955 3309793557\n"
+"r=604800 3600 0 90000\n"
+"z=2882844526 -1h 2898848070 0\n"
+"t=3309789955 3309793557\n"
+"r=604800 3600 0 90000\n"
+"z=2882844526 -1h 2898848070 0\n"
+ ;
+
+static int test_time(void)
+{
+ sdp_parser_t *parser;
+ sdp_session_t *sdp;
+ sdp_time_t *t, t1[1], t2[1];
+
+ BEGIN();
+
+ TEST_1((parser = sdp_parse(NULL, t_msg, sizeof(t_msg), 0)));
+ TEST_1((sdp = sdp_session(parser)));
+ TEST_1((t = sdp->sdp_time)); *t1 = *t; t1->t_next = NULL; *t2 = *t1;
+ TEST_1(sdp_time_cmp(t1, t1) == 0);
+ TEST_1(sdp_time_cmp(t1, t2) == 0);
+ TEST_1(sdp_time_cmp(t2, t1) == 0);
+ TEST_1((t = t->t_next)); *t1 = *t; t1->t_next = NULL;
+ TEST_1(sdp_time_cmp(t1, t2) > 0);
+ TEST_1(sdp_time_cmp(t2, t1) < 0);
+ TEST_1((t = t->t_next)); *t2 = *t; t2->t_next = NULL;
+ TEST_1(t2->t_zone); TEST_1(t2->t_repeat);
+ TEST_1(sdp_time_cmp(t2, t2) == 0);
+ TEST_1(sdp_time_cmp(t1, t2) > 0);
+ TEST_1(sdp_time_cmp(t2, t1) < 0);
+ TEST_1((t = t->t_next)); *t1 = *t; t1->t_next = NULL;
+ TEST_1(t1->t_zone); TEST_1(t1->t_repeat);
+ TEST_1(sdp_time_cmp(t1, t1) == 0);
+ TEST_1(sdp_time_cmp(t2, t2) == 0);
+ TEST_1(sdp_time_cmp(t1, t2) == 0);
+
+ sdp_parser_free(parser);
+
+ END();
+}
+
+static int test_key(void)
+{
+ BEGIN();
+ END();
+}
+
+#include <time.h>
+#include <stdlib.h>
+
+static int test_build(void)
+{
+ sdp_session_t *sdp, *dup;
+ sdp_origin_t *o;
+ sdp_time_t *t;
+ sdp_connection_t *c;
+ sdp_media_t *m, *m1;
+ sdp_rtpmap_t *rm;
+ sdp_list_t *l, *l1;
+ sdp_attribute_t *a;
+ su_home_t *home;
+ sdp_printer_t *printer;
+ char const *data;
+
+ BEGIN();
+
+ srand(time(NULL));
+
+ TEST_1(home = su_home_create());
+
+ /*
+ * Allocate an SDP structure using su_salloc().
+ * su_salloc() puts memory area size to the beginning of structure
+ * and zeroes rest of the structure.
+ */
+ TEST_1(sdp = su_salloc(home, sizeof(*sdp)));
+ TEST_1(o = su_salloc(home, sizeof(*o)));
+ TEST_1(t = su_salloc(home, sizeof(*t)));
+ TEST_1(c = su_salloc(home, sizeof(*c)));
+ TEST_1(m = su_salloc(home, sizeof(*m)));
+ TEST_1(rm = su_salloc(home, sizeof(*rm)));
+
+ sdp->sdp_origin = o;
+ sdp->sdp_time = t; /* zero time is fine for SIP */
+ sdp->sdp_connection = c;
+ sdp->sdp_media = m;
+
+ o->o_username = "test";
+ o->o_id = rand();
+ o->o_version = 1;
+ o->o_address = c;
+
+ c->c_nettype = sdp_net_in;
+ c->c_addrtype = sdp_addr_ip4;
+ c->c_address = "172.21.40.40";
+
+ m->m_session = sdp;
+ m->m_type = sdp_media_audio; m->m_type_name = "audio";
+ m->m_port = 5004;
+ m->m_proto = sdp_proto_rtp; m->m_proto_name = "RTP/AVP";
+ m->m_rtpmaps = rm;
+
+ rm->rm_predef = 1;
+ rm->rm_pt = 8;
+ rm->rm_encoding = "PCMA";
+ rm->rm_rate = 8000;
+
+ TEST_1(m1 = su_salloc(home, sizeof(*m1)));
+ TEST_1(l = su_salloc(home, sizeof(*l)));
+ TEST_1(l1 = su_salloc(home, sizeof(*l1)));
+ TEST_1(a = su_salloc(home, sizeof(*a)));
+
+ m->m_next = m1;
+
+ m1->m_session = sdp;
+ m1->m_type = sdp_media_message; m->m_type_name = "message";
+ m1->m_port = 5060;
+ m1->m_proto = sdp_proto_tcp; m->m_proto_name = "TCP";
+ m1->m_format = l;
+ m1->m_attributes = a;
+
+ l->l_text = "sip";
+
+ l->l_next = l1;
+ l1->l_text = "cpim";
+
+ a->a_name = "user";
+ a->a_value = "chat-81273845";
+
+ TEST_1(dup = sdp_session_dup(home, sdp));
+
+ TEST_1(printer = sdp_print(home, dup, NULL, 0, 0));
+ TEST_1(data = sdp_message(printer));
+
+ if (tstflags & tst_verbatim)
+ printf("sdp_torture.c: built SDP message:\"%s\".\n", data);
+
+ sdp_printer_free(printer);
+
+ END();
+}
+
+void usage(void)
+{
+ fprintf(stderr, "usage: %s [-v]\n", name);
+}
+
+int main(int argc, char *argv[])
+{
+ int retval = 0;
+ int i;
+
+ for (i = 1; argv[i]; i++) {
+ if (strcmp(argv[i], "-v") == 0)
+ tstflags |= tst_verbatim;
+ else
+ usage();
+ }
+
+ null = fopen("/dev/null", "ab");
+
+ retval |= test_error(); fflush(stdout);
+ retval |= test_session(); fflush(stdout);
+ retval |= test_session2(); fflush(stdout);
+ retval |= test_sanity(); fflush(stdout);
+ retval |= test_list(); fflush(stdout);
+ retval |= test_rtpmap(); fflush(stdout);
+ retval |= test_origin(); fflush(stdout);
+ retval |= test_connection(); fflush(stdout);
+ retval |= test_bandwidth(); fflush(stdout);
+ retval |= test_time(); fflush(stdout);
+ retval |= test_key(); fflush(stdout);
+ retval |= test_attribute(); fflush(stdout);
+ retval |= test_media(); fflush(stdout);
+ retval |= test_build(); fflush(stdout);
+
+ return retval;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/ADD-A-HEADER
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/ADD-A-HEADER Thu Dec 21 01:30:28 2006
@@ -0,0 +1,152 @@
+Description of Adding a SIP Header to Sofia SIP
+===============================================
+
+by Pekka Pessi (2002-08-16, updated 2006-10-03)
+
+There are three ways to extend the Sofia SIP parser, including a standard
+header in sip_t structure, including a standard header in extra headers or
+putting the extension headers into a separate library.
+
+Probalem with extending #sip_t is that it breaks binary compatibility.
+
+In the text below, we use "Example" header as our example with following
+ABNF:
+
+ sip-example = "Example" COLON 1*DIGIT
+
+
+IF YOUR HEADER IS A STANDARD ONE
+--------------------------------
+
+ * In <sip.h>, add:
+
+ - Add typedef to the header structure.
+
+ The typedefs to ordinary headers are in more or less alphabetic
+ order after typedef of sip_unknown_t. You should add a typedef line
+ like this:
+
+ typedef struct sip_example_s sip_example_t;
+
+ Note that the typedefs are documented together with the
+ implementation in the .c file.
+
+ - Add field to the sip_t structure (struct sip_s)
+ - Remember to add a comment containing the header name
+ after field for benefit of the AWK script autmatically generating
+ boilerplate functions and macros:
+ sip_example_t *sip_example; /**< Example */
+ - The AWK script msg_parser.awk automatically creates the default
+ prototypes and tags for the newly created header when the entry in
+ sip_t structure is formatted like to the example above.
+ It will complain about mismatches between header name and field name.
+
+ * Add the actual header structure:
+
+ The header structure would look like below. The first field MUST be a
+ sip_common_t structure, second field MUST be a pointer to next header
+ with same name. As a convention, if there can be only one header field
+ of this kind, the type of the "next" pointer is sip_error_t.
+
+ The fields representing the header value are located after the mandatory
+ fields, usually in the order they are present in the header contents. In
+ this case, the Example header consist of a 32-bit integer:
+
+ /**@ingroup sip_example
+ * @brief Structure for Example header.
+ */
+ struct sip_example_s {
+ sip_common_t ex_common[1]; /**< Common fragment info. */
+ sip_error_t *ex_next; /**< Link to next (dummy). */
+ unsigned long ex_value; /**< Value of example. */
+ };
+
+ * Write parsing tests for your new headers in torture_sip.c:
+
+ Add all relevant parsing/processing cases you can think of
+ at the end of function sip_header_test() or add a testing
+ function of your own.
+
+ * Add implementation in a suitable ".c" file
+ - For an simple example, see implementation of Date header in sip_basic.c
+ - Add a documentation group with @defgroup
+ - Document the typedef
+ - Add header class structure
+ - Add parsing and printing functions:
+ + sip_example_d(), sip_example_e()
+ - Add functions used when copying the header structure:
+ + sip_example_dup_xtra(), sip_example_dup_one()
+
+ * If you added a .c file, add to the Makefile.am
+ - remember to run autogen.sh unless you have given --enable-maintainer-mode
+ to configure script
+
+ * Run "make check" after you are ready
+
+ * Run "make check" after you are ready. Really.
+
+
+IF YOUR HEADERS ARE NON-STANDARD
+--------------------------------
+
+ - There is an example package sofia-sip-2543.tar.gz, available from
+ sofia-sip.sourceforge.net
+
+ See the extension package for 1)
+
+ - Create a header template for your header just like
+ sofia-sip/rfc2543.h.in (found in <sofia-sip/rfc2543.h> package),
+ e.g, sip_example.h.in:
+
+---8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<---
+/**@file sip_example.h.in
+ *
+ * Template for <sip_example.h>.
+ */
+
+#ifndef SIP_EXAMPLE_H
+/** Defined when <sip_example.h> has been included. */
+#define SIP_EXAMPLE_H
+
+/**@file sip_example.h
+*
+ * @brief Example header.
+ *
+ * #AUTO#
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Fri May 27 18:40:38 EEST 2005 ppessi
+ */
+
+#ifndef SIP_H
+#include <sofia-sip/sip.h>
+#endif
+#ifndef SIP_HEADER_H
+#include <sofia-sip/sip_header.h>
+#endif
+
+/**@ingroup sip_example
+ * @brief Structure for @b Example header.
+ */
+struct sip_example_s
+{
+ sip_common_t ex_common[1]; /**< Common fragment info */
+ sip_error_t *ex_next; /**< Link to next (dummy). */
+ uint32_t ex_value; /**< Value of Example */
+};
+
+typedef struct sip_example_s sip_example_t;
+
+struct sip_example_dummy_structure {
+ /* === Headers start here */
+ sip_example_t *sip_example; /**< Example */
+ /* === Headers end here */
+};
+
+
+#endif /** !defined(SIP_EXAMPLE_H) */
+--->8---->8---->8---->8---->8---->8---->8---->8---->8---->8---->8---->8---
+
+
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/ChangeLog Thu Dec 21 01:30:28 2006
@@ -0,0 +1,58 @@
+2006-01-25 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * Doxyfile (INPUT): Missing sip_dll.c broke refdoc
+ build. Now changed so that individual are not listed
+ anymore in INPUT.
+
+2006-01-10 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * Doxyfile: References to removed files sip_internal.h
+ and sip_extensions.h caused fatal doxygen error.
+
+2005-10-21 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * sip_contact_create_from_via_with_transport() now converts tport name to lcase.
+
+ M ./libsofia-sip-ua/sip/sip_util.c -10 +25
+
+2005-10-12 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Contact generated by nta now contains URL transport parameter.
+ The transport=UDP was left out from contact URL always. Now it is left out
+ only if both UDP and TCP are supported.
+ Added utility function sip_contact_create_from_via_with_transport().
+
+ M ./libsofia-sip-ua/nta/nta.c -2 +14
+ M ./libsofia-sip-ua/sip/sip_util.c -10 +28
+ M ./libsofia-sip-ua/sip/sip_util.h +6
+
+2005-08-01 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Makefile.am: Added sip_bad_mask.
+
+ * sip_mime.c: Fixed sip_accept_encoding_d() and
+ sip_accept_language_d() to accept empty list.
+
+ * sip_util.c: sip_header_as_string() can now return an empty
+ string, too.
+
+ * sip.h: Putting Proxy-Require in the beginning of hte message.
+
+ * torture_sip.c: Added tests for privacy.
+
+ * sip_security.c: Added error checking in Privacy: accept
+ commas-separated list, too.
+
+ * sip_parser.h: Added header classification masks.
+
+ * sip_mime.c: Using apndlist format for various Accept headers.
+
+ * sip_feature.c: Using msg_commalist_d() to decode Allow, Require,
+ Proxy-Require, Supported, and Unsupported.
+
+ * sip_basic.c: Not encoding comment in Contact. Always using
+ name-addr form for Route headers.
+
+2005-07-18 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * Initial import of the module to Sofia-SIP tree.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/Doxyfile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/Doxyfile Thu Dec 21 01:30:28 2006
@@ -0,0 +1,28 @@
+PROJECT_NAME = "sip"
+OUTPUT_DIRECTORY = ../docs/html/sip
+
+INPUT = sofia-sip sip.docs sip_parser.docs .
+
+ at INCLUDE = ../docs/Doxyfile.conf
+
+TAGFILES += \
+ ../docs/su.doxytags=../su \
+ ../docs/ipt.doxytags=../ipt \
+ ../docs/bnf.doxytags=../bnf \
+ ../docs/url.doxytags=../url \
+ ../docs/msg.doxytags=../msg \
+ ../docs/sdp.doxytags=../sdp \
+ ../docs/iptsec.doxytags=../iptsec \
+ ../docs/nta.doxytags=../nta \
+ ../docs/nua.doxytags=../nua
+
+GENERATE_TAGFILE = ../docs/sip.doxytags
+
+ALIASES += \
+ "SIP_TAG=@ingroup sip_tag\n" \
+ "SIP_HEADER=@ingroup sip_headers\n at defgroup" \
+ "SIP_PARSER=\n"
+
+ at INCLUDE = sip.doxyaliases
+
+IMAGE_PATH += images
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/GRAMMAR
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/GRAMMAR Thu Dec 21 01:30:28 2006
@@ -0,0 +1,537 @@
+/* SIP grammar from RFC3261
+ *
+ * alphanum = ALPHA / DIGIT
+ *
+ * reserved = ";" / "/" / "?" / ":" / "@" / "&" / "=" / "+"
+ * / "$" / ","
+ * unreserved = alphanum / mark
+ * mark = "-" / "_" / "." / "!" / "~" / "*" / "'"
+ * / "(" / ")"
+ * escaped = "%" HEXDIG HEXDIG
+ *
+ * LWS = [*WSP CRLF] 1*WSP ; linear whitespace
+ * SWS = [LWS] ; sep whitespace
+ *
+ * HCOLON = *( SP / HTAB ) ":" SWS
+ *
+ * TEXT-UTF8-TRIM = 1*TEXT-UTF8char *(*LWS TEXT-UTF8char)
+ * TEXT-UTF8char = %x21-7E / UTF8-NONASCII
+ * UTF8-NONASCII = %xC0-DF 1UTF8-CONT
+ * / %xE0-EF 2UTF8-CONT
+ * / %xF0-F7 3UTF8-CONT
+ * / %xF8-Fb 4UTF8-CONT
+ * / %xFC-FD 5UTF8-CONT
+ * UTF8-CONT = %x80-BF
+ *
+ * LHEX = DIGIT / %x61-66 ;lowercase a-f
+ *
+ * token = 1*(alphanum / "-" / "." / "!" / "%" / "*"
+ * / "_" / "+" / "`" / "'" / "~" )
+ * separators = "(" / ")" / "<" / ">" / "@" /
+ * "," / ";" / ":" / "\" / DQUOTE /
+ * "/" / "[" / "]" / "?" / "=" /
+ * "{" / "}" / SP / HTAB
+ * word = 1*(alphanum / "-" / "." / "!" / "%" / "*" /
+ * "_" / "+" / "`" / "'" / "~" /
+ * "(" / ")" / "<" / ">" /
+ * ":" / "\" / DQUOTE /
+ * "/" / "[" / "]" / "?" /
+ * "{" / "}" )
+ *
+ * STAR = SWS "*" SWS ; asterisk
+ * SLASH = SWS "/" SWS ; slash
+ * EQUAL = SWS "=" SWS ; equal
+ * LPAREN = SWS "(" SWS ; left parenthesis
+ * RPAREN = SWS ")" SWS ; right parenthesis
+ * RAQUOT = ">" SWS ; right angle quote
+ * LAQUOT = SWS "<"; left angle quote
+ * COMMA = SWS "," SWS ; comma
+ * SEMI = SWS ";" SWS ; semicolon
+ * COLON = SWS ":" SWS ; colon
+ * LDQUOT = SWS DQUOTE; open double quotation mark
+ * RDQUOT = DQUOTE SWS ; close double quotation mark
+ *
+ * comment = LPAREN *(ctext / quoted-pair / comment) RPAREN
+ * ctext = %x21-27 / %x2A-5B / %x5D-7E / UTF8-NONASCII
+ * / LWS
+ *
+ * quoted-string = SWS DQUOTE *(qdtext / quoted-pair ) DQUOTE
+ * qdtext = LWS / %x21 / %x23-5B / %x5D-7E
+ * / UTF8-NONASCII
+ *
+ * quoted-pair = "\" (%x00-09 / %x0B-0C
+ * / %x0E-7F)
+ *
+ * SIP-URI = "sip:" [ userinfo ] hostport
+ * uri-parameters [ headers ]
+ * SIPS-URI = "sips:" [ userinfo ] hostport
+ * uri-parameters [ headers ]
+ * userinfo = ( user / telephone-subscriber ) [ ":" password ] "@"
+ * user = 1*( unreserved / escaped / user-unreserved )
+ * user-unreserved = "&" / "=" / "+" / "$" / "," / ";" / "?" / "/"
+ * password = *( unreserved / escaped /
+ * "&" / "=" / "+" / "$" / "," )
+ * hostport = host [ ":" port ]
+ * host = hostname / IPv4address / IPv6reference
+ * hostname = *( domainlabel "." ) toplabel [ "." ]
+ * domainlabel = alphanum
+ * / alphanum *( alphanum / "-" ) alphanum
+ * toplabel = ALPHA / ALPHA *( alphanum / "-" ) alphanum
+ * IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT
+ * IPv6reference = "[" IPv6address "]"
+ * IPv6address = hexpart [ ":" IPv4address ]
+ * hexpart = hexseq / hexseq "::" [ hexseq ] / "::" [ hexseq ]
+ * hexseq = hex4 *( ":" hex4)
+ * hex4 = 1*4HEXDIG
+ * port = 1*DIGIT
+ *
+ * uri-parameters = *( ";" uri-parameter)
+ * uri-parameter = transport-param / user-param / method-param
+ * / ttl-param / maddr-param / lr-param / other-param
+ * transport-param = "transport="
+ * ( "udp" / "tcp" / "sctp" / "tls"
+ * / other-transport)
+ * other-transport = token
+ * user-param = "user=" ( "phone" / "ip" / other-user)
+ * other-user = token
+ * method-param = "method=" Method
+ * ttl-param = "ttl=" ttl
+ * maddr-param = "maddr=" host
+ * lr-param = "lr"
+ * other-param = pname [ "=" pvalue ]
+ * pname = 1*paramchar
+ * pvalue = 1*paramchar
+ * paramchar = param-unreserved / unreserved / escaped
+ * param-unreserved = "[" / "]" / "/" / ":" / "&" / "+" / "$"
+ *
+ * headers = "?" header *( "&" header )
+ * header = hname "=" hvalue
+ * hname = 1*( hnv-unreserved / unreserved / escaped )
+ * hvalue = *( hnv-unreserved / unreserved / escaped )
+ * hnv-unreserved = "[" / "]" / "/" / "?" / ":" / "+" / "$"
+ *
+ * SIP-message = Request / Response
+ * Request = Request-Line
+ * *( message-header )
+ * CRLF
+ * [ message-body ]
+ * Request-Line = Method SP Request-URI SP SIP-Version CRLF
+ * Request-URI = SIP-URI / SIPS-URI / absoluteURI
+ * absoluteURI = scheme ":" ( hier-part / opaque-part )
+ * hier-part = ( net-path / abs-path ) [ "?" query ]
+ * net-path = "//" authority [ abs-path ]
+ * abs-path = "/" path-segments
+ * opaque-part = uric-no-slash *uric
+ * uric = reserved / unreserved / escaped
+ * uric-no-slash = unreserved / escaped / ";" / "?" / ":" / "@"
+ * / "&" / "=" / "+" / "$" / ","
+ * path-segments = segment *( "/" segment )
+ * segment = *pchar *( ";" param )
+ * param = *pchar
+ * pchar = unreserved / escaped /
+ * ":" / "@" / "&" / "=" / "+" / "$" / ","
+ * scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
+ * authority = srvr / reg-name
+ * srvr = [ [ userinfo "@" ] hostport ]
+ * reg-name = 1*( unreserved / escaped / "$" / ","
+ * / ";" / ":" / "@" / "&" / "=" / "+" )
+ * query = *uric
+ * SIP-Version = "SIP" "/" 1*DIGIT "." 1*DIGIT
+ *
+ * message-header = (Accept
+ * / Accept-Encoding
+ * / Accept-Language
+ * / Alert-Info
+ * / Allow
+ * / Authentication-Info
+ * / Authorization
+ * / Call-ID
+ * / Call-Info
+ * / Contact
+ * / Content-Disposition
+ * / Content-Encoding
+ * / Content-Language
+ * / Content-Length
+ * / Content-Type
+ * / CSeq
+ * / Date
+ * / Error-Info
+ * / Expires
+ * / From
+ * / In-Reply-To
+ * / Max-Forwards
+ * / MIME-Version
+ * / Min-Expires
+ * / Organization
+ * / Priority
+ * / Proxy-Authenticate
+ * / Proxy-Authorization
+ * / Proxy-Require
+ * / Record-Route
+ * / Reply-To
+ * / Require
+ * / Retry-After
+ * / Route
+ * / Server
+ * / Subject
+ * / Supported
+ * / Timestamp
+ * / To
+ * / Unsupported
+ * / User-Agent
+ * / Via
+ * / Warning
+ * / WWW-Authenticate
+ * / extension-header) CRLF
+ *
+ * INVITEm = %x49.4E.56.49.54.45 ; INVITE in caps
+ * ACKm = %x41.43.4B ; ACK in caps
+ * OPTIONSm = %x4F.50.54.49.4F.4E.53 ; OPTIONS in caps
+ * BYEm = %x42.59.45 ; BYE in caps
+ * CANCELm = %x43.41.4E.43.45.4C ; CANCEL in caps
+ * REGISTERm = %x52.45.47.49.53.54.45.52 ; REGISTER in caps
+ * Method = INVITEm / ACKm / OPTIONSm / BYEm
+ * / CANCELm / REGISTERm
+ * / extension-method
+ * extension-method = token
+ * Response = Status-Line
+ * *( message-header )
+ * CRLF
+ * [ message-body ]
+ *
+ * Status-Line = SIP-Version SP Status-Code SP Reason-Phrase CRLF
+ * Status-Code = Informational
+ * / Redirection
+ * / Success
+ * / Client-Error
+ * / Server-Error
+ * / Global-Failure
+ * / extension-code
+ * extension-code = 3DIGIT
+ * Reason-Phrase = *(reserved / unreserved / escaped
+ * / UTF8-NONASCII / UTF8-CONT / SP / HTAB)
+ *
+ * Informational = "100" ; Trying
+ * / "180" ; Ringing
+ * / "181" ; Call Is Being Forwarded
+ * / "182" ; Queued
+ * / "183" ; Session Progress
+ *
+ * Success = "200" ; OK
+ *
+ * Redirection = "300" ; Multiple Choices
+ * / "301" ; Moved Permanently
+ * / "302" ; Moved Temporarily
+ * / "305" ; Use Proxy
+ * / "380" ; Alternative Service
+ *
+ * Client-Error = "400" ; Bad Request
+ * / "401" ; Unauthorized
+ * / "402" ; Payment Required
+ * / "403" ; Forbidden
+ * / "404" ; Not Found
+ * / "405" ; Method Not Allowed
+ * / "406" ; Not Acceptable
+ * / "407" ; Proxy Authentication Required
+ * / "408" ; Request Timeout
+ * / "410" ; Gone
+ * / "413" ; Request Entity Too Large
+ * / "414" ; Request-URI Too Large
+ * / "415" ; Unsupported Media Type
+ * / "416" ; Unsupported URI Scheme
+ * / "420" ; Bad Extension
+ * / "421" ; Extension Required
+ * / "423" ; Interval Too Brief
+ * / "480" ; Temporarily not available
+ * / "481" ; Call Leg/Transaction Does Not Exist
+ * / "482" ; Loop Detected
+ * / "483" ; Too Many Hops
+ * / "484" ; Address Incomplete
+ * / "485" ; Ambiguous
+ * / "486" ; Busy Here
+ * / "487" ; Request Terminated
+ * / "488" ; Not Acceptable Here
+ * / "491" ; Request Pending
+ * / "493" ; Undecipherable
+ *
+ * Server-Error = "500" ; Internal Server Error
+ * / "501" ; Not Implemented
+ * / "502" ; Bad Gateway
+ * / "503" ; Service Unavailable
+ * / "504" ; Server Time-out
+ * / "505" ; SIP Version not supported
+ * / "513" ; Message Too Large
+ *
+ * Global-Failure = "600" ; Busy Everywhere
+ * / "603" ; Decline
+ * / "604" ; Does not exist anywhere
+ * / "606" ; Not Acceptable
+ *
+ * Accept = "Accept" HCOLON
+ * [ accept-range *(COMMA accept-range) ]
+ * accept-range = media-range *(SEMI accept-param)
+ * ; Why not SLASH ? //PPe
+ * media-range = ( "*" "/" "*"
+ * / ( m-type SLASH "*" )
+ * / ( m-type SLASH m-subtype )
+ * ) *( SEMI m-parameter )
+ * accept-param = ("q" EQUAL qvalue) / generic-param
+ * qvalue = ( "0" [ "." 0*3DIGIT ] )
+ * / ( "1" [ "." 0*3("0") ] )
+ * generic-param = token [ EQUAL gen-value ]
+ * gen-value = token / host / quoted-string
+ *
+ * Accept-Encoding = "Accept-Encoding" HCOLON
+ * [ encoding *(COMMA encoding) ]
+ * encoding = codings *(SEMI accept-param)
+ * codings = content-coding / "*"
+ * content-coding = token
+ *
+ * Accept-Language = "Accept-Language" HCOLON
+ * [ language *(COMMA language) ]
+ * language = language-range *(SEMI accept-param)
+ * language-range = ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) / "*" )
+ *
+ * Alert-Info = "Alert-Info" HCOLON alert-param *(COMMA alert-param)
+ * alert-param = LAQUOT absoluteURI RAQUOT *( SEMI generic-param )
+ *
+ * Allow = "Allow" HCOLON [Method *(COMMA Method)]
+ *
+ * Authorization = "Authorization" HCOLON credentials
+ * credentials = ("Digest" LWS digest-response)
+ * / other-response
+ * digest-response = dig-resp *(COMMA dig-resp)
+ * dig-resp = username / realm / nonce / digest-uri
+ * / dresponse / algorithm / cnonce
+ * / opaque / message-qop
+ * / nonce-count / auth-param
+ * username = "username" EQUAL username-value
+ * username-value = quoted-string
+ * digest-uri = "uri" EQUAL LDQUOT digest-uri-value RDQUOT
+ * digest-uri-value = rquest-uri ; Equal to request-uri as specified
+ * by HTTP/1.1
+ * message-qop = "qop" EQUAL qop-value
+ * cnonce = "cnonce" EQUAL cnonce-value
+ * cnonce-value = nonce-value
+ * nonce-count = "nc" EQUAL nc-value
+ * nc-value = 8LHEX
+ * dresponse = "response" EQUAL request-digest
+ * request-digest = LDQUOT 32LHEX RDQUOT
+ * auth-param = auth-param-name EQUAL
+ * ( token / quoted-string )
+ * auth-param-name = token
+ * other-response = auth-scheme LWS auth-param
+ * *(COMMA auth-param)
+ * auth-scheme = token
+ *
+ * Authentication-Info = "Authentication-Info" HCOLON ainfo
+ * *(COMMA ainfo)
+ * ainfo = nextnonce / message-qop
+ * / response-auth / cnonce
+ * / nonce-count
+ * nextnonce = "nextnonce" EQUAL nonce-value
+ * response-auth = "rspauth" EQUAL response-digest
+ * response-digest = LDQUOT *LHEX RDQUOT
+ *
+ * Call-ID = ( "Call-ID" / "i" ) HCOLON callid
+ * callid = word [ "@" word ]
+ *
+ * Call-Info = "Call-Info" HCOLON info *(COMMA info)
+ * info = LAQUOT absoluteURI RAQUOT *( SEMI info-param)
+ * info-param = ( "purpose" EQUAL ( "icon" / "info"
+ * / "card" / token ) ) / generic-param
+ *
+ * Contact = ("Contact" / "m" ) HCOLON
+ * ( STAR / (contact-param *(COMMA contact-param)))
+ * contact-param = (name-addr / addr-spec) *(SEMI contact-params)
+ * name-addr = [ display-name ] LAQUOT addr-spec RAQUOT
+ * addr-spec = SIP-URI / SIPS-URI / absoluteURI
+ * display-name = *(token LWS)/ quoted-string
+ *
+ * contact-params = c-p-q / c-p-expires
+ * / contact-extension
+ * c-p-q = "q" EQUAL qvalue
+ * c-p-expires = "expires" EQUAL delta-seconds
+ * contact-extension = generic-param
+ * delta-seconds = 1*DIGIT
+ *
+ * Content-Disposition = "Content-Disposition" HCOLON
+ * disp-type *( SEMI disp-param )
+ * disp-type = "render" / "session" / "icon" / "alert"
+ * / disp-extension-token
+ * disp-param = handling-param / generic-param
+ * handling-param = "handling" EQUAL
+ * ( "optional" / "required"
+ * / other-handling )
+ * other-handling = token
+ * disp-extension-token = token
+ *
+ * Content-Encoding = ( "Content-Encoding" / "e" ) HCOLON
+ * content-coding *(COMMA content-coding)
+ *
+ * Content-Language = "Content-Language" HCOLON
+ * language-tag *(COMMA language-tag)
+ * language-tag = primary-tag *( "-" subtag )
+ * primary-tag = 1*8ALPHA
+ * subtag = 1*8ALPHA
+ *
+ * Content-Length = ( "Content-Length" / "l" ) HCOLON 1*DIGIT
+ * Content-Type = ( "Content-Type" / "c" ) HCOLON media-type
+ * media-type = m-type SLASH m-subtype *(SEMI m-parameter)
+ * m-type = discrete-type / composite-type
+ * discrete-type = "text" / "image" / "audio" / "video"
+ * / "application" / extension-token
+ * composite-type = "message" / "multipart" / extension-token
+ * extension-token = ietf-token / x-token
+ * ietf-token = token
+ * x-token = "x-" token
+ * m-subtype = extension-token / iana-token
+ * iana-token = token
+ * m-parameter = m-attribute EQUAL m-value
+ * m-attribute = token
+ * m-value = token / quoted-string
+ *
+ * CSeq = "CSeq" HCOLON 1*DIGIT LWS Method
+ *
+ * Date = "Date" HCOLON SIP-date
+ * SIP-date = rfc1123-date
+ * rfc1123-date = wkday "," SP date1 SP time SP "GMT"
+ * date1 = 2DIGIT SP month SP 4DIGIT
+ * ; day month year (e.g., 02 Jun 1982)
+ * time = 2DIGIT ":" 2DIGIT ":" 2DIGIT
+ * ; 00:00:00 - 23:59:59
+ * wkday = "Mon" / "Tue" / "Wed"
+ * / "Thu" / "Fri" / "Sat" / "Sun"
+ * month = "Jan" / "Feb" / "Mar" / "Apr"
+ * / "May" / "Jun" / "Jul" / "Aug"
+ * / "Sep" / "Oct" / "Nov" / "Dec"
+ *
+ * Error-Info = "Error-Info" HCOLON error-uri *(COMMA error-uri)
+ * error-uri = LAQUOT absoluteURI RAQUOT *( SEMI generic-param )
+ *
+ * Expires = "Expires" HCOLON delta-seconds
+ * From = ( "From" / "f" ) HCOLON from-spec
+ * from-spec = ( name-addr / addr-spec )
+ * *( SEMI from-param )
+ * from-param = tag-param / generic-param
+ * tag-param = "tag" EQUAL token
+ *
+ * In-Reply-To = "In-Reply-To" HCOLON callid *(COMMA callid)
+ *
+ * Max-Forwards = "Max-Forwards" HCOLON 1*DIGIT
+ *
+ * MIME-Version = "MIME-Version" HCOLON 1*DIGIT "." 1*DIGIT
+ *
+ * Min-Expires = "Min-Expires" HCOLON delta-seconds
+ *
+ * Organization = "Organization" HCOLON [TEXT-UTF8-TRIM]
+ *
+ * Priority = "Priority" HCOLON priority-value
+ * priority-value = "emergency" / "urgent" / "normal"
+ * / "non-urgent" / other-priority
+ * other-priority = token
+ *
+ * Proxy-Authenticate = "Proxy-Authenticate" HCOLON challenge
+ * challenge = ("Digest" LWS digest-cln *(COMMA digest-cln))
+ * / other-challenge
+ * other-challenge = auth-scheme LWS auth-param
+ * *(COMMA auth-param)
+ * digest-cln = realm / domain / nonce
+ * / opaque / stale / algorithm
+ * / qop-options / auth-param
+ * realm = "realm" EQUAL realm-value
+ * realm-value = quoted-string
+ * domain = "domain" EQUAL LDQUOT URI
+ * *( 1*SP URI ) RDQUOT
+ * URI = absoluteURI / abs-path
+ * nonce = "nonce" EQUAL nonce-value
+ * nonce-value = quoted-string
+ * opaque = "opaque" EQUAL quoted-string
+ * stale = "stale" EQUAL ( "true" / "false" )
+ * algorithm = "algorithm" EQUAL ( "MD5" / "MD5-sess"
+ * / token )
+ * qop-options = "qop" EQUAL LDQUOT qop-value
+ * *("," qop-value) RDQUOT
+ * qop-value = "auth" / "auth-int" / token
+ *
+ * Proxy-Authorization = "Proxy-Authorization" HCOLON credentials
+ *
+ * Proxy-Require = "Proxy-Require" HCOLON option-tag
+ * *(COMMA option-tag)
+ * option-tag = token
+ *
+ * Record-Route = "Record-Route" HCOLON rec-route *(COMMA rec-route)
+ * rec-route = name-addr *( SEMI rr-param )
+ * rr-param = generic-param
+ *
+ * Reply-To = "Reply-To" HCOLON rplyto-spec
+ * rplyto-spec = ( name-addr / addr-spec )
+ * *( SEMI rplyto-param )
+ * rplyto-param = generic-param
+ * Require = "Require" HCOLON option-tag *(COMMA option-tag)
+ *
+ * Retry-After = "Retry-After" HCOLON delta-seconds
+ * [ comment ] *( SEMI retry-param )
+ *
+ * retry-param = ("duration" EQUAL delta-seconds)
+ * / generic-param
+ *
+ * Route = "Route" HCOLON route-param *(COMMA route-param)
+ * route-param = name-addr *( SEMI rr-param )
+ *
+ * Server = "Server" HCOLON server-val *(LWS server-val)
+ * server-val = product / comment
+ * product = token [SLASH product-version]
+ * product-version = token
+ *
+ * Subject = ( "Subject" / "s" ) HCOLON [TEXT-UTF8-TRIM]
+ *
+ * Supported = ( "Supported" / "k" ) HCOLON
+ * [option-tag *(COMMA option-tag)]
+ *
+ * Timestamp = "Timestamp" HCOLON 1*(DIGIT)
+ * [ "." *(DIGIT) ] [ LWS delay ]
+ * delay = *(DIGIT) [ "." *(DIGIT) ]
+ *
+ * To = ( "To" / "t" ) HCOLON ( name-addr
+ * / addr-spec ) *( SEMI to-param )
+ * to-param = tag-param / generic-param
+ *
+ * Unsupported = "Unsupported" HCOLON option-tag *(COMMA option-tag)
+ * User-Agent = "User-Agent" HCOLON server-val *(LWS server-val)
+ *
+ * Via = ( "Via" / "v" ) HCOLON via-parm *(COMMA via-parm)
+ * via-parm = sent-protocol LWS sent-by *( SEMI via-params )
+ * via-params = via-ttl / via-maddr
+ * / via-received / via-branch
+ * / via-extension
+ * via-ttl = "ttl" EQUAL ttl
+ * via-maddr = "maddr" EQUAL host
+ * via-received = "received" EQUAL (IPv4address / IPv6address)
+ * via-branch = "branch" EQUAL token
+ * via-extension = generic-param
+ * sent-protocol = protocol-name SLASH protocol-version
+ * SLASH transport
+ * protocol-name = "SIP" / token
+ * protocol-version = token
+ * transport = "UDP" / "TCP" / "TLS" / "SCTP"
+ * / other-transport
+ * sent-by = host [ COLON port ]
+ * ttl = 1*3DIGIT ; 0 to 255
+ *
+ * Warning = "Warning" HCOLON warning-value *(COMMA warning-value)
+ * warning-value = warn-code SP warn-agent SP warn-text
+ * warn-code = 3DIGIT
+ * warn-agent = hostport / pseudonym
+ * ; the name or pseudonym of the server adding
+ * ; the Warning header, for use in debugging
+ * warn-text = quoted-string
+ * pseudonym = token
+ *
+ * WWW-Authenticate = "WWW-Authenticate" HCOLON challenge
+ *
+ * extension-header = header-name HCOLON header-value
+ * header-name = token
+ * header-value = *(TEXT-UTF8char / UTF8-CONT / LWS)
+ * message-body = *OCTET
+ */
\ No newline at end of file
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/Makefile.am Thu Dec 21 01:30:28 2006
@@ -0,0 +1,154 @@
+#
+# Makefile.am for sip module
+#
+
+# ----------------------------------------------------------------------
+# Header paths
+
+INCLUDES = -I$(srcdir)/../bnf -I../bnf \
+ -I$(srcdir)/../ipt -I../ipt \
+ -I$(srcdir)/../msg -I../msg \
+ -I$(srcdir)/../url -I../url \
+ -I$(srcdir)/../su -I../su
+
+# ----------------------------------------------------------------------
+# Build targets
+
+noinst_LTLIBRARIES = libsip.la
+
+check_PROGRAMS = torture_sip \
+ sip_test_msg validator date_test
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+
+GENERATED_H = sofia-sip/sip_hclasses.h \
+ sofia-sip/sip_protos.h sofia-sip/sip_tag.h \
+ sofia-sip/sip_extra.h
+H_IN = sofia-sip/sip_hclasses.h.in \
+ sofia-sip/sip_protos.h.in sofia-sip/sip_tag.h.in \
+ sofia-sip/sip_extra.h.in
+
+PUBLIC_H = sofia-sip/sip.h sofia-sip/sip_util.h \
+ sofia-sip/sip_header.h sofia-sip/sip_parser.h \
+ sofia-sip/sip_tag_class.h sofia-sip/sip_status.h
+
+GENERATED_C = sip_tag.c sip_tag_ref.c sip_parser_table.c
+
+BUILT_SOURCES = $(GENERATED_H) $(GENERATED_C)
+
+nobase_include_sofia_HEADERS = $(GENERATED_H) $(PUBLIC_H) $(H_IN)
+
+libsip_la_SOURCES = $(INTERNAL_H) \
+ sip_parser.c sip_header.c sip_util.c sip_pref_util.c \
+ sip_basic.c sip_extra.c sip_feature.c sip_mime.c \
+ sip_security.c sip_event.c sip_prack.c \
+ sip_refer.c sip_session.c \
+ sip_caller_prefs.c sip_reason.c \
+ sip_status.c sip_time.c \
+ sip_tag_class.c \
+ $(GENERATED_C)
+
+COVERAGE_INPUT = $(libsip_la_SOURCES) $(include_sofia_HEADERS)
+
+LDADD = libsip.la \
+ ../msg/libmsg.la \
+ ../bnf/libbnf.la \
+ ../url/liburl.la \
+ ../su/libsu.la
+
+torture_sip_LDFLAGS = -static
+sip_test_msg_LDFLAGS = -static
+date_test_LDFLAGS = -static
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+
+# note: srcdir needs to be specified, otherwise
+# breaks make distcheck target
+
+EXTRA_DIST = Doxyfile sip.docs sip_parser.docs sip.doxyaliases \
+ ADD-A-HEADER GRAMMAR sip_bad_mask \
+ sip_parser_table.c.in sip_tag.c.in \
+ sip_extra_headers.txt \
+ images/sip-parser.eps images/sip-parser.gif \
+ images/sip-parser2.eps images/sip-parser2.gif \
+ images/sip-parser3.eps images/sip-parser3.gif \
+ images/sip-parser4.eps images/sip-parser4.gif \
+ tests/own0.txt tests/own1.txt tests/own2.txt tests/own3.txt \
+ tests/own4.txt tests/own5.txt tests/own6.txt tests/own8.txt \
+ tests/test1.txt tests/test-ack-1.txt tests/test2.txt tests/test3.txt \
+ tests/test4.txt tests/test5.txt tests/test6.txt tests/test7.txt \
+ tests/test8.txt tests/test9.txt tests/test10.txt tests/test10b.txt \
+ tests/test10c.txt tests/test11.txt tests/test12.txt tests/test13.txt \
+ tests/test14-req.txt tests/test14.txt tests/test15.txt \
+ tests/test16.txt tests/test17.txt tests/test18.txt tests/test19.txt \
+ tests/test1a.txt tests/test20.txt tests/test21.txt tests/test22.txt \
+ tests/test23.txt tests/test24.txt tests/test25.txt tests/test26.txt \
+ tests/test27.txt tests/test28.txt tests/test29.txt tests/test30.txt \
+ tests/test31.txt tests/test32.txt tests/test33.txt tests/test34.txt \
+ tests/test35.txt tests/test36.txt tests/test37.txt tests/test38.txt \
+ tests/test39.txt tests/test40.txt tests/test41.txt tests/test42.txt
+
+# ----------------------------------------------------------------------
+# Tests
+
+TESTS = torture_sip run_sip_test_msg run_date_test
+
+dist_noinst_SCRIPTS = run_sip_test_msg run_date_test
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+
+include ../sofia.am
+
+MSG_PARSER_AWK = $(srcdir)/../msg/msg_parser.awk
+
+AWK_SIP_AWK = $(AWK) -f $(MSG_PARSER_AWK) module=sip
+
+#
+# Note: sip_bad_mask is used by nta to weed out bad messages
+#
+sip_parser_table.c: sip_bad_mask
+
+sofia-sip/sip_hclasses.h: sofia-sip/sip_hclasses.h.in
+sofia-sip/sip_protos.h: sofia-sip/sip_protos.h.in
+sofia-sip/sip_tag.h: sofia-sip/sip_tag.h.in
+
+$(GENERATED_H): $(MSG_PARSER_AWK)
+
+sip_parser_table.c: sip_parser_table.c.in $(MSG_PARSER_AWK)
+sip_tag.c: sip_tag.c.in $(MSG_PARSER_AWK)
+
+EXTRA = $(srcdir)/sip_extra_headers.txt
+
+sofia-sip/sip_hclasses.h: sofia-sip/sip.h
+ @-mkdir sofia-sip 2>/dev/null || true
+ $(AWK_SIP_AWK) PR=$@ TEMPLATE=$(srcdir)/sofia-sip/sip_hclasses.h.in $<
+
+sofia-sip/sip_protos.h: sofia-sip/sip.h
+ @-mkdir sofia-sip 2>/dev/null || true
+ $(AWK_SIP_AWK) PR=$@ TEMPLATE=$(srcdir)/sofia-sip/sip_protos.h.in $<
+
+sofia-sip/sip_tag.h: sofia-sip/sip.h
+ @-mkdir sofia-sip 2>/dev/null || true
+ $(AWK_SIP_AWK) PR=$@ TEMPLATE=$(srcdir)/sofia-sip/sip_tag.h.in $<
+
+sip_tag.c: sofia-sip/sip.h sip_extra_headers.txt
+ $(AWK_SIP_AWK) PR=$@ TEMPLATE=$(srcdir)/sip_tag.c.in $< $(EXTRA)
+
+sip_parser_table.c: sip_extra_headers.txt
+
+sip_parser_table.c: sofia-sip/sip.h
+ $(AWK_SIP_AWK) PT=$@ TEMPLATE=$(srcdir)/sip_parser_table.c.in \
+ FLAGFILE=$(srcdir)/sip_bad_mask \
+ MC_HASH_SIZE=127 MC_SHORT_SIZE=26 $< $(EXTRA)
+
+sofia-sip/sip_extra.h: sofia-sip/sip_extra.h.in sip_extra_headers.txt
+ @-mkdir -p sofia-sip 2>/dev/null
+ ${AWK_SIP_AWK} PR=$@ NO_FIRST=1 NO_LAST=1 \
+ PACKAGE_NAME="${PACKAGE_NAME}" \
+ PACKAGE_VERSION="${PACKAGE_VERSION}" \
+ TEMPLATE1=${srcdir}/sofia-sip/sip_hclasses.h.in \
+ TEMPLATE2=${srcdir}/sofia-sip/sip_protos.h.in \
+ TEMPLATE=$< $(EXTRA)
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/Makefile.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1,854 @@
+# 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.
+
+ at SET_MAKE@
+
+#
+# Makefile.am for sip module
+#
+
+# ----------------------------------------------------------------------
+# Header paths
+
+# common Makefile targets for libsofia-sip-ua modules
+# ---------------------------------------------------
+
+
+
+SOURCES = $(libsip_la_SOURCES) date_test.c test_sip_msg.c torture_sip.c validator.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 = torture_sip$(EXEEXT) test_sip_msg$(EXEEXT) \
+ validator$(EXEEXT) date_test$(EXEEXT)
+DIST_COMMON = $(dist_noinst_SCRIPTS) $(nobase_include_sofia_HEADERS) \
+ $(srcdir)/../sofia.am $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in ChangeLog
+subdir = libsofia-sip-ua/sip
+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 =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libsip_la_LIBADD =
+am__objects_1 = sip_tag.lo sip_tag_ref.lo sip_parser_table.lo
+am_libsip_la_OBJECTS = sip_parser.lo sip_header.lo sip_util.lo \
+ sip_pref_util.lo sip_basic.lo sip_extra.lo sip_feature.lo \
+ sip_mime.lo sip_security.lo sip_event.lo sip_prack.lo \
+ sip_refer.lo sip_session.lo sip_caller_prefs.lo sip_reason.lo \
+ sip_status.lo sip_time.lo sip_tag_class.lo $(am__objects_1)
+libsip_la_OBJECTS = $(am_libsip_la_OBJECTS)
+date_test_SOURCES = date_test.c
+date_test_OBJECTS = date_test.$(OBJEXT)
+date_test_LDADD = $(LDADD)
+date_test_DEPENDENCIES = libsip.la ../msg/libmsg.la ../bnf/libbnf.la \
+ ../url/liburl.la ../su/libsu.la
+test_sip_msg_SOURCES = test_sip_msg.c
+test_sip_msg_OBJECTS = test_sip_msg.$(OBJEXT)
+test_sip_msg_LDADD = $(LDADD)
+test_sip_msg_DEPENDENCIES = libsip.la ../msg/libmsg.la \
+ ../bnf/libbnf.la ../url/liburl.la ../su/libsu.la
+torture_sip_SOURCES = torture_sip.c
+torture_sip_OBJECTS = torture_sip.$(OBJEXT)
+torture_sip_LDADD = $(LDADD)
+torture_sip_DEPENDENCIES = libsip.la ../msg/libmsg.la ../bnf/libbnf.la \
+ ../url/liburl.la ../su/libsu.la
+validator_SOURCES = validator.c
+validator_OBJECTS = validator.$(OBJEXT)
+validator_LDADD = $(LDADD)
+validator_DEPENDENCIES = libsip.la ../msg/libmsg.la ../bnf/libbnf.la \
+ ../url/liburl.la ../su/libsu.la
+SCRIPTS = $(dist_noinst_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 = $(libsip_la_SOURCES) date_test.c test_sip_msg.c \
+ torture_sip.c validator.c
+DIST_SOURCES = $(libsip_la_SOURCES) date_test.c test_sip_msg.c \
+ torture_sip.c validator.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|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(include_sofiadir)"
+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)/../bnf -I../bnf \
+ -I$(srcdir)/../ipt -I../ipt \
+ -I$(srcdir)/../msg -I../msg \
+ -I$(srcdir)/../url -I../url \
+ -I$(srcdir)/../su -I../su
+
+
+# ----------------------------------------------------------------------
+# Build targets
+noinst_LTLIBRARIES = libsip.la
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+GENERATED_H = sofia-sip/sip_hclasses.h \
+ sofia-sip/sip_protos.h sofia-sip/sip_tag.h \
+ sofia-sip/sip_extra.h
+
+H_IN = sofia-sip/sip_hclasses.h.in \
+ sofia-sip/sip_protos.h.in sofia-sip/sip_tag.h.in \
+ sofia-sip/sip_extra.h.in
+
+PUBLIC_H = sofia-sip/sip.h sofia-sip/sip_util.h \
+ sofia-sip/sip_header.h sofia-sip/sip_parser.h \
+ sofia-sip/sip_tag_class.h sofia-sip/sip_status.h
+
+GENERATED_C = sip_tag.c sip_tag_ref.c sip_parser_table.c
+BUILT_SOURCES = $(GENERATED_H) $(GENERATED_C)
+nobase_include_sofia_HEADERS = $(GENERATED_H) $(PUBLIC_H) $(H_IN)
+libsip_la_SOURCES = $(INTERNAL_H) \
+ sip_parser.c sip_header.c sip_util.c sip_pref_util.c \
+ sip_basic.c sip_extra.c sip_feature.c sip_mime.c \
+ sip_security.c sip_event.c sip_prack.c \
+ sip_refer.c sip_session.c \
+ sip_caller_prefs.c sip_reason.c \
+ sip_status.c sip_time.c \
+ sip_tag_class.c \
+ $(GENERATED_C)
+
+COVERAGE_INPUT = $(libsip_la_SOURCES) $(include_sofia_HEADERS)
+LDADD = libsip.la \
+ ../msg/libmsg.la \
+ ../bnf/libbnf.la \
+ ../url/liburl.la \
+ ../su/libsu.la
+
+torture_sip_LDFLAGS = -static
+sip_test_msg_LDFLAGS = -static
+date_test_LDFLAGS = -static
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+
+# note: srcdir needs to be specified, otherwise
+# breaks make distcheck target
+EXTRA_DIST = Doxyfile sip.docs sip_parser.docs sip.doxyaliases \
+ ADD-A-HEADER GRAMMAR sip_bad_mask \
+ sip_parser_table.c.in sip_tag.c.in \
+ sip_extra_headers.txt \
+ images/sip-parser.eps images/sip-parser.gif \
+ images/sip-parser2.eps images/sip-parser2.gif \
+ images/sip-parser3.eps images/sip-parser3.gif \
+ images/sip-parser4.eps images/sip-parser4.gif \
+ tests/own0.txt tests/own1.txt tests/own2.txt tests/own3.txt \
+ tests/own4.txt tests/own5.txt tests/own6.txt tests/own8.txt \
+ tests/test1.txt tests/test-ack-1.txt tests/test2.txt tests/test3.txt \
+ tests/test4.txt tests/test5.txt tests/test6.txt tests/test7.txt \
+ tests/test8.txt tests/test9.txt tests/test10.txt tests/test10b.txt \
+ tests/test10c.txt tests/test11.txt tests/test12.txt tests/test13.txt \
+ tests/test14-req.txt tests/test14.txt tests/test15.txt \
+ tests/test16.txt tests/test17.txt tests/test18.txt tests/test19.txt \
+ tests/test1a.txt tests/test20.txt tests/test21.txt tests/test22.txt \
+ tests/test23.txt tests/test24.txt tests/test25.txt tests/test26.txt \
+ tests/test27.txt tests/test28.txt tests/test29.txt tests/test30.txt \
+ tests/test31.txt tests/test32.txt tests/test33.txt tests/test34.txt \
+ tests/test35.txt tests/test36.txt tests/test37.txt tests/test38.txt \
+ tests/test39.txt tests/test40.txt tests/test41.txt tests/test42.txt
+
+
+# ----------------------------------------------------------------------
+# Tests
+TESTS = torture_sip run_sip_test_msg run_date_test
+dist_noinst_SCRIPTS = run_sip_test_msg run_date_test
+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/msg_parser.awk
+AWK_SIP_AWK = $(AWK) -f $(MSG_PARSER_AWK) module=sip
+EXTRA = $(srcdir)/sip_extra_headers.txt
+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/sip/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu libsofia-sip-ua/sip/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-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
+libsip.la: $(libsip_la_OBJECTS) $(libsip_la_DEPENDENCIES)
+ $(LINK) $(libsip_la_LDFLAGS) $(libsip_la_OBJECTS) $(libsip_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
+date_test$(EXEEXT): $(date_test_OBJECTS) $(date_test_DEPENDENCIES)
+ @rm -f date_test$(EXEEXT)
+ $(LINK) $(date_test_LDFLAGS) $(date_test_OBJECTS) $(date_test_LDADD) $(LIBS)
+test_sip_msg$(EXEEXT): $(test_sip_msg_OBJECTS) $(test_sip_msg_DEPENDENCIES)
+ @rm -f test_sip_msg$(EXEEXT)
+ $(LINK) $(test_sip_msg_LDFLAGS) $(test_sip_msg_OBJECTS) $(test_sip_msg_LDADD) $(LIBS)
+torture_sip$(EXEEXT): $(torture_sip_OBJECTS) $(torture_sip_DEPENDENCIES)
+ @rm -f torture_sip$(EXEEXT)
+ $(LINK) $(torture_sip_LDFLAGS) $(torture_sip_OBJECTS) $(torture_sip_LDADD) $(LIBS)
+validator$(EXEEXT): $(validator_OBJECTS) $(validator_DEPENDENCIES)
+ @rm -f validator$(EXEEXT)
+ $(LINK) $(validator_LDFLAGS) $(validator_OBJECTS) $(validator_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/date_test.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip_basic.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip_caller_prefs.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip_event.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip_extra.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip_feature.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip_header.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip_mime.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip_parser.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip_parser_table.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip_prack.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip_pref_util.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip_reason.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip_refer.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip_security.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip_session.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip_status.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip_tag.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip_tag_class.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip_tag_ref.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip_time.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip_util.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_sip_msg.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/torture_sip.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/validator.Po at am__quote@
+
+.c.o:
+ at am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+ at am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ at am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at 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)/images $(distdir)/sofia-sip $(distdir)/tests
+ @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 $(LTLIBRARIES) $(SCRIPTS) $(HEADERS)
+installdirs:
+ for dir in "$(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-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-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-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-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-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-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) $<
+
+ at ENABLE_COVERAGE_TRUE@coverage:
+ at 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)
+
+#
+# Note: sip_bad_mask is used by nta to weed out bad messages
+#
+sip_parser_table.c: sip_bad_mask
+
+sofia-sip/sip_hclasses.h: sofia-sip/sip_hclasses.h.in
+sofia-sip/sip_protos.h: sofia-sip/sip_protos.h.in
+sofia-sip/sip_tag.h: sofia-sip/sip_tag.h.in
+
+$(GENERATED_H): $(MSG_PARSER_AWK)
+
+sip_parser_table.c: sip_parser_table.c.in $(MSG_PARSER_AWK)
+sip_tag.c: sip_tag.c.in $(MSG_PARSER_AWK)
+
+sofia-sip/sip_hclasses.h: sofia-sip/sip.h
+ @-mkdir sofia-sip 2>/dev/null || true
+ $(AWK_SIP_AWK) PR=$@ TEMPLATE=$(srcdir)/sofia-sip/sip_hclasses.h.in $<
+
+sofia-sip/sip_protos.h: sofia-sip/sip.h
+ @-mkdir sofia-sip 2>/dev/null || true
+ $(AWK_SIP_AWK) PR=$@ TEMPLATE=$(srcdir)/sofia-sip/sip_protos.h.in $<
+
+sofia-sip/sip_tag.h: sofia-sip/sip.h
+ @-mkdir sofia-sip 2>/dev/null || true
+ $(AWK_SIP_AWK) PR=$@ TEMPLATE=$(srcdir)/sofia-sip/sip_tag.h.in $<
+
+sip_tag.c: sofia-sip/sip.h sip_extra_headers.txt
+ $(AWK_SIP_AWK) PR=$@ TEMPLATE=$(srcdir)/sip_tag.c.in $< $(EXTRA)
+
+sip_parser_table.c: sip_extra_headers.txt
+
+sip_parser_table.c: sofia-sip/sip.h
+ $(AWK_SIP_AWK) PT=$@ TEMPLATE=$(srcdir)/sip_parser_table.c.in \
+ FLAGFILE=$(srcdir)/sip_bad_mask \
+ MC_HASH_SIZE=127 MC_SHORT_SIZE=26 $< $(EXTRA)
+
+sofia-sip/sip_extra.h: sofia-sip/sip_extra.h.in sip_extra_headers.txt
+ @-mkdir -p sofia-sip 2>/dev/null
+ ${AWK_SIP_AWK} PR=$@ NO_FIRST=1 NO_LAST=1 \
+ PACKAGE_NAME="${PACKAGE_NAME}" \
+ PACKAGE_VERSION="${PACKAGE_VERSION}" \
+ TEMPLATE1=${srcdir}/sofia-sip/sip_hclasses.h.in \
+ TEMPLATE2=${srcdir}/sofia-sip/sip_protos.h.in \
+ TEMPLATE=$< $(EXTRA)
+# 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:
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/date_test.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/date_test.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,116 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@internal
+ *
+ * @CFILE date_test.c
+ *
+ * Tester for SIP date parser
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Wed Mar 21 19:12:13 2001 ppessi
+ */
+
+#include <stdio.h>
+#include <sofia-sip/string0.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#include <sofia-sip/sip.h>
+#include <sofia-sip/sip_header.h>
+#include <sofia-sip/msg_date.h>
+
+void usage(void)
+{
+ fprintf(stderr,
+ "usage: date_test [SIP-date] "
+ "[YYYYy][DDd][HHh][MMm][SS[s]]\n");
+ exit(1);
+}
+
+int main(int ac, char *av[])
+{
+ int i;
+ sip_time_t t, delta, t2;
+ char const *s;
+ int verbatim = 0, retval = 0;
+
+ t = ((31 + 27) * 24) * 60 * 60;
+ delta = (365 * 24 + 6) * 60 * 60;
+
+ if (str0cmp(av[1], "-v") == 0)
+ verbatim = 1, av++;
+
+ if ((s = av[1])) {
+ if (msg_date_d(&s, &t) < 0) {
+ fprintf(stderr, "date_test: %s is not valid time\n", s);
+ exit(1);
+ }
+
+ if ((s = av[2])) {
+ for (delta = 0; *s; ) {
+ t2 = 0;
+ msg_delta_d(&s, &t2);
+
+ switch (*s++) {
+ case 'y': delta += t2 * (365 * 24 + 6) * 60 * 60; break;
+ case 'd': delta += t2 * 24 * 60 * 60; break;
+ case 'h': delta += t2 * 60 * 60; break;
+ case 'm': delta += t2 * 60; break;
+ case '\0': --s; /* FALLTHROUGH */
+ case 's': delta += t2; break;
+ default:
+ fprintf(stderr, "date_test: %s is not valid time offset\n" , av[2]);
+ usage();
+ break;
+ }
+ }
+ }
+ }
+
+ for (i = 0; i < 20; i++) {
+ char buf[80];
+
+ msg_date_e(buf, sizeof(buf), t);
+
+ if (verbatim)
+ printf("%08lx is %s\n", t, buf);
+
+ s = buf, t2 = 0;
+ if (msg_date_d(&s, &t2) < 0) {
+ fprintf(stderr, "date_test: decoding %s failed\n", buf);
+ retval = 1;
+ break;
+ }
+ else if (t2 != t) {
+ fprintf(stderr, "date_test: %lu != %lu\n", t, t2);
+ retval = 1;
+ break;
+ }
+ t += delta;
+ }
+
+ return retval;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser.eps
==============================================================================
Binary file. No diff available.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser.gif
==============================================================================
Binary file. No diff available.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser2.eps
==============================================================================
Binary file. No diff available.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser2.gif
==============================================================================
Binary file. No diff available.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser3.eps
==============================================================================
Binary file. No diff available.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser3.gif
==============================================================================
Binary file. No diff available.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser4.eps
==============================================================================
Binary file. No diff available.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser4.gif
==============================================================================
Binary file. No diff available.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/rfc2543.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/rfc2543.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,8564 @@
+
+
+
+
+
+
+Network Working Group M. Handley
+Request for Comments: 2543 ACIRI
+Category: Standards Track H. Schulzrinne
+ Columbia U.
+ E. Schooler
+ Cal Tech
+ J. Rosenberg
+ Bell Labs
+ March 1999
+
+ SIP: Session Initiation Protocol
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+IESG Note
+
+ The IESG intends to charter, in the near future, one or more working
+ groups to produce standards for "name lookup", where such names would
+ include electronic mail addresses and telephone numbers, and the
+ result of such a lookup would be a list of attributes and
+ characteristics of the user or terminal associated with the name.
+ Groups which are in need of a "name lookup" protocol should follow
+ the development of these new working groups rather than using SIP for
+ this function. In addition it is anticipated that SIP will migrate
+ towards using such protocols, and SIP implementors are advised to
+ monitor these efforts.
+
+Abstract
+
+ The Session Initiation Protocol (SIP) is an application-layer control
+ (signaling) protocol for creating, modifying and terminating sessions
+ with one or more participants. These sessions include Internet
+ multimedia conferences, Internet telephone calls and multimedia
+ distribution. Members in a session can communicate via multicast or
+ via a mesh of unicast relations, or a combination of these.
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 1]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ SIP invitations used to create sessions carry session descriptions
+ which allow participants to agree on a set of compatible media types.
+ SIP supports user mobility by proxying and redirecting requests to
+ the user's current location. Users can register their current
+ location. SIP is not tied to any particular conference control
+ protocol. SIP is designed to be independent of the lower-layer
+ transport protocol and can be extended with additional capabilities.
+
+Table of Contents
+
+ 1 Introduction ........................................ 7
+ 1.1 Overview of SIP Functionality ....................... 7
+ 1.2 Terminology ......................................... 8
+ 1.3 Definitions ......................................... 9
+ 1.4 Overview of SIP Operation ........................... 12
+ 1.4.1 SIP Addressing ...................................... 12
+ 1.4.2 Locating a SIP Server ............................... 13
+ 1.4.3 SIP Transaction ..................................... 14
+ 1.4.4 SIP Invitation ...................................... 15
+ 1.4.5 Locating a User ..................................... 17
+ 1.4.6 Changing an Existing Session ........................ 18
+ 1.4.7 Registration Services ............................... 18
+ 1.5 Protocol Properties ................................. 18
+ 1.5.1 Minimal State ....................................... 18
+ 1.5.2 Lower-Layer-Protocol Neutral ........................ 18
+ 1.5.3 Text-Based .......................................... 20
+ 2 SIP Uniform Resource Locators ....................... 20
+ 3 SIP Message Overview ................................ 24
+ 4 Request ............................................. 26
+ 4.1 Request-Line ........................................ 26
+ 4.2 Methods ............................................. 27
+ 4.2.1 INVITE .............................................. 28
+ 4.2.2 ACK ................................................. 29
+ 4.2.3 OPTIONS ............................................. 29
+ 4.2.4 BYE ................................................. 30
+ 4.2.5 CANCEL .............................................. 30
+ 4.2.6 REGISTER ............................................ 31
+ 4.3 Request-URI ......................................... 34
+ 4.3.1 SIP Version ......................................... 35
+ 4.4 Option Tags ......................................... 35
+ 4.4.1 Registering New Option Tags with IANA ............... 35
+ 5 Response ............................................ 36
+ 5.1 Status-Line ......................................... 36
+ 5.1.1 Status Codes and Reason Phrases ..................... 37
+ 6 Header Field Definitions ............................ 39
+ 6.1 General Header Fields ............................... 41
+ 6.2 Entity Header Fields ................................ 42
+ 6.3 Request Header Fields ............................... 43
+
+
+
+Handley, et al. Standards Track [Page 2]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ 6.4 Response Header Fields .............................. 43
+ 6.5 End-to-end and Hop-by-hop Headers ................... 43
+ 6.6 Header Field Format ................................. 43
+ 6.7 Accept .............................................. 44
+ 6.8 Accept-Encoding ..................................... 44
+ 6.9 Accept-Language ..................................... 45
+ 6.10 Allow ............................................... 45
+ 6.11 Authorization ....................................... 45
+ 6.12 Call-ID ............................................. 46
+ 6.13 Contact ............................................. 47
+ 6.14 Content-Encoding .................................... 50
+ 6.15 Content-Length ...................................... 51
+ 6.16 Content-Type ........................................ 51
+ 6.17 CSeq ................................................ 52
+ 6.18 Date ................................................ 53
+ 6.19 Encryption .......................................... 54
+ 6.20 Expires ............................................. 55
+ 6.21 From ................................................ 56
+ 6.22 Hide ................................................ 57
+ 6.23 Max-Forwards ........................................ 59
+ 6.24 Organization ........................................ 59
+ 6.25 Priority ............................................ 60
+ 6.26 Proxy-Authenticate .................................. 60
+ 6.27 Proxy-Authorization ................................. 61
+ 6.28 Proxy-Require ....................................... 61
+ 6.29 Record-Route ........................................ 62
+ 6.30 Require ............................................. 63
+ 6.31 Response-Key ........................................ 63
+ 6.32 Retry-After ......................................... 64
+ 6.33 Route ............................................... 65
+ 6.34 Server .............................................. 65
+ 6.35 Subject ............................................. 65
+ 6.36 Timestamp ........................................... 66
+ 6.37 To .................................................. 66
+ 6.38 Unsupported ......................................... 68
+ 6.39 User-Agent .......................................... 68
+ 6.40 Via ................................................. 68
+ 6.40.1 Requests ............................................ 68
+ 6.40.2 Receiver-tagged Via Header Fields ................... 69
+ 6.40.3 Responses ........................................... 70
+ 6.40.4 User Agent and Redirect Servers ..................... 70
+ 6.40.5 Syntax .............................................. 71
+ 6.41 Warning ............................................. 72
+ 6.42 WWW-Authenticate .................................... 74
+ 7 Status Code Definitions ............................. 75
+ 7.1 Informational 1xx ................................... 75
+ 7.1.1 100 Trying .......................................... 75
+ 7.1.2 180 Ringing ......................................... 75
+
+
+
+Handley, et al. Standards Track [Page 3]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ 7.1.3 181 Call Is Being Forwarded ......................... 75
+ 7.1.4 182 Queued .......................................... 76
+ 7.2 Successful 2xx ...................................... 76
+ 7.2.1 200 OK .............................................. 76
+ 7.3 Redirection 3xx ..................................... 76
+ 7.3.1 300 Multiple Choices ................................ 77
+ 7.3.2 301 Moved Permanently ............................... 77
+ 7.3.3 302 Moved Temporarily ............................... 77
+ 7.3.4 305 Use Proxy ....................................... 77
+ 7.3.5 380 Alternative Service ............................. 78
+ 7.4 Request Failure 4xx ................................. 78
+ 7.4.1 400 Bad Request ..................................... 78
+ 7.4.2 401 Unauthorized .................................... 78
+ 7.4.3 402 Payment Required ................................ 78
+ 7.4.4 403 Forbidden ....................................... 78
+ 7.4.5 404 Not Found ....................................... 78
+ 7.4.6 405 Method Not Allowed .............................. 78
+ 7.4.7 406 Not Acceptable .................................. 79
+ 7.4.8 407 Proxy Authentication Required ................... 79
+ 7.4.9 408 Request Timeout ................................. 79
+ 7.4.10 409 Conflict ........................................ 79
+ 7.4.11 410 Gone ............................................ 79
+ 7.4.12 411 Length Required ................................. 79
+ 7.4.13 413 Request Entity Too Large ........................ 80
+ 7.4.14 414 Request-URI Too Long ............................ 80
+ 7.4.15 415 Unsupported Media Type .......................... 80
+ 7.4.16 420 Bad Extension ................................... 80
+ 7.4.17 480 Temporarily Unavailable ......................... 80
+ 7.4.18 481 Call Leg/Transaction Does Not Exist ............. 81
+ 7.4.19 482 Loop Detected ................................... 81
+ 7.4.20 483 Too Many Hops ................................... 81
+ 7.4.21 484 Address Incomplete .............................. 81
+ 7.4.22 485 Ambiguous ....................................... 81
+ 7.4.23 486 Busy Here ....................................... 82
+ 7.5 Server Failure 5xx .................................. 82
+ 7.5.1 500 Server Internal Error ........................... 82
+ 7.5.2 501 Not Implemented ................................. 82
+ 7.5.3 502 Bad Gateway ..................................... 82
+ 7.5.4 503 Service Unavailable ............................. 83
+ 7.5.5 504 Gateway Time-out ................................ 83
+ 7.5.6 505 Version Not Supported ........................... 83
+ 7.6 Global Failures 6xx ................................. 83
+ 7.6.1 600 Busy Everywhere ................................. 83
+ 7.6.2 603 Decline ......................................... 84
+ 7.6.3 604 Does Not Exist Anywhere ......................... 84
+ 7.6.4 606 Not Acceptable .................................. 84
+ 8 SIP Message Body .................................... 84
+ 8.1 Body Inclusion ...................................... 84
+
+
+
+Handley, et al. Standards Track [Page 4]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ 8.2 Message Body Type ................................... 85
+ 8.3 Message Body Length ................................. 85
+ 9 Compact Form ........................................ 85
+ 10 Behavior of SIP Clients and Servers ................. 86
+ 10.1 General Remarks ..................................... 86
+ 10.1.1 Requests ............................................ 86
+ 10.1.2 Responses ........................................... 87
+ 10.2 Source Addresses, Destination Addresses and
+ Connections ......................................... 88
+ 10.2.1 Unicast UDP ......................................... 88
+ 10.2.2 Multicast UDP ....................................... 88
+ 10.3 TCP ................................................. 89
+ 10.4 Reliability for BYE, CANCEL, OPTIONS, REGISTER
+ Requests ............................................ 90
+ 10.4.1 UDP ................................................. 90
+ 10.4.2 TCP ................................................. 91
+ 10.5 Reliability for INVITE Requests ..................... 91
+ 10.5.1 UDP ................................................. 92
+ 10.5.2 TCP ................................................. 95
+ 10.6 Reliability for ACK Requests ........................ 95
+ 10.7 ICMP Handling ....................................... 95
+ 11 Behavior of SIP User Agents ......................... 95
+ 11.1 Caller Issues Initial INVITE Request ................ 96
+ 11.2 Callee Issues Response .............................. 96
+ 11.3 Caller Receives Response to Initial Request ......... 96
+ 11.4 Caller or Callee Generate Subsequent Requests ....... 97
+ 11.5 Receiving Subsequent Requests ....................... 97
+ 12 Behavior of SIP Proxy and Redirect Servers .......... 97
+ 12.1 Redirect Server ..................................... 97
+ 12.2 User Agent Server ................................... 98
+ 12.3 Proxy Server ........................................ 98
+ 12.3.1 Proxying Requests ................................... 98
+ 12.3.2 Proxying Responses .................................. 99
+ 12.3.3 Stateless Proxy: Proxying Responses ................. 99
+ 12.3.4 Stateful Proxy: Receiving Requests .................. 99
+ 12.3.5 Stateful Proxy: Receiving ACKs ...................... 99
+ 12.3.6 Stateful Proxy: Receiving Responses ................. 100
+ 12.3.7 Stateless, Non-Forking Proxy ........................ 100
+ 12.4 Forking Proxy ....................................... 100
+ 13 Security Considerations ............................. 104
+ 13.1 Confidentiality and Privacy: Encryption ............. 104
+ 13.1.1 End-to-End Encryption ............................... 104
+ 13.1.2 Privacy of SIP Responses ............................ 107
+ 13.1.3 Encryption by Proxies ............................... 108
+ 13.1.4 Hop-by-Hop Encryption ............................... 108
+ 13.1.5 Via field encryption ................................ 108
+ 13.2 Message Integrity and Access Control:
+ Authentication ...................................... 109
+
+
+
+Handley, et al. Standards Track [Page 5]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ 13.2.1 Trusting responses .................................. 112
+ 13.3 Callee Privacy ...................................... 113
+ 13.4 Known Security Problems ............................. 113
+ 14 SIP Authentication using HTTP Basic and Digest
+ Schemes ............................................. 113
+ 14.1 Framework ........................................... 113
+ 14.2 Basic Authentication ................................ 114
+ 14.3 Digest Authentication ............................... 114
+ 14.4 Proxy-Authentication ................................ 115
+ 15 SIP Security Using PGP .............................. 115
+ 15.1 PGP Authentication Scheme ........................... 115
+ 15.1.1 The WWW-Authenticate Response Header ................ 116
+ 15.1.2 The Authorization Request Header .................... 117
+ 15.2 PGP Encryption Scheme ............................... 118
+ 15.3 Response-Key Header Field for PGP ................... 119
+ 16 Examples ............................................ 119
+ 16.1 Registration ........................................ 119
+ 16.2 Invitation to a Multicast Conference ................ 121
+ 16.2.1 Request ............................................. 121
+ 16.2.2 Response ............................................ 122
+ 16.3 Two-party Call ...................................... 123
+ 16.4 Terminating a Call .................................. 125
+ 16.5 Forking Proxy ....................................... 126
+ 16.6 Redirects ........................................... 130
+ 16.7 Negotiation ......................................... 131
+ 16.8 OPTIONS Request ..................................... 132
+ A Minimal Implementation .............................. 134
+ A.1 Client .............................................. 134
+ A.2 Server .............................................. 135
+ A.3 Header Processing ................................... 135
+ B Usage of the Session Description Protocol (SDP)...... 136
+ B.1 Configuring Media Streams ........................... 136
+ B.2 Setting SDP Values for Unicast ...................... 138
+ B.3 Multicast Operation ................................. 139
+ B.4 Delayed Media Streams ............................... 139
+ B.5 Putting Media Streams on Hold ....................... 139
+ B.6 Subject and SDP "s=" Line ........................... 140
+ B.7 The SDP "o=" Line ................................... 140
+ C Summary of Augmented BNF ............................ 141
+ C.1 Basic Rules ......................................... 143
+ D Using SRV DNS Records ............................... 146
+ E IANA Considerations ................................. 148
+ F Acknowledgments ..................................... 149
+ G Authors' Addresses .................................. 149
+ H Bibliography ........................................ 150
+ I Full Copyright Statement ............................ 153
+
+
+
+
+
+Handley, et al. Standards Track [Page 6]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+1 Introduction
+
+1.1 Overview of SIP Functionality
+
+ The Session Initiation Protocol (SIP) is an application-layer control
+ protocol that can establish, modify and terminate multimedia sessions
+ or calls. These multimedia sessions include multimedia conferences,
+ distance learning, Internet telephony and similar applications. SIP
+ can invite both persons and "robots", such as a media storage
+ service. SIP can invite parties to both unicast and multicast
+ sessions; the initiator does not necessarily have to be a member of
+ the session to which it is inviting. Media and participants can be
+ added to an existing session.
+
+ SIP can be used to initiate sessions as well as invite members to
+ sessions that have been advertised and established by other means.
+ Sessions can be advertised using multicast protocols such as SAP,
+ electronic mail, news groups, web pages or directories (LDAP), among
+ others.
+
+ SIP transparently supports name mapping and redirection services,
+ allowing the implementation of ISDN and Intelligent Network telephony
+ subscriber services. These facilities also enable personal mobility.
+ In the parlance of telecommunications intelligent network services,
+ this is defined as: "Personal mobility is the ability of end users to
+ originate and receive calls and access subscribed telecommunication
+ services on any terminal in any location, and the ability of the
+ network to identify end users as they move. Personal mobility is
+ based on the use of a unique personal identity (i.e., personal
+ number)." [1]. Personal mobility complements terminal mobility, i.e.,
+ the ability to maintain communications when moving a single end
+ system from one subnet to another.
+
+ SIP supports five facets of establishing and terminating multimedia
+ communications:
+
+ User location: determination of the end system to be used for
+ communication;
+
+ User capabilities: determination of the media and media parameters to
+ be used;
+
+ User availability: determination of the willingness of the called
+ party to engage in communications;
+
+ Call setup: "ringing", establishment of call parameters at both
+ called and calling party;
+
+
+
+
+Handley, et al. Standards Track [Page 7]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ Call handling: including transfer and termination of calls.
+
+ SIP can also initiate multi-party calls using a multipoint control
+ unit (MCU) or fully-meshed interconnection instead of multicast.
+ Internet telephony gateways that connect Public Switched Telephone
+ Network (PSTN) parties can also use SIP to set up calls between them.
+
+ SIP is designed as part of the overall IETF multimedia data and
+ control architecture currently incorporating protocols such as RSVP
+ (RFC 2205 [2]) for reserving network resources, the real-time
+ transport protocol (RTP) (RFC 1889 [3]) for transporting real-time
+ data and providing QOS feedback, the real-time streaming protocol
+ (RTSP) (RFC 2326 [4]) for controlling delivery of streaming media,
+ the session announcement protocol (SAP) [5] for advertising
+ multimedia sessions via multicast and the session description
+ protocol (SDP) (RFC 2327 [6]) for describing multimedia sessions.
+ However, the functionality and operation of SIP does not depend on
+ any of these protocols.
+
+ SIP can also be used in conjunction with other call setup and
+ signaling protocols. In that mode, an end system uses SIP exchanges
+ to determine the appropriate end system address and protocol from a
+ given address that is protocol-independent. For example, SIP could be
+ used to determine that the party can be reached via H.323 [7], obtain
+ the H.245 [8] gateway and user address and then use H.225.0 [9] to
+ establish the call.
+
+ In another example, SIP might be used to determine that the callee is
+ reachable via the PSTN and indicate the phone number to be called,
+ possibly suggesting an Internet-to-PSTN gateway to be used.
+
+ SIP does not offer conference control services such as floor control
+ or voting and does not prescribe how a conference is to be managed,
+ but SIP can be used to introduce conference control protocols. SIP
+ does not allocate multicast addresses.
+
+ SIP can invite users to sessions with and without resource
+ reservation. SIP does not reserve resources, but can convey to the
+ invited system the information necessary to do this.
+
+1.2 Terminology
+
+ In this document, the key words "MUST", "MUST NOT", "REQUIRED",
+ "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY",
+ and "OPTIONAL" are to be interpreted as described in RFC 2119 [10]
+ and indicate requirement levels for compliant SIP implementations.
+
+
+
+
+
+Handley, et al. Standards Track [Page 8]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+1.3 Definitions
+
+ This specification uses a number of terms to refer to the roles
+ played by participants in SIP communications. The definitions of
+ client, server and proxy are similar to those used by the Hypertext
+ Transport Protocol (HTTP) (RFC 2068 [11]). The terms and generic
+ syntax of URI and URL are defined in RFC 2396 [12]. The following
+ terms have special significance for SIP.
+
+ Call: A call consists of all participants in a conference invited by
+ a common source. A SIP call is identified by a globally unique
+ call-id (Section 6.12). Thus, if a user is, for example, invited
+ to the same multicast session by several people, each of these
+ invitations will be a unique call. A point-to-point Internet
+ telephony conversation maps into a single SIP call. In a
+ multiparty conference unit (MCU) based call-in conference, each
+ participant uses a separate call to invite himself to the MCU.
+
+ Call leg: A call leg is identified by the combination of Call-ID, To
+ and From.
+
+ Client: An application program that sends SIP requests. Clients may
+ or may not interact directly with a human user. User agents and
+ proxies contain clients (and servers).
+
+ Conference: A multimedia session (see below), identified by a common
+ session description. A conference can have zero or more members
+ and includes the cases of a multicast conference, a full-mesh
+ conference and a two-party "telephone call", as well as
+ combinations of these. Any number of calls can be used to
+ create a conference.
+
+ Downstream: Requests sent in the direction from the caller to the
+ callee (i.e., user agent client to user agent server).
+
+ Final response: A response that terminates a SIP transaction, as
+ opposed to a provisional response that does not. All 2xx, 3xx,
+ 4xx, 5xx and 6xx responses are final.
+
+ Initiator, calling party, caller: The party initiating a conference
+ invitation. Note that the calling party does not have to be the
+ same as the one creating the conference.
+
+ Invitation: A request sent to a user (or service) requesting
+ participation in a session. A successful SIP invitation consists
+ of two transactions: an INVITE request followed by an ACK
+ request.
+
+
+
+
+Handley, et al. Standards Track [Page 9]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ Invitee, invited user, called party, callee: The person or service
+ that the calling party is trying to invite to a conference.
+
+ Isomorphic request or response: Two requests or responses are defined
+ to be isomorphic for the purposes of this document if they have
+ the same values for the Call-ID, To, From and CSeq header
+ fields. In addition, isomorphic requests have to have the same
+ Request-URI.
+
+ Location server: See location service.
+
+ Location service: A location service is used by a SIP redirect or
+ proxy server to obtain information about a callee's possible
+ location(s). Location services are offered by location servers.
+ Location servers MAY be co-located with a SIP server, but the
+ manner in which a SIP server requests location services is
+ beyond the scope of this document.
+
+ Parallel search: In a parallel search, a proxy issues several
+ requests to possible user locations upon receiving an incoming
+ request. Rather than issuing one request and then waiting for
+ the final response before issuing the next request as in a
+ sequential search , a parallel search issues requests without
+ waiting for the result of previous requests.
+
+ Provisional response: A response used by the server to indicate
+ progress, but that does not terminate a SIP transaction. 1xx
+ responses are provisional, other responses are considered final.
+
+ Proxy, proxy server: An intermediary program that acts as both a
+ server and a client for the purpose of making requests on behalf
+ of other clients. Requests are serviced internally or by passing
+ them on, possibly after translation, to other servers. A proxy
+ interprets, and, if necessary, rewrites a request message before
+ forwarding it.
+
+ Redirect server: A redirect server is a server that accepts a SIP
+ request, maps the address into zero or more new addresses and
+ returns these addresses to the client. Unlike a proxy server ,
+ it does not initiate its own SIP request. Unlike a user agent
+ server , it does not accept calls.
+
+ Registrar: A registrar is a server that accepts REGISTER requests. A
+ registrar is typically co-located with a proxy or redirect
+ server and MAY offer location services.
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 10]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ Ringback: Ringback is the signaling tone produced by the calling
+ client's application indicating that a called party is being
+ alerted (ringing).
+
+ Server: A server is an application program that accepts requests in
+ order to service requests and sends back responses to those
+ requests. Servers are either proxy, redirect or user agent
+ servers or registrars.
+
+ Session: From the SDP specification: "A multimedia session is a set
+ of multimedia senders and receivers and the data streams flowing
+ from senders to receivers. A multimedia conference is an example
+ of a multimedia session." (RFC 2327 [6]) (A session as defined
+ for SDP can comprise one or more RTP sessions.) As defined, a
+ callee can be invited several times, by different calls, to the
+ same session. If SDP is used, a session is defined by the
+ concatenation of the user name , session id , network type ,
+ address type and address elements in the origin field.
+
+ (SIP) transaction: A SIP transaction occurs between a client and a
+ server and comprises all messages from the first request sent
+ from the client to the server up to a final (non-1xx) response
+ sent from the server to the client. A transaction is identified
+ by the CSeq sequence number (Section 6.17) within a single call
+ leg. The ACK request has the same CSeq number as the
+ corresponding INVITE request, but comprises a transaction of its
+ own.
+
+ Upstream: Responses sent in the direction from the user agent server
+ to the user agent client.
+
+ URL-encoded: A character string encoded according to RFC 1738,
+ Section 2.2 [13].
+
+ User agent client (UAC), calling user agent: A user agent client is a
+ client application that initiates the SIP request.
+
+ User agent server (UAS), called user agent: A user agent server is a
+ server application that contacts the user when a SIP request is
+ received and that returns a response on behalf of the user. The
+ response accepts, rejects or redirects the request.
+
+ User agent (UA): An application which contains both a user agent
+ client and user agent server.
+
+ An application program MAY be capable of acting both as a client and
+ a server. For example, a typical multimedia conference control
+ application would act as a user agent client to initiate calls or to
+
+
+
+Handley, et al. Standards Track [Page 11]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ invite others to conferences and as a user agent server to accept
+ invitations. The properties of the different SIP server types are
+ summarized in Table 1.
+
+
+ property redirect proxy user agent registrar
+ server server server
+ __________________________________________________________________
+ also acts as a SIP client no yes no no
+ returns 1xx status yes yes yes yes
+ returns 2xx status no yes yes yes
+ returns 3xx status yes yes yes yes
+ returns 4xx status yes yes yes yes
+ returns 5xx status yes yes yes yes
+ returns 6xx status no yes yes yes
+ inserts Via header no yes no no
+ accepts ACK yes yes yes no
+
+
+ Table 1: Properties of the different SIP server types
+
+
+1.4 Overview of SIP Operation
+
+ This section explains the basic protocol functionality and operation.
+ Callers and callees are identified by SIP addresses, described in
+ Section 1.4.1. When making a SIP call, a caller first locates the
+ appropriate server (Section 1.4.2) and then sends a SIP request
+ (Section 1.4.3). The most common SIP operation is the invitation
+ (Section 1.4.4). Instead of directly reaching the intended callee, a
+ SIP request may be redirected or may trigger a chain of new SIP
+ requests by proxies (Section 1.4.5). Users can register their
+ location(s) with SIP servers (Section 4.2.6).
+
+1.4.1 SIP Addressing
+
+ The "objects" addressed by SIP are users at hosts, identified by a
+ SIP URL. The SIP URL takes a form similar to a mailto or telnet URL,
+ i.e., user at host. The user part is a user name or a telephone number.
+ The host part is either a domain name or a numeric network address.
+ See section 2 for a detailed discussion of SIP URL's.
+
+ A user's SIP address can be obtained out-of-band, can be learned via
+ existing media agents, can be included in some mailers' message
+ headers, or can be recorded during previous invitation interactions.
+ In many cases, a user's SIP URL can be guessed from their email
+ address.
+
+
+
+
+Handley, et al. Standards Track [Page 12]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ A SIP URL address can designate an individual (possibly located at
+ one of several end systems), the first available person from a group
+ of individuals or a whole group. The form of the address, for
+ example, sip:sales at example.com , is not sufficient, in general, to
+ determine the intent of the caller.
+
+ If a user or service chooses to be reachable at an address that is
+ guessable from the person's name and organizational affiliation, the
+ traditional method of ensuring privacy by having an unlisted "phone"
+ number is compromised. However, unlike traditional telephony, SIP
+ offers authentication and access control mechanisms and can avail
+ itself of lower-layer security mechanisms, so that client software
+ can reject unauthorized or undesired call attempts.
+
+1.4.2 Locating a SIP Server
+
+ When a client wishes to send a request, the client either sends it to
+ a locally configured SIP proxy server (as in HTTP), independent of
+ the Request-URI, or sends it to the IP address and port corresponding
+ to the Request-URI.
+
+ For the latter case, the client must determine the protocol, port and
+ IP address of a server to which to send the request. A client SHOULD
+ follow the steps below to obtain this information, but MAY follow the
+ alternative, optional procedure defined in Appendix D. At each step,
+ unless stated otherwise, the client SHOULD try to contact a server at
+ the port number listed in the Request-URI. If no port number is
+ present in the Request-URI, the client uses port 5060. If the
+ Request-URI specifies a protocol (TCP or UDP), the client contacts
+ the server using that protocol. If no protocol is specified, the
+ client tries UDP (if UDP is supported). If the attempt fails, or if
+ the client doesn't support UDP but supports TCP, it then tries TCP.
+
+ A client SHOULD be able to interpret explicit network notifications
+ (such as ICMP messages) which indicate that a server is not
+ reachable, rather than relying solely on timeouts. (For socket-based
+ programs: For TCP, connect() returns ECONNREFUSED if the client could
+ not connect to a server at that address. For UDP, the socket needs to
+ be bound to the destination address using connect() rather than
+ sendto() or similar so that a second write() fails with ECONNREFUSED
+ if there is no server listening) If the client finds the server is
+ not reachable at a particular address, it SHOULD behave as if it had
+ received a 400-class error response to that request.
+
+ The client tries to find one or more addresses for the SIP server by
+ querying DNS. The procedure is as follows:
+
+
+
+
+
+Handley, et al. Standards Track [Page 13]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ 1. If the host portion of the Request-URI is an IP address,
+ the client contacts the server at the given address.
+ Otherwise, the client proceeds to the next step.
+
+ 2. The client queries the DNS server for address records for
+ the host portion of the Request-URI. If the DNS server
+ returns no address records, the client stops, as it has
+ been unable to locate a server. By address record, we mean
+ A RR's, AAAA RR's, or other similar address records, chosen
+ according to the client's network protocol capabilities.
+
+
+ There are no mandatory rules on how to select a host name
+ for a SIP server. Users are encouraged to name their SIP
+ servers using the sip.domainname (i.e., sip.example.com)
+ convention, as specified in RFC 2219 [16]. Users may only
+ know an email address instead of a full SIP URL for a
+ callee, however. In that case, implementations may be able
+ to increase the likelihood of reaching a SIP server for
+ that domain by constructing a SIP URL from that email
+ address by prefixing the host name with "sip.". In the
+ future, this mechanism is likely to become unnecessary as
+ better DNS techniques, such as the one in Appendix D,
+ become widely available.
+
+ A client MAY cache a successful DNS query result. A successful query
+ is one which contained records in the answer, and a server was
+ contacted at one of the addresses from the answer. When the client
+ wishes to send a request to the same host, it MUST start the search
+ as if it had just received this answer from the name server. The
+ client MUST follow the procedures in RFC1035 [15] regarding DNS cache
+ invalidation when the DNS time-to-live expires.
+
+1.4.3 SIP Transaction
+
+ Once the host part has been resolved to a SIP server, the client
+ sends one or more SIP requests to that server and receives one or
+ more responses from the server. A request (and its retransmissions)
+ together with the responses triggered by that request make up a SIP
+ transaction. All responses to a request contain the same values in
+ the Call-ID, CSeq, To, and From fields (with the possible addition of
+ a tag in the To field (section 6.37)). This allows responses to be
+ matched with requests. The ACK request following an INVITE is not
+ part of the transaction since it may traverse a different set of
+ hosts.
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 14]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ If TCP is used, request and responses within a single SIP transaction
+ are carried over the same TCP connection (see Section 10). Several
+ SIP requests from the same client to the same server MAY use the same
+ TCP connection or MAY use a new connection for each request.
+
+ If the client sent the request via unicast UDP, the response is sent
+ to the address contained in the next Via header field (Section 6.40)
+ of the response. If the request is sent via multicast UDP, the
+ response is directed to the same multicast address and destination
+ port. For UDP, reliability is achieved using retransmission (Section
+ 10).
+
+ The SIP message format and operation is independent of the transport
+ protocol.
+
+1.4.4 SIP Invitation
+
+ A successful SIP invitation consists of two requests, INVITE followed
+ by ACK. The INVITE (Section 4.2.1) request asks the callee to join a
+ particular conference or establish a two-party conversation. After
+ the callee has agreed to participate in the call, the caller confirms
+ that it has received that response by sending an ACK (Section 4.2.2)
+ request. If the caller no longer wants to participate in the call, it
+ sends a BYE request instead of an ACK.
+
+ The INVITE request typically contains a session description, for
+ example written in SDP (RFC 2327 [6]) format, that provides the
+ called party with enough information to join the session. For
+ multicast sessions, the session description enumerates the media
+ types and formats that are allowed to be distributed to that session.
+ For a unicast session, the session description enumerates the media
+ types and formats that the caller is willing to use and where it
+ wishes the media data to be sent. In either case, if the callee
+ wishes to accept the call, it responds to the invitation by returning
+ a similar description listing the media it wishes to use. For a
+ multicast session, the callee SHOULD only return a session
+ description if it is unable to receive the media indicated in the
+ caller's description or wants to receive data via unicast.
+
+ The protocol exchanges for the INVITE method are shown in Fig. 1 for
+ a proxy server and in Fig. 2 for a redirect server. (Note that the
+ messages shown in the figures have been abbreviated slightly.) In
+ Fig. 1, the proxy server accepts the INVITE request (step 1),
+ contacts the location service with all or parts of the address (step
+ 2) and obtains a more precise location (step 3). The proxy server
+ then issues a SIP INVITE request to the address(es) returned by the
+ location service (step 4). The user agent server alerts the user
+ (step 5) and returns a success indication to the proxy server (step
+
+
+
+Handley, et al. Standards Track [Page 15]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ 6). The proxy server then returns the success result to the original
+ caller (step 7). The receipt of this message is confirmed by the
+ caller using an ACK request, which is forwarded to the callee (steps
+ 8 and 9). Note that an ACK can also be sent directly to the callee,
+ bypassing the proxy. All requests and responses have the same Call-
+ ID.
+
+
+
+
+
+ +....... cs.columbia.edu .......+
+ : :
+ : (~~~~~~~~~~) :
+ : ( location ) :
+ : ( service ) :
+ : (~~~~~~~~~~) :
+ : ^ | :
+ : | hgs at lab :
+ : 2| 3| :
+ : | | :
+ : henning | :
++.. cs.tu-berlin.de ..+ 1: INVITE : | | :
+: : henning at cs.col: | \/ 4: INVITE 5: ring :
+: cz at cs.tu-berlin.de ========================>(~~~~~~)=========>(~~~~~~) :
+: <........................( )<.........( ) :
+: : 7: 200 OK : ( )6: 200 OK ( ) :
+: : : ( work ) ( lab ) :
+: : 8: ACK : ( )9: ACK ( ) :
+: ========================>(~~~~~~)=========>(~~~~~~) :
++.....................+ +...............................+
+
+ ====> SIP request
+ ....> SIP response
+
+ ^
+ | non-SIP protocols
+ |
+
+
+ Figure 1: Example of SIP proxy server
+
+
+
+ The redirect server shown in Fig. 2 accepts the INVITE request (step
+ 1), contacts the location service as before (steps 2 and 3) and,
+ instead of contacting the newly found address itself, returns the
+ address to the caller (step 4), which is then acknowledged via an ACK
+
+
+
+Handley, et al. Standards Track [Page 16]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ request (step 5). The caller issues a new request, with the same
+ call-ID but a higher CSeq, to the address returned by the first
+ server (step 6). In the example, the call succeeds (step 7). The
+ caller and callee complete the handshake with an ACK (step 8).
+
+
+ The next section discusses what happens if the location service
+ returns more than one possible alternative.
+
+1.4.5 Locating a User
+
+ A callee may move between a number of different end systems over
+ time. These locations can be dynamically registered with the SIP
+ server (Sections 1.4.7, 4.2.6). A location server MAY also use one or
+ more other protocols, such as finger (RFC 1288 [17]), rwhois (RFC
+ 2167 [18]), LDAP (RFC 1777 [19]), multicast-based protocols [20] or
+ operating-system dependent mechanisms to actively determine the end
+ system where a user might be reachable. A location server MAY return
+ several locations because the user is logged in at several hosts
+ simultaneously or because the location server has (temporarily)
+ inaccurate information. The SIP server combines the results to yield
+ a list of a zero or more locations.
+
+ The action taken on receiving a list of locations varies with the
+ type of SIP server. A SIP redirect server returns the list to the
+ client as Contact headers (Section 6.13). A SIP proxy server can
+ sequentially or in parallel try the addresses until the call is
+ successful (2xx response) or the callee has declined the call (6xx
+ response). With sequential attempts, a proxy server can implement an
+ "anycast" service.
+
+ If a proxy server forwards a SIP request, it MUST add itself to the
+ beginning of the list of forwarders noted in the Via (Section 6.40)
+ headers. The Via trace ensures that replies can take the same path
+ back, ensuring correct operation through compliant firewalls and
+ avoiding request loops. On the response path, each host MUST remove
+ its Via, so that routing internal information is hidden from the
+ callee and outside networks. A proxy server MUST check that it does
+ not generate a request to a host listed in the Via sent-by, via-
+ received or via-maddr parameters (Section 6.40). (Note: If a host has
+ several names or network addresses, this does not always work. Thus,
+ each host also checks if it is part of the Via list.)
+
+ A SIP invitation may traverse more than one SIP proxy server. If one
+ of these "forks" the request, i.e., issues more than one request in
+ response to receiving the invitation request, it is possible that a
+ client is reached, independently, by more than one copy of the
+
+
+
+
+Handley, et al. Standards Track [Page 17]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ invitation request. Each of these copies bears the same Call-ID. The
+ user agent MUST return the same status response returned in the first
+ response. Duplicate requests are not an error.
+
+1.4.6 Changing an Existing Session
+
+ In some circumstances, it is desirable to change the parameters of an
+ existing session. This is done by re-issuing the INVITE, using the
+ same Call-ID, but a new or different body or header fields to convey
+ the new information. This re INVITE MUST have a higher CSeq than any
+ previous request from the client to the server.
+
+ For example, two parties may have been conversing and then want to
+ add a third party, switching to multicast for efficiency. One of the
+ participants invites the third party with the new multicast address
+ and simultaneously sends an INVITE to the second party, with the new
+ multicast session description, but with the old call identifier.
+
+1.4.7 Registration Services
+
+ The REGISTER request allows a client to let a proxy or redirect
+ server know at which address(es) it can be reached. A client MAY also
+ use it to install call handling features at the server.
+
+1.5 Protocol Properties
+
+1.5.1 Minimal State
+
+ A single conference session or call involves one or more SIP
+ request-response transactions. Proxy servers do not have to keep
+ state for a particular call, however, they MAY maintain state for a
+ single SIP transaction, as discussed in Section 12. For efficiency, a
+ server MAY cache the results of location service requests.
+
+1.5.2 Lower-Layer-Protocol Neutral
+
+ SIP makes minimal assumptions about the underlying transport and
+ network-layer protocols. The lower-layer can provide either a packet
+ or a byte stream service, with reliable or unreliable service.
+
+ In an Internet context, SIP is able to utilize both UDP and TCP as
+ transport protocols, among others. UDP allows the application to more
+ carefully control the timing of messages and their retransmission, to
+ perform parallel searches without requiring TCP connection state for
+ each outstanding request, and to use multicast. Routers can more
+ readily snoop SIP UDP packets. TCP allows easier passage through
+ existing firewalls.
+
+
+
+
+Handley, et al. Standards Track [Page 18]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+
+
+
+
+ +....... cs.columbia.edu .......+
+ : :
+ : (~~~~~~~~~~) :
+ : ( location ) :
+ : ( service ) :
+ : (~~~~~~~~~~) :
+ : ^ | :
+ : | hgs at lab :
+ : 2| 3| :
+ : | | :
+ : henning| :
++.. cs.tu-berlin.de ..+ 1: INVITE : | | :
+: : henning at cs.col: | \/ :
+: cz at cs.tu-berlin.de =======================>(~~~~~~) :
+: | ^ | <.......................( ) :
+: | . | : 4: 302 Moved : ( ) :
+: | . | : hgs at lab : ( work ) :
+: | . | : : ( ) :
+: | . | : 5: ACK : ( ) :
+: | . | =======================>(~~~~~~) :
+: | . | : : :
++.......|...|.........+ : :
+ | . | : :
+ | . | : :
+ | . | : :
+ | . | : :
+ | . | 6: INVITE hgs at lab.cs.columbia.edu (~~~~~~) :
+ | . ==================================================> ( ) :
+ | ..................................................... ( ) :
+ | 7: 200 OK : ( lab ) :
+ | : ( ) :
+ | 8: ACK : ( ) :
+ ======================================================> (~~~~~~) :
+ +...............................+
+
+ ====> SIP request
+ ....> SIP response
+
+ ^
+ | non-SIP protocols
+ |
+
+
+
+
+ Figure 2: Example of SIP redirect server
+
+Handley, et al. Standards Track [Page 19]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ When TCP is used, SIP can use one or more connections to attempt to
+ contact a user or to modify parameters of an existing conference.
+ Different SIP requests for the same SIP call MAY use different TCP
+ connections or a single persistent connection, as appropriate.
+
+ For concreteness, this document will only refer to Internet
+ protocols. However, SIP MAY also be used directly with protocols
+ such as ATM AAL5, IPX, frame relay or X.25. The necessary naming
+ conventions are beyond the scope of this document. User agents SHOULD
+ implement both UDP and TCP transport. Proxy, registrar, and redirect
+ servers MUST implement both UDP and TCP transport.
+
+1.5.3 Text-Based
+
+ SIP is text-based, using ISO 10646 in UTF-8 encoding throughout. This
+ allows easy implementation in languages such as Java, Tcl and Perl,
+ allows easy debugging, and most importantly, makes SIP flexible and
+ extensible. As SIP is used for initiating multimedia conferences
+ rather than delivering media data, it is believed that the additional
+ overhead of using a text-based protocol is not significant.
+
+2 SIP Uniform Resource Locators
+
+ SIP URLs are used within SIP messages to indicate the originator
+ (From), current destination (Request-URI) and final recipient (To) of
+ a SIP request, and to specify redirection addresses (Contact). A SIP
+ URL can also be embedded in web pages or other hyperlinks to indicate
+ that a particular user or service can be called via SIP. When used as
+ a hyperlink, the SIP URL indicates the use of the INVITE method.
+
+ The SIP URL scheme is defined to allow setting SIP request-header
+ fields and the SIP message-body.
+
+
+ This corresponds to the use of mailto: URLs. It makes it
+ possible, for example, to specify the subject, urgency or
+ media types of calls initiated through a web page or as
+ part of an email message.
+
+ A SIP URL follows the guidelines of RFC 2396 [12] and has the syntax
+ shown in Fig. 3. The syntax is described using Augmented Backus-Naur
+ Form (See Section C). Note that reserved characters have to be
+ escaped and that the "set of characters reserved within any given URI
+ component is defined by that component. In general, a character is
+ reserved if the semantics of the URI changes if the character is
+ replaced with its escaped US-ASCII encoding" [12].
+
+
+
+
+
+Handley, et al. Standards Track [Page 20]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+
+
+ SIP-URL = "sip:" [ userinfo "@" ] hostport
+ url-parameters [ headers ]
+ userinfo = user [ ":" password ]
+ user = *( unreserved | escaped
+ | "&" | "=" | "+" | "$" | "," )
+ password = *( unreserved | escaped
+ | "&" | "=" | "+" | "$" | "," )
+ hostport = host [ ":" port ]
+ host = hostname | IPv4address
+ hostname = *( domainlabel "." ) toplabel [ "." ]
+ domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum
+ toplabel = alpha | alpha *( alphanum | "-" ) alphanum
+ IPv4address = 1*digit "." 1*digit "." 1*digit "." 1*digit
+ port = *digit
+ url-parameters = *( ";" url-parameter )
+ url-parameter = transport-param | user-param | method-param
+ | ttl-param | maddr-param | other-param
+ transport-param = "transport=" ( "udp" | "tcp" )
+ ttl-param = "ttl=" ttl
+ ttl = 1*3DIGIT ; 0 to 255
+ maddr-param = "maddr=" host
+ user-param = "user=" ( "phone" | "ip" )
+ method-param = "method=" Method
+ tag-param = "tag=" UUID
+ UUID = 1*( hex | "-" )
+ other-param = ( token | ( token "=" ( token | quoted-string )))
+ headers = "?" header *( "&" header )
+ header = hname "=" hvalue
+ hname = 1*uric
+ hvalue = *uric
+ uric = reserved | unreserved | escaped
+ reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
+ "$" | ","
+ digits = 1*DIGIT
+
+
+ Figure 3: SIP URL syntax
+
+
+
+ The URI character classes referenced above are described in Appendix
+ C.
+
+ The components of the SIP URI have the following meanings.
+
+
+
+
+
+Handley, et al. Standards Track [Page 21]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+
+
+telephone-subscriber = global-phone-number | local-phone-number
+ global-phone-number = "+" 1*phonedigit [isdn-subaddress]
+ [post-dial]
+ local-phone-number = 1*(phonedigit | dtmf-digit |
+ pause-character) [isdn-subaddress]
+ [post-dial]
+ isdn-subaddress = ";isub=" 1*phonedigit
+ post-dial = ";postd=" 1*(phonedigit | dtmf-digit
+ | pause-character)
+ phonedigit = DIGIT | visual-separator
+ visual-separator = "-" | "."
+ pause-character = one-second-pause | wait-for-dial-tone
+ one-second-pause = "p"
+ wait-for-dial-tone = "w"
+ dtmf-digit = "*" | "#" | "A" | "B" | "C" | "D"
+
+ Figure 4: SIP URL syntax; telephone subscriber
+
+ user: If the host is an Internet telephony gateway, the user field
+ MAY also encode a telephone number using the notation of
+ telephone-subscriber (Fig. 4). The telephone number is a special
+ case of a user name and cannot be distinguished by a BNF. Thus,
+ a URL parameter, user, is added to distinguish telephone numbers
+ from user names. The phone identifier is to be used when
+ connecting to a telephony gateway. Even without this parameter,
+ recipients of SIP URLs MAY interpret the pre-@ part as a phone
+ number if local restrictions on the name space for user name
+ allow it.
+
+ password: The SIP scheme MAY use the format "user:password" in the
+ userinfo field. The use of passwords in the userinfo is NOT
+ RECOMMENDED, because the passing of authentication information
+ in clear text (such as URIs) has proven to be a security risk in
+ almost every case where it has been used.
+
+ host: The mailto: URL and RFC 822 email addresses require that
+ numeric host addresses ("host numbers") are enclosed in square
+ brackets (presumably, since host names might be numeric), while
+ host numbers without brackets are used for all other URLs. The
+ SIP URL requires the latter form, without brackets.
+
+ The issue of IPv6 literal addresses in URLs is being looked at
+ elsewhere in the IETF. SIP implementers are advised to keep up to
+ date on that activity.
+
+
+
+
+Handley, et al. Standards Track [Page 22]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ port: The port number to send a request to. If not present, the
+ procedures outlined in Section 1.4.2 are used to determine the
+ port number to send a request to.
+
+ URL parameters: SIP URLs can define specific parameters of the
+ request. URL parameters are added after the host component and
+ are separated by semi-colons. The transport parameter determines
+ the the transport mechanism (UDP or TCP). UDP is to be assumed
+ when no explicit transport parameter is included. The maddr
+ parameter provides the server address to be contacted for this
+ user, overriding the address supplied in the host field. This
+ address is typically a multicast address, but could also be the
+ address of a backup server. The ttl parameter determines the
+ time-to-live value of the UDP multicast packet and MUST only be
+ used if maddr is a multicast address and the transport protocol
+ is UDP. The user parameter was described above. For example, to
+ specify to call j.doe at big.com using multicast to 239.255.255.1
+ with a ttl of 15, the following URL would be used:
+
+
+ sip:j.doe at big.com;maddr=239.255.255.1;ttl=15
+
+
+
+ The transport, maddr, and ttl parameters MUST NOT be used in the From
+ and To header fields and the Request-URI; they are ignored if
+ present.
+
+ Headers: Headers of the SIP request can be defined with the "?"
+ mechanism within a SIP URL. The special hname "body" indicates
+ that the associated hvalue is the message-body of the SIP INVITE
+ request. Headers MUST NOT be used in the From and To header
+ fields and the Request-URI; they are ignored if present. hname
+ and hvalue are encodings of a SIP header name and value,
+ respectively. All URL reserved characters in the header names
+ and values MUST be escaped.
+
+ Method: The method of the SIP request can be specified with the
+ method parameter. This parameter MUST NOT be used in the From
+ and To header fields and the Request-URI; they are ignored if
+ present.
+
+ Table 2 summarizes where the components of the SIP URL can be used
+ and what default values they assume if not present.
+
+
+ Examples of SIP URLs are:
+
+
+
+
+Handley, et al. Standards Track [Page 23]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+
+ default Req.-URI To From Contact external
+ user -- x x x x x
+ password -- x x x x
+ host mandatory x x x x x
+ port 5060 x x x x x
+ user-param ip x x x x x
+ method INVITE x x
+ maddr-param -- x x
+ ttl-param 1 x x
+ transp.-param -- x x
+ headers -- x x
+
+
+ Table 2: Use and default values of URL components for SIP headers,
+ Request-URI and references
+
+ sip:j.doe at big.com
+ sip:j.doe:secret at big.com;transport=tcp
+ sip:j.doe at big.com?subject=project
+ sip:+1-212-555-1212:1234 at gateway.com;user=phone
+ sip:1212 at gateway.com
+ sip:alice at 10.1.2.3
+ sip:alice at example.com
+ sip:alice%40example.com at gateway.com
+ sip:alice at registrar.com;method=REGISTER
+
+
+
+ Within a SIP message, URLs are used to indicate the source and
+ intended destination of a request, redirection addresses and the
+ current destination of a request. Normally all these fields will
+ contain SIP URLs.
+
+ SIP URLs are case-insensitive, so that for example the two URLs
+ sip:j.doe at example.com and SIP:J.Doe at Example.com are equivalent. All
+ URL parameters are included when comparing SIP URLs for equality.
+
+ SIP header fields MAY contain non-SIP URLs. As an example, if a call
+ from a telephone is relayed to the Internet via SIP, the SIP From
+ header field might contain a phone URL.
+
+3 SIP Message Overview
+
+ SIP is a text-based protocol and uses the ISO 10646 character set in
+ UTF-8 encoding (RFC 2279 [21]). Senders MUST terminate lines with a
+ CRLF, but receivers MUST also interpret CR and LF by themselves as
+ line terminators.
+
+
+
+Handley, et al. Standards Track [Page 24]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ Except for the above difference in character sets, much of the
+ message syntax is and header fields are identical to HTTP/1.1; rather
+ than repeating the syntax and semantics here we use [HX.Y] to refer
+ to Section X.Y of the current HTTP/1.1 specification (RFC 2068 [11]).
+ In addition, we describe SIP in both prose and an augmented Backus-
+ Naur form (ABNF). See section C for an overview of ABNF.
+
+ Note, however, that SIP is not an extension of HTTP.
+
+ Unlike HTTP, SIP MAY use UDP. When sent over TCP or UDP, multiple SIP
+ transactions can be carried in a single TCP connection or UDP
+ datagram. UDP datagrams, including all headers, SHOULD NOT be larger
+ than the path maximum transmission unit (MTU) if the MTU is known, or
+ 1500 bytes if the MTU is unknown.
+
+
+ The 1500 bytes accommodates encapsulation within the
+ "typical" ethernet MTU without IP fragmentation. Recent
+ studies [22] indicate that an MTU of 1500 bytes is a
+ reasonable assumption. The next lower common MTU values are
+ 1006 bytes for SLIP and 296 for low-delay PPP (RFC 1191
+ [23]). Thus, another reasonable value would be a message
+ size of 950 bytes, to accommodate packet headers within the
+ SLIP MTU without fragmentation.
+
+ A SIP message is either a request from a client to a server, or a
+ response from a server to a client.
+
+
+
+ SIP-message = Request | Response
+
+
+ Both Request (section 4) and Response (section 5) messages use the
+ generic-message format of RFC 822 [24] for transferring entities (the
+ body of the message). Both types of messages consist of a start-line,
+ one or more header fields (also known as "headers"), an empty line
+ (i.e., a line with nothing preceding the carriage-return line-feed
+ (CRLF)) indicating the end of the header fields, and an optional
+ message-body. To avoid confusion with similar-named headers in HTTP,
+ we refer to the headers describing the message body as entity
+ headers. These components are described in detail in the upcoming
+ sections.
+
+
+
+ generic-message = start-line
+ *message-header
+
+
+
+Handley, et al. Standards Track [Page 25]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ CRLF
+ [ message-body ]
+
+ start-line = Request-Line | ;Section 4.1
+ Status-Line ;Section 5.1
+
+
+
+
+ message-header = ( general-header
+ | request-header
+ | response-header
+ | entity-header )
+
+
+
+ In the interest of robustness, any leading empty line(s) MUST be
+ ignored. In other words, if the Request or Response message begins
+ with one or more CRLF, CR, or LFs, these characters MUST be ignored.
+
+4 Request
+
+ The Request message format is shown below:
+
+
+
+ Request = Request-Line ; Section 4.1
+ *( general-header
+ | request-header
+ | entity-header )
+ CRLF
+ [ message-body ] ; Section 8
+
+
+4.1 Request-Line
+
+ The Request-Line begins with a method token, followed by the
+ Request-URI and the protocol version, and ending with CRLF. The
+ elements are separated by SP characters. No CR or LF are allowed
+ except in the final CRLF sequence.
+
+
+
+ Request-Line = Method SP Request-URI SP SIP-Version CRLF
+
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 26]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+
+
+ general-header = Accept ; Section 6.7
+ | Accept-Encoding ; Section 6.8
+ | Accept-Language ; Section 6.9
+ | Call-ID ; Section 6.12
+ | Contact ; Section 6.13
+ | CSeq ; Section 6.17
+ | Date ; Section 6.18
+ | Encryption ; Section 6.19
+ | Expires ; Section 6.20
+ | From ; Section 6.21
+ | Record-Route ; Section 6.29
+ | Timestamp ; Section 6.36
+ | To ; Section 6.37
+ | Via ; Section 6.40
+ entity-header = Content-Encoding ; Section 6.14
+ | Content-Length ; Section 6.15
+ | Content-Type ; Section 6.16
+ request-header = Authorization ; Section 6.11
+ | Contact ; Section 6.13
+ | Hide ; Section 6.22
+ | Max-Forwards ; Section 6.23
+ | Organization ; Section 6.24
+ | Priority ; Section 6.25
+ | Proxy-Authorization ; Section 6.27
+ | Proxy-Require ; Section 6.28
+ | Route ; Section 6.33
+ | Require ; Section 6.30
+ | Response-Key ; Section 6.31
+ | Subject ; Section 6.35
+ | User-Agent ; Section 6.39
+ response-header = Allow ; Section 6.10
+ | Proxy-Authenticate ; Section 6.26
+ | Retry-After ; Section 6.32
+ | Server ; Section 6.34
+ | Unsupported ; Section 6.38
+ | Warning ; Section 6.41
+ | WWW-Authenticate ; Section 6.42
+
+
+ Table 3: SIP headers
+
+4.2 Methods
+
+ The methods are defined below. Methods that are not supported by a
+ proxy or redirect server are treated by that server as if they were
+ an OPTIONS method and forwarded accordingly. Methods that are not
+
+
+
+Handley, et al. Standards Track [Page 27]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ supported by a user agent server or registrar cause a 501 (Not
+ Implemented) response to be returned (Section 7). As in HTTP, the
+ Method token is case-sensitive.
+
+
+
+ Method = "INVITE" | "ACK" | "OPTIONS" | "BYE"
+ | "CANCEL" | "REGISTER"
+
+
+4.2.1 INVITE
+
+ The INVITE method indicates that the user or service is being invited
+ to participate in a session. The message body contains a description
+ of the session to which the callee is being invited. For two-party
+ calls, the caller indicates the type of media it is able to receive
+ and possibly the media it is willing to send as well as their
+ parameters such as network destination. A success response MUST
+ indicate in its message body which media the callee wishes to receive
+ and MAY indicate the media the callee is going to send.
+
+
+ Not all session description formats have the ability to
+ indicate sending media.
+
+ A server MAY automatically respond to an invitation for a conference
+ the user is already participating in, identified either by the SIP
+ Call-ID or a globally unique identifier within the session
+ description, with a 200 (OK) response.
+
+ If a user agent receives an INVITE request for an existing call leg
+ with a higher CSeq sequence number than any previous INVITE for the
+ same Call-ID, it MUST check any version identifiers in the session
+ description or, if there are no version identifiers, the content of
+ the session description to see if it has changed. It MUST also
+ inspect any other header fields for changes. If there is a change,
+ the user agent MUST update any internal state or information
+ generated as a result of that header. If the session description has
+ changed, the user agent server MUST adjust the session parameters
+ accordingly, possibly after asking the user for confirmation.
+ (Versioning of the session description can be used to accommodate the
+ capabilities of new arrivals to a conference, add or delete media or
+ change from a unicast to a multicast conference.)
+
+ This method MUST be supported by SIP proxy, redirect and user agent
+ servers as well as clients.
+
+
+
+
+
+Handley, et al. Standards Track [Page 28]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+4.2.2 ACK
+
+ The ACK request confirms that the client has received a final
+ response to an INVITE request. (ACK is used only with INVITE
+ requests.) 2xx responses are acknowledged by client user agents, all
+ other final responses by the first proxy or client user agent to
+ receive the response. The Via is always initialized to the host that
+ originates the ACK request, i.e., the client user agent after a 2xx
+ response or the first proxy to receive a non-2xx final response. The
+ ACK request is forwarded as the corresponding INVITE request, based
+ on its Request-URI. See Section 10 for details.
+
+ The ACK request MAY contain a message body with the final session
+ description to be used by the callee. If the ACK message body is
+ empty, the callee uses the session description in the INVITE request.
+
+ A proxy server receiving an ACK request after having sent a 3xx, 4xx,
+ 5xx, or 6xx response must make a determination about whether the ACK
+ is for it, or for some user agent or proxy server further downstream.
+ This determination is made by examining the tag in the To field. If
+ the tag in the ACK To header field matches the tag in the To header
+ field of the response, and the From, CSeq and Call-ID header fields
+ in the response match those in the ACK, the ACK is meant for the
+ proxy server. Otherwise, the ACK SHOULD be proxied downstream as any
+ other request.
+
+
+ It is possible for a user agent client or proxy server to
+ receive multiple 3xx, 4xx, 5xx, and 6xx responses to a
+ request along a single branch. This can happen under
+ various error conditions, typically when a forking proxy
+ transitions from stateful to stateless before receiving all
+ responses. The various responses will all be identical,
+ except for the tag in the To field, which is different for
+ each one. It can therefore be used as a means to
+ disambiguate them.
+
+ This method MUST be supported by SIP proxy, redirect and user agent
+ servers as well as clients.
+
+4.2.3 OPTIONS
+
+ The server is being queried as to its capabilities. A server that
+ believes it can contact the user, such as a user agent where the user
+ is logged in and has been recently active, MAY respond to this
+ request with a capability set. A called user agent MAY return a
+ status reflecting how it would have responded to an invitation, e.g.,
+
+
+
+
+Handley, et al. Standards Track [Page 29]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ 600 (Busy). Such a server SHOULD return an Allow header field
+ indicating the methods that it supports. Proxy and redirect servers
+ simply forward the request without indicating their capabilities.
+
+ This method MUST be supported by SIP proxy, redirect and user agent
+ servers, registrars and clients.
+
+4.2.4 BYE
+
+ The user agent client uses BYE to indicate to the server that it
+ wishes to release the call. A BYE request is forwarded like an INVITE
+ request and MAY be issued by either caller or callee. A party to a
+ call SHOULD issue a BYE request before releasing a call ("hanging
+ up"). A party receiving a BYE request MUST cease transmitting media
+ streams specifically directed at the party issuing the BYE request.
+
+ If the INVITE request contained a Contact header, the callee SHOULD
+ send a BYE request to that address rather than the From address.
+
+ This method MUST be supported by proxy servers and SHOULD be
+ supported by redirect and user agent SIP servers.
+
+4.2.5 CANCEL
+
+ The CANCEL request cancels a pending request with the same Call-ID,
+ To, From and CSeq (sequence number only) header field values, but
+ does not affect a completed request. (A request is considered
+ completed if the server has returned a final status response.)
+
+ A user agent client or proxy client MAY issue a CANCEL request at any
+ time. A proxy, in particular, MAY choose to send a CANCEL to
+ destinations that have not yet returned a final response after it has
+ received a 2xx or 6xx response for one or more of the parallel-search
+ requests. A proxy that receives a CANCEL request forwards the request
+ to all destinations with pending requests.
+
+ The Call-ID, To, the numeric part of CSeq and From headers in the
+ CANCEL request are identical to those in the original request. This
+ allows a CANCEL request to be matched with the request it cancels.
+ However, to allow the client to distinguish responses to the CANCEL
+ from those to the original request, the CSeq Method component is set
+ to CANCEL. The Via header field is initialized to the proxy issuing
+ the CANCEL request. (Thus, responses to this CANCEL request only
+ reach the issuing proxy.)
+
+ Once a user agent server has received a CANCEL, it MUST NOT issue a
+ 2xx response for the cancelled original request.
+
+
+
+
+Handley, et al. Standards Track [Page 30]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ A redirect or user agent server receiving a CANCEL request responds
+ with a status of 200 (OK) if the transaction exists and a status of
+ 481 (Transaction Does Not Exist) if not, but takes no further action.
+ In particular, any existing call is unaffected.
+
+
+ The BYE request cannot be used to cancel branches of a
+ parallel search, since several branches may, through
+ intermediate proxies, find the same user agent server and
+ then terminate the call. To terminate a call instead of
+ just pending searches, the UAC must use BYE instead of or
+ in addition to CANCEL. While CANCEL can terminate any
+ pending request other than ACK or CANCEL, it is typically
+ useful only for INVITE. 200 responses to INVITE and 200
+ responses to CANCEL are distinguished by the method in the
+ Cseq header field, so there is no ambiguity.
+
+ This method MUST be supported by proxy servers and SHOULD be
+ supported by all other SIP server types.
+
+4.2.6 REGISTER
+
+ A client uses the REGISTER method to register the address listed in
+ the To header field with a SIP server.
+
+ A user agent MAY register with a local server on startup by sending a
+ REGISTER request to the well-known "all SIP servers" multicast
+ address "sip.mcast.net" (224.0.1.75). This request SHOULD be scoped
+ to ensure it is not forwarded beyond the boundaries of the
+ administrative system. This MAY be done with either TTL or
+ administrative scopes [25], depending on what is implemented in the
+ network. SIP user agents MAY listen to that address and use it to
+ become aware of the location of other local users [20]; however, they
+ do not respond to the request. A user agent MAY also be configured
+ with the address of a registrar server to which it sends a REGISTER
+ request upon startup.
+
+ Requests are processed in the order received. Clients SHOULD avoid
+ sending a new registration (as opposed to a retransmission) until
+ they have received the response from the server for the previous one.
+
+
+ Clients may register from different locations, by necessity
+ using different Call-ID values. Thus, the CSeq value cannot
+ be used to enforce ordering. Since registrations are
+ additive, ordering is less of a problem than if each
+ REGISTER request completely replaced all earlier ones.
+
+
+
+
+Handley, et al. Standards Track [Page 31]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ The meaning of the REGISTER request-header fields is defined as
+ follows. We define "address-of-record" as the SIP address that the
+ registry knows the registrand, typically of the form "user at domain"
+ rather than "user at host". In third-party registration, the entity
+ issuing the request is different from the entity being registered.
+
+ To: The To header field contains the address-of-record whose
+ registration is to be created or updated.
+
+ From: The From header field contains the address-of-record of the
+ person responsible for the registration. For first-party
+ registration, it is identical to the To header field value.
+
+ Request-URI: The Request-URI names the destination of the
+ registration request, i.e., the domain of the registrar. The
+ user name MUST be empty. Generally, the domains in the Request-
+ URI and the To header field have the same value; however, it is
+ possible to register as a "visitor", while maintaining one's
+ name. For example, a traveler sip:alice at acme.com (To) might
+ register under the Request-URI sip:atlanta.hiayh.org , with the
+ former as the To header field and the latter as the Request-URI.
+ The REGISTER request is no longer forwarded once it has reached
+ the server whose authoritative domain is the one listed in the
+ Request-URI.
+
+ Call-ID: All registrations from a client SHOULD use the same Call-ID
+ header value, at least within the same reboot cycle.
+
+ Cseq: Registrations with the same Call-ID MUST have increasing CSeq
+ header values. However, the server does not reject out-of-order
+ requests.
+
+ Contact: The request MAY contain a Contact header field; future non-
+ REGISTER requests for the URI given in the To header field
+ SHOULD be directed to the address(es) given in the Contact
+ header.
+
+ If the request does not contain a Contact header, the registration
+ remains unchanged.
+
+ This is useful to obtain the current list of registrations
+ in the response. Registrations using SIP URIs that differ
+ in one or more of host, port, transport-param or maddr-
+ param (see Figure 3) from an existing registration are
+ added to the list of registrations. Other URI types are
+ compared according to the standard URI equivalency rules
+ for the URI schema. If the URIs are equivalent to that of
+ an existing registration, the new registration replaces the
+
+
+
+Handley, et al. Standards Track [Page 32]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ old one if it has a higher q value or, for the same value
+ of q, if the ttl value is higher. All current registrations
+ MUST share the same action value. Registrations that have
+ a different action than current registrations for the same
+ user MUST be rejected with status of 409 (Conflict).
+
+ A proxy server ignores the q parameter when processing non-REGISTER
+ requests, while a redirect server simply returns that parameter in
+ its Contact response header field.
+
+
+ Having the proxy server interpret the q parameter is not
+ sufficient to guide proxy behavior, as it is not clear, for
+ example, how long it is supposed to wait between trying
+ addresses.
+
+ If the registration is changed while a user agent or proxy server
+ processes an invitation, the new information SHOULD be used.
+
+
+ This allows a service known as "directed pick-up". In the
+ telephone network, directed pickup permits a user at a
+ remote station who hears his own phone ringing to pick up
+ at that station, dial an access code, and be connected to
+ the calling user as if he had answered his own phone.
+
+ A server MAY choose any duration for the registration lifetime.
+ Registrations not refreshed after this amount of time SHOULD be
+ silently discarded. Responses to a registration SHOULD include an
+ Expires header (Section 6.20) or expires Contact parameters (Section
+ 6.13), indicating the time at which the server will drop the
+ registration. If none is present, one hour is assumed. Clients MAY
+ request a registration lifetime by indicating the time in an Expires
+ header in the request. A server SHOULD NOT use a higher lifetime than
+ the one requested, but MAY use a lower one. A single address (if
+ host-independent) MAY be registered from several different clients.
+
+ A client cancels an existing registration by sending a REGISTER
+ request with an expiration time (Expires) of zero seconds for a
+ particular Contact or the wildcard Contact designated by a "*" for
+ all registrations. Registrations are matched based on the user, host,
+ port and maddr parameters.
+
+ The server SHOULD return the current list of registrations in the 200
+ response as Contact header fields.
+
+ It is particularly important that REGISTER requests are authenticated
+ since they allow to redirect future requests (see Section 13.2).
+
+
+
+Handley, et al. Standards Track [Page 33]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ Beyond its use as a simple location service, this method is
+ needed if there are several SIP servers on a single host.
+ In that case, only one of the servers can use the default
+ port number.
+
+
+ Support of this method is RECOMMENDED.
+
+4.3 Request-URI
+
+ The Request-URI is a SIP URL as described in Section 2 or a general
+ URI. It indicates the user or service to which this request is being
+ addressed. Unlike the To field, the Request-URI MAY be re-written by
+ proxies.
+
+ When used as a Request-URI, a SIP-URL MUST NOT contain the
+ transport-param, maddr-param, ttl-param, or headers elements. A
+ server that receives a SIP-URL with these elements removes them
+ before further processing.
+
+
+ Typically, the UAC sets the Request-URI and To to the same
+ SIP URL, presumed to remain unchanged over long time
+ periods. However, if the UAC has cached a more direct path
+ to the callee, e.g., from the Contact header field of a
+ response to a previous request, the To would still contain
+ the long-term, "public" address, while the Request-URI
+ would be set to the cached address.
+
+ Proxy and redirect servers MAY use the information in the Request-URI
+ and request header fields to handle the request and possibly rewrite
+ the Request-URI. For example, a request addressed to the generic
+ address sip:sales at acme.com is proxied to the particular person, e.g.,
+ sip:bob at ny.acme.com , with the To field remaining as
+ sip:sales at acme.com. At ny.acme.com , Bob then designates Alice as
+ the temporary substitute.
+
+ The host part of the Request-URI typically agrees with one of the
+ host names of the receiving server. If it does not, the server SHOULD
+ proxy the request to the address indicated or return a 404 (Not
+ Found) response if it is unwilling or unable to do so. For example,
+ the Request-URI and server host name can disagree in the case of a
+ firewall proxy that handles outgoing calls. This mode of operation is
+ similar to that of HTTP proxies.
+
+ If a SIP server receives a request with a URI indicating a scheme
+ other than SIP which that server does not understand, the server MUST
+ return a 400 (Bad Request) response. It MUST do this even if the To
+
+
+
+Handley, et al. Standards Track [Page 34]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ header field contains a scheme it does understand. This is because
+ proxies are responsible for processing the Request-URI; the To field
+ is of end-to-end significance.
+
+4.3.1 SIP Version
+
+ Both request and response messages include the version of SIP in use,
+ and follow [H3.1] (with HTTP replaced by SIP, and HTTP/1.1 replaced
+ by SIP/2.0) regarding version ordering, compliance requirements, and
+ upgrading of version numbers. To be compliant with this
+ specification, applications sending SIP messages MUST include a SIP-
+ Version of "SIP/2.0".
+
+4.4 Option Tags
+
+ Option tags are unique identifiers used to designate new options in
+ SIP. These tags are used in Require (Section 6.30) and Unsupported
+ (Section 6.38) fields.
+
+ Syntax:
+
+
+ option-tag = token
+
+
+ See Section C for a definition of token. The creator of a new SIP
+ option MUST either prefix the option with their reverse domain name
+ or register the new option with the Internet Assigned Numbers
+ Authority (IANA). For example, "com.foo.mynewfeature" is an apt name
+ for a feature whose inventor can be reached at "foo.com". Individual
+ organizations are then responsible for ensuring that option names
+ don't collide. Options registered with IANA have the prefix
+ "org.iana.sip.", options described in RFCs have the prefix
+ "org.ietf.rfc.N", where N is the RFC number. Option tags are case-
+ insensitive.
+
+4.4.1 Registering New Option Tags with IANA
+
+ When registering a new SIP option, the following information MUST be
+ provided:
+
+ o Name and description of option. The name MAY be of any
+ length, but SHOULD be no more than twenty characters long. The
+ name MUST consist of alphanum (See Figure 3) characters only;
+
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 35]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ o Indication of who has change control over the option (for
+ example, IETF, ISO, ITU-T, other international standardization
+ bodies, a consortium or a particular company or group of
+ companies);
+
+ o A reference to a further description, if available, for
+ example (in order of preference) an RFC, a published paper, a
+ patent filing, a technical report, documented source code or a
+ computer manual;
+
+ o Contact information (postal and email address);
+
+ Registrations should be sent to iana at iana.org
+
+
+ This procedure has been borrowed from RTSP [4] and the RTP
+ AVP [26].
+
+5 Response
+
+ After receiving and interpreting a request message, the recipient
+ responds with a SIP response message. The response message format is
+ shown below:
+
+
+
+ Response = Status-Line ; Section 5.1
+ *( general-header
+ | response-header
+ | entity-header )
+ CRLF
+ [ message-body ] ; Section 8
+
+
+ SIP's structure of responses is similar to [H6], but is defined
+ explicitly here.
+
+5.1 Status-Line
+
+ The first line of a Response message is the Status-Line, consisting
+ of the protocol version (Section 4.3.1) followed by a numeric
+ Status-Code and its associated textual phrase, with each element
+ separated by SP characters. No CR or LF is allowed except in the
+ final CRLF sequence.
+
+
+
+ Status-Line = SIP-version SP Status-Code SP Reason-Phrase CRLF
+
+
+
+Handley, et al. Standards Track [Page 36]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+5.1.1 Status Codes and Reason Phrases
+
+ The Status-Code is a 3-digit integer result code that indicates the
+ outcome of the attempt to understand and satisfy the request. The
+ Reason-Phrase is intended to give a short textual description of the
+ Status-Code. The Status-Code is intended for use by automata, whereas
+ the Reason-Phrase is intended for the human user. The client is not
+ required to examine or display the Reason-Phrase.
+
+
+
+ Status-Code = Informational ;Fig. 5
+ | Success ;Fig. 5
+ | Redirection ;Fig. 6
+ | Client-Error ;Fig. 7
+ | Server-Error ;Fig. 8
+ | Global-Failure ;Fig. 9
+ | extension-code
+ extension-code = 3DIGIT
+ Reason-Phrase = *<TEXT-UTF8, excluding CR, LF>
+
+
+ We provide an overview of the Status-Code below, and provide full
+ definitions in Section 7. The first digit of the Status-Code defines
+ the class of response. The last two digits do not have any
+ categorization role. SIP/2.0 allows 6 values for the first digit:
+
+ 1xx: Informational -- request received, continuing to process the
+ request;
+
+ 2xx: Success -- the action was successfully received, understood, and
+ accepted;
+
+ 3xx: Redirection -- further action needs to be taken in order to
+ complete the request;
+
+ 4xx: Client Error -- the request contains bad syntax or cannot be
+ fulfilled at this server;
+
+ 5xx: Server Error -- the server failed to fulfill an apparently valid
+ request;
+
+ 6xx: Global Failure -- the request cannot be fulfilled at any server.
+
+ Figures 5 through 9 present the individual values of the numeric
+ response codes, and an example set of corresponding reason phrases
+ for SIP/2.0. These reason phrases are only recommended; they may be
+ replaced by local equivalents without affecting the protocol. Note
+
+
+
+Handley, et al. Standards Track [Page 37]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ that SIP adopts many HTTP/1.1 response codes. SIP/2.0 adds response
+ codes in the range starting at x80 to avoid conflicts with newly
+ defined HTTP response codes, and adds a new class, 6xx, of response
+ codes.
+
+ SIP response codes are extensible. SIP applications are not required
+ to understand the meaning of all registered response codes, though
+ such understanding is obviously desirable. However, applications MUST
+ understand the class of any response code, as indicated by the first
+ digit, and treat any unrecognized response as being equivalent to the
+ x00 response code of that class, with the exception that an
+ unrecognized response MUST NOT be cached. For example, if a client
+ receives an unrecognized response code of 431, it can safely assume
+ that there was something wrong with its request and treat the
+ response as if it had received a 400 (Bad Request) response code. In
+ such cases, user agents SHOULD present to the user the message body
+ returned with the response, since that message body is likely to
+ include human-readable information which will explain the unusual
+ status.
+
+
+
+ Informational = "100" ; Trying
+ | "180" ; Ringing
+ | "181" ; Call Is Being Forwarded
+ | "182" ; Queued
+ Success = "200" ; OK
+
+
+ Figure 5: Informational and success status codes
+
+
+
+
+
+ Redirection = "300" ; Multiple Choices
+ | "301" ; Moved Permanently
+ | "302" ; Moved Temporarily
+ | "303" ; See Other
+ | "305" ; Use Proxy
+ | "380" ; Alternative Service
+
+
+ Figure 6: Redirection status codes
+
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 38]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+
+
+ Client-Error = "400" ; Bad Request
+ | "401" ; Unauthorized
+ | "402" ; Payment Required
+ | "403" ; Forbidden
+ | "404" ; Not Found
+ | "405" ; Method Not Allowed
+ | "406" ; Not Acceptable
+ | "407" ; Proxy Authentication Required
+ | "408" ; Request Timeout
+ | "409" ; Conflict
+ | "410" ; Gone
+ | "411" ; Length Required
+ | "413" ; Request Entity Too Large
+ | "414" ; Request-URI Too Large
+ | "415" ; Unsupported Media Type
+ | "420" ; Bad Extension
+ | "480" ; Temporarily not available
+ | "481" ; Call Leg/Transaction Does Not Exist
+ | "482" ; Loop Detected
+ | "483" ; Too Many Hops
+ | "484" ; Address Incomplete
+ | "485" ; Ambiguous
+ | "486" ; Busy Here
+
+
+ Figure 7: Client error status codes
+
+
+ Server-Error = "500" ; Internal Server Error
+ | "501" ; Not Implemented
+ | "502" ; Bad Gateway
+ | "503" ; Service Unavailable
+ | "504" ; Gateway Time-out
+ | "505" ; SIP Version not supported
+
+
+ Figure 8: Server error status codes
+
+
+6 Header Field Definitions
+
+ SIP header fields are similar to HTTP header fields in both syntax
+ and semantics. In particular, SIP header fields follow the syntax for
+ message-header as described in [H4.2]. The rules for extending header
+ fields over multiple lines, and use of multiple message-header fields
+ with the same field-name, described in [H4.2] also apply to SIP. The
+
+
+
+Handley, et al. Standards Track [Page 39]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+
+
+ Global-Failure | "600" ; Busy Everywhere
+ | "603" ; Decline
+ | "604" ; Does not exist anywhere
+ | "606" ; Not Acceptable
+
+
+ Figure 9: Global failure status codes
+
+
+ rules in [H4.2] regarding ordering of header fields apply to SIP,
+ with the exception of Via fields, see below, whose order matters.
+ Additionally, header fields which are hop-by-hop MUST appear before
+ any header fields which are end-to-end. Proxies SHOULD NOT reorder
+ header fields. Proxies add Via header fields and MAY add other hop-
+ by-hop header fields. They can modify certain header fields, such as
+ Max-Forwards (Section 6.23) and "fix up" the Via header fields with
+ "received" parameters as described in Section 6.40.1. Proxies MUST
+ NOT alter any fields that are authenticated (see Section 13.2).
+
+ The header fields required, optional and not applicable for each
+ method are listed in Table 4 and Table 5. The table uses "o" to
+ indicate optional, "m" mandatory and "-" for not applicable. A "*"
+ indicates that the header fields are needed only if message body is
+ not empty. See sections 6.15, 6.16 and 8 for details.
+
+ The "where" column describes the request and response types with
+ which the header field can be used. "R" refers to header fields that
+ can be used in requests (that is, request and general header fields).
+ "r" designates a response or general-header field as applicable to
+ all responses, while a list of numeric values indicates the status
+ codes with which the header field can be used. "g" and "e" designate
+ general (Section 6.1) and entity header (Section 6.2) fields,
+ respectively. If a header field is marked "c", it is copied from the
+ request to the response.
+
+ The "enc." column describes whether this message header field MAY be
+ encrypted end-to-end. A "n" designates fields that MUST NOT be
+ encrypted, while "c" designates fields that SHOULD be encrypted if
+ encryption is used.
+
+ The "e-e" column has a value of "e" for end-to-end and a value of "h"
+ for hop-by-hop header fields.
+
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 40]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+
+ where enc. e-e ACK BYE CAN INV OPT REG
+ __________________________________________________________
+ Accept R e - - - o o o
+ Accept 415 e - - - o o o
+ Accept-Encoding R e - - - o o o
+ Accept-Encoding 415 e - - - o o o
+ Accept-Language R e - o o o o o
+ Accept-Language 415 e - o o o o o
+ Allow 200 e - - - - m -
+ Allow 405 e o o o o o o
+ Authorization R e o o o o o o
+ Call-ID gc n e m m m m m m
+ Contact R e o - - o o o
+ Contact 1xx e - - - o o -
+ Contact 2xx e - - - o o o
+ Contact 3xx e - o - o o o
+ Contact 485 e - o - o o o
+ Content-Encoding e e o - - o o o
+ Content-Length e e o - - o o o
+ Content-Type e e * - - * * *
+ CSeq gc n e m m m m m m
+ Date g e o o o o o o
+ Encryption g n e o o o o o o
+ Expires g e - - - o - o
+ From gc n e m m m m m m
+ Hide R n h o o o o o o
+ Max-Forwards R n e o o o o o o
+ Organization g c h - - - o o o
+
+
+ Table 4: Summary of header fields, A--O
+
+ Other header fields can be added as required; a server MUST ignore
+ header fields not defined in this specification that it does not
+ understand. A proxy MUST NOT remove or modify header fields not
+ defined in this specification that it does not understand. A compact
+ form of these header fields is also defined in Section 9 for use over
+ UDP when the request has to fit into a single packet and size is an
+ issue.
+
+ Table 6 in Appendix A lists those header fields that different client
+ and server types MUST be able to parse.
+
+6.1 General Header Fields
+
+ General header fields apply to both request and response messages.
+ The "general-header" field names can be extended reliably only in
+ combination with a change in the protocol version. However, new or
+
+
+Handley, et al. Standards Track [Page 41]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+
+ where enc. e-e ACK BYE CAN INV OPT REG
+ ___________________________________________________________________
+ Proxy-Authenticate 407 n h o o o o o o
+ Proxy-Authorization R n h o o o o o o
+ Proxy-Require R n h o o o o o o
+ Priority R c e - - - o - -
+ Require R e o o o o o o
+ Retry-After R c e - - - - - o
+ Retry-After 404,480,486 c e o o o o o o
+ 503 c e o o o o o o
+ 600,603 c e o o o o o o
+ Response-Key R c e - o o o o o
+ Record-Route R h o o o o o o
+ Record-Route 2xx h o o o o o o
+ Route R h o o o o o o
+ Server r c e o o o o o o
+ Subject R c e - - - o - -
+ Timestamp g e o o o o o o
+ To gc(1) n e m m m m m m
+ Unsupported 420 e o o o o o o
+ User-Agent g c e o o o o o o
+ Via gc(2) n e m m m m m m
+ Warning r e o o o o o o
+ WWW-Authenticate 401 c e o o o o o o
+
+
+ Table 5: Summary of header fields, P--Z; (1): copied with possible
+ addition of tag; (2): UAS removes first Via header field
+
+ experimental header fields MAY be given the semantics of general
+ header fields if all parties in the communication recognize them to
+ be "general-header" fields. Unrecognized header fields are treated as
+ "entity-header" fields.
+
+6.2 Entity Header Fields
+
+ The "entity-header" fields define meta-information about the
+ message-body or, if no body is present, about the resource identified
+ by the request. The term "entity header" is an HTTP 1.1 term where
+ the response body can contain a transformed version of the message
+ body. The original message body is referred to as the "entity". We
+ retain the same terminology for header fields but usually refer to
+ the "message body" rather then the entity as the two are the same in
+ SIP.
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 42]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+6.3 Request Header Fields
+
+ The "request-header" fields allow the client to pass additional
+ information about the request, and about the client itself, to the
+ server. These fields act as request modifiers, with semantics
+ equivalent to the parameters of a programming language method
+ invocation.
+
+ The "request-header" field names can be extended reliably only in
+ combination with a change in the protocol version. However, new or
+ experimental header fields MAY be given the semantics of "request-
+ header" fields if all parties in the communication recognize them to
+ be request-header fields. Unrecognized header fields are treated as
+ "entity-header" fields.
+
+6.4 Response Header Fields
+
+ The "response-header" fields allow the server to pass additional
+ information about the response which cannot be placed in the Status-
+ Line. These header fields give information about the server and about
+ further access to the resource identified by the Request-URI.
+
+ Response-header field names can be extended reliably only in
+ combination with a change in the protocol version. However, new or
+ experimental header fields MAY be given the semantics of "response-
+ header" fields if all parties in the communication recognize them to
+ be "response-header" fields. Unrecognized header fields are treated
+ as "entity-header" fields.
+
+6.5 End-to-end and Hop-by-hop Headers
+
+ End-to-end headers MUST be transmitted unmodified across all proxies,
+ while hop-by-hop headers MAY be modified or added by proxies.
+
+6.6 Header Field Format
+
+ Header fields ("general-header", "request-header", "response-header",
+ and "entity-header") follow the same generic header format as that
+ given in Section 3.1 of RFC 822 [24]. Each header field consists of a
+ name followed by a colon (":") and the field value. Field names are
+ case-insensitive. The field value MAY be preceded by any amount of
+ leading white space (LWS), though a single space (SP) is preferred.
+ Header fields can be extended over multiple lines by preceding each
+ extra line with at least one SP or horizontal tab (HT). Applications
+ MUST follow HTTP "common form" when generating these constructs,
+ since there might exist some implementations that fail to accept
+ anything beyond the common forms.
+
+
+
+
+Handley, et al. Standards Track [Page 43]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ message-header = field-name ":" [ field-value ] CRLF
+ field-name = token
+ field-value = *( field-content | LWS )
+ field-content = < the OCTETs making up the field-value
+ and consisting of either *TEXT-UTF8
+ or combinations of token,
+ separators, and quoted-string>
+
+
+ The relative order of header fields with different field names is not
+ significant. Multiple header fields with the same field-name may be
+ present in a message if and only if the entire field-value for that
+ header field is defined as a comma-separated list (i.e., #(values)).
+ It MUST be possible to combine the multiple header fields into one
+ "field-name: field-value" pair, without changing the semantics of the
+ message, by appending each subsequent field-value to the first, each
+ separated by a comma. The order in which header fields with the same
+ field-name are received is therefore significant to the
+ interpretation of the combined field value, and thus a proxy MUST NOT
+ change the order of these field values when a message is forwarded.
+
+ Field names are not case-sensitive, although their values may be.
+
+6.7 Accept
+
+ The Accept header follows the syntax defined in [H14.1]. The
+ semantics are also identical, with the exception that if no Accept
+ header is present, the server SHOULD assume a default value of
+ application/sdp.
+
+ This request-header field is used only with the INVITE, OPTIONS and
+ REGISTER request methods to indicate what media types are acceptable
+ in the response.
+
+ Example:
+
+
+ Accept: application/sdp;level=1, application/x-private, text/html
+
+
+
+6.8 Accept-Encoding
+
+ The Accept-Encoding request-header field is similar to Accept, but
+ restricts the content-codings [H3.4.1] that are acceptable in the
+ response. See [H14.3]. The syntax of this header is defined in
+ [H14.3]. The semantics in SIP are identical to those defined in
+ [H14.3].
+
+
+
+Handley, et al. Standards Track [Page 44]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+6.9 Accept-Language
+
+ The Accept-Language header follows the syntax defined in [H14.4]. The
+ rules for ordering the languages based on the q parameter apply to
+ SIP as well. When used in SIP, the Accept-Language request-header
+ field can be used to allow the client to indicate to the server in
+ which language it would prefer to receive reason phrases, session
+ descriptions or status responses carried as message bodies. A proxy
+ MAY use this field to help select the destination for the call, for
+ example, a human operator conversant in a language spoken by the
+ caller.
+
+ Example:
+
+
+ Accept-Language: da, en-gb;q=0.8, en;q=0.7
+
+
+6.10 Allow
+
+ The Allow entity-header field lists the set of methods supported by
+ the resource identified by the Request-URI. The purpose of this field
+ is strictly to inform the recipient of valid methods associated with
+ the resource. An Allow header field MUST be present in a 405 (Method
+ Not Allowed) response and SHOULD be present in an OPTIONS response.
+
+
+
+ Allow = "Allow" ":" 1#Method
+
+
+6.11 Authorization
+
+ A user agent that wishes to authenticate itself with a server --
+ usually, but not necessarily, after receiving a 401 response -- MAY
+ do so by including an Authorization request-header field with the
+ request. The Authorization field value consists of credentials
+ containing the authentication information of the user agent for the
+ realm of the resource being requested.
+
+ Section 13.2 overviews the use of the Authorization header, and
+ section 15 describes the syntax and semantics when used with PGP
+ based authentication.
+
+
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 45]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+6.12 Call-ID
+
+ The Call-ID general-header field uniquely identifies a particular
+ invitation or all registrations of a particular client. Note that a
+ single multimedia conference can give rise to several calls with
+ different Call-IDs, e.g., if a user invites a single individual
+ several times to the same (long-running) conference.
+
+ For an INVITE request, a callee user agent server SHOULD NOT alert
+ the user if the user has responded previously to the Call-ID in the
+ INVITE request. If the user is already a member of the conference and
+ the conference parameters contained in the session description have
+ not changed, a callee user agent server MAY silently accept the call,
+ regardless of the Call-ID. An invitation for an existing Call-ID or
+ session can change the parameters of the conference. A client
+ application MAY decide to simply indicate to the user that the
+ conference parameters have been changed and accept the invitation
+ automatically or it MAY require user confirmation.
+
+ A user may be invited to the same conference or call using several
+ different Call-IDs. If desired, the client MAY use identifiers within
+ the session description to detect this duplication. For example, SDP
+ contains a session id and version number in the origin (o) field.
+
+ The REGISTER and OPTIONS methods use the Call-ID value to
+ unambiguously match requests and responses. All REGISTER requests
+ issued by a single client SHOULD use the same Call-ID, at least
+ within the same boot cycle.
+
+
+ Since the Call-ID is generated by and for SIP, there is no
+ reason to deal with the complexity of URL-encoding and
+ case-ignoring string comparison.
+
+
+
+ Call-ID = ( "Call-ID" | "i" ) ":" local-id "@" host
+ local-id = 1*uric
+
+
+ "host" SHOULD be either a fully qualified domain name or a globally
+ routable IP address. If this is the case, the "local-id" SHOULD be an
+ identifier consisting of URI characters that is unique within "host".
+ Use of cryptographically random identifiers [27] is RECOMMENDED. If,
+ however, host is not an FQDN or globally routable IP address (such as
+ a net 10 address), the local-id MUST be globally unique, as opposed
+
+
+
+
+
+Handley, et al. Standards Track [Page 46]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ to unique within host. These rules guarantee overall global
+ uniqueness of the Call-ID. The value for Call-ID MUST NOT be reused
+ for a different call. Call-IDs are case-sensitive.
+
+
+ Using cryptographically random identifiers provides some
+ protection against session hijacking. Call-ID, To and From
+ are needed to identify a call leg. The distinction between
+ call and call leg matters in calls with third-party
+ control.
+
+ For systems which have tight bandwidth constraints, many of the
+ mandatory SIP headers have a compact form, as discussed in Section 9.
+ These are alternate names for the headers which occupy less space in
+ the message. In the case of Call-ID, the compact form is i.
+
+ For example, both of the following are valid:
+
+ Call-ID: f81d4fae-7dec-11d0-a765-00a0c91e6bf6 at foo.bar.com
+
+
+ or
+
+ i:f81d4fae-7dec-11d0-a765-00a0c91e6bf6 at foo.bar.com
+
+
+
+6.13 Contact
+
+ The Contact general-header field can appear in INVITE, ACK, and
+ REGISTER requests, and in 1xx, 2xx, 3xx, and 485 responses. In
+ general, it provides a URL where the user can be reached for further
+ communications.
+
+ INVITE and ACK requests: INVITE and ACK requests MAY contain Contact
+ headers indicating from which location the request is
+ originating.
+
+
+ This allows the callee to send future requests, such as
+ BYE, directly to the caller instead of through a series of
+ proxies. The Via header is not sufficient since the
+ desired address may be that of a proxy.
+
+ INVITE 2xx responses: A user agent server sending a definitive,
+ positive response (2xx) MAY insert a Contact response header
+ field indicating the SIP address under which it is reachable
+ most directly for future SIP requests, such as ACK, within the
+
+
+
+Handley, et al. Standards Track [Page 47]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ same Call-ID. The Contact header field contains the address of
+ the server itself or that of a proxy, e.g., if the host is
+ behind a firewall. The value of this Contact header is copied
+ into the Request-URI of subsequent requests for this call if the
+ response did not also contain a Record-Route header. If the
+ response also contains a Record-Route header field, the address
+ in the Contact header field is added as the last item in the
+ Route header field. See Section 6.29 for details.
+
+
+ The Contact value SHOULD NOT be cached across calls, as it
+ may not represent the most desirable location for a
+ particular destination address.
+
+ INVITE 1xx responses: A UAS sending a provisional response (1xx) MAY
+ insert a Contact response header. It has the same semantics in a
+ 1xx response as a 2xx INVITE response. Note that CANCEL requests
+ MUST NOT be sent to that address, but rather follow the same
+ path as the original request.
+
+ REGISTER requests: REGISTER requests MAY contain a Contact header
+ field indicating at which locations the user is reachable. The
+ REGISTER request defines a wildcard Contact field, "*", which
+ MUST only be used with Expires: 0 to remove all registrations
+ for a particular user. An optional "expires" parameter indicates
+ the desired expiration time of the registration. If a Contact
+ entry does not have an "expires" parameter, the Expires header
+ field is used as the default value. If neither of these
+ mechanisms is used, SIP URIs are assumed to expire after one
+ hour. Other URI schemes have no expiration times.
+
+ REGISTER 2xx responses: A REGISTER response MAY return all locations
+ at which the user is currently reachable. An optional "expires"
+ parameter indicates the expiration time of the registration. If
+ a Contact entry does not have an "expires" parameter, the value
+ of the Expires header field indicates the expiration time. If
+ neither mechanism is used, the expiration time specified in the
+ request, explicitly or by default, is used.
+
+ 3xx and 485 responses: The Contact response-header field can be used
+ with a 3xx or 485 (Ambiguous) response codes to indicate one or
+ more alternate addresses to try. It can appear in responses to
+ BYE, INVITE and OPTIONS methods. The Contact header field
+ contains URIs giving the new locations or user names to try, or
+ may simply specify additional transport parameters. A 300
+ (Multiple Choices), 301 (Moved Permanently), 302 (Moved
+ Temporarily) or 485 (Ambiguous) response SHOULD contain a
+ Contact field containing URIs of new addresses to be tried. A
+
+
+
+Handley, et al. Standards Track [Page 48]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ 301 or 302 response may also give the same location and username
+ that was being tried but specify additional transport parameters
+ such as a different server or multicast address to try or a
+ change of SIP transport from UDP to TCP or vice versa. The
+ client copies the "user", "password", "host", "port" and "user-
+ param" elements of the Contact URI into the Request-URI of the
+ redirected request and directs the request to the address
+ specified by the "maddr" and "port" parameters, using the
+ transport protocol given in the "transport" parameter. If
+ "maddr" is a multicast address, the value of "ttl" is used as
+ the time-to-live value.
+
+ Note that the Contact header field MAY also refer to a different
+ entity than the one originally called. For example, a SIP call
+ connected to GSTN gateway may need to deliver a special information
+ announcement such as "The number you have dialed has been changed."
+
+ A Contact response header field can contain any suitable URI
+ indicating where the called party can be reached, not limited to SIP
+ URLs. For example, it could contain URL's for phones, fax, or irc (if
+ they were defined) or a mailto: (RFC 2368, [28]) URL.
+
+ The following parameters are defined. Additional parameters may be
+ defined in other specifications.
+
+ q: The "qvalue" indicates the relative preference among the locations
+ given. "qvalue" values are decimal numbers from 0 to 1, with
+ higher values indicating higher preference.
+
+ action: The "action" parameter is used only when registering with the
+ REGISTER request. It indicates whether the client wishes that
+ the server proxy or redirect future requests intended for the
+ client. If this parameter is not specified the action taken
+ depends on server configuration. In its response, the registrar
+ SHOULD indicate the mode used. This parameter is ignored for
+ other requests.
+
+ expires: The "expires" parameter indicates how long the URI is valid.
+ The parameter is either a number indicating seconds or a quoted
+ string containing a SIP-date. If this parameter is not provided,
+ the value of the Expires header field determines how long the
+ URI is valid. Implementations MAY treat values larger than
+ 2**32-1 (4294967295 seconds or 136 years) as equivalent to
+ 2**32-1.
+
+
+
+ Contact = ( "Contact" | "m" ) ":"
+ ("*" | (1# (( name-addr | addr-spec )
+ [ *( ";" contact-params ) ] [ comment ] )))
+
+ name-addr = [ display-name ] "<" addr-spec ">"
+ addr-spec = SIP-URL | URI
+ display-name = *token | quoted-string
+
+ contact-params = "q" "=" qvalue
+ | "action" "=" "proxy" | "redirect"
+ | "expires" "=" delta-seconds | <"> SIP-date <">
+ | extension-attribute
+
+ extension-attribute = extension-name [ "=" extension-value ]
+
+ only allows one address, unquoted. Since URIs can contain
+ commas and semicolons as reserved characters, they can be
+ mistaken for header or parameter delimiters, respectively.
+ The current syntax corresponds to that for the To and From
+ header, which also allows the use of display names.
+
+ Example:
+
+
+ Contact: "Mr. Watson" <sip:watson at worcester.bell-telephone.com>
+ ;q=0.7; expires=3600,
+ "Mr. Watson" <mailto:watson at bell-telephone.com> ;q=0.1
+
+
+
+6.14 Content-Encoding
+
+
+
+ Content-Encoding = ( "Content-Encoding" | "e" ) ":"
+ 1#content-coding
+
+
+ The Content-Encoding entity-header field is used as a modifier to the
+ "media-type". When present, its value indicates what additional
+ content codings have been applied to the entity-body, and thus what
+ decoding mechanisms MUST be applied in order to obtain the media-type
+ referenced by the Content-Type header field. Content-Encoding is
+ primarily used to allow a body to be compressed without losing the
+ identity of its underlying media type.
+
+ If multiple encodings have been applied to an entity, the content
+ codings MUST be listed in the order in which they were applied.
+
+ All content-coding values are case-insensitive. The Internet Assigned
+ Numbers Authority (IANA) acts as a registry for content-coding value
+ tokens. See [3.5] for a definition of the syntax for content-coding.
+
+ Clients MAY apply content encodings to the body in requests. If the
+ server is not capable of decoding the body, or does not recognize any
+ of the content-coding values, it MUST send a 415 "Unsupported Media
+ Type" response, listing acceptable encodings in the Accept-Encoding
+
+
+
+Handley, et al. Standards Track [Page 50]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ header. A server MAY apply content encodings to the bodies in
+ responses. The server MUST only use encodings listed in the Accept-
+ Encoding header in the request.
+
+6.15 Content-Length
+
+ The Content-Length entity-header field indicates the size of the
+ message-body, in decimal number of octets, sent to the recipient.
+
+
+
+ Content-Length = ( "Content-Length" | "l" ) ":" 1*DIGIT
+
+
+ An example is
+
+ Content-Length: 3495
+
+
+
+ Applications SHOULD use this field to indicate the size of the
+ message-body to be transferred, regardless of the media type of the
+ entity. Any Content-Length greater than or equal to zero is a valid
+ value. If no body is present in a message, then the Content-Length
+ header field MUST be set to zero. If a server receives a UDP request
+ without Content-Length, it MUST assume that the request encompasses
+ the remainder of the packet. If a server receives a UDP request with
+ a Content-Length, but the value is larger than the size of the body
+ sent in the request, the client SHOULD generate a 400 class response.
+ If there is additional data in the UDP packet after the last byte of
+ the body has been read, the server MUST treat the remaining data as a
+ separate message. This allows several messages to be placed in a
+ single UDP packet.
+
+ If a response does not contain a Content-Length, the client assumes
+ that it encompasses the remainder of the UDP packet or the data until
+ the TCP connection is closed, as applicable. Section 8 describes how
+ to determine the length of the message body.
+
+6.16 Content-Type
+
+ The Content-Type entity-header field indicates the media type of the
+ message-body sent to the recipient. The "media-type" element is
+ defined in [H3.7].
+
+
+
+ Content-Type = ( "Content-Type" | "c" ) ":" media-type
+
+
+
+Handley, et al. Standards Track [Page 51]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ Examples of this header field are
+
+ Content-Type: application/sdp
+ Content-Type: text/html; charset=ISO-8859-4
+
+
+
+6.17 CSeq
+
+ Clients MUST add the CSeq (command sequence) general-header field to
+ every request. A CSeq header field in a request contains the request
+ method and a single decimal sequence number chosen by the requesting
+ client, unique within a single value of Call-ID. The sequence number
+ MUST be expressible as a 32-bit unsigned integer. The initial value
+ of the sequence number is arbitrary, but MUST be less than 2**31.
+ Consecutive requests that differ in request method, headers or body,
+ but have the same Call-ID MUST contain strictly monotonically
+ increasing and contiguous sequence numbers; sequence numbers do not
+ wrap around. Retransmissions of the same request carry the same
+ sequence number, but an INVITE with a different message body or
+ different header fields (a "re-invitation") acquires a new, higher
+ sequence number. A server MUST echo the CSeq value from the request
+ in its response. If the Method value is missing in the received CSeq
+ header field, the server fills it in appropriately.
+
+ The ACK and CANCEL requests MUST contain the same CSeq value as the
+ INVITE request that it refers to, while a BYE request cancelling an
+ invitation MUST have a higher sequence number. A BYE request with a
+ CSeq that is not higher should cause a 400 response to be generated.
+
+ A user agent server MUST remember the highest sequence number for any
+ INVITE request with the same Call-ID value. The server MUST respond
+ to, and then discard, any INVITE request with a lower sequence
+ number.
+
+ All requests spawned in a parallel search have the same CSeq value as
+ the request triggering the parallel search.
+
+
+
+ CSeq = "CSeq" ":" 1*DIGIT Method
+
+
+
+ Strictly speaking, CSeq header fields are needed for any
+ SIP request that can be cancelled by a BYE or CANCEL
+ request or where a client can issue several requests for
+ the same Call-ID in close succession. Without a sequence
+
+
+
+Handley, et al. Standards Track [Page 52]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ number, the response to an INVITE could be mistaken for the
+ response to the cancellation (BYE or CANCEL). Also, if the
+ network duplicates packets or if an ACK is delayed until
+ the server has sent an additional response, the client
+ could interpret an old response as the response to a re-
+ invitation issued shortly thereafter. Using CSeq also makes
+ it easy for the server to distinguish different versions of
+ an invitation, without comparing the message body.
+
+ The Method value allows the client to distinguish the response to an
+ INVITE request from that of a CANCEL response. CANCEL requests can be
+ generated by proxies; if they were to increase the sequence number,
+ it might conflict with a later request issued by the user agent for
+ the same call.
+
+ With a length of 32 bits, a server could generate, within a single
+ call, one request a second for about 136 years before needing to wrap
+ around. The initial value of the sequence number is chosen so that
+ subsequent requests within the same call will not wrap around. A
+ non-zero initial value allows to use a time-based initial sequence
+ number, if the client desires. A client could, for example, choose
+ the 31 most significant bits of a 32-bit second clock as an initial
+ sequence number.
+
+ Forked requests MUST have the same CSeq as there would be ambiguity
+ otherwise between these forked requests and later BYE issued by the
+ client user agent.
+
+ Example:
+
+
+ CSeq: 4711 INVITE
+
+
+
+6.18 Date
+
+ Date is a general-header field. Its syntax is:
+
+
+
+ SIP-date = rfc1123-date
+
+
+ See [H14.19] for a definition of rfc1123-date. Note that unlike
+ HTTP/1.1, SIP only supports the most recent RFC1123 [29] formatting
+ for dates.
+
+
+
+
+Handley, et al. Standards Track [Page 53]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ The Date header field reflects the time when the request or response
+ is first sent. Thus, retransmissions have the same Date header field
+ value as the original.
+
+
+ The Date header field can be used by simple end systems
+ without a battery-backed clock to acquire a notion of
+ current time.
+
+6.19 Encryption
+
+ The Encryption general-header field specifies that the content has
+ been encrypted. Section 13 describes the overall SIP security
+ architecture and algorithms. This header field is intended for end-
+ to-end encryption of requests and responses. Requests are encrypted
+ based on the public key belonging to the entity named in the To
+ header field. Responses are encrypted based on the public key
+ conveyed in the Response-Key header field. Note that the public keys
+ themselves may not be used for the encryption. This depends on the
+ particular algorithms used.
+
+ For any encrypted message, at least the message body and possibly
+ other message header fields are encrypted. An application receiving a
+ request or response containing an Encryption header field decrypts
+ the body and then concatenates the plaintext to the request line and
+ headers of the original message. Message headers in the decrypted
+ part completely replace those with the same field name in the
+ plaintext part. (Note: If only the body of the message is to be
+ encrypted, the body has to be prefixed with CRLF to allow proper
+ concatenation.) Note that the request method and Request-URI cannot
+ be encrypted.
+
+
+ Encryption only provides privacy; the recipient has no
+ guarantee that the request or response came from the party
+ listed in the From message header, only that the sender
+ used the recipient's public key. However, proxies will not
+ be able to modify the request or response.
+
+
+
+ Encryption = "Encryption" ":" encryption-scheme 1*SP
+ #encryption-params
+ encryption-scheme = token
+ encryption-params = token "=" ( token | quoted-string )
+
+ The token indicates the form of encryption used; it is
+ described in section 13.
+
+
+
+Handley, et al. Standards Track [Page 54]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ The example in Figure 10 shows a message encrypted with ASCII-armored
+ PGP that was generated by applying "pgp -ea" to the payload to be
+ encrypted.
+
+
+ INVITE sip:watson at boston.bell-telephone.com SIP/2.0
+ Via: SIP/2.0/UDP 169.130.12.5
+ From: <sip:a.g.bell at bell-telephone.com>
+ To: T. A. Watson <sip:watson at bell-telephone.com>
+ Call-ID: 187602141351 at worcester.bell-telephone.com
+ Content-Length: 885
+ Encryption: PGP version=2.6.2,encoding=ascii
+
+ hQEMAxkp5GPd+j5xAQf/ZDIfGD/PDOM1wayvwdQAKgGgjmZWe+MTy9NEX8O25Red
+ h0/pyrd/+DV5C2BYs7yzSOSXaj1C/tTK/4do6rtjhP8QA3vbDdVdaFciwEVAcuXs
+ ODxlNAVqyDi1RqFC28BJIvQ5KfEkPuACKTK7WlRSBc7vNPEA3nyqZGBTwhxRSbIR
+ RuFEsHSVojdCam4htcqxGnFwD9sksqs6LIyCFaiTAhWtwcCaN437G7mUYzy2KLcA
+ zPVGq1VQg83b99zPzIxRdlZ+K7+bAnu8Rtu+ohOCMLV3TPXbyp+err1YiThCZHIu
+ X9dOVj3CMjCP66RSHa/ea0wYTRRNYA/G+kdP8DSUcqYAAAE/hZPX6nFIqk7AVnf6
+ IpWHUPTelNUJpzUp5Ou+q/5P7ZAsn+cSAuF2YWtVjCf+SQmBR13p2EYYWHoxlA2/
+ GgKADYe4M3JSwOtqwU8zUJF3FIfk7vsxmSqtUQrRQaiIhqNyG7KxJt4YjWnEjF5E
+ WUIPhvyGFMJaeQXIyGRYZAYvKKklyAJcm29zLACxU5alX4M25lHQd9FR9Zmq6Jed
+ wbWvia6cAIfsvlZ9JGocmQYF7pcuz5pnczqP+/yvRqFJtDGD/v3s++G2R+ViVYJO
+ z/lxGUZaM4IWBCf+4DUjNanZM0oxAE28NjaIZ0rrldDQmO8V9FtPKdHxkqA5iJP+
+ 6vGOFti1Ak4kmEz0vM/Nsv7kkubTFhRl05OiJIGr9S1UhenlZv9l6RuXsOY/EwH2
+ z8X9N4MhMyXEVuC9rt8/AUhmVQ==
+ =bOW+
+
+
+
+ Figure 10: PGP Encryption Example
+
+
+
+ Since proxies can base their forwarding decision on any combination
+ of SIP header fields, there is no guarantee that an encrypted request
+ "hiding" header fields will reach the same destination as an
+ otherwise identical un-encrypted request.
+
+6.20 Expires
+
+ The Expires entity-header field gives the date and time after which
+ the message content expires.
+
+ This header field is currently defined only for the REGISTER and
+ INVITE methods. For REGISTER, it is a request and response-header
+ field. In a REGISTER request, the client indicates how long it wishes
+ the registration to be valid. In the response, the server indicates
+
+
+
+Handley, et al. Standards Track [Page 55]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ the earliest expiration time of all registrations. The server MAY
+ choose a shorter time interval than that requested by the client, but
+ SHOULD NOT choose a longer one.
+
+ For INVITE requests, it is a request and response-header field. In a
+ request, the caller can limit the validity of an invitation, for
+ example, if a client wants to limit the time duration of a search or
+ a conference invitation. A user interface MAY take this as a hint to
+ leave the invitation window on the screen even if the user is not
+ currently at the workstation. This also limits the duration of a
+ search. If the request expires before the search completes, the proxy
+ returns a 408 (Request Timeout) status. In a 302 (Moved Temporarily)
+ response, a server can advise the client of the maximal duration of
+ the redirection.
+
+ The value of this field can be either a SIP-date or an integer number
+ of seconds (in decimal), measured from the receipt of the request.
+ The latter approach is preferable for short durations, as it does not
+ depend on clients and servers sharing a synchronized clock.
+ Implementations MAY treat values larger than 2**32-1 (4294967295 or
+ 136 years) as equivalent to 2**32-1.
+
+
+
+ Expires = "Expires" ":" ( SIP-date | delta-seconds )
+
+
+ Two examples of its use are
+
+ Expires: Thu, 01 Dec 1994 16:00:00 GMT
+ Expires: 5
+
+
+
+6.21 From
+
+ Requests and responses MUST contain a From general-header field,
+ indicating the initiator of the request. The From field MAY contain
+ the "tag" parameter. The server copies the From header field from the
+ request to the response. The optional "display-name" is meant to be
+ rendered by a human-user interface. A system SHOULD use the display
+ name "Anonymous" if the identity of the client is to remain hidden.
+
+ The SIP-URL MUST NOT contain the "transport-param", "maddr-param",
+ "ttl-param", or "headers" elements. A server that receives a SIP-URL
+ with these elements removes them before further processing.
+
+
+
+
+
+Handley, et al. Standards Track [Page 56]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ Even if the "display-name" is empty, the "name-addr" form MUST be
+ used if the "addr-spec" contains a comma, question mark, or
+ semicolon.
+
+
+
+ From = ( "From" | "f" ) ":" ( name-addr | addr-spec )
+ *( ";" addr-params )
+ addr-params = tag-param
+ tag-param = "tag=" UUID
+ UUID = 1*( hex | "-" )
+
+
+ Examples:
+
+
+ From: "A. G. Bell" <sip:agb at bell-telephone.com>
+ From: sip:+12125551212 at server.phone2net.com
+ From: Anonymous <sip:c8oqz84zk7z at privacy.org>
+
+
+
+ The "tag" MAY appear in the From field of a request. It MUST be
+ present when it is possible that two instances of a user sharing a
+ SIP address can make call invitations with the same Call-ID.
+
+ The "tag" value MUST be globally unique and cryptographically random
+ with at least 32 bits of randomness. A single user maintains the same
+ tag throughout the call identified by the Call-ID.
+
+
+ Call-ID, To and From are needed to identify a call leg.
+ The distinction between call and call leg matters in calls
+ with multiple responses to a forked request. The format is
+ similar to the equivalent RFC 822 [24] header, but with a
+ URI instead of just an email address.
+
+6.22 Hide
+
+ A client uses the Hide request header field to indicate that it wants
+ the path comprised of the Via header fields (Section 6.40) to be
+ hidden from subsequent proxies and user agents. It can take two
+ forms: Hide: route and Hide: hop. Hide header fields are typically
+ added by the client user agent, but MAY be added by any proxy along
+ the path.
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 57]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ If a request contains the "Hide: route" header field, all following
+ proxies SHOULD hide their previous hop. If a request contains the
+ "Hide: hop" header field, only the next proxy SHOULD hide the
+ previous hop and then remove the Hide option unless it also wants to
+ remain anonymous.
+
+ A server hides the previous hop by encrypting the "host" and "port"
+ parts of the top-most Via header field with an algorithm of its
+ choice. Servers SHOULD add additional "salt" to the "host" and "port"
+ information prior to encryption to prevent malicious downstream
+ proxies from guessing earlier parts of the path based on seeing
+ identical encrypted Via headers. Hidden Via fields are marked with
+ the "hidden" Via option, as described in Section 6.40.
+
+ A server that is capable of hiding Via headers MUST attempt to
+ decrypt all Via headers marked as "hidden" to perform loop detection.
+ Servers that are not capable of hiding can ignore hidden Via fields
+ in their loop detection algorithm.
+
+
+ If hidden headers were not marked, a proxy would have to
+ decrypt all headers to detect loops, just in case one was
+ encrypted, as the Hide: Hop option may have been removed
+ along the way.
+
+ A host MUST NOT add such a "Hide: hop" header field unless it can
+ guarantee it will only send a request for this destination to the
+ same next hop. The reason for this is that it is possible that the
+ request will loop back through this same hop from a downstream proxy.
+ The loop will be detected by the next hop if the choice of next hop
+ is fixed, but could loop an arbitrary number of times otherwise.
+
+ A client requesting "Hide: route" can only rely on keeping the
+ request path private if it sends the request to a trusted proxy.
+ Hiding the route of a SIP request is of limited value if the request
+ results in data packets being exchanged directly between the calling
+ and called user agent.
+
+ The use of Hide header fields is discouraged unless path privacy is
+ truly needed; Hide fields impose extra processing costs and
+ restrictions for proxies and can cause requests to generate 482 (Loop
+ Detected) responses that could otherwise be avoided.
+
+ The encryption of Via header fields is described in more detail in
+ Section 13.
+
+ The Hide header field has the following syntax:
+
+
+
+
+Handley, et al. Standards Track [Page 58]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ Hide = "Hide" ":" ( "route" | "hop" )
+
+
+6.23 Max-Forwards
+
+ The Max-Forwards request-header field may be used with any SIP method
+ to limit the number of proxies or gateways that can forward the
+ request to the next downstream server. This can also be useful when
+ the client is attempting to trace a request chain which appears to be
+ failing or looping in mid-chain.
+
+
+
+ Max-Forwards = "Max-Forwards" ":" 1*DIGIT
+
+
+ The Max-Forwards value is a decimal integer indicating the remaining
+ number of times this request message is allowed to be forwarded.
+
+ Each proxy or gateway recipient of a request containing a Max-
+ Forwards header field MUST check and update its value prior to
+ forwarding the request. If the received value is zero (0), the
+ recipient MUST NOT forward the request. Instead, for the OPTIONS and
+ REGISTER methods, it MUST respond as the final recipient. For all
+ other methods, the server returns 483 (Too many hops).
+
+ If the received Max-Forwards value is greater than zero, then the
+ forwarded message MUST contain an updated Max-Forwards field with a
+ value decremented by one (1).
+
+ Example:
+
+ Max-Forwards: 6
+
+
+
+6.24 Organization
+
+ The Organization general-header field conveys the name of the
+ organization to which the entity issuing the request or response
+ belongs. It MAY also be inserted by proxies at the boundary of an
+ organization.
+
+
+ The field MAY be used by client software to filter calls.
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 59]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ Organization = "Organization" ":" *TEXT-UTF8
+
+
+6.25 Priority
+
+ The Priority request-header field indicates the urgency of the
+ request as perceived by the client.
+
+
+
+ Priority = "Priority" ":" priority-value
+ priority-value = "emergency" | "urgent" | "normal"
+ | "non-urgent"
+
+
+ It is RECOMMENDED that the value of "emergency" only be used when
+ life, limb or property are in imminent danger.
+
+ Examples:
+
+
+ Subject: A tornado is heading our way!
+ Priority: emergency
+
+ Subject: Weekend plans
+ Priority: non-urgent
+
+
+
+
+ These are the values of RFC 2076 [30], with the addition of
+ "emergency".
+
+6.26 Proxy-Authenticate
+
+ The Proxy-Authenticate response-header field MUST be included as part
+ of a 407 (Proxy Authentication Required) response. The field value
+ consists of a challenge that indicates the authentication scheme and
+ parameters applicable to the proxy for this Request-URI.
+
+ Unlike its usage within HTTP, the Proxy-Authenticate header MUST be
+ passed upstream in the response to the UAC. In SIP, only UAC's can
+ authenticate themselves to proxies.
+
+ The syntax for this header is defined in [H14.33]. See 14 for further
+ details on its usage.
+
+
+
+
+
+Handley, et al. Standards Track [Page 60]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ A client SHOULD cache the credentials used for a particular proxy
+ server and realm for the next request to that server. Credentials
+ are, in general, valid for a specific value of the Request-URI at a
+ particular proxy server. If a client contacts a proxy server that has
+ required authentication in the past, but the client does not have
+ credentials for the particular Request-URI, it MAY attempt to use the
+ most-recently used credential. The server responds with 401
+ (Unauthorized) if the client guessed wrong.
+
+
+ This suggested caching behavior is motivated by proxies
+ restricting phone calls to authenticated users. It seems
+ likely that in most cases, all destinations require the
+ same password. Note that end-to-end authentication is
+ likely to be destination-specific.
+
+6.27 Proxy-Authorization
+
+ The Proxy-Authorization request-header field allows the client to
+ identify itself (or its user) to a proxy which requires
+ authentication. The Proxy-Authorization field value consists of
+ credentials containing the authentication information of the user
+ agent for the proxy and/or realm of the resource being requested.
+
+ Unlike Authorization, the Proxy-Authorization header field applies
+ only to the next outbound proxy that demanded authentication using
+ the Proxy- Authenticate field. When multiple proxies are used in a
+ chain, the Proxy-Authorization header field is consumed by the first
+ outbound proxy that was expecting to receive credentials. A proxy MAY
+ relay the credentials from the client request to the next proxy if
+ that is the mechanism by which the proxies cooperatively authenticate
+ a given request.
+
+ See [H14.34] for a definition of the syntax, and section 14 for a
+ discussion of its usage.
+
+6.28 Proxy-Require
+
+ The Proxy-Require header field is used to indicate proxy-sensitive
+ features that MUST be supported by the proxy. Any Proxy-Require
+ header field features that are not supported by the proxy MUST be
+ negatively acknowledged by the proxy to the client if not supported.
+ Proxy servers treat this field identically to the Require field.
+
+ See Section 6.30 for more details on the mechanics of this message
+ and a usage example.
+
+
+
+
+
+Handley, et al. Standards Track [Page 61]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+6.29 Record-Route
+
+ The Record-Route request and response header field is added to a
+ request by any proxy that insists on being in the path of subsequent
+ requests for the same call leg. It contains a globally reachable
+ Request-URI that identifies the proxy server. Each proxy server adds
+ its Request-URI to the beginning of the list.
+
+ The server copies the Record-Route header field unchanged into the
+ response. (Record-Route is only relevant for 2xx responses.)
+
+ The calling user agent client copies the Record-Route header into a
+ Route header field of subsequent requests within the same call leg,
+ reversing the order of requests, so that the first entry is closest
+ to the user agent client. If the response contained a Contact header
+ field, the calling user agent adds its content as the last Route
+ header. Unless this would cause a loop, any client MUST send any
+ subsequent requests for this call leg to the first Request-URI in the
+ Route request header field and remove that entry.
+
+ The calling user agent MUST NOT use the Record-Route header field in
+ requests that contain Route header fields.
+
+
+ Some proxies, such as those controlling firewalls or in an
+ automatic call distribution (ACD) system, need to maintain
+ call state and thus need to receive any BYE and ACK packets
+ for the call.
+
+ The Record-Route header field has the following syntax:
+
+
+ Record-Route = "Record-Route" ":" 1# name-addr
+
+
+ Proxy servers SHOULD use the "maddr" URL parameter containing their
+ address to ensure that subsequent requests are guaranteed to reach
+ exactly the same server.
+
+ Example for a request that has traversed the hosts ieee.org and
+ bell-telephone.com , in that order:
+
+ Record-Route: <sip:a.g.bell at bell-telephone.com>,
+ <sip:a.bell at ieee.org>
+
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 62]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+6.30 Require
+
+ The Require request-header field is used by clients to tell user
+ agent servers about options that the client expects the server to
+ support in order to properly process the request. If a server does
+ not understand the option, it MUST respond by returning status code
+ 420 (Bad Extension) and list those options it does not understand in
+ the Unsupported header.
+
+
+
+ Require = "Require" ":" 1#option-tag
+
+
+ Example:
+
+ C->S: INVITE sip:watson at bell-telephone.com SIP/2.0
+ Require: com.example.billing
+ Payment: sheep_skins, conch_shells
+
+ S->C: SIP/2.0 420 Bad Extension
+ Unsupported: com.example.billing
+
+
+
+ This is to make sure that the client-server interaction
+ will proceed without delay when all options are understood
+ by both sides, and only slow down if options are not
+ understood (as in the example above). For a well-matched
+ client-server pair, the interaction proceeds quickly,
+ saving a round-trip often required by negotiation
+ mechanisms. In addition, it also removes ambiguity when the
+ client requires features that the server does not
+ understand. Some features, such as call handling fields,
+ are only of interest to end systems.
+
+ Proxy and redirect servers MUST ignore features that are not
+ understood. If a particular extension requires that intermediate
+ devices support it, the extension MUST be tagged in the Proxy-Require
+ field as well (see Section 6.28).
+
+6.31 Response-Key
+
+ The Response-Key request-header field can be used by a client to
+ request the key that the called user agent SHOULD use to encrypt the
+ response with. The syntax is:
+
+
+
+
+
+Handley, et al. Standards Track [Page 63]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ Response-Key = "Response-Key" ":" key-scheme 1*SP #key-param
+ key-scheme = token
+ key-param = token "=" ( token | quoted-string )
+
+
+ The "key-scheme" gives the type of encryption to be used for the
+ response. Section 13 describes security schemes.
+
+ If the client insists that the server return an encrypted response,
+ it includes a
+
+ Require: org.ietf.sip.encrypt-response
+
+ header field in its request. If the server cannot encrypt for
+ whatever reason, it MUST follow normal Require header field
+ procedures and return a 420 (Bad Extension) response. If this Require
+ header field is not present, a server SHOULD still encrypt if it can.
+
+6.32 Retry-After
+
+ The Retry-After general-header field can be used with a 503 (Service
+ Unavailable) response to indicate how long the service is expected to
+ be unavailable to the requesting client and with a 404 (Not Found),
+ 600 (Busy), or 603 (Decline) response to indicate when the called
+ party anticipates being available again. The value of this field can
+ be either an SIP-date or an integer number of seconds (in decimal)
+ after the time of the response.
+
+ A REGISTER request MAY include this header field when deleting
+ registrations with "Contact: * ;expires: 0". The Retry-After value
+ then indicates when the user might again be reachable. The registrar
+ MAY then include this information in responses to future calls.
+
+ An optional comment can be used to indicate additional information
+ about the time of callback. An optional "duration" parameter
+ indicates how long the called party will be reachable starting at the
+ initial time of availability. If no duration parameter is given, the
+ service is assumed to be available indefinitely.
+
+
+
+ Retry-After = "Retry-After" ":" ( SIP-date | delta-seconds )
+ [ comment ] [ ";" "duration" "=" delta-seconds ]
+
+
+ Examples of its use are
+
+ Retry-After: Mon, 21 Jul 1997 18:48:34 GMT (I'm in a meeting)
+
+
+
+Handley, et al. Standards Track [Page 64]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ Retry-After: Mon, 01 Jan 9999 00:00:00 GMT
+ (Dear John: Don't call me back, ever)
+ Retry-After: Fri, 26 Sep 1997 21:00:00 GMT;duration=3600
+ Retry-After: 120
+
+
+
+ In the third example, the callee is reachable for one hour starting
+ at 21:00 GMT. In the last example, the delay is 2 minutes.
+
+6.33 Route
+
+ The Route request-header field determines the route taken by a
+ request. Each host removes the first entry and then proxies the
+ request to the host listed in that entry, also using it as the
+ Request-URI. The operation is further described in Section 6.29.
+
+ The Route header field has the following syntax:
+
+
+ Route = "Route" ":" 1# name-addr
+
+
+6.34 Server
+
+ The Server response-header field contains information about the
+ software used by the user agent server to handle the request. The
+ syntax for this field is defined in [H14.39].
+
+6.35 Subject
+
+ This is intended to provide a summary, or to indicate the nature, of
+ the call, allowing call filtering without having to parse the session
+ description. (Also, the session description does not have to use the
+ same subject indication as the invitation.)
+
+
+
+ Subject = ( "Subject" | "s" ) ":" *TEXT-UTF8
+
+
+ Example:
+
+
+ Subject: Tune in - they are talking about your work!
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 65]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+6.36 Timestamp
+
+ The timestamp general-header field describes when the client sent the
+ request to the server. The value of the timestamp is of significance
+ only to the client and it MAY use any timescale. The server MUST echo
+ the exact same value and MAY, if it has accurate information about
+ this, add a floating point number indicating the number of seconds
+ that have elapsed since it has received the request. The timestamp is
+ used by the client to compute the round-trip time to the server so
+ that it can adjust the timeout value for retransmissions.
+
+
+
+ Timestamp = "Timestamp" ":" *(DIGIT) [ "." *(DIGIT) ] [ delay ]
+ delay = *(DIGIT) [ "." *(DIGIT) ]
+
+
+ Note that there MUST NOT be any LWS between a DIGIT and the decimal
+ point.
+
+6.37 To
+
+ The To general-header field specifies recipient of the request, with
+ the same SIP URL syntax as the From field.
+
+
+
+ To = ( "To" | "t" ) ":" ( name-addr | addr-spec )
+ *( ";" addr-params )
+
+
+ Requests and responses MUST contain a To general-header field,
+ indicating the desired recipient of the request. The optional
+ "display-name" is meant to be rendered by a human-user interface.
+ The UAS or redirect server copies the To header field into its
+ response, and MUST add a "tag" parameter if the request contained
+ more than one Via header field.
+
+
+ If there was more than one Via header field, the request
+ was handled by at least one proxy server. Since the
+ receiver cannot know whether any of the proxy servers
+ forked the request, it is safest to assume that they might
+ have.
+
+ The SIP-URL MUST NOT contain the "transport-param", "maddr-param",
+ "ttl-param", or "headers" elements. A server that receives a SIP-URL
+ with these elements removes them before further processing.
+
+
+
+Handley, et al. Standards Track [Page 66]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ The "tag" parameter serves as a general mechanism to distinguish
+ multiple instances of a user identified by a single SIP URL. As
+ proxies can fork requests, the same request can reach multiple
+ instances of a user (mobile and home phones, for example). As each
+ can respond, there needs to be a means to distinguish the responses
+ from each at the caller. The situation also arises with multicast
+ requests. The tag in the To header field serves to distinguish
+ responses at the UAC. It MUST be placed in the To field of the
+ response by each instance when there is a possibility that the
+ request was forked at an intermediate proxy. The "tag" MUST be added
+ by UAS, registrars and redirect servers, but MUST NOT be inserted
+ into responses forwarded upstream by proxies. The "tag" is added for
+ all definitive responses for all methods, and MAY be added for
+ informational responses from a UAS or redirect server. All subsequent
+ transactions between two entities MUST include the "tag" parameter,
+ as described in Section 11.
+
+ See Section 6.21 for details of the "tag" parameter.
+
+ The "tag" parameter in To headers is ignored when matching responses
+ to requests that did not contain a "tag" in their To header.
+
+ A SIP server returns a 400 (Bad Request) response if it receives a
+ request with a To header field containing a URI with a scheme it does
+ not recognize.
+
+ Even if the "display-name" is empty, the "name-addr" form MUST be
+ used if the "addr-spec" contains a comma, question mark, or
+ semicolon.
+
+ The following are examples of valid To headers:
+
+ To: The Operator <sip:operator at cs.columbia.edu>;tag=287447
+ To: sip:+12125551212 at server.phone2net.com
+
+
+
+
+ Call-ID, To and From are needed to identify a call leg.
+ The distinction between call and call leg matters in calls
+ with multiple responses from a forked request. The "tag" is
+ added to the To header field in the response to allow
+ forking of future requests for the same call by proxies,
+ while addressing only one of the possibly several
+ responding user agent servers. It also allows several
+ instances of the callee to send requests that can be
+ distinguished.
+
+
+
+
+Handley, et al. Standards Track [Page 67]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+6.38 Unsupported
+
+ The Unsupported response-header field lists the features not
+ supported by the server. See Section 6.30 for a usage example and
+ motivation.
+
+ Syntax:
+
+
+
+ Unsupported = "Unsupported" ":" 1#option-tag
+
+
+6.39 User-Agent
+
+ The User-Agent general-header field contains information about the
+ client user agent originating the request. The syntax and semantics
+ are defined in [H14.42].
+
+6.40 Via
+
+ The Via field indicates the path taken by the request so far. This
+ prevents request looping and ensures replies take the same path as
+ the requests, which assists in firewall traversal and other unusual
+ routing situations.
+
+6.40.1 Requests
+
+ The client originating the request MUST insert into the request a Via
+ field containing its host name or network address and, if not the
+ default port number, the port number at which it wishes to receive
+ responses. (Note that this port number can differ from the UDP source
+ port number of the request.) A fully-qualified domain name is
+ RECOMMENDED. Each subsequent proxy server that sends the request
+ onwards MUST add its own additional Via field before any existing Via
+ fields. A proxy that receives a redirection (3xx) response and then
+ searches recursively, MUST use the same Via headers as on the
+ original proxied request.
+
+ A proxy SHOULD check the top-most Via header field to ensure that it
+ contains the sender's correct network address, as seen from that
+ proxy. If the sender's address is incorrect, the proxy MUST add an
+ additional "received" attribute, as described 6.40.2.
+
+
+ A host behind a network address translator (NAT) or
+ firewall may not be able to insert a network address into
+ the Via header that can be reached by the next hop beyond
+
+
+
+Handley, et al. Standards Track [Page 68]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ the NAT. Use of the received attribute allows SIP requests
+ to traverse NAT's which only modify the source IP address.
+ NAT's which modify port numbers, called Network Address
+ Port Translator's (NAPT) will not properly pass SIP when
+ transported on UDP, in which case an application layer
+ gateway is required. When run over TCP, SIP stands a better
+ chance of traversing NAT's, since its behavior is similar
+ to HTTP in this case (but of course on different ports).
+
+ A proxy sending a request to a multicast address MUST add the "maddr"
+ parameter to its Via header field, and SHOULD add the "ttl"
+ parameter. If a server receives a request which contained an "maddr"
+ parameter in the topmost Via field, it SHOULD send the response to
+ the multicast address listed in the "maddr" parameter.
+
+ If a proxy server receives a request which contains its own address
+ in the Via header value, it MUST respond with a 482 (Loop Detected)
+ status code.
+
+ A proxy server MUST NOT forward a request to a multicast group which
+ already appears in any of the Via headers.
+
+
+ This prevents a malfunctioning proxy server from causing
+ loops. Also, it cannot be guaranteed that a proxy server
+ can always detect that the address returned by a location
+ service refers to a host listed in the Via list, as a
+ single host may have aliases or several network interfaces.
+
+6.40.2 Receiver-tagged Via Header Fields
+
+ Normally, every host that sends or forwards a SIP message adds a Via
+ field indicating the path traversed. However, it is possible that
+ Network Address Translators (NATs) changes the source address and
+ port of the request (e.g., from net-10 to a globally routable
+ address), in which case the Via header field cannot be relied on to
+ route replies. To prevent this, a proxy SHOULD check the top-most Via
+ header field to ensure that it contains the sender's correct network
+ address, as seen from that proxy. If the sender's address is
+ incorrect, the proxy MUST add a "received" parameter to the Via
+ header field inserted by the previous hop. Such a modified Via header
+ field is known as a receiver-tagged Via header field. An example is:
+
+
+ Via: SIP/2.0/UDP erlang.bell-telephone.com:5060
+ Via: SIP/2.0/UDP 10.0.0.1:5060 ;received=199.172.136.3
+
+
+
+
+
+Handley, et al. Standards Track [Page 69]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ In this example, the message originated from 10.0.0.1 and traversed a
+ NAT with the external address border.ieee.org (199.172.136.3) to
+ reach erlang.bell-telephone.com. The latter noticed the mismatch,
+ and added a parameter to the previous hop's Via header field,
+ containing the address that the packet actually came from. (Note that
+ the NAT border.ieee.org is not a SIP server.)
+
+6.40.3 Responses
+
+ Via header fields in responses are processed by a proxy or UAC
+ according to the following rules:
+
+ 1. The first Via header field should indicate the proxy or
+ client processing this response. If it does not, discard
+ the message. Otherwise, remove this Via field.
+
+ 2. If there is no second Via header field, this response is
+ destined for this client. Otherwise, the processing depends
+ on whether the Via field contains a "maddr" parameter or is
+ a receiver-tagged field:
+
+ - If the second Via header field contains a "maddr"
+ parameter, send the response to the multicast address
+ listed there, using the port indicated in "sent-by", or
+ port 5060 if none is present. The response SHOULD be sent
+ using the TTL indicated in the "ttl" parameter, or with a
+ TTL of 1 if that parameter is not present. For
+ robustness, responses MUST be sent to the address
+ indicated in the "maddr" parameter even if it is not a
+ multicast address.
+
+ - If the second Via header field does not contain a "maddr"
+ parameter and is a receiver-tagged field (Section
+ 6.40.2), send the message to the address in the
+ "received" parameter, using the port indicated in the
+ "sent-by" value, or using port 5060 if none is present.
+
+ - If neither of the previous cases apply, send the message
+ to the address indicated by the "sent-by" value in the
+ second Via header field.
+
+6.40.4 User Agent and Redirect Servers
+
+ A UAS or redirect server sends a response based on one of the
+ following rules:
+
+ o If the first Via header field in the request contains a
+ "maddr" parameter, send the response to the multicast address
+
+
+
+Handley, et al. Standards Track [Page 70]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ listed there, using the port indicated in "sent-by", or port
+ 5060 if none is present. The response SHOULD be sent using the
+ TTL indicated in the "ttl" parameter, or with a TTL of 1 if
+ that parameter is not present. For robustness, responses MUST
+ be sent to the address indicated in the "maddr" parameter even
+ if it is not a multicast address.
+
+ o If the address in the "sent-by" value of the first Via field
+ differs from the source address of the packet, send the
+ response to the actual packet source address, similar to the
+ treatment for receiver-tagged Via header fields (Section
+ 6.40.2).
+
+ o If neither of these conditions is true, send the response to
+ the address contained in the "sent-by" value. If the request
+ was sent using TCP, use the existing TCP connection if
+ available.
+
+6.40.5 Syntax
+
+ The format for a Via header field is shown in Fig. 11. The defaults
+ for "protocol-name" and "transport" are "SIP" and "UDP",
+ respectively. The "maddr" parameter, designating the multicast
+ address, and the "ttl" parameter, designating the time-to-live (TTL)
+ value, are included only if the request was sent via multicast. The
+ "received" parameter is added only for receiver-added Via fields
+ (Section 6.40.2). For reasons of privacy, a client or proxy may wish
+ to hide its Via information by encrypting it (see Section 6.22). The
+ "hidden" parameter is included if this header field was hidden by the
+ upstream proxy (see 6.22). Note that privacy of the proxy relies on
+ the cooperation of the next hop, as the next-hop proxy will, by
+ necessity, know the IP address and port number of the source host.
+
+
+ The "branch" parameter is included by every forking proxy. The token
+ MUST be unique for each distinct request generated when a proxy
+ forks. CANCEL requests MUST have the same branch value as the
+ corresponding forked request. When a response arrives at the proxy it
+ can use the branch value to figure out which branch the response
+ corresponds to. A proxy which generates a single request (non-
+ forking) MAY also insert the "branch" parameter. The identifier has
+ to be unique only within a set of isomorphic requests.
+
+
+ Via: SIP/2.0/UDP first.example.com:4000;ttl=16
+ ;maddr=224.2.0.1 ;branch=a7c6a8dlze (Example)
+ Via: SIP/2.0/UDP adk8
+
+
+
+
+Handley, et al. Standards Track [Page 71]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+
+
+ Via = ( "Via" | "v") ":" 1#( sent-protocol sent-by
+ *( ";" via-params ) [ comment ] )
+ via-params = via-hidden | via-ttl | via-maddr
+ | via-received | via-branch
+ via-hidden = "hidden"
+ via-ttl = "ttl" "=" ttl
+ via-maddr = "maddr" "=" maddr
+ via-received = "received" "=" host
+ via-branch = "branch" "=" token
+ sent-protocol = protocol-name "/" protocol-version "/" transport
+ protocol-name = "SIP" | token
+ protocol-version = token
+ transport = "UDP" | "TCP" | token
+ sent-by = ( host [ ":" port ] ) | ( concealed-host )
+ concealed-host = token
+ ttl = 1*3DIGIT ; 0 to 255
+
+
+ Figure 11: Syntax of Via header field
+
+
+6.41 Warning
+
+ The Warning response-header field is used to carry additional
+ information about the status of a response. Warning headers are sent
+ with responses and have the following format:
+
+
+
+ Warning = "Warning" ":" 1#warning-value
+ warning-value = warn-code SP warn-agent SP warn-text
+ warn-code = 3DIGIT
+ warn-agent = ( host [ ":" port ] ) | pseudonym
+ ; the name or pseudonym of the server adding
+ ; the Warning header, for use in debugging
+ warn-text = quoted-string
+
+
+ A response MAY carry more than one Warning header.
+
+ The "warn-text" should be in a natural language that is most likely
+ to be intelligible to the human user receiving the response. This
+ decision can be based on any available knowledge, such as the
+ location of the cache or user, the Accept-Language field in a
+ request, or the Content-Language field in a response. The default
+ language is i-default [31].
+
+
+
+Handley, et al. Standards Track [Page 72]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ Any server MAY add Warning headers to a response. Proxy servers MUST
+ place additional Warning headers before any Authorization headers.
+ Within that constraint, Warning headers MUST be added after any
+ existing Warning headers not covered by a signature. A proxy server
+ MUST NOT delete any Warning header field that it received with a
+ response.
+
+ When multiple Warning headers are attached to a response, the user
+ agent SHOULD display as many of them as possible, in the order that
+ they appear in the response. If it is not possible to display all of
+ the warnings, the user agent first displays warnings that appear
+ early in the response.
+
+ The warn-code consists of three digits. A first digit of "3"
+ indicates warnings specific to SIP.
+
+ This is a list of the currently-defined "warn-code"s, each with a
+ recommended warn-text in English, and a description of its meaning.
+ Note that these warnings describe failures induced by the session
+ description.
+
+ Warnings 300 through 329 are reserved for indicating problems with
+ keywords in the session description, 330 through 339 are warnings
+ related to basic network services requested in the session
+ description, 370 through 379 are warnings related to quantitative QoS
+ parameters requested in the session description, and 390 through 399
+ are miscellaneous warnings that do not fall into one of the above
+ categories.
+
+ 300 Incompatible network protocol: One or more network protocols
+ contained in the session description are not available.
+
+ 301 Incompatible network address formats: One or more network address
+ formats contained in the session description are not available.
+
+ 302 Incompatible transport protocol: One or more transport protocols
+ described in the session description are not available.
+
+ 303 Incompatible bandwidth units: One or more bandwidth measurement
+ units contained in the session description were not understood.
+
+ 304 Media type not available: One or more media types contained in
+ the session description are not available.
+
+ 305 Incompatible media format: One or more media formats contained in
+ the session description are not available.
+
+
+
+
+
+Handley, et al. Standards Track [Page 73]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ 306 Attribute not understood: One or more of the media attributes in
+ the session description are not supported.
+
+ 307 Session description parameter not understood: A parameter other
+ than those listed above was not understood.
+
+ 330 Multicast not available: The site where the user is located does
+ not support multicast.
+
+ 331 Unicast not available: The site where the user is located does
+ not support unicast communication (usually due to the presence
+ of a firewall).
+
+ 370 Insufficient bandwidth: The bandwidth specified in the session
+ description or defined by the media exceeds that known to be
+ available.
+
+ 399 Miscellaneous warning: The warning text can include arbitrary
+ information to be presented to a human user, or logged. A system
+ receiving this warning MUST NOT take any automated action.
+
+
+ 1xx and 2xx have been taken by HTTP/1.1.
+
+ Additional "warn-code"s, as in the example below, can be defined
+ through IANA.
+
+ Examples:
+
+
+ Warning: 307 isi.edu "Session parameter 'foo' not understood"
+ Warning: 301 isi.edu "Incompatible network address type 'E.164'"
+
+
+
+6.42 WWW-Authenticate
+
+ The WWW-Authenticate response-header field MUST be included in 401
+ (Unauthorized) response messages. The field value consists of at
+ least one challenge that indicates the authentication scheme(s) and
+ parameters applicable to the Request-URI. See [H14.46] for a
+ definition of the syntax, and section 14 for an overview of usage.
+
+ The content of the "realm" parameter SHOULD be displayed to the user.
+ A user agent SHOULD cache the authorization credentials for a given
+ value of the destination (To header) and "realm" and attempt to re-
+ use these values on the next request for that destination.
+
+
+
+
+Handley, et al. Standards Track [Page 74]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ In addition to the "basic" and "digest" authentication schemes
+ defined in the specifications cited above, SIP defines a new scheme,
+ PGP (RFC 2015, [32]), Section 15. Other schemes, such as S/MIME, are
+ for further study.
+
+7 Status Code Definitions
+
+ The response codes are consistent with, and extend, HTTP/1.1 response
+ codes. Not all HTTP/1.1 response codes are appropriate, and only
+ those that are appropriate are given here. Other HTTP/1.1 response
+ codes SHOULD NOT be used. Response codes not defined by HTTP/1.1 have
+ codes x80 upwards to avoid clashes with future HTTP response codes.
+ Also, SIP defines a new class, 6xx. The default behavior for unknown
+ response codes is given for each category of codes.
+
+7.1 Informational 1xx
+
+ Informational responses indicate that the server or proxy contacted
+ is performing some further action and does not yet have a definitive
+ response. The client SHOULD wait for a further response from the
+ server, and the server SHOULD send such a response without further
+ prompting. A server SHOULD send a 1xx response if it expects to take
+ more than 200 ms to obtain a final response. A server MAY issue zero
+ or more 1xx responses, with no restriction on their ordering or
+ uniqueness. Note that 1xx responses are not transmitted reliably,
+ that is, they do not cause the client to send an ACK. Servers are
+ free to retransmit informational responses and clients can inquire
+ about the current state of call processing by re-sending the request.
+
+7.1.1 100 Trying
+
+ Some unspecified action is being taken on behalf of this call (e.g.,
+ a database is being consulted), but the user has not yet been
+ located.
+
+7.1.2 180 Ringing
+
+ The called user agent has located a possible location where the user
+ has registered recently and is trying to alert the user.
+
+7.1.3 181 Call Is Being Forwarded
+
+ A proxy server MAY use this status code to indicate that the call is
+ being forwarded to a different set of destinations.
+
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 75]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+7.1.4 182 Queued
+
+ The called party is temporarily unavailable, but the callee has
+ decided to queue the call rather than reject it. When the callee
+ becomes available, it will return the appropriate final status
+ response. The reason phrase MAY give further details about the status
+ of the call, e.g., "5 calls queued; expected waiting time is 15
+ minutes". The server MAY issue several 182 responses to update the
+ caller about the status of the queued call.
+
+7.2 Successful 2xx
+
+ The request was successful and MUST terminate a search.
+
+7.2.1 200 OK
+
+ The request has succeeded. The information returned with the response
+ depends on the method used in the request, for example:
+
+ BYE: The call has been terminated. The message body is empty.
+
+ CANCEL: The search has been cancelled. The message body is empty.
+
+ INVITE: The callee has agreed to participate; the message body
+ indicates the callee's capabilities.
+
+ OPTIONS: The callee has agreed to share its capabilities, included in
+ the message body.
+
+ REGISTER: The registration has succeeded. The client treats the
+ message body according to its Content-Type.
+
+7.3 Redirection 3xx
+
+ 3xx responses give information about the user's new location, or
+ about alternative services that might be able to satisfy the call.
+ They SHOULD terminate an existing search, and MAY cause the initiator
+ to begin a new search if appropriate.
+
+ Any redirection (3xx) response MUST NOT suggest any of the addresses
+ in the Via (Section 6.40) path of the request in the Contact header
+ field. (Addresses match if their host and port number match.)
+
+ To avoid forwarding loops, a user agent client or proxy MUST check
+ whether the address returned by a redirect server equals an address
+ tried earlier.
+
+
+
+
+
+Handley, et al. Standards Track [Page 76]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+7.3.1 300 Multiple Choices
+
+ The address in the request resolved to several choices, each with its
+ own specific location, and the user (or user agent) can select a
+ preferred communication end point and redirect its request to that
+ location.
+
+ The response SHOULD include an entity containing a list of resource
+ characteristics and location(s) from which the user or user agent can
+ choose the one most appropriate, if allowed by the Accept request
+ header. The entity format is specified by the media type given in the
+ Content-Type header field. The choices SHOULD also be listed as
+ Contact fields (Section 6.13). Unlike HTTP, the SIP response MAY
+ contain several Contact fields or a list of addresses in a Contact
+ field. User agents MAY use the Contact header field value for
+ automatic redirection or MAY ask the user to confirm a choice.
+ However, this specification does not define any standard for such
+ automatic selection.
+
+
+ This status response is appropriate if the callee can be
+ reached at several different locations and the server
+ cannot or prefers not to proxy the request.
+
+7.3.2 301 Moved Permanently
+
+ The user can no longer be found at the address in the Request-URI and
+ the requesting client SHOULD retry at the new address given by the
+ Contact header field (Section 6.13). The caller SHOULD update any
+ local directories, address books and user location caches with this
+ new value and redirect future requests to the address(es) listed.
+
+7.3.3 302 Moved Temporarily
+
+ The requesting client SHOULD retry the request at the new address(es)
+ given by the Contact header field (Section 6.13). The duration of
+ the redirection can be indicated through an Expires (Section 6.20)
+ header. If there is no explicit expiration time, the address is only
+ valid for this call and MUST NOT be cached for future calls.
+
+7.3.4 305 Use Proxy
+
+ The requested resource MUST be accessed through the proxy given by
+ the Contact field. The Contact field gives the URI of the proxy. The
+ recipient is expected to repeat this single request via the proxy.
+ 305 responses MUST only be generated by user agent servers.
+
+
+
+
+
+Handley, et al. Standards Track [Page 77]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+7.3.5 380 Alternative Service
+
+ The call was not successful, but alternative services are possible.
+ The alternative services are described in the message body of the
+ response. Formats for such bodies are not defined here, and may be
+ the subject of future standardization.
+
+7.4 Request Failure 4xx
+
+ 4xx responses are definite failure responses from a particular
+ server. The client SHOULD NOT retry the same request without
+ modification (e.g., adding appropriate authorization). However, the
+ same request to a different server might be successful.
+
+7.4.1 400 Bad Request
+
+ The request could not be understood due to malformed syntax.
+
+7.4.2 401 Unauthorized
+
+ The request requires user authentication.
+
+7.4.3 402 Payment Required
+
+ Reserved for future use.
+
+7.4.4 403 Forbidden
+
+ The server understood the request, but is refusing to fulfill it.
+ Authorization will not help, and the request SHOULD NOT be repeated.
+
+7.4.5 404 Not Found
+
+ The server has definitive information that the user does not exist at
+ the domain specified in the Request-URI. This status is also returned
+ if the domain in the Request-URI does not match any of the domains
+ handled by the recipient of the request.
+
+7.4.6 405 Method Not Allowed
+
+ The method specified in the Request-Line is not allowed for the
+ address identified by the Request-URI. The response MUST include an
+ Allow header field containing a list of valid methods for the
+ indicated address.
+
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 78]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+7.4.7 406 Not Acceptable
+
+ The resource identified by the request is only capable of generating
+ response entities which have content characteristics not acceptable
+ according to the accept headers sent in the request.
+
+7.4.8 407 Proxy Authentication Required
+
+ This code is similar to 401 (Unauthorized), but indicates that the
+ client MUST first authenticate itself with the proxy. The proxy MUST
+ return a Proxy-Authenticate header field (section 6.26) containing a
+ challenge applicable to the proxy for the requested resource. The
+ client MAY repeat the request with a suitable Proxy-Authorization
+ header field (section 6.27). SIP access authentication is explained
+ in section 13.2 and 14.
+
+ This status code is used for applications where access to the
+ communication channel (e.g., a telephony gateway) rather than the
+ callee requires authentication.
+
+7.4.9 408 Request Timeout
+
+ The server could not produce a response, e.g., a user location,
+ within the time indicated in the Expires request-header field. The
+ client MAY repeat the request without modifications at any later
+ time.
+
+7.4.10 409 Conflict
+
+ The request could not be completed due to a conflict with the current
+ state of the resource. This response is returned if the action
+ parameter in a REGISTER request conflicts with existing
+ registrations.
+
+7.4.11 410 Gone
+
+ The requested resource is no longer available at the server and no
+ forwarding address is known. This condition is expected to be
+ considered permanent. If the server does not know, or has no facility
+ to determine, whether or not the condition is permanent, the status
+ code 404 (Not Found) SHOULD be used instead.
+
+7.4.12 411 Length Required
+
+ The server refuses to accept the request without a defined Content-
+ Length. The client MAY repeat the request if it adds a valid
+ Content-Length header field containing the length of the message-body
+ in the request message.
+
+
+
+Handley, et al. Standards Track [Page 79]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+7.4.13 413 Request Entity Too Large
+
+ The server is refusing to process a request because the request
+ entity is larger than the server is willing or able to process. The
+ server MAY close the connection to prevent the client from continuing
+ the request.
+
+ If the condition is temporary, the server SHOULD include a Retry-
+ After header field to indicate that it is temporary and after what
+ time the client MAY try again.
+
+7.4.14 414 Request-URI Too Long
+
+ The server is refusing to service the request because the Request-URI
+ is longer than the server is willing to interpret.
+
+7.4.15 415 Unsupported Media Type
+
+ The server is refusing to service the request because the message
+ body of the request is in a format not supported by the requested
+ resource for the requested method. The server SHOULD return a list of
+ acceptable formats using the Accept, Accept-Encoding and Accept-
+ Language header fields.
+
+7.4.16 420 Bad Extension
+
+ The server did not understand the protocol extension specified in a
+ Require (Section 6.30) header field.
+
+7.4.17 480 Temporarily Unavailable
+
+ The callee's end system was contacted successfully but the callee is
+ currently unavailable (e.g., not logged in or logged in in such a
+ manner as to preclude communication with the callee). The response
+ MAY indicate a better time to call in the Retry-After header. The
+ user could also be available elsewhere (unbeknownst to this host),
+ thus, this response does not terminate any searches. The reason
+ phrase SHOULD indicate a more precise cause as to why the callee is
+ unavailable. This value SHOULD be setable by the user agent. Status
+ 486 (Busy Here) MAY be used to more precisely indicate a particular
+ reason for the call failure.
+
+ This status is also returned by a redirect server that recognizes the
+ user identified by the Request-URI, but does not currently have a
+ valid forwarding location for that user.
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 80]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+7.4.18 481 Call Leg/Transaction Does Not Exist
+
+ This status is returned under two conditions: The server received a
+ BYE request that does not match any existing call leg or the server
+ received a CANCEL request that does not match any existing
+ transaction. (A server simply discards an ACK referring to an unknown
+ transaction.)
+
+7.4.19 482 Loop Detected
+
+ The server received a request with a Via (Section 6.40) path
+ containing itself.
+
+7.4.20 483 Too Many Hops
+
+ The server received a request that contains more Via entries (hops)
+ (Section 6.40) than allowed by the Max-Forwards (Section 6.23) header
+ field.
+
+7.4.21 484 Address Incomplete
+
+ The server received a request with a To (Section 6.37) address or
+ Request-URI that was incomplete. Additional information SHOULD be
+ provided.
+
+
+ This status code allows overlapped dialing. With overlapped
+ dialing, the client does not know the length of the dialing
+ string. It sends strings of increasing lengths, prompting
+ the user for more input, until it no longer receives a 484
+ status response.
+
+7.4.22 485 Ambiguous
+
+ The callee address provided in the request was ambiguous. The
+ response MAY contain a listing of possible unambiguous addresses in
+ Contact headers.
+
+ Revealing alternatives can infringe on privacy concerns of the user
+ or the organization. It MUST be possible to configure a server to
+ respond with status 404 (Not Found) or to suppress the listing of
+ possible choices if the request address was ambiguous.
+
+ Example response to a request with the URL lee at example.com :
+
+ 485 Ambiguous SIP/2.0
+ Contact: Carol Lee <sip:carol.lee at example.com>
+
+
+
+
+Handley, et al. Standards Track [Page 81]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ Contact: Ping Lee <sip:p.lee at example.com>
+ Contact: Lee M. Foote <sip:lee.foote at example.com>
+
+
+
+ Some email and voice mail systems provide this
+ functionality. A status code separate from 3xx is used
+ since the semantics are different: for 300, it is assumed
+ that the same person or service will be reached by the
+ choices provided. While an automated choice or sequential
+ search makes sense for a 3xx response, user intervention is
+ required for a 485 response.
+
+7.4.23 486 Busy Here
+
+ The callee's end system was contacted successfully but the callee is
+ currently not willing or able to take additional calls. The response
+ MAY indicate a better time to call in the Retry-After header. The
+ user could also be available elsewhere, such as through a voice mail
+ service, thus, this response does not terminate any searches. Status
+ 600 (Busy Everywhere) SHOULD be used if the client knows that no
+ other end system will be able to accept this call.
+
+7.5 Server Failure 5xx
+
+ 5xx responses are failure responses given when a server itself has
+ erred. They are not definitive failures, and MUST NOT terminate a
+ search if other possible locations remain untried.
+
+7.5.1 500 Server Internal Error
+
+ The server encountered an unexpected condition that prevented it from
+ fulfilling the request. The client MAY display the specific error
+ condition, and MAY retry the request after several seconds.
+
+7.5.2 501 Not Implemented
+
+ The server does not support the functionality required to fulfill the
+ request. This is the appropriate response when the server does not
+ recognize the request method and is not capable of supporting it for
+ any user.
+
+7.5.3 502 Bad Gateway
+
+ The server, while acting as a gateway or proxy, received an invalid
+ response from the downstream server it accessed in attempting to
+ fulfill the request.
+
+
+
+
+Handley, et al. Standards Track [Page 82]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+7.5.4 503 Service Unavailable
+
+ The server is currently unable to handle the request due to a
+ temporary overloading or maintenance of the server. The implication
+ is that this is a temporary condition which will be alleviated after
+ some delay. If known, the length of the delay MAY be indicated in a
+ Retry-After header. If no Retry-After is given, the client MUST
+ handle the response as it would for a 500 response.
+
+ Note: The existence of the 503 status code does not imply that a
+ server has to use it when becoming overloaded. Some servers MAY wish
+ to simply refuse the connection.
+
+7.5.5 504 Gateway Time-out
+
+ The server, while acting as a gateway, did not receive a timely
+ response from the server (e.g., a location server) it accessed in
+ attempting to complete the request.
+
+7.5.6 505 Version Not Supported
+
+ The server does not support, or refuses to support, the SIP protocol
+ version that was used in the request message. The server is
+ indicating that it is unable or unwilling to complete the request
+ using the same major version as the client, other than with this
+ error message. The response MAY contain an entity describing why that
+ version is not supported and what other protocols are supported by
+ that server. The format for such an entity is not defined here and
+ may be the subject of future standardization.
+
+7.6 Global Failures 6xx
+
+ 6xx responses indicate that a server has definitive information about
+ a particular user, not just the particular instance indicated in the
+ Request-URI. All further searches for this user are doomed to failure
+ and pending searches SHOULD be terminated.
+
+7.6.1 600 Busy Everywhere
+
+ The callee's end system was contacted successfully but the callee is
+ busy and does not wish to take the call at this time. The response
+ MAY indicate a better time to call in the Retry-After header. If the
+ callee does not wish to reveal the reason for declining the call, the
+ callee uses status code 603 (Decline) instead. This status response
+ is returned only if the client knows that no other end point (such as
+ a voice mail system) will answer the request. Otherwise, 486 (Busy
+ Here) should be returned.
+
+
+
+
+Handley, et al. Standards Track [Page 83]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+7.6.2 603 Decline
+
+ The callee's machine was successfully contacted but the user
+ explicitly does not wish to or cannot participate. The response MAY
+ indicate a better time to call in the Retry-After header.
+
+7.6.3 604 Does Not Exist Anywhere
+
+ The server has authoritative information that the user indicated in
+ the To request field does not exist anywhere. Searching for the user
+ elsewhere will not yield any results.
+
+7.6.4 606 Not Acceptable
+
+ The user's agent was contacted successfully but some aspects of the
+ session description such as the requested media, bandwidth, or
+ addressing style were not acceptable.
+
+ A 606 (Not Acceptable) response means that the user wishes to
+ communicate, but cannot adequately support the session described. The
+ 606 (Not Acceptable) response MAY contain a list of reasons in a
+ Warning header field describing why the session described cannot be
+ supported. Reasons are listed in Section 6.41. It is hoped that
+ negotiation will not frequently be needed, and when a new user is
+ being invited to join an already existing conference, negotiation may
+ not be possible. It is up to the invitation initiator to decide
+ whether or not to act on a 606 (Not Acceptable) response.
+
+8 SIP Message Body
+
+8.1 Body Inclusion
+
+ Requests MAY contain message bodies unless otherwise noted. Within
+ this specification, the BYE request MUST NOT contain a message body.
+ For ACK, INVITE and OPTIONS, the message body is always a session
+ description. The use of message bodies for REGISTER requests is for
+ further study.
+
+ For response messages, the request method and the response status
+ code determine the type and interpretation of any message body. All
+ responses MAY include a body. Message bodies for 1xx responses
+ contain advisory information about the progress of the request. 2xx
+ responses to INVITE requests contain session descriptions. In 3xx
+ responses, the message body MAY contain the description of
+ alternative destinations or services, as described in Section 7.3.
+ For responses with status 400 or greater, the message body MAY
+
+
+
+
+
+Handley, et al. Standards Track [Page 84]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ contain additional, human-readable information about the reasons for
+ failure. It is RECOMMENDED that information in 1xx and 300 and
+ greater responses be of type text/plain or text/html
+
+8.2 Message Body Type
+
+ The Internet media type of the message body MUST be given by the
+ Content-Type header field. If the body has undergone any encoding
+ (such as compression) then this MUST be indicated by the Content-
+ Encoding header field, otherwise Content-Encoding MUST be omitted. If
+ applicable, the character set of the message body is indicated as
+ part of the Content-Type header-field value.
+
+8.3 Message Body Length
+
+ The body length in bytes SHOULD be given by the Content-Length header
+ field. Section 6.15 describes the behavior in detail.
+
+ The "chunked" transfer encoding of HTTP/1.1 MUST NOT be used for SIP.
+ (Note: The chunked encoding modifies the body of a message in order
+ to transfer it as a series of chunks, each with its own size
+ indicator.)
+
+9 Compact Form
+
+ When SIP is carried over UDP with authentication and a complex
+ session description, it may be possible that the size of a request or
+ response is larger than the MTU. To address this problem, a more
+ compact form of SIP is also defined by using abbreviations for the
+ common header fields listed below:
+
+
+ short field name long field name note
+ c Content-Type
+ e Content-Encoding
+ f From
+ i Call-ID
+ m Contact from "moved"
+ l Content-Length
+ s Subject
+ t To
+ v Via
+
+
+ Thus, the message in section 16.2 could also be written:
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 85]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ INVITE sip:schooler at vlsi.caltech.edu SIP/2.0
+ v:SIP/2.0/UDP 131.215.131.131;maddr=239.128.16.254;ttl=16
+ v:SIP/2.0/UDP 128.16.64.19
+ f:sip:mjh at isi.edu
+ t:sip:schooler at cs.caltech.edu
+ i:62729-27 at 128.16.64.19
+ c:application/sdp
+ CSeq: 4711 INVITE
+ l:187
+
+ v=0
+ o=user1 53655765 2353687637 IN IP4 128.3.4.5
+ s=Mbone Audio
+ i=Discussion of Mbone Engineering Issues
+ e=mbone at somewhere.com
+ c=IN IP4 224.2.0.1/127
+ t=0 0
+ m=audio 3456 RTP/AVP 0
+
+
+
+ Clients MAY mix short field names and long field names within the
+ same request. Servers MUST accept both short and long field names for
+ requests. Proxies MAY change header fields between their long and
+ short forms, but this MUST NOT be done to fields following an
+ Authorization header.
+
+10 Behavior of SIP Clients and Servers
+
+10.1 General Remarks
+
+ SIP is defined so it can use either UDP (unicast or multicast) or TCP
+ as a transport protocol; it provides its own reliability mechanism.
+
+10.1.1 Requests
+
+ Servers discard isomorphic requests, but first retransmit the
+ appropriate response. (SIP requests are said to be idempotent , i.e.,
+ receiving more than one copy of a request does not change the server
+ state.)
+
+ After receiving a CANCEL request from an upstream client, a stateful
+ proxy server MAY send a CANCEL on all branches where it has not yet
+ received a final response.
+
+ When a user agent receives a request, it checks the Call-ID against
+ those of in-progress calls. If the Call-ID was found, it compares the
+ tag value of To with the user's tag and rejects the request if the
+
+
+
+Handley, et al. Standards Track [Page 86]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ two do not match. If the From header, including any tag value,
+ matches the value for an existing call leg, the server compares the
+ CSeq header field value. If less than or equal to the current
+ sequence number, the request is a retransmission. Otherwise, it is a
+ new request. If the From header does not match an existing call leg,
+ a new call leg is created.
+
+ If the Call-ID was not found, a new call leg is created, with entries
+ for the To, From and Call-ID headers. In this case, the To header
+ field should not have contained a tag. The server returns a response
+ containing the same To value, but with a unique tag added. The tag
+ MAY be omitted if the request contained only one Via header field.
+
+10.1.2 Responses
+
+ A server MAY issue one or more provisional responses at any time
+ before sending a final response. If a stateful proxy, user agent
+ server, redirect server or registrar cannot respond to a request with
+ a final response within 200 ms, it SHOULD issue a provisional (1xx)
+ response as soon as possible. Stateless proxies MUST NOT issue
+ provisional responses on their own.
+
+ Responses are mapped to requests by the matching To, From, Call-ID,
+ CSeq headers and the branch parameter of the first Via header.
+ Responses terminate request retransmissions even if they have Via
+ headers that cause them to be delivered to an upstream client.
+
+ A stateful proxy may receive a response that it does not have state
+ for, that is, where it has no a record of an associated request. If
+ the Via header field indicates that the upstream server used TCP, the
+ proxy actively opens a TCP connection to that address. Thus, proxies
+ have to be prepared to receive responses on the incoming side of
+ passive TCP connections, even though most responses will arrive on
+ the incoming side of an active connection. (An active connection is a
+ TCP connection initiated by the proxy, a passive connection is one
+ accepted by the proxy, but initiated by another entity.)
+
+ 100 responses SHOULD NOT be forwarded, other 1xx responses MAY be
+ forwarded, possibly after the server eliminates responses with status
+ codes that had already been sent earlier. 2xx responses are forwarded
+ according to the Via header. Once a stateful proxy has received a 2xx
+ response, it MUST NOT forward non-2xx final responses. Responses
+ with status 300 and higher are retransmitted by each stateful proxy
+ until the next upstream proxy sends an ACK (see below for timing
+ details) or CANCEL.
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 87]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ A stateful proxy SHOULD maintain state for at least 32 seconds after
+ the receipt of the first definitive non-200 response, in order to
+ handle retransmissions of the response.
+
+
+ The 32 second window is given by the maximum retransmission
+ duration of 200-class responses using the default timers,
+ in case the ACK is lost somewhere on the way to the called
+ user agent or the next stateful proxy.
+
+10.2 Source Addresses, Destination Addresses and Connections
+
+10.2.1 Unicast UDP
+
+ Responses are returned to the address listed in the Via header field
+ (Section 6.40), not the source address of the request.
+
+
+ Recall that responses are not generated by the next-hop
+ stateless server, but generated by either a proxy server or
+ the user agent server. Thus, the stateless proxy can only
+ use the Via header field to forward the response.
+
+10.2.2 Multicast UDP
+
+ Requests MAY be multicast; multicast requests likely feature a host-
+ independent Request-URI. This request SHOULD be scoped to ensure it
+ is not forwarded beyond the boundaries of the administrative system.
+ This MAY be done with either TTL or administrative scopes[25],
+ depending on what is implemented in the network.
+
+ A client receiving a multicast query does not have to check whether
+ the host part of the Request-URI matches its own host or domain name.
+ If the request was received via multicast, the response is also
+ returned via multicast. Responses to multicast requests are multicast
+ with the same TTL as the request, where the TTL is derived from the
+ ttl parameter in the Via header (Section 6.40).
+
+ To avoid response implosion, servers MUST NOT answer multicast
+ requests with a status code other than 2xx or 6xx. The server delays
+ its response by a random interval uniformly distributed between zero
+ and one second. Servers MAY suppress responses if they hear a lower-
+ numbered or 6xx response from another group member prior to sending.
+ Servers do not respond to CANCEL requests received via multicast to
+ avoid request implosion. A proxy or UAC SHOULD send a CANCEL on
+ receiving the first 2xx or 6xx response to a multicast request.
+
+
+
+
+
+Handley, et al. Standards Track [Page 88]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ Server response suppression is a MAY since it requires a
+ server to violate some basic message processing rules. Lets
+ say A sends a multicast request, and it is received by B,C,
+ and D. B sends a 200 response. The topmost Via field in the
+ response will contain the address of A. C will also receive
+ this response, and could use it to suppress its own
+ response. However, C would normally not examine this
+ response, as the topmost Via is not its own. Normally, a
+ response received with an incorrect topmost Via MUST be
+ dropped, but not in this case. To distinguish this packet
+ from a misrouted or multicast looped packet is fairly
+ complex, and for this reason the procedure is a MAY. The
+ CANCEL, instead, provides a simpler and more standard way
+ to perform response suppression. It is for this reason that
+ the use of CANCEL here is a SHOULD
+
+10.3 TCP
+
+ A single TCP connection can serve one or more SIP transactions. A
+ transaction contains zero or more provisional responses followed by
+ one or more final responses. (Typically, transactions contain exactly
+ one final response, but there are exceptional circumstances, where,
+ for example, multiple 200 responses can be generated.)
+
+ The client SHOULD keep the connection open at least until the first
+ final response arrives. If the client closes or resets the TCP
+ connection prior to receiving the first final response, the server
+ treats this action as equivalent to a CANCEL request.
+
+
+ This behavior makes it less likely that malfunctioning
+ clients cause a proxy server to keep connection state
+ indefinitely.
+
+ The server SHOULD NOT close the TCP connection until it has sent its
+ final response, at which point it MAY close the TCP connection if it
+ wishes to. However, normally it is the client's responsibility to
+ close the connection.
+
+ If the server leaves the connection open, and if the client so
+ desires it MAY re-use the connection for further SIP requests or for
+ requests from the same family of protocols (such as HTTP or stream
+ control commands).
+
+
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 89]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ If a server needs to return a response to a client and no longer has
+ a connection open to that client, it MAY open a connection to the
+ address listed in the Via header. Thus, a proxy or user agent MUST be
+ prepared to receive both requests and responses on a "passive"
+ connection.
+
+10.4 Reliability for BYE, CANCEL, OPTIONS, REGISTER Requests
+
+10.4.1 UDP
+
+ A SIP client using UDP SHOULD retransmit a BYE, CANCEL, OPTIONS, or
+ REGISTER request with an exponential backoff, starting at a T1 second
+ interval, doubling the interval for each packet, and capping off at a
+ T2 second interval. This means that after the first packet is sent,
+ the second is sent T1 seconds later, the next 2*T1 seconds after
+ that, the next 4*T1 seconds after that, and so on, until the interval
+ hits T2. Subsequent retransmissions are spaced by T2 seconds. If the
+ client receives a provisional response, it continues to retransmit
+ the request, but with an interval of T2 seconds. Retransmissions
+ cease when the client has sent a total of eleven packets, or receives
+ a definitive response. Default values for T1 and T2 are 500 ms and 4
+ s, respectively. Clients MAY use larger values, but SHOULD NOT use
+ smaller ones. Servers retransmit the response upon receipt of a
+ request retransmission. After the server sends a final response, it
+ cannot be sure the client has received the response, and thus SHOULD
+ cache the results for at least 10*T2 seconds to avoid having to, for
+ example, contact the user or location server again upon receiving a
+ request retransmission.
+
+
+ Use of the exponential backoff is for congestion control
+ purposes. However, the back-off must cap off, since request
+ retransmissions are used to trigger response
+ retransmissions at the server. Without a cap, the loss of a
+ single response could significantly increase transaction
+ latencies.
+
+ The value of the initial retransmission timer is smaller than that
+ that for TCP since it is expected that network paths suitable for
+ interactive communications have round-trip times smaller than 500 ms.
+ For congestion control purposes, the retransmission count has to be
+ bounded. Given that most transactions are expected to consist of one
+ request and a few responses, round-trip time estimation is not likely
+ to be very useful. If RTT estimation is desired to more quickly
+ discover a missing final response, each request retransmission needs
+ to be labeled with its own Timestamp (Section 6.36), returned in the
+ response. The server caches the result until it can be sure that the
+ client will not retransmit the same request again.
+
+
+
+Handley, et al. Standards Track [Page 90]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ Each server in a proxy chain generates its own final response to a
+ CANCEL request. The server responds immediately upon receipt of the
+ CANCEL request rather than waiting until it has received final
+ responses from the CANCEL requests it generates.
+
+ BYE and OPTIONS final responses are generated by redirect and user
+ agent servers; REGISTER final responses are generated by registrars.
+ Note that in contrast to the reliability mechanism described in
+ Section 10.5, responses to these requests are not retransmitted
+ periodically and not acknowledged via ACK.
+
+10.4.2 TCP
+
+ Clients using TCP do not need to retransmit requests.
+
+10.5 Reliability for INVITE Requests
+
+ Special considerations apply for the INVITE method.
+
+ 1. After receiving an invitation, considerable time can elapse
+ before the server can determine the outcome. For example,
+ if the called party is "rung" or extensive searches are
+ performed, delays between the request and a definitive
+ response can reach several tens of seconds. If either
+ caller or callee are automated servers not directly
+ controlled by a human being, a call attempt could be
+ unbounded in time.
+
+ 2. If a telephony user interface is modeled or if we need to
+ interface to the PSTN, the caller's user interface will
+ provide "ringback", a signal that the callee is being
+ alerted. (The status response 180 (Ringing) MAY be used to
+ initiate ringback.) Once the callee picks up, the caller
+ needs to know so that it can enable the voice path and stop
+ ringback. The callee's response to the invitation could get
+ lost. Unless the response is transmitted reliably, the
+ caller will continue to hear ringback while the callee
+ assumes that the call exists.
+
+ 3. The client has to be able to terminate an on-going request,
+ e.g., because it is no longer willing to wait for the
+ connection or search to succeed. The server will have to
+ wait several retransmission intervals to interpret the lack
+ of request retransmissions as the end of a call. If the
+ call succeeds shortly after the caller has given up, the
+ callee will "pick up the phone" and not be "connected".
+
+
+
+
+
+Handley, et al. Standards Track [Page 91]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+10.5.1 UDP
+
+ For UDP, A SIP client SHOULD retransmit a SIP INVITE request with an
+ interval that starts at T1 seconds, and doubles after each packet
+ transmission. The client ceases retransmissions if it receives a
+ provisional or definitive response, or once it has sent a total of 7
+ request packets.
+
+ A server which transmits a provisional response should retransmit it
+ upon reception of a duplicate request. A server which transmits a
+ final response should retransmit it with an interval that starts at
+ T1 seconds, and doubles for each subsequent packet. Response
+ retransmissions cease when any one of the following occurs:
+
+ 1. An ACK request for the same transaction is received;
+
+ 2. a BYE request for the same call leg is received;
+
+ 3. a CANCEL request for the same call leg is received and the
+ final response status was equal or greater to 300;
+
+ 4. the response has been transmitted 7 times.
+
+ Only the user agent client generates an ACK for 2xx final responses,
+ If the response contained a Contact header field, the ACK MAY be sent
+ to the address listed in that Contact header field. If the response
+ did not contain a Contact header, the client uses the same To header
+ field and Request-URI as for the INVITE request and sends the ACK to
+ the same destination as the original INVITE request. ACKs for final
+ responses other than 2xx are sent to the same server that the
+ original request was sent to, using the same Request-URI as the
+ original request. Note, however, that the To header field in the ACK
+ is copied from the response being acknowledged, not the request, and
+ thus MAY additionally contain the tag parameter. Also note than
+ unlike 2xx final responses, a proxy generates an ACK for non-2xx
+ final responses.
+
+ The ACK request MUST NOT be acknowledged to prevent a response-ACK
+ feedback loop. Fig. 12 and 13 show the client and server state
+ diagram for invitations.
+
+
+
+
+ The mechanism in Sec. 10.4 would not work well for INVITE
+ because of the long delays between INVITE and a final
+ response. If the 200 response were to get lost, the callee
+ would believe the call to exist, but the voice path would
+
+
+
+Handley, et al. Standards Track [Page 92]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+
+
+ +===========+
+ * *
+ ...........>* Initial *<;;;;;;;;;;
+ : 7 INVITE * * ;
+ : sent +===========+ ;
+ : | ;
+ : | - ;
+ : | INVITE ;
+ : | ;
+ : v ;
+ : ************* ;
+ : T1*2^n <--* * ;
+ : INVITE -->* Calling *--------+ ;
+ : * * | ;
+ : ************* | ;
+ : : | | ;
+ :.............: | 1xx xxx | ;
+ | - ACK | ;
+ | | ;
+ v | ;
+ ************* | ;
+ * * | ;
+ * Ringing *<->1xx | ;
+ * * | ;
+ ************* | ;
+ | | ;
+ |<-------------+ ;
+ | ;
+ v ;
+ ************* ;
+ xxx <--* * ;
+ ACK -->* Completed * ;
+ * * ;
+ ************* ;
+ ; 32s (for proxy);
+ ;;;;;;;;;;;;;;;;;;
+
+ event (xxx=status)
+ message
+
+
+ Figure 12: State transition diagram of client for INVITE method
+
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 93]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+
+
+ 7 pkts sent +===============+
++-------------->* *
+| * Initial *<...............
+|;;;;;;;;;;;;;;>* * :
+|; +===============+ :
+|; CANCEL ! :
+|; 200 ! INVITE :
+|; ! 1xx :
+|; ! :
+|; v :
+|; ***************** BYE :
+|; INVITE -->* * 200 :
+|; 1xx <--* Call proceed. *..............>:
+|; * * :
+|;;;;;;;;;;;;;;;***************** :
+|; ! ! :
+|: ! ! :
+|; failure ! ! picks up :
+|; >= 300 ! ! 200 :
+|; +-------+ +-------+ :
+|; v v :
+|; *********** *********** :
+|;INVITE<* *<T1*2^n->* *>INVITE :
+|;status>* failure *>status<-* success *<status :
+|; * * * * :
+|;;;;;;;;*********** *********** :
+| ! : | | ! : :
+| ! : | | ! : :
++-------------!-:-+------------+ ! : :
+ ! :.................!..:.........>:
+ ! ! BYE :
+ +---------+---------+ 200 :
+ event ! ACK :
+message sent v :
+ ***************** :
+ V---* * :
+ ACK * Confirmed * :
+ |-->* * :
+ ***************** .
+ :......................>:
+
+
+ Figure 13: State transition diagram of server for INVITE method
+
+Handley, et al. Standards Track [Page 94]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ be dead since the caller does not know that the callee has
+ picked up. Thus, the INVITE retransmission interval would
+ have to be on the order of a second or two to limit the
+ duration of this state confusion. Retransmitting the
+ response with an exponential back-off helps ensure that the
+ response is received, without placing an undue burden on
+ the network.
+
+10.5.2 TCP
+
+ A user agent using TCP MUST NOT retransmit requests, but uses the
+ same algorithm as for UDP (Section 10.5.1) to retransmit responses
+ until it receives an ACK.
+
+
+ It is necessary to retransmit 2xx responses as their
+ reliability is assured end-to-end only. If the chain of
+ proxies has a UDP link in the middle, it could lose the
+ response, with no possibility of recovery. For simplicity,
+ we also retransmit non-2xx responses, although that is not
+ strictly necessary.
+
+10.6 Reliability for ACK Requests
+
+ The ACK request does not generate responses. It is only generated
+ when a response to an INVITE request arrives (see Section 10.5). This
+ behavior is independent of the transport protocol. Note that the ACK
+ request MAY take a different path than the original INVITE request,
+ and MAY even cause a new TCP connection to be opened in order to send
+ it.
+
+10.7 ICMP Handling
+
+ Handling of ICMP messages in the case of UDP messages is
+ straightforward. For requests, a host, network, port, or protocol
+ unreachable error SHOULD be treated as if a 400-class response was
+ received. For responses, these errors SHOULD cause the server to
+ cease retransmitting the response.
+
+ Source quench ICMP messages SHOULD be ignored. TTL exceeded errors
+ SHOULD be ignored. Parameter problem errors SHOULD be treated as if a
+ 400-class response was received.
+
+11 Behavior of SIP User Agents
+
+ This section describes the rules for user agent client and servers
+ for generating and processing requests and responses.
+
+
+
+
+Handley, et al. Standards Track [Page 95]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+11.1 Caller Issues Initial INVITE Request
+
+ When a user agent client desires to initiate a call, it formulates an
+ INVITE request. The To field in the request contains the address of
+ the callee. The Request-URI contains the same address. The From field
+ contains the address of the caller. If the From address can appear
+ in requests generated by other user agent clients for the same call,
+ the caller MUST insert the tag parameter in the From field. A UAC MAY
+ optionally add a Contact header containing an address where it would
+ like to be contacted for transactions from the callee back to the
+ caller.
+
+11.2 Callee Issues Response
+
+ When the initial INVITE request is received at the callee, the callee
+ can accept, redirect, or reject the call. In all of these cases, it
+ formulates a response. The response MUST copy the To, From, Call-ID,
+ CSeq and Via fields from the request. Additionally, the responding
+ UAS MUST add the tag parameter to the To field in the response if the
+ request contained more than one Via header field. Since a request
+ from a UAC may fork and arrive at multiple hosts, the tag parameter
+ serves to distinguish, at the UAC, multiple responses from different
+ UAS's. The UAS MAY add a Contact header field in the response. It
+ contains an address where the callee would like to be contacted for
+ subsequent transactions, including the ACK for the current INVITE.
+ The UAS stores the values of the To and From field, including any
+ tags. These become the local and remote addresses of the call leg,
+ respectively.
+
+11.3 Caller Receives Response to Initial Request
+
+ Multiple responses may arrive at the UAC for a single INVITE request,
+ due to a forking proxy. Each response is distinguished by the "tag"
+ parameter in the To header field, and each represents a distinct call
+ leg. The caller MAY choose to acknowledge or terminate the call with
+ each responding UAS. To acknowledge, it sends an ACK request, and to
+ terminate it sends a BYE request. The To header field in the ACK or
+ BYE MUST be the same as the To field in the 200 response, including
+ any tag. The From header field MUST be the same as the From header
+ field in the 200 (OK) response, including any tag. The Request-URI of
+ the ACK or BYE request MAY be set to whatever address was found in
+ the Contact header field in the 200 (OK) response, if present.
+ Alternately, a UAC may copy the address from the To header field into
+ the Request-URI. The UAC also notes the value of the To and From
+ header fields in each response. For each call leg, the To header
+ field becomes the remote address, and the From header field becomes
+ the local address.
+
+
+
+
+Handley, et al. Standards Track [Page 96]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+11.4 Caller or Callee Generate Subsequent Requests
+
+ Once the call has been established, either the caller or callee MAY
+ generate INVITE or BYE requests to change or terminate the call.
+ Regardless of whether the caller or callee is generating the new
+ request, the header fields in the request are set as follows. For the
+ desired call leg, the To header field is set to the remote address,
+ and the From header field is set to the local address (both including
+ any tags). The Contact header field MAY be different than the Contact
+ header field sent in a previous response or request. The Request-URI
+ MAY be set to the value of the Contact header field received in a
+ previous request or response from the remote party, or to the value
+ of the remote address.
+
+11.5 Receiving Subsequent Requests
+
+ When a request is received subsequently, the following checks are
+ made:
+
+ 1. If the Call-ID is new, the request is for a new call,
+ regardless of the values of the To and From header fields.
+
+ 2. If the Call-ID exists, the request is for an existing call.
+ If the To, From, Call-ID, and CSeq values exactly match
+ (including tags) those of any requests received previously,
+ the request is a retransmission.
+
+ 3. If there was no match to the previous step, the To and From
+ fields are compared against existing call leg local and
+ remote addresses. If there is a match, and the CSeq in the
+ request is higher than the last CSeq received on that leg,
+ the request is a new transaction for an existing call leg.
+
+12 Behavior of SIP Proxy and Redirect Servers
+
+ This section describes behavior of SIP redirect and proxy servers in
+ detail. Proxy servers can "fork" connections, i.e., a single incoming
+ request spawns several outgoing (client) requests.
+
+12.1 Redirect Server
+
+ A redirect server does not issue any SIP requests of its own. After
+ receiving a request other than CANCEL, the server gathers the list of
+ alternative locations and returns a final response of class 3xx or it
+ refuses the request. For well-formed CANCEL requests, it SHOULD
+ return a 2xx response. This response ends the SIP transaction. The
+
+
+
+
+
+Handley, et al. Standards Track [Page 97]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ redirect server maintains transaction state for the whole SIP
+ transaction. It is up to the client to detect forwarding loops
+ between redirect servers.
+
+12.2 User Agent Server
+
+ User agent servers behave similarly to redirect servers, except that
+ they also accept requests and can return a response of class 2xx.
+
+12.3 Proxy Server
+
+ This section outlines processing rules for proxy servers. A proxy
+ server can either be stateful or stateless. When stateful, a proxy
+ remembers the incoming request which generated outgoing requests, and
+ the outgoing requests. A stateless proxy forgets all information once
+ an outgoing request is generated. A forking proxy SHOULD be stateful.
+ Proxies that accept TCP connections MUST be stateful.
+
+
+ Otherwise, if the proxy were to lose a request, the TCP
+ client would never retransmit it.
+
+ A stateful proxy SHOULD NOT become stateless until after it sends a
+ definitive response upstream, and at least 32 seconds after it
+ received a definitive response.
+
+ A stateful proxy acts as a virtual UAS/UAC. It implements the server
+ state machine when receiving requests, and the client state machine
+ for generating outgoing requests, with the exception of receiving a
+ 2xx response to an INVITE. Instead of generating an ACK, the 2xx
+ response is always forwarded upstream towards the caller.
+ Furthermore, ACK's for 200 responses to INVITE's are always proxied
+ downstream towards the UAS, as they would be for a stateless proxy.
+
+ A stateless proxy does not act as a virtual UAS/UAC (as this would
+ require state). Rather, a stateless proxy forwards every request it
+ receives downstream, and every response it receives upstream.
+
+12.3.1 Proxying Requests
+
+ To prevent loops, a server MUST check if its own address is already
+ contained in the Via header field of the incoming request.
+
+ The To, From, Call-ID, and Contact tags are copied exactly from the
+ original request. The proxy SHOULD change the Request-URI to indicate
+ the server where it intends to send the request.
+
+
+
+
+
+Handley, et al. Standards Track [Page 98]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ A proxy server always inserts a Via header field containing its own
+ address into those requests that are caused by an incoming request.
+ Each proxy MUST insert a "branch" parameter (Section 6.40).
+
+12.3.2 Proxying Responses
+
+ A proxy only processes a response if the topmost Via field matches
+ one of its addresses. A response with a non-matching top Via field
+ MUST be dropped.
+
+12.3.3 Stateless Proxy: Proxying Responses
+
+ A stateless proxy removes its own Via field, and checks the address
+ in the next Via field. In the case of UDP, the response is sent to
+ the address listed in the "maddr" tag if present, otherwise to the
+ "received" tag if present, and finally to the address in the "sent-
+ by" field. A proxy MUST remain stateful when handling requests
+ received via TCP.
+
+ A stateless proxy MUST NOT generate its own provisional responses.
+
+12.3.4 Stateful Proxy: Receiving Requests
+
+ When a stateful proxy receives a request, it checks the To, From
+ (including tags), Call-ID and CSeq against existing request records.
+ If the tuple exists, the request is a retransmission. The provisional
+ or final response sent previously is retransmitted, as per the server
+ state machine. If the tuple does not exist, the request corresponds
+ to a new transaction, and the request should be proxied.
+
+ A stateful proxy server MAY generate its own provisional (1xx)
+ responses.
+
+12.3.5 Stateful Proxy: Receiving ACKs
+
+ When an ACK request is received, it is either processed locally or
+ proxied. To make this determination, the To, From, CSeq and Call-ID
+ fields are compared against those in previous requests. If there is
+ no match, the ACK request is proxied as if it were an INVITE request.
+ If there is a match, and if the server had ever sent a 200 response
+ upstream, the ACK is proxied. If the server had never sent any
+ responses upstream, the ACK is also proxied. If the server had sent a
+ 3xx, 4xx, 5xx or 6xx response, but no 2xx response, the ACK is
+ processed locally if the tag in the To field of the ACK matches the
+ tag sent by the proxy in the response.
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 99]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+12.3.6 Stateful Proxy: Receiving Responses
+
+ When a proxy server receives a response that has passed the Via
+ checks, the proxy server checks the To (without the tag), From
+ (including the tag), Call-ID and CSeq against values seen in previous
+ requests. If there is no match, the response is forwarded upstream to
+ the address listed in the Via field. If there is a match, the
+ "branch" tag in the Via field is examined. If it matches a known
+ branch identifier, the response is for the given branch, and
+ processed by the virtual client for the given branch. Otherwise, the
+ response is dropped.
+
+ A stateful proxy should obey the rules in Section 12.4 to determine
+ if the response should be proxied upstream. If it is to be proxied,
+ the same rules for stateless proxies above are followed, with the
+ following addition for TCP. If a request was received via TCP
+ (indicated by the protocol in the top Via header), the proxy checks
+ to see if it has a connection currently open to that address. If so,
+ the response is sent on that connection. Otherwise, a new TCP
+ connection is opened to the address and port in the Via field, and
+ the response is sent there. Note that this implies that a UAC or
+ proxy MUST be prepared to receive responses on the incoming side of a
+ TCP connection. Definitive non 200-class responses MUST be
+ retransmitted by the proxy, even over a TCP connection.
+
+12.3.7 Stateless, Non-Forking Proxy
+
+ Proxies in this category issue at most a single unicast request for
+ each incoming SIP request, that is, they do not "fork" requests.
+ However, servers MAY choose to always operate in a mode that allows
+ issuing of several requests, as described in Section 12.4.
+
+ The server can forward the request and any responses. It does not
+ have to maintain any state for the SIP transaction. Reliability is
+ assured by the next redirect or stateful proxy server in the server
+ chain.
+
+ A proxy server SHOULD cache the result of any address translations
+ and the response to speed forwarding of retransmissions. After the
+ cache entry has been expired, the server cannot tell whether an
+ incoming request is actually a retransmission of an older request.
+ The server will treat it as a new request and commence another
+ search.
+
+12.4 Forking Proxy
+
+ The server MUST respond to the request immediately with a 100
+ (Trying) response.
+
+
+
+Handley, et al. Standards Track [Page 100]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ Successful responses to an INVITE request MAY contain a Contact
+ header field so that the following ACK or BYE bypasses the proxy
+ search mechanism. If the proxy requires future requests to be routed
+ through it, it adds a Record-Route header to the request (Section
+ 6.29).
+
+ The following C-code describes the behavior of a proxy server issuing
+ several requests in response to an incoming INVITE request. The
+ function request(r, a, b) sends a SIP request of type r to address a,
+ with branch id b. await_response() waits until a response is received
+ and returns the response. close(a) closes the TCP connection to
+ client with address a. response(r) sends a response to the client.
+ ismulticast() returns 1 if the location is a multicast address and
+ zero otherwise. The variable timeleft indicates the amount of time
+ left until the maximum response time has expired. The variable
+ recurse indicates whether the server will recursively try addresses
+ returned through a 3xx response. A server MAY decide to recursively
+ try only certain addresses, e.g., those which are within the same
+ domain as the proxy server. Thus, an initial multicast request can
+ trigger additional unicast requests.
+
+
+ /* request type */
+ typedef enum {INVITE, ACK, BYE, OPTIONS, CANCEL, REGISTER} Method;
+
+ process_request(Method R, int N, address_t address[])
+ {
+ struct {
+ int branch; /* branch id */
+ int done; /* has responded */
+ } outgoing[];
+ int done[]; /* address has responded */
+ char *location[]; /* list of locations */
+ int heard = 0; /* number of sites heard from */
+ int class; /* class of status code */
+ int timeleft = 120; /* sample timeout value */
+ int loc = 0; /* number of locations */
+ struct { /* response */
+ int status; /* response: CANCEL=-1 */
+ int locations; /* number of redirect locations */
+ char *location[]; /* redirect locations */
+ address_t a; /* address of respondent */
+ int branch; /* branch identifier */
+ } r, best; /* response, best response */
+ int i;
+
+ best.status = 1000;
+ for (i = 0; i < N; i++) {
+
+
+
+Handley, et al. Standards Track [Page 101]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ request(R, address[i], i);
+ outgoing[i].done = 0;
+ outgoing[i].branch = i;
+ }
+
+ while (timeleft > 0 && heard < N) {
+ r = await_response();
+ class = r.status / 100;
+
+ /* If final response, mark branch as done. */
+ if (class >= 2) {
+ heard++;
+ for (i = 0; i < N; i++) {
+ if (r.branch == outgoing[i].branch) {
+ outgoing[i].done = 1;
+ break;
+ }
+ }
+ }
+ /* CANCEL: respond, fork and wait for responses */
+ else if (class < 0) {
+ best.status = 200;
+ response(best);
+ for (i = 0; i < N; i++) {
+ if (!outgoing[i].done)
+ request(CANCEL, address[i], outgoing[i].branch);
+ }
+ best.status = -1;
+ }
+
+ /* Send an ACK */
+
+ if (class != 2) {
+ if (R == INVITE) request(ACK, r.a, r.branch);
+ }
+
+
+ if (class == 2) {
+ if (r.status < best.status) best = r;
+ break;
+ }
+ else if (class == 3) {
+ /* A server MAY optionally recurse. The server MUST check
+ * whether it has tried this location before and whether
+ * the location is part of the Via path of the incoming
+ * request. This check is omitted here for brevity.
+ * Multicast locations MUST NOT be returned to the client if
+ * the server is not recursing.
+
+
+
+Handley, et al. Standards Track [Page 102]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ */
+ if (recurse) {
+ multicast = 0;
+ N += r.locations;
+ for (i = 0; i < r.locations; i++) {
+ request(R, r.location[i]);
+ }
+ } else if (!ismulticast(r.location)) {
+ best = r;
+ }
+ }
+ else if (class == 4) {
+ if (best.status >= 400) best = r;
+ }
+ else if (class == 5) {
+ if (best.status >= 500) best = r;
+ }
+ else if (class == 6) {
+ best = r;
+ break;
+ }
+ }
+
+ /* We haven't heard anything useful from anybody. */
+ if (best.status == 1000) {
+ best.status = 404;
+ }
+ if (best.status/100 != 3) loc = 0;
+ response(best);
+ }
+
+
+ Responses are processed as follows. The process completes (and state
+ can be freed) when all requests have been answered by final status
+ responses (for unicast) or 60 seconds have elapsed (for multicast). A
+ proxy MAY send a CANCEL to all branches and return a 408 (Timeout) to
+ the client after 60 seconds or more.
+
+ 1xx: The proxy MAY forward the response upstream towards the client.
+
+ 2xx: The proxy MUST forward the response upstream towards the client,
+ without sending an ACK downstream. After receiving a 2xx, the
+ server MAY terminate all other pending requests by sending a
+ CANCEL request and closing the TCP connection, if applicable.
+ (Terminating pending requests is advisable as searches consume
+ resources. Also, INVITE requests could "ring" on a number of
+ workstations if the callee is currently logged in more than
+ once.)
+
+
+
+Handley, et al. Standards Track [Page 103]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ 3xx: The proxy MUST send an ACK and MAY recurse on the listed Contact
+ addresses. Otherwise, the lowest-numbered response is returned
+ if there were no 2xx responses.
+
+ Location lists are not merged as that would prevent
+ forwarding of authenticated responses. Also, responses can
+ have message bodies, so that merging is not feasible.
+
+ 4xx, 5xx: The proxy MUST send an ACK and remember the response if it
+ has a lower status code than any previous 4xx and 5xx responses.
+ On completion, the lowest-numbered response is returned if there
+ were no 2xx or 3xx responses.
+
+ 6xx: The proxy MUST forward the response to the client and send an
+ ACK. Other pending requests MAY be terminated with CANCEL as
+ described for 2xx responses.
+
+ A proxy server forwards any response for Call-IDs for which it does
+ not have a pending transaction according to the response's Via
+ header. User agent servers respond to BYE requests for unknown call
+ legs with status code 481 (Transaction Does Not Exist); they drop ACK
+ requests with unknown call legs silently.
+
+ Special considerations apply for choosing forwarding destinations for
+ ACK and BYE requests. In most cases, these requests will bypass
+ proxies and reach the desired party directly, keeping proxies from
+ having to make forwarding decisions.
+
+ A proxy MAY maintain call state for a period of its choosing. If a
+ proxy still has list of destinations that it forwarded the last
+ INVITE to, it SHOULD direct ACK requests only to those downstream
+ servers.
+
+13 Security Considerations
+
+13.1 Confidentiality and Privacy: Encryption
+
+13.1.1 End-to-End Encryption
+
+ SIP requests and responses can contain sensitive information about
+ the communication patterns and communication content of individuals.
+ The SIP message body MAY also contain encryption keys for the session
+ itself. SIP supports three complementary forms of encryption to
+ protect privacy:
+
+ o End-to-end encryption of the SIP message body and certain
+ sensitive header fields;
+
+
+
+
+Handley, et al. Standards Track [Page 104]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ o hop-by-hop encryption to prevent eavesdropping that tracks
+ who is calling whom;
+
+ o hop-by-hop encryption of Via fields to hide the route a
+ request has taken.
+
+ Not all of the SIP request or response can be encrypted end-to-end
+ because header fields such as To and Via need to be visible to
+ proxies so that the SIP request can be routed correctly. Hop-by-hop
+ encryption encrypts the entire SIP request or response on the wire so
+ that packet sniffers or other eavesdroppers cannot see who is calling
+ whom. Hop-by-hop encryption can also encrypt requests and responses
+ that have been end-to-end encrypted. Note that proxies can still see
+ who is calling whom, and this information is also deducible by
+ performing a network traffic analysis, so this provides a very
+ limited but still worthwhile degree of protection.
+
+ SIP Via fields are used to route a response back along the path taken
+ by the request and to prevent infinite request loops. However, the
+ information given by them can also provide useful information to an
+ attacker. Section 6.22 describes how a sender can request that Via
+ fields be encrypted by cooperating proxies without compromising the
+ purpose of the Via field.
+
+ End-to-end encryption relies on keys shared by the two user agents
+ involved in the request. Typically, the message is sent encrypted
+ with the public key of the recipient, so that only that recipient can
+ read the message. All implementations SHOULD support PGP-based
+ encryption [33] and MAY implement other schemes.
+
+ A SIP request (or response) is end-to-end encrypted by splitting the
+ message to be sent into a part to be encrypted and a short header
+ that will remain in the clear. Some parts of the SIP message, namely
+ the request line, the response line and certain header fields marked
+ with "n" in the "enc." column in Table 4 and 5 need to be read and
+ returned by proxies and thus MUST NOT be encrypted end-to-end.
+ Possibly sensitive information that needs to be made available as
+ plaintext include destination address (To) and the forwarding path
+ (Via) of the call. The Authorization header field MUST remain in the
+ clear if it contains a digital signature as the signature is
+ generated after encryption, but MAY be encrypted if it contains
+ "basic" or "digest" authentication. The From header field SHOULD
+ normally remain in the clear, but MAY be encrypted if required, in
+ which case some proxies MAY return a 401 (Unauthorized) status if
+ they require a From field.
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 105]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ Other header fields MAY be encrypted or MAY travel in the clear as
+ desired by the sender. The Subject, Allow and Content-Type header
+ fields will typically be encrypted. The Accept, Accept-Language,
+ Date, Expires, Priority, Require, Call-ID, Cseq, and Timestamp header
+ fields will remain in the clear.
+
+ All fields that will remain in the clear MUST precede those that will
+ be encrypted. The message is encrypted starting with the first
+ character of the first header field that will be encrypted and
+ continuing through to the end of the message body. If no header
+ fields are to be encrypted, encrypting starts with the second CRLF
+ pair after the last header field, as shown below. Carriage return and
+ line feed characters have been made visible as "$", and the encrypted
+ part of the message is outlined.
+
+
+ INVITE sip:watson at boston.bell-telephone.com SIP/2.0$
+ Via: SIP/2.0/UDP 169.130.12.5$
+ To: T. A. Watson <sip:watson at bell-telephone.com>$
+ From: A. Bell <sip:a.g.bell at bell-telephone.com>$
+ Encryption: PGP version=5.0$
+ Content-Length: 224$
+ Call-ID: 187602141351 at worcester.bell-telephone.com$
+ CSeq: 488$
+ $
+ *******************************************************
+ * Subject: Mr. Watson, come here.$ *
+ * Content-Type: application/sdp$ *
+ * $ *
+ * v=0$ *
+ * o=bell 53655765 2353687637 IN IP4 128.3.4.5$ *
+ * c=IN IP4 135.180.144.94$ *
+ * m=audio 3456 RTP/AVP 0 3 4 5$ *
+ *******************************************************
+
+
+
+ An Encryption header field MUST be added to indicate the encryption
+ mechanism used. A Content-Length field is added that indicates the
+ length of the encrypted body. The encrypted body is preceded by a
+ blank line as a normal SIP message body would be.
+
+ Upon receipt by the called user agent possessing the correct
+ decryption key, the message body as indicated by the Content-Length
+ field is decrypted, and the now-decrypted body is appended to the
+ clear-text header fields. There is no need for an additional
+ Content-Length header field within the encrypted body because the
+ length of the actual message body is unambiguous after decryption.
+
+
+
+Handley, et al. Standards Track [Page 106]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ Had no SIP header fields required encryption, the message would have
+ been as below. Note that the encrypted body MUST then include a blank
+ line (start with CRLF) to disambiguate between any possible SIP
+ header fields that might have been present and the SIP message body.
+
+
+ INVITE sip:watson at boston.bell-telephone.com SIP/2.0$
+ Via: SIP/2.0/UDP 169.130.12.5$
+ To: T. A. Watson <sip:watson at bell-telephone.com>$
+ From: A. Bell <a.g.bell at bell-telephone.com>$
+ Encryption: PGP version=5.0$
+ Content-Type: application/sdp$
+ Content-Length: 107$
+ $
+ *************************************************
+ * $ *
+ * v=0$ *
+ * o=bell 53655765 2353687637 IN IP4 128.3.4.5$ *
+ * c=IN IP4 135.180.144.94$ *
+ * m=audio 3456 RTP/AVP 0 3 4 5$ *
+ *************************************************
+
+
+
+13.1.2 Privacy of SIP Responses
+
+ SIP requests can be sent securely using end-to-end encryption and
+ authentication to a called user agent that sends an insecure
+ response. This is allowed by the SIP security model, but is not a
+ good idea. However, unless the correct behavior is explicit, it
+ would not always be possible for the called user agent to infer what
+ a reasonable behavior was. Thus when end-to-end encryption is used by
+ the request originator, the encryption key to be used for the
+ response SHOULD be specified in the request. If this were not done,
+ it might be possible for the called user agent to incorrectly infer
+ an appropriate key to use in the response. Thus, to prevent key-
+ guessing becoming an acceptable strategy, we specify that a called
+ user agent receiving a request that does not specify a key to be used
+ for the response SHOULD send that response unencrypted.
+
+ Any SIP header fields that were encrypted in a request SHOULD also be
+ encrypted in an encrypted response. Contact response fields MAY be
+ encrypted if the information they contain is sensitive, or MAY be
+ left in the clear to permit proxies more scope for localized
+ searches.
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 107]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+13.1.3 Encryption by Proxies
+
+ Normally, proxies are not allowed to alter end-to-end header fields
+ and message bodies. Proxies MAY, however, encrypt an unsigned request
+ or response with the key of the call recipient.
+
+
+ Proxies need to encrypt a SIP request if the end system
+ cannot perform encryption or to enforce organizational
+ security policies.
+
+13.1.4 Hop-by-Hop Encryption
+
+ SIP requests and responses MAY also be protected by security
+ mechanisms at the transport or network layer. No particular mechanism
+ is defined or recommended here. Two possibilities are IPSEC [34] or
+ TLS [35]. The use of a particular mechanism will generally need to be
+ specified out of band, through manual configuration, for example.
+
+13.1.5 Via field encryption
+
+ When Via header fields are to be hidden, a proxy that receives a
+ request containing an appropriate "Hide: hop" header field (as
+ specified in section 6.22) SHOULD encrypt the header field. As only
+ the proxy that encrypts the field will decrypt it, the algorithm
+ chosen is entirely up to the proxy implementor. Two methods satisfy
+ these requirements:
+
+ o The server keeps a cache of Via header fields and the
+ associated To header field, and replaces the Via header field
+ with an index into the cache. On the reverse path, take the
+ Via header field from the cache rather than the message.
+
+ This is insufficient to prevent message looping, and so an
+ additional ID MUST be added so that the proxy can detect loops.
+ This SHOULD NOT normally be the address of the proxy as the goal
+ is to hide the route, so instead a sufficiently large random
+ number SHOULD be used by the proxy and maintained in the cache.
+
+ It is possible for replies to get directed to the wrong
+ originator if the cache entry gets reused, so great care needs
+ to be taken to ensure this does not happen.
+
+ o The server MAY use a secret key to encrypt the Via field, a
+ timestamp and an appropriate checksum in any such message with
+ the same secret key. The checksum is needed to detect whether
+ successful decoding has occurred, and the timestamp is
+
+
+
+
+Handley, et al. Standards Track [Page 108]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ required to prevent possible replay attacks and to ensure that
+ no two requests from the same previous hop have the same
+ encrypted Via field. This is the preferred solution.
+
+13.2 Message Integrity and Access Control: Authentication
+
+ Protective measures need to be taken to prevent an active attacker
+ from modifying and replaying SIP requests and responses. The same
+ cryptographic measures that are used to ensure the authenticity of
+ the SIP message also serve to authenticate the originator of the
+ message. However, the "basic" and "digest" authentication mechanism
+ offer authentication only, without message integrity.
+
+ Transport-layer or network-layer authentication MAY be used for hop-
+ by-hop authentication. SIP also extends the HTTP WWW-Authenticate
+ (Section 6.42) and Authorization (Section 6.11) header field and
+ their Proxy counterparts to include cryptographically strong
+ signatures. SIP also supports the HTTP "basic" and "digest" schemes
+ (see Section 14) and other HTTP authentication schemes to be defined
+ that offer a rudimentary mechanism of ascertaining the identity of
+ the caller.
+
+
+ Since SIP requests are often sent to parties with which no
+ prior communication relationship has existed, we do not
+ specify authentication based on shared secrets.
+
+ SIP requests MAY be authenticated using the Authorization header
+ field to include a digital signature of certain header fields, the
+ request method and version number and the payload, none of which are
+ modified between client and called user agent. The Authorization
+ header field is used in requests to authenticate the request
+ originator end-to-end to proxies and the called user agent, and in
+ responses to authenticate the called user agent or proxies returning
+ their own failure codes. If required, hop-by-hop authentication can
+ be provided, for example, by the IPSEC Authentication Header.
+
+ SIP does not dictate which digital signature scheme is used for
+ authentication, but does define how to provide authentication using
+ PGP in Section 15. As indicated above, SIP implementations MAY also
+ use "basic" and "digest" authentication and other authentication
+ mechanisms defined for HTTP. Note that "basic" authentication has
+ severe security limitations. The following does not apply to these
+ schemes.
+
+ To cryptographically sign a SIP request, the order of the SIP header
+ fields is important. When an Authorization header field is present,
+ it indicates that all header fields following the Authorization
+
+
+
+Handley, et al. Standards Track [Page 109]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ header field have been included in the signature. Therefore, hop-
+ by-hop header fields which MUST or SHOULD be modified by proxies MUST
+ precede the Authorization header field as they will generally be
+ modified or added-to by proxy servers. Hop-by-hop header fields
+ which MAY be modified by a proxy MAY appear before or after the
+ Authorization header. When they appear before, they MAY be modified
+ by a proxy. When they appear after, they MUST NOT be modified by a
+ proxy. To sign a request, a client constructs a message from the
+ request method (in upper case) followed, without LWS, by the SIP
+ version number, followed, again without LWS, by the request headers
+ to be signed and the message body. The message thus constructed is
+ then signed.
+
+ For example, if the SIP request is to be:
+
+ INVITE sip:watson at boston.bell-telephone.com SIP/2.0
+ Via: SIP/2.0/UDP 169.130.12.5
+ Authorization: PGP version=5.0, signature=...
+ From: A. Bell <sip:a.g.bell at bell-telephone.com>
+ To: T. A. Watson <sip:watson at bell-telephone.com>
+ Call-ID: 187602141351 at worcester.bell-telephone.com
+ Subject: Mr. Watson, come here.
+ Content-Type: application/sdp
+ Content-Length: ...
+
+ v=0
+ o=bell 53655765 2353687637 IN IP4 128.3.4.5
+ c=IN IP4 135.180.144.94
+ m=audio 3456 RTP/AVP 0 3 4 5
+
+
+
+ Then the data block that is signed is:
+
+ INVITESIP/2.0From: A. Bell <sip:a.g.bell at bell-telephone.com>
+ To: T. A. Watson <sip:watson at bell-telephone.com>
+ Call-ID: 187602141351 at worcester.bell-telephone.com
+ Subject: Mr. Watson, come here.
+ Content-Type: application/sdp
+ Content-Length: ...
+
+ v=0
+ o=bell 53655765 2353687637 IN IP4 128.3.4.5
+ c=IN IP4 135.180.144.94
+ m=audio 3456 RTP/AVP 0 3 4 5
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 110]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ Clients wishing to authenticate requests MUST construct the portion
+ of the message below the Authorization header using a canonical form.
+ This allows a proxy to parse the message, take it apart, and
+ reconstruct it, without causing an authentication failure due to
+ extra white space, for example. Canonical form consists of the
+ following rules:
+
+ o No short form header fields
+
+ o Header field names are capitalized as shown in this document
+
+ o No white space between the header name and the colon
+
+ o A single space after the colon
+
+ o Line termination with a CRLF
+
+ o No line folding
+
+ o No comma separated lists of header values; each must appear
+ as a separate header
+
+ o Only a single SP between tokens, between tokens and quoted
+ strings, and between quoted strings; no SP after last token or
+ quoted string
+
+ o No LWS between tokens and separators, except as described
+ above for after the colon in header fields
+
+ Note that if a message is encrypted and authenticated using a digital
+ signature, when the message is generated encryption is performed
+ before the digital signature is generated. On receipt, the digital
+ signature is checked before decryption.
+
+ A client MAY require that a server sign its response by including a
+ Require: org.ietf.sip.signed-response request header field. The
+ client indicates the desired authentication method via the WWW-
+ Authenticate header.
+
+ The correct behavior in handling unauthenticated responses to a
+ request that requires authenticated responses is described in section
+ 13.2.1.
+
+
+
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 111]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+13.2.1 Trusting responses
+
+ There is the possibility that an eavesdropper listens to requests and
+ then injects unauthenticated responses that terminate, redirect or
+ otherwise interfere with a call. (Even encrypted requests contain
+ enough information to fake a response.)
+
+ Clients need to be particularly careful with 3xx redirection
+ responses. Thus a client receiving, for example, a 301 (Moved
+ Permanently) which was not authenticated when the public key of the
+ called user agent is known to the client, and authentication was
+ requested in the request SHOULD be treated as suspicious. The correct
+ behavior in such a case would be for the called-user to form a dated
+ response containing the Contact field to be used, to sign it, and
+ give this signed stub response to the proxy that will provide the
+ redirection. Thus the response can be authenticated correctly. A
+ client SHOULD NOT automatically redirect such a request to the new
+ location without alerting the user to the authentication failure
+ before doing so.
+
+ Another problem might be responses such as 6xx failure responses
+ which would simply terminate a search, or "4xx" and "5xx" response
+ failures.
+
+ If TCP is being used, a proxy SHOULD treat 4xx and 5xx responses as
+ valid, as they will not terminate a search. However, fake 6xx
+ responses from a rogue proxy terminate a search incorrectly. 6xx
+ responses SHOULD be authenticated if requested by the client, and
+ failure to do so SHOULD cause such a client to ignore the 6xx
+ response and continue a search.
+
+ With UDP, the same problem with 6xx responses exists, but also an
+ active eavesdropper can generate 4xx and 5xx responses that might
+ cause a proxy or client to believe a failure occurred when in fact it
+ did not. Typically 4xx and 5xx responses will not be signed by the
+ called user agent, and so there is no simple way to detect these
+ rogue responses. This problem is best prevented by using hop-by-hop
+ encryption of the SIP request, which removes any additional problems
+ that UDP might have over TCP.
+
+ These attacks are prevented by having the client require response
+ authentication and dropping unauthenticated responses. A server user
+ agent that cannot perform response authentication responds using the
+ normal Require response of 420 (Bad Extension).
+
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 112]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+13.3 Callee Privacy
+
+ User location and SIP-initiated calls can violate a callee's privacy.
+ An implementation SHOULD be able to restrict, on a per-user basis,
+ what kind of location and availability information is given out to
+ certain classes of callers.
+
+13.4 Known Security Problems
+
+ With either TCP or UDP, a denial of service attack exists by a rogue
+ proxy sending 6xx responses. Although a client SHOULD choose to
+ ignore such responses if it requested authentication, a proxy cannot
+ do so. It is obliged to forward the 6xx response back to the client.
+ The client can then ignore the response, but if it repeats the
+ request it will probably reach the same rogue proxy again, and the
+ process will repeat.
+
+14 SIP Authentication using HTTP Basic and Digest Schemes
+
+ SIP implementations MAY use HTTP's basic and digest authentication
+ mechanisms to provide a rudimentary form of security. This section
+ overviews usage of these mechanisms in SIP. The basic operation is
+ almost completely identical to that for HTTP [36]. This section
+ outlines this operation, pointing to [36] for details, and noting the
+ differences when used in SIP.
+
+14.1 Framework
+
+ The framework for SIP authentication parallels that for HTTP [36]. In
+ particular, the BNF for auth-scheme, auth-param, challenge, realm,
+ realm-value, and credentials is identical. The 401 response is used
+ by user agent servers in SIP to challenge the authorization of a user
+ agent client. Additionally, registrars and redirect servers MAY make
+ use of 401 responses for authorization, but proxies MUST NOT, and
+ instead MAY use the 407 response. The requirements for inclusion of
+ the Proxy-Authenticate, Proxy-Authorization, WWW-Authenticate, and
+ Authorization in the various messages is identical to [36].
+
+ Since SIP does not have the concept of a canonical root URL, the
+ notion of protections spaces are interpreted differently for SIP. The
+ realm is a protection domain for all SIP URIs with the same value for
+ the userinfo, host and port part of the SIP Request-URI. For example:
+
+
+ INVITE sip:alice.wonderland at example.com SIP/2.0
+ WWW-Authenticate: Basic realm="business"
+
+
+
+
+
+Handley, et al. Standards Track [Page 113]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ and
+
+
+ INVITE sip:aw at example.com SIP/2.0
+ WWW-Authenticate: Basic realm="business"
+
+
+
+ define different protection realms according to this rule.
+
+ When a UAC resubmits a request with its credentials after receiving a
+ 401 or 407 response, it MUST increment the CSeq header field as it
+ would normally do when sending an updated request.
+
+14.2 Basic Authentication
+
+ The rules for basic authentication follow those defined in [36], but
+ with the words "origin server" replaced with "user agent server,
+ redirect server , or registrar".
+
+ Since SIP URIs are not hierarchical, the paragraph in [36] that
+ states that "all paths at or deeper than the depth of the last
+ symbolic element in the path field of the Request-URI also are within
+ the protection space specified by the Basic realm value of the
+ current challenge" does not apply for SIP. SIP clients MAY
+ preemptively send the corresponding Authorization header with
+ requests for SIP URIs within the same protection realm (as defined
+ above) without receipt of another challenge from the server.
+
+14.3 Digest Authentication
+
+ The rules for digest authentication follow those defined in [36],
+ with "HTTP 1.1" replaced by "SIP/2.0" in addition to the following
+ differences:
+
+ 1. The URI included in the challenge has the following BNF:
+
+
+ URI = SIP-URL
+
+
+ 2. The BNF for digest-uri-value is:
+
+
+ digest-uri-value = Request-URI ; a defined in Section
+ 4.3
+
+
+
+
+
+Handley, et al. Standards Track [Page 114]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ 3. The example procedure for choosing a nonce based on Etag
+ does not work for SIP.
+
+ 4. The Authentication-Info and Proxy-Authentication-Info
+ fields are not used in SIP.
+
+ 5. The text in [36] regarding cache operation does not apply
+ to SIP.
+
+ 6. [36] requires that a server check that the URI in the
+ request line, and the URI included in the Authorization
+ header, point to the same resource. In a SIP context, these
+ two URI's may actually refer to different users, due to
+ forwarding at some proxy. Therefore, in SIP, a server MAY
+ check that the request-uri in the Authorization header
+ corresponds to a user that the server is willing to accept
+ forwarded or direct calls for.
+
+14.4 Proxy-Authentication
+
+ The use of the Proxy-Authentication and Proxy-Authorization parallel
+ that as described in [36], with one difference. Proxies MUST NOT add
+ the Proxy-Authorization header. 407 responses MUST be forwarded
+ upstream towards the client following the procedures for any other
+ response. It is the client's responsibility to add the Proxy-
+ Authorization header containing credentials for the proxy which has
+ asked for authentication.
+
+
+ If a proxy were to resubmit a request with a Proxy-
+ Authorization header field, it would need to increment the
+ CSeq in the new request. However, this would mean that the
+ UAC which submitted the original request would discard a
+ response from the UAS, as the CSeq value would be
+ different.
+
+ See sections 6.26 and 6.27 for additional information on usage of
+ these fields as they apply to SIP.
+
+15 SIP Security Using PGP
+
+15.1 PGP Authentication Scheme
+
+ The "pgp" authentication scheme is based on the model that the client
+ authenticates itself with a request signed with the client's private
+ key. The server can then ascertain the origin of the request if it
+ has access to the public key, preferably signed by a trusted third
+ party.
+
+
+
+Handley, et al. Standards Track [Page 115]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+15.1.1 The WWW-Authenticate Response Header
+
+
+
+ WWW-Authenticate = "WWW-Authenticate" ":" "pgp" pgp-challenge
+ pgp-challenge = * (";" pgp-params )
+ pgp-params = realm | pgp-version | pgp-algorithm | nonce
+ realm = "realm" "=" realm-value
+ realm-value = quoted-string
+ pgp-version = "version" "="
+ <"> digit *( "." digit ) *letter <">
+ pgp-algorithm = "algorithm" "=" ( "md5" | "sha1" | token )
+ nonce = "nonce" "=" nonce-value
+ nonce-value = quoted-string
+
+
+
+ The meanings of the values of the parameters used above are as
+ follows:
+
+ realm: A string to be displayed to users so they know which identity
+ to use. This string SHOULD contain at least the name of the host
+ performing the authentication and MAY additionally indicate the
+ collection of users who might have access. An example might be "
+ Users with call-out privileges ".
+
+ pgp-algorithm: The value of this parameter indicates the PGP message
+ integrity check (MIC) to be used to produce the signature. If
+ this not present it is assumed to be "md5". The currently
+ defined values are "md5" for the MD5 checksum, and "sha1" for
+ the SHA.1 algorithm.
+
+ pgp-version: The version of PGP that the client MUST use. Common
+ values are "2.6.2" and "5.0". The default is 5.0.
+
+ nonce: A server-specified data string which should be uniquely
+ generated each time a 401 response is made. It is RECOMMENDED
+ that this string be base64 or hexadecimal data. Specifically,
+ since the string is passed in the header lines as a quoted
+ string, the double-quote character is not allowed. The contents
+ of the nonce are implementation dependent. The quality of the
+ implementation depends on a good choice. Since the nonce is used
+ only to prevent replay attacks and is signed, a time stamp in
+ units convenient to the server is sufficient.
+
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 116]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ Replay attacks within the duration of the call setup are of
+ limited interest, so that timestamps with a resolution of a
+ few seconds are often should be sufficient. In that case,
+ the server does not have to keep a record of the nonces.
+
+ Example:
+
+ WWW-Authenticate: pgp ;version="5.0"
+ ;realm="Your Startrek identity, please" ;algorithm=md5
+ ;nonce="913082051"
+
+
+
+15.1.2 The Authorization Request Header
+
+ The client is expected to retry the request, passing an Authorization
+ header line, which is defined as follows.
+
+
+
+ Authorization = "Authorization" ":" "pgp" *( ";" pgp-response )
+ pgp-response = realm | pgp-version | pgp-signature
+ | signed-by | nonce
+ pgp-signature = "signature" "=" quoted-string
+ signed-by = "signed-by" "=" <"> URI <">
+
+
+ The client MUST increment the CSeq header before resubmitting the
+ request. The signature MUST correspond to the From header of the
+ request unless the signed-by parameter is provided.
+
+ pgp-signature: The PGP ASCII-armored signature [33], as it appears
+ between the "BEGIN PGP MESSAGE" and "END PGP MESSAGE"
+ delimiters, without the version indication. The signature is
+ included without any linebreaks.
+
+ The signature is computed across the nonce (if present), request
+ method, request version and header fields following the Authorization
+ header and the message body, in the same order as they appear in the
+ message. The request method and version are prepended to the header
+ fields without any white space. The signature is computed across the
+ headers as sent, and the terminating CRLF. The CRLF following the
+ Authorization header is NOT included in the signature.
+
+ A server MAY be configured not to generate nonces only if replay
+ attacks are not a concern.
+
+
+
+
+
+Handley, et al. Standards Track [Page 117]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ Not generating nonces avoids the additional set of request,
+ 401 response and possibly ACK messages and reduces delay by
+ one round-trip time.
+
+
+ Using the ASCII-armored version is about 25% less space-
+ efficient than including the binary signature, but it is
+ significantly easier for the receiver to piece together.
+ Versions of the PGP program always include the full
+ (compressed) signed text in their output unless ASCII-
+ armored mode ( -sta ) is specified. Typical signatures are
+ about 200 bytes long. -- The PGP signature mechanism allows
+ the client to simply pass the request to an external PGP
+ program. This relies on the requirement that proxy servers
+ are not allowed to reorder or change header fields.
+
+ realm: The realm is copied from the corresponding WWW-Authenticate
+ header field parameter.
+
+ signed-by: If and only if the request was not signed by the entity
+ listed in the From header, the signed-by header indicates the
+ name of the signing entity, expressed as a URI.
+
+ Receivers of signed SIP messages SHOULD discard any end-to-end header
+ fields above the Authorization header, as they may have been
+ maliciously added en route by a proxy.
+
+ Example:
+
+ Authorization: pgp version="5.0"
+ ;realm="Your Startrek identity, please"
+ ;nonce="913082051"
+ ;signature="iQB1AwUBNNJiUaYBnHmiiQh1AQFYsgL/Wt3dk6TWK81/b0gcNDf
+ VAUGU4rhEBW972IPxFSOZ94L1qhCLInTPaqhHFw1cb3lB01rA0RhpV4t5yCdUt
+ SRYBSkOK29o5e1KlFeW23EzYPVUm2TlDAhbcjbMdfC+KLFX
+ =aIrx"
+
+
+
+15.2 PGP Encryption Scheme
+
+ The PGP encryption scheme uses the following syntax:
+
+
+
+ Encryption = "Encryption" ":" "pgp" pgp-eparams
+ pgp-eparams = 1# ( pgp-version | pgp-encoding )
+ pgp-encoding = "encoding" "=" "ascii" | token
+
+
+
+Handley, et al. Standards Track [Page 118]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ encoding: Describes the encoding or "armor" used by PGP. The value
+ "ascii" refers to the standard PGP ASCII armor, without the
+ lines containing "BEGIN PGP MESSAGE" and "END PGP MESSAGE" and
+ without the version identifier. By default, the encrypted part
+ is included as binary.
+
+ Example:
+
+ Encryption: pgp version="2.6.2", encoding="ascii"
+
+
+
+15.3 Response-Key Header Field for PGP
+
+
+
+ Response-Key = "Response-Key" ":" "pgp" pgp-eparams
+ pgp-eparams = 1# ( pgp-version | pgp-encoding | pgp-key)
+ pgp-key = "key" "=" quoted-string
+
+
+ If ASCII encoding has been requested via the encoding parameter, the
+ key parameter contains the user's public key as extracted from the
+ pgp key ring with the "pgp -kxa user ".
+
+ Example:
+
+ Response-Key: pgp version="2.6.2", encoding="ascii",
+ key="mQBtAzNWHNYAAAEDAL7QvAdK2utY05wuUG+ItYK5tCF8HNJM60sU4rLaV+eUnkMk
+ mOmJWtc2wXcZx1XaXb2lkydTQOesrUR75IwNXBuZXPEIMThEa5WLsT7VLme7njnx
+ sE86SgWmAZx5ookIdQAFEbQxSGVubmluZyBTY2h1bHpyaW5uZSA8c2NodWx6cmlu
+ bmVAY3MuY29sdW1iaWEuZWR1Pg==
+ =+y19"
+
+
+
+16 Examples
+
+ In the following examples, we often omit the message body and the
+ corresponding Content-Length and Content-Type headers for brevity.
+
+16.1 Registration
+
+ A user at host saturn.bell-tel.com registers on start-up, via
+ multicast, with the local SIP server named bell-tel.com. In the
+ example, the user agent on saturn expects to receive SIP requests on
+ UDP port 3890.
+
+
+
+
+Handley, et al. Standards Track [Page 119]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ C->S: REGISTER sip:bell-tel.com SIP/2.0
+ Via: SIP/2.0/UDP saturn.bell-tel.com
+ From: sip:watson at bell-tel.com
+ To: sip:watson at bell-tel.com
+ Call-ID: 70710 at saturn.bell-tel.com
+ CSeq: 1 REGISTER
+ Contact: <sip:watson at saturn.bell-tel.com:3890;transport=udp>
+ Expires: 7200
+
+
+
+ The registration expires after two hours. Any future invitations for
+ watson at bell-tel.com arriving at sip.bell-tel.com will now be
+ redirected to watson at saturn.bell-tel.com, UDP port 3890.
+
+ If Watson wants to be reached elsewhere, say, an on-line service he
+ uses while traveling, he updates his reservation after first
+ cancelling any existing locations:
+
+
+ C->S: REGISTER sip:bell-tel.com SIP/2.0
+ Via: SIP/2.0/UDP saturn.bell-tel.com
+ From: sip:watson at bell-tel.com
+ To: sip:watson at bell-tel.com
+ Call-ID: 70710 at saturn.bell-tel.com
+ CSeq: 2 REGISTER
+ Contact: *
+ Expires: 0
+
+ C->S: REGISTER sip:bell-tel.com SIP/2.0
+ Via: SIP/2.0/UDP saturn.bell-tel.com
+ From: sip:watson at bell-tel.com
+ To: sip:watson at bell-tel.com
+ Call-ID: 70710 at saturn.bell-tel.com
+ CSeq: 3 REGISTER
+ Contact: sip:tawatson at example.com
+
+
+
+ Now, the server will forward any request for Watson to the server at
+ example.com, using the Request-URI tawatson at example.com. For the
+ server at example.com to reach Watson, he will need to send a
+ REGISTER there, or inform the server of his current location through
+ some other means.
+
+ It is possible to use third-party registration. Here, the secretary
+ jon.diligent registers his boss, T. Watson:
+
+
+
+
+Handley, et al. Standards Track [Page 120]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ C->S: REGISTER sip:bell-tel.com SIP/2.0
+ Via: SIP/2.0/UDP pluto.bell-tel.com
+ From: sip:jon.diligent at bell-tel.com
+ To: sip:watson at bell-tel.com
+ Call-ID: 17320 at pluto.bell-tel.com
+ CSeq: 1 REGISTER
+ Contact: sip:tawatson at example.com
+
+
+
+ The request could be sent to either the registrar at bell-tel.com or
+ the server at example.com. In the latter case, the server at
+ example.com would proxy the request to the address indicated in the
+ Request-URI. Then, Max-Forwards header could be used to restrict the
+ registration to that server.
+
+16.2 Invitation to a Multicast Conference
+
+ The first example invites schooler at vlsi.cs.caltech.edu to a multicast
+ session. All examples use the Session Description Protocol (SDP) (RFC
+ 2327 [6]) as the session description format.
+
+16.2.1 Request
+
+
+ C->S: INVITE sip:schooler at cs.caltech.edu SIP/2.0
+ Via: SIP/2.0/UDP csvax.cs.caltech.edu;branch=8348
+ ;maddr=239.128.16.254;ttl=16
+ Via: SIP/2.0/UDP north.east.isi.edu
+ From: Mark Handley <sip:mjh at isi.edu>
+ To: Eve Schooler <sip:schooler at caltech.edu>
+ Call-ID: 2963313058 at north.east.isi.edu
+ CSeq: 1 INVITE
+ Subject: SIP will be discussed, too
+ Content-Type: application/sdp
+ Content-Length: 187
+
+ v=0
+ o=user1 53655765 2353687637 IN IP4 128.3.4.5
+ s=Mbone Audio
+ i=Discussion of Mbone Engineering Issues
+ e=mbone at somewhere.com
+ c=IN IP4 224.2.0.1/127
+ t=0 0
+ m=audio 3456 RTP/AVP 0
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 121]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ The From request header above states that the request was initiated
+ by mjh at isi.edu and addressed to schooler at caltech.edu (From header
+ fields). The Via fields list the hosts along the path from invitation
+ initiator (the last element of the list) towards the callee. In the
+ example above, the message was last multicast to the administratively
+ scoped group 239.128.16.254 with a ttl of 16 from the host
+ csvax.cs.caltech.edu. The second Via header field indicates that it
+ was originally sent from the host north.east.isi.edu. The Request-URI
+ indicates that the request is currently being being addressed to
+ schooler at cs.caltech.edu, the local address that csvax looked up for
+ the callee.
+
+ In this case, the session description is using the Session
+ Description Protocol (SDP), as stated in the Content-Type header.
+
+ The header is terminated by an empty line and is followed by a
+ message body containing the session description.
+
+16.2.2 Response
+
+ The called user agent, directly or indirectly through proxy servers,
+ indicates that it is alerting ("ringing") the called party:
+
+
+ S->C: SIP/2.0 180 Ringing
+ Via: SIP/2.0/UDP csvax.cs.caltech.edu;branch=8348
+ ;maddr=239.128.16.254;ttl=16
+ Via: SIP/2.0/UDP north.east.isi.edu
+ From: Mark Handley <sip:mjh at isi.edu>
+ To: Eve Schooler <sip:schooler at caltech.edu> ;tag=9883472
+ Call-ID: 2963313058 at north.east.isi.edu
+ CSeq: 1 INVITE
+
+
+
+ A sample response to the invitation is given below. The first line of
+ the response states the SIP version number, that it is a 200 (OK)
+ response, which means the request was successful. The Via headers are
+ taken from the request, and entries are removed hop by hop as the
+ response retraces the path of the request. A new authentication field
+ MAY be added by the invited user's agent if required. The Call-ID is
+ taken directly from the original request, along with the remaining
+ fields of the request message. The original sense of From field is
+ preserved (i.e., it is the session initiator).
+
+ In addition, the Contact header gives details of the host where the
+ user was located, or alternatively the relevant proxy contact point
+ which should be reachable from the caller's host.
+
+
+
+Handley, et al. Standards Track [Page 122]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ S->C: SIP/2.0 200 OK
+ Via: SIP/2.0/UDP csvax.cs.caltech.edu;branch=8348
+ ;maddr=239.128.16.254;ttl=16
+ Via: SIP/2.0/UDP north.east.isi.edu
+ From: Mark Handley <sip:mjh at isi.edu>
+ To: Eve Schooler <sip:schooler at caltech.edu> ;tag=9883472
+ Call-ID: 2963313058 at north.east.isi.edu
+ CSeq: 1 INVITE
+ Contact: sip:es at jove.cs.caltech.edu
+
+
+
+ The caller confirms the invitation by sending an ACK request to the
+ location named in the Contact header:
+
+
+ C->S: ACK sip:es at jove.cs.caltech.edu SIP/2.0
+ Via: SIP/2.0/UDP north.east.isi.edu
+ From: Mark Handley <sip:mjh at isi.edu>
+ To: Eve Schooler <sip:schooler at caltech.edu> ;tag=9883472
+ Call-ID: 2963313058 at north.east.isi.edu
+ CSeq: 1 ACK
+
+
+
+16.3 Two-party Call
+
+ For two-party Internet phone calls, the response must contain a
+ description of where to send the data. In the example below, Bell
+ calls Watson. Bell indicates that he can receive RTP audio codings 0
+ (PCMU), 3 (GSM), 4 (G.723) and 5 (DVI4).
+
+
+ C->S: INVITE sip:watson at boston.bell-tel.com SIP/2.0
+ Via: SIP/2.0/UDP kton.bell-tel.com
+ From: A. Bell <sip:a.g.bell at bell-tel.com>
+ To: T. Watson <sip:watson at bell-tel.com>
+ Call-ID: 3298420296 at kton.bell-tel.com
+ CSeq: 1 INVITE
+ Subject: Mr. Watson, come here.
+ Content-Type: application/sdp
+ Content-Length: ...
+
+ v=0
+ o=bell 53655765 2353687637 IN IP4 128.3.4.5
+ s=Mr. Watson, come here.
+ c=IN IP4 kton.bell-tel.com
+ m=audio 3456 RTP/AVP 0 3 4 5
+
+
+
+Handley, et al. Standards Track [Page 123]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ S->C: SIP/2.0 100 Trying
+ Via: SIP/2.0/UDP kton.bell-tel.com
+ From: A. Bell <sip:a.g.bell at bell-tel.com>
+ To: T. Watson <sip:watson at bell-tel.com> ;tag=37462311
+ Call-ID: 3298420296 at kton.bell-tel.com
+ CSeq: 1 INVITE
+ Content-Length: 0
+
+ S->C: SIP/2.0 180 Ringing
+ Via: SIP/2.0/UDP kton.bell-tel.com
+ From: A. Bell <sip:a.g.bell at bell-tel.com>
+ To: T. Watson <sip:watson at bell-tel.com> ;tag=37462311
+ Call-ID: 3298420296 at kton.bell-tel.com
+ CSeq: 1 INVITE
+ Content-Length: 0
+
+ S->C: SIP/2.0 182 Queued, 2 callers ahead
+ Via: SIP/2.0/UDP kton.bell-tel.com
+ From: A. Bell <sip:a.g.bell at bell-tel.com>
+ To: T. Watson <sip:watson at bell-tel.com> ;tag=37462311
+ Call-ID: 3298420296 at kton.bell-tel.com
+ CSeq: 1 INVITE
+ Content-Length: 0
+
+ S->C: SIP/2.0 182 Queued, 1 caller ahead
+ Via: SIP/2.0/UDP kton.bell-tel.com
+ From: A. Bell <sip:a.g.bell at bell-tel.com>
+ To: T. Watson <sip:watson at bell-tel.com> ;tag=37462311
+ Call-ID: 3298420296 at kton.bell-tel.com
+ CSeq: 1 INVITE
+ Content-Length: 0
+
+ S->C: SIP/2.0 200 OK
+ Via: SIP/2.0/UDP kton.bell-tel.com
+ From: A. Bell <sip:a.g.bell at bell-tel.com>
+ To: <sip:watson at bell-tel.com> ;tag=37462311
+ Call-ID: 3298420296 at kton.bell-tel.com
+ CSeq: 1 INVITE
+ Contact: sip:watson at boston.bell-tel.com
+ Content-Type: application/sdp
+ Content-Length: ...
+
+ v=0
+ o=watson 4858949 4858949 IN IP4 192.1.2.3
+ s=I'm on my way
+ c=IN IP4 boston.bell-tel.com
+ m=audio 5004 RTP/AVP 0 3
+
+
+
+
+Handley, et al. Standards Track [Page 124]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ The example illustrates the use of informational status responses.
+ Here, the reception of the call is confirmed immediately (100), then,
+ possibly after some database mapping delay, the call rings (180) and
+ is then queued, with periodic status updates.
+
+ Watson can only receive PCMU and GSM. Note that Watson's list of
+ codecs may or may not be a subset of the one offered by Bell, as each
+ party indicates the data types it is willing to receive. Watson will
+ send audio data to port 3456 at c.bell-tel.com, Bell will send to
+ port 5004 at boston.bell-tel.com.
+
+ By default, the media session is one RTP session. Watson will receive
+ RTCP packets on port 5005, while Bell will receive them on port 3457.
+
+ Since the two sides have agreed on the set of media, Bell confirms
+ the call without enclosing another session description:
+
+
+ C->S: ACK sip:watson at boston.bell-tel.com SIP/2.0
+ Via: SIP/2.0/UDP kton.bell-tel.com
+ From: A. Bell <sip:a.g.bell at bell-tel.com>
+ To: T. Watson <sip:watson at bell-tel.com> ;tag=37462311
+ Call-ID: 3298420296 at kton.bell-tel.com
+ CSeq: 1 ACK
+
+
+
+16.4 Terminating a Call
+
+ To terminate a call, caller or callee can send a BYE request:
+
+
+ C->S: BYE sip:watson at boston.bell-tel.com SIP/2.0
+ Via: SIP/2.0/UDP kton.bell-tel.com
+ From: A. Bell <sip:a.g.bell at bell-tel.com>
+ To: T. A. Watson <sip:watson at bell-tel.com> ;tag=37462311
+ Call-ID: 3298420296 at kton.bell-tel.com
+ CSeq: 2 BYE
+
+
+
+ If the callee wants to abort the call, it simply reverses the To and
+ From fields. Note that it is unlikely that a BYE from the callee will
+ traverse the same proxies as the original INVITE.
+
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 125]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+16.5 Forking Proxy
+
+ In this example, Bell (a.g.bell at bell-tel.com) (C), currently seated
+ at host c.bell-tel.com wants to call Watson (t.watson at ieee.org). At
+ the time of the call, Watson is logged in at two workstations,
+ t.watson at x.bell-tel.com (X) and watson at y.bell-tel.com (Y), and has
+ registered with the IEEE proxy server (P) called sip.ieee.org. The
+ IEEE server also has a registration for the home machine of Watson,
+ at watson at h.bell-tel.com (H), as well as a permanent registration at
+ watson at acm.org (A). For brevity, the examples omit the session
+ description and Via header fields.
+
+ Bell's user agent sends the invitation to the SIP server for the
+ ieee.org domain:
+
+
+ C->P: INVITE sip:t.watson at ieee.org SIP/2.0
+ Via: SIP/2.0/UDP c.bell-tel.com
+ From: A. Bell <sip:a.g.bell at bell-tel.com>
+ To: T. Watson <sip:t.watson at ieee.org>
+ Call-ID: 31415 at c.bell-tel.com
+ CSeq: 1 INVITE
+
+
+
+ The SIP server at ieee.org tries the four addresses in parallel. It
+ sends the following message to the home machine:
+
+
+ P->H: INVITE sip:watson at h.bell-tel.com SIP/2.0
+ Via: SIP/2.0/UDP sip.ieee.org ;branch=1
+ Via: SIP/2.0/UDP c.bell-tel.com
+ From: A. Bell <sip:a.g.bell at bell-tel.com>
+ To: T. Watson <sip:t.watson at ieee.org>
+ Call-ID: 31415 at c.bell-tel.com
+ CSeq: 1 INVITE
+
+
+
+ This request immediately yields a 404 (Not Found) response, since
+ Watson is not currently logged in at home:
+
+
+ H->P: SIP/2.0 404 Not Found
+ Via: SIP/2.0/UDP sip.ieee.org ;branch=1
+ Via: SIP/2.0/UDP c.bell-tel.com
+ From: A. Bell <sip:a.g.bell at bell-tel.com>
+ To: T. Watson <sip:t.watson at ieee.org>;tag=87454273
+
+
+
+Handley, et al. Standards Track [Page 126]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ Call-ID: 31415 at c.bell-tel.com
+ CSeq: 1 INVITE
+
+
+
+ The proxy ACKs the response so that host H can stop retransmitting
+ it:
+
+ P->H: ACK sip:watson at h.bell-tel.com SIP/2.0
+ Via: SIP/2.0/UDP sip.ieee.org ;branch=1
+ From: A. Bell <sip:a.g.bell at bell-tel.com>
+ To: T. Watson <sip:t.watson at ieee.org>;tag=87454273
+ Call-ID: 31415 at c.bell-tel.com
+ CSeq: 1 ACK
+
+
+
+ Also, P attempts to reach Watson through the ACM server:
+
+ P->A: INVITE sip:watson at acm.org SIP/2.0
+ Via: SIP/2.0/UDP sip.ieee.org ;branch=2
+ Via: SIP/2.0/UDP c.bell-tel.com
+ From: A. Bell <sip:a.g.bell at bell-tel.com>
+ To: T. Watson <sip:t.watson at ieee.org>
+ Call-ID: 31415 at c.bell-tel.com
+ CSeq: 1 INVITE
+
+
+
+ In parallel, the next attempt proceeds, with an INVITE to X and Y:
+
+
+ P->X: INVITE sip:t.watson at x.bell-tel.com SIP/2.0
+ Via: SIP/2.0/UDP sip.ieee.org ;branch=3
+ Via: SIP/2.0/UDP c.bell-tel.com
+ From: A. Bell <sip:a.g.bell at bell-tel.com>
+ To: T. Watson <sip:t.watson at ieee.org>
+ Call-ID: 31415 at c.bell-tel.com
+ CSeq: 1 INVITE
+
+ P->Y: INVITE sip:watson at y.bell-tel.com SIP/2.0
+ Via: SIP/2.0/UDP sip.ieee.org ;branch=4
+ Via: SIP/2.0/UDP c.bell-tel.com
+ From: A. Bell <sip:a.g.bell at bell-tel.com>
+ To: T. Watson <sip:t.watson at ieee.org>
+ Call-ID: 31415 at c.bell-tel.com
+ CSeq: 1 INVITE
+
+
+
+
+Handley, et al. Standards Track [Page 127]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ As it happens, both Watson at X and a colleague in the other lab at
+ host Y hear the phones ringing and pick up. Both X and Y return 200s
+ via the proxy to Bell.
+
+
+ X->P: SIP/2.0 200 OK
+ Via: SIP/2.0/UDP sip.ieee.org ;branch=3
+ Via: SIP/2.0/UDP c.bell-tel.com
+ From: A. Bell <sip:a.g.bell at bell-tel.com>
+ To: T. Watson <sip:t.watson at ieee.org> ;tag=192137601
+ Call-ID: 31415 at c.bell-tel.com
+ CSeq: 1 INVITE
+ Contact: sip:t.watson at x.bell-tel.com
+
+ Y->P: SIP/2.0 200 OK
+ Via: SIP/2.0/UDP sip.ieee.org ;branch=4
+ Via: SIP/2.0/UDP c.bell-tel.com
+ Contact: sip:t.watson at y.bell-tel.com
+ From: A. Bell <sip:a.g.bell at bell-tel.com>
+ To: T. Watson <sip:t.watson at ieee.org> ;tag=35253448
+ Call-ID: 31415 at c.bell-tel.com
+ CSeq: 1 INVITE
+
+
+
+ Both responses are forwarded to Bell, using the Via information. At
+ this point, the ACM server is still searching its database. P can now
+ cancel this attempt:
+
+
+ P->A: CANCEL sip:watson at acm.org SIP/2.0
+ Via: SIP/2.0/UDP sip.ieee.org ;branch=2
+ From: A. Bell <sip:a.g.bell at bell-tel.com>
+ To: T. Watson <sip:t.watson at ieee.org>
+ Call-ID: 31415 at c.bell-tel.com
+ CSeq: 1 CANCEL
+
+
+
+ The ACM server gladly stops its neural-network database search and
+ responds with a 200. The 200 will not travel any further, since P is
+ the last Via stop.
+
+
+ A->P: SIP/2.0 200 OK
+ Via: SIP/2.0/UDP sip.ieee.org ;branch=2
+ From: A. Bell <sip:a.g.bell at bell-tel.com>
+ To: T. Watson <sip:t.watson at ieee.org>
+
+
+
+Handley, et al. Standards Track [Page 128]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ Call-ID: 31415 at c.bell-tel.com
+ CSeq: 1 CANCEL
+
+
+
+ Bell gets the two 200 responses from X and Y in short order. Bell's
+ reaction now depends on his software. He can either send an ACK to
+ both if human intelligence is needed to determine who he wants to
+ talk to or he can automatically reject one of the two calls. Here, he
+ acknowledges both, separately and directly to the final destination:
+
+
+ C->X: ACK sip:t.watson at x.bell-tel.com SIP/2.0
+ Via: SIP/2.0/UDP c.bell-tel.com
+ From: A. Bell <sip:a.g.bell at bell-tel.com>
+ To: T. Watson <sip:t.watson at ieee.org>;tag=192137601
+ Call-ID: 31415 at c.bell-tel.com
+ CSeq: 1 ACK
+
+ C->Y: ACK sip:watson at y.bell-tel.com SIP/2.0
+ Via: SIP/2.0/UDP c.bell-tel.com
+ From: A. Bell <sip:a.g.bell at bell-tel.com>
+ To: T. Watson <sip:t.watson at ieee.org>;tag=35253448
+ Call-ID: 31415 at c.bell-tel.com
+ CSeq: 1 ACK
+
+
+
+ After a brief discussion between Bell with X and Y, it becomes clear
+ that Watson is at X. (Note that this is not a three-way call; only
+ Bell can talk to X and Y, but X and Y cannot talk to each other.)
+ Thus, Bell sends a BYE to Y, which is replied to:
+
+
+ C->Y: BYE sip:watson at y.bell-tel.com SIP/2.0
+ Via: SIP/2.0/UDP c.bell-tel.com
+ From: A. Bell <sip:a.g.bell at bell-tel.com>
+ To: T. Watson <sip:t.watson at ieee.org>;tag=35253448
+ Call-ID: 31415 at c.bell-tel.com
+ CSeq: 2 BYE
+
+ Y->C: SIP/2.0 200 OK
+ Via: SIP/2.0/UDP c.bell-tel.com
+ From: A. Bell <sip:a.g.bell at bell-tel.com>
+ To: T. Watson <sip:t.watson at ieee.org>;tag=35253448
+ Call-ID: 31415 at c.bell-tel.com
+ CSeq: 2 BYE
+
+
+
+
+Handley, et al. Standards Track [Page 129]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+16.6 Redirects
+
+ Replies with status codes 301 (Moved Permanently) or 302 (Moved
+ Temporarily) specify another location using the Contact field.
+ Continuing our earlier example, the server P at ieee.org decides to
+ redirect rather than proxy the request:
+
+
+ P->C: SIP/2.0 302 Moved temporarily
+ Via: SIP/2.0/UDP c.bell-tel.com
+ From: A. Bell <sip:a.g.bell at bell-tel.com>
+ To: T. Watson <sip:t.watson at ieee.org>;tag=72538263
+ Call-ID: 31415 at c.bell-tel.com
+ CSeq: 1 INVITE
+ Contact: sip:watson at h.bell-tel.com,
+ sip:watson at acm.org, sip:t.watson at x.bell-tel.com,
+ sip:watson at y.bell-tel.com
+ CSeq: 1 INVITE
+
+
+
+ As another example, assume Alice (A) wants to delegate her calls to
+ Bob (B) while she is on vacation until July 29th, 1998. Any calls
+ meant for her will reach Bob with Alice's To field, indicating to him
+ what role he is to play. Charlie (C) calls Alice (A), whose server
+ returns:
+
+
+ A->C: SIP/2.0 302 Moved temporarily
+ From: Charlie <sip:charlie at caller.com>
+ To: Alice <sip:alice at anywhere.com> ;tag=2332462
+ Call-ID: 27182 at caller.com
+ Contact: sip:bob at anywhere.com
+ Expires: Wed, 29 Jul 1998 9:00:00 GMT
+ CSeq: 1 INVITE
+
+
+
+ Charlie then sends the following request to the SIP server of the
+ anywhere.com domain. Note that the server at anywhere.com forwards
+ the request to Bob based on the Request-URI.
+
+
+ C->B: INVITE sip:bob at anywhere.com SIP/2.0
+ From: sip:charlie at caller.com
+ To: sip:alice at anywhere.com
+ Call-ID: 27182 at caller.com
+ CSeq: 2 INVITE
+
+
+
+Handley, et al. Standards Track [Page 130]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ In the third redirection example, we assume that all outgoing
+ requests are directed through a local firewall F at caller.com, with
+ Charlie again inviting Alice:
+
+
+ C->F: INVITE sip:alice at anywhere.com SIP/2.0
+ From: sip:charlie at caller.com
+ To: Alice <sip:alice at anywhere.com>
+ Call-ID: 27182 at caller.com
+ CSeq: 1 INVITE
+
+
+
+ The local firewall at caller.com happens to be overloaded and thus
+ redirects the call from Charlie to a secondary server S:
+
+
+ F->C: SIP/2.0 302 Moved temporarily
+ From: sip:charlie at caller.com
+ To: Alice <sip:alice at anywhere.com>
+ Call-ID: 27182 at caller.com
+ CSeq: 1 INVITE
+ Contact: <sip:alice at anywhere.com:5080;maddr=spare.caller.com>
+
+
+
+ Based on this response, Charlie directs the same invitation to the
+ secondary server spare.caller.com at port 5080, but maintains the
+ same Request-URI as before:
+
+
+ C->S: INVITE sip:alice at anywhere.com SIP/2.0
+ From: sip:charlie at caller.com
+ To: Alice <sip:alice at anywhere.com>
+ Call-ID: 27182 at caller.com
+ CSeq: 2 INVITE
+
+
+
+16.7 Negotiation
+
+ An example of a 606 (Not Acceptable) response is:
+
+
+ S->C: SIP/2.0 606 Not Acceptable
+ From: sip:mjh at isi.edu
+ To: <sip:schooler at cs.caltech.edu> ;tag=7434264
+ Call-ID: 14142 at north.east.isi.edu
+
+
+
+Handley, et al. Standards Track [Page 131]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ CSeq: 1 INVITE
+ Contact: sip:mjh at north.east.isi.edu
+ Warning: 370 "Insufficient bandwidth (only have ISDN)",
+ 305 "Incompatible media format",
+ 330 "Multicast not available"
+ Content-Type: application/sdp
+ Content-Length: 50
+
+ v=0
+ s=Let's talk
+ b=CT:128
+ c=IN IP4 north.east.isi.edu
+ m=audio 3456 RTP/AVP 5 0 7
+ m=video 2232 RTP/AVP 31
+
+
+
+ In this example, the original request specified a bandwidth that was
+ higher than the access link could support, requested multicast, and
+ requested a set of media encodings. The response states that only 128
+ kb/s is available and that (only) DVI, PCM or LPC audio could be
+ supported in order of preference.
+
+ The response also states that multicast is not available. In such a
+ case, it might be appropriate to set up a transcoding gateway and
+ re-invite the user.
+
+16.8 OPTIONS Request
+
+ A caller Alice can use an OPTIONS request to find out the
+ capabilities of a potential callee Bob, without "ringing" the
+ designated address. Bob returns a description indicating that he is
+ capable of receiving audio encodings PCM Ulaw (payload type 0), 1016
+ (payload type 1), GSM (payload type 3), and SX7300/8000 (dynamic
+ payload type 99), and video encodings H.261 (payload type 31) and
+ H.263 (payload type 34).
+
+
+ C->S: OPTIONS sip:bob at example.com SIP/2.0
+ From: Alice <sip:alice at anywhere.org>
+ To: Bob <sip:bob at example.com>
+ Call-ID: 6378 at host.anywhere.org
+ CSeq: 1 OPTIONS
+ Accept: application/sdp
+
+ S->C: SIP/2.0 200 OK
+ From: Alice <sip:alice at anywhere.org>
+ To: Bob <sip:bob at example.com> ;tag=376364382
+
+
+
+Handley, et al. Standards Track [Page 132]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ Call-ID: 6378 at host.anywhere.org
+ Content-Length: 81
+ Content-Type: application/sdp
+
+ v=0
+ m=audio 0 RTP/AVP 0 1 3 99
+ m=video 0 RTP/AVP 31 34
+ a=rtpmap:99 SX7300/8000
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 133]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+A Minimal Implementation
+
+A.1 Client
+
+ All clients MUST be able to generate the INVITE and ACK requests.
+ Clients MUST generate and parse the Call-ID, Content-Length,
+ Content-Type, CSeq, From and To headers. Clients MUST also parse the
+ Require header. A minimal implementation MUST understand SDP (RFC
+ 2327, [6]). It MUST be able to recognize the status code classes 1
+ through 6 and act accordingly.
+
+ The following capability sets build on top of the minimal
+ implementation described in the previous paragraph. In general, each
+ capability listed below builds on the ones above it:
+
+ Basic: A basic implementation adds support for the BYE method to
+ allow the interruption of a pending call attempt. It includes a
+ User-Agent header in its requests and indicates its preferred
+ language in the Accept-Language header.
+
+ Redirection: To support call forwarding, a client needs to be able to
+ understand the Contact header, but only the SIP-URL part, not
+ the parameters.
+
+ Firewall-friendly: A firewall-friendly client understands the Route
+ and Record-Route header fields and can be configured to use a
+ local proxy for all outgoing requests.
+
+ Negotiation: A client MUST be able to request the OPTIONS method and
+ understand the 380 (Alternative Service) status and the Contact
+ parameters to participate in terminal and media negotiation. It
+ SHOULD be able to parse the Warning response header to provide
+ useful feedback to the caller.
+
+ Authentication: If a client wishes to invite callees that require
+ caller authentication, it MUST be able to recognize the 401
+ (Unauthorized) status code, MUST be able to generate the
+ Authorization request header and MUST understand the WWW-
+ Authenticate response header.
+
+ If a client wishes to use proxies that require caller authentication,
+ it MUST be able to recognize the 407 (Proxy Authentication Required)
+ status code, MUST be able to generate the Proxy-Authorization request
+ header and understand the Proxy-Authenticate response header.
+
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 134]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+A.2 Server
+
+ A minimally compliant server implementation MUST understand the
+ INVITE, ACK, OPTIONS and BYE requests. A proxy server MUST also
+ understand CANCEL. It MUST parse and generate, as appropriate, the
+ Call-ID, Content-Length, Content-Type, CSeq, Expires, From, Max-
+ Forwards, Require, To and Via headers. It MUST echo the CSeq and
+ Timestamp headers in the response. It SHOULD include the Server
+ header in its responses.
+
+A.3 Header Processing
+
+ Table 6 lists the headers that different implementations support. UAC
+ refers to a user-agent client (calling user agent), UAS to a user-
+ agent server (called user-agent).
+
+ The fields in the table have the following meaning. Type is as in
+ Table 4 and 5. "-" indicates the field is not meaningful to this
+ system (although it might be generated by it). "m" indicates the
+ field MUST be understood. "b" indicates the field SHOULD be
+ understood by a Basic implementation. "r" indicates the field SHOULD
+ be understood if the system claims to understand redirection. "a"
+ indicates the field SHOULD be understood if the system claims to
+ support authentication. "e" indicates the field SHOULD be understood
+ if the system claims to support encryption. "o" indicates support of
+ the field is purely optional. Headers whose support is optional for
+ all implementations are not shown.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 135]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+
+
+ type UAC proxy UAS registrar
+ _____________________________________________________
+ Accept R - o m m
+ Accept-Encoding R - - m m
+ Accept-Language R - b b b
+ Allow 405 o - - -
+ Authorization R a o a a
+ Call-ID g m m m m
+ Content-Encoding g m - m m
+ Content-Length g m m m m
+ Content-Type g m - m m
+ CSeq g m m m m
+ Encryption g e - e e
+ Expires g - o o m
+ From g m o m m
+ Hide R - m - -
+ Contact R - - - m
+ Contact r r r - -
+ Max-Forwards R - b - -
+ Proxy-Authenticate 407 a - - -
+ Proxy-Authorization R - a - -
+ Proxy-Require R - m - -
+ Require R m - m m
+ Response-Key R - - e e
+ Route R - m - -
+ Timestamp g o o m m
+ To g m m m m
+ Unsupported r b b - -
+ User-Agent g b - b -
+ Via g m m m m
+ WWW-Authenticate 401 a - - -
+
+
+ Table 6: Header Field Processing Requirements
+
+B Usage of the Session Description Protocol (SDP)
+
+ This section describes the use of the Session Description Protocol
+ (SDP) (RFC 2327 [6]).
+
+B.1 Configuring Media Streams
+
+ The caller and callee align their media descriptions so that the nth
+ media stream ("m=" line) in the caller's session description
+ corresponds to the nth media stream in the callee's description.
+
+
+
+
+Handley, et al. Standards Track [Page 136]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ All media descriptions SHOULD contain "a=rtpmap" mappings from RTP
+ payload types to encodings.
+
+ This allows easier migration away from static payload
+ types.
+
+ If the callee wants to neither send nor receive a stream offered by
+ the caller, the callee sets the port number of that stream to zero in
+ its media description.
+
+
+ There currently is no other way than port zero for the
+ callee to refuse a bidirectional stream offered by the
+ caller. Both caller and callee need to be aware what media
+ tools are to be started.
+
+ For example, assume that the caller Alice has included the following
+ description in her INVITE request. It includes an audio stream and
+ two bidirectional video streams, using H.261 (payload type 31) and
+ MPEG (payload type 32).
+
+
+ v=0
+ o=alice 2890844526 2890844526 IN IP4 host.anywhere.com
+ c=IN IP4 host.anywhere.com
+ m=audio 49170 RTP/AVP 0
+ a=rtpmap:0 PCMU/8000
+ m=video 51372 RTP/AVP 31
+ a=rtpmap:31 H261/90000
+ m=video 53000 RTP/AVP 32
+ a=rtpmap:32 MPV/90000
+
+
+
+ The callee, Bob, does not want to receive or send the first video
+ stream, so it returns the media description below:
+
+ v=0
+ o=bob 2890844730 2890844730 IN IP4 host.example.com
+ c=IN IP4 host.example.com
+ m=audio 47920 RTP/AVP 0 1
+ a=rtpmap:0 PCMU/8000
+ a=rtpmap:1 1016/8000
+ m=video 0 RTP/AVP 31
+ m=video 53000 RTP/AVP 32
+ a=rtpmap:32 MPV/90000
+
+
+
+
+
+Handley, et al. Standards Track [Page 137]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+B.2 Setting SDP Values for Unicast
+
+ If a session description from a caller contains a media stream which
+ is listed as send (receive) only, it means that the caller is only
+ willing to send (receive) this stream, not receive (send). The same
+ is true for the callee.
+
+ For receive-only and send-or-receive streams, the port number and
+ address in the session description indicate where the media stream
+ should be sent to by the recipient of the session description, either
+ caller or callee. For send-only streams, the address and port number
+ have no significance and SHOULD be set to zero.
+
+ The list of payload types for each media stream conveys two pieces of
+ information, namely the set of codecs that the caller or callee is
+ capable of sending or receiving, and the RTP payload type numbers
+ used to identify those codecs. For receive-only or send-and-receive
+ media streams, a caller SHOULD list all of the codecs it is capable
+ of supporting in the session description in an INVITE or ACK. For
+ send-only streams, the caller SHOULD indicate only those it wishes to
+ send for this session. For receive-only streams, the payload type
+ numbers indicate the value of the payload type field in RTP packets
+ the caller is expecting to receive for that codec type. For send-only
+ streams, the payload type numbers indicate the value of the payload
+ type field in RTP packets the caller is planning to send for that
+ codec type. For send-and-receive streams, the payload type numbers
+ indicate the value of the payload type field the caller expects to
+ both send and receive.
+
+ If a media stream is listed as receive-only by the caller, the callee
+ lists, in the response, those codecs it intends to use from among the
+ ones listed in the request. If a media stream is listed as send-only
+ by the caller, the callee lists, in the response, those codecs it is
+ willing to receive among the ones listed in the the request. If the
+ media stream is listed as both send and receive, the callee lists
+ those codecs it is capable of sending or receiving among the ones
+ listed by the caller in the INVITE. The actual payload type numbers
+ in the callee's session description corresponding to a particular
+ codec MUST be the same as the caller's session description.
+
+ If caller and callee have no media formats in common for a particular
+ stream, the callee MUST return a session description containing the
+ particular "m=" line, but with the port number set to zero, and no
+ payload types listed.
+
+ If there are no media formats in common for all streams, the callee
+ SHOULD return a 400 response, with a 304 Warning header field.
+
+
+
+
+Handley, et al. Standards Track [Page 138]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+B.3 Multicast Operation
+
+ The interpretation of send-only and receive-only for multicast media
+ sessions differs from that for unicast sessions. For multicast,
+ send-only means that the recipient of the session description (caller
+ or callee) SHOULD only send media streams to the address and port
+ indicated. Receive-only means that the recipient of the session
+ description SHOULD only receive media on the address and port
+ indicated.
+
+ For multicast, receive and send multicast addresses are the same and
+ all parties use the same port numbers to receive media data. If the
+ session description provided by the caller is acceptable to the
+ callee, the callee can choose not to include a session description or
+ MAY echo the description in the response.
+
+ A callee MAY, in the response, return a session description with some
+ of the payload types removed, or port numbers set to zero (but no
+ other value). This indicates to the caller that the callee does not
+ support the given stream or media types which were removed. A callee
+ MUST NOT change whether a given stream is send-only, receive-only, or
+ send-and-receive.
+
+ If a callee does not support multicast at all, it SHOULD return a 400
+ status response and include a 330 Warning.
+
+B.4 Delayed Media Streams
+
+ In some cases, a caller may not know the set of media formats which
+ it can support at the time it would like to issue an invitation. This
+ is the case when the caller is actually a gateway to another protocol
+ which performs media format negotiation after call setup. When this
+ occurs, a caller MAY issue an INVITE with a session description that
+ contains no media lines. The callee SHOULD interpret this to mean
+ that the caller wishes to participate in a multimedia session
+ described by the session description, but that the media streams are
+ not yet known. The callee SHOULD return a session description
+ indicating the streams and media formats it is willing to support,
+ however. The caller MAY update the session description either in the
+ ACK request or in a re-INVITE at a later time, once the streams are
+ known.
+
+B.5 Putting Media Streams on Hold
+
+ If a party in a call wants to put the other party "on hold", i.e.,
+ request that it temporarily stops sending one or more media streams,
+ a party re-invites the other by sending an INVITE request with a
+ modified session description. The session description is the same as
+
+
+
+Handley, et al. Standards Track [Page 139]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ in the original invitation (or response), but the "c" destination
+ addresses for the media streams to be put on hold are set to zero
+ (0.0.0.0).
+
+B.6 Subject and SDP "s=" Line
+
+ The SDP "s=" line and the SIP Subject header field have different
+ meanings when inviting to a multicast session. The session
+ description line describes the subject of the multicast session,
+ while the SIP Subject header field describes the reason for the
+ invitation. The example in Section 16.2 illustrates this point. For
+ invitations to two-party sessions, the SDP "s=" line MAY be left
+ empty.
+
+B.7 The SDP "o=" Line
+
+ The "o=" line is not strictly necessary for two-party sessions, but
+ MUST be present to allow re-use of SDP-based tools.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 140]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+C Summary of Augmented BNF
+
+ All of the mechanisms specified in this document are described in
+ both prose and an augmented Backus-Naur Form (BNF) similar to that
+ used by RFC 822 [9]. Implementors will need to be familiar with the
+ notation in order to understand this specification. The augmented BNF
+ includes the following constructs:
+
+
+
+ name = definition
+
+
+ The name of a rule is simply the name itself (without any enclosing
+ "<" and ">") and is separated from its definition by the equal "="
+ character. White space is only significant in that indentation of
+ continuation lines is used to indicate a rule definition that spans
+ more than one line. Certain basic rules are in uppercase, such as SP,
+ LWS, HT, CRLF, DIGIT, ALPHA, etc. Angle brackets are used within
+ definitions whenever their presence will facilitate discerning the
+ use of rule names.
+
+
+ "literal"
+
+
+ Quotation marks surround literal text. Unless stated otherwise, the
+ text is case-insensitive.
+
+
+ rule1 | rule2
+
+
+ Elements separated by a bar ("|") are alternatives, e.g., "yes | no"
+ will accept yes or no.
+
+
+ (rule1 rule2)
+
+
+ Elements enclosed in parentheses are treated as a single element.
+ Thus, "(elem (foo | bar) elem)" allows the token sequences "elem foo
+ elem" and "elem bar elem".
+
+
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 141]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ *rule
+
+
+ The character "*" preceding an element indicates repetition. The full
+ form is "<n>*<m>element" indicating at least <n> and at most <m>
+ occurrences of element. Default values are 0 and infinity so that
+ "*(element)" allows any number, including zero; "1*element" requires
+ at least one; and "1*2element" allows one or two.
+
+
+ [rule]
+
+
+ Square brackets enclose optional elements; "[foo bar]" is equivalent
+ to "*1(foo bar)".
+
+
+ N rule
+
+
+ Specific repetition: "<n>(element)" is equivalent to
+ "<n>*<n>(element)"; that is, exactly <n> occurrences of (element).
+ Thus 2DIGIT is a 2-digit number, and 3ALPHA is a string of three
+ alphabetic characters.
+
+
+ #rule
+
+
+ A construct "#" is defined, similar to "*", for defining lists of
+ elements. The full form is "<n>#<m> element" indicating at least <n>
+ and at most <m> elements, each separated by one or more commas (",")
+ and OPTIONAL linear white space (LWS). This makes the usual form of
+ lists very easy; a rule such as
+
+
+
+ ( *LWS element *( *LWS "," *LWS element ))
+
+
+ can be shown as 1# element. Wherever this construct is used, null
+ elements are allowed, but do not contribute to the count of elements
+ present. That is, "(element), , (element)" is permitted, but counts
+ as only two elements. Therefore, where at least one element is
+ required, at least one non-null element MUST be present. Default
+ values are 0 and infinity so that "#element" allows any number,
+ including zero; "1#element" requires at least one; and "1#2element"
+ allows one or two.
+
+
+
+Handley, et al. Standards Track [Page 142]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ ; comment
+
+
+ A semi-colon, set off some distance to the right of rule text, starts
+ a comment that continues to the end of line. This is a simple way of
+ including useful notes in parallel with the specifications.
+
+
+ implied *LWS
+
+
+ The grammar described by this specification is word-based. Except
+ where noted otherwise, linear white space (LWS) can be included
+ between any two adjacent words (token or quoted-string), and between
+ adjacent tokens and separators, without changing the interpretation
+ of a field. At least one delimiter (LWS and/or separators) MUST exist
+ between any two tokens (for the definition of "token" below), since
+ they would otherwise be interpreted as a single token.
+
+C.1 Basic Rules
+
+ The following rules are used throughout this specification to
+ describe basic parsing constructs. The US-ASCII coded character set
+ is defined by ANSI X3.4-1986.
+
+
+ OCTET = <any 8-bit sequence of data>
+ CHAR = <any US-ASCII character (octets 0 - 127)>
+ upalpha = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" |
+ "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" |
+ "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z"
+ lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" |
+ "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" |
+ "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z"
+ alpha = lowalpha | upalpha
+ digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" |
+ "8" | "9"
+ alphanum = alpha | digit
+ CTL = <any US-ASCII control character
+ (octets 0 -- 31) and DEL (127)>
+ CR = %d13 ; US-ASCII CR, carriage return character
+ LF = %d10 ; US-ASCII LF, line feed character
+ SP = %d32 ; US-ASCII SP, space character
+ HT = %d09 ; US-ASCII HT, horizontal tab character
+ CRLF = CR LF ; typically the end of a line
+
+
+ The following are defined in RFC 2396 [12] for the SIP URI:
+
+
+
+Handley, et al. Standards Track [Page 143]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ unreserved = alphanum | mark
+ mark = "-" | "_" | "." | "!" | "~" | "*" | "'"
+ | "(" | ")"
+ escaped = "%" hex hex
+
+
+ SIP header field values can be folded onto multiple lines if the
+ continuation line begins with a space or horizontal tab. All linear
+ white space, including folding, has the same semantics as SP. A
+ recipient MAY replace any linear white space with a single SP before
+ interpreting the field value or forwarding the message downstream.
+
+
+
+ LWS = [CRLF] 1*( SP | HT ) ; linear whitespace
+
+
+ The TEXT-UTF8 rule is only used for descriptive field contents and
+ values that are not intended to be interpreted by the message parser.
+ Words of *TEXT-UTF8 contain characters from the UTF-8 character set
+ (RFC 2279 [21]). In this regard, SIP differs from HTTP, which uses
+ the ISO 8859-1 character set.
+
+
+
+ TEXT-UTF8 = <any UTF-8 character encoding, except CTLs,
+ but including LWS>
+
+
+ A CRLF is allowed in the definition of TEXT-UTF8 only as part of a
+ header field continuation. It is expected that the folding LWS will
+ be replaced with a single SP before interpretation of the TEXT-UTF8
+ value.
+
+ Hexadecimal numeric characters are used in several protocol elements.
+
+
+
+ hex = "A" | "B" | "C" | "D" | "E" | "F"
+ | "a" | "b" | "c" | "d" | "e" | "f" | digit
+
+
+ Many SIP header field values consist of words separated by LWS or
+ special characters. These special characters MUST be in a quoted
+ string to be used within a parameter value.
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 144]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ token = 1*< any CHAR except CTL's or separators>
+ separators = "(" | ")" | "<" | ">" | "@" |
+ "," | ";" | ":" | "\" | <"> |
+ "/" | "[" | "]" | "?" | "=" |
+ "{" | "}" | SP | HT
+
+
+ Comments can be included in some SIP header fields by surrounding the
+ comment text with parentheses. Comments are only allowed in fields
+ containing "comment" as part of their field value definition. In all
+ other fields, parentheses are considered part of the field value.
+
+
+
+ comment = "(" *(ctext | quoted-pair | comment) ")"
+ ctext = < any TEXT-UTF8 excluding "(" and ")">
+
+
+ A string of text is parsed as a single word if it is quoted using
+ double-quote marks.
+
+
+
+ quoted-string = ( <"> *(qdtext | quoted-pair ) <"> )
+ qdtext = <any TEXT-UTF8 except <">>
+
+
+ The backslash character ("\") MAY be used as a single-character
+ quoting mechanism only within quoted-string and comment constructs.
+
+
+
+ quoted-pair = " \ " CHAR
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 145]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+D Using SRV DNS Records
+
+ The following procedure is experimental and relies on DNS SRV records
+ (RFC 2052 [14]). The steps listed below are used in place of the two
+ steps in section 1.4.2.
+
+ If a step elicits no addresses, the client continues to the next
+ step. However if a step elicits one or more addresses, but no SIP
+ server at any of those addresses responds, then the client concludes
+ the server is down and doesn't continue on to the next step.
+
+ When SRV records are to be used, the protocol to use when querying
+ for the SRV record is "sip". SRV records contain port numbers for
+ servers, in addition to IP addresses; the client always uses this
+ port number when contacting the SIP server. Otherwise, the port
+ number in the SIP URI is used, if present. If there is no port number
+ in the URI, the default port, 5060, is used.
+
+ 1. If the host portion of the Request-URI is an IP address,
+ the client contacts the server at the given address. If the
+ host portion of the Request-URI is not an IP address, the
+ client proceeds to the next step.
+
+ 2. The Request-URI is examined. If it contains an explicit
+ port number, the next two steps are skipped.
+
+ 3. The Request-URI is examined. If it does not specify a
+ protocol (TCP or UDP), the client queries the name server
+ for SRV records for both UDP (if supported by the client)
+ and TCP (if supported by the client) SIP servers. The
+ format of these queries is defined in RFC 2052 [14]. The
+ results of the query or queries are merged together and
+ ordered based on priority. Then, the searching technique
+ outlined in RFC 2052 [14] is used to select servers in
+ order. If DNS doesn't return any records, the user goes to
+ the last step. Otherwise, the user attempts to contact
+ each server in the order listed. If no server is
+ contacted, the user gives up.
+
+ 4. If the Request-URI specifies a protocol (TCP or UDP) that
+ is supported by the client, the client queries the name
+ server for SRV records for SIP servers of that protocol
+ type only. If the client does not support the protocol
+ specified in the Request-URI, it gives up. The searching
+ technique outlined in RFC 2052 [14] is used to select
+ servers from the DNS response in order. If DNS doesn't
+
+
+
+
+
+Handley, et al. Standards Track [Page 146]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ return any records, the user goes to the last step.
+ Otherwise, the user attempts to contact each server in the
+ order listed. If no server is contacted, the user gives up.
+
+ 5. The client queries the name server for address records for
+ the host portion of the Request-URI. If there were no
+ address records, the client stops, as it has been unable to
+ locate a server. By address record, we mean A RR's, AAAA
+ RR's, or their most modern equivalent.
+
+ A client MAY cache a successful DNS query result. A successful query
+ is one which contained records in the answer, and a server was
+ contacted at one of the addresses from the answer. When the client
+ wishes to send a request to the same host, it starts the search as if
+ it had just received this answer from the name server. The server
+ uses the procedures specified in RFC1035 [15] regarding cache
+ invalidation when the time-to-live of the DNS result expires. If the
+ client does not find a SIP server among the addresses listed in the
+ cached answer, it starts the search at the beginning of the sequence
+ described above.
+
+ For example, consider a client that wishes to send a SIP request. The
+ Request-URI for the destination is sip:user at company.com. The client
+ only supports UDP. It would follow these steps:
+
+ 1. The host portion is not an IP address, so the client goes
+ to step 2 above.
+
+ 2. The client does a DNS query of QNAME="sip.udp.company.com",
+ QCLASS=IN, QTYPE=SRV. Since it doesn't support TCP, it
+ omits the TCP query. There were no addresses in the DNS
+ response, so the client goes to the next step.
+
+ 3. The client does a DNS query for A records for
+ "company.com". An address is found, so that client attempts
+ to contact a server at that address at port 5060.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 147]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+E IANA Considerations
+
+ Section 4.4 describes a name space and mechanism for registering SIP
+ options.
+
+ Section 6.41 describes the name space for registering SIP warn-codes.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 148]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+F Acknowledgments
+
+ We wish to thank the members of the IETF MMUSIC WG for their comments
+ and suggestions. Detailed comments were provided by Anders
+ Kristensen, Jim Buller, Dave Devanathan, Yaron Goland, Christian
+ Huitema, Gadi Karmi, Jonathan Lennox, Keith Moore, Vern Paxson, Moshe
+ J. Sambol, and Eric Tremblay.
+
+ This work is based, inter alia, on [37,38].
+
+G Authors' Addresses
+
+ Mark Handley
+ AT&T Center for Internet Research at ISCI (ACIRI)
+ 1947 Center St., Suite 600
+ Berkeley, CA 94704-119
+ USA
+ Email: mjh at aciri.org
+
+ Henning Schulzrinne
+ Dept. of Computer Science
+ Columbia University
+ 1214 Amsterdam Avenue
+ New York, NY 10027
+ USA
+ Email: schulzrinne at cs.columbia.edu
+
+ Eve Schooler
+ Computer Science Department 256-80
+ California Institute of Technology
+ Pasadena, CA 91125
+ USA
+ Email: schooler at cs.caltech.edu
+
+ Jonathan Rosenberg
+ Lucent Technologies, Bell Laboratories
+ Rm. 4C-526
+ 101 Crawfords Corner Road
+ Holmdel, NJ 07733
+ USA
+ Email: jdrosen at bell-labs.com
+
+
+
+
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 149]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+H Bibliography
+
+ [1] Pandya, R., "Emerging mobile and personal communication systems,"
+ IEEE Communications Magazine , vol. 33, pp. 44--52, June 1995.
+
+ [2] Braden, B., Zhang, L., Berson, S., Herzog, S. and S. Jamin,
+ "Resource ReSerVation protocol (RSVP) -- version 1 functional
+ specification", RFC 2205, October 1997.
+
+ [3] Schulzrinne, H., Casner, S., Frederick, R. and V. Jacobson, "RTP:
+ a transport protocol for real-time applications", RFC 1889,
+ Internet Engineering Task Force, Jan. 1996.
+
+ [4] Schulzrinne, H., Lanphier, R. and A. Rao, "Real time streaming
+ protocol (RTSP)", RFC 2326, April 1998.
+
+ [5] Handley, M., "SAP: Session announcement protocol," Internet
+ Draft, Internet Engineering Task Force, Nov. 1996. Work in
+ progress.
+
+ [6] Handley, M. and V. Jacobson, "SDP: session description protocol",
+ RFC 2327, April 1998.
+
+ [7] International Telecommunication Union, "Visual telephone systems
+ and equipment for local area networks which provide a non-
+ guaranteed quality of service," Recommendation H.323,
+ Telecommunication Standardization Sector of ITU, Geneva,
+ Switzerland, May 1996.
+
+ [8] International Telecommunication Union, "Control protocol for
+ multimedia communication," Recommendation H.245,
+ Telecommunication Standardization Sector of ITU, Geneva,
+ Switzerland, Feb. 1998.
+
+ [9] International Telecommunication Union, "Media stream
+ packetization and synchronization on non-guaranteed quality of
+ service LANs," Recommendation H.225.0, Telecommunication
+ Standardization Sector of ITU, Geneva, Switzerland, Nov. 1996.
+
+ [10] Bradner, S., "Key words for use in RFCs to indicate requirement
+ levels", BCP 14, RFC 2119, Mardch 1997.
+
+ [11] Fielding, R., Gettys, J., Mogul, J., Nielsen, H. and T.
+ Berners-Lee, "Hypertext transfer protocol -- HTTP/1.1", RFC
+ 2068, January 1997.
+
+ [12] Berners-Lee, T., Fielding, R. and L. Masinter, "Uniform resource
+ identifiers (URI): generic syntax", RFC 2396, August 1998.
+
+
+
+Handley, et al. Standards Track [Page 150]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ [13] Berners-Lee, T., Masinter, L. and M. McCahill, "Uniform resource
+ locators (URL)", RFC 1738, December 1994.
+
+ [14] Gulbrandsen, A. and P. Vixie, "A DNS RR for specifying the
+ location of services (DNS SRV)", RFC 2052, October 1996.
+
+ [15] Mockapetris, P., "Domain names - implementation and
+ specification", STD 13, RFC 1035, Noveberm 1997.
+
+ [16] Hamilton, M. and R. Wright, "Use of DNS aliases for network
+ services", RFC 2219, October 1997.
+
+ [17] Zimmerman, D., "The finger user information protocol", RFC 1288,
+ December 1991.
+
+ [18] Williamson, S., Kosters, M., Blacka, D., Singh, J. and K.
+ Zeilstra, "Referral whois (rwhois) protocol V1.5", RFC 2167,
+ June 1997.
+
+ [19] Yeong, W., Howes, T. and S. Kille, "Lightweight directory access
+ protocol", RFC 1777, March 1995.
+
+ [20] Schooler, E., "A multicast user directory service for
+ synchronous rendezvous," Master's Thesis CS-TR-96-18, Department
+ of Computer Science, California Institute of Technology,
+ Pasadena, California, Aug. 1996.
+
+ [21] Yergeau, F., "UTF-8, a transformation format of ISO 10646", RFC
+ 2279, January 1998.
+
+ [22] Stevens, W., TCP/IP illustrated: the protocols , vol. 1.
+ Reading, Massachusetts: Addison-Wesley, 1994.
+
+ [23] Mogul, J. and S. Deering, "Path MTU discovery", RFC 1191,
+ November 1990.
+
+ [24] Crocker, D., "Standard for the format of ARPA internet text
+ messages", RFC STD 11, RFC 822, August 1982.
+
+ [25] Meyer, D., "Administratively scoped IP multicast", RFC 2365,
+ July 1998.
+
+ [26] Schulzrinne, H., "RTP profile for audio and video conferences
+ with minimal control", RFC 1890, January 1996
+
+ [27] Eastlake, D., Crocker, S. and J. Schiller, "Randomness
+ recommendations for security", RFC 1750, December 1994.
+
+
+
+
+Handley, et al. Standards Track [Page 151]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+ [28] Hoffman, P., Masinter, L. and J. Zawinski, "The mailto URL
+ scheme", RFC 2368, July 1998.
+
+ [29] Braden, B., "Requirements for internet hosts - application and
+ support", STD 3, RFC 1123, October 1989.
+
+ [30] Palme, J., "Common internet message headers", RFC 2076, February
+ 1997.
+
+ [31] Alvestrand, H., "IETF policy on character sets and languages",
+ RFC 2277, January 1998.
+
+ [32] Elkins, M., "MIME security with pretty good privacy (PGP)", RFC
+ 2015, October 1996.
+
+ [33] Atkins, D., Stallings, W. and P. Zimmermann, "PGP message
+ exchange formats", RFC 1991, August 1996.
+
+ [34] Atkinson, R., "Security architecture for the internet protocol",
+ RFC 2401, November 1998.
+
+ [35] Allen, C. and T. Dierks, "The TLS protocol version 1.0," RFC
+ 2246, January 1999.
+
+ [36] Franks, J., Hallam-Baker, P., Hostetler, J., Lawrence, S.,
+ Leach, P., Luotonen, A. and L. Stewart, "HTTP authentication:
+ Basic and digest access authentication," Internet Draft,
+ Internet Engineering Task Force, Sept. 1998. Work in progress.
+
+ [37] Schooler, E., "Case study: multimedia conference control in a
+ packet-switched teleconferencing system," Journal of
+ Internetworking: Research and Experience , vol. 4, pp. 99--120,
+ June 1993. ISI reprint series ISI/RS-93-359.
+
+ [38] Schulzrinne, H., "Personal mobility for multimedia services in
+ the Internet," in European Workshop on Interactive Distributed
+ Multimedia Systems and Services (IDMS) , (Berlin, Germany), Mar.
+ 1996.
+
+
+
+
+
+
+
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 152]
+
+RFC 2543 SIP: Session Initiation Protocol March 1999
+
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 153]
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/run-tests
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/run-tests Thu Dec 21 01:30:28 2006
@@ -0,0 +1,47 @@
+#! /bin/sh
+#
+# Run the parser tests
+#
+# usage: run-tests [test_program] [test-case...]
+#
+# --------------------------------------------------------------------
+#
+# This file is part of the Sofia-SIP package
+#
+# Copyright (C) 2005 Nokia Corporation.
+#
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+#
+# --------------------------------------------------------------------
+#
+
+msg_test="${1:-./msg_test}"
+shift
+
+rc=0
+
+for n in "$@";
+do
+ if "$msg_test" < "$n" > /dev/null ; then
+ true
+ else
+ echo "$n: ERROR"; rc=1
+ fi
+done
+
+exit $rc
\ No newline at end of file
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/run_date_test
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/run_date_test Thu Dec 21 01:30:28 2006
@@ -0,0 +1,2 @@
+#!/bin/sh
+./date_test "Sun, 18 Mar 2001 23:01:00 GMT"
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip.docs Thu Dec 21 01:30:28 2006
@@ -0,0 +1,608 @@
+/* -*- c -*- */
+
+/**@MODULEPAGE "sip" - SIP Parser Module
+ *
+ * @section sip_meta Module Meta Information
+ *
+ * The Sofia @b sip module contains interface to the SIP parser and the
+ * header and message objects.
+ *
+ * @CONTACT Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @STATUS @SofiaSIP Core library
+ *
+ * @LICENSE LGPL
+ *
+ * @section sip_overview Overview
+ *
+ * The structure of each header is defined in @b <sip.h>. In addition to the
+ * header structure, there is defined a @em header @em class structure and
+ * some standard functions for each header in the include file @b
+ * <sofia-sip/sip_header.h>. For header @c X, there are types, functions,
+ * macros and header class declared in <sofia-sip/sip_protos.h> and
+ * <sofia-sip/sip_hclass.h>. See @ref sip_header_x for detailed description
+ * of these header-specific boilerplate declarations.
+ *
+ * In addition to this interface, the @ref sip_parser "SIP parser documentation"
+ * contains description of the functionality required when a parser is
+ * extended by a new header. It is possible to add new headers to the SIP
+ * parser or extend the definition of existing ones.
+ *
+ * @section sip_parser_intro Parsing SIP Messages
+ *
+ * Sofia SIP parser follows @em recursive-descent principle. In other words,
+ * it is a program that descends the SIP syntax tree top-down recursively.
+ * (All syntax trees have root at top and they grow downwards.)
+ *
+ * In the case of SIP such a parser is very efficient. The parser can choose
+ * between different forms based on each token, as SIP 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 SIP parser for each
+ * header. As there are no framing between SIP messages, the parser
+ * considers any received data, be it a UDP datagram or a TCP stream, as a
+ * @em message @em stream, which may consist of one or more SIP messages.
+ * The parser works by first separating stream into fragments, then building
+ * a complete message based on parsing result. After a message is completed,
+ * it can be given to the message stream customer (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.
+ *
+ * For each message, the parser starts by separating the first fragment,
+ * which is either a request or status line. After the first line has been
+ * processed, the parser engine continues by separating the headers
+ * one-by-one from the message. After the parser encounters an empty line
+ * separating the headers and the message body (payload), it invokes a
+ * function parsing the separator and payload fragment(s). When the message
+ * is complete, the parser can hand the message over to the protocol engine.
+ * Then it is ready to start again with first fragment of the next message.
+ *
+ * @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 request or status line, each
+ * header, separator and the payload 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 buffers for the message, the
+ * fragment chain, and a whole 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 hidden from other modules.
+ *
+ * The abstract message module @b msg also drives the reverse process,
+ * invoking the encoding method of each fragment so that the whole outgoing
+ * SIP message is encoded properly.
+ *
+ * @section sip_header_struct SIP 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 special function
+ * for each individual header. The header-specific parsing function divides
+ * the contents of the header into semantically meaningful segments and
+ * stores the result in a header-specific structure.
+ *
+ * The parser passes the fragment contents to a parsing function immediately
+ * after it has separated a fragment from the message. The parsing function
+ * is defined by the @e header @e class. The header class is either
+ * determined by the fragment position (first line, separator line or
+ * payload), or it is found from the hash table using the header name as
+ * key. There is also a special header class for @e unknown headers, headers
+ * with a name that is not regocnized by the parser.
+ *
+ * For instance, the @From header has following syntax:
+ *
+ * @code
+ * from = ("From" | "f") ":"
+ * ( name-addr | addr-spec ) *( ";" addr-params )
+ * name-addr = [ display-name ] "<" addr-spec ">"
+ * addr-spec = SIP-URL | URI
+ * display-name = *token | quoted-string
+ * addr-params = *( tag-param | generic-param )
+ * tag-param = "tag" "=" ( token | quoted-string )
+ * @endcode
+ *
+ * When a @From header is parsed, the header parser function sip_from_d()
+ * separates the @e display-name, @e addr-spec and each parameter in the @e
+ * addr-params list. The parsing result is assigned to a #sip_from_t
+ * structure, which is defined as follows:
+ *
+ * @code
+ * typedef struct sip_addr_s {
+ * sip_common_t a_common[1];
+ * sip_unknown_t *a_next;
+ * char const *a_display;
+ * url_t a_url[1];
+ * sip_param_t const *a_params;
+ * char const *a_tag;
+ * } sip_from_t;
+ * @endcode
+ *
+ * The string containing the @e display-name is put into the @c a_display
+ * field, the URL contents can be found in the @c a_url field, and the list
+ * of @e addr-params parameters is put in the @c a_params array. If there
+ * is a @e tag-param present, a pointer to the parameter value is assigned
+ * to @c a_tag field.
+ *
+ * @section sip_msg_struct SIP Message as a C struct
+ *
+ * It is not enough to represent a SIP message as a collection of headers
+ * following each other. The programmer also needs a convenient way to
+ * access certain headers at the SIP message level, for example, accessing
+ * directly the @From header instead of going through all headers and
+ * examining their name. The structured view to the SIP message is provided
+ * via a C struct with type #sip_t.
+ *
+ * In other words, a single message is represented by two types, first type
+ * (#msg_t) is private to the msg module and inaccessable by an application
+ * programmer, second (#sip_t) is a public structure containing the parsed
+ * headers.
+ *
+ * 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;
+ * int sip_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; // @RecordRoute
+ * sip_max_forwards_t *sip_max_forwards; // @MaxForwards
+ * ...
+ * } 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.
+ *
+ * @note Within the @b msg module, the public structure is known as
+ * #msg_pub_t. The application programmer can cast a #msg_t pointer to
+ * #sip_t with sip_object() function (or macro).
+ *
+ *
+ * @section sip_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 BYE message with only the
+ * mandatory fields included:
+ * @code
+ * BYE sip:joe at 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 at example.edu>;tag=77241a86
+ * To: Joe User <sip:joe at example.com>;tag=7c6276c1
+ * Call-ID: 4c4e911b at 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 header 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 the second @Via in the header list.
+ *
+ */
+
+/**@defgroup sip_headers SIP Headers
+ *
+ * SIP headers and other SIP message elements.
+ *
+ * For each SIP header recognized by the SIP module, there is a header
+ * structure containing the parsed value. The header structure name is
+ * generated from the header name by lowercasing the name, replacing the
+ * non-alphanumeric characters (usually just minus "-") with underscore "_"
+ * characters, and then adding prefix @c sip_ and suffix @c _t. For
+ * instance, the contents of header "MIME-Version" is stored in a structure
+ * called sip_mime_version_t.
+ *
+ */
+
+/**@ingroup sip_headers
+ * @defgroup sip_header_x SIP Header X - Conventions
+ *
+ * For a SIP header X, there are types, functions, macros and global data
+ * declared in <sofia-sip/sip_protos.h> and <sofia-sip/sip_hclass.h> as
+ * follows:
+ * - #sip_X_t is the structure used to store parsed header,
+ * - SIP_X_INIT() initializes a static instance of #sip_X_t,
+ * - sip_X_init() initializes a dynamic instance of #sip_X_t,
+ * - sip_is_X() tests if header object is instance of header X,
+ * - sip_X_make() creates a header X object by decoding given string,
+ * - sip_X_format() creates a header X object by decoding given
+ * printf() list,
+ * - sip_X_dup() duplicates (deeply copies) the header X,
+ * - sip_X_copy() copies the header X,
+ * - #msg_hclass_t #sip_X_class[] contains the @em header @em class
+ * for header X.
+ *
+ * All header structures contain the common part, a #sip_common_t structure
+ * (@a X_common[]), a link to the next header in list (@a X_next), and
+ * various fields describing the header value (in this case, @a X_value).
+ * The header structure looks like this:
+ * @code
+ * typedef struct sip_X_s
+ * {
+ * 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; // Encoded data
+ * usize_t h_len; // Encoding length (including CRLF)
+ * } X_common[1];
+ * sip_X_t *X_next; // Link to next X header field
+ * uint32_t X_value; // Value of X
+ * msg_param_t *X_param; // List of parameters
+ * } sip_X_t;
+ * @endcode
+ *
+ * The common structure #msg_common_t (aka #sip_common_t)
+ * can be considered as a base class for all
+ * headers. The structure contains the pointers for dual-linked
+ * fragment chain (@a h_succ, @a h_prev), a pointer to header class (@a
+ * h_class), a pointer to the text encoding of header contents (@a h_data)
+ * and the length of the encoding (@a h_len). (@a X_common is an array of size
+ * 1, as it makes it easy to cast a header pointer to a pointer to
+ * msg_common_t.)
+ *
+ * The @a X_next is a pointer to another header (usually a pointer to
+ * structure of same type). If there are multiple headers with same name,
+ * like the two "Via" headers in the example above, the @a X_next is used to
+ * link the second header to the first. The fragment chain cannot be used
+ * for this purpose as the headers with same name are not necessarily
+ * adjacent in the parsed message.
+ *
+ * The rest of the fields contain the parsed or decoded representation of
+ * the header. In this case, it is a 32-bit integer followed by a list of
+ * parameters. The content of parameters is not parsed, they are just
+ * separated from each other and then stored in an dynamically allocated
+ * array of string pointers. Pointer to the array is stored to @a X_params.
+ *
+ * For more complex header structures, see #sip_contact_t or #sip_rack_t.
+ *
+ * @{
+ */
+
+/**The structure #sip_X_t contains representation of a SIP
+ * @ref sip_header_x "X" header.
+ *
+ * The #sip_X_t is defined as follows:
+ * @code
+ * typedef struct sip_X_s {
+ * msg_common_t X_common[1]; // Common fragment info
+ * sip_X_t *X_next; // Link to next X header field
+ * uint32_t X_value; // Value of X
+ * msg_param_t *X_param; // List of parameters
+ * } sip_X_t;
+ * @endcode
+ */
+typedef struct sip_X_s sip_X_t;
+
+/**@var msg_hclass_t sip_X_class[];
+ * @brief Header class for SIP X.
+ *
+ * The header class sip_X_class defines how a SIP
+ * X is parsed and printed. It also
+ * contains methods used by SIP parser and other functions
+ * to manipulate the sip_X_t header structure.
+ *
+ */
+SIP_DLL extern msg_hclass_t sip_X_class[];
+
+enum {
+ /** Hash of X. @internal */
+ sip_X_hash = hash
+};
+
+/** Parse a X. @internal */
+msg_parse_f sip_X_d;
+
+/** Print a X. @internal */
+msg_print_f sip_X_e;
+
+/**Initializer for structure sip_X_t.
+ *
+ * A static sip_X_t structure must be initialized
+ * with the SIP_X_INIT() macro. For instance,
+ * @code
+ *
+ * sip_X_t sip_X = SIP_X_INIT;
+ *
+ * @endcode
+ * @HI
+ */
+#define SIP_X_INIT() SIP_HDR_INIT(X)
+
+/**Initialize a structure sip_X_t.
+ *
+ * An sip_X_t structure can be initialized with the
+ * sip_X_init() function/macro. For instance,
+ * @code
+ *
+ * sip_X_t sip_X;
+ *
+ * sip_X_init(&sip_X);
+ *
+ * @endcode
+ * @HI
+ */
+#if SU_HAVE_INLINE
+su_inline sip_X_t *sip_X_init(sip_X_t x[1])
+{
+ return SIP_HEADER_INIT(x, sip_X_class, sizeof(sip_X_t));
+}
+#else
+#define sip_X_init(x) \
+ SIP_HEADER_INIT(x, sip_X_class, sizeof(sip_X_t))
+#endif
+
+/**Test if header object is instance of sip_X_t.
+ *
+ * The function sip_is_X() returns true (nonzero) if
+ * the header class is an instance of X
+ * object and false (zero) otherwise.
+ *
+ * @param header pointer to the header structure to be tested
+ *
+ * @return
+ * The function sip_is_X() returns true (nonzero) if
+ * the header object is an instance of header X and
+ * false (zero) otherwise.
+ */
+#if SU_HAVE_INLINE
+su_inline int sip_is_X(sip_header_t const *header)
+{
+ return header && header->sh_class->hc_id == sip_hdr_X;
+}
+#else
+int sip_is_X(sip_header_t const *header);
+#endif
+
+#define sip_X_p(h) sip_is_X((h))
+
+/**Duplicate (deep copy) @c sip_X_t.
+ *
+ * The function sip_X_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
+ *
+ * X = sip_X_dup(home, sip->sip_X);
+ *
+ * @endcode
+ *
+ * @return
+ * The function sip_X_dup() returns a pointer to the
+ * newly duplicated sip_X_t header structure, or NULL
+ * upon an error.
+ */
+sip_X_t *sip_X_dup(su_home_t *home, sip_X_t const *hdr);
+
+/**Copy a sip_X_t header structure.
+ *
+ * The function sip_X_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
+ *
+ * X = sip_X_copy(home, sip->sip_X);
+ *
+ * @endcode
+ *
+ * @return
+ * The function sip_X_copy() returns a pointer to
+ * newly copied header structure, or NULL upon an error.
+ */
+sip_X_t *sip_X_copy(su_home_t *home, sip_X_t const *hdr);
+
+/**Make a header structure sip_X_t.
+ *
+ * The function sip_X_make() makes a new
+ * sip_X_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
+ * sip_header_make().
+ *
+ * @return
+ * The function sip_X_make() returns a pointer to
+ * newly maked sip_X_t header structure, or NULL upon
+ * an error.
+ */
+#if SU_HAVE_INLINE
+su_inline sip_X_t *sip_X_make(su_home_t *home, char const *s)
+{
+ return sip_header_make(home, sip_X_class, s)->sh_X;
+}
+#else
+sip_X_t *sip_X_make(su_home_t *home, char const *s);
+#endif
+
+/**Make a X from formatting result.
+ *
+ * The function sip_X_format() makes a new
+ * X 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 sip_X_format() returns a pointer to newly
+ * makes header structure, or NULL upon an error.
+ *
+ * @HIDE
+ */
+#if SU_HAVE_INLINE
+su_inline
+#endif
+sip_X_t *sip_X_format(su_home_t *home, char const *fmt, ...)
+ __attribute__((format (printf, 2, 3)));
+
+#if SU_HAVE_INLINE
+su_inline sip_X_t *sip_X_format(su_home_t *home, char const *fmt, ...)
+{
+ sip_header_t *h;
+ va_list ap;
+
+ va_start(ap, fmt);
+ h = sip_header_vformat(home, sip_X_class, fmt, ap);
+ va_end(ap);
+
+ return h->sh_X;
+}
+#endif
+
+/**Decode a header X.
+ *
+ * The function sip_X_d() decodes value of the header X in the preallocated
+ * header structure @a h. The string @a s to be decoded should not contain
+ * the header name or colon. The decoding function also expects that the
+ * leading and trailing whitespace has been removed from the string @a s.
+ *
+ * @param home memory home used to allocate new header structure.
+ * @param h sip_X_t header structure
+ * @param s string to be decoded
+ * @param bsiz length of string @a s
+ *
+ * @return
+ * The function sip_X_d() returns non-negative value when successful, or
+ * -1 upon an error.
+ */
+int sip_X_d(su_home_t *home, sip_header_t *h, char *s, int bsiz);
+
+/**Encode a header X.
+ *
+ * The function sip_X_e() encodes a header structure @a h to the given
+ * buffer @a buf. Even if the given buffer @a buf is NULL or its size @a
+ * bufsiz is too small to fit the encoding result, the function returns the
+ * number of characters required for the encoding.
+ *
+ * @param buf buffer to store the encoding result
+ * @param bsiz size of the encoding buffer
+ * @param h header to be encoded.
+ * @param flags flags controlling the encoding
+ *
+ * @note
+ * The encoding buffer size @b must be @b bigger than, not equal to,
+ * the actual encoding result.
+ *
+ * @return
+ * The function sip_X_e() returns the number of characters required for the
+ * encoding.
+ *
+ */
+int sip_X_e(char buf[], int bsiz, sip_header_t const *h, int flags);
+
+/** @} */
+
+/**@defgroup sip_status_codes SIP Status Codes and Reason Phrases
+ *
+ * The macros and variables for the standard SIP status codes and reason
+ * phrases are defined in <sip_status.h>.
+ */
+
+/**@defgroup sip_tag SIP Tags
+ *
+ * SIP headers in tag item lists and tagged argument lists.
+ *
+ * The include file <sip_tag.h> defines tags and tag items for including SIP
+ * headers in tag item lists or tagged argument lists. For each header,
+ * there is a tag for pointer to header object and an another tag for string
+ * containing header value. For example, @From header has tags
+ * SIPTAG_FROM() and SIPTAG_FROM_STR().
+ *
+ * It is also possible to include user-defined headers or non-standard
+ * headers using SIPTAG_HEADER_STR().
+ *
+ * A function taking SIP headers as arguments could be called like this:
+ * @code
+ * sip_payload_t *payload;
+ * ...
+ * sip_add_tl(msg, sip,
+ * SIPTAG_CONTENT_TYPE_STR("text/plain"),
+ * SIPTAG_USER_AGENT(agent->user_agent),
+ * SIPTAG_PAYLOAD(payload),
+ * SIPTAG_HEADER_STR("X-Header: contents\nP-Header: bar"),
+ * TAG_END());
+ * ...
+ * @endcode
+ *
+ * In the above fragment, the function sip_add_tl() will add @ContentType
+ * and @UserAgent headers along with message payload to the SIP message.
+ * The @ContentType header is made with value "text/plain".
+ *
+ */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip.doxyaliases
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip.doxyaliases Thu Dec 21 01:30:28 2006
@@ -0,0 +1,70 @@
+ALIASES += \
+ "AcceptContact=@ref sip_accept_contact \"Accept-Contact\"" \
+ "AcceptEncoding=@ref sip_accept_encoding \"Accept-Encoding\"" \
+ "AcceptLanguage=@ref sip_accept_language \"Accept-Language\"" \
+ "Accept=@ref sip_accept \"Accept\"" \
+ "AllowEvents=@ref sip_allow_events \"Allow-Events\"" \
+ "Allow=@ref sip_allow \"Allow\"" \
+ "AuthenticationInfo=@ref sip_authentication_info \"Authentication-Info\"" \
+ "Authorization=@ref sip_authorization \"Authorization\"" \
+ "CSeq=@ref sip_cseq \"CSeq\"" \
+ "CallID=@ref sip_call_id \"Call-ID\"" \
+ "CallInfo=@ref sip_call_info \"Call-Info\"" \
+ "Contact=@ref sip_contact \"Contact\"" \
+ "ContentDisposition=@ref sip_content_disposition \"Content-Disposition\"" \
+ "ContentEncoding=@ref sip_content_encoding \"Content-Encoding\"" \
+ "ContentLanguage=@ref sip_content_language \"Content-Language\"" \
+ "ContentLength=@ref sip_content_length \"Content-Length\"" \
+ "ContentType=@ref sip_content_type \"Content-Type\"" \
+ "Date=@ref sip_date \"Date\"" \
+ "ErrorInfo=@ref sip_error_info \"Error-Info\"" \
+ "Event=@ref sip_event \"Event\"" \
+ "Expires=@ref sip_expires \"Expires\"" \
+ "From=@ref sip_from \"From\"" \
+ "InReplyTo=@ref sip_in_reply_to \"In-Reply-To\"" \
+ "MIMEVersion=@ref sip_mime_version \"MIME-Version\"" \
+ "MaxForwards=@ref sip_max_forwards \"Max-Forwards\"" \
+ "MinExpires=@ref sip_min_expires \"Min-Expires\"" \
+ "MinSE=@ref sip_min_se \"Min-SE\"" \
+ "Organization=@ref sip_organization \"Organization\"" \
+ "Path=@ref sip_path \"Path\"" \
+ "Priority=@ref sip_priority \"Priority\"" \
+ "Privacy=@ref sip_privacy \"Privacy\"" \
+ "ProxyAuthenticate=@ref sip_proxy_authenticate \"Proxy-Authenticate\"" \
+ "ProxyAuthenticationInfo=@ref sip_proxy_authentication_info \"Proxy-Authentication-Info\"" \
+ "ProxyAuthorization=@ref sip_proxy_authorization \"Proxy-Authorization\"" \
+ "ProxyRequire=@ref sip_proxy_require \"Proxy-Require\"" \
+ "RAck=@ref sip_rack \"RAck\"" \
+ "RSeq=@ref sip_rseq \"RSeq\"" \
+ "Reason=@ref sip_reason \"Reason\"" \
+ "RecordRoute=@ref sip_record_route \"Record-Route\"" \
+ "ReferTo=@ref sip_refer_to \"Refer-To\"" \
+ "ReferredBy=@ref sip_referred_by \"Referred-By\"" \
+ "RejectContact=@ref sip_reject_contact \"Reject-Contact\"" \
+ "Replaces=@ref sip_replaces \"Replaces\"" \
+ "RequestDisposition=@ref sip_request_disposition \"Request-Disposition\"" \
+ "Require=@ref sip_require \"Require\"" \
+ "RetryAfter=@ref sip_retry_after \"Retry-After\"" \
+ "Route=@ref sip_route \"Route\"" \
+ "SIPETag=@ref sip_etag \"SIP-ETag\"" \
+ "SIPIfMatch=@ref sip_if_match \"SIP-If-Match\"" \
+ "SecurityClient=@ref sip_security_client \"Security-Client\"" \
+ "SecurityServer=@ref sip_security_server \"Security-Server\"" \
+ "SecurityVerify=@ref sip_security_verify \"Security-Verify\"" \
+ "Server=@ref sip_server \"Server\"" \
+ "ServiceRoute=@ref sip_service_route \"Service-Route\"" \
+ "SessionExpires=@ref sip_session_expires \"Session-Expires\"" \
+ "Subject=@ref sip_subject \"Subject\"" \
+ "SubscriptionState=@ref sip_subscription_state \"Subscription-State\"" \
+ "Supported=@ref sip_supported \"Supported\"" \
+ "Timestamp=@ref sip_timestamp \"Timestamp\"" \
+ "To=@ref sip_to \"To\"" \
+ "Unsupported=@ref sip_unsupported \"Unsupported\"" \
+ "UserAgent=@ref sip_user_agent \"User-Agent\"" \
+ "Via=@ref sip_via \"Via\"" \
+ "WWWAuthenticate=@ref sip_www_authenticate \"WWW-Authenticate\"" \
+ "Warning=@ref sip_warning \"Warning\"" \
+ "ReferSub=@ref sip_refer_sub \"Refer-Sub\"" \
+ "SuppressBodyIfMatch=@ref sip_suppress_body_if_match \"Suppress-Body-If-Match\"" \
+ "SuppressNotifyIfMatch=@ref sip_suppress_notify_if_match \"Suppress-Notify-If-Match\"" \
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_bad_mask
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_bad_mask Thu Dec 21 01:30:28 2006
@@ -0,0 +1,95 @@
+#
+# nta has a bad_mask specifying which headers cause nta to automatically
+# return 400 Bad Message if a critical header or pseudoheader in a request
+# has a parsing error.
+#
+# The parsing error can be later checked with msg_extract_errors(), too.
+#
+# See <sip_parser.h> for definition of mask values.
+#
+# The mask can be set when header is added with
+# msg_mclass_insert_header_flags().
+#
+# The flags of existing headers can be modified, if a copy of message class
+# is first made with msg_mclass_clone().
+#
+
+#
+# Headers that must be valid for all requests
+#
+request = sip_mask_request | sip_mask_response
+status = sip_mask_request | sip_mask_response
+From = sip_mask_request | sip_mask_response
+To = sip_mask_request | sip_mask_response
+CSeq = sip_mask_request | sip_mask_response
+Call-ID = sip_mask_request | sip_mask_response
+Content-Length = sip_mask_request | sip_mask_response
+Via = sip_mask_request | sip_mask_response
+
+#
+# User-Agent headers
+#
+Content-Type = sip_mask_ua
+Content-Disposition = sip_mask_ua
+Content-Encoding = sip_mask_ua
+
+#
+# Proxy heades
+#
+Route = sip_mask_proxy
+Max-Forwards = sip_mask_proxy
+Proxy-Require = sip_mask_proxy
+Proxy-Authorization = sip_mask_proxy
+
+#
+# Registrar headers
+#
+Min-Expires = sip_mask_registrar
+Authorization = sip_mask_registrar
+Path = sip_mask_registrar
+
+#
+# Headers that must be valid in UA, proxy or registrar
+#
+Supported = sip_mask_ua | sip_mask_proxy | sip_mask_registrar
+Contact = sip_mask_ua | sip_mask_proxy | sip_mask_registrar
+Require = sip_mask_ua | sip_mask_registrar
+Record-Route = sip_mask_ua | sip_mask_proxy
+
+Expires = sip_mask_registrar | sip_mask_events
+
+#
+# 100rel headers
+#
+RAck = sip_mask_100rel
+RSeq = sip_mask_100rel
+
+#
+# Event headers
+#
+Event = sip_mask_events
+Subscription-State = sip_mask_events
+
+#
+# 'timer' headers
+#
+Session-Expires = sip_mask_timer
+Min-SE = sip_mask_timer
+
+#
+# Privacy headers
+#
+Privacy = sip_mask_privacy
+
+#
+# Headers used in caller preferences
+#
+Request-Disposition = sip_mask_pref
+Accept-Contact = sip_mask_pref
+Reject-Contact = sip_mask_pref
+
+#
+# PUBLISH headers (NOTE: No SIP- here!)
+#
+Etag = sip_mask_publish
+If-Match = sip_mask_publish
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_basic.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_basic.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,2734 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE sip_basic.c
+ * @brief Basic SIP headers.
+ *
+ * Implementation of header classes for basic SIP headers, like request and
+ * status lines, payload, @CallID, @CSeq, @Contact, @ContentLength, @Date,
+ * @Expires, @From, @Route, @RecordRoute, @To, and @Via.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Tue Jun 13 02:57:51 2000 ppessi
+ */
+
+#include "config.h"
+
+/* Avoid casting sip_t to msg_pub_t and sip_header_t to msg_header_t */
+#define MSG_PUB_T struct sip_s
+#define MSG_HDR_T union sip_header_u
+
+#include <sofia-sip/su_alloc.h>
+#include <sofia-sip/string0.h>
+
+#include "sofia-sip/sip_parser.h"
+#include <sofia-sip/sip_util.h>
+#include <sofia-sip/sip_status.h>
+
+#include <sofia-sip/msg_date.h>
+
+#include <sofia-sip/su_uniqueid.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <limits.h>
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_request Request Line
+ *
+ * The request line is first line in a SIP request message. Its syntax defined
+ * in @RFC3261 as follows:
+ *
+ * @code
+ * Request-Line = Method SP Request-URI SP SIP-Version CRLF
+ * Request-URI = SIP-URI / SIPS-URI / absoluteURI
+ * absoluteURI = scheme ":" ( hier-part / opaque-part )
+ * hier-part = ( net-path / abs-path ) [ "?" query ]
+ * net-path = "//" authority [ abs-path ]
+ * abs-path = "/" path-segments
+ * opaque-part = uric-no-slash *uric
+ * uric = reserved / unreserved / escaped
+ * uric-no-slash = unreserved / escaped / ";" / "?" / ":" / "@"
+ * / "&" / "=" / "+" / "$" / ","
+ * path-segments = segment *( "/" segment )
+ * segment = *pchar *( ";" param )
+ * param = *pchar
+ * pchar = unreserved / escaped /
+ * ":" / "@" / "&" / "=" / "+" / "$" / ","
+ * scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
+ * authority = srvr / reg-name
+ * srvr = [ [ userinfo "@" ] hostport ]
+ * reg-name = 1*( unreserved / escaped / "$" / ","
+ * / ";" / ":" / "@" / "&" / "=" / "+" )
+ * query = *uric
+ * SIP-Version = "SIP" "/" 1*DIGIT "." 1*DIGIT
+ * @endcode
+ *
+ * The parsed request-line is stored in #sip_request_t structure.
+ */
+
+/**@ingroup sip_request
+ * @typedef typedef struct sip_request_s sip_request_t;
+ *
+ * The structure #sip_request_t contains representation of SIP request line.
+ *
+ * The #sip_request_t is defined as follows:
+ * @code
+ * typedef struct sip_request_s {
+ * sip_common_t rq_common[1]; // Common fragment info
+ * sip_unknown_t *rq_next; // Link to next (dummy)
+ * sip_method_t rq_method; // Method enum
+ * char const *rq_method_name; // Method name
+ * url_t rq_url[1]; // RequestURI
+ * char const *rq_version; // Protocol version
+ * } sip_request_t;
+ * @endcode
+ */
+
+#define sip_request_insert msg_request_insert
+
+static msg_xtra_f sip_request_dup_xtra;
+static msg_dup_f sip_request_dup_one;
+#define sip_request_update NULL
+
+msg_hclass_t sip_request_class[] =
+SIP_HEADER_CLASS(request, NULL, "", rq_common, single_critical, request);
+
+/**Parse @ref sip_request "request line" from a a SIP message. */
+issize_t sip_request_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ sip_request_t *rq = h->sh_request;
+ char *uri, *version;
+
+ if (msg_firstline_d(s, &uri, &version) < 0 || !uri || !version ||
+ (rq->rq_method = sip_method_d(&s, &rq->rq_method_name)) < 0 || *s ||
+ url_d(rq->rq_url, uri) < 0 ||
+ sip_version_d(&version, &rq->rq_version) < 0 || *version)
+ return -1;
+
+ return 0;
+}
+
+/**Encode @ref sip_request "request line" of a a SIP message. */
+issize_t sip_request_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+ sip_request_t const *rq = h->sh_request;
+
+ 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 sip_request_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+ sip_request_t const *rq = h->sh_request;
+
+ offset += url_xtra(rq->rq_url);
+ if (!rq->rq_method)
+ offset += MSG_STRING_SIZE(rq->rq_method_name);
+ offset += sip_version_xtra(rq->rq_version);
+
+ return offset;
+}
+
+/** Duplicate one request header. */
+char *sip_request_dup_one(sip_header_t *dst, sip_header_t const *src,
+ char *b, isize_t xtra)
+{
+ sip_request_t *rq = dst->sh_request;
+ sip_request_t const *o = src->sh_request;
+ char *end = b + xtra;
+
+ URL_DUP(b, end, rq->rq_url, o->rq_url);
+
+ if (!(rq->rq_method = o->rq_method))
+ MSG_STRING_DUP(b, rq->rq_method_name, o->rq_method_name);
+ else
+ rq->rq_method_name = o->rq_method_name;
+ sip_version_dup(&b, &rq->rq_version, o->rq_version);
+
+ assert(b <= end);
+
+ return b;
+}
+
+/**@ingroup sip_request
+ *
+ * Create a @ref sip_request "request line" object.
+ *
+ * Create a request line object with
+ * method enum @a method, method name @a name, request URI @a uri, and
+ * protocol version @a version. The memory for the header object is
+ * allocated from the memory home @a home.
+ *
+ * @param home memory home used to allocate #sip_request_t object
+ * @param method method enum
+ * @param name method name (required if method is not well-known)
+ * @param uri request URI
+ * @param version version string (defaults to "SIP/2.0" if NULL)
+ *
+ * @par Example
+ * The following code fragment creates an OPTIONS request object:
+ * @code
+ * sip_request_t *rq;
+ * rq = sip_request_create(home, SIP_METHOD_OPTIONS, requestURI, NULL);
+ * @endcode
+
+ * @note
+ * If you provide an non-NULL @a version string, it is not copied. The
+ * version string @b MUST remain constant.
+ */
+sip_request_t *sip_request_create(su_home_t *home,
+ sip_method_t method, char const *name,
+ url_string_t const *uri,
+ char const *version)
+{
+ size_t xtra;
+ sip_request_t *rq;
+
+ if (method)
+ name = sip_method_name(method, name);
+
+ if (!name)
+ return NULL;
+
+ if (!method)
+ method = sip_method_code(name);
+
+ xtra = url_xtra(uri->us_url) + (method ? 0 : strlen(name) + 1);
+
+ rq = sip_header_alloc(home, sip_request_class, xtra)->sh_request;
+
+ if (rq) {
+ char *b = (char *)(rq + 1), *end = b + xtra;
+
+ rq->rq_method = method;
+ rq->rq_method_name = name;
+ if (!method)
+ MSG_STRING_DUP(b, rq->rq_method_name, name);
+
+ URL_DUP(b, end, rq->rq_url, uri->us_url);
+
+ rq->rq_version = version ? version : SIP_VERSION_CURRENT;
+ assert(b == end);
+ }
+
+ return rq;
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_status Status Line
+ *
+ * The status line is first line in a response message. It is defined in
+ * @RFC3261 as follows:
+ *
+ * @code
+ * Status-Line = SIP-Version SP Status-Code SP Reason-Phrase CRLF
+ * Status-Code = Informational
+ * / Redirection
+ * / Success
+ * / Client-Error
+ * / Server-Error
+ * / Global-Failure
+ * / extension-code
+ * extension-code = 3DIGIT
+ * Reason-Phrase = *(reserved / unreserved / escaped
+ * / UTF8-NONASCII / UTF8-CONT / SP / HTAB)
+ * @endcode
+ *
+ * The parsed status line is stored in #sip_status_t structure.
+ */
+
+/**@ingroup sip_status
+ * @typedef typedef struct sip_status_s sip_status_t;
+ *
+ * The structure #sip_status_t contains representation of SIP
+ * @ref sip_status "status line".
+ *
+ * The #sip_status_t is defined as follows:
+ * @code
+ * typedef struct sip_status_s {
+ * sip_common_t st_common[1]; // Common fragment info
+ * sip_unknown_t *st_next; // Link to next (dummy)
+ * char const *st_version; // Protocol version
+ * int st_status; // Status code
+ * char const *st_phrase; // Status phrase
+ * } sip_status_t;
+ * @endcode
+ */
+
+
+static msg_xtra_f sip_status_dup_xtra;
+static msg_dup_f sip_status_dup_one;
+
+#define sip_status_insert msg_status_insert
+#define sip_status_update NULL
+
+msg_hclass_t sip_status_class[] =
+SIP_HEADER_CLASS(status, NULL, "", st_common, single_critical, status);
+
+/** Parse status line */
+issize_t sip_status_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ sip_status_t *st = h->sh_status;
+ char *status, *phrase;
+ unsigned long code;
+
+ if (msg_firstline_d(s, &status, &phrase) < 0 ||
+ sip_version_d(&s, &st->st_version) < 0 || *s ||
+ (code = strtoul(status, &status, 10)) >= INT_MAX || *status)
+ return -1;
+
+ st->st_status = code;
+ st->st_phrase = phrase;
+
+ return 0;
+}
+
+issize_t sip_status_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+ int status;
+
+ assert(sip_is_status(h));
+
+ status = h->sh_status->st_status;
+
+ if (status > 999 || status < 100)
+ status = 0;
+
+ return snprintf(b, bsiz, "%s %03u %s" CRLF,
+ h->sh_status->st_version,
+ status,
+ h->sh_status->st_phrase);
+}
+
+/** Extra size of a #sip_status_t object. */
+isize_t sip_status_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+ sip_status_t const *st = h->sh_status;
+ offset += sip_version_xtra(st->st_version);
+ offset += MSG_STRING_SIZE(st->st_phrase);
+ return offset;
+}
+
+/** Duplicate one status header. */
+char *sip_status_dup_one(sip_header_t *dst, sip_header_t const *src,
+ char *b, isize_t xtra)
+{
+ sip_status_t *st = dst->sh_status;
+ sip_status_t const *o = src->sh_status;
+ char *end = b + xtra;
+
+ sip_version_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;
+}
+
+/**@ingroup sip_status
+ *
+ * Create a @ref sip_status "status line" object.
+ *
+ * @param home memory home used to allocate #sip_status_t object
+ * @param status status code (in range 100 - 699)
+ * @param phrase status phrase (may be NULL)
+ * @param version version string (defaults to "SIP/2.0" if NULL)
+ *
+ * @note
+ * If you provide an non-NULL @a version string, it is not copied. The
+ * string @b MUST remain constant.
+ *
+ * @return
+ * A pointer to newly created @ref sip_status "status line"
+ * structure when successful, or NULL upon an error.
+ */
+sip_status_t *sip_status_create(su_home_t *home,
+ unsigned status,
+ char const *phrase,
+ char const *version)
+{
+ sip_status_t *st;
+
+ if (status < 100 || status > 699)
+ return NULL;
+
+ if (phrase == NULL && (phrase = sip_status_phrase(status)) == NULL)
+ phrase = "";
+
+ if ((st = sip_header_alloc(home, sip_status_class, 0)->sh_status)) {
+ st->st_status = status;
+ st->st_phrase = phrase;
+ st->st_version = version ? version : SIP_VERSION_CURRENT;
+ }
+
+ return st;
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_payload Message Body
+ *
+ * The payload structure contains the optional message body. The message
+ * body stored in the #sip_payload_t structure has no internal structure,
+ * but it is accessed as a byte array. Use @ref sdp_parser "SDP parser" to
+ * parse SDP content, for instance.
+ *
+ * The message body is stored in a #sip_payload_t structure.
+ */
+
+/**@ingroup sip_payload
+ * @typedef typedef struct sip_payload_s sip_payload_t;
+ *
+ * The structure #sip_payload_t contains representation of SIP message payload.
+ *
+ * The #sip_payload_t is defined as follows:
+ * @code
+ * typedef struct sip_payload_s {
+ * msg_common_t pl_common[1]; // Common fragment info
+ * msg_header_t *pl_next; // Next payload (if multipart message)
+ * char *pl_data; // Data - may contain NUL
+ * unsigned pl_len; // Length of message payload
+ * } sip_payload_t;
+ * @endcode
+ */
+
+#define sip_payload_d msg_payload_d
+#define sip_payload_e msg_payload_e
+#define sip_payload_dup_xtra msg_payload_dup_xtra
+#define sip_payload_dup_one msg_payload_dup_one
+#define sip_payload_update NULL
+
+msg_hclass_t sip_payload_class[] =
+SIP_HEADER_CLASS(payload, NULL, "", pl_common, single, payload);
+
+/**@ingroup sip_payload
+ *
+ * Create a @ref sip_payload "SIP payload" structure.
+ *
+ * Create a new SIP payload structure. it
+ * copies the given data to the the payload data, and NUL terminates it (it
+ * allocates one extra byte for NUL). If a NULL pointer is given as @a data,
+ * sip_payload_create() allocates and zeroes a data buffer of @a len bytes.
+ *
+ * @param home memory home
+ * @param data payload data
+ * @param len payload length
+ *
+ * @return A pointer to newly created
+ * payload structure, if successful, and NULL upon an error.
+ */
+sip_payload_t *sip_payload_create(su_home_t *home, void const *data, isize_t len)
+{
+ msg_hclass_t *hc = sip_payload_class;
+ sip_header_t *h = sip_header_alloc(home, hc, len + 1);
+ sip_payload_t *pl = h->sh_payload;
+
+ if (pl) {
+ char *b = sip_header_data(h);
+ if (data) {
+ memcpy(b, data, len);
+ b[len] = 0;
+ }
+ else {
+ memset(b, 0, len + 1);
+ }
+
+ h->sh_data = pl->pl_data = b;
+ h->sh_len = pl->pl_len = len;
+ }
+
+ return pl;
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_separator Separator Line
+ *
+ * An empty line separates message headers from the message body (payload).
+ * In order to avoid modifying messages with integrity protection, the
+ * separator line has its own header structure which is included in the
+ * #sip_t structure.
+ *
+ * The parsed separator line is stored in #sip_separator_t structure.
+ */
+
+/**@ingroup sip_separator
+ * @typedef typedef struct sip_separator_s sip_separator_t;
+ *
+ * The structure #sip_separator_t contains representation of separator line
+ * between message headers and body.
+ *
+ * The #sip_separator_t is defined as follows:
+ * @code
+ * typedef struct sip_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
+ * } sip_separator_t;
+ * @endcode
+ */
+
+#define sip_separator_d msg_separator_d
+#define sip_separator_e msg_separator_e
+#define sip_separator_insert msg_separator_insert
+
+msg_hclass_t sip_separator_class[] =
+SIP_HEADER_CLASS(separator, NULL, "", sep_common, single, any);
+
+/**@ingroup sip_separator
+ *
+ * Create a @ref sip_separator "SIP separator line" structure.
+ */
+sip_separator_t *sip_separator_create(su_home_t *home)
+{
+ sip_separator_t *sep =
+ sip_header_alloc(home, sip_separator_class, 0)->sh_separator;
+
+ if (sep)
+ strcpy(sep->sep_data, CRLF);
+
+ return sep;
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_unknown Unknown Headers
+ *
+ * The unknown headers are handled with #sip_unknown_t structure. The
+ * unknown header name is stored in @a un_name field and the header field
+ * following the colon is stored in @a un_value field.
+ *
+ * @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 regarded as unknown and put into
+ * list of unknown headers.
+ */
+
+/**@ingroup sip_unknown
+ * @typedef typedef struct sip_unknown_s sip_unknown_t;
+ *
+ * The structure #sip_unknown_t contains representation of unknown headers.
+ *
+ * The #sip_unknown_t is defined as follows:
+ * @code
+ * typedef 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
+ * } sip_unknown_t;
+ * @endcode
+ */
+
+#define sip_unknown_dup_xtra msg_unknown_dup_xtra
+#define sip_unknown_dup_one msg_unknown_dup_one
+#define sip_unknown_update NULL
+
+msg_hclass_t sip_unknown_class[] =
+SIP_HEADER_CLASS(unknown, "", "", un_common, append, unknown);
+
+issize_t sip_unknown_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ return msg_unknown_d(home, h, s, slen);
+}
+
+issize_t sip_unknown_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+ return msg_unknown_e(b, bsiz, h, flags);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_error Erroneous Headers
+ *
+ * The erroneous headers are stored in #sip_error_t structure.
+ *
+ * @note Other headers (like duplicate @ContentLength headers) may be put
+ * into the list of erroneous headers (@c sip->sip_error). If the list of
+ * erroneous headers is processed, the header type must be validated first
+ * by calling sip_is_error() (or by other relevant tests).
+ */
+
+/**@ingroup sip_error
+ * @typedef typedef msg_error_t sip_error_t;
+ * The structure #sip_error_t contains representation of error headers.
+ *
+ * The #sip_error_t is defined as follows:
+ * @code
+ * typedef 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)
+ * } sip_error_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_error_class[] =
+SIP_HEADER_CLASS(error, NULL, "", er_common, append, any);
+
+issize_t sip_error_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
+{
+ return 0;
+}
+
+issize_t sip_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;
+}
+
+/* ====================================================================== */
+/*
+ * addr = ("To" | "t" | "From" | "f") ":"
+ * ( name-addr | addr-spec ) *( ";" addr-params )
+ * name-addr = [ display-name ] "<" addr-spec ">"
+ * addr-spec = SIP-URL | URI
+ * display-name = *token | quoted-string
+ */
+
+/**Parse @e name-addr.
+ *
+ * Parses <i>( name-addr | addr-spec )</i> construct on @Contact, @From,
+ * @To, and other compatible headers. It splits the argument string in
+ * four parts:
+ *
+ * @par
+ * @e [display-name] @e addr-spec @e [parameters] @e [comment] @e [ss]
+ *
+ * @param home pointer to memory home
+ * @param inout_s pointer to pointer to string to be parsed
+ * @param return_display value-result parameter for @e display-name
+ * @param return_url value-result parameter for @e addr-spec
+ * @param return_params value-result paramater for @e parameters
+ * @param return_comment value-result parameter for @e comment
+ *
+ * @note After succesful call to the function @c sip_name_addr_d(), *ss
+ * contains pointer to the first character not beloging to @e name-addr,
+ * most probably a comma. If that character is a separator, the last parameter
+ * may not be NUL (zero) terminated. So, after examining value of @a **ss,
+ * the calling function @b MUST set it to NUL.
+ *
+ * @retval 0 if successful
+ * @retval -1 upon an error
+ *
+ * @sa @From, @To, @Contact
+ */
+issize_t sip_name_addr_d(su_home_t *home,
+ char **inout_s,
+ char const **return_display,
+ url_t *return_url,
+ msg_param_t const **return_params,
+ char const **return_comment)
+{
+ char c, *s = *inout_s;
+ char *display = NULL, *addr_spec = NULL;
+ size_t n;
+
+ if (*s == '\0') /* Empty string */
+ return -1;
+
+ if (return_display && *s == '"') {
+ /* Quoted string */
+ if (msg_quoted_d(&s, &display) == -1)
+ return -1;
+
+ /* Now, we should have a '<' in s[0] */
+ if (s[0] != '<')
+ return -1;
+ s++[0] = '\0'; /* NUL terminate quoted string... */
+ n = strcspn(s, ">");
+ addr_spec = s; s += n;
+ if (*s) *s++ = '\0'; else return -1;
+ }
+ else {
+ if (return_display)
+ n = span_token_lws(s);
+ else
+ n = 0;
+
+ if (s[n] == '<') {
+ /* OK, we got a display name */
+ display = s; s += n + 1;
+ /* NUL terminate display name */
+ while (n > 0 && IS_LWS(display[n - 1]))
+ n--;
+ if (n > 0)
+ display[n] = '\0';
+ else
+ display = "";
+
+ n = strcspn(s, ">");
+ addr_spec = s; s += n; if (*s) *s++ = '\0'; else return -1;
+ }
+ else {
+ /* addr-spec only */
+ addr_spec = s;
+ /**@sa
+ * Discussion about comma, semicolon and question mark in
+ * @RFC3261 section 20.10.
+ */
+ if (return_params)
+ n = strcspn(s, " \t,;?"); /* DO NOT accept ,;? in URL */
+ else
+ /* P-Asserted-Identity and friends */
+ n = strcspn(s, " ,"); /* DO NOT accept , in URL */
+ s += n;
+ if (IS_LWS(*s))
+ *s++ = '\0';
+ }
+ }
+
+ skip_lws(&s);
+
+ if (return_display)
+ *return_display = display;
+
+ /* Now, url may still not be NUL terminated, e.g., if
+ * it is like "Contact: url:foo,sip:bar,sip:zunk"
+ */
+ c = *s; *s = '\0'; /* terminate temporarily */
+ if (url_d(return_url, addr_spec) == -1)
+ return -1;
+ *s = c; /* return terminator */
+
+ *inout_s = s;
+
+ if (c == ';' && return_params)
+ if (msg_params_d(home, inout_s, return_params) == -1)
+ return -1;
+
+ if (**inout_s == '(' && return_comment)
+ if (msg_comment_d(inout_s, return_comment) == -1)
+ return -1;
+
+ return 0;
+}
+
+/**Encode @e name-addr and parameter list.
+ *
+ * Encodes @e name-addr headers, like @From, @To, @CallInfo, @ErrorInfo,
+ * @Route, and @RecordRoute.
+ *
+ * @param b buffer to store the encoding result
+ * @param bsiz size of the buffer @a b
+ * @param flags encoding flags
+ * @param display display name encoded before the @a url (may be NULL)
+ * @param brackets if true, use always brackets around @a url
+ * @param url pointer to URL structure
+ * @param params pointer to parameter list (may be NULL)
+ * @param comment comment string encoded after others (may be NULL)
+ *
+ * @return
+ * Returns number of characters in encoding, excluding the
+ * final NUL.
+ *
+ * @note
+ * The encoding result may be incomplete if the buffer size is not large
+ * enough to store the whole encoding result.
+ */
+issize_t sip_name_addr_e(char b[], isize_t bsiz,
+ int flags,
+ char const *display,
+ int brackets, url_t const url[],
+ msg_param_t const params[],
+ char const *comment)
+{
+ int const compact = MSG_IS_COMPACT(flags);
+ char const *u;
+ char *b0 = b, *end = b + bsiz;
+
+ brackets = brackets || display ||
+ (url && (url->url_params ||
+ url->url_headers ||
+ ((u = url->url_user) && u[strcspn(u, ";,?")]) ||
+ ((u = url->url_password) && u[strcspn(u, ",")])));
+
+ if (display && display[0]) {
+ MSG_STRING_E(b, end, display);
+ if (!compact) MSG_CHAR_E(b, end, ' ');
+ }
+ if (url) {
+ if (brackets) MSG_CHAR_E(b, end, '<');
+ URL_E(b, end, url);
+ if (brackets) MSG_CHAR_E(b, end, '>');
+ }
+
+ MSG_PARAMS_E(b, end, params, flags);
+
+ if (comment) {
+ if (!compact) MSG_CHAR_E(b, end, ' ');
+ MSG_CHAR_E(b, end, '(');
+ MSG_STRING_E(b, end, comment);
+ MSG_CHAR_E(b, end, ')');
+ }
+
+ MSG_TERM_E(b, end);
+
+ return b - b0;
+}
+
+/** Parse @To or @From headers */
+issize_t sip_addr_d(su_home_t *home,
+ sip_header_t *h,
+ char *s,
+ isize_t slen)
+{
+ sip_addr_t *a = (sip_addr_t *)h;
+ char const *comment = NULL;
+ if (sip_name_addr_d(home,
+ &s,
+ &a->a_display,
+ a->a_url,
+ &a->a_params,
+ &comment) == -1
+ || *s /* XXX - something extra? */)
+ return -1;
+
+ a->a_tag = msg_params_find(a->a_params, "tag=");
+
+ return 0;
+}
+
+static int sip_addr_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+ sip_addr_t const *a = (sip_addr_t const *)h;
+
+ return sip_name_addr_e(b, bsiz,
+ flags,
+ a->a_display,
+ MSG_IS_CANONIC(flags), a->a_url,
+ a->a_params,
+ NULL);
+}
+
+/**
+ * Extra dup size of a sip_addr_t object.
+ *
+ * This function calculates extra size required when duplicating a
+ * sip_addr_t object.
+ *
+ * @param a pointer to a sip_addr_t object
+ *
+ * @return
+ * Size of strings related to sip_addr_t object.
+ */
+static
+isize_t sip_addr_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+ sip_addr_t const *a = (sip_addr_t const *)h;
+
+ MSG_PARAMS_SIZE(offset, a->a_params);
+ offset += MSG_STRING_SIZE(a->a_display);
+ offset += url_xtra(a->a_url);
+
+ return offset;
+}
+
+/**@internal
+ * Duplicate one sip_addr_t object.
+ */
+static char *sip_addr_dup_one(sip_header_t *dst, sip_header_t const *src,
+ char *b, isize_t xtra)
+{
+ sip_addr_t *a = (sip_addr_t *)dst;
+ sip_addr_t const *o = (sip_addr_t *)src;
+ char *end = b + xtra;
+
+ b = msg_params_dup(&a->a_params, o->a_params, b, xtra);
+ MSG_STRING_DUP(b, a->a_display, o->a_display);
+ URL_DUP(b, end, a->a_url, o->a_url);
+
+ assert(b <= end);
+
+ return b;
+}
+
+/** Update parameters in sip_addr_t object */
+static int sip_addr_update(msg_common_t *h,
+ char const *name, isize_t namelen,
+ char const *value)
+{
+ sip_addr_t *a = (sip_addr_t *)h;
+
+ if (name == NULL) {
+ a->a_tag = NULL;
+ }
+ else if (namelen == strlen("tag") && !strncasecmp(name, "tag", namelen)) {
+ a->a_tag = value;
+ }
+
+ return 0;
+}
+
+/** Create an address header object from URL */
+static sip_addr_t *
+sip_addr_make_url(su_home_t *home, msg_hclass_t *hc, url_string_t const *us)
+{
+ size_t n;
+ sip_header_t *h;
+
+ n = url_xtra(us->us_url);
+ h = sip_header_alloc(home, sip_to_class, n);
+
+ if (h) {
+ sip_addr_t *a = h->sh_to;
+ char *s2 = sip_header_data(h);
+
+ if ((size_t)url_dup(s2, n, a->a_url, us->us_url) == n)
+ return a;
+
+ su_free(home, h);
+ }
+
+ return NULL;
+}
+
+/** Add a tag to address structure. */
+static
+int sip_addr_tag(su_home_t *home, sip_addr_t *a, char const *tag)
+{
+ if (a && tag) {
+ msg_param_t value = strchr(tag, '=');
+
+ if (value)
+ value = strchr(value, '=') + 1;
+ else
+ value = tag;
+
+ if (a->a_tag) {
+ if (strcasecmp(a->a_tag, value) == 0)
+ return 0;
+ else
+ return -1;
+ }
+
+ if (tag == value)
+ tag = su_sprintf(home, "tag=%s", tag);
+ else
+ tag = su_strdup(home, tag);
+
+ if (tag)
+ if (msg_header_replace_param(home, a->a_common, tag) >= 0)
+ return 0;
+ }
+
+ return -1;
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_call_id Call-ID Header
+ *
+ * The @b Call-ID header uniquely identifies a particular invitation or all
+ * registrations of a particular client. It is defined in @RFC3261 as
+ * follows:
+ *
+ * @code
+ * Call-ID = ( "Call-ID" / "i" ) HCOLON callid
+ * callid = word [ "@" word ]
+ * word = 1*(alphanum / "-" / "." / "!" / "%" / "*" /
+ * "_" / "+" / "`" / "'" / "~" / "(" / ")" / "<" / ">" /
+ * ":" / "\" / DQUOTE / "/" / "[" / "]" / "?" / "{" / "}" )
+ * @endcode
+ *
+ * The parsed Call-ID Header is stored in #sip_call_id_t structure.
+ */
+
+/**@ingroup sip_call_id
+ * @typedef typedef struct sip_call_id_s sip_call_id_t;
+ *
+ * The structure #sip_call_id_t contains representation of SIP @CallID
+ * header.
+ *
+ * The #sip_call_id_t is defined as follows:
+ * @code
+ * typedef struct sip_call_id_s {
+ * sip_common_t i_common[1]; // Common fragment info
+ * sip_call_id_t *i_next; // Link to next (dummy)
+ * char const *i_id; // ID value
+ * uint32_t i_hash; // Hash value (always nonzero)
+ * } sip_call_id_t;
+ * @endcode
+ */
+
+static msg_xtra_f sip_call_id_dup_xtra;
+static msg_dup_f sip_call_id_dup_one;
+#define sip_call_id_update NULL
+
+msg_hclass_t sip_call_id_class[] =
+SIP_HEADER_CLASS(call_id, "Call-ID", "i", i_common, single, call_id);
+
+issize_t sip_call_id_d(su_home_t *home,
+ sip_header_t *h,
+ char *s,
+ isize_t slen)
+{
+ sip_call_id_t *i = h->sh_call_id;
+
+ i->i_id = s; /* XXX - why not sip_word_at_word_d(&s); */
+ i->i_hash = msg_hash_string(s);
+
+ return 0;
+}
+
+
+issize_t sip_call_id_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+ size_t n = strlen(h->sh_call_id->i_id);
+
+ if (bsiz > n)
+ strcpy(b, h->sh_call_id->i_id);
+
+ return (issize_t)n;
+}
+
+/** Extra size of a #sip_call_id_t object. */
+isize_t sip_call_id_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+ sip_call_id_t const *i = h->sh_call_id;
+ return offset + MSG_STRING_SIZE(i->i_id);
+}
+
+/**Duplicate a sip_call_id object.
+ *
+ * Duplicate (copy deeply) a single #sip_call_id_t header object.
+ *
+ * @param dst pointer to newly allocated header object
+ * @param src pointer to a header object to be duplicated
+ * @param b memory buffer used to copy external references
+ * @param xtra number bytes in buffer @a b
+ *
+ * @return Pointer to the new copy of #sip_call_id_t object, or @c NULL
+ * upon an error.
+ */
+char *sip_call_id_dup_one(sip_header_t *dst, sip_header_t const *src,
+ char *b, isize_t xtra)
+{
+ sip_call_id_t *i = dst->sh_call_id;
+ sip_call_id_t const *o = src->sh_call_id;
+ char *end = b + xtra;
+
+ MSG_STRING_DUP(b, i->i_id, o->i_id);
+ if (!(i->i_hash = o->i_hash))
+ i->i_hash = msg_hash_string(i->i_id);
+ assert(b <= end); (void)end;
+
+ return b;
+}
+
+/**@ingroup sip_call_id
+ *
+ * Create a @CallID header object.
+ *
+ * Create a Call-ID header object with a new unique value. It uses
+ * su_guid_generate() function to generate the value. If the local host name
+ * @a domain is specified, it is prepended to the generated value instead of
+ * local MAC address.
+
+ * @param home memory home
+ * @param domain local domain name
+ *
+ * @return A pointer to newly created @CallID header object when
+ * successful or NULL upon an error.
+ *
+ * @sa su_guid_generate(), su_guid_sprintf()
+ */
+sip_call_id_t *sip_call_id_create(su_home_t *home, char const *domain)
+{
+ sip_call_id_t *i;
+ size_t xtra = su_guid_strlen + 1 + (domain ? strlen(domain) + 1 : 0);
+
+ i = sip_header_alloc(home, sip_call_id_class, xtra)->sh_call_id;
+
+ if (i) {
+ char *b;
+ su_guid_t guid[1];
+
+ i->i_id = b = (char *)(i + 1);
+
+ su_guid_generate(guid);
+ /*
+ * Guid looks like "NNNNNNNN-NNNN-NNNN-NNNN-XXXXXXXXXXXX"
+ * where NNNNNNNN-NNNN-NNNN-NNNN is timestamp and XX is MAC address
+ * (but we use usually random ID for MAC because we do not have
+ * guid generator available for all processes within node)
+ */
+ su_guid_sprintf(b, su_guid_strlen + 1, guid);
+
+ /* If we have a domain name don't include MAC address at the end of guid */
+ if (domain) {
+ b[8 + 5 + 5 + 5] = '@';
+ strcpy(b + 8 + 5 + 5 + 5 + 1, domain);
+ }
+
+ i->i_hash = msg_hash_string(i->i_id);
+ }
+
+ return i;
+
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_cseq CSeq Header
+ *
+ * The CSeq header (command sequence) uniquely identifies transactions
+ * within a dialog. It is defined in @RFC3261 as follows:
+ *
+ * @code
+ * CSeq = "CSeq" HCOLON 1*DIGIT LWS Method
+ * Method = INVITEm / ACKm / OPTIONSm / BYEm
+ * / CANCELm / REGISTERm
+ * / extension-method
+ * extension-method = token
+ * @endcode
+ *
+ * The parsed CSeq header is stored in #sip_cseq_t structure.
+ */
+
+/**@ingroup sip_cseq
+ * @typedef typedef struct sip_cseq_s sip_cseq_t;
+ *
+ * The structure #sip_cseq_t contains representation of SIP @CSeq header.
+ *
+ * The #sip_cseq_t is defined as follows:
+ * @code
+ * typedef struct sip_cseq_s {
+ * sip_common_t cs_common[1]; // Common fragment info
+ * sip_error_t *cs_next; // Link to next (dummy)
+ * uint32_t cs_seq; // Sequence number
+ * sip_method_t cs_method; // Method enum
+ * char const *cs_method_name; // Method name
+ * } sip_cseq_t;
+ * @endcode
+ */
+
+static msg_xtra_f sip_cseq_dup_xtra;
+static msg_dup_f sip_cseq_dup_one;
+#define sip_cseq_update NULL
+
+msg_hclass_t sip_cseq_class[] =
+SIP_HEADER_CLASS(cseq, "CSeq", "", cs_common, single, cseq);
+
+issize_t sip_cseq_d(su_home_t *home,
+ sip_header_t *h,
+ char *s,
+ isize_t slen)
+{
+ sip_cseq_t *cs = h->sh_cseq;
+
+ if (msg_uint32_d(&s, &cs->cs_seq) < 0)
+ return -1;
+
+ if (*s) {
+ if ((cs->cs_method = sip_method_d(&s, &cs->cs_method_name)) >= 0)
+ return 0;
+ }
+
+ return -1;
+}
+
+
+issize_t sip_cseq_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+ assert(sip_is_cseq(h));
+
+ return snprintf(b, bsiz,
+ "%u %s",
+ h->sh_cseq->cs_seq,
+ h->sh_cseq->cs_method_name);
+}
+
+isize_t sip_cseq_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+ sip_cseq_t const *cs = h->sh_cseq;
+ if (!cs->cs_method)
+ return offset + MSG_STRING_SIZE(cs->cs_method_name);
+ else
+ return offset;
+}
+
+char *sip_cseq_dup_one(sip_header_t *dst, sip_header_t const *src,
+ char *b, isize_t xtra)
+{
+ sip_cseq_t *cs = dst->sh_cseq;
+ sip_cseq_t const *o = src->sh_cseq;
+ char *end = b + xtra;
+
+ if (!(cs->cs_method = o->cs_method))
+ MSG_STRING_DUP(b, cs->cs_method_name, o->cs_method_name);
+ else
+ cs->cs_method_name = o->cs_method_name;
+ cs->cs_seq = o->cs_seq;
+
+ assert(b <= end); (void)end;
+
+ return b;
+}
+
+/**@ingroup sip_cseq
+ *
+ * Create a @CSeq header object.
+ *
+ * Create a @CSeq header object with the
+ * sequence number @a seq, method enum @a method and method name @a
+ * method_name. The memory for the header object is allocated from the
+ * memory home @a home.
+ *
+ * @param home memory home
+ * @param seq sequence number
+ * @param method method enum
+ * @param method_name method name (required if method is not well-known)
+ *
+ * @par Example
+ * The following code fragment creates a cseq object for OPTIONS request:
+ * @code
+ * sip_cseq_t *cseq;
+ * cseq = sip_cseq_create(home, agent->seq++, SIP_METHOD_OPTIONS);
+ * @endcode
+ *
+ * @return
+ * A pointer to newly created @CSeq
+ * header object when successful or NULL upon an error.
+ */
+sip_cseq_t *sip_cseq_create(su_home_t *home,
+ uint32_t seq,
+ unsigned method,
+ char const *method_name)
+{
+ size_t xtra;
+ sip_cseq_t *cs;
+
+ if (method)
+ method_name = sip_method_name(method, method_name);
+
+ if (method_name == NULL)
+ return NULL;
+
+ xtra = (method ? 0 : (strlen(method_name) + 1));
+
+ cs = sip_header_alloc(home, sip_cseq_class, xtra)->sh_cseq;
+
+ if (cs) {
+ cs->cs_seq = seq;
+ cs->cs_method = method;
+ if (!method)
+ method_name = strcpy((char *)(cs + 1), method_name);
+ cs->cs_method_name = method_name;
+ }
+ return cs;
+}
+
+
+/* ====================================================================== */
+/**@SIP_HEADER sip_contact Contact Header
+ *
+ * The Contact header contain a list of URLs used to redirect future
+ * requests. Its syntax is defined in @RFC3261 as follows:
+ *
+ * @code
+ * Contact = ("Contact" / "m" ) HCOLON
+ * ( STAR / (contact-param *(COMMA contact-param)))
+ * contact-param = (name-addr / addr-spec) *(SEMI contact-params)
+ * name-addr = [ display-name ] LAQUOT addr-spec RAQUOT
+ * addr-spec = SIP-URI / SIPS-URI / absoluteURI
+ * display-name = *(token LWS)/ quoted-string
+ * contact-params = c-p-q / c-p-expires
+ * / contact-extension
+ * c-p-q = "q" EQUAL qvalue
+ * c-p-expires = "expires" EQUAL delta-seconds
+ * contact-extension = generic-param
+ * delta-seconds = 1*DIGIT
+ * @endcode
+ *
+ * @note
+ * The @RFC2543 syntax allowed <comment>. We accept it, but don't encode it.
+ *
+ * Each parsed Contact header field is stored in #sip_contact_t structure.
+ */
+
+/**@ingroup sip_contact
+ * @typedef typedef struct sip_contact_s sip_contact_t;
+ *
+ * The structure #sip_contact_t contains representation of SIP @Contact
+ * header.
+ *
+ * The #sip_contact_t is defined as follows:
+ * @code
+ * typedef struct sip_contact_s {
+ * sip_common_t m_common[1]; // Common fragment info
+ * sip_contact_t *m_next; // Link to next
+ * char const *m_display; // Display name
+ * url_t m_url[1]; // SIP URL
+ * msg_param_t const *m_params; // List of contact-params
+ * char const *m_comment; // Comment
+ *
+ * char const *m_q; // Priority
+ * char const *m_expires; // Expiration time
+ * } sip_contact_t;
+ * @endcode
+ *
+ * @note The <comment> field @ref sip_contact_s::m_comment "m_comment" is
+ * deprecated: it is parsed but not included in encoding.
+ */
+
+static msg_xtra_f sip_contact_dup_xtra;
+static msg_dup_f sip_contact_dup_one;
+static msg_update_f sip_contact_update;
+
+/** @showinitializer */
+msg_hclass_t sip_contact_class[] =
+ /*
+ * Cut through the fog of macros
+ * SIP_HEADER_CLASS(contact, "Contact", "m", m_params, append, contact);
+ * and show here how the msg_hclass_t is initialized
+ */
+ {{
+ /* hc_hash: */ sip_contact_hash,
+ /* hc_parse: */ sip_contact_d,
+ /* hc_print: */ sip_contact_e,
+ /* hc_dxtra: */ sip_contact_dup_xtra,
+ /* hc_dup_one: */ sip_contact_dup_one,
+ /* hc_update: */ sip_contact_update,
+ /* hc_name: */ "Contact",
+ /* hc_len: */ sizeof("Contact") - 1,
+ /* hc_short: */ "m",
+ /* hc_size: */ MSG_ALIGN(sizeof(sip_contact_t), sizeof(void*)),
+ /* hc_params: */ offsetof(sip_contact_t, m_params),
+ /* hc_kind: */ msg_kind_append,
+ /* hc_critical: */ 0
+ }};
+
+issize_t sip_contact_d(su_home_t *home,
+ sip_header_t *h,
+ char *s,
+ isize_t slen)
+{
+ sip_contact_t *m = (sip_contact_t *)h;
+
+ assert(h);
+
+ while (*s == ',') /* Ignore empty entries (comma-whitespace) */
+ *s = '\0', s += span_lws(s + 1) + 1;
+
+ if (sip_name_addr_d(home, &s, &m->m_display, m->m_url,
+ &m->m_params, &m->m_comment) == -1)
+ return -1;
+
+ return msg_parse_next_field(home, h, s, slen);
+}
+
+
+issize_t sip_contact_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+ sip_contact_t const *m = h->sh_contact;
+ int always_lt_gt = MSG_IS_CANONIC(flags) && m->m_url->url_type != url_any;
+
+ assert(sip_is_contact(h));
+
+ return sip_name_addr_e(b, bsiz, flags,
+ m->m_display, always_lt_gt, m->m_url,
+ m->m_params,
+ NULL /* m->m_comment */);
+}
+
+
+isize_t sip_contact_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+ sip_contact_t const *m = h->sh_contact;
+
+ MSG_PARAMS_SIZE(offset, m->m_params);
+ offset += MSG_STRING_SIZE(m->m_display);
+ offset += url_xtra(m->m_url);
+ offset += MSG_STRING_SIZE(m->m_comment);
+
+ return offset;
+}
+
+char *sip_contact_dup_one(sip_header_t *dst, sip_header_t const *src,
+ char *b, isize_t xtra)
+{
+ char *end = b + xtra;
+ sip_contact_t *m = dst->sh_contact;
+ sip_contact_t const *o = src->sh_contact;
+
+ b = msg_params_dup(&m->m_params, o->m_params, b, xtra);
+ MSG_STRING_DUP(b, m->m_display, o->m_display);
+ URL_DUP(b, end, m->m_url, o->m_url);
+ MSG_STRING_DUP(b, m->m_comment, o->m_comment);
+
+ assert(b <= end);
+
+ return b;
+}
+
+/** Update parameter in #sip_contact_t */
+static int sip_contact_update(msg_common_t *h,
+ char const *name, isize_t namelen,
+ char const *value)
+{
+ sip_contact_t *m = (sip_contact_t *)h;
+
+ if (name == NULL) {
+ m->m_q = NULL;
+ m->m_expires = NULL;
+ }
+ else if (namelen == 1 && strncasecmp(name, "q", 1) == 0) {
+ /* XXX - check for invalid value? */
+ m->m_q = value;
+ }
+ else if (namelen == strlen("expires") &&
+ !strncasecmp(name, "expires", namelen)) {
+ m->m_expires = value;
+ }
+
+ return 0;
+}
+
+/**@ingroup sip_contact
+ *
+ * Add a parameter to a @Contact header object
+ *
+ * Add a parameter to a @Contact
+ * object. It does not copy the contents of the string @c param.
+ *
+ * @note This function @b does @b not duplicate @p param.
+ *
+ * @param home memory home
+ * @param m #sip_contact_t object
+ * @param param parameter string
+ *
+ * @return 0 when successful, and -1 upon an error.
+ *
+ * @deprecated Use msg_header_replace_param() directly.
+ */
+int sip_contact_add_param(su_home_t *home,
+ sip_contact_t *m,
+ char const *param)
+{
+ return msg_header_replace_param(home, m->m_common, param);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_content_length Content-Length Header
+ *
+ * The Content-Length header indicates the size of the message-body in
+ * decimal number of octets. Its syntax is defined in @RFC3261 as
+ * follows:
+ *
+ * @code
+ * Content-Length = ( "Content-Length" / "l" ) HCOLON 1*DIGIT
+ * @endcode
+ *
+ * The parsed Content-Length header is stored in #sip_content_length_t
+ * structure.
+ */
+
+/**@ingroup sip_content_length
+ * @typedef typedef struct sip_content_length_s sip_content_length_t;
+ *
+ * The structure #sip_content_length_t contains representation of SIP
+ * @ContentLength header.
+ *
+ * The #sip_content_length_t is defined as follows:
+ * @code
+ * typedef struct sip_content_length_s {
+ * sip_common_t l_common[1]; // Common fragment info
+ * sip_error_t *l_next; // Dummy link to next
+ * uint32_t l_length; // Message body length in bytes
+ * } sip_content_length_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_content_length_class[] =
+SIP_HEADER_CLASS(content_length, "Content-Length", "l", l_common,
+ single_critical, any);
+
+issize_t sip_content_length_d(su_home_t *home,
+ sip_header_t *h,
+ char *s,
+ isize_t slen)
+{
+ return sip_numeric_d(home, h, s, slen);
+}
+
+issize_t sip_content_length_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+ assert(sip_is_content_length(h));
+ return sip_numeric_e(b, bsiz, h, flags);
+}
+
+/**@ingroup sip_content_length
+ *
+ * Create a @ContentLength header object.
+ *
+ * Create a @ContentLength
+ * header object with the value @a n. The memory for the header is
+ * allocated from the memory home @a home.
+ *
+ * @param home memory home
+ * @param n payload size in bytes
+ *
+ * @return
+ * A pointer to newly created @ContentLength header object when successful
+ * or NULL upon an error.
+ */
+sip_content_length_t *sip_content_length_create(su_home_t *home, uint32_t n)
+{
+ sip_content_length_t *l =
+ sip_header_alloc(home, sip_content_length_class, 0)->sh_content_length;
+
+ if (l)
+ l->l_length = n;
+
+ return l;
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_date Date Header
+ *
+ * The Date header field reflects the time when the request or response was
+ * first sent. Its syntax is defined in @RFC3261 and @RFC2616 section 14.18 as
+ * follows:
+ *
+ * @code
+ * Date = "Date" HCOLON SIP-date
+ * SIP-date = rfc1123-date
+ * rfc1123-date = wkday "," SP date1 SP time SP "GMT"
+ * date1 = 2DIGIT SP month SP 4DIGIT
+ * ; day month year (e.g., 02 Jun 1982)
+ * time = 2DIGIT ":" 2DIGIT ":" 2DIGIT
+ * ; 00:00:00 - 23:59:59
+ * wkday = "Mon" / "Tue" / "Wed"
+ * / "Thu" / "Fri" / "Sat" / "Sun"
+ * month = "Jan" / "Feb" / "Mar" / "Apr"
+ * / "May" / "Jun" / "Jul" / "Aug"
+ * / "Sep" / "Oct" / "Nov" / "Dec"
+ * @endcode
+ *
+ * The parsed Date header is stored in #sip_date_t structure.
+ */
+
+/**@ingroup sip_date
+ * @typedef typedef struct sip_date_s sip_date_t;
+ *
+ * The structure #sip_date_t contains representation of SIP @Date header.
+ *
+ * The #sip_date_t is defined as follows:
+ * @code
+ * typedef struct sip_date_s {
+ * sip_common_t d_common[1]; // Common fragment info
+ * sip_date_t *d_next; // Link to next (dummy)
+ * sip_time_t d_time; // Seconds since Jan 1, 1900
+ * } sip_date_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_date_class[] =
+SIP_HEADER_CLASS(date, "Date", "", d_common, single, any);
+
+issize_t sip_date_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ sip_date_t *date = h->sh_date;
+
+ if (msg_date_d((char const **)&s, &date->d_time) < 0 || *s)
+ return -1;
+ else
+ return 0;
+}
+
+issize_t sip_date_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+ sip_date_t const *date = h->sh_date;
+
+ return msg_date_e(b, bsiz, date->d_time);
+}
+
+/**@ingroup sip_date
+ * @brief Create an @Date header object.
+ *
+ * Create a @Date header object with
+ * the date @a date. If @date is 0, current time (as returned by sip_now())
+ * is used.
+ *
+ * @param home memory home
+ * @param date date expressed as seconds since Mon, 01 Jan 1900 00:00:00
+ *
+ * @return
+ * A pointer to newly created @Date header object when successful, or NULL
+ * upon an error.
+ */
+sip_date_t *sip_date_create(su_home_t *home, sip_time_t date)
+{
+ sip_header_t *h = sip_header_alloc(home, sip_date_class, 0);
+
+ if (h) {
+ if (date == 0)
+ date = sip_now();
+ h->sh_date->d_time = date;
+ }
+
+ return h->sh_date;
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_expires Expires Header
+ *
+ * The Expires header field gives the date and time after which the message
+ * content expires. Its syntax is defined in @RFC3261 as follows:
+ *
+ * @code
+ * Expires = "Expires" HCOLON delta-seconds
+ * @endcode
+ *
+ * Note that the first SIP revision (@RFC2543) also allowed absolute time in
+ * Expires.
+ *
+ * The parsed Expires header is stored in #sip_expires_t structure.
+ */
+
+/**@ingroup sip_expires
+ * @typedef typedef struct sip_expires_s sip_expires_t;
+ *
+ * The structure #sip_expires_t contains representation of SIP @Expires
+ * header.
+ *
+ * The #sip_expires_t is defined as follows:
+ * @code
+ * typedef struct sip_expires_s {
+ * sip_common_t ex_common[1]; // Common fragment info
+ * sip_error_t *ex_next; // Link to next (dummy)
+ * sip_time_t ex_date; // Seconds since Jan 1, 1900
+ * sip_time_t ex_delta; // ...or delta seconds
+ * } sip_expires_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_expires_class[] =
+SIP_HEADER_CLASS(expires, "Expires", "", ex_common, single, any);
+
+issize_t sip_expires_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ sip_expires_t *expires = h->sh_expires;
+
+ if (msg_date_delta_d((char const **)&s,
+ &expires->ex_date,
+ &expires->ex_delta) < 0 || *s)
+ return -1;
+ else
+ return 0;
+}
+
+issize_t sip_expires_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+ sip_expires_t const *expires = h->sh_expires;
+
+ if (expires->ex_date)
+ return msg_date_e(b, bsiz, expires->ex_date + expires->ex_delta);
+ else
+ return msg_delta_e(b, bsiz, expires->ex_delta);
+}
+
+/**@ingroup sip_expires
+ * @brief Create an @Expires header object.
+ *
+ * Create an @Expires header object with the expiration time @a delta.
+ *
+ * @param home memory home used to allocate #sip_expires_t structure
+ * @param delta relative expiration time in seconds
+ *
+ * @return
+ * A pointer to newly created @Expires header object when successful or NULL
+ * upon an error.
+ */
+sip_expires_t *sip_expires_create(su_home_t *home, sip_time_t delta)
+{
+ sip_header_t *h = sip_header_alloc(home, sip_expires_class, 0);
+
+ if (h)
+ h->sh_expires->ex_delta = delta;
+
+ return h->sh_expires;
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_from From Header
+ *
+ * The From header indicates the initiator of the request. It is defined in
+ * @RFC3261 as follows:
+ *
+ * @code
+ * From = ( "From" / "f" ) HCOLON from-spec
+ * from-spec = ( name-addr / addr-spec )
+ * *( SEMI from-param )
+ * from-param = tag-param / generic-param
+ * tag-param = "tag" EQUAL token
+ * @endcode
+ *
+ *
+ * The parsed From header is stored in #sip_from_t structure.
+ */
+
+/**@ingroup sip_from
+ * @typedef typedef struct sip_addr_s sip_from_t;
+ *
+ * The structure #sip_from_t contains representation of @From header.
+ *
+ * The #sip_from_t is defined as follows:
+ * @code
+ * typedef struct sip_addr_s {
+ * sip_common_t a_common[1]; // Common fragment info
+ * sip_error_t *a_next; // Link to next
+ * char const *a_display; // Display name
+ * url_t a_url[1]; // URL
+ * msg_param_t const *a_params; // List of from-param
+ * char const *a_comment; // Comment
+ * char const *a_tag; // Tag parameter
+ * } sip_from_t;
+ * @endcode
+ *
+ */
+
+msg_hclass_t sip_from_class[] =
+SIP_HEADER_CLASS(from, "From", "f", a_params, single, addr);
+
+issize_t sip_from_d(su_home_t *home,
+ sip_header_t *h,
+ char *s,
+ isize_t slen)
+{
+ return sip_addr_d(home, h, s, slen);
+}
+
+issize_t sip_from_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+ assert(sip_is_from(h));
+ return sip_addr_e(b, bsiz, h, flags);
+}
+
+/**@ingroup sip_from
+ *
+ * Create a @From header object with URL.
+ *
+ * @param home memory home used to allocate #sip_from_t structure
+ * @param s pointer to the URL or a string
+ *
+ * @return
+ * A pointer to newly created @From header object when successful or NULL
+ * upon an error.
+ */
+sip_from_t *
+sip_from_create(su_home_t *home, url_string_t const *s)
+{
+ return sip_addr_make_url(home, sip_from_class, s);
+}
+
+/**@ingroup sip_from
+ *
+ * Add a parameter to an #sip_from_t object.
+ *
+ * @param home memory home
+ * @param from a pointer to #sip_from_t object
+ * @param param parameter string
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error
+ *
+ * @deprecated Use msg_header_replace_param() directly.
+ */
+int sip_from_add_param(su_home_t *home,
+ sip_from_t *from,
+ char const *param)
+{
+ return msg_header_replace_param(home, from->a_common, param);
+}
+
+/**@ingroup sip_from
+ *
+ * Add a tag to a @From header. If @a tag is
+ * identical with the existing one, nothing will be done. An error is
+ * returned, if the header already contains a different tag. The @a tag can
+ * be provided either as a single token ("deadbeer") or as in parameter form
+ * ("tag=deadbeer"). In both cases the tag is duplicated using the memory
+ * home @a home.
+ *
+ * @param home memory home used to allocate new tag
+ * @param from @From header to modify
+ * @param tag tag token or parameter to be added
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error.
+ */
+int sip_from_tag(su_home_t *home, sip_from_t *from, char const *tag)
+{
+ return sip_addr_tag(home, from, tag);
+}
+
+
+int sip_to_tag(su_home_t *home, sip_to_t *to, char const *tag)
+{
+ return sip_addr_tag(home, to, tag);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_max_forwards Max-Forwards Header
+ *
+ * The Max-Forwards header is used to limit the number of proxies or
+ * gateways that can forward the request. The Max-Forwards syntax is
+ * defined in @RFC3261 as follows:
+ *
+ * @code
+ * Max-Forwards = "Max-Forwards" HCOLON 1*DIGIT
+ * @endcode
+ *
+ *
+ * The parsed Max-Forwards header is stored in #sip_max_forwards_t structure.
+ */
+
+/**@ingroup sip_max_forwards
+ * @typedef typedef struct sip_max_forwards_s sip_max_forwards_t;
+ *
+ * The structure #sip_max_forwards_t contains representation of SIP
+ * @MaxForwards header.
+ *
+ * The #sip_max_forwards_t is defined as follows:
+ * @code
+ * typedef struct sip_max_forwards_s {
+ * sip_common_t mf_common[1]; // Common fragment info
+ * sip_error_t *mf_next; // Link to next (dummy)
+ * unsigned long mf_count; // Digits
+ * } sip_max_forwards_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_max_forwards_class[] =
+SIP_HEADER_CLASS(max_forwards, "Max-Forwards", "", mf_common,
+ single, any);
+
+issize_t sip_max_forwards_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ return sip_numeric_d(home, h, s, slen);
+}
+
+issize_t sip_max_forwards_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+ assert(sip_is_max_forwards(h));
+ return sip_numeric_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_min_expires Min-Expires Header
+ *
+ * The Min-Expires header is used to limit the number of proxies or
+ * gateways that can forward the request. The Min-Expires syntax is
+ * defined in @RFC3261 as follows:
+ *
+ * @code
+ * Min-Expires = "Min-Expires" HCOLON delta-seconds
+ * @endcode
+ *
+ * The parsed Min-Expires header is stored in #sip_min_expires_t structure.
+ */
+
+/**@ingroup sip_min_expires
+ * @typedef typedef struct sip_min_expires_s sip_min_expires_t;
+ *
+ * The structure #sip_min_expires_t contains representation of SIP
+ * @MinExpires header.
+ *
+ * The #sip_min_expires_t is defined as follows:
+ * @code
+ * typedef struct sip_min_expires_s {
+ * sip_common_t me_common[1]; // Common fragment info
+ * sip_error_t *me_next; // Link to next (dummy)
+ * unsigned long me_delta; // Seconds
+ * } sip_min_expires_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_min_expires_class[] =
+SIP_HEADER_CLASS(min_expires, "Min-Expires", "", me_common,
+ single, any);
+
+issize_t sip_min_expires_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ return sip_numeric_d(home, h, s, slen);
+}
+
+issize_t sip_min_expires_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+ assert(sip_is_min_expires(h));
+ return sip_numeric_e(b, bsiz, h, f);
+}
+
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_retry_after Retry-After Header
+ *
+ * The Retry-After response-header field @RFC3261 section 20.33 can be used to
+ * indicate how long the service is expected to be unavailable or when the
+ * called party anticipates being available again. Its syntax is defined in
+ * @RFC3261 as follows:
+ *
+ * @code
+ * Retry-After = "Retry-After" HCOLON delta-seconds
+ * [ comment ] *( SEMI retry-param )
+ * retry-param = ("duration" EQUAL delta-seconds)
+ * / generic-param
+ * @endcode
+ *
+ * The parsed Retry-After header is stored in #sip_retry_after_t structure.
+ */
+
+/**@ingroup sip_retry_after
+ * @typedef struct sip_retry_after_s sip_retry_after_t;
+ *
+ * The structure #sip_retry_after_t contains representation of an
+ * @RetryAfter header.
+ *
+ * The #sip_retry_after_t is defined as follows:
+ * @code
+ * typedef struct sip_retry_after_s {
+ * sip_common_t af_common[1]; // Common fragment info
+ * sip_error_t *af_next; // Link to next (dummy)
+ * sip_time_t af_delta; // Seconds to before retry
+ * char const *af_comment; // Comment string
+ * msg_param_t const *af_params; // List of parameters
+ * char const *af_duration; // Duration parameter
+ * } sip_retry_after_t;
+ * @endcode
+ */
+
+static msg_xtra_f sip_retry_after_dup_xtra;
+static msg_dup_f sip_retry_after_dup_one;
+static msg_update_f sip_retry_after_update;
+
+msg_hclass_t sip_retry_after_class[] =
+SIP_HEADER_CLASS(retry_after, "Retry-After", "", af_params, single,
+ retry_after);
+
+issize_t sip_retry_after_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ sip_retry_after_t *af = h->sh_retry_after;
+
+ if ((msg_delta_d((char const **)&s, &af->af_delta) < 0) ||
+ (*s == '(' && msg_comment_d(&s, &af->af_comment) == -1) ||
+ (*s == ';' && msg_params_d(home, &s, &af->af_params) == -1) ||
+ (*s != '\0')) {
+ if (af->af_params)
+ su_free(home, (void *)af->af_params), af->af_params = NULL;
+ return -1;
+ }
+
+ if (af->af_params)
+ msg_header_update_params(h->sh_common, 0);
+
+ return 0;
+}
+
+issize_t sip_retry_after_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+ sip_retry_after_t const *af = h->sh_retry_after;
+ int const compact = MSG_IS_COMPACT(f);
+ char *b0 = b, *end = b + bsiz;
+
+ b += snprintf(b, bsiz, "%lu", af->af_delta);
+
+ if (af->af_comment) {
+ if (!compact)
+ MSG_CHAR_E(b, end, ' ');
+ MSG_CHAR_E(b, end, '(');
+ MSG_STRING_E(b, end, af->af_comment);
+ MSG_CHAR_E(b, end, ')');
+ if (!compact && af->af_params && af->af_params[0])
+ MSG_CHAR_E(b, end, ' ');
+ }
+
+ if (af->af_params)
+ MSG_PARAMS_E(b, end, af->af_params, f);
+
+ MSG_TERM_E(b, end);
+
+ return b - b0;
+}
+
+isize_t sip_retry_after_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+ sip_retry_after_t const *af = h->sh_retry_after;
+
+ MSG_PARAMS_SIZE(offset, af->af_params);
+ offset += MSG_STRING_SIZE(af->af_comment);
+
+ return offset;
+}
+
+char *sip_retry_after_dup_one(sip_header_t *dst,
+ sip_header_t const *src,
+ char *b,
+ isize_t xtra)
+{
+ sip_retry_after_t *af = dst->sh_retry_after;
+ sip_retry_after_t const *o = src->sh_retry_after;
+ char *end = b + xtra;
+
+ b = msg_params_dup(&af->af_params, o->af_params, b, xtra);
+ MSG_STRING_DUP(b, af->af_comment, o->af_comment);
+ af->af_delta = o->af_delta;
+
+ assert(b <= end); (void)end;
+
+ return b;
+}
+
+static int sip_retry_after_update(msg_common_t *h,
+ char const *name, isize_t namelen,
+ char const *value)
+{
+ sip_retry_after_t *af = (sip_retry_after_t *)h;
+
+ if (name == NULL) {
+ af->af_duration = NULL;
+ }
+ else if (namelen == strlen("duration") &&
+ !strncasecmp(name, "duration", namelen)) {
+ af->af_duration = value;
+ }
+
+ return 0;
+}
+
+
+/* ====================================================================== */
+
+/**Parse a @Route or a @RecordRoute header.
+ *
+ * @retval 0 when successful,
+ * @retval -1 upon an error.
+ */
+issize_t sip_any_route_d(su_home_t *home,
+ sip_header_t *h,
+ char *s,
+ isize_t slen)
+{
+ sip_route_t *r = (sip_route_t *)h;
+
+ assert(h);
+
+ while (*s == ',') /* Ignore empty entries (comma-whitespace) */
+ *s = '\0', s += span_lws(s + 1) + 1;
+
+ if (sip_name_addr_d(home, &s, &r->r_display,
+ r->r_url, &r->r_params, NULL) < 0)
+ return -1;
+
+ return msg_parse_next_field(home, h, s, slen);
+}
+
+issize_t sip_any_route_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+ sip_route_t const *r = h->sh_route;
+
+ return sip_name_addr_e(b, bsiz, flags,
+ r->r_display, 1, r->r_url, r->r_params, NULL);
+}
+
+isize_t sip_any_route_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+ sip_route_t const *r = h->sh_route;
+
+ MSG_PARAMS_SIZE(offset, r->r_params);
+ offset += MSG_STRING_SIZE(r->r_display);
+ offset += url_xtra(r->r_url);
+
+ return offset;
+}
+
+char *sip_any_route_dup_one(sip_header_t *dst, sip_header_t const *src,
+ char *b,
+ isize_t xtra)
+{
+ sip_route_t *r = dst->sh_route;
+ sip_route_t const *o = src->sh_route;
+ char *end = b + xtra;
+
+ b = msg_params_dup(&r->r_params, o->r_params, b, xtra);
+ MSG_STRING_DUP(b, r->r_display, o->r_display);
+ URL_DUP(b, end, r->r_url, o->r_url);
+
+ assert(b <= end);
+
+ return b;
+}
+
+#define sip_any_route_update NULL
+
+
+/** Create a route.
+ *
+ * Create a route or record-route entry
+ * from two URLs; first one provides the URL, second maddr parameter and
+ * port.
+ *
+ * @param home memory home
+ * @param rq_url route URL
+ * @param maddr optional route address and port
+ * */
+static
+sip_route_t *sip_any_route_create(su_home_t *home,
+ msg_hclass_t *hc,
+ url_t const *rq_url,
+ url_t const *maddr)
+{
+ sip_header_t *h;
+ sip_route_t *rr;
+ url_t url[1];
+ size_t xtra, n, n_url, n_params, n_addr;
+ char *b, *param;
+
+ *url = *rq_url;
+ if (maddr) {
+ url->url_port = maddr->url_port;
+ url->url_params = NULL;
+ }
+ n_url = url_xtra(url);
+
+ n_params = maddr && maddr->url_params ? strlen(maddr->url_params) : 0;
+
+ if (maddr && (!maddr->url_params ||
+ !url_param(maddr->url_params, "maddr", NULL, 0)))
+ n_addr = (n_params != 0) + strlen("maddr=") + strlen(maddr->url_host);
+ else
+ n_addr = 0;
+
+ xtra = n_url + n_params + n_addr + (n_params || n_addr);
+
+ h = sip_header_alloc(home, hc, xtra);
+ if ((rr = h->sh_record_route)) {
+ b = sip_header_data(h);
+ n = url_dup(b, n_url, rr->r_url, url);
+ assert(n == n_url);
+
+ if (n_params || n_addr) {
+ param = b + n_url;
+ if (n_params) {
+ rr->r_url->url_params = strcpy(param, maddr->url_params);
+ param += n_params;
+ }
+ if (n_addr) {
+ if (n_params)
+ *param++ = ';';
+ strcpy(param, "maddr="), param += strlen("maddr=");
+ strcpy(param, maddr->url_host), param += strlen(maddr->url_host);
+ }
+ assert(b + xtra == param + 1);
+ }
+ }
+
+ return rr;
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_route Route Header
+ *
+ * The Route headers is used to store the route set of a transaction.
+ * The Route header is defined in @RFC3261 as follows:
+ *
+ * @code
+ * Route = "Route" HCOLON route-param *(COMMA route-param)
+ * route-param = name-addr *( SEMI rr-param )
+ * @endcode
+ *
+ * The parsed Route header is stored in #sip_route_t structure.
+ */
+
+/**@ingroup sip_route
+ * @typedef typedef struct sip_route_s sip_route_t;
+ *
+ * The structure #sip_route_t contains representation of SIP @Route header.
+ *
+ * The #sip_route_t is defined as follows:
+ * @code
+ * typedef struct sip_route_s {
+ * sip_common_t r_common[1]; // Common fragment info
+ * sip_route_t *r_next; // Link to next @Route
+ * char const *r_display; // Display name
+ * url_t r_url[1]; // @Route URL
+ * msg_param_t const *r_params; // List of route parameters
+ * } sip_route_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_route_class[] =
+SIP_HEADER_CLASS(route, "Route", "", r_params, append, any_route);
+
+issize_t sip_route_d(su_home_t *home,
+ sip_header_t *h,
+ char *s,
+ isize_t slen)
+{
+ return sip_any_route_d(home, h, s, slen);
+}
+
+issize_t sip_route_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+ assert(sip_is_route(h));
+ return sip_any_route_e(b, bsiz, h, flags);
+}
+
+/**@ingroup sip_route
+ * @brief Create a @Route header object.
+ *
+ * Creates a route entry from two URLs; first one provides the URL, second
+ * maddr parameter and port.
+ *
+ * @param home memory home
+ * @param url route URL
+ * @param maddr optional route address and port
+ *
+ * @return
+ * Returns a pointer to newly created @Route header object when successful,
+ * or NULL upon an error.
+ */
+sip_route_t *sip_route_create(su_home_t *home,
+ url_t const *url,
+ url_t const *maddr)
+{
+ return sip_any_route_create(home, sip_route_class, url, maddr);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_record_route Record-Route Header
+ *
+ * The Record-Route headers are used to establish a route for transactions
+ * belonging to a session. The Record-Route header is defined in @RFC3261
+ * as follows:
+ *
+ * @code
+ * Record-Route = "Record-Route" HCOLON rec-route *(COMMA rec-route)
+ * rec-route = name-addr *( SEMI rr-param )
+ * rr-param = generic-param
+ * @endcode
+ *
+ * The parsed Record-Route header is stored in #sip_record_route_t structure.
+ */
+
+/**@ingroup sip_record_route
+ * @typedef typedef struct sip_record_route_s sip_record_route_t;
+ *
+ * The structure #sip_record_route_t contains representation of SIP
+ * @RecordRoute header.
+ *
+ * The #sip_record_route_t is defined as follows:
+ * @code
+ * typedef struct sip_route_s {
+ * sip_common_t r_common[1]; // Common fragment info
+ * sip_record_route_t *r_next; // Link to next <rec-route>
+ * char const *r_display; // Display name
+ * url_t r_url[1]; // @RecordRoute URL
+ * msg_param_t const *r_params; // List of route parameters
+ * } sip_record_route_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_record_route_class[] =
+SIP_HEADER_CLASS(record_route, "Record-Route", "",
+ r_params, prepend, any_route);
+
+issize_t sip_record_route_d(su_home_t *home,
+ sip_header_t *h,
+ char *s,
+ isize_t slen)
+{
+ return sip_any_route_d(home, h, s, slen);
+}
+
+issize_t sip_record_route_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+ assert(sip_is_record_route(h));
+ return sip_any_route_e(b, bsiz, h, flags);
+}
+
+/** @ingroup sip_record_route
+ *
+ * Create a record-route.
+ *
+ * Create a record-route entry from two URLs; first one provides the URL,
+ * second maddr parameter and port.
+ *
+ * @param home memory home
+ * @param rq_url route URL
+ * @param maddr optional route address and port
+ *
+ * @return
+ * A pointer to newly created @RecordRoute header object when successful or
+ * NULL upon an error.
+ */
+sip_record_route_t *sip_record_route_create(su_home_t *home,
+ url_t const *rq_url,
+ url_t const *maddr)
+{
+ return sip_any_route_create(home, sip_record_route_class, rq_url, maddr);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_to To Header
+ *
+ * The To header field specifies the "logical" recipient of the
+ * request. It is defined in @RFC3261 as follows:
+ *
+ * @code
+ * To = ( "To" / "t" ) HCOLON ( name-addr
+ * / addr-spec ) *( SEMI to-param )
+ * to-param = tag-param / generic-param
+ * @endcode
+ *
+ * The parsed To header is stored in #sip_to_t structure.
+ */
+
+/**@ingroup sip_to
+ * @typedef typedef struct sip_addr_s sip_to_t;
+ *
+ * The structure #sip_to_t contains representation of @To header.
+ *
+ * The #sip_to_t is defined as follows:
+ * @code
+ * typedef struct {
+ * sip_common_t a_common[1]; // Common fragment info
+ * sip_error_t *a_next; // Link to next (dummy)
+ * char const *a_display; // Display name
+ * url_t a_url[1]; // URL
+ * msg_param_t const *a_params; // List of to-params
+ * char const *a_comment; // Comment
+ * char const *a_tag; // Tag parameter
+ * } sip_to_t;
+ * @endcode
+ *
+ */
+
+msg_hclass_t sip_to_class[] =
+SIP_HEADER_CLASS(to, "To", "t", a_params, single, addr);
+
+issize_t sip_to_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ return sip_addr_d(home, h, s, slen);
+}
+
+issize_t sip_to_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+ assert(sip_is_to(h));
+
+ return sip_addr_e(b, bsiz, h, flags);
+}
+
+/**@ingroup sip_to
+ *
+ * Create a @To header object with URL.
+ *
+ * @param home memory home
+ * @param url URL (string or pointer to url_t)
+ *
+ * @return
+ * A pointer to newly created @To header object when successful or NULL upon
+ * an error.
+ */
+sip_to_t *
+sip_to_create(su_home_t *home, url_string_t const *url)
+{
+ return sip_addr_make_url(home, sip_to_class, url);
+}
+
+/**@ingroup sip_to
+ *
+ * Add a parameter to a #sip_to_t object.
+ *
+ * @note This function @b does @b not duplicate @p param.
+ *
+ * @param home memory home
+ * @param to #sip_to_t structure
+ * @param param parameter string
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error
+ *
+ * @deprecated Use msg_header_replace_param() directly.
+ */
+int sip_to_add_param(su_home_t *home,
+ sip_to_t *to,
+ char const *param)
+{
+ return msg_header_replace_param(home, to->a_common, param);
+}
+
+/* ====================================================================== */
+/**@SIP_HEADER sip_via Via Header
+ *
+ * The Via header indicates the path taken by the request so far. Via
+ * headers can be used to prevent request looping and ensure replies take
+ * the same path as the requests. The Via syntax is defined in @RFC3261
+ * as follows:
+ *
+ * @code
+ * Via = ( "Via" / "v" ) HCOLON via-parm *(COMMA via-parm)
+ * via-parm = sent-protocol LWS sent-by *( SEMI via-params )
+ * via-params = via-ttl / via-maddr
+ * / via-received / via-branch
+ * / via-extension
+ * via-ttl = "ttl" EQUAL ttl
+ * via-maddr = "maddr" EQUAL host
+ * via-received = "received" EQUAL (IPv4address / IPv6address)
+ * via-branch = "branch" EQUAL token
+ * via-extension = generic-param
+ * sent-protocol = protocol-name SLASH protocol-version
+ * SLASH transport
+ * protocol-name = "SIP" / token
+ * protocol-version = token
+ * transport = "UDP" / "TCP" / "TLS" / "SCTP"
+ * / other-transport
+ * sent-by = host [ COLON port ]
+ * ttl = 1*3DIGIT ; 0 to 255
+ * @endcode
+ *
+ * @note
+ * The @RFC2543 syntax allowed <comment>. We accept it, but don't encode it.
+ *
+ * In addition to the parameters defined in @RFC3261, @RFC3486 defines a
+ * parameter "comp":
+ * @code
+ * via-compression = "comp" EQUAL ("sigcomp" / other-compression)
+ * via-params /= via-compression
+ * @endcode
+ *
+ * @RFC3581 defines a parameter "rport":
+ * @code
+ * response-port = "rport" [EQUAL 1*DIGIT]
+ * via-params /= response-port
+ * @endcode
+ *
+ * The parsed Via header is stored in #sip_via_t structure.
+ */
+
+/**@ingroup sip_via
+ * @typedef typedef struct sip_via_s sip_via_t;
+ *
+ * The structure #sip_via_t contains representation of SIP @Via header.
+ *
+ * The #sip_via_t is defined as follows:
+ * @code
+ * typedef struct sip_via_s {
+ * sip_common_t v_common[1]; // Common fragment info
+ * sip_via_t *v_next; // Link to next @Via header
+ * char const *v_protocol; // Application and transport protocol
+ * char const *v_host; // Hostname
+ * char const *v_port; // Port number
+ * msg_param_t const *v_params; // List of via-params
+ * char const *v_comment; // Comment
+ *
+ * char const *v_ttl; // "ttl" parameter
+ * char const *v_maddr; // "maddr" parameter
+ * char const *v_received; // "received" parameter
+ * char const *v_branch; // "branch" parameter
+ * char const *v_comp; // "comp" parameter
+ * char const *v_rport; // "rport" parameter
+ * } sip_via_t;
+ * @endcode
+ */
+
+static msg_xtra_f sip_via_dup_xtra;
+static msg_dup_f sip_via_dup_one;
+static msg_update_f sip_via_update;
+
+msg_hclass_t sip_via_class[] =
+SIP_HEADER_CLASS(via, "Via", "v", v_params, prepend, via);
+
+issize_t sip_via_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ sip_via_t *v = (sip_via_t *)h;
+
+ assert(h);
+
+ while (*s == ',') /* Ignore empty entries (comma-whitespace) */
+ *s = '\0', s += span_lws(s + 1) + 1;
+
+ /* sent-protocol sent-by *( ";" via-params ) [ comment ] */
+
+ /* Parse protocol */
+ if (sip_transport_d(&s, &v->v_protocol) == -1)
+ return -1;
+ /* Host (and port) */
+ if (msg_hostport_d(&s, &v->v_host, &v->v_port) == -1)
+ return -1;
+ /* Parameters */
+ if (*s == ';' && msg_params_d(home, &s, &v->v_params) == -1)
+ return -1;
+ /* Comment */
+ if (*s == '(' && msg_comment_d(&s, &v->v_comment) == -1)
+ return -1;
+
+ return msg_parse_next_field(home, h, s, slen);
+}
+
+issize_t sip_via_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+ char *b0 = b, *end = b + bsiz;
+ sip_via_t const *v = h->sh_via;
+
+ assert(sip_is_via(h));
+
+ MSG_STRING_E(b, end, v->v_protocol);
+ MSG_CHAR_E(b, end, ' ');
+ MSG_STRING_E(b, end, v->v_host);
+ if (v->v_port) {
+ MSG_CHAR_E(b, end, ':');
+ MSG_STRING_E(b, end, v->v_port);
+ }
+ MSG_PARAMS_E(b, end, v->v_params, flags);
+#if 0
+ /* Comment is deprecated in @RFC3265 - accept it, but do not send */
+ if (v->v_comment) {
+ if (!MSG_IS_COMPACT(flags))
+ MSG_CHAR_E(b, end, ' ');
+ MSG_CHAR_E(b, end, '(');
+ MSG_STRING_E(b, end, v->v_comment);
+ MSG_CHAR_E(b, end, ')');
+ }
+#endif
+ MSG_TERM_E(b, end);
+
+ return b - b0;
+}
+
+isize_t sip_via_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+ sip_via_t const *v = h->sh_via;
+
+ MSG_PARAMS_SIZE(offset, v->v_params);
+ offset += sip_transport_xtra(v->v_protocol);
+ offset += MSG_STRING_SIZE(v->v_host);
+ offset += MSG_STRING_SIZE(v->v_port);
+ offset += MSG_STRING_SIZE(v->v_comment);
+
+ return offset;
+}
+
+/** Duplicate one #sip_via_t object */
+char *sip_via_dup_one(sip_header_t *dst, sip_header_t const *src,
+ char *b, isize_t xtra)
+{
+ sip_via_t *v = dst->sh_via;
+ sip_via_t const *o = src->sh_via;
+ char *end = b + xtra;
+
+ b = msg_params_dup(&v->v_params, o->v_params, b, xtra);
+ sip_transport_dup(&b, &v->v_protocol, o->v_protocol);
+ MSG_STRING_DUP(b, v->v_host, o->v_host);
+ MSG_STRING_DUP(b, v->v_port, o->v_port);
+ MSG_STRING_DUP(b, v->v_comment, o->v_comment);
+
+ assert(b <= end); (void)end;
+
+ return b;
+}
+
+static int sip_via_update(msg_common_t *h,
+ char const *name, isize_t namelen,
+ char const *value)
+{
+ sip_via_t *v = (sip_via_t *)h;
+
+ if (name == NULL) {
+ v->v_ttl = NULL;
+ v->v_maddr = NULL;
+ v->v_received = NULL;
+ v->v_branch = NULL;
+ v->v_rport = NULL;
+ v->v_comp = NULL;
+ }
+#define MATCH(s) (namelen == strlen(#s) && !strncasecmp(name, #s, strlen(#s)))
+
+ else if (MATCH(ttl)) {
+ v->v_ttl = value;
+ }
+ else if (MATCH(maddr)) {
+ v->v_maddr = value;
+ }
+ else if (MATCH(received)) {
+ v->v_received = value;
+ }
+ else if (MATCH(branch)) {
+ v->v_branch = value;
+ }
+ else if (MATCH(rport)) {
+ v->v_rport = value;
+ }
+ else if (MATCH(comp)) {
+ v->v_comp = value;
+ }
+
+ #undef MATCH
+
+ return 0;
+ }
+
+/**@ingroup sip_via
+ *
+ * Add a parameter to a @Via object.
+ *
+ * @note This function @b does @b not duplicate @p param.
+ *
+ * @param home memory home
+ * @param v #sip_via_t object
+ * @param param parameter string
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error.
+ *
+ * @deprecated Use msg_header_replace_param() directly.
+ */
+int sip_via_add_param(su_home_t *home,
+ sip_via_t *v,
+ char const *param)
+{
+ return msg_header_replace_param(home, v->v_common, param);
+}
+
+/**@ingroup sip_via
+ *
+ * Create a @Via object.
+ *
+ * Create a new @Via header object with
+ * given parameters. If @a transport is NULL, the default transport
+ * "SIP/2.0/UDP" is used. A NULL-terminated list of parameters can be
+ * specified after transport.
+ *
+ * @param home memory home
+ * @param host host name
+ * @param port protocol port number
+ * @param transport transport protocol (default is "SIP/2.0/UDP")
+ * @param ... NULL-terminated list of parameters
+ *
+ * @return
+ * A pointer to newly created
+ * @Via header object when successful or NULL upon an error.
+ */
+sip_via_t *sip_via_create(su_home_t *home,
+ char const *host,
+ char const *port,
+ char const *transport,
+ /* char const *params */
+ ...)
+{
+ sip_via_t *v, via[1] = {{{{ NULL }}}};
+ va_list params;
+
+ via->v_common->h_class = sip_via_class;
+
+ if (transport)
+ via->v_protocol = transport;
+ else
+ via->v_protocol = sip_transport_udp;
+
+ via->v_host = host;
+ via->v_port = port;
+
+ v = msg_header_dup_as(home, sip_via_class, (sip_header_t *)via)->sh_via;
+
+ if (v) {
+ char const *param;
+ va_start(params, transport);
+
+ for (param = va_arg(params, char const *);
+ param;
+ param = va_arg(params, char const *)) {
+ if ((param = su_strdup(home, param))) {
+ if (msg_header_replace_param(home, v->v_common, param) < 0)
+ break;
+ }
+ }
+
+ va_end(params);
+ }
+
+ return v;
+}
+
+/**@ingroup sip_via
+ *
+ * Get port number corresponding to a @Via line.
+ *
+ * If @a using_rport is non-null, try rport.
+ * If *using_rport is non-zero, try rport even if <protocol> is not UDP.
+ * If <protocol> is UDP, set *using_rport to zero.
+ */
+char const *sip_via_port(sip_via_t const *v, int *using_rport)
+{
+ if (v == NULL)
+ return NULL;
+
+ if (using_rport) {
+ char const *port;
+
+ if (v->v_rport && !v->v_maddr /* multicast */) {
+ if (v->v_protocol == sip_transport_udp ||
+ strcasecmp(v->v_protocol, sip_transport_udp) == 0)
+ port = v->v_rport, *using_rport = 0;
+ else if (*using_rport)
+ port = v->v_rport;
+ else
+ port = NULL;
+
+ if (port && port[0])
+ return port;
+ }
+
+ *using_rport = 0; /* No, we don't... */
+ }
+
+ if (v->v_port)
+ return v->v_port;
+
+ if (sip_transport_has_tls(v->v_protocol))
+ return SIPS_DEFAULT_SERV; /* 5061 */
+ else
+ return SIP_DEFAULT_SERV; /* 5060 */
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_caller_prefs.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_caller_prefs.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,427 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE sip_caller_prefs.c
+ * @brief SIP headers related to Caller Preferences
+ *
+ * Implementation of header classes for Caller-Preferences-related SIP
+ * headers @AcceptContact, @RejectContact, and @RequestDisposition.
+ *
+ * @author Remeres Jacobs <remeres.jacobs at nokia.com>
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Th 23.01.2003
+ */
+
+#include "config.h"
+
+/* Avoid casting sip_t to msg_pub_t and sip_header_t to msg_header_t */
+#define MSG_PUB_T struct sip_s
+#define MSG_HDR_T union sip_header_u
+
+#include "sofia-sip/sip_parser.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_request_disposition Request-Disposition Header
+ *
+ * The Request-Disposition header syntax is defined in
+ * @RFC3841 section 10 as follows:
+ *
+ * @code
+ * Request-Disposition = ( "Request-Disposition" | "d" ) HCOLON
+ * directive *(COMMA directive)
+ * directive = proxy-directive / cancel-directive /
+ * fork-directive / recurse-directive /
+ * parallel-directive / queue-directive)
+ * proxy-directive = "proxy" / "redirect"
+ * cancel-directive = "cancel" / "no-cancel"
+ * fork-directive = "fork" / "no-fork"
+ * recurse-directive = "recurse" / "no-recurse"
+ * parallel-directive = "parallel" / "sequential"
+ * queue-directive = "queue" / "no-queue"
+ * @endcode
+ *
+ *
+ * The parsed Request-Disposition header
+ * is stored in #sip_request_disposition_t structure.
+ */
+
+/**@ingroup sip_request_disposition
+ * @typedef typedef struct sip_request_disposition_s sip_request_disposition_t;
+ *
+ * The structure #sip_request_disposition_t contains representation of
+ * @RequestDisposition header.
+ *
+ * The #sip_request_disposition_t is defined as follows:
+ * @code
+ * typedef struct sip_request_disposition_s
+ * {
+ * sip_common_t rd_common[1]; // Common fragment info
+ * sip_unknown_t *rd_next; // Link to next (dummy)
+ * msg_param_t *rd_items; // List of directives
+ * } sip_request_disposition_t;
+ * @endcode
+ */
+
+static msg_xtra_f sip_request_disposition_dup_xtra;
+static msg_dup_f sip_request_disposition_dup_one;
+#define sip_request_disposition_update NULL
+
+msg_hclass_t sip_request_disposition_class[] =
+SIP_HEADER_CLASS(request_disposition, "Request-Disposition", "d", rd_items,
+ list, request_disposition);
+
+issize_t sip_request_disposition_d(su_home_t *home, sip_header_t *h,
+ char *s, isize_t slen)
+{
+ sip_request_disposition_t *rd = h->sh_request_disposition;
+
+ return msg_commalist_d(home, &s, &rd->rd_items, msg_token_scan);
+}
+
+
+issize_t sip_request_disposition_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+ char *end = b + bsiz, *b0 = b;
+ sip_request_disposition_t const *o = h->sh_request_disposition;
+
+ assert(sip_is_request_disposition(h));
+
+ MSG_COMMALIST_E(b, end, o->rd_items, flags);
+
+ return b - b0;
+}
+
+
+isize_t sip_request_disposition_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+ sip_request_disposition_t const *o = h->sh_request_disposition;
+
+ MSG_PARAMS_SIZE(offset, o->rd_items);
+
+ return offset;
+}
+
+
+/** Duplicate one #sip_request_disposition_t object */
+char *sip_request_disposition_dup_one(sip_header_t *dst,
+ sip_header_t const *src,
+ char *b, isize_t xtra)
+{
+ char *end = b + xtra;
+ sip_request_disposition_t *o_dst = dst->sh_request_disposition;
+ sip_request_disposition_t const *o_src = src->sh_request_disposition;
+ msg_param_t const **dst_items = (msg_param_t const **)&o_dst->rd_items;
+
+ b = msg_params_dup(dst_items, o_src->rd_items, b, xtra);
+
+ assert(b <= end); (void)end;
+
+ return b;
+}
+
+/* ====================================================================== */
+
+/**@ingroup sip_caller_prefs
+ *
+ * Add a parameter to a @AcceptContact or @RejectContact header object.
+ *
+ * @note This function does not duplicate @p param.
+ *
+ * @param home memory home
+ * @param cp pointer to #sip_accept_contact_t or #sip_reject_contact_t
+ * @param param parameter string
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error
+ *
+ * @deprecated Use msg_header_replace_param() instead.
+ */
+int sip_caller_prefs_add_param(su_home_t *home,
+ sip_caller_prefs_t *cp,
+ char const *param)
+{
+ return msg_header_replace_param(home, cp->cp_common, param);
+}
+
+static
+size_t span_attribute_value(char *s)
+{
+ size_t n;
+
+ n = span_token_lws(s);
+ if (n > 0 && s[n] == '=') {
+ n += 1 + span_lws(s + n + 1);
+ if (s[n] == '"')
+ n += span_quoted(s + n);
+ else
+ n += span_token(s + n);
+ n += span_lws(s + n);
+ }
+
+ return n;
+}
+
+static
+issize_t sip_caller_prefs_d(su_home_t *home, sip_header_t *h,
+ char *s, isize_t slen)
+{
+ sip_caller_prefs_t *cp = (sip_caller_prefs_t *)h;
+ url_t url[1];
+ char const *ignore = NULL;
+ int kludge = 0;
+
+ assert(h);
+
+ while (*s == ',') /* Ignore empty entries (comma-whitespace) */
+ *s = '\0', s += span_lws(s + 1) + 1;
+
+ /* Kludge: support PoC IS spec with a typo... */
+ if (strncasecmp(s, "*,", 2) == 0)
+ s[1] = ';', kludge = 0;
+ else if (s[0] != '*' && s[0] != '<') {
+ /* Kludge: missing URL - */
+ size_t n = span_attribute_value(s);
+ kludge = n > 0 && (s[n] == '\0' || s[n] == ',' || s[n] == ';');
+ }
+
+ if (kludge) {
+ if (msg_any_list_d(home, &s, (msg_param_t **)&cp->cp_params,
+ msg_attribute_value_scanner, ';') == -1)
+ return -1;
+ }
+ /* Parse params (and ignore display name and url) */
+ else if (sip_name_addr_d(home, &s, &ignore, url, &cp->cp_params, NULL)
+ == -1)
+ return -1;
+ /* Be liberal... */
+ /* if (url->url_type != url_any)
+ return -1; */
+
+ return msg_parse_next_field(home, h, s, slen);
+}
+
+static
+issize_t sip_caller_prefs_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+ sip_caller_prefs_t const *cp = h->sh_caller_prefs;
+ char *b0 = b, *end = b + bsiz;
+
+ MSG_CHAR_E(b, end, '*');
+ MSG_PARAMS_E(b, end, cp->cp_params, flags);
+ MSG_TERM_E(b, end);
+
+ return b - b0;
+}
+
+
+static
+isize_t sip_caller_prefs_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+ sip_caller_prefs_t const *cp = h->sh_caller_prefs;
+
+ MSG_PARAMS_SIZE(offset, cp->cp_params);
+
+ return offset;
+}
+
+static
+char *sip_caller_prefs_dup_one(sip_header_t *dst, sip_header_t const *src,
+ char *b, isize_t xtra)
+{
+ char *end = b + xtra;
+ sip_caller_prefs_t *cp = dst->sh_caller_prefs;
+ sip_caller_prefs_t const *o = src->sh_caller_prefs;
+
+ b = msg_params_dup(&cp->cp_params, o->cp_params, b, xtra);
+
+ assert(b <= end); (void)end;
+
+ return b;
+}
+
+/**@SIP_HEADER sip_accept_contact Accept-Contact Header
+ *
+ * The Accept-Contact syntax is defined in @RFC3841 section 10 as follows:
+ *
+ * @code
+ * Accept-Contact = ("Accept-Contact" / "a") HCOLON ac-value
+ * *(COMMA ac-value)
+ * ac-value = "*" *(SEMI ac-params)
+ * ac-params = feature-param / req-param
+ * / explicit-param / generic-param
+ * ;;feature param from RFC 3840
+ * ;;generic-param from RFC 3261
+ * req-param = "require"
+ * explicit-param = "explicit"
+ * @endcode
+ *
+ * Despite the BNF, there MUST NOT be more than one req-param or
+ * explicit-param in an ac-params. Furthermore, there can only be one
+ * instance of any feature tag in feature-param.
+ *
+ * @sa @RFC3840, @RFC3841, sip_contact_accept(), sip_contact_score().
+ *
+ * The parsed Accept-Contact header
+ * is stored in #sip_accept_contact_t structure.
+ */
+
+/**@ingroup sip_accept_contact
+ * @typedef struct sip_caller_prefs_s sip_accept_contact_t;
+ *
+ * The structure #sip_accept_contact_t contains representation of SIP
+ * @AcceptContact header.
+ *
+ * The #sip_accept_contact_t is defined as follows:
+ * @code
+ * typedef struct caller_prefs_s {
+ * sip_common_t cp_common[1]; // Common fragment info
+ * sip_caller_prefs_t *cp_next; // Link to next ac-value
+ * msg_param_t const *cp_params; // List of parameters
+ * char const *cp_q; // Priority
+ * unsigned cp_require :1; // Shortcut to "require" parameter
+ * unsigned cp_explicit :1; // Shortcut to "explicit" parameter
+ * } sip_accept_contact_t;
+ * @endcode
+ */
+
+#define sip_accept_contact_dup_xtra sip_caller_prefs_dup_xtra
+#define sip_accept_contact_dup_one sip_caller_prefs_dup_one
+
+static int sip_accept_contact_update(msg_common_t *h,
+ char const *name, isize_t namelen,
+ char const *value);
+
+msg_hclass_t sip_accept_contact_class[] =
+SIP_HEADER_CLASS(accept_contact, "Accept-Contact", "a", cp_params, append,
+ accept_contact);
+
+issize_t sip_accept_contact_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ return sip_caller_prefs_d(home, h, s, slen);
+}
+
+
+issize_t sip_accept_contact_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+ return sip_caller_prefs_e(b, bsiz, h, flags);
+}
+
+static int sip_accept_contact_update(msg_common_t *h,
+ char const *name, isize_t namelen,
+ char const *value)
+{
+ sip_caller_prefs_t *cp = (sip_caller_prefs_t *)h;
+
+ if (name == NULL) {
+ cp->cp_q = NULL;
+ cp->cp_require = 0;
+ cp->cp_explicit = 0;
+ }
+#define MATCH(s) (namelen == strlen(#s) && !strncasecmp(name, #s, strlen(#s)))
+
+#if nomore
+ else if (MATCH(q)) {
+ cp->cp_q = value;
+ }
+#endif
+ else if (MATCH(require)) {
+ cp->cp_require = value != NULL;
+ }
+ else if (MATCH(explicit)) {
+ cp->cp_explicit = value != NULL;
+ }
+
+#undef MATCH
+
+ return 0;
+}
+
+
+/**@SIP_HEADER sip_reject_contact Reject-Contact Header
+ *
+ * The Reject-Contact syntax is defined in @RFC3841 section 10 as follows:
+ *
+ * @code
+ * Reject-Contact = ("Reject-Contact" / "j") HCOLON rc-value
+ * *(COMMA rc-value)
+ * rc-value = "*" *(SEMI rc-params)
+ * rc-params = feature-param / generic-param
+ * ;;feature param from RFC 3840
+ * ;;generic-param from RFC 3261
+ * @endcode
+ *
+ * Despite the BNF, there MUST NOT be more than one instance of any feature
+ * tag in feature-param.
+ *
+ * @sa @RFC3840, @RFC3841, sip_contact_reject(), sip_contact_score().
+ *
+ * The parsed Reject-Contact header
+ * is stored in #sip_reject_contact_t structure.
+ */
+
+/**@ingroup sip_reject_contact
+ * @typedef struct sip_caller_prefs_s sip_reject_contact_t;
+ *
+ * The structure #sip_reject_contact_t contains representation of SIP
+ * @RejectContact header.
+ *
+ * The #sip_reject_contact_t is defined as follows:
+ * @code
+ * typedef struct caller_prefs_s {
+ * sip_common_t cp_common[1]; // Common fragment info
+ * sip_caller_prefs_t *cp_next; // Link to next rc-value
+ * msg_param_t const *cp_params; // List of parameters
+ * } sip_reject_contact_t;
+ * @endcode
+ *
+ * @note Fields @c cp_q, @c cp_require and @c cp_explicit are ignored for
+ * @RejectContact header.
+ */
+
+#define sip_reject_contact_dup_xtra sip_caller_prefs_dup_xtra
+#define sip_reject_contact_dup_one sip_caller_prefs_dup_one
+#define sip_reject_contact_update NULL
+
+msg_hclass_t sip_reject_contact_class[] =
+SIP_HEADER_CLASS(reject_contact, "Reject-Contact", "j", cp_params, append,
+ reject_contact);
+
+issize_t sip_reject_contact_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ return sip_caller_prefs_d(home, h, s, slen);
+}
+
+
+issize_t sip_reject_contact_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+ return sip_caller_prefs_e(b, bsiz, h, flags);
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_event.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_event.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,548 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE sip_event.c
+ * @brief Event SIP headers.
+ *
+ * Implementation of header classes for event-related SIP headers @Event,
+ * @AllowEvents, and @SubscriptionState.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Thu Sep 13 21:24:15 EEST 2001 ppessi
+ */
+
+#include "config.h"
+
+/* Avoid casting sip_t to msg_pub_t and sip_header_t to msg_header_t */
+#define MSG_PUB_T struct sip_s
+#define MSG_HDR_T union sip_header_u
+
+#include "sofia-sip/sip_parser.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_event Event Header
+ *
+ * The Event header is used to indicate the which event or class of events
+ * the message contains or subscribes. Its syntax is defined in @RFC3265 as
+ * follows:
+ *
+ * @code
+ * Event = ( "Event" / "o" ) HCOLON event-type
+ * *( SEMI event-param )
+ * event-type = event-package *( "." event-template )
+ * event-package = token-nodot
+ * event-template = token-nodot
+ * token-nodot = 1*( alphanum / "-" / "!" / "%" / "*"
+ * / "_" / "+" / "`" / "'" / "~" )
+ * event-param = generic-param / ( "id" EQUAL token )
+ * @endcode
+ *
+ * The parsed Event header is stored in #sip_event_t structure.
+ */
+
+/**@ingroup sip_event
+ * @typedef struct sip_event_s sip_event_t;
+ *
+ * The structure #sip_event_t contains representation of an @Event header.
+ *
+ * The #sip_event_t is defined as follows:
+ * @code
+ * typedef struct sip_event_s
+ * {
+ * sip_common_t o_common; // Common fragment info
+ * sip_error_t *o_next; // Link to next (dummy)
+ * char const * o_type; // Event type
+ * msg_param_t const *o_params; // List of parameters
+ * char const *o_id; // Event ID
+ * } sip_event_t;
+ * @endcode
+ */
+
+static msg_xtra_f sip_event_dup_xtra;
+static msg_dup_f sip_event_dup_one;
+static msg_update_f sip_event_update;
+
+msg_hclass_t sip_event_class[] =
+SIP_HEADER_CLASS(event, "Event", "o", o_params, single, event);
+
+issize_t sip_event_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ sip_event_t *o = h->sh_event;
+ size_t n;
+
+ n = span_token(s); if (n == 0) return -1;
+ o->o_type = s; s += n;
+ while (IS_LWS(*s)) { *s++ = '\0'; }
+ if (*s == ';') {
+ if (msg_params_d(home, &s, &o->o_params) < 0 || *s)
+ return -1;
+ msg_header_update_params(o->o_common, 0);
+ }
+ return 0;
+}
+
+issize_t sip_event_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+ char *end = b + bsiz, *b0 = b;
+ sip_event_t const *o = h->sh_event;
+
+ assert(sip_is_event(h));
+ MSG_STRING_E(b, end, o->o_type);
+ MSG_PARAMS_E(b, end, o->o_params, flags);
+
+ return b - b0;
+}
+
+isize_t sip_event_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+ sip_event_t const *o = h->sh_event;
+
+ MSG_PARAMS_SIZE(offset, o->o_params);
+ offset += MSG_STRING_SIZE(o->o_type);
+
+ return offset;
+}
+
+/** Duplicate one #sip_event_t object */
+char *sip_event_dup_one(sip_header_t *dst, sip_header_t const *src,
+ char *b, isize_t xtra)
+{
+ sip_event_t *o_dst = dst->sh_event;
+ sip_event_t const *o_src = src->sh_event;
+
+ char *end = b + xtra;
+ b = msg_params_dup(&o_dst->o_params, o_src->o_params, b, xtra);
+ MSG_STRING_DUP(b, o_dst->o_type, o_src->o_type);
+ assert(b <= end); (void)end;
+
+ return b;
+}
+
+/** Update parameters in @Event header. */
+static int sip_event_update(msg_common_t *h,
+ char const *name, isize_t namelen,
+ char const *value)
+{
+ sip_event_t *o = (sip_event_t *)h;
+
+ if (name == NULL) {
+ o->o_id = NULL;
+ }
+ else if (namelen == strlen("id") && !strncasecmp(name, "id", namelen)) {
+ o->o_id = value;
+ }
+
+ return 0;
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_allow_events Allow-Events Header
+ *
+ * The Allow-Events header is used to indicate which events or classes of
+ * events the notifier supports. Its syntax is defined in @RFC3265 as
+ * follows:
+ *
+ * @code
+ * Allow-Events = ( "Allow-Events" / "u" ) HCOLON event-type
+ * *(COMMA event-type)
+ * @endcode
+ *
+ * The parsed Allow-Events header is stored in #sip_allow_events_t structure.
+ *
+ * Note that the event name is case-sensitive. The event "Presence" is
+ * different from "presence". However, it is very unwise to use such event
+ * names.
+ *
+ * @sa @Event, @RFC3265, msg_header_find_item(), msg_header_replace_item(),
+ * msg_header_remove_item()
+ */
+
+/**@ingroup sip_allow_events
+ * @typedef struct msg_list_s sip_allow_events_t;
+ *
+ * The structure #sip_allow_events_t contains representation of an
+ * @AllowEvents header.
+ *
+ * The #sip_allow_events_t is defined as follows:
+ * @code
+ * typedef 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
+ * } sip_allow_events_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_allow_events_class[] =
+SIP_HEADER_CLASS_LIST(allow_events, "Allow-Events", "u", list);
+
+issize_t sip_allow_events_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ return msg_list_d(home, h, s, slen);
+}
+
+issize_t sip_allow_events_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+ assert(sip_is_allow_events(h));
+ return msg_list_e(b, bsiz, h, f);
+}
+
+/** Append an event to a @AllowEvents header.
+ *
+ * @note This function @b does @b duplicate @p event.
+ *
+ * @deprecated Use msg_header_replace_item() directly.
+ */
+int sip_allow_events_add(su_home_t *home,
+ sip_allow_events_t *ae,
+ char const *event)
+{
+ event = su_strdup(home, event);
+ if (!event)
+ return -1;
+ return msg_header_replace_item(home, ae->k_common, event);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_subscription_state Subscription-State Header
+ *
+ * The Subscription-State header is used to indicate in which state a
+ * subscription is. Its syntax is defined in @RFC3265 section 4.2.4 as
+ * follows:
+ *
+ * @code
+ * Subscription-State = "Subscription-State" HCOLON substate-value
+ * *( SEMI subexp-params )
+ * substate-value = "active" / "pending" / "terminated"
+ * / extension-substate
+ * extension-substate = token
+ * subexp-params = ("reason" EQUAL event-reason-value)
+ * / ("expires" EQUAL delta-seconds)
+ * / ("retry-after" EQUAL delta-seconds)
+ * / generic-param
+ * event-reason-value = "deactivated"
+ * / "probation"
+ * / "rejected"
+ * / "timeout"
+ * / "giveup"
+ * / "noresource"
+ * / event-reason-extension
+ * event-reason-extension = token
+ * @endcode
+ *
+ * The parsed Subscription-State header
+ * is stored in #sip_subscription_state_t structure.
+ */
+
+/**@ingroup sip_subscription_state
+ * @typedef struct sip_subscription_state_s sip_subscription_state_t;
+ *
+ * The structure #sip_subscription_state_t contains representation of an
+ * @SubscriptionState header.
+ *
+ * The #sip_subscription_state_t is defined as follows:
+ * @code
+ * typedef struct sip_subscription_state_s
+ * {
+ * sip_common_t ss_common[1];
+ * sip_unknown_t *ss_next;
+ * // Subscription state: "pending", "active" or "terminated"
+ * char const *ss_substate;
+ * msg_param_t const *ss_params; // List of parameters
+ * char const *ss_reason; // Reason of terminating
+ * char const *ss_expires; // Subscription lifetime in seconds
+ * char const *ss_retry_after; // Value of retry-after parameter
+ * } sip_subscription_state_t;
+ * @endcode
+ */
+
+static msg_xtra_f sip_subscription_state_dup_xtra;
+static msg_dup_f sip_subscription_state_dup_one;
+static msg_update_f sip_subscription_state_update;
+
+msg_hclass_t sip_subscription_state_class[] =
+SIP_HEADER_CLASS(subscription_state, "Subscription-State", "",
+ ss_params, single,
+ subscription_state);
+
+issize_t sip_subscription_state_d(su_home_t *home, sip_header_t *h,
+ char *s, isize_t slen)
+{
+ sip_subscription_state_t *ss = h->sh_subscription_state;
+ ss->ss_substate = s;
+
+ s += span_token(s); /* forwards the pointer to the end of substate-value */
+ if (s == ss->ss_substate)
+ return -1;
+ if (IS_LWS(*s)) {
+ *s = '\0'; s += span_lws(s + 1) + 1;
+ }
+
+ /* check if parameters are present and if so parse them */
+ if (*s == ';') {
+ if ( msg_params_d(home, &s, &ss->ss_params) < 0)
+ return -1;
+ if (msg_header_update_params(ss->ss_common, 0) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+issize_t sip_subscription_state_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+ char *end = b + bsiz, *b0 = b;
+ sip_subscription_state_t const *ss = h->sh_subscription_state;
+
+ assert(sip_is_subscription_state(h));
+
+ MSG_STRING_E(b, end, ss->ss_substate);
+ MSG_PARAMS_E(b, end, ss->ss_params, flags);
+
+ return b - b0;
+}
+
+isize_t sip_subscription_state_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+ sip_subscription_state_t const *ss = h->sh_subscription_state;
+
+ /* Calculates memory size occupied */
+ MSG_PARAMS_SIZE(offset, ss->ss_params);
+ offset += MSG_STRING_SIZE(ss->ss_substate);
+
+ return offset;
+}
+
+/** Duplicate one #sip_subscription_state_t object */
+char *sip_subscription_state_dup_one(sip_header_t *dst, sip_header_t const *src,
+ char *b, isize_t xtra)
+{
+ sip_subscription_state_t *ss_dst = dst->sh_subscription_state;
+ sip_subscription_state_t const *ss_src = src->sh_subscription_state;
+ char *end = b + xtra;
+
+ b = msg_params_dup(&ss_dst->ss_params, ss_src->ss_params, b, xtra);
+ MSG_STRING_DUP(b, ss_dst->ss_substate, ss_src->ss_substate);
+ assert(b <= end); (void)end;
+
+ return b;
+}
+
+static int sip_subscription_state_update(msg_common_t *h,
+ char const *name, isize_t namelen,
+ char const *value)
+{
+ sip_subscription_state_t *ss = (sip_subscription_state_t *)h;
+
+ if (name == NULL) {
+ ss->ss_reason = NULL;
+ ss->ss_retry_after = NULL;
+ ss->ss_expires = NULL;
+ }
+#define MATCH(s) (namelen == strlen(#s) && !strncasecmp(name, #s, strlen(#s)))
+
+ else if (MATCH(reason)) {
+ ss->ss_reason = value;
+ }
+ else if (MATCH(retry-after)) {
+ ss->ss_retry_after = value;
+ }
+ else if (MATCH(expires)) {
+ ss->ss_expires = value;
+ }
+
+#undef MATCH
+
+ return 0;
+}
+
+#if 0 /* More dead headers */
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_publication Publication Header
+ *
+ * The Publication header is used to indicate the which publication or class
+ * of publications the message contains. Its syntax is defined
+ * in (draft-niemi-simple-publish-00.txt) as follows:
+ *
+ * @code
+ * Publication = ( "Publication") HCOLON publish-package
+ * *( SEMI publish-param )
+ * publish-package = token-nodot
+ * token-nodot = 1*( alphanum / "-" / "!" / "%" / "*"
+ * / "_" / "+" / "`" / "'" / "~" )
+ * publish-param = generic-param / pstream / ptype
+ * pstream = "stream" EQUAL token
+ * ptype = "type" EQUAL token
+ * @endcode
+ *
+ *
+ * The parsed Publication header is stored in #sip_publication_t structure.
+ */
+
+/**@ingroup sip_publication
+ * @brief Structure for Publication header.
+ */
+struct sip_publication_s
+{
+ sip_common_t pub_common; /**< Common fragment info */
+ sip_error_t *pub_next; /**< Link to next (dummy) */
+ char const * pub_package; /**< Publication packaage */
+ msg_param_t const *pub_params; /**< List of parameters */
+ msg_param_t pub_type; /**< Publication type */
+ msg_param_t pub_stream; /**< Publication stream */
+};
+
+static msg_xtra_f sip_publication_dup_xtra;
+static msg_dup_f sip_publication_dup_one;
+
+msg_hclass_t sip_publication_class[] =
+SIP_HEADER_CLASS(publication, "Publication", "", pub_params, single,
+ publication);
+
+static inline void sip_publication_update(sip_publication_t *pub);
+
+issize_t sip_publication_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ sip_publication_t *pub = h->sh_publication;
+ size_t n;
+
+ n = span_token(s); if (n == 0) return -1;
+ pub->pub_package = s; s += n;
+ while (IS_LWS(*s)) { *s++ = '\0'; }
+ if (*s == ';') {
+ if (msg_params_d(home, &s, &pub->pub_params) < 0 || *s)
+ return -1;
+ sip_publication_update(pub);
+ }
+ return 0;
+}
+
+issize_t sip_publication_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+ char *end = b + bsiz, *b0 = b;
+ sip_publication_t const *pub = h->sh_publication;
+
+ assert(sip_is_publication(h));
+ MSG_STRING_E(b, end, pub->pub_package);
+ MSG_PARAMS_E(b, end, pub->pub_params, flags);
+
+ return b - b0;
+}
+
+isize_t sip_publication_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+ sip_publication_t const *pub = h->sh_publication;
+
+ MSG_PARAMS_SIZE(offset, pub->pub_params);
+ offset += MSG_STRING_SIZE(pub->pub_package);
+
+ return offset;
+}
+
+/** Duplicate one #sip_publication_t object */
+char *sip_publication_dup_one(sip_header_t *dst, sip_header_t const *src,
+ char *b, isize_t xtra)
+{
+ sip_publication_t *pub_dst = dst->sh_publication;
+ sip_publication_t const *pub_src = src->sh_publication;
+
+ char *end = b + xtra;
+ b = msg_params_dup(&pub_dst->pub_params, pub_src->pub_params, b, xtra);
+ MSG_STRING_DUP(b, pub_dst->pub_package, pub_src->pub_package);
+ if (pub_dst->pub_params)
+ sip_publication_update(pub_dst);
+ assert(b <= end);
+
+ return b;
+}
+
+static inline void sip_publication_update(sip_publication_t *pub)
+{
+ size_t i;
+
+ if (pub->pub_params)
+ for (i = 0; pub->pub_params[i]; i++) {
+ if (strncasecmp(pub->pub_params[i], "stream=", strlen("stream=")) == 0)
+ pub->pub_stream = pub->pub_params[i] + strlen("stream=");
+ else if (strncasecmp(pub->pub_params[i], "type=", strlen("type=")) == 0)
+ pub->pub_type = pub->pub_params[i] + strlen("type=");
+ }
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_allow_publications Allow-Publication Header
+ *
+ * The Allow-Publication header is used to indicate which publications or classes of
+ * publications the server supports. Its syntax is defined in [niemi]
+ * (draft-niemi-simple-publish-00.txt) as follows:
+ *
+ * @code
+ * Allow-Publications = "Allow-Publications" HCOLON publish-type
+ * * ( COMMA publish-type )
+ * @endcode
+ *
+ *
+ * The parsed Allow-Publication Header
+ * is stored in #sip_allow_publications_t structure.
+ */
+
+msg_hclass_t sip_allow_publications_class[] =
+SIP_HEADER_CLASS_LIST(allow_publications, "Allow-Publications", "", list);
+
+issize_t sip_allow_publications_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ return msg_list_d(home, h, s, slen);
+}
+
+issize_t sip_allow_publications_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+ assert(sip_is_allow_publications(h));
+ return msg_list_e(b, bsiz, h, f);
+}
+
+/** Append an publication to a Allow-Publications header. */
+int sip_allow_publications_add(su_home_t *home,
+ sip_allow_publications_t *ae,
+ char const *e)
+{
+ e = su_strdup(home, e);
+ if (!e)
+ return -1;
+ return msg_params_replace(home, (msg_param_t **)&ae->k_items, e);
+}
+
+#endif
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_extra.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_extra.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,890 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE sip_extra.c
+ * @brief Non-critical SIP headers
+ *
+ * This file contains implementation of @CallInfo, @ErrorInfo,
+ * @Organization, @Priority, @RetryAfter, @Server, @Subject,
+ * @Timestamp, and @UserAgent headers.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Tue Jun 13 02:57:51 2000 ppessi
+ */
+
+#include "config.h"
+
+/* Avoid casting sip_t to msg_pub_t and sip_header_t to msg_header_t */
+#define MSG_PUB_T struct sip_s
+#define MSG_HDR_T union sip_header_u
+
+#include "sofia-sip/sip_parser.h"
+#include "sofia-sip/sip_extra.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <assert.h>
+
+/* ====================================================================== */
+
+static issize_t sip_info_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen);
+
+static isize_t sip_info_dup_xtra(sip_header_t const *h, isize_t offset);
+static char *sip_info_dup_one(sip_header_t *dst,
+ sip_header_t const *src,
+ char *b,
+ isize_t xtra);
+
+#define sip_info_update NULL
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_call_info Call-Info Header
+ *
+ * The Call-Info header provides additional information about the caller or
+ * callee. Its syntax is defined in @RFC3261 as follows:
+ *
+ * @code
+ * Call-Info = "Call-Info" HCOLON info *(COMMA info)
+ * info = LAQUOT absoluteURI RAQUOT *( SEMI info-param)
+ * info-param = ( "purpose" EQUAL ( "icon" / "info"
+ * / "card" / token ) ) / generic-param
+ * @endcode
+ *
+ *
+ * The parsed Call-Info header is stored in #sip_call_info_t structure.
+ */
+
+/**@ingroup sip_call_info
+ * @typedef struct sip_call_info_s sip_call_info_t;
+ *
+ * The structure #sip_call_info_t contains representation of an
+ * @CallInfo header.
+ *
+ * The #sip_call_info_t is defined as follows:
+ * @code
+ * struct sip_call_info_s
+ * {
+ * sip_common_t ci_common[1]; // Common fragment info
+ * sip_call_info_t *ci_next; // Link to next @CallInfo
+ * url_t ci_url[1]; // URI to call info
+ * msg_param_t const *ci_params; // List of parameters
+ * char const *ci_purpose; // Value of @b purpose parameter
+ * };
+ * @endcode
+ */
+
+#define sip_call_info_dup_xtra sip_info_dup_xtra
+#define sip_call_info_dup_one sip_info_dup_one
+static msg_update_f sip_call_info_update;
+
+msg_hclass_t sip_call_info_class[] =
+SIP_HEADER_CLASS(call_info, "Call-Info", "",
+ ci_params, append, call_info);
+
+issize_t sip_call_info_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ issize_t retval = sip_info_d(home, h, s, slen);
+
+ if (retval == 0)
+ for (;h; h = h->sh_next)
+ msg_header_update_params(h->sh_common, 0);
+
+ return retval;
+}
+
+issize_t sip_call_info_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+ sip_call_info_t *ci = (sip_call_info_t *)h;
+
+ assert(sip_call_info_p(h));
+
+ return sip_name_addr_e(b, bsiz, f, NULL, 1, ci->ci_url, ci->ci_params, NULL);
+}
+
+/** @internal
+ * Update parameter in a @CallInfo object.
+ *
+ */
+static
+int sip_call_info_update(msg_common_t *h,
+ char const *name, isize_t namelen,
+ char const *value)
+{
+ sip_call_info_t *ci = (sip_call_info_t *)h;
+
+ if (name == NULL) {
+ ci->ci_purpose = NULL;
+ }
+ else if (namelen == strlen("purpose") &&
+ !strncasecmp(name, "purpose", namelen)) {
+ ci->ci_purpose = value;
+ }
+
+ return 0;
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_error_info Error-Info Header
+ *
+ * The Error-Info header provides a pointer to additional information about
+ * the error status response. Its syntax is defined in @RFC3261 as follows:
+ *
+ * @code
+ * Error-Info = "Error-Info" HCOLON error-uri *(COMMA error-uri)
+ * error-uri = LAQUOT absoluteURI RAQUOT *( SEMI generic-param )
+ * @endcode
+ *
+ *
+ * The parsed Error-Info header is stored in #sip_error_info_t structure.
+ */
+
+/**@ingroup sip_error_info
+ * @typedef struct sip_error_info_s sip_error_info_t;
+ *
+ * The structure #sip_error_info_t contains representation of an
+ * @ErrorInfo header.
+ *
+ * The #sip_error_info_t is defined as follows:
+ * @code
+ * struct sip_error_info_s
+ * {
+ * sip_common_t ei_common[1]; // Common fragment info
+ * sip_error_info_t *ei_next; // Link to next @ErrorInfo
+ * url_t ei_url[1]; // URI to error info
+ * msg_param_t const *ei_params; // List of parameters
+ * };
+ * @endcode
+ */
+
+msg_hclass_t sip_error_info_class[] =
+SIP_HEADER_CLASS(error_info, "Error-Info", "",
+ ei_params, append, info);
+
+issize_t sip_error_info_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ return sip_info_d(home, h, s, slen);
+}
+
+issize_t sip_error_info_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+ sip_error_info_t const *ei = h->sh_error_info;
+
+ assert(sip_error_info_p(h));
+
+ return sip_name_addr_e(b, bsiz, f,
+ NULL, 1, ei->ei_url, ei->ei_params, NULL);
+}
+
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_in_reply_to In-Reply-To Header
+ *
+ * The @b In-Reply-To request header field enumerates the
+ * @ref sip_call_id "Call-IDs" that this call references or returns.
+ * Its syntax is defined in @RFC3261 as follows:
+ *
+ * @code
+ * In-Reply-To = "In-Reply-To" HCOLON callid *(COMMA callid)
+ * @endcode
+ *
+ * The parsed In-Reply-To header is stored in #sip_in_reply_to_t structure.
+ */
+
+/**@ingroup sip_in_reply_to
+ * @typedef struct msg_list_s sip_in_reply_to_t;
+ *
+ * The structure #sip_in_reply_to_t contains representation of SIP
+ * @InReplyTo header.
+ *
+ * The #sip_in_reply_to_t is defined as follows:
+ * @code
+ * typedef 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 call ids
+ * } sip_allow_events_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_in_reply_to_class[] =
+SIP_HEADER_CLASS_LIST(in_reply_to, "In-Reply-To", "", list);
+
+issize_t sip_in_reply_to_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ return msg_list_d(home, h, s, slen);
+}
+
+issize_t sip_in_reply_to_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+ assert(sip_in_reply_to_p(h));
+ return msg_list_e(b, bsiz, h, f);
+}
+
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_organization Organization Header
+ *
+ * The Organization header field conveys the name of the organization to
+ * which the entity issuing the request or response belongs. Its syntax is
+ * defined in @RFC3261 as follows:
+ *
+ * @code
+ * Organization = "Organization" HCOLON [TEXT-UTF8-TRIM]
+ * @endcode
+ *
+ *
+ * The parsed Organization header is stored in #sip_organization_t structure.
+ */
+
+/**@ingroup sip_organization
+ * @typedef struct msg_generic_s sip_organization_t;
+ *
+ * The structure #sip_organization_t contains representation of a SIP
+ * @Organization header.
+ *
+ * The #sip_organization_t is defined as follows:
+ * @code
+ * typedef 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; // Organization text
+ * } sip_organization_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_organization_class[] =
+SIP_HEADER_CLASS_G(organization, "Organization", "", single);
+
+issize_t sip_organization_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ return sip_generic_d(home, h, s, slen);
+}
+
+issize_t sip_organization_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+ assert(sip_organization_p(h));
+ return sip_generic_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_priority Priority Header
+ *
+ * The Priority request-header field indicates the urgency of the request as
+ * perceived by the client. Its syntax is defined in @RFC3261 as follows:
+ *
+ * @code
+ * Priority = "Priority" HCOLON priority-value
+ * priority-value = "emergency" / "urgent" / "normal"
+ * / "non-urgent" / other-priority
+ * other-priority = token
+ * @endcode
+ *
+ *
+ * The parsed Priority header is stored in #sip_priority_t structure.
+ */
+
+/**@ingroup sip_priority
+ * @typedef struct msg_generic_s sip_priority_t;
+ *
+ * The structure #sip_priority_t contains representation of a SIP
+ * @Priority header.
+ *
+ * The #sip_priority_t is defined as follows:
+ * @code
+ * typedef struct msg_generic_s
+ * {
+ * msg_common_t g_common[1]; // Common fragment info
+ * msg_generic_t *g_next; // Dummy link to next header
+ * char const *g_string; // Priority token
+ * } sip_priority_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_priority_class[] =
+SIP_HEADER_CLASS_G(priority, "Priority", "", single);
+
+issize_t sip_priority_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ sip_priority_t *priority = (sip_priority_t *)h;
+
+ if (msg_token_d(&s, &priority->g_string) < 0)
+ return -1;
+
+ if (*s && !IS_LWS(*s)) /* Something extra after priority token? */
+ return -1;
+
+ return 0;
+}
+
+issize_t sip_priority_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+ assert(sip_priority_p(h));
+ return sip_generic_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_server Server Header
+ *
+ * The Server response-header field contains information about the software
+ * used by the user agent server to handle the request. Its syntax is
+ * defined in @RFC2616 section 14.38 and @RFC3261 as follows:
+ *
+ * @code
+ * Server = "Server" HCOLON server-val *(LWS server-val)
+ * server-val = product / comment
+ * product = token [SLASH product-version]
+ * product-version = token
+ * @endcode
+ *
+ * The parsed Server header is stored in #sip_server_t structure.
+ */
+
+/**@ingroup sip_server
+ * @typedef struct msg_generic_s sip_server_t;
+ *
+ * The structure #sip_server_t contains representation of a SIP
+ * @Server header.
+ *
+ * The #sip_server_t is defined as follows:
+ * @code
+ * typedef 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; // Server tokens
+ * } sip_server_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_server_class[] =
+SIP_HEADER_CLASS_G(server, "Server", "", single);
+
+issize_t sip_server_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ return sip_generic_d(home, h, s, slen);
+}
+
+issize_t sip_server_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+ assert(sip_server_p(h));
+ return sip_generic_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_subject Subject Header
+ *
+ * The Subject header provides a summary or indicates the nature of the
+ * request. Its syntax is defined in @RFC3261 as follows:
+ *
+ * @code
+ * Subject = ( "Subject" / "s" ) HCOLON [TEXT-UTF8-TRIM]
+ * @endcode
+ *
+ * The parsed Subject header is stored in #sip_subject_t structure.
+ */
+
+/**@ingroup sip_subject
+ * @typedef struct msg_generic_s sip_subject_t;
+ *
+ * The structure #sip_subject_t contains representation of a SIP
+ * @Subject header.
+ *
+ * The #sip_subject_t is defined as follows:
+ * @code
+ * typedef 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; // Subject text
+ * } sip_subject_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_subject_class[] =
+SIP_HEADER_CLASS_G(subject, "Subject", "s", single);
+
+issize_t sip_subject_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ return sip_generic_d(home, h, s, slen);
+}
+
+issize_t sip_subject_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+ assert(sip_subject_p(h));
+ return sip_generic_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_timestamp Timestamp Header
+ *
+ * The @b Timestamp header describes when the client sent the request to the
+ * server, and it is used by the client to adjust its retransmission
+ * intervals. Its syntax is defined in @RFC3261 as follows:
+ *
+ * @code
+ * Timestamp = "Timestamp" HCOLON 1*(DIGIT)
+ * [ "." *(DIGIT) ] [ LWS delay ]
+ * delay = *(DIGIT) [ "." *(DIGIT) ]
+ * @endcode
+ *
+ * The parsed Timestamp header is stored in #sip_timestamp_t structure.
+ */
+
+/**@ingroup sip_timestamp
+ * @typedef struct sip_timestamp_s sip_timestamp_t;
+ *
+ * The structure #sip_timestamp_t contains representation of a SIP
+ * @Timestamp header.
+ *
+ * The #sip_timestamp_t is defined as follows:
+ * @code
+ * typedef struct sip_timestamp_s
+ * {
+ * sip_common_t ts_common[1]; // Common fragment info
+ * sip_error_t *ts_next; // Dummy link
+ * char const *ts_stamp; // Original timestamp
+ * char const *ts_delay; // Delay at UAS
+ * } sip_timestamp_t;
+ * @endcode
+ */
+
+static isize_t sip_timestamp_dup_xtra(sip_header_t const *h, isize_t offset);
+static char *sip_timestamp_dup_one(sip_header_t *dst,
+ sip_header_t const *src,
+ char *b,
+ isize_t xtra);
+#define sip_timestamp_update NULL
+
+msg_hclass_t sip_timestamp_class[] =
+SIP_HEADER_CLASS(timestamp, "Timestamp", "", ts_common, single,
+ timestamp);
+
+issize_t sip_timestamp_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ sip_timestamp_t *ts = (sip_timestamp_t*)h;
+
+ ts->ts_stamp = s;
+ s += span_digit(s);
+ if (s == ts->ts_stamp)
+ return -1;
+ if (*s == '.') { s += span_digit(s + 1) + 1; }
+
+ if (IS_LWS(*s)) {
+ *s = '\0';
+ s += span_lws(s + 1) + 1;
+ ts->ts_delay = s;
+ s += span_digit(s); if (*s == '.') { s += span_digit(s + 1) + 1; }
+ }
+
+ if (!*s || IS_LWS(*s))
+ *s++ = '\0';
+ else
+ return -1;
+
+ return 0;
+}
+
+issize_t sip_timestamp_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+ sip_timestamp_t const *ts = h->sh_timestamp;
+ char *end = b + bsiz, *b0 = b;
+
+ assert(sip_timestamp_p(h));
+
+ MSG_STRING_E(b, end, ts->ts_stamp);
+ if (ts->ts_delay) {
+ MSG_CHAR_E(b, end, ' ');
+ MSG_STRING_E(b, end, ts->ts_delay);
+ }
+
+ MSG_TERM_E(b, end);
+
+ return b - b0;
+}
+
+static
+isize_t sip_timestamp_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+ sip_timestamp_t const *ts = h->sh_timestamp;
+
+ offset += MSG_STRING_SIZE(ts->ts_stamp);
+ offset += MSG_STRING_SIZE(ts->ts_delay);
+
+ return offset;
+}
+
+static
+char *sip_timestamp_dup_one(sip_header_t *dst,
+ sip_header_t const *src,
+ char *b,
+ isize_t xtra)
+{
+ sip_timestamp_t *ts = dst->sh_timestamp;
+ sip_timestamp_t const *o = src->sh_timestamp;
+ char *end = b + xtra;
+
+ MSG_STRING_DUP(b, ts->ts_stamp, o->ts_stamp);
+ MSG_STRING_DUP(b, ts->ts_delay, o->ts_delay);
+
+ assert(b <= end); (void)end;
+
+ return b;
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_user_agent User-Agent Header
+ *
+ * The User-Agent header contains information about the client user agent
+ * originating the request. Its syntax is defined in [H14.43, S10.45] as
+ * follows:
+ *
+ * @code
+ * User-Agent = "User-Agent" HCOLON server-val *(LWS server-val)
+ * server-val = product / comment
+ * product = token [SLASH product-version]
+ * product-version = token
+ * @endcode
+ *
+ * The parsed User-Agent header is stored in #sip_user_agent_t structure.
+ */
+
+/**@ingroup sip_user_agent
+ * @typedef struct msg_generic_s sip_user_agent_t;
+ *
+ * The structure #sip_user_agent_t contains representation of a SIP
+ * @UserAgent header.
+ *
+ * The #sip_user_agent_t is defined as follows:
+ * @code
+ * typedef 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; // User-Agent components
+ * } sip_user_agent_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_user_agent_class[] =
+SIP_HEADER_CLASS_G(user_agent, "User-Agent", "", single);
+
+issize_t sip_user_agent_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ return sip_generic_d(home, h, s, slen);
+}
+
+issize_t sip_user_agent_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+ assert(sip_user_agent_p(h));
+ return sip_generic_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_etag SIP-ETag Header
+ *
+ * The @b SIP-ETag header field identifies the published event state. Its
+ * syntax is defined in @RFC3903 as follows:
+ *
+ * @code
+ * SIP-ETag = "SIP-ETag" HCOLON entity-tag
+ * entity-tag = token
+ * @endcode
+ *
+ * The parsed SIP-ETag header is stored in #sip_etag_t structure.
+ */
+
+/**@ingroup sip_etag
+ * @typedef struct msg_generic_s sip_etag_t;
+ *
+ * The structure #sip_etag_t contains representation of a SIP
+ * @SIPETag header.
+ *
+ * The #sip_etag_t is defined as follows:
+ * @code
+ * typedef 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; // entity-tag
+ * } sip_etag_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_etag_class[] =
+SIP_HEADER_CLASS_G(etag, "SIP-ETag", "", single);
+
+issize_t sip_etag_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ sip_etag_t *etag = (sip_etag_t *)h;
+
+ return msg_token_d(&s, &etag->g_value);
+}
+
+issize_t sip_etag_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+ return msg_generic_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_if_match SIP-If-Match Header
+ *
+ * The @b SIP-If-Match header field identifies the specific entity of event
+ * state that the request is refreshing, modifying or removing. Its syntax
+ * is defined in @RFC3903 as follows:
+ *
+ * @code
+ * SIP-If-Match = "SIP-If-Match" HCOLON entity-tag
+ * entity-tag = token
+ * @endcode
+ *
+ * The parsed SIP-If-Match header is stored in #sip_if_match_t structure.
+ */
+
+/**@ingroup sip_if_match
+ * @typedef struct msg_generic_s sip_if_match_t;
+ *
+ * The structure #sip_if_match_t contains representation of a SIP
+ * @SIPIfMatch header.
+ *
+ * The #sip_if_match_t is defined as follows:
+ * @code
+ * typedef 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; // entity-tag
+ * } sip_if_match_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_if_match_class[] =
+SIP_HEADER_CLASS_G(if_match, "SIP-If-Match", "", single);
+
+issize_t sip_if_match_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ return sip_etag_d(home, h, s, slen);
+}
+
+issize_t sip_if_match_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+ return sip_etag_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/** Parsing @CallInfo, @ErrorInfo. */
+static
+issize_t sip_info_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ sip_call_info_t *ci = h->sh_call_info;
+ char *end = s + slen;
+
+ assert(h);
+
+ while (*s == ',')
+ s += span_lws(s + 1) + 1;
+
+ if (sip_name_addr_d(home, &s, NULL, ci->ci_url, &ci->ci_params, NULL) < 0)
+ return -1;
+
+ /* Recurse */
+ return msg_parse_next_field(home, h, s, end - s);
+}
+
+isize_t sip_info_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+ sip_call_info_t const *ci = h->sh_call_info;
+
+ MSG_PARAMS_SIZE(offset, ci->ci_params);
+ offset += url_xtra(ci->ci_url);
+
+ return offset;
+}
+
+char *sip_info_dup_one(sip_header_t *dst,
+ sip_header_t const *src,
+ char *b,
+ isize_t xtra)
+{
+ sip_call_info_t *ci = dst->sh_call_info;
+ sip_call_info_t const *o = src->sh_call_info;
+ char *end = b + xtra;
+
+ b = msg_params_dup(&ci->ci_params, o->ci_params, b, xtra);
+ URL_DUP(b, end, ci->ci_url, o->ci_url);
+
+ assert(b <= end);
+
+ return b;
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_suppress_body_if_match Suppress-Body-If-Match Header
+ *
+ * The @b Suppress-Body-If-Match header field identifies a SIP event content
+ * already known by the watcher. Its syntax is defined in
+ * draft-niemi-sip-subnot-etags-01 as follows:
+ *
+ * @code
+ * Suppress-Body-If-Match = "Suppress-Body-If-Match" HCOLON entity-tag
+ * entity-tag = token
+ * @endcode
+ *
+ * The parsed Suppress-Body-If-Match header is stored in
+ * #sip_suppress_body_if_match_t structure.
+ *
+ * @sa @RFC3265, draft-niemi-sip-subnot-etags-01.txt
+ *
+ * @NEW_1_12_5. Note that #sip_t does not contain @a
+ * sip_suppress_body_if_match field, but sip_suppress_body_if_match()
+ * function should be used for accessing the @b Suppress-Body-If-Match
+ * header structure.
+ */
+
+/**@ingroup sip_suppress_body_if_match
+ * @typedef struct sip_suppress_body_if_match_s sip_suppress_body_if_match_t;
+ *
+ * The structure #sip_suppress_body_if_match_t contains representation of a
+ * SIP @SuppressBodyIfMatch header.
+ *
+ * The #sip_suppress_body_if_match_t is defined as follows:
+ * @code
+ * typedef struct sip_suppress_body_if_match_s
+ * {
+ * sip_common_t sbim_common[1]; // Common fragment info
+ * sip_error_t *sbim_next; // Dummy link to next header
+ * char const *sbim_tag; // entity-tag
+ * } sip_suppress_body_if_match_t;
+ * @endcode
+ */
+
+#define sip_suppress_body_if_match_dup_xtra msg_generic_dup_xtra
+#define sip_suppress_body_if_match_dup_one msg_generic_dup_one
+#define sip_suppress_body_if_match_update NULL
+
+msg_hclass_t sip_suppress_body_if_match_class[] =
+SIP_HEADER_CLASS(suppress_body_if_match,
+ "Suppress-Body-If-Match", "",
+ sbim_common, single, suppress_body_if_match);
+
+issize_t sip_suppress_body_if_match_d(su_home_t *home,
+ sip_header_t *h,
+ char *s, isize_t slen)
+{
+ sip_suppress_body_if_match_t *sbim = (void *)h;
+ return msg_token_d(&s, &sbim->sbim_tag);
+}
+
+issize_t sip_suppress_body_if_match_e(char b[], isize_t bsiz,
+ sip_header_t const *h,
+ int f)
+{
+ return sip_etag_e(b, bsiz, h, f);
+}
+
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_suppress_notify_if_match Suppress-Notify-If-Match Header
+ *
+ * The @b Suppress-Notify-If-Match header is used to suppress
+ * superfluous NOTIFY transactions. Its syntax is defined in
+ * draft-niemi-sip-subnot-etags-01 as follows:
+ *
+ * @code
+ * Suppress-Notify-If-Match = "Suppress-Notify-If-Match" HCOLON entity-tag
+ * entity-tag = token
+ * @endcode
+ *
+ * The parsed Suppress-Notify-If-Match header is stored in
+ * #sip_suppress_notify_if_match_t structure.
+ *
+ * @sa @RFC3265, draft-niemi-sip-subnot-etag-01
+ *
+ * @NEW_1_12_5. Note that #sip_t does not contain @a
+ * sip_suppress_notify_if_match field, but sip_suppress_notify_if_match()
+ * function should be used for accessing the @b Suppress-Notify-If-Match
+ * header structure.
+ */
+
+/**@ingroup sip_suppress_notify_if_match
+ * @typedef struct sip_suppress_notify_if_match_s \
+ * sip_suppress_notify_if_match_t;
+ *
+ * The structure #sip_suppress_notify_if_match_t contains representation of a
+ * SIP @SuppressNotifyIfMatch header.
+ *
+ * The #sip_suppress_notify_if_match_t is defined as follows:
+ * @code
+ * typedef struct sip_suppress_notify_if_match_s
+ * {
+ * sip_common_t snim_common[1]; // Common fragment info
+ * sip_error_t *snim_next; // Dummy link to next header
+ * char const *snim_tag; // entity-tag
+ * } sip_suppress_notify_if_match_t;
+ * @endcode
+ */
+
+#define sip_suppress_notify_if_match_dup_xtra msg_generic_dup_xtra
+#define sip_suppress_notify_if_match_dup_one msg_generic_dup_one
+#define sip_suppress_notify_if_match_update NULL
+
+msg_hclass_t sip_suppress_notify_if_match_class[] =
+SIP_HEADER_CLASS(suppress_notify_if_match,
+ "Suppress-Notify-If-Match", "",
+ snim_common, single, suppress_notify_if_match);
+
+issize_t sip_suppress_notify_if_match_d(su_home_t *home,
+ sip_header_t *h,
+ char *s, isize_t slen)
+{
+ sip_suppress_notify_if_match_t *snim = (void *)h;
+ return msg_token_d(&s, &snim->snim_tag);
+}
+
+issize_t sip_suppress_notify_if_match_e(char b[], isize_t bsiz,
+ sip_header_t const *h,
+ int f)
+{
+ return msg_generic_e(b, bsiz, h, f);
+}
+
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_extra_headers.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_extra_headers.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,13 @@
+#
+# This file specifies extra SIP headers not included in sip_t structure
+#
+# The line format is:
+# C-name @SINCE sip_t-like-comment
+#
+#### EXTRA HEADER LIST STARTS HERE ####
+
+refer_sub @VERSION_1_12_5 /**< Refer-Sub header */
+suppress_body_if_match @VERSION_1_12_5 /**< Suppress-Body-If-Match header */
+suppress_notify_if_match @VERSION_1_12_5 /**< Suppress-Notify-If-Match header*/
+
+#### EXTRA HEADER LIST ENDS HERE ####
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_feature.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_feature.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,595 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE sip_feature.c
+ *
+ * @brief Feature-related SIP header handling
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Tue Jun 13 02:57:51 2000 ppessi
+ */
+
+#include "config.h"
+
+/* Avoid casting sip_t to msg_pub_t and sip_header_t to msg_header_t */
+#define MSG_PUB_T struct sip_s
+#define MSG_HDR_T union sip_header_u
+
+#include "sofia-sip/sip_parser.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_allow Allow Header
+ *
+ * The Allow header lists the set of methods supported by the user agent
+ * generating the message. Its syntax is defined in @RFC3261 as
+ * follows:
+ *
+ * @code
+ * Allow = "Allow" HCOLON [Method *(COMMA Method)]
+ * @endcode
+ *
+ * The parsed Allow header is stored in #sip_allow_t structure.
+ *
+ * Note that SIP methods are case-sensitive: "INVITE" method is different from
+ * "Invite".
+ *
+ * @sa msg_header_find_item(), msg_header_replace_item(),
+ * msg_header_remove_item()
+ */
+
+/**@ingroup sip_allow
+ * @typedef struct msg_list_s sip_allow_t;
+ *
+ * The structure #sip_allow_t contains representation of an @Allow header.
+ *
+ * The #sip_allow_t is defined as follows:
+ * @code
+ * typedef struct msg_allow_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
+ * uint32_t k_bitmap; // Bitmap of allowed methods
+ * } sip_allow_t;
+ * @endcode
+ *
+ * @note The field @a k_bitmap was added in @VERSION_1_12_5.
+ */
+
+#define sip_allow_dup_xtra msg_list_dup_xtra
+#define sip_allow_dup_one msg_list_dup_one
+static msg_update_f sip_allow_update;
+
+msg_hclass_t sip_allow_class[] =
+SIP_HEADER_CLASS(allow, "Allow", "", k_items, list, allow);
+
+issize_t sip_allow_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ sip_allow_t *k = (sip_allow_t *)h;
+ issize_t retval = msg_commalist_d(home, &s, &k->k_items, msg_token_scan);
+ msg_header_update_params(k->k_common, 0);
+ return retval;
+}
+
+issize_t sip_allow_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+ assert(sip_is_allow(h));
+ return msg_list_e(b, bsiz, h, f);
+}
+
+static int sip_allow_update(msg_common_t *h,
+ char const *name, isize_t namelen,
+ char const *value)
+{
+ sip_allow_t *k = (sip_allow_t *)h;
+
+ if (name == NULL) {
+ k->k_bitmap = 0;
+ }
+ else {
+ sip_method_t method = sip_method_code(name);
+
+ if (method >= 0 && method < 32)
+ k->k_bitmap |= 1 << method;
+ }
+
+ return 0;
+}
+
+/** Return true if the method is listed in @Allow header. */
+int sip_is_allowed(sip_allow_t const *allow,
+ sip_method_t method,
+ char const *name)
+{
+ if (method < sip_method_unknown || !allow)
+ return 0;
+
+ if (sip_method_unknown < method && method < 32)
+ /* Well-known method */
+ return (allow->k_bitmap & (1 << method)) != 0;
+
+ if (method == sip_method_unknown &&
+ (allow->k_bitmap & (1 << sip_method_unknown)) == 0)
+ return 0;
+
+ return msg_header_find_item(allow->k_common, name) != NULL;
+}
+
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_proxy_require Proxy-Require Header
+ *
+ * The Proxy-Require header is used to indicate proxy-sensitive features
+ * that @b MUST be supported by the proxy. Its syntax is defined in @RFC3261
+ * as follows:
+ *
+ * @code
+ * Proxy-Require = "Proxy-Require" HCOLON option-tag *(COMMA option-tag)
+ * @endcode
+ *
+ *
+ * The parsed Proxy-Require header is stored in #sip_proxy_require_t structure.
+ */
+
+/**@ingroup sip_proxy_require
+ * @typedef struct msg_list_s sip_proxy_require_t;
+ *
+ * The structure #sip_proxy_require_t contains representation of an
+ * @ProxyRequire header.
+ *
+ * The #sip_proxy_require_t is defined as follows:
+ * @code
+ * typedef struct msg_list_s
+ * {
+ * msg_common_t k_common[1]; // Common fragment info
+ * msg_list_t *k_next; // Dummy link
+ * msg_param_t *k_items; // List of items
+ * } sip_proxy_require_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_proxy_require_class[] =
+SIP_HEADER_CLASS_LIST(proxy_require, "Proxy-Require", "", list);
+
+issize_t sip_proxy_require_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ sip_proxy_require_t *k = (sip_proxy_require_t *)h;
+ return msg_commalist_d(home, &s, &k->k_items, msg_token_scan);
+}
+
+issize_t sip_proxy_require_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+ assert(sip_is_proxy_require(h));
+ return msg_list_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_require Require Header
+ *
+ * The Require header is used by clients to tell user agent servers about
+ * options that the client expects the server to support in order to
+ * properly process the request. Its syntax is defined in @RFC3261
+ * as follows:
+ *
+ * @code
+ * Require = "Require" HCOLON option-tag *(COMMA option-tag)
+ * @endcode
+ *
+ * The parsed Require header is stored in #sip_require_t structure.
+ */
+
+/**@ingroup sip_require
+ * @typedef struct msg_list_s sip_require_t;
+ *
+ * The structure #sip_require_t contains representation of an
+ * @Require header.
+ *
+ * The #sip_require_t is defined as follows:
+ * @code
+ * typedef 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
+ * } sip_require_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_require_class[] =
+SIP_HEADER_CLASS_LIST(require, "Require", "", list);
+
+issize_t sip_require_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ sip_require_t *k = (sip_require_t *)h;
+ return msg_commalist_d(home, &s, &k->k_items, msg_token_scan);
+}
+
+issize_t sip_require_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+ assert(sip_is_require(h));
+ return msg_list_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_supported Supported Header
+ *
+ * The Supported header enumerates all the capabilities of the client or
+ * server. Its syntax is defined in @RFC3261 as follows:
+ *
+ * @code
+ * Supported = ( "Supported" / "k" ) HCOLON
+ * [option-tag *(COMMA option-tag)]
+ * @endcode
+ *
+ * The parsed option-tags of Supported header
+ * are stored in #sip_supported_t structure.
+ */
+
+/**@ingroup sip_supported
+ * @typedef struct msg_list_s sip_supported_t;
+ *
+ * The structure #sip_supported_t contains representation of an
+ * @Supported header.
+ *
+ * The #sip_supported_t is defined as follows:
+ * @code
+ * typedef 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
+ * } sip_supported_t;
+ * @endcode
+ */
+
+
+msg_hclass_t sip_supported_class[] =
+SIP_HEADER_CLASS_LIST(supported, "Supported", "k", list);
+
+issize_t sip_supported_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ sip_supported_t *k = (sip_supported_t *)h;
+ return msg_commalist_d(home, &s, &k->k_items, msg_token_scan);
+}
+
+issize_t sip_supported_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+ assert(sip_is_supported(h));
+ return msg_list_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_unsupported Unsupported Header
+ *
+ * The Unsupported header lists the features not supported by the server.
+ * Its syntax is defined in @RFC3261 as follows:
+ *
+ * @code
+ * Unsupported = "Unsupported" HCOLON [option-tag *(COMMA option-tag)]
+ * @endcode
+ *
+ *
+ * The parsed Unsupported header is stored in #sip_unsupported_t structure.
+ */
+
+/**@ingroup sip_unsupported
+ * @typedef struct msg_list_s sip_unsupported_t;
+ *
+ * The structure #sip_unsupported_t contains representation of an
+ * @Unsupported header.
+ *
+ * The #sip_unsupported_t is defined as follows:
+ * @code
+ * typedef 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
+ * } sip_unsupported_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_unsupported_class[] =
+SIP_HEADER_CLASS_LIST(unsupported, "Unsupported", "", list);
+
+issize_t sip_unsupported_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ sip_unsupported_t *k = (sip_unsupported_t *)h;
+ return msg_commalist_d(home, &s, &k->k_items, msg_token_scan);
+}
+
+issize_t sip_unsupported_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+ assert(sip_is_unsupported(h));
+ return msg_list_e(b, bsiz, h, f);
+}
+
+/** Check if required feature is supported.
+ *
+ * @retval NULL if all the required features are supported
+ * @retval pointer to a @Unsupported header or
+ * #SIP_NONE if @a home is NULL
+ */
+sip_unsupported_t *sip_has_unsupported(su_home_t *home,
+ sip_supported_t const *support,
+ sip_require_t const *require)
+{
+ return sip_has_unsupported_any(home, support, NULL, NULL,
+ require, NULL, NULL);
+}
+
+
+/** Check if required feature is supported.
+ *
+ * @retval NULL if all the required features are supported
+ * @retval pointer to a @Unsupported header or
+ * #SIP_NONE if @a home is NULL
+ */
+sip_unsupported_t *
+sip_has_unsupported2(su_home_t *home,
+ sip_supported_t const *support,
+ sip_require_t const *support_by_require,
+ sip_require_t const *require)
+{
+ return
+ sip_has_unsupported_any(home,
+ support, support_by_require, NULL,
+ require, NULL, NULL);
+}
+
+
+/** Ensure that required features are supported.
+ *
+ * The supported features can be listed in @Supported, @Require or
+ * @ProxyRequire headers (in @a supported, @a by_require, or @a
+ * by_proxy_require parameters, respectively)
+ *
+ * @param home (optional) home pointer for allocating @Unsupported header
+ * @param supported @Supported features (may be NULL) [IN]
+ * @param by_require supported features listed by
+ * @Require (may be NULL) [IN]
+ * @param by_proxy_require supported features listed
+ * by @ProxyRequire (may be NULL) [IN]
+ *
+ * @param require list of required features (may be NULL) [IN]
+ * @param require2 2nd list of required features (may be NULL) [IN]
+ * @param require3 3rd list of required features (may be NULL) [IN]
+ *
+ * @retval NULL if all the required features are supported
+ * @retval pointer to a @Unsupported header or
+ * #SIP_NONE if @a home is NULL
+ */
+sip_unsupported_t *
+sip_has_unsupported_any(su_home_t *home,
+ sip_supported_t const *supported,
+ sip_require_t const *by_require,
+ sip_proxy_require_t const *by_proxy_require,
+ sip_require_t const *require,
+ sip_require_t const *require2,
+ sip_require_t const *require3)
+{
+ size_t i, j;
+ sip_unsupported_t *unsupported = NULL;
+ msg_param_t const empty[1] = { NULL };
+ msg_param_t const *slist = empty;
+ msg_param_t const *rlist = empty;
+ msg_param_t const *prlist = empty;
+
+ if (require2 == NULL)
+ require2 = require3, require3 = NULL;
+ if (require == NULL)
+ require = require2, require2 = NULL;
+
+ if (require && require->k_items) {
+ if (supported && supported->k_items)
+ slist = supported->k_items;
+ if (by_require && by_require->k_items)
+ rlist = by_require->k_items;
+ if (by_proxy_require && by_proxy_require->k_items)
+ prlist = by_proxy_require->k_items;
+
+ for (i = 0; require->k_items && require->k_items[i];) {
+ msg_param_t feature = require->k_items[i++];
+
+ for (j = 0; slist[j]; j++)
+ if (strcasecmp(feature, slist[j]) == 0) {
+ feature = NULL;
+ break;
+ }
+
+ if (feature)
+ for (j = 0; rlist[j]; j++)
+ if (strcasecmp(feature, rlist[j]) == 0) {
+ feature = NULL;
+ break;
+ }
+
+ if (feature)
+ for (j = 0; prlist[j]; j++)
+ if (strcasecmp(feature, prlist[j]) == 0) {
+ feature = NULL;
+ break;
+ }
+
+ if (feature) {
+ if (home) {
+ if (unsupported == NULL)
+ unsupported = sip_unsupported_make(home, feature);
+ else
+ msg_params_add(home,
+ (msg_param_t **)&unsupported->k_items,
+ feature);
+ }
+ else {
+ return (sip_unsupported_t *)SIP_NONE;
+ }
+ }
+
+ if (require->k_items[i] == NULL && require2 && require2->k_items) {
+ i = 0, require = require2, require2 = require3, require3 = NULL;
+ }
+ }
+ }
+
+ return unsupported;
+}
+
+
+int sip_has_feature(msg_list_t const *supported, char const *feature)
+{
+ size_t i;
+
+ if (!feature || !feature[0])
+ return 1; /* Empty feature is always supported */
+
+ for (; supported; supported = supported->k_next)
+ if (supported->k_items)
+ for (i = 0; supported->k_items[i]; i++)
+ if (strcasecmp(feature, supported->k_items[i]) == 0)
+ return 1;
+
+ return 0;
+}
+
+/** Check that a feature is supported. */
+int sip_has_supported(sip_supported_t const *supported, char const *feature)
+{
+ return sip_has_feature(supported, feature);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_path Path Header
+ *
+ * The Path header field is a SIP extension header field (@RFC3327) with
+ * syntax very similar to the @RecordRoute header field. It is used in
+ * conjunction with SIP REGISTER requests and with 200 class messages in
+ * response to REGISTER (REGISTER responses).
+ *
+ * @code
+ * Path = "Path" HCOLON path-value *(COMMA path-value)
+ * path-value = name-addr *( SEMI rr-param )
+ * @endcode
+ *
+ *
+ * The parsed Path header is stored in #sip_path_t structure.
+ */
+
+/**@ingroup sip_path
+ * @typedef typedef struct sip_route_s sip_path_t;
+ *
+ * The structure #sip_path_t contains representation of SIP @Path header.
+ *
+ * The #sip_path_t is defined as follows:
+ * @code
+ * typedef struct sip_route_s {
+ * sip_common_t r_common[1]; // Common fragment info
+ * sip_path_t *r_next; // Link to next @Path
+ * char const *r_display; // Display name
+ * url_t r_url[1]; // @Path URL
+ * msg_param_t const *r_params; // List of parameters
+ * } sip_path_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_path_class[] =
+SIP_HEADER_CLASS(path, "Path", "", r_params, prepend, any_route);
+
+issize_t sip_path_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ return sip_any_route_d(home, h, s, slen);
+}
+
+issize_t sip_path_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+ assert(sip_is_path(h));
+ return sip_any_route_e(b, bsiz, h, flags);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_service_route Service-Route Header
+ *
+ * The "Service-Route" is a SIP extension header field (@RFC3608), which can
+ * contain a route vector that will direct requests through a specific
+ * sequence of proxies. A registrar may use a Service-Route header field to
+ * inform a UA of a service route that, if used by the UA, will provide
+ * services from a proxy or set of proxies associated with that registrar.
+ * The Service-Route header field may be included by a registrar in the
+ * response to a REGISTER request. The syntax for the Service-Route header
+ * field is:
+ *
+ * @code
+ * Service-Route = "Service-Route" HCOLON sr-value *(COMMA sr-value)
+ * sr-value = name-addr *( SEMI rr-param )
+ * @endcode
+ *
+ * The parsed Service-Route header is stored in #sip_service_route_t structure.
+ *
+ * @sa @RFC3608, @Path, @Route, @RecordRoute
+ */
+
+/**@ingroup sip_service_route
+ * @typedef typedef struct sip_route_s sip_service_route_t;
+ *
+ * The structure #sip_service_route_t contains representation of SIP
+ * @ServiceRoute header.
+ *
+ * The #sip_service_route_t is defined as follows:
+ * @code
+ * typedef struct sip_route_s {
+ * sip_common_t r_common[1]; // Common fragment info
+ * sip_service_route_t*r_next; // Link to next @ServiceRoute
+ * char const *r_display; // Display name
+ * url_t r_url[1]; // Service-Route URL
+ * msg_param_t const *r_params; // List of parameters
+ * } sip_service_route_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_service_route_class[] =
+SIP_HEADER_CLASS(service_route, "Service-Route", "",
+ r_params, append, any_route);
+
+issize_t sip_service_route_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ return sip_any_route_d(home, h, s, slen);
+}
+
+issize_t sip_service_route_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+ assert(sip_is_service_route(h));
+ return sip_any_route_e(b, bsiz, h, flags);
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_header.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_header.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,136 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE sip_header.c
+ *
+ * SIP header handling.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Tue Jun 13 02:57:51 2000 ppessi
+ */
+
+#include "config.h"
+
+/* Avoid casting sip_t to msg_pub_t and sip_header_t to msg_header_t */
+#define MSG_PUB_T struct sip_s
+#define MSG_HDR_T union sip_header_u
+
+/* Get bodies of inlined functions included in library */
+#define SIP_STATIC_INLINE
+
+#include <sofia-sip/su_alloc.h>
+#include "sofia-sip/sip_parser.h"
+#include <sofia-sip/sip_status.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <limits.h>
+#include <stdarg.h>
+
+#include <assert.h>
+
+/** Copy a SIP header.
+ *
+ * @deprecated Use msg_header_copy() instead.
+ */
+sip_header_t *sip_header_copy(su_home_t *home, sip_header_t const *h)
+{
+ if (h == NULL || h == SIP_NONE)
+ return NULL;
+ return msg_header_copy_as(home, h->sh_class, h);
+}
+
+/** Duplicate a SIP header.
+ *
+ * @deprecated Use msg_header_dup() instead.
+ */
+sip_header_t *sip_header_dup(su_home_t *home, sip_header_t const *h)
+{
+ if (h == NULL || h == SIP_NONE)
+ return NULL;
+ return msg_header_dup_as(home, h->sh_class, h);
+
+}
+
+/** Decode a SIP header.
+ *
+ * @deprecated Use msg_header_d() instead.
+ */
+sip_header_t *sip_header_d(su_home_t *home, msg_t const *msg, char const *b)
+{
+ return msg_header_d(home, msg, b);
+}
+
+/** Encode a SIP header.
+ *
+ * @deprecated Use msg_header_e() instead.
+ */
+issize_t sip_header_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+ return msg_header_e(b, bsiz, (msg_header_t const *)h, flags);
+}
+
+sip_header_t *sip_header_format(su_home_t *home,
+ msg_hclass_t *hc,
+ char const *fmt,
+ ...)
+{
+ sip_header_t *h;
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ h = msg_header_vformat(home, hc, fmt, ap);
+
+ va_end(ap);
+
+ return h;
+}
+
+/** Add a duplicate of header object to a SIP message. */
+int sip_add_dup(msg_t *msg,
+ sip_t *sip,
+ sip_header_t const *o)
+{
+ return msg_header_add_dup(msg, (msg_pub_t *)sip, o);
+}
+
+int sip_add_dup_as(msg_t *msg,
+ sip_t *sip,
+ msg_hclass_t *hc,
+ sip_header_t const *o)
+{
+ return msg_header_add_dup_as(msg, (msg_pub_t *)sip, hc, o);
+}
+
+int sip_add_make(msg_t *msg,
+ sip_t *sip,
+ msg_hclass_t *hc,
+ char const *s)
+{
+ return msg_header_add_make(msg, sip, hc, s);
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_mime.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_mime.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,717 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE sip_mime.c
+ *
+ * MIME-related SIP headers
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Tue Jun 13 02:57:51 2000 ppessi
+ */
+
+#include "config.h"
+
+/* Avoid casting sip_t to msg_pub_t and sip_header_t to msg_header_t */
+#define MSG_PUB_T struct sip_s
+#define MSG_HDR_T union sip_header_u
+
+#include "sofia-sip/sip_parser.h"
+#include "sofia-sip/msg_mime_protos.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_accept Accept Header
+ *
+ * The @b Accept request-header field can be used to specify certain media
+ * types which are acceptable for the response. Its syntax is defined in
+ * [H14.1, S10.6] as follows:
+ *
+ * @code
+ * Accept = "Accept" HCOLON
+ * [ accept-range *(COMMA accept-range) ]
+ * accept-range = media-range *(SEMI accept-param)
+ * media-range = ( "*" "/" "*"
+ * / ( m-type SLASH "*" )
+ * / ( m-type SLASH m-subtype )
+ * ) *( SEMI m-parameter )
+ * accept-param = ("q" EQUAL qvalue) / generic-param
+ * qvalue = ( "0" [ "." 0*3DIGIT ] )
+ * / ( "1" [ "." 0*3("0") ] )
+ * generic-param = token [ EQUAL gen-value ]
+ * gen-value = token / host / quoted-string
+ * @endcode
+ *
+ *
+ * The parsed Accept header is stored in #sip_accept_t structure.
+ */
+
+/**@ingroup sip_accept
+ * @typedef typedef struct sip_accept_s sip_accept_t;
+ *
+ * The structure #sip_accept_t contains representation of SIP
+ * @Accept header.
+ *
+ * The #sip_accept_t is defined as follows:
+ * @code
+ * typedef struct sip_accept_s {
+ * sip_common_t ac_common[1]; // Common fragment info
+ * sip_accept_t *ac_next; // Pointer to next @Acceptheader
+ * 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
+ * } sip_accept_t;
+ * @endcode
+ */
+
+#define sip_accept_dup_xtra msg_accept_dup_xtra
+#define sip_accept_dup_one msg_accept_dup_one
+#define sip_accept_update msg_accept_update
+
+msg_hclass_t sip_accept_class[] =
+SIP_HEADER_CLASS(accept, "Accept", "", ac_params, apndlist, accept);
+
+issize_t sip_accept_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ return msg_accept_d(home, h, s, slen);
+}
+
+issize_t sip_accept_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+ return msg_accept_e(b, bsiz, h, flags);
+}
+
+#if SIP_HAVE_ACCEPT_DISPOSITION
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_accept_disposition Accept-Disposition Header
+ *
+ * The Accept-Disposition header field is used to indicate what content
+ * disposition types are acceptable to a client or server. Its syntax is
+ * defined in draft-lennox-sip-reg-payload-01.txt section 3.2 as follows:
+ *
+ * @code
+ * Accept-Disposition = "Accept-Disposition" ":"
+ * #( (disposition-type | "*") *( ";" generic-param ) )
+ * @endcode
+ *
+ *
+ * The parsed Accept-Disposition header
+ * is stored in #sip_accept_disposition_t structure.
+ */
+
+msg_hclass_t sip_accept_disposition_class[] =
+SIP_HEADER_CLASS(accept_disposition, "Accept-Disposition", "",
+ ad_params, apndlist, accept_disposition);
+
+issize_t sip_accept_disposition_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ sip_accept_disposition_t *ad = (sip_accept_disposition_t *)h;
+
+ assert(h);
+
+ /* Ignore empty entries (comma-whitespace) */
+ while (*s == ',')
+ s += span_lws(s + 1) + 1;
+
+ /* "Accept:" #(type/subtyp ; *(parameters))) */
+ if (/* Parse protocol */
+ sip_version_d(&s, &ad->ad_type) == -1 ||
+ (ad->ad_subtype = strchr(ad->ad_type, '/')) == NULL ||
+ (*s == ';' && msg_params_d(home, &s, &ad->ad_params) == -1))
+ return -1;
+
+ if (ad->ad_subtype) ad->ad_subtype++;
+
+ return msg_parse_next_field(home, h, s, slen);
+}
+
+issize_t sip_accept_disposition_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+ char *b0 = b, *end = b + bsiz;
+ sip_accept_disposition_t const *ad = h->sh_accept_disposition;
+
+ MSG_STRING_E(b, end, ad->ad_type);
+ MSG_PARAMS_E(b, end, ad->ad_params, flags);
+ MSG_TERM_E(b, end);
+
+ return b - b0;
+}
+#endif
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_accept_encoding Accept-Encoding Header
+ *
+ * The Accept-Encoding header is similar to Accept, but restricts the
+ * content-codings that are acceptable in the response. Its syntax is
+ * defined in [H14.3, S10.7] as follows:
+ *
+ * @code
+ * Accept-Encoding = "Accept-Encoding" HCOLON
+ * [ encoding *(COMMA encoding) ]
+ * encoding = codings *(SEMI accept-param)
+ * codings = content-coding / "*"
+ * content-coding = token
+ * @endcode
+ *
+ *
+ * The parsed Accept-Encoding header
+ * is stored in #sip_accept_encoding_t structure.
+ */
+
+/**@ingroup sip_accept_encoding
+ * @typedef typedef struct msg_accept_any_s sip_accept_encoding_t;
+ *
+ * The structure #sip_accept_encoding_t contains representation of SIP
+ * @AcceptEncoding header.
+ *
+ * The #sip_accept_encoding_t is defined as follows:
+ * @code
+ * typedef struct {
+ * msg_common_t aa_common[1]; // Common fragment info
+ * sip_accept_encoding_t *aa_next; // Pointer to next @AcceptEncoding header
+ * char const *aa_value; // Encoding token
+ * msg_param_t const *aa_params; // List of parameters
+ * char const *aa_q; // Value of q parameter
+ * } sip_accept_encoding_t;
+ * @endcode
+ */
+
+#define sip_accept_encoding_dup_xtra msg_accept_any_dup_xtra
+#define sip_accept_encoding_dup_one msg_accept_any_dup_one
+#define sip_accept_encoding_update msg_accept_any_update
+
+msg_hclass_t sip_accept_encoding_class[] =
+SIP_HEADER_CLASS(accept_encoding, "Accept-Encoding", "",
+ aa_params, apndlist, accept_encoding);
+
+issize_t sip_accept_encoding_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ issize_t retval = msg_accept_encoding_d(home, h, s, slen);
+
+ if (retval == -2) {
+ /* Empty Accept-Encoding list is not an error */
+ sip_accept_encoding_t *aa = (sip_accept_encoding_t *)h;
+ aa->aa_value = "";
+ retval = 0;
+ }
+
+ return retval;
+}
+
+issize_t sip_accept_encoding_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+ return msg_accept_encoding_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_accept_language Accept-Language Header
+ *
+ * The Accept-Language header can be used to allow the client to indicate to
+ * the server in which language it would prefer to receive reason phrases,
+ * session descriptions or status responses carried as message bodies. Its
+ * syntax is defined in [H14.4, S10.8] as follows:
+ *
+ * @code
+ * Accept-Language = "Accept-Language" HCOLON
+ * [ language *(COMMA language) ]
+ * language = language-range *(SEMI accept-param)
+ * language-range = ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) / "*" )
+ * @endcode
+ *
+ *
+ * The parsed Accept-Language header
+ * is stored in #sip_accept_language_t structure.
+ */
+
+/**@ingroup sip_accept_language
+ * @typedef typedef struct msg_accept_any_s sip_accept_language_t;
+ *
+ * The structure #sip_accept_language_t contains representation of SIP
+ * @AcceptLanguage header.
+ *
+ * The #sip_accept_language_t is defined as follows:
+ * @code
+ * typedef struct {
+ * msg_common_t aa_common[1]; // Common fragment info
+ * sip_accept_language_t *aa_next; // Pointer to next <language>
+ * char const *aa_value; // Language-range
+ * msg_param_t const *aa_params; // List of accept-parameters
+ * char const *aa_q; // Value of q parameter
+ * } sip_accept_language_t;
+ * @endcode
+ */
+
+#define sip_accept_language_dup_xtra msg_accept_any_dup_xtra
+#define sip_accept_language_dup_one msg_accept_any_dup_one
+#define sip_accept_language_update msg_accept_any_update
+
+msg_hclass_t sip_accept_language_class[] =
+SIP_HEADER_CLASS(accept_language, "Accept-Language", "",
+ aa_params, apndlist, accept_language);
+
+issize_t sip_accept_language_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ int retval = msg_accept_language_d(home, h, s, slen);
+
+ if (retval == -2) {
+ /* Empty Accept-Language list is not an error */
+ ((sip_accept_language_t *)h)->aa_value = "";
+ retval = 0;
+ }
+
+ return retval;
+}
+
+issize_t sip_accept_language_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+ return msg_accept_language_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_content_disposition Content-Disposition Header
+ *
+ * The Content-Disposition header field describes how the message body or,
+ * in the case of multipart messages, a message body part is to be
+ * interpreted by the UAC or UAS. Its syntax is defined in @RFC3261
+ * as follows:
+ *
+ * @code
+ * Content-Disposition = "Content-Disposition" HCOLON
+ * disp-type *( SEMI disp-param )
+ * disp-type = "render" / "session" / "icon" / "alert"
+ * / disp-extension-token
+ * disp-param = handling-param / generic-param
+ * handling-param = "handling" EQUAL
+ * ( "optional" / "required"
+ * / other-handling )
+ * other-handling = token
+ * disp-extension-token = token
+ * @endcode
+ *
+ * The Content-Disposition header was extended by
+ * draft-lennox-sip-reg-payload-01.txt section 3.1 as follows:
+ *
+ * @code
+ * Content-Disposition = "Content-Disposition" ":"
+ * disposition-type *( ";" disposition-param )
+ * disposition-type = "script" | "sip-cgi" | token
+ * disposition-param = action-param
+ * | modification-date-param
+ * | generic-param
+ * action-param = "action" "=" action-value
+ * action-value = "store" | "remove" | token
+ * modification-date-param = "modification-date" "=" quoted-date-time
+ * quoted-date-time = <"> SIP-date <">
+ * @endcode
+ *
+ * The parsed Content-Disposition header
+ * is stored in #sip_content_disposition_t structure.
+ */
+
+/**@ingroup sip_content_disposition
+ * @typedef struct msg_content_disposition_s sip_content_disposition_t;
+ *
+ * The structure #sip_content_disposition_t contains representation of an
+ * @ContentDisposition header.
+ *
+ * The #sip_content_disposition_t is defined as follows:
+ * @code
+ * typedef 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
+ * } sip_content_disposition_t;
+ * @endcode
+ */
+
+static msg_xtra_f sip_content_disposition_dup_xtra;
+static msg_dup_f sip_content_disposition_dup_one;
+#define sip_content_disposition_update msg_content_disposition_update
+
+msg_hclass_t sip_content_disposition_class[] =
+SIP_HEADER_CLASS(content_disposition, "Content-Disposition", "", cd_params,
+ single, content_disposition);
+
+issize_t sip_content_disposition_d(su_home_t *home, sip_header_t *h,
+ char *s, isize_t slen)
+{
+ return msg_content_disposition_d(home, h, s, slen);
+}
+
+issize_t sip_content_disposition_e(char b[], isize_t bsiz,
+ sip_header_t const *h, int f)
+{
+ return msg_content_disposition_e(b, bsiz, h, f);
+}
+
+static
+isize_t sip_content_disposition_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+ return msg_content_disposition_dup_xtra(h, offset);
+}
+
+/** Duplicate one #sip_content_disposition_t object */
+static
+char *sip_content_disposition_dup_one(sip_header_t *dst,
+ sip_header_t const *src,
+ char *b, isize_t xtra)
+{
+ return msg_content_disposition_dup_one(dst, src, b, xtra);
+}
+
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_content_encoding Content-Encoding Header
+ *
+ * The Content-Encoding header indicates what additional content codings
+ * have been applied to the entity-body. Its syntax is defined in @RFC3261
+ * as follows:
+ *
+ * @code
+ * Content-Encoding = ( "Content-Encoding" / "e" ) HCOLON
+ * content-coding *(COMMA content-coding)
+ * content-coding = token
+ * @endcode
+ *
+ * The parsed Content-Encoding header
+ * is stored in #sip_content_encoding_t structure.
+ */
+
+/**@ingroup sip_content_encoding
+ * @typedef struct msg_list_s sip_content_encoding_t;
+ *
+ * The structure #sip_content_encoding_t contains representation of an
+ * @ContentEncoding header.
+ *
+ * The #sip_content_encoding_t is defined as follows:
+ * @code
+ * typedef 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
+ * } sip_content_encoding_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_content_encoding_class[] =
+SIP_HEADER_CLASS_LIST(content_encoding, "Content-Encoding", "e", list);
+
+issize_t sip_content_encoding_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ return msg_list_d(home, h, s, slen);
+}
+
+issize_t sip_content_encoding_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+ return msg_list_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_content_language Content-Language Header
+ *
+ * The Content-Language header @RFC2616 section 14.12 describes the natural language(s) of
+ * the intended audience for the enclosed entity. Note that this might not
+ * be equivalent to all the languages used within the entity-body. Its
+ * syntax is defined in @RFC3261 as follows:
+ *
+ * @code
+ * Content-Language = "Content-Language" HCOLON
+ * language-tag *(COMMA language-tag)
+ * language-tag = primary-tag *( "-" subtag )
+ * primary-tag = 1*8ALPHA
+ * subtag = 1*8ALPHA
+ * @endcode
+ *
+ * The parsed Content-Language header
+ * is stored in #sip_content_language_t structure.
+ */
+
+/**@ingroup sip_content_language
+ * @typedef typedef struct msg_content_language_s sip_content_language_t;
+ *
+ * The structure #sip_content_language_t contains representation of
+ * @ContentLanguage header.
+ *
+ * The #sip_content_language_t is defined as follows:
+ * @code
+ * typedef struct {
+ * msg_common_t k_common[1]; // Common fragment info
+ * msg_content_language_t *k_next; // (Content-Encoding header)
+ * msg_param_t *k_items; // List of languages
+ * } sip_content_language_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_content_language_class[] =
+SIP_HEADER_CLASS_LIST(content_language, "Content-Language", "", list);
+
+issize_t sip_content_language_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ return msg_list_d(home, h, s, slen);
+}
+
+issize_t sip_content_language_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+ return msg_list_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_content_type Content-Type Header
+ *
+ * The Content-Type header indicates the media type of the message-body sent
+ * to the recipient. Its syntax is defined in [H3.7, S] as
+ * follows:
+ *
+ * @code
+ * Content-Type = ( "Content-Type" / "c" ) HCOLON media-type
+ * media-type = m-type SLASH m-subtype *(SEMI m-parameter)
+ * m-type = discrete-type / composite-type
+ * discrete-type = "text" / "image" / "audio" / "video"
+ * / "application" / extension-token
+ * composite-type = "message" / "multipart" / extension-token
+ * extension-token = ietf-token / x-token
+ * ietf-token = token
+ * x-token = "x-" token
+ * m-subtype = extension-token / iana-token
+ * iana-token = token
+ * m-parameter = m-attribute EQUAL m-value
+ * m-attribute = token
+ * m-value = token / quoted-string
+ * @endcode
+ *
+ * The parsed Content-Type header is stored in #sip_content_type_t structure.
+ */
+
+/**@ingroup sip_content_type
+ * @typedef typedef struct sip_content_type_s sip_content_type_t;
+ *
+ * The structure #sip_content_type_t contains representation of SIP
+ * @ContentType header.
+ *
+ * The #sip_content_type_t is defined as follows:
+ * @code
+ * typedef struct sip_content_type_s {
+ * sip_common_t c_common[1]; // Common fragment info
+ * sip_unknown_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
+ * } sip_content_type_t;
+ * @endcode
+ *
+ * The whitespace in the @a c_type is always removed when parsing.
+ */
+
+static msg_xtra_f sip_content_type_dup_xtra;
+static msg_dup_f sip_content_type_dup_one;
+#define sip_content_type_update NULL
+
+msg_hclass_t sip_content_type_class[] =
+SIP_HEADER_CLASS(content_type, "Content-Type", "c", c_params,
+ single, content_type);
+
+issize_t sip_content_type_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ sip_content_type_t *c;
+
+ assert(h);
+
+ c = h->sh_content_type;
+
+ /* "Content-type:" type/subtyp *(; parameter))) */
+ if (/* Parse protocol */
+ sip_version_d(&s, &c->c_type) == -1 || /* compacts token / token */
+ (c->c_subtype = strchr(c->c_type, '/')) == NULL ||
+ (*s == ';' && msg_params_d(home, &s, &c->c_params) == -1) ||
+ (*s != '\0'))
+ return -1;
+
+ c->c_subtype++;
+
+ return 0;
+}
+
+issize_t sip_content_type_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+ char *b0 = b, *end = b + bsiz;
+ sip_content_type_t const *c = h->sh_content_type;
+
+ MSG_STRING_E(b, end, c->c_type);
+ MSG_PARAMS_E(b, end, c->c_params, flags);
+ MSG_TERM_E(b, end);
+
+ return b - b0;
+}
+
+static
+isize_t sip_content_type_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+ sip_content_type_t const *c = h->sh_content_type;
+
+ MSG_PARAMS_SIZE(offset, c->c_params);
+ offset += MSG_STRING_SIZE(c->c_type);
+
+ return offset;
+}
+
+/** Duplicate one #sip_content_type_t object */
+static
+char *sip_content_type_dup_one(sip_header_t *dst, sip_header_t const *src,
+ char *b, isize_t xtra)
+{
+ sip_content_type_t *c = dst->sh_content_type;
+ sip_content_type_t const *o = src->sh_content_type;
+ char *end = b + xtra;
+
+ b = msg_params_dup(&c->c_params, o->c_params, b, xtra);
+ MSG_STRING_DUP(b, c->c_type, o->c_type);
+ c->c_subtype = strchr(c->c_type, '/');
+ c->c_subtype++;
+
+ assert(b <= end); (void)end;
+
+ return b;
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_mime_version MIME-Version Header
+ *
+ * MIME-Version header indicates what version of the MIME protocol was used
+ * to construct the message. Its syntax is defined in [H19.4.1, S10.28]
+ * as follows:
+ *
+ * @code
+ * MIME-Version = "MIME-Version" HCOLON 1*DIGIT "." 1*DIGIT
+ * @endcode
+ *
+ * The parsed MIME-Version header is stored in #sip_mime_version_t structure.
+ */
+
+/**@ingroup sip_mime_version
+ * @typedef struct msg_generic_s sip_mime_version_t;
+ *
+ * The structure #sip_mime_version_t contains representation of an
+ * @MIMEVersion header.
+ *
+ * The #sip_mime_version_t is defined as follows:
+ * @code
+ * typedef 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
+ * } sip_mime_version_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_mime_version_class[] =
+SIP_HEADER_CLASS_G(mime_version, "MIME-Version", "", single);
+
+issize_t sip_mime_version_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ return sip_generic_d(home, h, s, slen);
+}
+
+issize_t sip_mime_version_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+ return sip_generic_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_warning Warning Header
+ *
+ * The Warning response-header field is used to carry additional information
+ * about the status of a response. Its syntax is defined in @RFC3261 as
+ * follows:
+ *
+ * @code
+ * Warning = "Warning" HCOLON warning-value *(COMMA warning-value)
+ * warning-value = warn-code SP warn-agent SP warn-text
+ * warn-code = 3DIGIT
+ * warn-agent = hostport / pseudonym
+ * ; the name or pseudonym of the server adding
+ * ; the Warning header, for use in debugging
+ * warn-text = quoted-string
+ * pseudonym = token
+ * @endcode
+ *
+ * The parsed Warning header is stored in #sip_warning_t structure.
+ */
+
+/**@ingroup sip_warning
+ * @typedef struct msg_warning_s sip_warning_t;
+ *
+ * The structure #sip_warning_t contains representation of an
+ * @Warning header.
+ *
+ * The #sip_warning_t is defined as follows:
+ * @code
+ * typedef 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
+ * } sip_warning_t;
+ * @endcode
+ */
+
+#define sip_warning_dup_xtra msg_warning_dup_xtra
+#define sip_warning_dup_one msg_warning_dup_one
+#define sip_warning_update NULL
+
+msg_hclass_t sip_warning_class[] =
+SIP_HEADER_CLASS(warning, "Warning", "", w_common, append, warning);
+
+issize_t sip_warning_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ return msg_warning_d(home, h, s, slen);
+}
+issize_t sip_warning_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+ return msg_warning_e(b, bsiz, h, f);
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_parser.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_parser.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,568 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup sip_parser
+ * @CFILE sip_parser.c
+ *
+ * SIP parser.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Thu Oct 5 14:01:24 2000 ppessi
+ */
+
+#include "config.h"
+
+/* Avoid casting sip_t to msg_pub_t and sip_header_t to msg_header_t */
+#define MSG_PUB_T struct sip_s
+#define MSG_HDR_T union sip_header_u
+
+#include <sofia-sip/su_tagarg.h>
+#include "sofia-sip/sip_parser.h"
+#include <sofia-sip/msg_mclass.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <limits.h>
+
+#ifndef UINT32_MAX
+#define UINT32_MAX (0xffffffffU)
+#endif
+
+/** Version of the SIP module */
+char const sip_parser_version[] = VERSION;
+
+/** SIP version 2.0. */
+char const sip_version_2_0[] = "SIP/2.0";
+
+/** Default message class */
+extern msg_mclass_t sip_mclass[];
+
+msg_mclass_t *sip_default_mclass(void)
+{
+ return sip_mclass;
+}
+
+/** Extract the SIP message body, including separator line.
+ *
+ * @param msg message object [IN]
+ * @param sip public SIP message structure [IN/OUT]
+ * @param b buffer containing unparsed data [IN]
+ * @param bsiz buffer size [IN]
+ * @param eos true if buffer contains whole message [IN]
+ *
+ * @retval -1 error
+ * @retval 0 cannot proceed
+ * @retval m
+ */
+issize_t sip_extract_body(msg_t *msg, sip_t *sip, char b[], isize_t bsiz, int eos)
+{
+ ssize_t m = 0;
+ size_t body_len;
+
+ if (!(sip->sip_flags & MSG_FLG_BODY)) {
+ /* We are looking at a potential empty line */
+ m = msg_extract_separator(msg, (msg_pub_t *)sip, b, bsiz, eos);
+ if (m <= 0)
+ return m;
+ sip->sip_flags |= MSG_FLG_BODY;
+ b += m;
+ bsiz -= m;
+ }
+
+ if (sip->sip_content_length)
+ body_len = sip->sip_content_length->l_length;
+ else if (MSG_IS_MAILBOX(sip->sip_flags)) /* message fragments */
+ body_len = 0;
+ else if (eos)
+ body_len = bsiz;
+ else if (bsiz == 0)
+ return m;
+ else
+ return -1;
+
+ if (body_len == 0) {
+ sip->sip_flags |= MSG_FLG_COMPLETE;
+ return m;
+ }
+
+ if (m)
+ return m;
+
+ if (eos && body_len > bsiz) {
+ sip->sip_flags |= MSG_FLG_TRUNC | MSG_FLG_ERROR;
+ return bsiz;
+ }
+
+ if ((m = msg_extract_payload(msg, (msg_pub_t *)sip,
+ NULL, body_len, b, bsiz, eos)) == -1)
+ return -1;
+
+ sip->sip_flags |= MSG_FLG_FRAGS;
+ if (bsiz >= body_len)
+ sip->sip_flags |= MSG_FLG_COMPLETE;
+
+ return m;
+}
+
+/** Parse SIP version.
+ *
+ * Parse a SIP version string. Update the
+ * pointer at @a ss to first non-LWS character after the version string.
+ *
+ * @param ss string to be parsed [IN/OUT]
+ * @param ver value result for version [OUT]
+ *
+ * @retval 0 when successful,
+ * @retval -1 upon an error.
+ */
+int sip_version_d(char **ss, char const **ver)
+{
+ char *s = *ss;
+ char const *result;
+ size_t const version_size = sizeof(sip_version_2_0) - 1;
+
+ if (strncasecmp(s, sip_version_2_0, version_size) == 0 &&
+ !IS_TOKEN(s[version_size])) {
+ result = sip_version_2_0;
+ s += version_size;
+ }
+ else {
+ /* Version consists of two tokens, separated by / */
+ size_t l1 = 0, l2 = 0, n;
+
+ result = s;
+
+ l1 = span_token(s);
+ for (n = l1; IS_LWS(s[n]); n++);
+ if (s[n] == '/') {
+ for (n++; IS_LWS(s[n]); n++);
+ l2 = span_token(s + n);
+ n += l2;
+ }
+
+ if (l1 == 0 || l2 == 0)
+ return -1;
+
+ /* If there is extra ws between tokens, compact version */
+ if (n > l1 + 1 + l2) {
+ s[l1] = '/';
+ memmove(s + l1 + 1, s + n - l2, l2);
+ s[l1 + 1 + l2] = 0;
+
+ /* Compare again with compacted version */
+ if (strcasecmp(s, sip_version_2_0) == 0)
+ result = sip_version_2_0;
+ }
+
+ s += n;
+ }
+
+ while (IS_WS(*s)) *s++ = '\0';
+
+ *ss = s;
+
+ if (ver)
+ *ver = result;
+
+ return 0;
+}
+
+/** Calculate extra space required by version string */
+isize_t sip_version_xtra(char const *version)
+{
+ if (version == SIP_VERSION_CURRENT)
+ return 0;
+ return MSG_STRING_SIZE(version);
+}
+
+/** Duplicate a transport string */
+void sip_version_dup(char **pp, char const **dd, char const *s)
+{
+ if (s == SIP_VERSION_CURRENT)
+ *dd = s;
+ else
+ MSG_STRING_DUP(*pp, *dd, s);
+}
+
+char const sip_method_name_invite[] = "INVITE";
+char const sip_method_name_ack[] = "ACK";
+char const sip_method_name_cancel[] = "CANCEL";
+char const sip_method_name_bye[] = "BYE";
+char const sip_method_name_options[] = "OPTIONS";
+char const sip_method_name_register[] = "REGISTER";
+char const sip_method_name_info[] = "INFO";
+char const sip_method_name_prack[] = "PRACK";
+char const sip_method_name_update[] = "UPDATE";
+char const sip_method_name_message[] = "MESSAGE";
+char const sip_method_name_subscribe[] = "SUBSCRIBE";
+char const sip_method_name_notify[] = "NOTIFY";
+char const sip_method_name_refer[] = "REFER";
+char const sip_method_name_publish[] = "PUBLISH";
+
+/** Well-known SIP method names. */
+char const * const sip_method_names[] = {
+ "<UNKNOWN>",
+ sip_method_name_invite,
+ sip_method_name_ack,
+ sip_method_name_cancel,
+ sip_method_name_bye,
+ sip_method_name_options,
+ sip_method_name_register,
+ sip_method_name_info,
+ sip_method_name_prack,
+ sip_method_name_update,
+ sip_method_name_message,
+ sip_method_name_subscribe,
+ sip_method_name_notify,
+ sip_method_name_refer,
+ sip_method_name_publish,
+ /* If you add something here, add also them to sip_method_d! */
+ NULL
+};
+
+/** Get canonic method name. */
+char const *sip_method_name(sip_method_t method, char const *name)
+{
+ const size_t N = sizeof(sip_method_names)/sizeof(sip_method_names[0]);
+ if (method > 0 && (size_t)method <= N)
+ return sip_method_names[method];
+ else if (method == 0)
+ return name;
+ else
+ return NULL;
+}
+
+/**Parse a SIP method name.
+ *
+ * Parse a SIP method name and return a code corresponding to the method.
+ * The address of the first non-LWS character after method name is stored in
+ * @a *ss.
+ *
+ * @param ss pointer to pointer to string to be parsed
+ * @param return_name value-result parameter for method name
+ *
+ * @note
+ * If there is no whitespace after method name, the value in @a *return_name
+ * may not be NUL-terminated. The calling function @b must NUL terminate
+ * the value by setting the @a **ss to NUL after first examining its value.
+ *
+ * @return The method code if method
+ * was identified, 0 (sip_method_unknown()) if method is not known, or @c -1
+ * (sip_method_invalid()) if an error occurred.
+ *
+ * If the value-result argument @a return_name is not @c NULL,
+ * a pointer to the method name is stored to it.
+ */
+sip_method_t sip_method_d(char **ss, char const **return_name)
+{
+ char *s = *ss, c = *s;
+ char const *name;
+ int code = sip_method_unknown;
+ size_t n = 0;
+
+#define MATCH(s, m) (strncmp(s, m, n = sizeof(m) - 1) == 0)
+
+ switch (c) {
+ case 'A': if (MATCH(s, "ACK")) code = sip_method_ack; break;
+ case 'B': if (MATCH(s, "BYE")) code = sip_method_bye; break;
+ case 'C':
+ if (MATCH(s, "CANCEL"))
+ code = sip_method_cancel;
+ break;
+ case 'I':
+ if (MATCH(s, "INVITE"))
+ code = sip_method_invite;
+ else if (MATCH(s, "INFO"))
+ code = sip_method_info;
+ break;
+ case 'M': if (MATCH(s, "MESSAGE")) code = sip_method_message; break;
+ case 'N': if (MATCH(s, "NOTIFY")) code = sip_method_notify; break;
+ case 'O': if (MATCH(s, "OPTIONS")) code = sip_method_options; break;
+ case 'P':
+ if (MATCH(s, "PRACK")) code = sip_method_prack;
+ else if (MATCH(s, "PUBLISH")) code = sip_method_publish;
+ break;
+ case 'R':
+ if (MATCH(s, "REGISTER"))
+ code = sip_method_register;
+ else if (MATCH(s, "REFER"))
+ code = sip_method_refer;
+ break;
+ case 'S':
+ if (MATCH(s, "SUBSCRIBE"))
+ code = sip_method_subscribe;
+ break;
+ case 'U':
+ if (MATCH(s, "UPDATE"))
+ code = sip_method_update;
+ break;
+ }
+
+#undef MATCH
+
+ if (IS_NON_WS(s[n]))
+ /* Unknown method */
+ code = sip_method_unknown;
+
+ if (code == sip_method_unknown) {
+ name = s;
+ for (n = 0; IS_UNRESERVED(s[n]); n++)
+ ;
+ if (s[n]) {
+ if (!IS_LWS(s[n]))
+ return sip_method_invalid;
+ if (return_name)
+ s[n++] = '\0';
+ }
+ }
+ else {
+ name = sip_method_names[code];
+ }
+
+ while (IS_LWS(s[n]))
+ n++;
+
+ *ss = (s + n);
+ if (return_name) *return_name = name;
+
+ return code;
+}
+
+/** Get method enum corresponding to method name */
+sip_method_t sip_method_code(char const *name)
+{
+ /* Note that sip_method_d() does not change string if return_name is NULL */
+ return sip_method_d((char **)&name, NULL);
+}
+
+char const sip_transport_udp[] = "SIP/2.0/UDP";
+char const sip_transport_tcp[] = "SIP/2.0/TCP";
+char const sip_transport_sctp[] = "SIP/2.0/SCTP";
+char const sip_transport_tls[] = "SIP/2.0/TLS";
+
+/** Decode transport */
+issize_t sip_transport_d(char **ss, char const **ttransport)
+{
+ char const *transport;
+ char *pn, *pv, *pt;
+ size_t pn_len, pv_len, pt_len;
+ char *s = *ss;
+
+#define TRANSPORT_MATCH(t) \
+ (strncasecmp(s+7, t+7, sizeof(t)-8) == 0 && (IS_LWS(s[sizeof(t)])) \
+ && (transport = t, s += sizeof(t) - 1))
+
+ if (strncasecmp(s, "SIP/2.0", 7) != 0 ||
+ (!TRANSPORT_MATCH(sip_transport_udp) &&
+ !TRANSPORT_MATCH(sip_transport_tcp) &&
+ !TRANSPORT_MATCH(sip_transport_sctp) &&
+ !TRANSPORT_MATCH(sip_transport_tls))) {
+ /* Protocol name */
+ transport = pn = s;
+ skip_token(&s);
+ pn_len = s - pn;
+ skip_lws(&s);
+ if (pn_len == 0 || *s++ != '/') return -1;
+ skip_lws(&s);
+
+ /* Protocol version */
+ pv = s;
+ skip_token(&s);
+ pv_len = s - pv;
+ skip_lws(&s);
+ if (pv_len == 0 || *s++ != '/') return -1;
+ skip_lws(&s);
+
+ /* Transport protocol */
+ pt = s;
+ skip_token(&s);
+ pt_len = s - pt;
+ if (pt_len == 0) return -1;
+
+ /* Remove whitespace between protocol name and version */
+ if (pn + pn_len + 1 != pv) {
+ pn[pn_len] = '/';
+ pv = memmove(pn + pn_len + 1, pv, pv_len);
+ }
+
+ /* Remove whitespace between protocol version and transport */
+ if (pv + pv_len + 1 != pt) {
+ pv[pv_len] = '/';
+ pt = memmove(pv + pv_len + 1, pt, pt_len);
+ pt[pt_len] = '\0';
+
+ /* extra whitespace? */
+ if (!strcasecmp(transport, sip_transport_udp))
+ transport = sip_transport_udp;
+ else if (!strcasecmp(transport, sip_transport_tcp))
+ transport = sip_transport_tcp;
+ else if (!strcasecmp(transport, sip_transport_sctp))
+ transport = sip_transport_sctp;
+ else if (!strcasecmp(transport, sip_transport_tls))
+ transport = sip_transport_tls;
+ }
+ }
+
+ if (IS_LWS(*s)) { *s++ = '\0'; skip_lws(&s); }
+ *ss = s;
+ *ttransport = transport;
+ return 0;
+}
+
+/** Calculate extra space required by sip_transport_dup() */
+isize_t sip_transport_xtra(char const *transport)
+{
+ if (transport == sip_transport_udp ||
+ transport == sip_transport_tcp ||
+ transport == sip_transport_sctp ||
+ transport == sip_transport_tls ||
+ strcasecmp(transport, sip_transport_udp) == 0 ||
+ strcasecmp(transport, sip_transport_tcp) == 0 ||
+ strcasecmp(transport, sip_transport_sctp) == 0 ||
+ strcasecmp(transport, sip_transport_tls) == 0)
+ return 0;
+
+ return MSG_STRING_SIZE(transport);
+}
+
+/** Duplicate a transport string */
+void sip_transport_dup(char **pp, char const **dd, char const *s)
+{
+ if (s == sip_transport_udp)
+ *dd = s;
+ else if (s == sip_transport_tcp)
+ *dd = s;
+ else if (s == sip_transport_sctp)
+ *dd = s;
+ else if (s == sip_transport_tls)
+ *dd = s;
+ else if (strcasecmp(s, sip_transport_udp) == 0)
+ *dd = sip_transport_udp;
+ else if (strcasecmp(s, sip_transport_tcp) == 0)
+ *dd = sip_transport_tcp;
+ else if (strcasecmp(s, sip_transport_sctp) == 0)
+ *dd = sip_transport_sctp;
+ else if (strcasecmp(s, sip_transport_tls) == 0)
+ *dd = sip_transport_tls;
+ else
+ MSG_STRING_DUP(*pp, *dd, s);
+}
+
+/** Parse SIP <word "@" word> construct used in @CallID. */
+char *sip_word_at_word_d(char **ss)
+{
+ char *rv = *ss, *s0 = *ss;
+
+ skip_word(ss);
+ if (s0 == *ss)
+ return NULL;
+ if (**ss == '@') {
+ (*ss)++;
+ s0 = *ss;
+ skip_word(ss);
+ if (s0 == *ss)
+ return NULL;
+ }
+ if (IS_LWS(**ss))
+ (*ss)++;
+ skip_lws(ss);
+
+ return rv;
+}
+
+/**Add message separator, then test if message is complete.
+ *
+ * Add sip_content_length and sip_separator if they are missing.
+ * The test that all necessary message components ( @From, @To,
+ * @CSeq, @CallID, @ContentLength and message separator are present.
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error: headers are missing and they could not be added
+ */
+int sip_complete_message(msg_t *msg)
+{
+ sip_t *sip = sip_object(msg);
+ su_home_t *home = msg_home(msg);
+ size_t len = 0;
+ ssize_t mplen;
+
+ if (sip == NULL)
+ return -1;
+
+ if (!sip->sip_separator)
+ sip->sip_separator = sip_separator_create(msg_home(msg));
+
+ if (sip->sip_multipart) {
+ sip_content_type_t *c = sip->sip_content_type;
+ msg_multipart_t *mp = sip->sip_multipart;
+ sip_common_t *head;
+
+ if (!c || msg_multipart_complete(msg_home(msg), c, mp) < 0)
+ return -1;
+
+ if (sip->sip_payload)
+ head = sip->sip_payload->pl_common;
+ else
+ head = sip->sip_separator->sep_common;
+
+ if (!head || !msg_multipart_serialize(&head->h_succ, mp))
+ return -1;
+
+ mplen = msg_multipart_prepare(msg, mp, sip->sip_flags);
+ if (mplen == -1)
+ return -1;
+ len = (size_t)mplen;
+ }
+
+ if (sip->sip_payload)
+ len += sip->sip_payload->pl_len;
+
+ if (len > UINT32_MAX)
+ return -1;
+
+ if (!sip->sip_content_length) {
+ msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t*)
+ sip_content_length_create(home, (uint32_t)len));
+ }
+ else {
+ if (sip->sip_content_length->l_length != len) {
+ sip->sip_content_length->l_length = (uint32_t)len;
+ sip_fragment_clear(sip->sip_content_length->l_common);
+ }
+ }
+
+ if (!sip->sip_cseq ||
+ !sip->sip_call_id ||
+ !sip->sip_to ||
+ !sip->sip_from ||
+ !sip->sip_separator ||
+ !sip->sip_content_length)
+ return -1;
+
+ return 0;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_parser.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_parser.docs Thu Dec 21 01:30:28 2006
@@ -0,0 +1,91 @@
+/* -*- c -*- */
+
+/**@page sip_parser SIP Parser
+ *
+ * This part of the Sofia documentation describes the internal working of
+ * SIP parser. It documents the internal functions and macros used when a
+ * new parser is added.
+ *
+ * The @b sip module contains interface to the SIP headers and message
+ * objects. The interface is abstracted using objects known as
+ * @ref msg_hclass_s "header classes" and @ref msg_mclass_s "message classes".
+ *
+ * The @ref msg_mclass_s "message class" defines how a message is handled:
+ * parsed and encoded. It contains a parser table with references to header
+ * classes. It also contains function pointers used by the parser to handle
+ * message body and other details that vary between protocols.
+ *
+ * A @ref msg_hclass_s "header class" defines how a single header is parsed.
+ * Each header has its own header class. There are also header classes for
+ * message elements that are not really headers, like @ref sip_request
+ * "request" and @ref sip_status "status line",
+ * @ref sip_separator "separator between headers" and
+ * @ref sip_payload "message body"
+ * (which is also known as payload). There is also a header classes
+ * for @ref sip_unknown "unknown headers" and
+ * @ref sip_error "headers that contained parsing errors".
+ *
+ *
+ * @section sip_add_headers Adding Headers to Parser
+ *
+ * Sofia SIP Parser can be extended easily, either by application or by
+ * internally extending the sofia-sip library itself.
+ *
+ * Create a header template for your header just like sip_rfc2543.h.in,
+ * e.g, sip_example.h.in:
+ *
+ *@code
+/**@file sip_example.h.in
+ *
+ * Template for <sofia-sip/sip_example.h>.
+ */
+
+#ifndef SIP_EXAMPLE_H
+/** Defined when <sofia-sip/sip_example.h> has been included. */
+#define SIP_EXAMPLE_H
+
+/**@file sofia-sip/sip_example.h
+*
+ * @brief Example header.
+ *
+ * #AUTO#
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Fri May 27 18:40:38 EEST 2005 ppessi
+ */
+
+#ifndef SIP_H
+#include <sip.h>
+#endif
+
+/**@ingroup sip_also
+ * @brief Structure for @b Also header.
+ */
+struct sip_also_s
+{
+ sip_common_t also_common[1]; /**< Common fragment info */
+ sip_also_t *also_next; /**< Link to next Also header */
+ char const *also_display; /**< Display name */
+ url_t also_url[1]; /**< URL */
+};
+
+typedef struct sip_also_s sip_also_t;
+typedef sip_generic_t sip_hide_t;
+typedef sip_auth_t sip_encryption_t;
+typedef sip_auth_t sip_response_key_t;
+
+struct sip_example_dummy_structure {
+ /* === Headers start here */
+ sip_also_t *sip_also; /**< Also */
+ sip_hide_t *sip_hide; /**< Hide */
+ sip_encryption_t *sip_encryption; /**< Encryption */
+ sip_response_key_t *sip_response_key; /**< Response-Key */
+ /* === Headers end here */
+};
+
+
+#endif /** !defined(SIP_EXAMPLE_H) */
+--->8---->8---->8---->8---->8---->8---->8---->8---->8---->8---->8---->8---
+ * @endcode
+ */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_parser_table.c.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_parser_table.c.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1,56 @@
+/**@IFILE sip_parser_table.c.in
+ *
+ * Template for <sip_parser_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 at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE sip_parser_table.c
+ * @brief SIP parser table
+ *
+ * #AUTO#
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Tue Oct 1 20:28:59 2002 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <string.h>
+
+/* Avoid casting sip_t to msg_pub_t and sip_header_t to msg_header_t */
+#define MSG_PUB_T struct sip_s
+#define MSG_HDR_T union sip_header_u
+
+#include <sofia-sip/sip_parser.h>
+#include <sofia-sip/sip_extra.h>
+#include <sofia-sip/msg_mclass.h>
+
+
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_prack.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_prack.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,203 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE sip_prack.c
+ * @brief SIP headers for Prack.
+ *
+ * The file @b sip_prack.c contains implementation of header classes for
+ * PRACK-related SIP headers @RAck and @RSeq.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Thu Sep 13 21:24:15 EEST 2001 ppessi
+ */
+
+#include "config.h"
+
+/* Avoid casting sip_t to msg_pub_t and sip_header_t to msg_header_t */
+#define MSG_PUB_T struct sip_s
+#define MSG_HDR_T union sip_header_u
+
+#include "sofia-sip/sip_parser.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_rack RAck Header
+ *
+ * The RAck header indicates the sequence number of the provisional response
+ * which is being acknowledged. Its syntax is defined in
+ * @RFC3262 section 10 as follows:
+ *
+ * @code
+ * RAck = "RAck" HCOLON response-num LWS CSeq-num LWS Method
+ * response-num = 1*DIGIT
+ * CSeq-num = 1*DIGIT
+ * @endcode
+ *
+ * @sa @RFC3262, nta_outgoing_prack(), nta_reliable_treply(),
+ * nta_reliable_mreply().
+ *
+ * The parsed RAck header is stored in #sip_rack_t structure.
+ */
+
+/**@ingroup sip_rack
+ * @typedef struct sip_rack_s sip_rack_t;
+ *
+ * The structure #sip_rack_t contains representation of an @RAck header.
+ *
+ * The #sip_rack_t is defined as follows:
+ * @code
+ * typedef struct sip_rack_s
+ * {
+ * sip_common_t ra_common; // Common fragment info
+ * sip_error_t *ra_next; // Dummy link to next
+ * uint32_t ra_response; // Sequence number of response
+ * uint32_t ra_cseq; // Sequence number of request
+ * sip_method_t ra_method; // Original request method
+ * char const *ra_method_name; // Original request method name
+ * } sip_rack_t;
+ * @endcode
+ */
+
+static msg_xtra_f sip_rack_dup_xtra;
+static msg_dup_f sip_rack_dup_one;
+#define sip_rack_update NULL
+
+msg_hclass_t sip_rack_class[] =
+SIP_HEADER_CLASS(rack, "RAck", "", ra_common, single, rack);
+
+issize_t sip_rack_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ sip_rack_t *ra = h->sh_rack;
+
+ ra->ra_response = strtoul(s, &s, 10);
+
+ if (IS_LWS(*s)) {
+ skip_lws(&s);
+ ra->ra_cseq = strtoul(s, &s, 10);
+
+ if (IS_LWS(*s)) {
+ skip_lws(&s);
+ if ((ra->ra_method = sip_method_d(&s, &ra->ra_method_name)) >= 0) {
+ return 0;
+ }
+ }
+ }
+
+ return -1;
+}
+
+issize_t sip_rack_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+ sip_rack_t const *ra = h->sh_rack;
+
+ assert(sip_is_rack(h));
+
+ return snprintf(b, bsiz, "%u %u %s",
+ ra->ra_response, ra->ra_cseq, ra->ra_method_name);
+}
+
+isize_t sip_rack_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+ sip_rack_t const *ra = h->sh_rack;
+
+ if (ra->ra_method == sip_method_unknown)
+ return offset + MSG_STRING_SIZE(ra->ra_method_name);
+ else
+ return offset;
+}
+
+/** Duplicate one #sip_rack_t object */
+char *sip_rack_dup_one(sip_header_t *dst, sip_header_t const *src,
+ char *b, isize_t xtra)
+{
+ sip_rack_t *ra_dst = dst->sh_rack;
+ sip_rack_t const *ra_src = src->sh_rack;
+
+ char *end = b + xtra;
+
+ ra_dst->ra_response = ra_src->ra_response;
+ ra_dst->ra_cseq = ra_src->ra_cseq;
+ ra_dst->ra_method = ra_src->ra_method;
+
+ if (ra_src->ra_method == sip_method_unknown)
+ MSG_STRING_DUP(b, ra_dst->ra_method_name, ra_src->ra_method_name);
+ else
+ ra_dst->ra_method_name = ra_src->ra_method_name;
+
+ assert(b <= end); (void)end;
+
+ return b;
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_rseq RSeq Header
+ *
+ * The RSeq header identifies provisional responses within a transaction.
+ * Its syntax is defined in @RFC3262 section 10 as follows:
+ *
+ * @code
+ * RSeq = "RSeq" HCOLON response-num
+ * response-num = 1*DIGIT
+ * @endcode
+ *
+ * The parsed RSeq header is stored in #sip_rseq_t structure.
+ */
+
+/**@ingroup sip_rseq
+ * @typedef struct sip_rseq_s sip_rseq_t;
+ *
+ * The structure #sip_rseq_t contains representation of an @RSeq header.
+ *
+ * The #sip_rseq_t is defined as follows:
+ * @code
+ * typedef struct sip_rseq_s
+ * {
+ * sip_common_t rs_common; // Common fragment info
+ * sip_error_t *rs_next; // Dummy link to next
+ * uint32_t rs_response; // Sequence number of response
+ * } sip_rseq_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_rseq_class[] =
+SIP_HEADER_CLASS(rseq, "RSeq", "", rs_common, single, any);
+
+issize_t sip_rseq_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ return msg_numeric_d(home, h, s, slen);
+}
+
+issize_t sip_rseq_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+ assert(sip_is_rseq(h));
+ return msg_numeric_e(b, bsiz, h, f);
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_pref_util.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_pref_util.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,559 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE sip_pref_util.c
+ *
+ * SIP callercaps and callerprefs utility functions.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Tue Nov 2 16:39:33 EET 2004 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <float.h>
+
+#include "sofia-sip/sip_parser.h"
+#include <sofia-sip/sip_header.h>
+#include <sofia-sip/sip_util.h>
+#include <sofia-sip/sip_status.h>
+
+/** Parse a single preference */
+int sip_prefs_parse(union sip_pref *sp,
+ char const **in_out_s,
+ int *return_negation)
+{
+ char const *s;
+ size_t n;
+ enum sp_type old_type;
+
+ assert(sp && in_out_s && *in_out_s && return_negation);
+
+ old_type = sp->sp_type;
+ sp->sp_type = sp_error;
+
+ s = *in_out_s;
+ if (!s)
+ return 0;
+
+ if (old_type == sp_init) {
+ if (s[0] == '\0' ||
+ strcasecmp(s, "TRUE") == 0 ||
+ strcasecmp(s, "\"TRUE\"") == 0) {
+ /* Boolean */
+ sp->sp_type = sp_literal;
+ sp->sp_literal.spl_value = "TRUE";
+ sp->sp_literal.spl_length = 4;
+ *return_negation = 0;
+ *in_out_s = s + strlen(s);
+ return 1;
+ } else if (strcasecmp(s, "FALSE") == 0 ||
+ strcasecmp(s, "\"FALSE\"") == 0) {
+ /* Boolean */
+ sp->sp_type = sp_literal;
+ sp->sp_literal.spl_value = "FALSE";
+ sp->sp_literal.spl_length = 5;
+ *return_negation = 0;
+ *in_out_s = s + strlen(s);
+ return 1;
+ } else if (s[0] == '"' && s[1] != '\0') {
+ for (s++; IS_LWS(s[0]); s++);
+ } else
+ old_type = sp_error;
+ } else if (!s[0]) {
+ sp->sp_type = sp_init;
+ return 0;
+ }
+
+ if (old_type == sp_error)
+ return 0;
+
+ if ((*return_negation = s[0] == '!'))
+ for (s++; IS_LWS(s[0]); s++);
+
+ if (*s == '#') {
+ /* Numeric */
+ double n1, n2;
+ char s0, *e;
+
+ for (s++; IS_LWS(s[0]); s++);
+
+ s0 = s[0];
+
+ if (s0 == '=')
+ sp->sp_type = sp_range, n1 = n2 = strtod(s = s + 1, &e);
+ else if (s0 == '<' && s[1] == '=')
+ sp->sp_type = sp_range, n1 = DBL_MIN, n2 = strtod(s = s + 2, &e);
+ else if (s0 == '>' && s[1] == '=')
+ sp->sp_type = sp_range, n1 = strtod(s = s + 2, &e), n2 = DBL_MAX;
+ else if (((n1 = strtod(s, &e)) != 0.0 || s != e) && e[0] == ':')
+ sp->sp_type = sp_range, n2 = strtod(s = e + 1, &e);
+ else
+ /* Error in conversion */
+ sp->sp_type = sp_error, n1 = DBL_MAX, n2 = DBL_MIN;
+
+ if (s == e && (n1 == 0.0 || n2 == 0.0))
+ sp->sp_type = sp_error; /* Error in conversion */
+
+ sp->sp_range.spr_lower = n1;
+ sp->sp_range.spr_upper = n2;
+
+ s = e;
+ } else if (*s == '<') {
+ /* Quoted string */
+ n = strcspn(++s, ">");
+ sp->sp_type = sp_string;
+ sp->sp_string.sps_value = s;
+ sp->sp_string.sps_length = n;
+ s += n + 1;
+ } else if ((n = span_token(s))) {
+ /* Literal */
+ sp->sp_type = sp_literal;
+ sp->sp_literal.spl_value = s;
+ sp->sp_literal.spl_length = n;
+ s += n;
+ }
+
+ for (; IS_LWS(s[0]); s++);
+
+ if (s[0] == ',' || (s[0] == '"' && s[1] == '\0'))
+ for (s++; IS_LWS(s[0]); s++);
+ else
+ old_type = sp_error;
+
+ if (old_type != sp_init && old_type != sp->sp_type)
+ sp->sp_type = sp_error;
+
+ *in_out_s = s;
+
+ return sp->sp_type != sp_error;
+}
+
+/** Return true if preferences match */
+int sip_prefs_match(union sip_pref const *a,
+ union sip_pref const *b)
+{
+ if (!a || !b)
+ return 0;
+ if (a->sp_type != b->sp_type)
+ return 0;
+ switch (a->sp_type) {
+ default:
+ case sp_error:
+ return 0;
+ case sp_literal:
+ return
+ a->sp_literal.spl_length == b->sp_literal.spl_length &&
+ strncasecmp(a->sp_literal.spl_value, b->sp_literal.spl_value,
+ a->sp_literal.spl_length) == 0;
+ case sp_string:
+ return
+ a->sp_string.sps_length == b->sp_string.sps_length &&
+ strncmp(a->sp_string.sps_value, b->sp_string.sps_value,
+ a->sp_string.sps_length) == 0;
+ case sp_range:
+ return
+ a->sp_range.spr_lower <= b->sp_range.spr_upper &&
+ a->sp_range.spr_upper >= b->sp_range.spr_lower;
+ }
+}
+
+/**Find a matching parameter-value pair from a parameter list.
+ *
+ * Check if the given feature values match with each other.
+ *
+ * @param pvalue first feature parameter
+ * @param nvalue second feature parameter
+ * @param return_parse_error return-value parameter for error (may be NULL)
+ *
+ * @retval 1 if given feature parameters match
+ * @retval 0 if there is no match or a parse or type error occurred.
+ *
+ * If there is a parsing or type error, 0 is returned and @a
+ * *return_parse_error is set to -1.
+ *
+ * @sa sip_prefs_parse(), sip_prefs_match(), union #sip_pref.
+ */
+int sip_prefs_matching(char const *pvalue,
+ char const *nvalue,
+ int *return_parse_error)
+{
+ int error;
+ char const *p;
+ union sip_pref np[1], pp[1];
+ int n_negated, p_negated;
+
+ if (!return_parse_error)
+ return_parse_error = &error;
+
+ if (!pvalue || !nvalue)
+ return 0;
+
+ memset(np, 0, sizeof np);
+
+ /* Usually nvalue is from Accept/Reject-Contact,
+ pvalue is from Contact */
+ while (sip_prefs_parse(np, &nvalue, &n_negated)) {
+ memset(pp, 0, sizeof pp);
+ p = pvalue;
+
+ while (sip_prefs_parse(pp, &p, &p_negated)) {
+ if (pp->sp_type != np->sp_type) /* Types do not match */
+ return 0;
+
+ if (sip_prefs_match(np, pp) /* We found matching value */
+ ? !p_negated /* without negative */
+ : p_negated) /* Negative did not match */
+ break;
+ }
+
+ if (pp->sp_type == sp_error)
+ return *return_parse_error = -1, 0;
+
+ if (pp->sp_type != sp_init /* We found matching value */
+ ? !n_negated /* and we expected one */
+ : n_negated) /* We found none and expected none */
+ return 1;
+ }
+
+ if (np->sp_type == sp_error)
+ *return_parse_error = -1;
+
+ return 0;
+}
+
+/** Check if the parameter is a valid feature tag.
+ *
+ * A feature tag is a parameter starting with a single plus, or a well-known
+ * feature tag listed in @RFC3841: "audio", "automata", "application",
+ * "class", "control", "duplex", "data", "description", "events", "isfocus",
+ * "language", "mobility", "methods", "priority", "schemes", "type", or
+ * "video". However, well-known feature tag can not start with plus. So,
+ * "+alarm" or "audio" is a feature tag, "alarm", "++alarm", or "+audio" are
+ * not.
+ *
+ * @retval 1 if string is a feature tag parameter
+ * @retval 0 otherwise
+ */
+int sip_is_callerpref(char const *param)
+{
+#define MATCH(s) \
+ (strncasecmp(param + 1, s + 1, strlen(s) - 1) == 0 && \
+ (param[strlen(s)] == '=' || param[strlen(s)] == '\0'))
+
+ int xor = 0, base = 0;
+
+ if (!param || !param[0])
+ return 0;
+
+ if (param[0] == '+')
+ param++, xor = 1;
+
+ switch (param[0]) {
+ case 'a': case 'A':
+ base = MATCH("audio") || MATCH("automata") || MATCH("application") ||
+ MATCH("actor");
+ break;
+ case 'c': case 'C':
+ base = MATCH("class") || MATCH("control");
+ break;
+ case 'd': case 'D':
+ base = MATCH("duplex") || MATCH("data") || MATCH("description");
+ break;
+ case 'e': case 'E':
+ base = MATCH("events");
+ break;
+ case 'i': case 'I':
+ base = MATCH("isfocus");
+ break;
+ case 'l': case 'L':
+ base = MATCH("language");
+ break;
+ case 'm': case 'M':
+ base = MATCH("mobility") || MATCH("methods");
+ break;
+ case 'p': case 'P':
+ base = MATCH("priority");
+ break;
+ case 's': case 'S':
+ base = MATCH("schemes");
+ break;
+ case 't': case 'T':
+ base = MATCH("type");
+ break;
+ case 'v': case 'V':
+ base = MATCH("video");
+ break;
+ default:
+ base = 0;
+ break;
+ }
+#undef MATCH
+
+ return base ^ xor;
+}
+
+/** Check if @Contact is immune to callerprefs. */
+int sip_contact_is_immune(sip_contact_t const *m)
+{
+ unsigned i;
+
+ if (m->m_params)
+ for (i = 0; m->m_params[i]; i++) {
+ if (sip_is_callerpref(m->m_params[i]))
+ return 0;
+ }
+
+ return 1;
+}
+
+/**Check if @Contact matches by @AcceptContact.
+ *
+ * Matching @AcceptContact and @Contact headers is done as explained in
+ * @RFC3841 section 7.2.4. The caller score can be calculated from the
+ * returned S and N values.
+ *
+ * @par Matching
+ * The @AcceptContact header contains number of feature tag parameters. The
+ * count of feature tags is returned in @a return_N. For each feature tag in
+ * @AcceptContact, the feature tag with same name is searched from the
+ * @Contact header. If both headers contain the feature tag with same name,
+ * their values are compared. If the value in @AcceptContact does not match
+ * with the value in @Contact, there is mismatch and 0 is returned. If they
+ * match, S is increased by 1.
+ *
+ * @param m pointer to @Contact header structure
+ * @param cp pointer to @AcceptContact header structure
+ * @param return_N return-value parameter for number of
+ * feature tags in @AcceptContact
+ * @param return_S return-value parameter for number of
+ * matching feature tags
+ * @param return_error return-value parameter for parsing error
+ *
+ * For example,
+ * @code
+ * if (sip_contact_accept(contact, accept_contact, &S, &N, &error)) {
+ * if (N == 0)
+ * score == 1.0;
+ * else
+ * score = (double)S / (double)N;
+ * if (accept_contact->cp_explicit) {
+ * if (accept_contact->cp_require)
+ * goto drop;
+ * else
+ * score = 0.0;
+ * }
+ * }
+ * else if (!error) {
+ * score = 0.0;
+ * }
+ * @endcode
+ *
+ * @retval 1 if @Contact matches
+ * @return @a return_S contains number of matching feature tags
+ * @return @a return_N contains number of feature tags in @AcceptContact
+ * @retval 0 if @Contact does not match
+ * @return @a return_error contains -1 if feature tag value was malformed
+ *
+ * @sa @RFC3841 section 7.2.4, sip_contact_score(), sip_contact_reject(),
+ * sip_contact_is_immune(), sip_contact_immunize(), sip_is_callerpref(),
+ * sip_prefs_matching().
+ */
+int sip_contact_accept(sip_contact_t const *m,
+ sip_accept_contact_t const *cp,
+ unsigned *return_S,
+ unsigned *return_N,
+ int *return_error)
+{
+ char const *cap, *acc;
+ unsigned i, S, N;
+ size_t eq;
+
+ if (!return_N) return_N = &N;
+ if (!return_S) return_S = &S;
+
+ *return_S = 0, *return_N = 0;
+
+ if (!m || !cp || !m->m_params || !cp->cp_params)
+ return 1;
+
+ for (i = 0, S = 0, N = 0; cp->cp_params[i]; i++) {
+ acc = cp->cp_params[i];
+ if (!sip_is_callerpref(acc))
+ continue;
+
+ N++;
+
+ cap = msg_params_find(m->m_params, acc);
+
+ if (cap) {
+ eq = strcspn(acc, "=");
+ acc += eq + (acc[eq] == '=');
+
+ if (!sip_prefs_matching(cap, acc, return_error))
+ return 0;
+
+ S++;
+ }
+ }
+
+ *return_S = S; /* Matched feature tags */
+ *return_N = N; /* Number of feature tags in @AcceptContact */
+
+ return 1;
+}
+
+
+/** Check if @Contact is rejected by @RejectContact.
+ *
+ * @param m pointer to @Contact header
+ * @param reject pointer to @RejectContact header
+ *
+ * @retval 1 when rejecting
+ * @retval 0 when @Contact does not match with @RejectContact
+ *
+ * @sa sip_contact_score(), sip_contact_accept(), sip_contact_immunize(),
+ * sip_contact_is_immune(), @RFC3841, @RejectContact, @Contact
+ */
+int sip_contact_reject(sip_contact_t const *m,
+ sip_reject_contact_t const *reject)
+{
+ unsigned S, N;
+ int error;
+
+ if (!m || !m->m_params || !reject || !reject->cp_params)
+ return 0;
+
+ return sip_contact_accept(m, reject, &S, &N, &error) && S == N && N > 0;
+}
+
+/**Immunize @Contact to callerprefs.
+ *
+ * Make a copy of @Contact header @a m and remove all parameters which
+ * affect caller preferences.
+ *
+ * @param home home object used when allocating copy
+ * @param m pointer to @Contact header structure to immunize
+ *
+ * @retval pointer to immunized copy if successful
+ * @retval NULL upon an error
+ *
+ * @sa @RFC3841, sip_is_callerpref(), sip_contact_score(),
+ * sip_contact_accept(), sip_contact_reject(), @Contact
+ */
+sip_contact_t *sip_contact_immunize(su_home_t *home, sip_contact_t const *m)
+{
+ unsigned i, j;
+ sip_contact_t m0[1], *m1;
+ msg_param_t *params;
+
+ if (!m)
+ return NULL;
+
+ *m0 = *m, m0->m_next = NULL;
+
+ m1 = sip_contact_copy(home, m0);
+
+ if (m1 == NULL || !m1->m_params)
+ return m1;
+
+ params = (msg_param_t *)m1->m_params;
+
+ for (i = 0, j = 0; params[i]; i++) {
+ if (!sip_is_callerpref(params[i]))
+ params[j++] = params[i];
+ }
+
+ params[j] = NULL;
+
+ return m1;
+}
+
+/** Calculate score for contact.
+ *
+ * The caller preference score is an integer in range of 0 to 1000.
+ *
+ * @retval -1 if the contact is rejected
+ * @retval 1000 if contact is immune to caller preferences
+ * @retval 0..1000 reflecting @RFC3481 score in 0.000 - 1.000.
+ *
+ * @sa sip_q_value(),
+ * sip_contact_accept(), sip_contact_reject(), sip_contact_is_immune(),
+ * sip_contact_immunize(), sip_is_callerpref(), sip_prefs_matching(),
+ * @RFC3481, @AcceptContact, @RejectContact, @Contact
+ */
+int sip_contact_score(sip_contact_t const *m,
+ sip_accept_contact_t const *ac,
+ sip_reject_contact_t const *rc)
+{
+ unsigned long S_total = 0;
+ unsigned M = 0, scale = 1000;
+ int error = 0;
+
+ if (sip_contact_is_immune(m))
+ return 1000; /* Immune */
+
+ for (; rc; rc = rc->cp_next)
+ if (sip_contact_reject(m, rc))
+ break;
+ if (rc)
+ return -1; /* Rejected */
+
+ for (; ac; ac = ac->cp_next) {
+ unsigned S, N;
+
+ if (!sip_contact_accept(m, ac, &S, &N, &error)) {
+ if (ac->cp_require)
+ return 0; /* Discarded */
+ continue;
+ }
+
+ M++;
+
+ /* Apply score */
+ if (S < N && ac->cp_explicit) {
+ S = 0;
+ if (ac->cp_require)
+ return 0; /* Dropped */
+ }
+
+ if (S > 0 && N > 0)
+ S_total += sip_q_value(ac->cp_q) * (scale * S / N + (2 * S >= N));
+ }
+
+ if (!M)
+ return 0;
+
+ S_total /= M;
+
+ if (S_total < scale * 1000)
+ return S_total / scale;
+ else
+ return 1000;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_reason.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_reason.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,172 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE sip_reason.c
+ * @brief @Reason header.
+ *
+ * The file @b sip_reason.c contains implementation of header class for
+ * SIP header @Reason.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ */
+
+#include "config.h"
+
+/* Avoid casting sip_t to msg_pub_t and sip_header_t to msg_header_t */
+#define MSG_PUB_T struct sip_s
+#define MSG_HDR_T union sip_header_u
+
+#include "sofia-sip/sip_parser.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+/**@SIP_HEADER sip_reason Reason Header
+ *
+ * The Reason header is used to indicate why a SIP request was issued or why
+ * a provisional response was sent. It can be used with HRPF scenarios. It
+ * is defined in @RFC3326 as follows:
+ *
+ * @code
+ * Reason = "Reason" HCOLON reason-value *(COMMA reason-value)
+ * reason-value = protocol *(SEMI reason-params)
+ * protocol = "SIP" / "Q.850" / token
+ * reason-params = protocol-cause / reason-text
+ * / reason-extension
+ * protocol-cause = "cause" EQUAL cause
+ * cause = 1*DIGIT
+ * reason-text = "text" EQUAL quoted-string
+ * reason-extension = generic-param
+ * @endcode
+ *
+ * The parsed Reason header is stored in #sip_reason_t structure.
+ */
+
+/**@ingroup sip_reason
+ * @typedef typedef struct sip_reason_s sip_reason_t;
+ *
+ * The structure #sip_reason_t contains representation of SIP @Reason header.
+ *
+ * The #sip_reason_t is defined as follows:
+ * @code
+ * typedef struct sip_reason_s
+ * {
+ * sip_common_t re_common[1]; // Common fragment info
+ * sip_reason_t *re_next; // Link to next <reason-value>
+ * char const *re_protocol; // Protocol
+ * msg_param_t const *re_params; // List of reason parameters
+ * char const *re_cause; // Value of cause parameter
+ * char const *re_text; // Value of text parameter
+ * } sip_reason_t;
+ * @endcode
+ */
+
+static msg_xtra_f sip_reason_dup_xtra;
+static msg_dup_f sip_reason_dup_one;
+static msg_update_f sip_reason_update;
+
+msg_hclass_t sip_reason_class[] =
+SIP_HEADER_CLASS(reason, "Reason", "", re_params, append, reason);
+
+issize_t sip_reason_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ sip_reason_t *re = (sip_reason_t *)h;
+ size_t n;
+
+ while (*s == ',') /* Ignore empty entries (comma-whitespace) */
+ *s = '\0', s += span_lws(s + 1) + 1;
+
+ re->re_protocol = s;
+ if ((n = span_token(s)) == 0)
+ return -1;
+ s += n; while (IS_LWS(*s)) *s++ = '\0';
+ if (*s == ';' && msg_params_d(home, &s, &re->re_params) < 0)
+ return -1;
+
+ return msg_parse_next_field(home, h, s, slen);
+}
+
+issize_t sip_reason_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+ char *end = b + bsiz, *b0 = b;
+ sip_reason_t const *re = h->sh_reason;
+
+ assert(sip_is_reason(h));
+ MSG_STRING_E(b, end, re->re_protocol);
+ MSG_PARAMS_E(b, end, re->re_params, flags);
+
+ return b - b0;
+}
+
+isize_t sip_reason_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+ sip_reason_t const *re = h->sh_reason;
+
+ MSG_PARAMS_SIZE(offset, re->re_params);
+ offset += MSG_STRING_SIZE(re->re_protocol);
+
+ return offset;
+}
+
+/** Duplicate one #sip_reason_t object */
+char *sip_reason_dup_one(sip_header_t *dst, sip_header_t const *src,
+ char *b, isize_t xtra)
+{
+ sip_reason_t *re_dst = dst->sh_reason;
+ sip_reason_t const *re_src = src->sh_reason;
+
+ char *end = b + xtra;
+ b = msg_params_dup(&re_dst->re_params, re_src->re_params, b, xtra);
+ MSG_STRING_DUP(b, re_dst->re_protocol, re_src->re_protocol);
+ assert(b <= end); (void)end;
+
+ return b;
+}
+
+/** Update parameter values for @Reason header */
+static int sip_reason_update(msg_common_t *h,
+ char const *name, isize_t namelen,
+ char const *value)
+{
+ sip_reason_t *re = (sip_reason_t *)h;
+
+ if (name == NULL) {
+ re->re_cause = NULL;
+ re->re_text = NULL;
+ }
+#define MATCH(s) (namelen == strlen(#s) && !strncasecmp(name, #s, strlen(#s)))
+
+ else if (MATCH(cause)) {
+ re->re_cause = value;
+ }
+ else if (MATCH(text)) {
+ re->re_text = value;
+ }
+
+#undef MATCH
+
+ return 0;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_refer.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_refer.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,555 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE sip_refer.c
+ * @brief SIP REFER-related headers.
+ *
+ * The file @b sip_refer.c contains implementation of header classes for
+ * REFER-related SIP headers @ReferTo and @ReferredBy.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Jan 23 13:23:45 EET 2002 ppessi
+ */
+
+#include "config.h"
+
+/* Avoid casting sip_t to msg_pub_t and sip_header_t to msg_header_t */
+#define MSG_PUB_T struct sip_s
+#define MSG_HDR_T union sip_header_u
+
+#include "sofia-sip/sip_parser.h"
+#include "sofia-sip/sip_extra.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_refer_to Refer-To Header
+ *
+ * The Refer-To header provides a URI to reference. Its syntax is defined in
+ * @RFC3515 section 2.1 as follows:
+ *
+ * @code
+ * Refer-To = ("Refer-To" / "r") HCOLON ( name-addr / addr-spec )
+ * *(SEMI generic-param)
+ * @endcode
+ *
+ *
+ * The parsed Refer-To header is stored in #sip_refer_to_t structure.
+ */
+
+/**@ingroup sip_refer_to
+ *
+ * @typedef typedef struct sip_refer_to_s sip_refer_to_t;
+ *
+ * The structure #sip_refer_to_t contains representation of @ReferTo
+ * header.
+ *
+ * The #sip_refer_to_t is defined as follows:
+ * @code
+ * typedef struct sip_refer_to_s
+ * {
+ * sip_common_t r_common[1]; // Common fragment info
+ * sip_error_t *r_next; // Link to next (dummy)
+ * char const r_display; // Display name
+ * url_t r_url[1]; // URI to reference
+ * msg_param_t const *r_params; // List of generic parameters
+ * } sip_refer_to_t;
+ * @endcode
+ */
+
+static msg_xtra_f sip_refer_to_dup_xtra;
+static msg_dup_f sip_refer_to_dup_one;
+#define sip_refer_to_update NULL
+
+msg_hclass_t sip_refer_to_class[] =
+SIP_HEADER_CLASS(refer_to, "Refer-To", "r", r_params, single, refer_to);
+
+issize_t sip_refer_to_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ issize_t retval;
+ sip_refer_to_t *r = (sip_refer_to_t *)h;
+
+ retval = sip_name_addr_d(home, &s,
+ &r->r_display,
+ r->r_url,
+ &r->r_params,
+ NULL);
+ if (retval < 0)
+ return retval;
+
+ if (*s == '?' && !r->r_display && !r->r_url->url_headers) {
+ /* Missing <> around URL */
+ *s++ = '\0';
+ r->r_url->url_headers = s;
+ s += strcspn(s, " \t;,");
+ if (IS_LWS(*s))
+ *s++ = '\0', skip_lws(&s);
+ if (*s)
+ return -1;
+ r->r_display = s; /* Put empty string in display so that we encode using <> */
+ }
+ else if (*s)
+ return -1;
+
+ return retval;
+}
+
+issize_t sip_refer_to_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+ sip_refer_to_t const *r = h->sh_refer_to;
+
+ assert(sip_is_refer_to(h));
+
+ return sip_name_addr_e(b, bsiz, flags,
+ r->r_display, MSG_IS_CANONIC(flags),
+ r->r_url,
+ r->r_params,
+ NULL);
+}
+
+isize_t sip_refer_to_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+ sip_refer_to_t const *r = h->sh_refer_to;
+
+ MSG_PARAMS_SIZE(offset, r->r_params);
+ offset += MSG_STRING_SIZE(r->r_display);
+ offset += url_xtra(r->r_url);
+
+ return offset;
+}
+
+/** Duplicate one #sip_refer_to_t object */
+char *sip_refer_to_dup_one(sip_header_t *dst, sip_header_t const *src,
+ char *b, isize_t xtra)
+{
+ sip_refer_to_t *r_dst = dst->sh_refer_to;
+ sip_refer_to_t const *r_src = src->sh_refer_to;
+
+ char *end = b + xtra;
+
+ b = msg_params_dup(&r_dst->r_params, r_src->r_params, b, xtra);
+ MSG_STRING_DUP(b, r_dst->r_display, r_src->r_display);
+ URL_DUP(b, end, r_dst->r_url, r_src->r_url);
+
+ assert(b <= end);
+
+ return b;
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_referred_by Referred-By Header
+ *
+ * The Referred-By header conveys the identity of the original referrer to
+ * the referred-to party. Its syntax is defined in
+ * @RFC3892 section 3 as follows:
+ *
+ * @code
+ * Referred-By = ("Referred-By" / "b") HCOLON referrer-uri
+ * *( SEMI (referredby-id-param / generic-param) )
+ *
+ * referrer-uri = ( name-addr / addr-spec )
+ *
+ * referredby-id-param = "cid" EQUAL sip-clean-msg-id
+ *
+ * sip-clean-msg-id = LDQUOT dot-atom "@" (dot-atom / host) RDQUOT
+ *
+ * dot-atom = atom *( "." atom )
+ *
+ * atom = 1*( alphanum / "-" / "!" / "%" / "*" /
+ * "_" / "+" / "'" / "`" / "~" )
+ * @endcode
+ *
+ *
+ * The parsed Referred-By header is stored in #sip_referred_by_t structure.
+ */
+
+/**@ingroup sip_referred_by
+ *
+ * @typedef typedef struct sip_referred_by_s sip_referred_by_t;
+ *
+ * The structure #sip_referred_by_t contains representation of @ReferredBy
+ * header.
+ *
+ * The #sip_referred_by_t is defined as follows:
+ * @code
+ * typedef struct sip_referred_by_s
+ * {
+ * sip_common_t b_common[1]; // Common fragment info
+ * sip_error_t *b_next; // Link to next (dummy)
+ * char const b_display,
+ * url_t b_url[1]; // Referrer-URI
+ * msg_param_t const *b_params; // List of parameters
+ * char const *b_cid;
+ * } sip_referred_by_t;
+ * @endcode
+ */
+
+static msg_xtra_f sip_referred_by_dup_xtra;
+static msg_dup_f sip_referred_by_dup_one;
+static msg_update_f sip_referred_by_update;
+
+msg_hclass_t sip_referred_by_class[] =
+SIP_HEADER_CLASS(referred_by, "Referred-By", "b", b_params, single,
+ referred_by);
+
+issize_t sip_referred_by_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ sip_referred_by_t *b = h->sh_referred_by;
+
+ if (sip_name_addr_d(home, &s,
+ &b->b_display,
+ b->b_url,
+ &b->b_params,
+ NULL) < 0 || *s /* Extra stuff? */)
+ return -1;
+
+ if (b->b_params)
+ msg_header_update_params(b->b_common, 0);
+
+ return 0;
+}
+
+issize_t sip_referred_by_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+ assert(sip_is_referred_by(h));
+
+ return sip_name_addr_e(b, bsiz, flags,
+ h->sh_referred_by->b_display,
+ MSG_IS_CANONIC(flags), h->sh_referred_by->b_url,
+ h->sh_referred_by->b_params,
+ NULL);
+}
+
+isize_t sip_referred_by_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+ sip_referred_by_t const *b = h->sh_referred_by;
+
+ MSG_PARAMS_SIZE(offset, b->b_params);
+ offset += MSG_STRING_SIZE(b->b_display);
+ offset += url_xtra(b->b_url);
+
+ return offset;
+}
+
+char *sip_referred_by_dup_one(sip_header_t *dst, sip_header_t const *src,
+ char *b,
+ isize_t xtra)
+{
+ sip_referred_by_t *nb = dst->sh_referred_by;
+ sip_referred_by_t const *o = src->sh_referred_by;
+ char *end = b + xtra;
+
+ b = msg_params_dup(&nb->b_params, o->b_params, b, xtra);
+ MSG_STRING_DUP(b, nb->b_display, o->b_display);
+ URL_DUP(b, end, nb->b_url, o->b_url);
+
+ nb->b_cid = msg_params_find(nb->b_params, "cid=");
+
+ assert(b <= end);
+
+ return b;
+}
+
+static int sip_referred_by_update(msg_common_t *h,
+ char const *name, isize_t namelen,
+ char const *value)
+{
+ sip_referred_by_t *b = (sip_referred_by_t *)h;
+
+ if (name == NULL) {
+ b->b_cid = NULL;
+ }
+ else if (namelen == strlen("cid") && !strncasecmp(name, "cid", namelen)) {
+ b->b_cid = value;
+ }
+
+ return 0;
+}
+
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_replaces Replaces Header
+ *
+ * The Replaces header indicates that a single dialog identified by the
+ * header field is to be shut down and logically replaced by the incoming
+ * INVITE in which it is contained. Its syntax is defined in
+ * @RFC3891 section 6.1 as follows:
+ *
+ * @code
+ * Replaces = "Replaces" HCOLON callid *(SEMI replaces-param)
+ * replaces-param = to-tag / from-tag / early-flag / generic-param
+ * to-tag = "to-tag" EQUAL token
+ * from-tag = "from-tag" EQUAL token
+ * early-flag = "early-only"
+ * @endcode
+ *
+ * A Replaces header field MUST contain exactly one <to-tag> and exactly
+ * one <from-tag>, as they are required for unique dialog matching. For
+ * compatibility with dialogs initiated by @RFC2543 compliant UAs, a
+ * tag of zero ("0") matches both tags of zero and null. A Replaces header
+ * field MAY contain the <early-only> flag.
+ *
+ * The parsed Replaces header is stored in #sip_replaces_t structure.
+ *
+ * @sa @RFC3891, nta_leg_by_replaces(), nta_leg_make_replaces()
+ */
+
+/**@ingroup sip_replaces
+ *
+ * @typedef typedef struct sip_replaces_s sip_replaces_t;
+ *
+ * The structure #sip_replaces_t contains representation of @Replaces
+ * header.
+ *
+ * The #sip_replaces_t is defined as follows:
+ * @code
+ * typedef struct sip_replaces_s
+ * {
+ * sip_common_t rp_common[1]; // Common fragment info
+ * sip_error_t *rp_next; // Dummy link to next
+ * char const *rp_call_id; // @CallID of dialog to replace
+ * msg_param_t const *rp_params; // List of parameters
+ * char const *rp_to_tag; // Value of "to-tag" parameter
+ * char const *rp_from_tag; // Value of "from-tag" parameter
+ * unsigned rp_early_only; // early-only parameter
+ * } sip_replaces_t;
+ * @endcode
+ */
+
+static msg_xtra_f sip_replaces_dup_xtra;
+static msg_dup_f sip_replaces_dup_one;
+static msg_update_f sip_replaces_update;
+
+msg_hclass_t sip_replaces_class[] =
+SIP_HEADER_CLASS(replaces, "Replaces", "", rp_params, single, replaces);
+
+/** Decode (parse) @Replaces header */
+issize_t sip_replaces_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ sip_replaces_t *rp = h->sh_replaces;
+
+ rp->rp_call_id = sip_word_at_word_d(&s);
+ if (!rp->rp_call_id)
+ return -1;
+ if (*s) {
+ if (msg_params_d(home, &s, &rp->rp_params) == -1)
+ return -1;
+ msg_header_update_params(rp->rp_common, 0);
+ }
+
+ return s - rp->rp_call_id;
+}
+
+/** Encode (print) @Replaces header */
+issize_t sip_replaces_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+ char *b0 = b, *end = b + bsiz;
+ sip_replaces_t const *rp = h->sh_replaces;
+
+ assert(sip_is_replaces(h));
+ MSG_STRING_E(b, end, rp->rp_call_id);
+ MSG_PARAMS_E(b, end, rp->rp_params, flags);
+ MSG_TERM_E(b, end);
+
+ return b - b0;
+}
+
+/** Calculate extra storage used by @Replaces header field */
+isize_t sip_replaces_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+ sip_replaces_t const *rp = h->sh_replaces;
+
+ MSG_PARAMS_SIZE(offset, rp->rp_params);
+ offset += MSG_STRING_SIZE(rp->rp_call_id);
+
+ return offset;
+}
+
+/** Duplicate a @Replaces header field */
+char *sip_replaces_dup_one(sip_header_t *dst, sip_header_t const *src,
+ char *b, isize_t xtra)
+{
+ sip_replaces_t *rp_dst = dst->sh_replaces;
+ sip_replaces_t const *rp_src = src->sh_replaces;
+
+ char *end = b + xtra;
+
+ b = msg_params_dup(&rp_dst->rp_params, rp_src->rp_params, b, xtra);
+ MSG_STRING_DUP(b, rp_dst->rp_call_id, rp_src->rp_call_id);
+
+ assert(b <= end); (void)end;
+
+ return b;
+}
+
+/** Update parameters in @Replaces header. */
+static int sip_replaces_update(msg_common_t *h,
+ char const *name, isize_t namelen,
+ char const *value)
+{
+ sip_replaces_t *rp = (sip_replaces_t *)h;
+
+ if (name == NULL) {
+ rp->rp_to_tag = NULL;
+ rp->rp_from_tag = NULL;
+ rp->rp_early_only = 0;
+ }
+#define MATCH(s) (namelen == strlen(#s) && !strncasecmp(name, #s, strlen(#s)))
+
+ else if (MATCH(to-tag)) {
+ rp->rp_to_tag = value;
+ }
+ else if (MATCH(from-tag)) {
+ rp->rp_from_tag = value;
+ }
+ else if (MATCH(early-only)) {
+ rp->rp_early_only = value != NULL;
+ }
+
+#undef MATCH
+
+ return 0;
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_refer_sub Refer-Sub Header
+ *
+ * SIP header field @b Refer-Sub is meaningful and MAY be used with a REFER
+ * request and the corresponding 2XX response only. This header field set to
+ * "false" specifies that a REFER-Issuer requests that the REFER-Recipient
+ * doesn't establish an implicit subscription and the resultant dialog.
+ *
+ * Refer-Sub = "Refer-Sub" HCOLON refer-sub-value *(SEMI exten)
+ * refer-sub-value = "true" / "false"
+ * exten = generic-param
+ *
+ * The parsed Refer-Sub header is stored in #sip_refer_sub_t structure.
+ *
+ * @NEW_1_12_5. Note that #sip_t does not contain @a sip_refer_sub field,
+ * but sip_refer_sub() accessor function should be used for accessing @b
+ * Refer-Sub header structure.
+ *
+ * @sa @RFC4488, nua_refer(), #nua_i_refer
+ */
+
+/**@ingroup sip_refer_sub
+ *
+ * @typedef typedef struct sip_refer_sub_s sip_refer_sub_t;
+ *
+ * The structure #sip_refer_sub_t contains representation of @ReferSub
+ * header.
+ *
+ * The #sip_refer_sub_t is defined as follows:
+ * @code
+ * typedef struct sip_refer_sub_s
+ * {
+ * sip_common_t rs_common[1]; // Common fragment info
+ * sip_error_t *rs_next; // Dummy link to next
+ * char const *rs_value; // "true" or "false"
+ * msg_param_t const *rs_params; // List of extension parameters
+ * } sip_refer_sub_t;
+ * @endcode
+ *
+ * @NEW_1_12_5.
+ */
+
+static msg_xtra_f sip_refer_sub_dup_xtra;
+static msg_dup_f sip_refer_sub_dup_one;
+#define sip_refer_sub_update NULL
+
+msg_hclass_t sip_refer_sub_class[] =
+SIP_HEADER_CLASS(refer_sub, "Refer-Sub", "", rs_params, single, refer_sub);
+
+/** Decode (parse) @ReferSub header */
+issize_t sip_refer_sub_d(su_home_t *home,
+ sip_header_t *h,
+ char *s, isize_t slen)
+{
+ sip_refer_sub_t *rs = (sip_refer_sub_t *)h;
+
+ if (msg_token_d(&s, &rs->rs_value) < 0)
+ return -1;
+
+ if (strcasecmp(rs->rs_value, "false") &&
+ strcasecmp(rs->rs_value, "true"))
+ return -1;
+
+ if (*s)
+ if (msg_params_d(home, &s, &rs->rs_params) == -1)
+ return -1;
+
+ return s - rs->rs_value;
+}
+
+/** Encode (print) @ReferSub header */
+issize_t sip_refer_sub_e(char b[], isize_t bsiz,
+ sip_header_t const *h,
+ int flags)
+{
+ char *b0 = b, *end = b + bsiz;
+ sip_refer_sub_t const *rs = (sip_refer_sub_t *)h;
+
+ assert(sip_is_refer_sub(h));
+ MSG_STRING_E(b, end, rs->rs_value);
+ MSG_PARAMS_E(b, end, rs->rs_params, flags);
+ MSG_TERM_E(b, end);
+
+ return b - b0;
+}
+
+/** Calculate extra storage used by @ReferSub header field */
+isize_t sip_refer_sub_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+ sip_refer_sub_t const *rs = (sip_refer_sub_t *)h;
+
+ MSG_PARAMS_SIZE(offset, rs->rs_params);
+ offset += MSG_STRING_SIZE(rs->rs_value);
+
+ return offset;
+}
+
+/** Duplicate a @ReferSub header field */
+char *sip_refer_sub_dup_one(sip_header_t *dst, sip_header_t const *src,
+ char *b, isize_t xtra)
+{
+ sip_refer_sub_t *rs_dst = (sip_refer_sub_t *)dst;
+ sip_refer_sub_t const *rs_src = (sip_refer_sub_t *)src;
+
+ char *end = b + xtra;
+
+ b = msg_params_dup(&rs_dst->rs_params, rs_src->rs_params, b, xtra);
+ MSG_STRING_DUP(b, rs_dst->rs_value, rs_src->rs_value);
+
+ assert(b <= end); (void)end;
+
+ return b;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_security.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_security.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,841 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE sip_security.c
+ *
+ * Security-related SIP header handling.
+ *
+ * This file contains implementation of headers related to HTTP authentication
+ * (@RFC2617):
+ * @ref sip_authorization "Authorization",
+ * @ref sip_authentication_info "Authentication-Info",
+ * @ref sip_proxy_authenticate "Proxy-Authenticate",
+ * @ref sip_proxy_authentication_info "Proxy-Authentication-Info",
+ * @ref sip_proxy_authorization "Proxy-Authorization", and
+ * @ref sip_www_authenticate "WWW-Authenticate".
+ *
+ * There is also implementation of headers related to security agreement
+ * (@RFC3329):
+ * @ref sip_security_client "Security-Client",
+ * @ref sip_security_server "Security-Server", and
+ * @ref sip_security_verify "Security-Verify" headers.
+ *
+ * The implementation of @ref sip_privacy "Privacy" header (@RFC3323) is
+ * also here.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Tue Jun 13 02:57:51 2000 ppessi
+ */
+
+#include "config.h"
+
+/* Avoid casting sip_t to msg_pub_t and sip_header_t to msg_header_t */
+#define MSG_PUB_T struct sip_s
+#define MSG_HDR_T union sip_header_u
+
+#include "sofia-sip/sip_parser.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <assert.h>
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_authorization Authorization Header
+ *
+ * The Authorization header consists of credentials containing the
+ * authentication information of the user agent for the realm of the
+ * resource being requested. Its syntax is defined in @RFC2617 and @RFC3261
+ * as follows:
+ *
+ * @code
+ * Authorization = "Authorization" HCOLON credentials
+ * credentials = ("Digest" LWS digest-response)
+ * / other-response
+ * digest-response = dig-resp *(COMMA dig-resp)
+ * dig-resp = username / realm / nonce / digest-uri
+ * / dresponse / algorithm / cnonce
+ * / opaque / message-qop
+ * / nonce-count / auth-param
+ * username = "username" EQUAL username-value
+ * username-value = quoted-string
+ * digest-uri = "uri" EQUAL LDQUOT digest-uri-value RDQUOT
+ * digest-uri-value = rquest-uri ; Equal to request-uri as specified
+ * by HTTP/1.1
+ * message-qop = "qop" EQUAL qop-value
+ * cnonce = "cnonce" EQUAL cnonce-value
+ * cnonce-value = nonce-value
+ * nonce-count = "nc" EQUAL nc-value
+ * nc-value = 8LHEX
+ * dresponse = "response" EQUAL request-digest
+ * request-digest = LDQUOT 32LHEX RDQUOT
+ * auth-param = auth-param-name EQUAL
+ * ( token / quoted-string )
+ * auth-param-name = token
+ * other-response = auth-scheme LWS auth-param
+ * *(COMMA auth-param)
+ * auth-scheme = token
+ * @endcode
+ *
+ * The parsed Authorization header
+ * is stored in #sip_authorization_t structure.
+ *
+ * @sa @RFC2617, auth_mod_verify(), auth_mod_check(), auth_get_params(),
+ * auth_digest_response_get().
+ */
+
+/**@ingroup sip_authorization
+ * @typedef typedef struct sip_authorization_s sip_authorization_t;
+ *
+ * The structure #sip_authorization_t contains representation of SIP
+ * @Authorization header.
+ *
+ * The #sip_authorization_t is defined as follows:
+ * @code
+ * typedef 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
+ * } sip_authorization_t;
+ * @endcode
+ *
+ */
+
+msg_hclass_t sip_authorization_class[] =
+SIP_HEADER_CLASS_AUTH(authorization, "Authorization", single);
+
+issize_t sip_authorization_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ return msg_auth_d(home, h, s, slen);
+}
+
+issize_t sip_authorization_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+ assert(sip_is_authorization(h));
+ return msg_auth_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_proxy_authenticate Proxy-Authenticate Header
+ *
+ * The Proxy-Authenticate header consists of a challenge that indicates the
+ * authentication scheme and parameters applicable to the proxy. Its syntax
+ * is defined in [H14.33, S10.31] as follows:
+ *
+ * @code
+ * Proxy-Authenticate = "Proxy-Authenticate" HCOLON challenge
+ * challenge = ("Digest" LWS digest-cln *(COMMA digest-cln))
+ * / other-challenge
+ * other-challenge = auth-scheme LWS auth-param
+ * *(COMMA auth-param)
+ * digest-cln = realm / domain / nonce
+ * / opaque / stale / algorithm
+ * / qop-options / auth-param
+ * realm = "realm" EQUAL realm-value
+ * realm-value = quoted-string
+ * domain = "domain" EQUAL LDQUOT URI
+ * *( 1*SP URI ) RDQUOT
+ * URI = absoluteURI / abs-path
+ * nonce = "nonce" EQUAL nonce-value
+ * nonce-value = quoted-string
+ * opaque = "opaque" EQUAL quoted-string
+ * stale = "stale" EQUAL ( "true" / "false" )
+ * algorithm = "algorithm" EQUAL ( "MD5" / "MD5-sess"
+ * / token )
+ * qop-options = "qop" EQUAL LDQUOT qop-value
+ * *("," qop-value) RDQUOT
+ * qop-value = "auth" / "auth-int" / token
+ * @endcode
+ *
+ *
+ * The parsed Proxy-Authenticate header
+ * is stored in #sip_proxy_authenticate_t structure.
+ */
+
+/**@ingroup sip_proxy_authenticate
+ * @typedef typedef struct sip_proxy_authenticate_s sip_proxy_authenticate_t;
+ *
+ * The structure #sip_proxy_authenticate_t contains representation of SIP
+ * @ProxyAuthenticate header.
+ *
+ * The #sip_proxy_authenticate_t is defined as follows:
+ * @code
+ * typedef 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
+ * } sip_proxy_authenticate_t;
+ * @endcode
+ *
+ */
+
+msg_hclass_t sip_proxy_authenticate_class[] =
+SIP_HEADER_CLASS_AUTH(proxy_authenticate, "Proxy-Authenticate", append);
+
+issize_t sip_proxy_authenticate_d(su_home_t *home, sip_header_t *h,
+ char *s, isize_t slen)
+{
+ return msg_auth_d(home, h, s, slen);
+}
+
+issize_t sip_proxy_authenticate_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+ assert(sip_is_proxy_authenticate(h));
+ return msg_auth_e(b, bsiz, h, f);
+}
+
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_proxy_authorization Proxy-Authorization Header
+ *
+ * The Proxy-Authorization header consists of credentials containing the
+ * authentication information of the user agent for the proxy and/or realm
+ * of the resource being requested. Its syntax is defined in @RFC3261
+ * as follows:
+ *
+ * @code
+ * Proxy-Authorization = "Proxy-Authorization" ":" credentials
+ * credentials = ("Digest" LWS digest-response)
+ * / other-response
+ * @endcode
+ *
+ * @sa auth_mod_verify(), auth_mod_check(), auth_get_params(),
+ * auth_digest_response_get().
+ *
+ * The parsed Proxy-Authorization header
+ * is stored in #sip_proxy_authorization_t structure.
+ */
+
+/**@ingroup sip_proxy_authorization
+ * @typedef typedef struct sip_proxy_authorization_s sip_proxy_authorization_t;
+ *
+ * The structure #sip_proxy_authorization_t contains representation of SIP
+ * @ProxyAuthorization header.
+ *
+ * The #sip_proxy_authorization_t is defined as follows:
+ * @code
+ * typedef 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
+ * } sip_proxy_authorization_t;
+ * @endcode
+ *
+ */
+
+msg_hclass_t sip_proxy_authorization_class[] =
+SIP_HEADER_CLASS_AUTH(proxy_authorization, "Proxy-Authorization", append);
+
+issize_t sip_proxy_authorization_d(su_home_t *home, sip_header_t *h,
+ char *s, isize_t slen)
+{
+ return msg_auth_d(home, h, s, slen);
+}
+
+issize_t sip_proxy_authorization_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+ assert(sip_is_proxy_authorization(h));
+ return msg_auth_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_www_authenticate WWW-Authenticate Header
+ *
+ * The WWW-Authenticate header consists of at least one challenge that
+ * indicates the authentication scheme(s) and parameters applicable to the
+ * Request-URI. Its syntax is defined in @RFC3261 as
+ * follows:
+ *
+ * @code
+ * WWW-Authenticate = "WWW-Authenticate" HCOLON challenge
+ * challenge = ("Digest" LWS digest-cln *(COMMA digest-cln))
+ * / other-challenge
+ * other-challenge = auth-scheme LWS auth-param *(COMMA auth-param)
+ * @endcode
+ *
+ * See @ProxyAuthenticate for the definition of \<digest-cln\>.
+ *
+ * The parsed WWW-Authenticate header
+ * is stored in #sip_www_authenticate_t structure.
+ */
+
+/**@ingroup sip_www_authenticate
+ * @typedef typedef struct sip_www_authenticate_s sip_www_authenticate_t;
+ *
+ * The structure #sip_www_authenticate_t contains representation of SIP
+ * @WWWAuthenticate header.
+ *
+ * The #sip_www_authenticate_t is defined as follows:
+ * @code
+ * typedef 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
+ * } sip_www_authenticate_t;
+ * @endcode
+ *
+ */
+
+msg_hclass_t sip_www_authenticate_class[] =
+SIP_HEADER_CLASS_AUTH(www_authenticate, "WWW-Authenticate", single);
+
+issize_t sip_www_authenticate_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ return msg_auth_d(home, h, s, slen);
+}
+
+issize_t sip_www_authenticate_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+ assert(sip_is_www_authenticate(h));
+ return msg_auth_e(b, bsiz, h, f);
+}
+
+/**@SIP_HEADER sip_authentication_info Authentication-Info Header
+ *
+ * The @b Authentication-Info header contains either a next-nonce used by
+ * next request and/or authentication from server used in mutual
+ * authentication. The syntax of @b Authentication-Info header is defined in
+ * @RFC2617 and @RFC3261 as follows:
+ *
+ * @code
+ * Authentication-Info = "Authentication-Info" HCOLON ainfo
+ * *(COMMA ainfo)
+ * ainfo = nextnonce / message-qop
+ * / response-auth / cnonce
+ * / nonce-count
+ * nextnonce = "nextnonce" EQUAL nonce-value
+ * response-auth = "rspauth" EQUAL response-digest
+ * response-digest = LDQUOT *LHEX RDQUOT
+ * @endcode
+ *
+ * The parsed Authentication-Info header
+ * is stored in #sip_authentication_info_t structure.
+ */
+
+/**@ingroup sip_authentication_info
+ * @typedef typedef struct sip_authentication_info_s sip_authentication_info_t;
+ *
+ * The structure #sip_authentication_info_t contains representation of SIP
+ * @AuthenticationInfo header.
+ *
+ * The #sip_authentication_info_t is defined as follows:
+ * @code
+ * typedef struct msg_auth_info_s
+ * {
+ * msg_common_t ai_common[1]; // Common fragment info
+ * msg_error_t *ai_next; // Dummy link to next header
+ * msg_param_t *ai_items; // List of ainfo
+ * } sip_authentication_info_t;
+ * @endcode
+ */
+
+#define sip_authentication_info_dup_xtra msg_list_dup_xtra
+#define sip_authentication_info_dup_one msg_list_dup_one
+#define sip_authentication_info_update NULL
+
+msg_hclass_t sip_authentication_info_class[] =
+ SIP_HEADER_CLASS(authentication_info, "Authentication-Info", "",
+ ai_params, append, authentication_info);
+
+issize_t sip_authentication_info_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ return msg_list_d(home, (msg_header_t *)h, s, slen);
+}
+
+
+issize_t sip_authentication_info_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+ assert(sip_is_authentication_info(h));
+ return msg_list_e(b, bsiz, h, f);
+}
+
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_proxy_authentication_info Proxy-Authentication-Info Header
+ *
+ * The @b Proxy-Authentication-Info header contains either a next-nonce used
+ * by next request and/or authentication from proxy used in mutual
+ * authentication. The syntax of @b Proxy-Authentication-Info header is defined
+ * in @RFC2617 as follows:
+ *
+ * @code
+ * Proxy-Authentication-Info = "Proxy-Authentication-Info" HCOLON ainfo
+ * *(COMMA ainfo)
+ * ainfo = nextnonce / message-qop
+ * / response-auth / cnonce
+ * / nonce-count
+ * nextnonce = "nextnonce" EQUAL nonce-value
+ * response-auth = "rspauth" EQUAL response-digest
+ * response-digest = LDQUOT *LHEX RDQUOT
+ * @endcode
+ *
+ * @note @b Proxy-Authentication-Info is not specified @RFC3261 and it is
+ * mentioned by @RFC2617 but in passage.
+ *
+ * The parsed Proxy-Authentication-Info header
+ * is stored in #sip_proxy_authentication_info_t structure.
+ */
+
+/**@ingroup sip_proxy_authentication_info
+ * @typedef typedef struct msg_authentication_info_s sip_proxy_authentication_info_t;
+ *
+ * The structure #sip_proxy_authentication_info_t contains representation of SIP
+ * @ProxyAuthenticationInfo header.
+ *
+ * The #sip_proxy_authentication_info_t is defined as follows:
+ * @code
+ * typedef struct msg_auth_info_s
+ * {
+ * msg_common_t ai_common[1]; // Common fragment info
+ * msg_error_t *ai_next; // Dummy link to next header
+ * msg_param_t *ai_items; // List of ainfo
+ * } sip_proxy_authentication_info_t;
+ * @endcode
+ *
+ */
+
+#define sip_proxy_authentication_info_dup_xtra msg_list_dup_xtra
+#define sip_proxy_authentication_info_dup_one msg_list_dup_one
+#define sip_proxy_authentication_info_update NULL
+
+msg_hclass_t sip_proxy_authentication_info_class[] =
+ SIP_HEADER_CLASS(proxy_authentication_info, "Proxy-Authentication-Info", "",
+ ai_params, append, proxy_authentication_info);
+
+issize_t sip_proxy_authentication_info_d(su_home_t *home, sip_header_t *h,
+ char *s, isize_t slen)
+{
+ return msg_list_d(home, (msg_header_t *)h, s, slen);
+}
+
+issize_t sip_proxy_authentication_info_e(char b[], isize_t bsiz,
+ sip_header_t const *h, int f)
+{
+ assert(sip_is_proxy_authentication_info(h)); /* This is soo popular */
+ return msg_list_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+
+/* Functions parsing @RFC3329 SIP Security Agreement headers */
+
+typedef struct sip_security_agree_s sip_security_agree_t;
+#define sh_security_agree sh_security_client
+
+static
+issize_t sip_security_agree_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ sip_security_agree_t *sa = (sip_security_agree_t *)h;
+
+ isize_t n;
+
+ while (*s == ',') /* Ignore empty entries (comma-whitespace) */
+ *s = '\0', s += span_lws(s + 1) + 1;
+
+ if ((n = span_token(s)) == 0)
+ return -1;
+ sa->sa_mec = s; s += n; while (IS_LWS(*s)) *s++ = '\0';
+ if (*s == ';' && msg_params_d(home, &s, &sa->sa_params) < 0)
+ return -1;
+
+ return msg_parse_next_field(home, h, s, slen);
+}
+
+static
+issize_t sip_security_agree_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+ char *end = b + bsiz, *b0 = b;
+ sip_security_agree_t const *sa = (sip_security_agree_t const *)h;
+
+ MSG_STRING_E(b, end, sa->sa_mec);
+ MSG_PARAMS_E(b, end, sa->sa_params, flags);
+
+ return b - b0;
+}
+
+static
+isize_t sip_security_agree_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+ sip_security_agree_t const *sa = h->sh_security_agree;
+
+ MSG_PARAMS_SIZE(offset, sa->sa_params);
+ offset += MSG_STRING_SIZE(sa->sa_mec);
+
+ return offset;
+}
+
+/** Duplicate one sip_security_agree_t object */
+static
+char *sip_security_agree_dup_one(sip_header_t *dst, sip_header_t const *src,
+ char *b, isize_t xtra)
+{
+ sip_security_agree_t *sa_dst = dst->sh_security_agree;
+ sip_security_agree_t const *sa_src = src->sh_security_agree;
+
+ char *end = b + xtra;
+ b = msg_params_dup(&sa_dst->sa_params, sa_src->sa_params, b, xtra);
+ MSG_STRING_DUP(b, sa_dst->sa_mec, sa_src->sa_mec);
+ assert(b <= end); (void)end;
+
+ return b;
+}
+
+static int sip_security_agree_update(msg_common_t *h,
+ char const *name, isize_t namelen,
+ char const *value)
+{
+ sip_security_agree_t *sa = (sip_security_agree_t *)h;
+
+ if (name == NULL) {
+ sa->sa_q = NULL;
+ sa->sa_d_alg = NULL;
+ sa->sa_d_qop = NULL;
+ sa->sa_d_ver = NULL;
+ }
+#define MATCH(s) (namelen == strlen(#s) && !strncasecmp(name, #s, strlen(#s)))
+
+ else if (MATCH(q)) {
+ sa->sa_q = value;
+ }
+ else if (MATCH(d-alg)) {
+ sa->sa_d_alg = value;
+ }
+ else if (MATCH(d-qop)) {
+ sa->sa_d_qop = value;
+ }
+ else if (MATCH(d-ver)) {
+ sa->sa_d_ver = value;
+ }
+
+#undef MATCH
+
+ return 0;
+}
+
+
+/**@SIP_HEADER sip_security_client Security-Client Header
+ *
+ * The Security-Client header is defined by @RFC3329, "Security Mechanism
+ * Agreement for the Session Initiation Protocol (SIP)".
+ *
+ * @code
+ * security-client = "Security-Client" HCOLON
+ * sec-mechanism *(COMMA sec-mechanism)
+ * security-server = "Security-Server" HCOLON
+ * sec-mechanism *(COMMA sec-mechanism)
+ * security-verify = "Security-Verify" HCOLON
+ * sec-mechanism *(COMMA sec-mechanism)
+ * sec-mechanism = mechanism-name *(SEMI mech-parameters)
+ * mechanism-name = ( "digest" / "tls" / "ipsec-ike" /
+ * "ipsec-man" / token )
+ * mech-parameters = ( preference / digest-algorithm /
+ * digest-qop / digest-verify / extension )
+ * preference = "q" EQUAL qvalue
+ * qvalue = ( "0" [ "." 0*3DIGIT ] )
+ * / ( "1" [ "." 0*3("0") ] )
+ * digest-algorithm = "d-alg" EQUAL token
+ * digest-qop = "d-qop" EQUAL token
+ * digest-verify = "d-ver" EQUAL LDQUOT 32LHEX RDQUOT
+ * extension = generic-param
+ * @endcode
+ *
+ * @sa @SecurityServer, @SecurityVerify, sip_security_verify_compare(),
+ * sip_security_client_select(), @RFC3329
+ *
+ * The parsed Security-Client header
+ * is stored in #sip_security_client_t structure.
+ */
+
+/**@ingroup sip_security_client
+ * @typedef typedef struct sip_security_client_s sip_security_client_t;
+ *
+ * The structure #sip_security_client_t contains representation of SIP
+ * @SecurityClient header.
+ *
+ * The #sip_security_client_t is defined as follows:
+ * @code
+ * typedef struct sip_security_agree_s
+ * {
+ * sip_common_t sa_common[1]; // Common fragment info
+ * sip_security_client_t *sa_next; // Link to next mechanism
+ * char const *sa_mec; // Security mechanism
+ * msg_param_t const *sa_params; // List of mechanism parameters
+ * char const *sa_q; // Value of q (preference) parameter
+ * char const *sa_d_alg; // Value of d-alg parameter
+ * char const *sa_d_qop; // Value of d-qop parameter
+ * char const *sa_d_ver; // Value of d-ver parameter
+ * } sip_security_client_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_security_client_class[] =
+SIP_HEADER_CLASS(security_client, "Security-Client", "",
+ sa_params, append, security_agree);
+
+issize_t sip_security_client_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ return sip_security_agree_d(home, h, s, slen);
+}
+
+issize_t sip_security_client_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+ return sip_security_agree_e(b, bsiz, h, f);
+}
+
+
+/**@SIP_HEADER sip_security_server Security-Server Header
+ *
+ * The Security-Server header is defined by @RFC3329, "Security Mechanism
+ * Agreement for the Session Initiation Protocol (SIP)".
+ *
+ * @sa @SecurityClient, @SecurityVerify, sip_security_verify_compare(),
+ * sip_security_client_select(), @RFC3329.
+ *
+ * The parsed Security-Server header
+ * is stored in #sip_security_server_t structure.
+ */
+
+/**@ingroup sip_security_server
+ * @typedef typedef struct sip_security_server_s sip_security_server_t;
+ *
+ * The structure #sip_security_server_t contains representation of SIP
+ * @SecurityServer header.
+ *
+ * The #sip_security_server_t is defined as follows:
+ * @code
+ * typedef struct sip_security_agree_s
+ * {
+ * sip_common_t sa_common[1]; // Common fragment info
+ * sip_security_server_t *sa_next; // Link to next mechanism
+ * char const *sa_mec; // Security mechanism
+ * msg_param_t const *sa_params; // List of mechanism parameters
+ * char const *sa_q; // Value of q (preference) parameter
+ * char const *sa_d_alg; // Value of d-alg parameter
+ * char const *sa_d_qop; // Value of d-qop parameter
+ * char const *sa_d_ver; // Value of d-ver parameter
+ * } sip_security_server_t;
+ * @endcode
+ */
+
+msg_hclass_t sip_security_server_class[] =
+SIP_HEADER_CLASS(security_server, "Security-Server", "",
+ sa_params, append, security_agree);
+
+issize_t sip_security_server_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ return sip_security_agree_d(home, h, s, slen);
+}
+
+issize_t sip_security_server_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+ return sip_security_agree_e(b, bsiz, h, f);
+}
+
+
+/**@SIP_HEADER sip_security_verify Security-Verify Header
+ *
+ * The Security-Verify header is defined by @RFC3329, "Security Mechanism
+ * Agreement for the Session Initiation Protocol (SIP)".
+ *
+ * @sa @SecurityClient, @SecurityServer, sip_security_verify_compare(),
+ * sip_security_client_select(), @RFC3329.
+ *
+ * The parsed Security-Verify header
+ * is stored in #sip_security_verify_t structure.
+ */
+
+/**@ingroup sip_security_verify
+ * @typedef typedef struct sip_security_verify_s sip_security_verify_t;
+ *
+ * The structure #sip_security_verify_t contains representation of SIP
+ * @SecurityVerify header.
+ *
+ * The #sip_security_verify_t is defined as follows:
+ * @code
+ * typedef struct sip_security_agree_s
+ * {
+ * sip_common_t sa_common[1]; // Common fragment info
+ * sip_security_verify_t *sa_next; // Link to next mechanism
+ * char const *sa_mec; // Security mechanism
+ * msg_param_t const *sa_params; // List of mechanism parameters
+ * char const *sa_q; // Value of q (preference) parameter
+ * char const *sa_d_alg; // Value of d-alg parameter
+ * char const *sa_d_qop; // Value of d-qop parameter
+ * char const *sa_d_ver; // Value of d-ver parameter
+ * } sip_security_verify_t;
+ * @endcode
+ */
+
+
+msg_hclass_t sip_security_verify_class[] =
+SIP_HEADER_CLASS(security_verify, "Security-Verify", "",
+ sa_params, append, security_agree);
+
+issize_t sip_security_verify_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ return sip_security_agree_d(home, h, s, slen);
+}
+
+issize_t sip_security_verify_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+ return sip_security_agree_e(b, bsiz, h, f);
+}
+
+/* ====================================================================== */
+/* RFC 3323 */
+
+/**@SIP_HEADER sip_privacy Privacy Header
+ *
+ * The Privacy header is used by User-Agent to request privacy services from
+ * the network. Its syntax is defined in @RFC3323 as follows:
+ *
+ * @code
+ * Privacy-hdr = "Privacy" HCOLON priv-value *(";" priv-value)
+ * priv-value = "header" / "session" / "user" / "none" / "critical"
+ * / token
+ * @endcode
+ *
+ * The parsed Privacy header is stored in #sip_privacy_t structure.
+ */
+
+/**@ingroup sip_privacy
+ * @typedef typedef struct sip_privacy_s sip_privacy_t;
+ *
+ * The structure #sip_privacy_t contains representation of a SIP @Privacy
+ * header.
+ *
+ * The #sip_privacy_t is defined as follows:
+ * @code
+ * typedef struct sip_privacy_s {
+ * sip_common_t priv_common[1]; // Common fragment info
+ * sip_error_t *priv_next; // Dummy link
+ * msg_param_t const *priv_values; // List of privacy values
+ * } sip_privacy_t;
+ * @endcode
+ */
+
+msg_xtra_f sip_privacy_dup_xtra;
+msg_dup_f sip_privacy_dup_one;
+
+#define sip_privacy_update NULL
+
+msg_hclass_t sip_privacy_class[] =
+SIP_HEADER_CLASS(privacy, "Privacy", "", priv_values, single, privacy);
+
+static
+issize_t sip_privacy_token_scan(char *start)
+{
+ char *s = start;
+ skip_token(&s);
+
+ if (s == start)
+ return -1;
+
+ if (IS_LWS(*s))
+ *s++ = '\0';
+ skip_lws(&s);
+
+ return s - start;
+}
+
+issize_t sip_privacy_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ sip_privacy_t *priv = (sip_privacy_t *)h;
+
+ while (*s == ';' || *s == ',') {
+ s++;
+ skip_lws(&s);
+ }
+
+ for (;;) {
+ if (msg_any_list_d(home, &s, (msg_param_t **)&priv->priv_values,
+ sip_privacy_token_scan, ';') < 0)
+ return -1;
+
+ if (*s == '\0')
+ return 0; /* Success! */
+
+ if (*s == ',')
+ *s++ = '\0'; /* We accept comma-separated list, too */
+ else if (IS_TOKEN(*s))
+ ; /* LWS separated list... */
+ else
+ return -1;
+ }
+}
+
+issize_t sip_privacy_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
+{
+ sip_privacy_t const *priv = h->sh_privacy;
+ char *b0 = b, *end = b + bsiz;
+ size_t i;
+
+ if (priv->priv_values) {
+ for (i = 0; priv->priv_values[i]; i++) {
+ if (i > 0) MSG_CHAR_E(b, end, ';');
+ MSG_STRING_E(b, end, priv->priv_values[i]);
+ }
+ }
+
+ MSG_TERM_E(b, end);
+
+ return b - b0;
+}
+
+isize_t sip_privacy_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+ sip_privacy_t const *priv = h->sh_privacy;
+
+ MSG_PARAMS_SIZE(offset, priv->priv_values);
+
+ return offset;
+}
+
+char *sip_privacy_dup_one(sip_header_t *dst,
+ sip_header_t const *src,
+ char *b,
+ isize_t xtra)
+{
+ sip_privacy_t *priv = dst->sh_privacy;
+ sip_privacy_t const *o = src->sh_privacy;
+ char *end = b + xtra;
+
+ b = msg_params_dup(&priv->priv_values, o->priv_values, b, xtra);
+
+ assert(b <= end); (void)end;
+
+ return b;
+}
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_session.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_session.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,252 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE sip_session.c
+ * @brief Session Timer SIP headers.
+ *
+ * The file @b sip_session.c contains implementation of header classes for
+ * session-timer-related SIP headers @SessionExpires and @MinSE.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Thu Sep 13 21:24:15 EEST 2001 ppessi
+ */
+
+#include "config.h"
+
+/* Avoid casting sip_t to msg_pub_t and sip_header_t to msg_header_t */
+#define MSG_PUB_T struct sip_s
+#define MSG_HDR_T union sip_header_u
+
+#include "sofia-sip/sip_parser.h"
+#include <sofia-sip/msg_date.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+
+/* ====================================================================== */
+
+/**@SIP_HEADER sip_session_expires Session-Expires Header
+ *
+ * The Session-Expires header is used to convey the lifetime of the session.
+ * Its syntax is defined in @RFC4028 as follows:
+ *
+ * @code
+ * Session-Expires = ("Session-Expires" | "x") HCOLON delta-seconds
+ * *(SEMI se-params)
+ * se-params = refresher-param / generic-param
+ * refresher-param = "refresher" EQUAL ("uas" / "uac")
+ * @endcode
+ *
+ * The parsed Session-Expires header is stored in #sip_session_expires_t structure.
+ */
+
+/**@ingroup sip_session_expires
+ * @typedef typedef struct sip_session_expires_s sip_session_expires_t;
+ *
+ * The structure #sip_session_expires_t contains representation of the SIP
+ * @SessionExpires header.
+ *
+ * The #sip_session_expires_t is defined as follows:
+ * @code
+ * typedef struct sip_session_expires_s
+ * {
+ * sip_common_t x_common[1];
+ * sip_unknown_t *x_next;
+ * unsigned long x_delta; //Delta Seconds
+ * msg_param_t *x_params;
+ * char const *x_refresher; //Who will send the refresh UAS or UAC
+ * } sip_session_expires_t;
+ * @endcode
+ */
+
+static msg_xtra_f sip_session_expires_dup_xtra;
+static msg_dup_f sip_session_expires_dup_one;
+static msg_update_f sip_session_expires_update;
+
+msg_hclass_t sip_session_expires_class[] =
+SIP_HEADER_CLASS(session_expires, "Session-Expires", "x", x_params, single,
+ session_expires);
+
+issize_t sip_session_expires_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ sip_session_expires_t *x = h->sh_session_expires;
+
+ if (msg_delta_d((char const **) &s, &x->x_delta) < 0)
+ return -1;
+ if (*s == ';') {
+ if (msg_params_d(home, &s, &x->x_params) < 0 || *s)
+ return -1;
+ x->x_refresher = msg_params_find(x->x_params, "refresher");
+ }
+ return 0;
+}
+
+issize_t sip_session_expires_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+ char *end = b + bsiz, *b0 = b;
+ int n = 0;
+ sip_session_expires_t const *o = h->sh_session_expires;
+
+ n = snprintf(b, bsiz, "%lu", o->x_delta);
+ b += n;
+ MSG_PARAMS_E(b, end, o->x_params, flags);
+
+ return b - b0;
+}
+
+isize_t sip_session_expires_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+ sip_session_expires_t const *o = h->sh_session_expires;
+
+ MSG_PARAMS_SIZE(offset, o->x_params);
+
+ return offset;
+}
+
+/** Duplicate one #sip_session_expires_t object */
+char *sip_session_expires_dup_one(sip_header_t *dst, sip_header_t const *src,
+ char *b, isize_t xtra)
+{
+ sip_session_expires_t *o_dst = dst->sh_session_expires;
+ sip_session_expires_t const *o_src = src->sh_session_expires;
+
+ char *end = b + xtra;
+ b = msg_params_dup(&o_dst->x_params, o_src->x_params, b, xtra);
+ o_dst->x_delta = o_src->x_delta;
+ assert(b <= end); (void)end;
+
+ return b;
+}
+
+/** Update parameters in @SessionExpires header. */
+static int sip_session_expires_update(msg_common_t *h,
+ char const *name, isize_t namelen,
+ char const *value)
+{
+ sip_session_expires_t *x = (sip_session_expires_t *)h;
+
+ if (name == NULL) {
+ x->x_refresher = NULL;
+ }
+ else if (namelen == strlen("refresher") &&
+ !strncasecmp(name, "refresher", namelen)) {
+ x->x_refresher = value;
+ }
+
+ return 0;
+}
+
+
+
+/**@SIP_HEADER sip_min_se Min-SE Header
+ *
+ * The Min-SE header is used to indicate the minimum value for the session
+ * interval. Its syntax is defined in @RFC4028 as follows:
+ *
+ * @code
+ * MMin-SE = "Min-SE" HCOLON delta-seconds *(SEMI generic-param)
+ * @endcode
+ *
+ * The parsed Min-SE header is stored in #sip_min_se_t structure.
+ */
+
+/**@ingroup sip_min_se
+ * @typedef typedef struct sip_min_se_s sip_min_se_t;
+ *
+ * The structure #sip_min_se_t contains representation of the SIP
+ * @MinSE header.
+ *
+ * The #sip_min_se_t is defined as follows:
+ * @code
+ * typedef struct sip_min_se_s
+ * {
+ * sip_common_t min_common[1];
+ * sip_unknown_t *min_next;
+ * unsigned long min_delta; // Delta seconds
+ * sip_params_t *min_params; // List of extension parameters
+ * } sip_min_se_t;
+ * @endcode
+ */
+
+static msg_xtra_f sip_min_se_dup_xtra;
+static msg_dup_f sip_min_se_dup_one;
+#define sip_min_se_update NULL
+
+msg_hclass_t sip_min_se_class[] =
+SIP_HEADER_CLASS(min_se, "Min-SE", "", min_params, single, min_se);
+
+issize_t sip_min_se_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ sip_min_se_t *min = h->sh_min_se;
+
+ if (msg_delta_d((char const **) &s, &min->min_delta) < 0)
+ return -1;
+ if (*s == ';') {
+ if (msg_params_d(home, &s, &min->min_params) < 0 || *s)
+ return -1;
+ }
+
+ return 0;
+}
+
+issize_t sip_min_se_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
+{
+ char *end = b + bsiz, *b0 = b;
+ int n = 0;
+ sip_min_se_t const *o = (sip_min_se_t *)h;
+
+ n = snprintf(b, bsiz, "%lu", o->min_delta);
+ b += n;
+ MSG_PARAMS_E(b, end, o->min_params, flags);
+
+ return b - b0;
+}
+
+isize_t sip_min_se_dup_xtra(sip_header_t const *h, isize_t offset)
+{
+ sip_min_se_t const *o = (sip_min_se_t *)h;
+
+ MSG_PARAMS_SIZE(offset, o->min_params);
+
+ return offset;
+}
+
+/** Duplicate one #sip_min_se_t object */
+char *sip_min_se_dup_one(sip_header_t *dst, sip_header_t const *src,
+ char *b, isize_t xtra)
+{
+ sip_min_se_t *o_dst = (sip_min_se_t *)dst;
+ sip_min_se_t const *o_src = (sip_min_se_t *)src;
+
+ char *end = b + xtra;
+ b = msg_params_dup(&o_dst->min_params, o_src->min_params, b, xtra);
+ o_dst->min_delta = o_src->min_delta;
+ assert(b <= end); (void)end;
+
+ return b;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_status.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_status.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,198 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup sip_status_codes
+ * @CFILE sip_status.c
+ *
+ * SIP status codes and standard phrases.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Fri Aug 11 18:03:33 2000 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <sofia-sip/sip_status.h>
+
+char const
+ sip_100_Trying[] = "Trying",
+ sip_180_Ringing[] = "Ringing",
+ sip_181_Call_is_being_forwarded[] = "Call Is Being Forwarded",
+ sip_182_Queued[] = "Queued",
+ sip_183_Session_progress[] = "Session Progress",
+
+ sip_200_OK[] = "OK",
+ sip_202_Accepted[] = "Accepted",
+
+ sip_300_Multiple_choices[] = "Multiple Choices",
+ sip_301_Moved_permanently[] = "Moved Permanently",
+ sip_302_Moved_temporarily[] = "Moved Temporarily",
+ sip_305_Use_proxy[] = "Use Proxy",
+ sip_380_Alternative_service[] = "Alternative Service",
+
+ sip_400_Bad_request[] = "Bad Request",
+ sip_401_Unauthorized[] = "Unauthorized",
+ sip_402_Payment_required[] = "Payment Required",
+ sip_403_Forbidden[] = "Forbidden",
+ sip_404_Not_found[] = "Not Found",
+ sip_405_Method_not_allowed[] = "Method Not Allowed",
+ sip_406_Not_acceptable[] = "Not Acceptable",
+ sip_407_Proxy_auth_required[] = "Proxy Authentication Required",
+ sip_408_Request_timeout[] = "Request Timeout",
+ sip_409_Conflict[] = "Conflict",
+ sip_410_Gone[] = "Gone",
+ sip_411_Length_required[] = "Length Required",
+ sip_412_Precondition_failed[] = "Precondition Failed",
+ sip_413_Request_too_large[] = "Request Entity Too Large",
+ sip_414_Request_uri_too_long[] = "Request-URI Too Long",
+ sip_415_Unsupported_media[] = "Unsupported Media Type",
+ sip_416_Unsupported_uri[] = "Unsupported URI Scheme",
+ sip_417_Resource_priority[]= "Unknown Resource-Priority",
+ sip_420_Bad_extension[] = "Bad Extension",
+ sip_421_Extension_required[] = "Extension Required",
+ sip_422_Session_timer[] = "Session Interval Too Small",
+ sip_423_Interval_too_brief[] = "Interval Too Brief",
+
+ sip_480_Temporarily_unavailable[] = "Temporarily Unavailable",
+ sip_481_No_transaction[] = "Call/Transaction Does Not Exist",
+ sip_482_Loop_detected[] = "Loop Detected",
+ sip_483_Too_many_hops[] = "Too Many Hops",
+ sip_484_Address_incomplete[] = "Address Incomplete",
+ sip_485_Ambiguous[] = "Ambiguous",
+ sip_486_Busy_here[] = "Busy Here",
+ sip_487_Request_terminated[] = "Request Terminated",
+ sip_488_Not_acceptable[] = "Not Acceptable Here",
+ sip_489_Bad_event[] = "Bad Event",
+ sip_490_Request_updated[] = "Request Updated",
+ sip_491_Request_pending[] = "Request Pending",
+ sip_493_Undecipherable[] = "Undecipherable",
+ sip_494_Secagree_required [] = "Security Agreement Required",
+
+ sip_500_Internal_server_error[] = "Internal Server Error",
+ sip_501_Not_implemented[] = "Not Implemented",
+ sip_502_Bad_gateway[] = "Bad Gateway",
+ sip_503_Service_unavailable[] = "Service Unavailable",
+ sip_504_Gateway_time_out[] = "Gateway Time-out",
+ sip_505_Version_not_supported[] = "Version Not Supported",
+ sip_513_Message_too_large[] = "Message Too Large",
+ sip_580_Precondition[] = "Precondition Failure",
+
+ sip_600_Busy_everywhere[] = "Busy Everywhere",
+ sip_603_Decline[] = "Decline",
+ sip_604_Does_not_exist_anywhere[] = "Does Not Exist Anywhere",
+ sip_606_Not_acceptable[] = "Not Acceptable",
+ sip_687_Dialog_terminated[] = "Dialog Terminated"
+ ;
+
+/** Convert a SIP status code to a status phrase.
+ *
+ * Convert a SIP status code to a status phrase. If the status code is not
+ * in the range 100..699, NULL is returned. If the status code is not known,
+ * empty string "" is returned.
+ *
+ * @param status well-known status code in range 100..699
+ *
+ * @return
+ * A response message corresponding to status code, or NULL upon an error.
+ */
+char const *sip_status_phrase(int status)
+{
+ if (status < 100 || status > 699)
+ return NULL;
+
+ switch (status) {
+ case 100: return sip_100_Trying;
+ case 180: return sip_180_Ringing;
+ case 181: return sip_181_Call_is_being_forwarded;
+ case 182: return sip_182_Queued;
+ case 183: return sip_183_Session_progress;
+
+ case 200: return sip_200_OK;
+ case 202: return sip_202_Accepted;
+
+ case 300: return sip_300_Multiple_choices;
+ case 301: return sip_301_Moved_permanently;
+ case 302: return sip_302_Moved_temporarily;
+ case 305: return sip_305_Use_proxy;
+ case 380: return sip_380_Alternative_service;
+
+ case 400: return sip_400_Bad_request;
+ case 401: return sip_401_Unauthorized;
+ case 402: return sip_402_Payment_required;
+ case 403: return sip_403_Forbidden;
+ case 404: return sip_404_Not_found;
+ case 405: return sip_405_Method_not_allowed;
+ case 406: return sip_406_Not_acceptable;
+ case 407: return sip_407_Proxy_auth_required;
+ case 408: return sip_408_Request_timeout;
+ case 409: return sip_409_Conflict;
+ case 410: return sip_410_Gone;
+ case 411: return sip_411_Length_required;
+ case 412: return sip_412_Precondition_failed;
+ case 413: return sip_413_Request_too_large;
+ case 414: return sip_414_Request_uri_too_long;
+ case 415: return sip_415_Unsupported_media;
+ case 416: return sip_416_Unsupported_uri;
+ case 417: return sip_417_Resource_priority;
+
+ case 420: return sip_420_Bad_extension;
+ case 421: return sip_421_Extension_required;
+ case 422: return sip_422_Session_timer;
+ case 423: return sip_423_Interval_too_brief;
+
+ case 480: return sip_480_Temporarily_unavailable;
+ case 481: return sip_481_No_transaction;
+ case 482: return sip_482_Loop_detected;
+ case 483: return sip_483_Too_many_hops;
+ case 484: return sip_484_Address_incomplete;
+ case 485: return sip_485_Ambiguous;
+ case 486: return sip_486_Busy_here;
+ case 487: return sip_487_Request_terminated;
+ case 488: return sip_488_Not_acceptable;
+ case 489: return sip_489_Bad_event;
+ case 490: return sip_490_Request_updated;
+ case 491: return sip_491_Request_pending;
+ case 493: return sip_493_Undecipherable;
+ case 494: return sip_494_Secagree_required;
+
+ case 500: return sip_500_Internal_server_error;
+ case 501: return sip_501_Not_implemented;
+ case 502: return sip_502_Bad_gateway;
+ case 503: return sip_503_Service_unavailable;
+ case 504: return sip_504_Gateway_time_out;
+ case 505: return sip_505_Version_not_supported;
+ case 513: return sip_513_Message_too_large;
+ case 580: return sip_580_Precondition;
+
+ case 600: return sip_600_Busy_everywhere;
+ case 603: return sip_603_Decline;
+ case 604: return sip_604_Does_not_exist_anywhere;
+ case 606: return sip_606_Not_acceptable;
+ case 687: return sip_687_Dialog_terminated;
+ }
+
+ return "";
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_tag.c.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_tag.c.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1,94 @@
+/**@IFILE sip_tag.c.in
+ *
+ * Template for <sip_tag.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 at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE sip_tag.c SIP Tags.
+ *
+ * #AUTO#
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Fri Feb 23 12:46:42 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <assert.h>
+#include <stddef.h>
+#include <string.h>
+
+#include <sofia-sip/su.h>
+
+#define TAG_NAMESPACE "sip"
+
+#include "sofia-sip/sip_parser.h"
+#include <sofia-sip/sip_tag.h>
+
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/su_tag_inline.h>
+#include <sofia-sip/sip_tag_class.h>
+
+#include <sofia-sip/su_tagarg.h>
+
+tag_typedef_t siptag_any = NSTAG_TYPEDEF(*);
+
+tag_typedef_t siptag_sip = SIPMSGTAG_TYPEDEF(sip);
+
+tag_typedef_t siptag_header = {{ "sip", "header", siphdrtag_class, 0 }};
+
+tag_typedef_t siptag_header_str = STRTAG_TYPEDEF(header_str);
+
+tag_typedef_t siptag_end = TAG_TYPEDEF(tag_end, end);
+
+
+extern msg_hclass_t sip_#xxxxxx#_class[];
+
+/**@ingroup sip_#xxxxxx#
+ * Tag for @ref sip_#xxxxxx# "#xxxxxxx_xxxxxxx#" object.
+ */
+tag_typedef_t siptag_#xxxxxx# = SIPHDRTAG_TYPEDEF(#xxxxxx#);
+/**@ingroup sip_#xxxxxx#
+ * Tag for string with @ref sip_#xxxxxx# "#xxxxxxx_xxxxxxx#" value.
+ */
+tag_typedef_t siptag_#xxxxxx#_str = SIPSTRTAG_TYPEDEF(#xxxxxx#);
+
+/** List of all tags for SIP headers */
+tag_type_t sip_tag_list[] =
+{
+ siptag_#xxxxxx#,
+ NULL
+};
+
+/** List of all string tags for SIP headers */
+tag_type_t sip_tag_str_list[] =
+{
+ siptag_#xxxxxx#_str,
+ NULL
+};
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_tag_class.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_tag_class.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,476 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@SIP_TAG
+ *
+ * @CFILE sip_tag_class.c SIP Tag classes
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Fri Feb 23 12:46:42 2001 ppessi
+ */
+
+#include "config.h"
+
+#include "sofia-sip/sip_parser.h"
+
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/su_tag_inline.h>
+#include <sofia-sip/sip_tag_class.h>
+#include <sofia-sip/sip_tag.h>
+#include <sofia-sip/su_tagarg.h>
+#include <sofia-sip/su_strlst.h>
+
+#include <ctype.h>
+#include <assert.h>
+#include <stddef.h>
+#include <string.h>
+
+/** Tag class for SIP header tags. @HIDE */
+tag_class_t siphdrtag_class[1] =
+ {{
+ sizeof(siphdrtag_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 */ siptag_filter,
+ /* tc_ref_set */ t_ptr_ref_set,
+ /* tc_scan */ msghdrtag_scan,
+ }};
+
+/** Tag class for SIP header string tags. @HIDE */
+tag_class_t sipstrtag_class[1] =
+ {{
+ sizeof(sipstrtag_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 SIP message tags. @HIDE */
+tag_class_t sipmsgtag_class[1] =
+ {{
+ sizeof(sipmsgtag_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 /* siptag_sip_filter */,
+ /* tc_ref_set */ t_ptr_ref_set,
+ }};
+
+
+/** Filter a for SIP header tag.
+ *
+ * @param[in] dst tag list for filtering result. May be NULL.
+ * @param[in] f filter tag
+ * @param[in] src tag item from source list.
+ * @param[in,out] bb pointer to pointer of mempory area used to dup
+ * the filtering result
+ *
+ * This function is also used to calculate size for filtering result.
+ */
+tagi_t *siptag_filter(tagi_t *dst,
+ tagi_t const f[],
+ tagi_t const *src,
+ void **bb)
+{
+ tagi_t stub[2] = {{ NULL }};
+ tag_type_t srctt, tt = f->t_tag;
+ msg_hclass_t *hc = (msg_hclass_t *)tt->tt_magic;
+
+ assert(src);
+
+ srctt = src->t_tag;
+
+ /* Match filtered header with a header from a SIP message */
+ if (srctt && srctt->tt_class == sipmsgtag_class) {
+ sip_t const *sip = (sip_t const *)src->t_value;
+ sip_header_t const **hh, *h;
+
+ if (sip == NULL)
+ return dst;
+
+ hh = (sip_header_t const **)
+ msg_hclass_offset((msg_mclass_t *)sip->sip_common->h_class,
+ (msg_pub_t *)sip, hc);
+
+ /* Is header present in the SIP message? */
+ if ((char *)hh >= ((char *)sip + sip->sip_size) ||
+ (char *)hh < (char *)&sip->sip_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; srctt = tt;
+ }
+
+ if (tt != srctt)
+ 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;
+ }
+}
+
+/** Duplicate headers from taglist and add them to the SIP message. */
+int sip_add_tl(msg_t *msg, sip_t *sip,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ tagi_t const *t;
+ ta_list ta;
+ int retval;
+
+ ta_start(ta, tag, value);
+
+ t = ta_args(ta);
+
+ retval = sip_add_tagis(msg, sip, &t);
+
+ ta_end(ta);
+ return retval;
+}
+
+/** Add duplicates of headers from taglist to the SIP message. */
+int sip_add_tagis(msg_t *msg, sip_t *sip, tagi_t const **inout_list)
+{
+ tagi_t const *t;
+ tag_type_t tag;
+ tag_value_t value;
+
+ if (!msg || !inout_list)
+ return -1;
+
+ if (sip == NULL)
+ sip = sip_object(msg);
+
+ for (t = *inout_list; t; t = t_next(t)) {
+ tag = t->t_tag, value = t->t_value;
+
+ if (tag == NULL || tag == siptag_end) {
+ t = t_next(t);
+ break;
+ }
+
+ if (!value)
+ continue;
+
+ if (SIPTAG_P(tag)) {
+ msg_hclass_t *hc = (msg_hclass_t *)tag->tt_magic;
+ msg_header_t *h = (msg_header_t *)value, **hh;
+
+ if (h == SIP_NONE) { /* Remove header */
+ hh = msg_hclass_offset(msg_mclass(msg), (msg_pub_t *)sip, hc);
+ while (*hh)
+ msg_header_remove(msg, (msg_pub_t *)sip, *hh);
+ continue;
+ }
+
+ if (tag == siptag_header)
+ hc = h->sh_class;
+
+ if (msg_header_add_dup_as(msg, (msg_pub_t *)sip, hc, h) < 0)
+ break;
+ }
+ else if (SIPTAG_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 *)sip, hc, s) < 0)
+ return -1;
+ }
+ else if (tag == siptag_header_str) {
+ if (msg_header_add_str(msg, (msg_pub_t *)sip, (char const *)value) < 0)
+ return -1;
+ }
+ }
+
+ *inout_list = t;
+
+ return 0;
+}
+
+static char const *append_escaped(su_strlst_t *l,
+ msg_hclass_t *hc,
+ char const *s);
+
+/** Convert tagged SIP headers to a URL-encoded headers list.
+ *
+ * The SIP URI can contain a query part separated with the "?", which
+ * specifies SIP headers that are included in the request constructed
+ * from the URI. For example, using URI @code <sip:example.com?subject=test>
+ * would include @Subject header with value "test" in the request.
+ *
+ * @param home memory home used to allocate query string (if NULL, use malloc)
+ * @param tag, value, ... list of tagged arguments
+ *
+ * @bug This function returns NULL if SIPTAG_REQUEST(), SIPTAG_STATUS(),
+ * SIPTAG_HEADER(), SIPTAG_UNKNOWN(), SIPTAG_ERROR(), SIPTAG_SEPARATOR(), or
+ * any corresponding string tag is included in the tag list. It ignores
+ * SIPTAG_SIP().
+ *
+ * @par Example
+ * @code
+ * url->url_headers =
+ * sip_headers_as_url_query(home, SIPTAG_REPLACES(replaces), TAG_END());
+ * @endcode
+ *
+ * @since New in @VERSION_1_12_4.
+ *
+ * @sa
+ * url_query_as_header_string(), sip_url_query_as_taglist(),
+ * nta_msg_request_complete(),
+ * @RFC3261 section 19.1.1 "Headers", #url_t, url_s#url_headers
+ */
+char *sip_headers_as_url_query(su_home_t *home,
+ tag_type_t tag, tag_value_t value,
+ ...)
+{
+ ta_list ta;
+ tagi_t const *t;
+ su_strlst_t *l = su_strlst_create(home);
+ su_home_t *lhome = su_strlst_home(l);
+ char const *retval = "";
+
+ if (!l)
+ return NULL;
+
+ ta_start(ta, tag, value);
+
+ for (t = ta_args(ta); t && retval; t = t_next(t)) {
+ msg_hclass_t *hc;
+
+ if (t->t_value == 0 || t->t_value == -1)
+ continue;
+
+ hc = (msg_hclass_t *)t->t_tag->tt_magic;
+
+ if (SIPTAG_P(t->t_tag)) {
+ sip_header_t const *h = (sip_header_t const *)t->t_value;
+ char *s = sip_header_as_string(lhome, h);
+
+ retval = append_escaped(l, hc, s);
+
+ if (retval != s)
+ su_free(lhome, s);
+ }
+ else if (SIPTAG_STR_P(t->t_tag)) {
+ retval = append_escaped(l, hc, (char const *)t->t_value);
+ }
+ }
+
+ ta_end(ta);
+
+ if (retval)
+ retval = su_strlst_join(l, home, "");
+
+ su_strlst_destroy(l);
+
+ return (char *)retval;
+}
+
+/* "[" / "]" / "/" / "?" / ":" / "+" / "$" */
+#define HNV_UNRESERVED "[]/?;+$"
+#define HNV_RESERVED ":=,"
+
+/* Append a string to list and url-escape it if needed */
+static
+char const *append_escaped(su_strlst_t *l,
+ msg_hclass_t *hc,
+ char const *s)
+{
+ char const *name;
+
+ if (hc == NULL)
+ return NULL;
+
+ if (hc->hc_hash == sip_payload_hash)
+ name = "body";
+ else /* XXX - could we use short form? */
+ name = hc->hc_name;
+
+ if (name == NULL)
+ return NULL;
+
+ if (s) {
+ su_home_t *lhome = su_strlst_home(l);
+ size_t slen;
+ isize_t elen;
+ char *n, *escaped;
+ char *sep = su_strlst_len(l) > 0 ? "&" : "";
+
+ n = su_sprintf(lhome, "%s%s=", sep, name);
+ if (!su_strlst_append(l, n))
+ return NULL;
+
+ for (;*n; n++)
+ if (isupper(*n))
+ *n = tolower(*n);
+
+ slen = strlen(s); elen = url_esclen(s, HNV_RESERVED);
+
+ if ((size_t)elen == slen)
+ return su_strlst_append(l, s);
+
+ escaped = su_alloc(lhome, elen + 1);
+ if (escaped)
+ return su_strlst_append(l, url_escape(escaped, s, HNV_RESERVED));
+ }
+
+ return NULL;
+}
+
+/** Convert URL query to a tag list.
+ *
+ * SIP headers encoded as URL @a query is parsed returned as a tag list.
+ * Unknown headers are encoded as SIPTAG_HEADER_STR().
+ *
+ * @param home memory home used to alloate string (if NULL, malloc() it)
+ * @param query query part from SIP URL
+ * @param parser optional SIP parser used
+ *
+ * @sa sip_add_tl(), sip_add_tagis(), SIPTAG_HEADER_STR(),
+ * sip_headers_as_url_query(), url_query_as_header_string(),
+ * @RFC3261 section 19.1.1 "Headers", #url_t, url_s#url_headers
+ *
+ * @NEW_1_12_4.
+ *
+ * @bug Extension headers are ignored. The @a parser parameter is not used
+ * at the moment.
+ */
+tagi_t *sip_url_query_as_taglist(su_home_t *home, char const *query,
+ msg_mclass_t const *parser)
+{
+ tagi_t *retval = NULL;
+ char *s;
+ su_strlst_t *l;
+ isize_t N;
+ size_t i, j, n;
+
+ if (query == NULL || query[0] == '\0' || query[0] == '&')
+ return NULL;
+
+ s = su_strdup(home, query); if (!s) return NULL;
+ l = su_strlst_split(home, s, "&");
+ N = su_strlst_len(l);
+
+ if (N == 0)
+ goto error;
+
+ retval = su_zalloc(home, (N + 1) * sizeof (*retval));
+ if (retval == NULL)
+ goto error;
+
+ for (i = 0; i < N; i++) {
+ char const *hnv;
+ char *value;
+ tag_type_t t;
+ tag_value_t v;
+ msg_hclass_t *hc = NULL;
+
+ hnv = su_strlst_item(l, i);
+ n = strcspn(hnv, "=");
+ if (n == 0)
+ break;
+
+ if (n == 4 && strncasecmp(hnv, "body", 4) == 0)
+ t = siptag_payload, hc = sip_payload_class;
+ else for (j = 0; (t = sip_tag_list[j]); j++) {
+ hc = (msg_hclass_t *)sip_tag_list[j]->tt_magic;
+ if (n == 1 && strncasecmp(hnv, hc->hc_short, 1) == 0)
+ break;
+ else if (n == (size_t)hc->hc_len && strncasecmp(hnv, hc->hc_name, n) == 0)
+ break;
+ }
+
+ value = (char *)hnv + n;
+ *value++ = ':';
+ n = url_unescape_to(value, value, SIZE_MAX);
+ value[n] = '\0';
+
+ if (t) {
+ msg_header_t *h = msg_header_make(home, hc, value);
+ if (!h)
+ break;
+ v = (tag_value_t)h;
+ }
+ else {
+ char *s;
+ s = su_alloc(home, n + 1);
+ if (!s)
+ break;
+ memcpy(s, value, n + 1);
+ t = siptag_header_str;
+ v = (tag_value_t)s;
+ }
+ retval[i].t_tag = t, retval[i].t_value = v;
+ }
+
+ retval[i].t_tag = NULL, retval[i].t_value = (tag_value_t)0;
+
+ if (i < N) {
+ for (j = 0; j < i; j++) {
+ if (retval[i].t_tag == siptag_header_str)
+ su_free(home, (void *)retval[i].t_value);
+ else
+ msg_header_free_all(home, (msg_header_t *)retval[i].t_value);
+ }
+ su_free(home, retval);
+ retval = NULL;
+ }
+
+ error:
+ su_free(home, s);
+ su_strlst_destroy(l);
+
+ return retval;
+}
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_time.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_time.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,107 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE sip_time.c
+ * @brief SIP time handling
+ *
+ * Functions for handling time and dates in SIP.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Wed Apr 11 18:57:06 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <assert.h>
+
+#include "sofia-sip/sip_parser.h"
+#include <sofia-sip/sip_util.h>
+#include <sofia-sip/msg_date.h>
+#include <sofia-sip/su_time.h>
+
+/** Return current time as seconds since Epoch. */
+sip_time_t sip_now(void)
+{
+ return su_now().tv_sec;
+}
+
+/**@ingroup sip_expires
+ *
+ * Calculate the expiration time for a SIP @Contact.
+ *
+ * @param m @Contact header
+ * @param ex @Expires header
+ * @param date @Date header
+ * @param def default expiration time
+ * @param now current time.
+ *
+ * @note If @a m is NULL, the function calculates the expiration time
+ * based on the @Expires and @Date headers.
+ *
+ * @note If @a now is 0, the function gets the current time using sip_now().
+ *
+ * @return
+ * The expiration time in seconds.
+ */
+sip_time_t sip_contact_expires(sip_contact_t const *m,
+ sip_expires_t const *ex,
+ sip_date_t const *date,
+ sip_time_t def,
+ sip_time_t now)
+{
+ sip_time_t time = 0, delta = def;
+
+ /* "Contact: *" */
+ if (m && m->m_url->url_type == url_any)
+ return 0;
+
+ if (m && m->m_expires) {
+ msg_param_t expires = m->m_expires;
+ if (msg_date_delta_d(&expires, &time, &delta) < 0)
+ return def;
+ }
+ else if (ex) {
+ time = ex->ex_date;
+ delta = ex->ex_delta;
+ }
+
+ if (time) {
+ if (date)
+ now = date->d_time;
+ else if (now == 0)
+ now = sip_now();
+
+ if (time > now)
+ delta = time - now;
+ else
+ delta = 0;
+ }
+
+ return delta;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_util.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_util.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1422 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE sip_util.c
+ *
+ * SIP utility functions.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Tue Jun 13 02:57:51 2000 ppessi
+ */
+
+#include "config.h"
+
+/* Avoid casting sip_t to msg_pub_t and sip_header_t to msg_header_t */
+#define MSG_PUB_T struct sip_s
+#define MSG_HDR_T union sip_header_u
+
+#include <sofia-sip/su_alloc.h>
+#include <sofia-sip/su_strlst.h>
+#include <sofia-sip/string0.h>
+
+#include "sofia-sip/sip_parser.h"
+#include <sofia-sip/sip_header.h>
+#include <sofia-sip/sip_util.h>
+#include <sofia-sip/sip_status.h>
+
+#include <sofia-sip/bnf.h>
+#include <sofia-sip/hostdomain.h>
+
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <float.h>
+#include <limits.h>
+#include <ctype.h>
+
+/**
+ * Compare two SIP addresses ( @From or @To headers).
+ *
+ * @retval nonzero if matching.
+ * @retval zero if not matching.
+ */
+int sip_addr_match(sip_addr_t const *a, sip_addr_t const *b)
+{
+ return
+ (a->a_tag == NULL || b->a_tag == NULL ||
+ strcmp(a->a_tag, b->a_tag) == 0)
+ &&
+ str0casecmp(a->a_host, b->a_host) == 0
+ &&
+ str0cmp(a->a_user, b->a_user) == 0
+ &&
+ str0cmp(a->a_url->url_scheme, b->a_url->url_scheme);
+}
+
+
+/**@ingroup sip_contact
+ *
+ * Create a contact header.
+ *
+ * Create a @Contact header object with the given URL and list of parameters.
+ *
+ * @param home memory home
+ * @param url URL (string or pointer to url_t)
+ * @param p,... NULL-terminated list of @Contact parameters
+ *
+ * @return
+ * A pointer to newly created @Contact header object when successful or NULL
+ * upon an error.
+ *
+ */
+sip_contact_t * sip_contact_create(su_home_t *home,
+ url_string_t const *url,
+ char const *p, ...)
+{
+ su_strlst_t *l;
+ su_home_t *lhome;
+ sip_contact_t *m;
+
+ if (url == NULL)
+ return NULL;
+
+ l = su_strlst_create_with(NULL, "<", NULL), lhome = su_strlst_home(l);
+ if (l == NULL)
+ return NULL;
+
+ if (url_is_string(url))
+ su_strlst_append(l, (char const *)url);
+ else
+ su_strlst_append(l, url_as_string(lhome, url->us_url));
+
+ su_strlst_append(l, ">");
+
+ if (p) {
+ va_list ap;
+ va_start(ap, p);
+
+ for (; p; p = va_arg(ap, char const *)) {
+ su_strlst_append(l, ";");
+ su_strlst_append(l, p);
+ }
+
+ va_end(ap);
+ }
+
+ m = sip_contact_make(home, su_strlst_join(l, lhome, ""));
+
+ su_strlst_destroy(l);
+
+ return m;
+}
+
+/** Convert a @Via header to @Contact header.
+ *
+ * The @Contact URI will contain the port number if needed. If transport
+ * protocol name starts with "TLS", "SIPS:" URI schema is used. Transport
+ * parameter is included in the URI unless the transport protocol is UDP.
+ *
+ * @param home memory home
+ * @param v @Via header field structure
+ * (with <sent-protocol> and <sent-by> parameters)
+ * @param user username for @Contact URI (may be NULL)
+ *
+ * @retval contact header structure
+ * @retval NULL upon an error
+ *
+ * @sa sip_contact_create_from_via_with_transport(),
+ * sip_contact_string_from_via()
+ */
+sip_contact_t *
+sip_contact_create_from_via(su_home_t *home,
+ sip_via_t const *v,
+ char const *user)
+{
+ const char *tp;
+
+ if (!v) return NULL;
+
+ tp = v->v_protocol;
+
+ if (tp == sip_transport_udp ||
+ strcasecmp(tp, sip_transport_udp) == 0) /* Default is UDP */
+ tp = NULL;
+
+ return sip_contact_create_from_via_with_transport(home, v, user, tp);
+}
+
+/** Convert a @Via header to @Contact header.
+ *
+ * The @Contact URI will contain the port number and transport parameters if
+ * needed. If transport protocol name starts with "TLS", "SIPS:" URI schema
+ * is used.
+ *
+ * @param home memory home
+ * @param v @Via header field structure
+ * (with <sent-by> parameter containing host and port)
+ * @param user username for @Contact URI (may be NULL)
+ * @param transport transport name for @Contact URI (may be NULL)
+ *
+ * @retval contact header structure
+ * @retval NULL upon an error
+ *
+ * @sa sip_contact_create_from_via(), sip_contact_string_from_via()
+ */
+sip_contact_t *
+sip_contact_create_from_via_with_transport(su_home_t *home,
+ sip_via_t const *v,
+ char const *user,
+ char const *transport)
+{
+ char *s = sip_contact_string_from_via(NULL, v, user, transport);
+ sip_contact_t *m = sip_contact_make(home, s);
+ su_free(NULL, s);
+ return m;
+}
+
+/** Convert a @Via header to @Contact URL string.
+ *
+ * The @Contact URI will contain the port number and transport parameters if
+ * needed. If transport protocol name starts with "TLS", "SIPS:" URI schema
+ * is used.
+ *
+ * The contact URI string returned will always have angle brackets ("<" and
+ * ">") around it.
+ *
+ * @param home memory home
+ * @param v @Via header field structure
+ * (with <sent-by> parameter containing host and port)
+ * @param user username for @Contact URI (may be NULL)
+ * @param transport transport name for @Contact URI (may be NULL)
+ *
+ * @retval string containing Contact URI with angle brackets
+ * @retval NULL upon an error
+ */
+char *
+sip_contact_string_from_via(su_home_t *home,
+ sip_via_t const *v,
+ char const *user,
+ char const *transport)
+{
+ const char *host, *port, *maddr, *comp;
+ char const *scheme = "sip:";
+ int one = 1;
+ char _transport[16];
+
+ if (!v) return NULL;
+
+ host = v->v_host;
+ if (v->v_received)
+ host = v->v_received;
+ port = sip_via_port(v, &one);
+ maddr = v->v_maddr;
+ comp = v->v_comp;
+
+ if (host == NULL)
+ return NULL;
+
+ if (sip_transport_has_tls(v->v_protocol) ||
+ sip_transport_has_tls(transport)) {
+ scheme = "sips:";
+ if (port && strcmp(port, SIPS_DEFAULT_SERV) == 0)
+ port = NULL;
+ if (port || host_is_ip_address(host))
+ transport = NULL;
+ }
+ else if (port && host_is_ip_address(host) &&
+ strcmp(port, SIP_DEFAULT_SERV) == 0) {
+ port = NULL;
+ }
+
+ if (transport && strncasecmp(transport, "SIP/2.0/", 8) == 0)
+ transport += 8;
+
+ /* Make transport parameter lowercase */
+ if (transport && strlen(transport) < (sizeof _transport)) {
+ char *s = strcpy(_transport, transport);
+
+ for (s = _transport; *s && *s != ';'; s++)
+ if (isupper(*s))
+ *s = tolower(*s);
+
+ transport = _transport;
+ }
+
+ return su_strcat_all(home,
+ "<",
+ scheme,
+ user ? user : "", user ? "@" : "",
+ host,
+ SIP_STRLOG(":", port),
+ SIP_STRLOG(";transport=", transport),
+ SIP_STRLOG(";maddr=", maddr),
+ SIP_STRLOG(";comp=", comp),
+ ">",
+ NULL);
+}
+
+/** Check if tranport name refers to TLS */
+int sip_transport_has_tls(char const *transport_name)
+{
+ if (!transport_name)
+ return 0;
+
+ if (transport_name == sip_transport_tls)
+ return 1;
+
+ /* transport name starts with TLS or SIP/2.0/TLS */
+ return
+ strncasecmp(transport_name, "TLS", 3) == 0 ||
+ strncasecmp(transport_name, sip_transport_tls, 11) == 0;
+}
+
+/**Perform sanity check on a SIP message
+ *
+ * Check that the SIP message has all the mandatory fields.
+ *
+ * @param sip SIP message to be checked
+ *
+ * @return
+ * When the SIP message fulfills the minimum requirements, return zero,
+ * otherwise a negative status code.
+ */
+int
+sip_sanity_check(sip_t const *sip)
+{
+ if (!sip ||
+ !((sip->sip_request != NULL) ^ (sip->sip_status != NULL)) ||
+ !sip->sip_to ||
+ !sip->sip_from ||
+ !sip->sip_call_id ||
+ !sip->sip_cseq ||
+ !sip->sip_via ||
+ (sip->sip_flags & MSG_FLG_TRUNC))
+ return -1; /* Bad request */
+
+ if (sip->sip_request) {
+ url_t const *ruri = sip->sip_request->rq_url;
+
+ switch (ruri->url_type) {
+ case url_invalid:
+ return -1;
+
+ case url_sip: case url_sips: case url_im: case url_pres:
+ if (!ruri->url_host || strlen(ruri->url_host) == 0)
+ return -1;
+ break;
+
+ case url_tel:
+ if (!ruri->url_user || strlen(ruri->url_user) == 0)
+ return -1;
+ break;
+ }
+
+ if (sip->sip_request->rq_method != sip->sip_cseq->cs_method)
+ return -1;
+ if (sip->sip_request->rq_method == sip_method_unknown &&
+ str0casecmp(sip->sip_request->rq_method_name,
+ sip->sip_cseq->cs_method_name))
+ return -1;
+ }
+
+ return 0;
+}
+
+/** Decode a string containg header field.
+ *
+ * The header object is initialized with the contents of the string. The
+ * string is modified when parsing. The home is used to allocate extra
+ * memory required when parsing, e.g., for parameter list or when there
+ * string contains multiple header fields.
+ *
+ * @deprecated
+ * Use msg_header_make() or header-specific make functions, e.g.,
+ * sip_via_make().
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error.
+ */
+issize_t sip_header_field_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
+{
+ assert(SIP_HDR_TEST(h));
+
+ if (h && s && s[slen] == '\0') {
+ size_t n = span_lws(s);
+ s += n; slen -= n;
+
+ for (n = slen; n >= 1 && IS_LWS(s[n - 1]); n--)
+ ;
+
+ s[n] = '\0';
+
+ return h->sh_class->hc_parse(home, h, s, slen);
+ }
+ else
+ return -1;
+}
+
+/** Encode a SIP header contents.
+ *
+ * @deprecated Use msg_header_field_e() instead.
+ */
+issize_t sip_header_field_e(char *b, isize_t bsiz, sip_header_t const *h, int flags)
+{
+ return msg_header_field_e(b, bsiz, h, flags);
+}
+
+/** Convert the header @a h to a string allocated from @a home. */
+char *sip_header_as_string(su_home_t *home, sip_header_t const *h)
+{
+ ssize_t len;
+ char *rv, s[128];
+
+ if (h == NULL)
+ return NULL;
+
+ len = sip_header_field_e(s, sizeof(s), h, 0);
+
+ if (len >= 0 && (size_t)len < sizeof(s))
+ return su_strdup(home, s);
+
+ if (len == -1)
+ len = 2 * sizeof(s);
+ else
+ len += 1;
+
+ for (rv = su_alloc(home, len);
+ rv;
+ rv = su_realloc(home, rv, len)) {
+ ssize_t n = sip_header_field_e(s, sizeof(s), h, 0);
+ if (n > -1 && n + 1 <= len)
+ break;
+ if (n > -1) /* glibc >2.1 */
+ len = n + 1;
+ else /* glibc 2.0 */
+ len *= 2;
+ }
+
+ return rv;
+}
+
+/** Calculate size of a SIP header. */
+isize_t sip_header_size(sip_header_t const *h)
+{
+ assert(h == NULL || h == SIP_NONE || h->sh_class);
+ if (h == NULL || h == SIP_NONE)
+ return 0;
+ else
+ return h->sh_class->hc_dxtra(h, h->sh_class->hc_size);
+}
+
+/** Duplicate a url or make a url out of string.
+ * @deprecated Use url_hdup() instead.
+ */
+url_t *sip_url_dup(su_home_t *home, url_t const *o)
+{
+ return url_hdup(home, o);
+}
+
+/**Calculate Q value.
+ *
+ * Convert q-value string @a q to numeric value
+ * in range (0..1000). Q values are used, for instance, to describe
+ * relative priorities of registered contacts.
+ *
+ * @param q q-value string <code>("1" | "." 1,3DIGIT)</code>
+ *
+ * @return An integer in range 0 .. 1000.
+ */
+unsigned sip_q_value(char const *q)
+{
+ unsigned value = 0;
+
+ if (!q)
+ return 1000;
+ if (q[0] != '0' && q[0] != '.' && q[0] != '1')
+ return 500; /* Garbage... */
+ while (q[0] == '0')
+ q++;
+ if (q[0] >= '1' && q[0] <= '9')
+ return 1000;
+ if (q[0] == '\0')
+ return 0;
+ if (q[0] != '.')
+ return 500; /* Garbage... */
+
+ if (q[1] >= '0' && q[1] <= '9') {
+ value = (q[1] - '0') * 100;
+ if (q[2] >= '0' && q[2] <= '9') {
+ value += (q[2] - '0') * 10;
+ if (q[3] >= '0' && q[3] <= '9') {
+ value += (q[3] - '0');
+ if (q[4] > '5' && q[4] <= '9')
+ /* Round upwards */
+ value += 1;
+ else if (q[4] == '5')
+ value += value & 1; /* Round to even */
+ }
+ }
+ }
+
+ return value;
+}
+
+
+/**@ingroup sip_route
+ *
+ * Get first route header and remove it from its fragment chain.
+ *
+ */
+sip_route_t *sip_route_remove(msg_t *msg, sip_t *sip)
+{
+ sip_route_t *r;
+
+ if ((r = sip->sip_route))
+ msg_header_remove(msg, (msg_pub_t *)sip, (msg_header_t *)r);
+
+ return r;
+}
+
+/**@ingroup sip_route
+ *
+ * Get last route header and remove it from its fragment chain.
+ *
+ */
+sip_route_t *sip_route_pop(msg_t *msg, sip_t *sip)
+{
+ sip_route_t *r;
+
+ for (r = sip->sip_route; r; r = r->r_next)
+ if (r->r_next == NULL) {
+ msg_header_remove(msg, (msg_pub_t *)sip, (msg_header_t *)r);
+ return r;
+ }
+
+ return NULL;
+}
+
+
+/**@ingroup sip_route
+ *
+ * Get first route header and rewrite the RequestURI.
+ */
+sip_route_t *sip_route_follow(msg_t *msg, sip_t *sip)
+{
+ if (sip->sip_route) {
+ /* XXX - in case of outbound proxy, route may contain our address */
+
+ sip_route_t *r = sip_route_remove(msg, sip);
+ sip_request_t *rq = sip->sip_request;
+
+ rq = sip_request_create(msg_home(msg), rq->rq_method, rq->rq_method_name,
+ (url_string_t const *)r->r_url, rq->rq_version);
+ url_strip_transport(rq->rq_url);
+
+ msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)rq);
+
+ return r;
+ }
+ return NULL;
+}
+
+/**@ingroup sip_route
+ *
+ * Check if route header has lr param.
+ *
+ * "lr" param can be either URL or header parameter.
+ */
+int
+sip_route_is_loose(sip_route_t const *r)
+{
+ if (!r)
+ return 0;
+ if (r->r_url->url_params)
+ return url_has_param(r->r_url, "lr");
+ else
+ return r->r_params && msg_params_find(r->r_params, "lr") != NULL;
+}
+
+/**@ingroup sip_route
+ *
+ * Reverse a route header (@Route, @RecordRoute, @Path, @ServiceRoute).
+ */
+sip_route_t *sip_route_reverse_as(su_home_t *home,
+ msg_hclass_t *hc,
+ sip_route_t const *route)
+{
+ sip_route_t *reverse = NULL;
+ sip_route_t r[1], *tmp;
+ sip_route_init(r);
+
+ r->r_common->h_class = hc;
+
+ for (reverse = NULL; route; route = route->r_next) {
+ *r->r_url = *route->r_url;
+ /* Fix broken (Record-)Routes without <> */
+ if (r->r_url->url_params == NULL
+ && r->r_params
+ && r->r_params[0]
+ && (r->r_params[0][0] == 'l' || r->r_params[0][0] == 'L')
+ && (r->r_params[0][1] == 'r' || r->r_params[0][1] == 'R')
+ && (r->r_params[0][2] == '=' || r->r_params[0][2] == 0))
+ r->r_url->url_params = route->r_params[0],
+ r->r_params = route->r_params + 1;
+ else
+ r->r_params = route->r_params;
+ tmp = (sip_route_t *)msg_header_dup_as(home, hc, (msg_header_t *)r);
+ if (!tmp)
+ goto error;
+ tmp->r_next = reverse;
+ reverse = tmp;
+ }
+
+ return reverse;
+
+ error:
+ msg_header_free_all(home, (msg_header_t *)reverse);
+ return NULL;
+}
+
+
+/**@ingroup sip_route
+ *
+ * Reverse a @Route header.
+ *
+ * Reverse A route header like @RecordRoute or @Path.
+ */
+sip_route_t *sip_route_reverse(su_home_t *home, sip_route_t const *route)
+{
+ return sip_route_reverse_as(home, sip_route_class, route);
+}
+
+
+/**@ingroup sip_route
+ *
+ * Fix and duplicate a route header (@Route, @RecordRoute, @Path, @ServiceRoute).
+ *
+ */
+sip_route_t *sip_route_fixdup_as(su_home_t *home,
+ msg_hclass_t *hc,
+ sip_route_t const *route)
+{
+ sip_route_t *copy = NULL;
+ sip_route_t r[1], **rr;
+ sip_route_init(r);
+
+ /* Copy the record route as route */
+ for (rr = © route; route = route->r_next) {
+ *r->r_url = *route->r_url;
+ /* Fix broken (Record-)Routes without <> */
+ if (r->r_url->url_params == NULL
+ && r->r_params
+ && r->r_params[0]
+ && (r->r_params[0][0] == 'l' || r->r_params[0][0] == 'L')
+ && (r->r_params[0][1] == 'r' || r->r_params[0][1] == 'R')
+ && (r->r_params[0][2] == '=' || r->r_params[0][2] == 0))
+ r->r_url->url_params = route->r_params[0],
+ r->r_params = route->r_params + 1;
+ else
+ r->r_params = route->r_params;
+ *rr = (sip_route_t *)msg_header_dup_as(home, hc, (msg_header_t *)r);
+ if (!*rr) goto error;
+ rr = &(*rr)->r_next;
+ }
+
+ return copy;
+
+ error:
+ msg_header_free_all(home, (msg_header_t *)copy);
+ return NULL;
+}
+
+
+/**@ingroup sip_route
+ *
+ * Fix and duplicate a @Route header.
+ *
+ * Copy a route header like @RecordRoute or @Path as @Route.
+ *
+ */
+sip_route_t *sip_route_fixdup(su_home_t *home, sip_route_t const *route)
+{
+ return sip_route_fixdup_as(home, sip_route_class, route);
+}
+
+static void sip_fragment_clear_chain(sip_header_t *h)
+{
+ void const *next;
+
+ for (h = h; h; h = h->sh_succ) {
+ next = (char *)h->sh_data + h->sh_len;
+
+ sip_fragment_clear(h->sh_common);
+
+ if (!next ||
+ !h->sh_succ ||
+ h->sh_next != h->sh_succ ||
+ h->sh_succ->sh_data != next ||
+ h->sh_succ->sh_len)
+ return;
+ }
+}
+
+/**@ingroup sip_route
+ *
+ * Fix @Route header.
+ */
+sip_route_t *sip_route_fix(sip_route_t *route)
+{
+ sip_route_t *r;
+ sip_header_t *h = NULL;
+ size_t i;
+
+ for (r = route; r; r = r->r_next) {
+ /* Keep track of first header structure on this header line */
+ if (!h
+ || (char *)h->sh_data + h->sh_len != r->r_common->h_data
+ || r->r_common->h_len)
+ h = (sip_header_t *)r;
+
+ if (r->r_url->url_params == NULL
+ && r->r_params
+ && r->r_params[0]
+ && (r->r_params[0][0] == 'l' || r->r_params[0][0] == 'L')
+ && (r->r_params[0][1] == 'r' || r->r_params[0][1] == 'R')
+ && (r->r_params[0][2] == '=' || r->r_params[0][2] == 0)) {
+ r->r_url->url_params = r->r_params[0];
+
+ for (i = 0; r->r_params[i]; i++)
+ ((char const **)r->r_params)[i] = r->r_params[i + 1];
+
+ sip_fragment_clear_chain(h);
+ }
+ }
+
+ return route;
+}
+
+/**@ingroup sip_via
+ *
+ * Get first via header and remove it from its fragment chain.
+ */
+sip_via_t *sip_via_remove(msg_t *msg, sip_t *sip)
+{
+ sip_via_t *v;
+
+ if (sip == NULL)
+ return NULL;
+
+ for (v = sip->sip_via; v; v = v->v_next) {
+ sip_fragment_clear(v->v_common);
+
+ if (v->v_next != (void *)v->v_common->h_succ)
+ break;
+ }
+
+ if ((v = sip->sip_via))
+ msg_header_remove(msg, (msg_pub_t *)sip, (msg_header_t *)v);
+
+ return v;
+}
+
+/** Serialize payload.
+ *
+ * The sip_payload_serialize() adds missing headers to MIME multiparty payload,
+ * encodes them and orders them in header chain. It also calculates the total
+ * length of the payload.
+ */
+unsigned long sip_payload_serialize(msg_t *msg, sip_payload_t *pl)
+{
+ unsigned long total;
+
+ for (total = 0; pl; pl = (sip_payload_t *)pl->pl_next) {
+ total += (unsigned)pl->pl_common->h_len;
+ }
+
+ return total;
+}
+
+/**
+ * Remove extra parameters from an AOR URL.
+ *
+ * The extra parameters listed in the @RFC3261 table 1 include port number,
+ * method, maddr, ttl, transport, lr and headers.
+ *
+ * @note The funtion modifies the @a url and the strings attached to it.
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error
+ */
+int sip_aor_strip(url_t *url)
+{
+ if (url == NULL)
+ return -1;
+
+ url->url_port = NULL;
+ url->url_headers = NULL;
+
+ if (url->url_params)
+ url_strip_transport(url);
+
+ if (url->url_params)
+ url->url_params =
+ url_strip_param_string((char *)url->url_params, "lr");
+
+ return 0;
+}
+
+/** Compare @SecurityVerify header with @SecurityServer header. */
+int sip_security_verify_compare(sip_security_server_t const *s,
+ sip_security_verify_t const *v,
+ msg_param_t *return_d_ver)
+{
+ size_t i, j;
+ int retval, digest;
+ msg_param_t const *s_params, *v_params, empty[] = { NULL };
+
+ if (return_d_ver)
+ *return_d_ver = NULL;
+
+ if (s == NULL)
+ return 0;
+
+ for (;;s = s->sa_next, v = v->sa_next) {
+ if (s == NULL || v == NULL)
+ return (s == NULL) - (v == NULL);
+
+ if ((retval = str0cmp(s->sa_mec, v->sa_mec)))
+ return retval;
+
+ digest = strcasecmp(s->sa_mec, "Digest") == 0;
+
+ s_params = s->sa_params, v_params = v->sa_params;
+
+ if (digest && s_params == NULL && v_params != NULL)
+ s_params = empty;
+
+ if (s_params == NULL || v_params == NULL) {
+ if ((retval = (s_params == NULL) - (v_params == NULL)))
+ return retval;
+ continue;
+ }
+
+ for (i = 0, j = 0;; i++, j++) {
+ if (digest && v_params[j] &&
+ strncasecmp(v_params[j], "d-ver=", 6) == 0) {
+ if (return_d_ver)
+ *return_d_ver = v_params[j] + strlen("d-ver=");
+ j++;
+ }
+
+ retval = str0cmp(s_params[i], v_params[j]);
+
+ if (retval || s_params[i] == NULL || v_params[j] == NULL)
+ break;
+ }
+
+ if (retval)
+ return retval;
+ }
+}
+
+/** Select best mechanism from @SecurityClient header.
+ *
+ * @note We assume that @SecurityServer header in @a s is sorted by
+ * preference.
+ */
+sip_security_client_t const *
+sip_security_client_select(sip_security_client_t const *client,
+ sip_security_server_t const *server)
+{
+ sip_security_server_t const *c, *s;
+
+ if (server == NULL || client == NULL)
+ return NULL;
+
+ for (s = server; s; s = s->sa_next) {
+ for (c = client; c; c = c->sa_next) {
+ if (str0cmp(s->sa_mec, c->sa_mec) == 0)
+ return c;
+ }
+ }
+
+ return NULL;
+}
+
+/**Checks if the response with given response code terminates dialog or
+ * dialog usage.
+ *
+ * @return -1 if the response with given code terminates whole dialog.
+ * @return 1 if the response terminates the dialog usage.
+ * @return 0 if the response does not terminate dialog or dialog usage.
+ *
+ * @return
+ * The @a *return_graceful_terminate_usage is set to 1, if application
+ * should gracefully terminate its dialog usage. It is set to 0, if no
+ * graceful terminate is required. If it is up to application policy to
+ * decide whether to gracefully terminate or not, the
+ * @a *return_graceful_terminate_usage is left unmodified.
+ *
+ * @sa
+ * http://www.ietf.org/internet-drafts/draft-ietf-sipping-dialogusage-02.txt
+ */
+int sip_response_terminates_dialog(int response_code,
+ sip_method_t method,
+ int *return_graceful_terminate_usage)
+{
+ enum { no_effect, terminate_usage = 1, terminate_dialog = -1 };
+ int dummy;
+
+ if (!return_graceful_terminate_usage)
+ return_graceful_terminate_usage = &dummy;
+
+ if (response_code < 300)
+ return *return_graceful_terminate_usage = 0;
+
+ /*
+ 3xx responses: Redirection mid-dialog is not well understood in SIP,
+ but whatever effect it has impacts the entire dialog and all of
+ its usages equally. In our example scenario, both the
+ subscription and the invite usage would be redirected by this
+ single response.
+ */
+ if (response_code < 400)
+ return *return_graceful_terminate_usage = 0;
+
+ if (response_code < 500) switch (response_code) {
+ default:
+ case 400: /** @par 400 and unrecognized 4xx responses
+
+ These responses affect only the NOTIFY transaction, not the
+ subscription, the dialog it resides in (beyond affecting the local
+ CSeq), or any other usage of that dialog. In general, the response
+ is a complaint about this transaction, not the usage or dialog the
+ transaction occurs in.
+ */
+ *return_graceful_terminate_usage = 0;
+ return 0;
+
+ case 401:
+ case 407: /** @par 401 Unauthorized and 407 Proxy Authentication Required
+
+ This request, not the subscription or dialog, is being challenged. The
+ usages and dialog are not terminated.
+ */
+ *return_graceful_terminate_usage = 0;
+ return 0;
+
+ case 402: /** @par 402 Payment Required
+
+ This is a reserved response code. If encountered, it should be
+ treated as an unrecognized 4xx.
+ */
+ *return_graceful_terminate_usage = 0;
+ return 0;
+
+ case 403: /** @par 403 Forbidden
+
+ This response terminates the subscription, but has no effect on
+ any other usages of the dialog. In our example scenario, the
+ invite usage continues to exist. Similarly, if the 403 came in
+ response to a re-INVITE, the invite usage would be terminated, but
+ not the subscription.
+ */
+ *return_graceful_terminate_usage = 0;
+ return 0;
+
+ case 404: /** @par 404 Not Found
+
+ This response destroys the dialog and all usages sharing it. The
+ Request-URI that is being 404ed is the remote target set by the
+ @Contact provided by the peer. Getting this response means
+ something has gone fundamentally wrong with the dialog state.
+ */
+ return terminate_dialog;
+
+ case 405: /** @par 405 Method Not Allowed
+
+ In our example scenario, this response destroys the subscription,
+ but not the invite usage or the dialog. It's an aberrant case for
+ NOTIFYs to receive a 405 since they only come as a result to
+ something that creates subscription. In general, a 405 within a
+ given usage affects only that usage, but does not affect other
+ usages of the dialog.
+ */
+ switch (method) {
+ case sip_method_notify:
+ case sip_method_subscribe:
+ case sip_method_invite:
+ return terminate_usage;
+ default:
+ *return_graceful_terminate_usage = 0;
+ return 0;
+ }
+
+ case 406: /** @par 406 Not Acceptable
+
+ These responses concern details of the message in the transaction.
+ Subsequent requests in this same usage may succeed. Neither the
+ usage nor dialog is terminated, other usages sharing this dialog
+ are unaffected.
+ */
+ *return_graceful_terminate_usage = 0;
+ return 0;
+
+ case 408: /** @par 408 Request Timeout
+
+ Receiving a 408 will have the same effect on
+ usages and dialogs as a real transaction timeout as described in
+ Section 3.2.
+ */
+ return terminate_usage;
+
+ case 410: /** @par 410 Gone
+
+ This response destroys the dialog and all usages sharing
+ it. The Request-URI that is being rejected is the remote target
+ set by the @Contact provided by the peer. Similar to 404, getting
+ this response means something has gone fundamentally wrong with
+ the dialog state, its slightly less aberrant in that the other
+ endpoint recognizes that this was once a valid URI that it isn't
+ willing to respond to anymore.
+ */
+ return terminate_dialog;
+
+ case 412: /* Conditional Request Failed: */
+ case 413: /* Request Entity Too Large: */
+ case 414: /* Request-URI Too Long: */
+ case 415: /* Unsupported Media Type: */
+ /** @par 412, 413, 414 and 415
+
+ These responses concern details of the message in the transaction.
+ Subsequent requests in this same usage may succeed. Neither the usage
+ nor dialog is terminated, other usages sharing this dialog are
+ unaffected.
+ */
+ *return_graceful_terminate_usage = 0;
+ return 0;
+
+ case 416: /** @par 416 Unsupported URI Scheme
+
+ Similar to 404 and 410, this response
+ came to a request whose Request-URI was provided by the peer in a
+ @Contact header field. Something has gone fundamentally wrong, and
+ the dialog and all of its usages are destroyed.
+ */
+ return terminate_dialog;
+
+ case 417:
+ /** @par 417 Uknown Resource-Priority
+ The effect of this response on usages
+ and dialogs is analgous to that for 420 and 488. The usage is not
+ affected. The dialog is only affected by a change in its local
+ @CSeq. No other usages of the dialog are affected.
+ */
+
+ case 420: /* Bad Extension */
+ case 421: /* Extension Required */
+
+ /** @par 420 Bad Extension and 421 Extension Required
+
+ These responses are objecting to the request, not the usage. The
+ usage is not affected. The dialog is only affected by a change in
+ its local @CSeq. No other usages of the dialog are affected.
+ */
+
+ case 422: /** @par 422 Session Interval Too Small
+
+ This response will not be returned to
+ a NOTIFY in our example scenario. This response is non-sensical
+ for any mid-usage request. If it is received, an element in the
+ path of the request is violating protocol, and the recipient
+ should treat this as it would an unknown 4xx response. If the
+ response came to a request that was attempting to establish a new
+ usage in an existing dialog, no new usage is created and existing
+ usages are unaffected.
+ */
+ *return_graceful_terminate_usage = 0;
+ return 0;
+
+ case 423: /** @par 423 Interval Too Brief
+
+ This response won't happen in our example
+ scenario, but if it came in response to a re-SUBSCRIBE, the
+ subscribe usage is not destroyed (or otherwise affected). No
+ other usages of the dialog are affected.
+ */
+ *return_graceful_terminate_usage = 0;
+ return sip_method_subscribe == method ? terminate_usage : no_effect;
+
+ case 428: /** @par 428 Use Identity Header
+
+ This response objects to the request, not
+ the usage. The usage is not affected. The dialog is only
+ affected by a change in its local @CSeq. No other usages of the
+ dialog are affected. */
+ *return_graceful_terminate_usage = 0;
+ return 0;
+
+ case 429: /** @par 429 Provide Referrer Identity
+
+ This response won't be returned to a NOTIFY as in our example
+ scenario, but when it is returned to a REFER, it is objecting to
+ the REFER request itself, not any usage the REFER occurs within.
+ The usage is unaffected. Any other usages sharing this dialog are
+ unaffected. The dialog is only affected by a change in its local
+ @CSeq.
+ */
+
+ case 436: case 437: case 438:
+ /** @par 436 Bad Identity-Info, 437 Unsupported Certificate, 438 Invalid \
+ * Identity Header
+ *
+ * These responses object to the request, not the usage.
+ * The usage is not affected. The dialog is only affected by a
+ * change in its local @CSeq. No other usages of the dialog are
+ * affected.
+ */
+ *return_graceful_terminate_usage = 0;
+ return 0;
+
+
+ case 480: /** @par 480 Temporarily Unavailable
+
+ @RFC3261 is unclear on what this response means for mid-usage
+ requests. Clarifications will be made to show that this response
+ affects only the usage in which the request occurs. No other usages
+ are affected. If the response included a @RetryAfter header field,
+ further requests in that usage should not be sent until the indicated
+ time has past. Requests in other usages may still be sent at any time.
+ */
+ return terminate_usage;
+
+
+ case 481: /** @par 481 Call/Transaction Does Not Exist
+
+ This response indicates that the peer has lost its copy of the dialog
+ state. The dialog and any usages sharing it are destroyed.
+
+ The dialog
+ itself should not be destroyed unless this was the last usage.
+ The effects of a 481 on a dialog and its usages are the most
+ ambiguous of any final response. There are implementations that
+ have chosen the meaning recommended here, and others that destroy
+ the entire dialog without regard to the number of outstanding
+ usages. Going forward with this clarification will allow those
+ deployed implementations that assumed only the usage was destroyed
+ to work with a wider number of implementations. Those that made
+ the other choice will continue to function as they do now,
+ suffering at most the same extra messages needed for a peer to
+ discover that that other usages have gone away that they currently
+ do. However, the necessary clarification to @RFC3261 needs to
+ make it very clear that the ability to terminate usages
+ independently from the overall dialog using a 481 is not
+ justification for designing new applications that count on
+ multiple usages in a dialog.
+ */
+ return terminate_usage;
+
+
+ case 482: /** @par 482 Loop Detected
+
+ This response is aberrant mid-dialog. It will
+ only occur if the @RecordRoute header field was improperly
+ constructed by the proxies involved in setting up the dialog's
+ initial usage, or if a mid-dialog request forks and merges (which
+ should never happen). Future requests using this dialog state
+ will also fail. The dialog and any usages sharing it are
+ destroyed.
+ */
+ return terminate_dialog;
+
+
+ case 483: /** @par 483 Too Many Hops
+
+ Similar to 482, receiving this mid-dialog is
+ aberrant. Unlike 482, recovery may be possible by increasing
+ @MaxForwards (assuming that the requester did something strange
+ like using a smaller value for @MaxForwards in mid-dialog requests
+ than it used for an initial request). If the request isn't tried
+ with an increased @MaxForwards, then the agent should attempt to
+ gracefully terminate this usage and all other usages that share
+ its dialog.
+ */
+ *return_graceful_terminate_usage = 1;
+ return 0;
+
+ case 484: /* Address Incomplete */
+ case 485: /* Ambiguous */
+ /** @par 484 Address Incomplete and 485 Ambiguous
+
+ Similar to 404 and 410, these
+ responses came to a request whose Request-URI was provided by the
+ peer in a @Contact header field. Something has gone fundamentally
+ wrong, and the dialog and all of its usages are destroyed.
+ */
+ return terminate_dialog;
+
+ case 486: /** @par 486 Busy Here
+
+ This response is non-sensical in our example scenario,
+ or in any scenario where this response comes inside an established
+ usage. If it occurs in that context, it should be treated as an
+ unknown 4xx response. The usage, and any other usages sharing its
+ dialog are unaffected. The dialog is only affected by the change
+ in its local @CSeq. If this response is to a request that is
+ attempting to establish a new usage within an existing dialog
+ (such as an INVITE sent within a dialog established by a
+ subscription), the request fails, no new usage is created, and no
+ other usages are affected.
+ */
+ *return_graceful_terminate_usage = 0;
+ return 0;
+
+ case 487: /** @par 487 Request Terminated
+
+ This response speaks to the disposition of a
+ particular request (transaction). The usage in which that request
+ occurs is not affected by this response (it may be affected by
+ another associated request within that usage). No other usages
+ sharing this dialog are affected.
+ */
+ *return_graceful_terminate_usage = 0;
+ return 0;
+
+ case 488: /** @par 488 Not Acceptable Here
+
+ This response is objecting to the request,
+ not the usage. The usage is not affected. The dialog is only
+ affected by a change in its local @CSeq. No other usages of the
+ dialog are affected.
+ */
+ *return_graceful_terminate_usage = 0;
+ return 0;
+
+ case 489: /** @par 489 Bad Event
+
+ In our example scenario, @RFC3265 declares that the
+ subscription usage in which the NOTIFY is sent is terminated. The
+ invite usage is unaffected and the dialog continues to exist.
+ This response is only valid in the context of SUBSCRIBE and
+ NOTIFY. UAC behavior for receiving this response to other methods
+ is not specified, but treating it as an unknown 4xx is a
+ reasonable practice.
+ */
+ *return_graceful_terminate_usage = 0;
+ return method == sip_method_notify ? terminate_usage : no_effect;
+
+ case 491: /** @par 491 Request Pending
+
+ This response addresses in-dialog request glare.
+ Its affect is scoped to the request. The usage in which the
+ request occurs is not affected. The dialog is only affected by
+ the change in its local @CSeq. No other usages sharing this dialog
+ are affected.
+ */
+ *return_graceful_terminate_usage = 0;
+ return 0;
+
+ case 493: /** @par 493 Undecipherable
+
+ This response objects to the request, not the
+ usage. The usage is not affected. The dialog is only affected by
+ a change in its local @CSeq. No other usages of the dialog are
+ affected.
+ */
+ *return_graceful_terminate_usage = 0;
+ return 0;
+
+ case 494: /** @par 494 Security Agreement Required
+
+ This response is objecting to the
+ request, not the usage. The usage is not affected. The dialog is
+ only affected by a change in its local @CSeq. No other usages of
+ the dialog are affected.
+ */
+ *return_graceful_terminate_usage = 0;
+ return 0;
+ }
+
+ if (response_code < 600) switch (response_code) {
+ case 500: /* 500 and 5xx unrecognized responses */
+ default:
+ /** @par 500 and 5xx unrecognized responses
+
+ These responses are complaints against the request (transaction),
+ not the usage. If the response contains a @RetryAfter header field
+ value, the server thinks the condition is temporary and the
+ request can be retried after the indicated interval. This usage,
+ and any other usages sharing the dialog are unaffected. If the
+ response does not contain a @RetryAfter header field value, the UA
+ may decide to retry after an interval of its choosing or attempt
+ to gracefully terminate the usage. Whether or not to terminate
+ other usages depends on the application. If the UA receives a 500
+ (or unrecognized 5xx) in response to an attempt to gracefully
+ terminate this usage, it can treat this usage as terminated. If
+ this is the last usage sharing the dialog, the dialog is also
+ terminated.
+ */
+ /* Do not change *return_graceful_terminate_usage */
+ return 0;
+
+ case 501: /** @par 501 Not Implemented
+
+ This would be a degenerate response in our
+ example scenario since the NOTIFY is being sent as part of an
+ established subscribe usage. In this case, the UA knows the
+ condition is unrecoverable and should stop attempting to send
+ NOTIFYs on this usage. (It may or may not destroy the usage. If
+ it remembers the bad behavior, it can reject any refresh
+ subscription). In general, this response may or may not affect
+ the usage (a 501 to an unknown method or an INFO will not end an
+ invite usage). It will never affect other usages sharing this
+ usage's dialog.
+ */
+ /* Do not change *return_graceful_terminate_usage */
+ return 0;
+
+ case 502: /** @par 502 Bad Gateway
+
+ This response is aberrant mid-dialog. It will only occur if the
+ @RecordRoute header field was improperly constructed by the
+ proxies involved in setting up the dialog's initial usage. Future
+ requests using this dialog state will also fail. The dialog and
+ any usages sharing it are destroyed.
+ */
+ return terminate_dialog;
+
+ case 503: /** @par 503 Service Unavailable
+
+ As per @RFC3263, the logic handling locating SIP servers for
+ transactions may handle 503 requests (effectively sequentially
+ forking at the endpoint based on DNS results). If this process
+ does not yield a better response, a 503 may be returned to the
+ transaction user. Like a 500 response, the error is a complaint
+ about this transaction, not the usage. Because this response
+ occurred in the context of an established usage (hence an existing
+ dialog), the route-set has already been formed and any opportunity
+ to try alternate servers (as recommended in @RFC3261) has been exhausted
+ by the @RFC3263 logic. The response should be handled as described
+ for 500 earlier in this memo.
+ */
+ /* Do not change *return_graceful_terminate_usage */
+ return 0;
+
+ case 504: /** @par 504 Server Time-out
+
+ It is not obvious under what circumstances this
+ response would be returned to a request in an existing dialog. If
+ it occurs it should have the same affect on the dialog and its
+ usages as described for unknown 5xx responses.
+ */
+ /* Do not change *return_graceful_terminate_usage */
+ return 0;
+
+ case 505: /* Version Not Supported */
+ case 513: /* Message Too Large */
+ /** @par 505 Version Not Supported and 513 Message Too Large
+
+ These responses are objecting to the request, not the usage. The
+ usage is not affected. The dialog is only affected by a change in
+ its local @CSeq. No other usages of the dialog are affected.
+ */
+ *return_graceful_terminate_usage = 0;
+ return 0;
+
+ case 580: /** @par 580 Precondition Failure
+
+ This response is objecting to the request,
+ not the usage. The usage is not affected. The dialog is only
+ affected by a change in its local @CSeq. No other usages of the
+ dialog are affected.
+ */
+ *return_graceful_terminate_usage = 0;
+ return 0;
+ }
+
+ if (response_code < 700) switch (response_code) {
+ case 600: /* 600 and 6xx unrecognized responses */
+ default:
+ /** @par 600 and 6xx unrecognized responses
+
+ Unlike 400 Bad Request, a 600 response code says something about
+ the recipient user, not the request that was made. This end user
+ is stating an unwillingness to communicate.
+
+ If the response contains a @RetryAfter header field value, the
+ user is indicating willingness to communicate later and the
+ request can be retried after the indicated interval. This usage,
+ and any other usages sharing the dialog are unaffected. If the
+ response does not contain a @RetryAfter header field value, the UA
+ may decide to retry after an interval of its choosing or attempt
+ to gracefully terminate the usage. Whether or not to terminate
+ other usages depends on the application. If the UA receives a 600
+ (or unrecognized 6xx) in response to an attempt to gracefully
+ terminate this usage, it can treat this usage as terminated. If
+ this is the last usage sharing the dialog, the dialog is also
+ terminated.
+ */
+ /* Do not change graceful_terminate */
+ return 0;
+
+ case 603: /** @par 603 Decline
+
+ This response declines the action indicated by the
+ associated request. It can be used, for example, to decline a
+ hold or transfer attempt. Receiving this response does NOT
+ terminate the usage it occurs in. Other usages sharing the dialog
+ are unaffected.
+ */
+ *return_graceful_terminate_usage = 0;
+ return 0;
+
+ case 604: /** @par 604 Does Not Exist Anywhere
+
+ Like 404, this response destroys the
+ dialog and all usages sharing it. The Request-URI that is being
+ 604ed is the remote target set by the @Contact provided by the
+ peer. Getting this response means something has gone
+ fundamentally wrong with the dialog state.
+ */
+ return terminate_dialog;
+
+ case 606: /** @par 606 Not Acceptable
+
+ This response is objecting to aspects of the
+ associated request, not the usage the request appears in. The
+ usage is unaffected. Any other usages sharing the dialog are
+ unaffected. The only affect on the dialog is the change in the
+ local @CSeq.
+ */
+ *return_graceful_terminate_usage = 0;
+ return 0;
+ }
+
+ /* Do not change graceful_terminate */
+
+ return 0;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,919 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SIP_H
+/** Defined when <sofia-sip/sip.h> has been included. */
+#define SIP_H
+
+/**@file sofia-sip/sip.h
+ *
+ * SIP objects.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created : Thu Jun 8 19:28:55 2000 ppessi
+ */
+
+#ifndef MSG_TYPES_H
+#include <sofia-sip/msg_types.h>
+#endif
+#ifndef MSG_MIME_H
+#include <sofia-sip/msg_mime.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** IDs for well-known SIP methods. */
+typedef enum {
+ sip_method_invalid = -1, /**< Invalid method name */
+ sip_method_unknown = 0, /**< Unknown method, use @c method_name */
+ sip_method_invite, /**< INVITE */
+ sip_method_ack, /**< ACK */
+ sip_method_cancel, /**< CANCEL */
+ sip_method_bye, /**< BYE */
+ sip_method_options, /**< OPTIONS */
+ sip_method_register, /**< REGISTER */
+ sip_method_info, /**< INFO */
+ sip_method_prack, /**< PRACK */
+ sip_method_update, /**< UPDATE */
+ sip_method_message, /**< MESSAGE */
+ sip_method_subscribe, /**< SUBSCRIBE */
+ sip_method_notify, /**< NOTIFY */
+ sip_method_refer, /**< REFER */
+ sip_method_publish, /**< PUBLISH */
+} sip_method_t;
+
+#define SIP_METHOD(s) sip_method_unknown, #s
+#define SIP_METHOD_ACK sip_method_ack, "ACK"
+#define SIP_METHOD_CANCEL sip_method_cancel, "CANCEL"
+#define SIP_METHOD_BYE sip_method_bye, "BYE"
+#define SIP_METHOD_INVITE sip_method_invite, "INVITE"
+#define SIP_METHOD_OPTIONS sip_method_options, "OPTIONS"
+#define SIP_METHOD_REGISTER sip_method_register, "REGISTER"
+#define SIP_METHOD_INFO sip_method_info, "INFO"
+#define SIP_METHOD_PRACK sip_method_prack, "PRACK"
+#define SIP_METHOD_UPDATE sip_method_update, "UPDATE"
+#define SIP_METHOD_MESSAGE sip_method_message, "MESSAGE"
+#define SIP_METHOD_SUBSCRIBE sip_method_subscribe, "SUBSCRIBE"
+#define SIP_METHOD_NOTIFY sip_method_notify, "NOTIFY"
+#define SIP_METHOD_REFER sip_method_refer, "REFER"
+#define SIP_METHOD_PUBLISH sip_method_publish, "PUBLISH"
+
+/** Magic pointer value - never valid for SIP headers. @HI */
+#define SIP_NONE ((void const *)-1L)
+
+/** SIP protocol identifier @HIDE */
+#define SIP_PROTOCOL_TAG ((void *)0x53495020) /* 'SIP'20 */
+
+enum {
+ /** Default port for SIP as integer */
+ SIP_DEFAULT_PORT = 5060,
+#define SIP_DEFAULT_PORT SIP_DEFAULT_PORT
+
+/** Default port for SIP as string */
+#define SIP_DEFAULT_SERV "5060"
+
+ /** Default port for SIPS as integer */
+ SIPS_DEFAULT_PORT = 5061,
+#define SIPS_DEFAULT_PORT SIPS_DEFAULT_PORT
+ /** Default port for SIPS as string */
+#define SIPS_DEFAULT_SERV "5061"
+};
+
+/** Time in seconds since Jan 01 1900. */
+typedef msg_time_t sip_time_t;
+
+/** Latest time that can be expressed with #sip_time_t. @HIDE */
+#define SIP_TIME_MAX ((sip_time_t)MSG_TIME_MAX)
+
+/** SIP message object. */
+typedef struct sip_s sip_t;
+
+/** Any SIP header - union of all possible SIP headers. */
+typedef union sip_header_u sip_header_t;
+
+/** Type of a generic SIP header. */
+typedef struct msg_generic_s sip_generic_t;
+#define g_value g_string
+
+/** Common part of all the header structures. */
+typedef msg_common_t sip_common_t;
+
+/** SIP parameter string. */
+typedef msg_param_t sip_param_t;
+
+/** @To or @From header. */
+typedef struct sip_addr_s sip_addr_t;
+
+/** @Authorization, @ProxyAuthenticate, @WWWAuthenticate */
+typedef msg_auth_t sip_auth_t;
+
+typedef struct sip_request_s sip_request_t;
+typedef struct sip_status_s sip_status_t;
+typedef msg_error_t sip_error_t;
+typedef msg_unknown_t sip_unknown_t;
+typedef msg_separator_t sip_separator_t;
+typedef msg_payload_t sip_payload_t;
+
+typedef struct sip_accept_s sip_accept_t;
+typedef msg_accept_any_t sip_accept_encoding_t;
+typedef msg_accept_any_t sip_accept_language_t;
+typedef struct sip_allow_s sip_allow_t;
+typedef struct msg_auth_info_s sip_authentication_info_t;
+typedef struct msg_auth_s sip_authorization_t;
+typedef struct sip_call_id_s sip_call_id_t;
+typedef struct sip_call_info_s sip_call_info_t;
+typedef struct sip_contact_s sip_contact_t;
+typedef struct sip_cseq_s sip_cseq_t;
+typedef struct msg_generic_s sip_etag_t;
+typedef struct msg_generic_s sip_if_match_t;
+typedef msg_content_disposition_t sip_content_disposition_t;
+typedef msg_list_t sip_content_encoding_t;
+typedef msg_list_t sip_content_language_t;
+typedef struct sip_content_length_s sip_content_length_t;
+typedef struct msg_content_type_s sip_content_type_t;
+typedef struct msg_generic_s sip_mime_version_t;
+typedef struct sip_date_s sip_date_t;
+typedef struct sip_error_info_s sip_error_info_t;
+typedef struct sip_expires_s sip_expires_t;
+typedef struct sip_addr_s sip_from_t;
+typedef msg_list_t sip_in_reply_to_t;
+typedef struct sip_max_forwards_s sip_max_forwards_t;
+typedef struct sip_min_expires_s sip_min_expires_t;
+typedef struct sip_min_se_s sip_min_se_t;
+typedef struct msg_generic_s sip_organization_t;
+typedef struct msg_generic_s sip_priority_t;
+typedef struct msg_auth_s sip_proxy_authenticate_t;
+typedef struct msg_auth_info_s sip_proxy_authentication_info_t;
+typedef struct msg_auth_s sip_proxy_authorization_t;
+typedef msg_list_t sip_proxy_require_t;
+typedef struct sip_rack_s sip_rack_t;
+typedef struct sip_reason_s sip_reason_t;
+typedef struct sip_route_s sip_record_route_t;
+
+typedef struct sip_refer_to_s sip_refer_to_t;
+typedef struct sip_referred_by_s sip_referred_by_t;
+typedef struct sip_replaces_s sip_replaces_t;
+
+typedef struct sip_request_disposition_s sip_request_disposition_t;
+
+typedef struct sip_caller_prefs_s sip_caller_prefs_t;
+typedef struct sip_caller_prefs_s sip_accept_contact_t;
+typedef struct sip_caller_prefs_s sip_reject_contact_t;
+
+typedef msg_list_t sip_require_t;
+typedef struct sip_retry_after_s sip_retry_after_t;
+typedef struct sip_route_s sip_route_t;
+typedef struct sip_rseq_s sip_rseq_t;
+typedef struct msg_generic_s sip_server_t;
+typedef struct sip_session_expires_s
+ sip_session_expires_t;
+typedef struct msg_generic_s sip_subject_t;
+typedef struct sip_subscription_state_s
+ sip_subscription_state_t;
+typedef msg_list_t sip_supported_t;
+typedef struct sip_timestamp_s sip_timestamp_t;
+typedef struct sip_addr_s sip_to_t;
+typedef msg_list_t sip_unsupported_t;
+typedef struct msg_generic_s sip_user_agent_t;
+typedef struct sip_via_s sip_via_t;
+typedef msg_warning_t sip_warning_t;
+typedef struct msg_auth_s sip_www_authenticate_t;
+
+typedef struct sip_event_s sip_event_t;
+typedef msg_list_t sip_allow_events_t;
+
+/* RFC 3323 - @Privacy */
+typedef struct sip_privacy_s sip_privacy_t;
+
+/* RFC 3327 - @Path */
+typedef struct sip_route_s sip_path_t;
+
+/* RFC 3329 - Security Mechanism Agreement */
+typedef struct sip_security_agree_s sip_security_client_t;
+typedef struct sip_security_agree_s sip_security_server_t;
+typedef struct sip_security_agree_s sip_security_verify_t;
+
+/* RFC 3608 - Service Route */
+typedef struct sip_route_s sip_service_route_t;
+
+
+/**SIP message object.
+ *
+ * This structure contains a parsed SIP message. The struct is usually
+ * referred with typedef #sip_t. It is used to access the headers and
+ * payload within the SIP message. The generic transport aspects of the
+ * message, like network address, is accessed using the #msg_t object
+ * directly.
+ */
+struct sip_s {
+ msg_common_t sip_common[1]; /**< For recursive inclusion */
+ msg_pub_t *sip_next; /**< Dummy link to msgfrag */
+ void *sip_user; /**< Application data */
+ unsigned sip_size; /**< Size of structure */
+ int sip_flags; /**< Parser flags */
+
+ sip_error_t *sip_error; /**< Erroneous headers */
+
+ /* Pseudoheaders */
+ sip_request_t *sip_request; /**< Request line */
+ sip_status_t *sip_status; /**< Status line */
+
+ /* === Headers start here */
+ 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_proxy_require_t *sip_proxy_require; /**< Proxy-Require */
+
+ sip_from_t *sip_from; /**< From (f) */
+ sip_to_t *sip_to; /**< To (t) */
+ sip_call_id_t *sip_call_id; /**< Call-ID (i) */
+ sip_cseq_t *sip_cseq; /**< CSeq */
+ sip_contact_t *sip_contact; /**< Contact (m) */
+ sip_rseq_t *sip_rseq; /**< RSeq */
+ sip_rack_t *sip_rack; /**< RAck */
+
+ /* Caller Preferences */
+ sip_request_disposition_t *sip_request_disposition;
+ /**< Request-Disposition (d) */
+ sip_accept_contact_t *sip_accept_contact;/**< Accept-Contact (a) */
+ sip_reject_contact_t *sip_reject_contact;/**< Reject-Contact (j) */
+
+ sip_expires_t *sip_expires; /**< Expires */
+ sip_date_t *sip_date; /**< Date */
+ sip_retry_after_t *sip_retry_after; /**< Retry-After */
+ sip_timestamp_t *sip_timestamp; /**< Timestamp */
+ sip_min_expires_t *sip_min_expires; /**< Min-Expires */
+
+ sip_subject_t *sip_subject; /**< Subject (s) */
+ sip_priority_t *sip_priority; /**< Priority */
+
+ sip_call_info_t *sip_call_info; /**< Call-Info */
+ sip_organization_t *sip_organization; /**< Organization */
+ sip_server_t *sip_server; /**< Server */
+ sip_user_agent_t *sip_user_agent; /**< User-Agent */
+ sip_in_reply_to_t *sip_in_reply_to; /**< In-Reply-To */
+
+ sip_accept_t *sip_accept; /**< Accept */
+ sip_accept_encoding_t *sip_accept_encoding; /**< Accept-Encoding */
+ sip_accept_language_t *sip_accept_language; /**< Accept-Language */
+
+ sip_allow_t *sip_allow; /**< Allow */
+ sip_require_t *sip_require; /**< Require */
+ sip_supported_t *sip_supported; /**< Supported (k) */
+ sip_unsupported_t *sip_unsupported; /**< Unsupported */
+
+ /* RFC 3265 */
+ sip_event_t *sip_event; /**< Event (o) */
+ sip_allow_events_t *sip_allow_events; /**< Allow-Events (u) */
+ sip_subscription_state_t *sip_subscription_state;
+ /**< Subscription-State */
+
+ sip_proxy_authenticate_t *sip_proxy_authenticate;
+ /**< Proxy-Authenticate */
+ sip_proxy_authentication_info_t *sip_proxy_authentication_info;
+ /**< Proxy-Authentication-Info */
+ sip_proxy_authorization_t *sip_proxy_authorization;
+ /**< Proxy-Authorization */
+ sip_authorization_t *sip_authorization;
+ /**< Authorization */
+ sip_www_authenticate_t *sip_www_authenticate;
+ /**< WWW-Authenticate */
+ sip_authentication_info_t *sip_authentication_info;
+ /**< Authentication-Info */
+ sip_error_info_t *sip_error_info; /**< Error-Info */
+ sip_warning_t *sip_warning; /**< Warning */
+
+ /* RFC 3515 */
+ sip_refer_to_t *sip_refer_to; /**< Refer-To (r) */
+ sip_referred_by_t *sip_referred_by; /**< Referred-By (b) */
+ sip_replaces_t *sip_replaces; /**< Replaces */
+
+ /* draft-ietf-sip-session-timer */
+ sip_session_expires_t *sip_session_expires;
+ /**< Session-Expires (x) */
+ sip_min_se_t *sip_min_se; /**< Min-SE */
+
+ sip_path_t *sip_path; /**< Path */
+ sip_service_route_t *sip_service_route; /**< Service-Route */
+
+ sip_reason_t *sip_reason; /**< Reason */
+
+ sip_security_client_t *sip_security_client; /**< Security-Client */
+ sip_security_server_t *sip_security_server; /**< Security-Server */
+ sip_security_verify_t *sip_security_verify; /**< Security-Verify */
+
+ sip_privacy_t *sip_privacy; /**< Privacy */
+
+ sip_etag_t *sip_etag; /**< SIP-ETag */
+ sip_if_match_t *sip_if_match; /**< SIP-If-Match */
+
+ /* Entity headers */
+ sip_mime_version_t *sip_mime_version; /**< MIME-Version */
+ sip_content_type_t *sip_content_type; /**< Content-Type (c) */
+ sip_content_encoding_t *sip_content_encoding;
+ /**< Content-Encoding (e) */
+ sip_content_language_t *sip_content_language; /**< Content-Language */
+ sip_content_disposition_t *sip_content_disposition;
+ /**< Content-Disposition */
+ sip_content_length_t *sip_content_length;/**< Content-Length (l) */
+
+ /* === Headers end here */
+
+ sip_unknown_t *sip_unknown; /**< Unknown headers */
+ sip_separator_t *sip_separator;
+ /**< Separator between headers and payload */
+ sip_payload_t *sip_payload; /**< Message payload */
+ msg_multipart_t *sip_multipart; /**< Multipart MIME payload */
+};
+
+
+/** @ingroup sip_request
+ * @brief Structure for @ref sip_request "SIP request line".
+ */
+struct sip_request_s
+{
+ sip_common_t rq_common[1]; /**< Common fragment info */
+ sip_error_t *rq_next; /**< Link to next (dummy) */
+ sip_method_t rq_method; /**< Method enum */
+ char const *rq_method_name; /**< Method name */
+ url_t rq_url[1]; /**< RequestURI */
+ char const *rq_version; /**< Protocol version */
+};
+
+/**@ingroup sip_status
+ * @brief Structure for @ref sip_status "SIP status line".
+ */
+struct sip_status_s
+{
+ sip_common_t st_common[1]; /**< Common fragment info */
+ sip_error_t *st_next; /**< Link to next (dummy) */
+ char const *st_version; /**< Protocol version */
+ int st_status; /**< Status code */
+ char const *st_phrase; /**< Status phrase */
+};
+
+/**@ingroup sip_from
+ * @brief Structure for @From and @To headers.
+ */
+struct sip_addr_s
+{
+ sip_common_t a_common[1]; /**< Common fragment info */
+ sip_error_t *a_next;
+ char const *a_display; /**< Display name */
+ url_t a_url[1]; /**< URL */
+ msg_param_t const *a_params; /**< Parameter table */
+ char const *a_comment; /**< Comment */
+
+ char const *a_tag; /**< Tag parameter */
+};
+
+#define a_user a_url->url_user
+#define a_host a_url->url_host
+
+/**@ingroup sip_accept
+ * @brief Structure for @Accept header field.
+ */
+struct sip_accept_s
+{
+ sip_common_t ac_common[1]; /**< Common fragment info */
+ sip_accept_t *ac_next; /**< Pointer to next @Accept value */
+ 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 sip_allow
+ * @brief Structure for @Allow header field.
+ *
+ * @NEW_1_12_5 (before used struct msg_list_s with @Allow).
+ */
+struct sip_allow_s
+{
+ msg_common_t k_common[1]; /**< Common fragment info */
+ msg_list_t *k_next; /**< Link to next */
+ msg_param_t *k_items; /**< List of allowed items */
+ uint32_t k_bitmap; /**< Bitmap of allowed methods.
+ @NEW_1_12_5 */
+};
+
+/**@ingroup sip_authentication_info
+ * @brief Structure for @AuthenticationInfo header.
+ *
+ * @deprecated Use struct msg_auth_info_s instead.
+ */
+struct sip_authentication_info_s
+{
+ sip_common_t ai_common[1]; /**< Common fragment info */
+ sip_error_t *ai_next; /**< Dummy link to next */
+ msg_param_t const *ai_params; /**< List of authentication info */
+};
+
+/**@ingroup sip_call_id
+ * @brief Structure for @CallID (and @InReplyTo) header fields.
+ */
+struct sip_call_id_s {
+ sip_common_t i_common[1]; /**< Common fragment info */
+ sip_call_id_t *i_next; /**< Link to next (In-Reply-To) */
+ char const *i_id; /**< ID value */
+ uint32_t i_hash; /**< Hash value (always nonzero) */
+};
+
+/**@ingroup sip_call_info
+ * @brief Structure for @CallInfo header.
+ */
+struct sip_call_info_s
+{
+ sip_common_t ci_common[1]; /**< Common fragment info */
+ sip_call_info_t *ci_next; /**< Link to next @CallInfo */
+ url_t ci_url[1]; /**< URI to call info */
+ msg_param_t const *ci_params; /**< List of parameters */
+ char const *ci_purpose; /**< Value of @b purpose parameter */
+};
+
+/**@ingroup sip_cseq
+ * @brief Structure for @CSeq header.
+ */
+struct sip_cseq_s
+{
+ sip_common_t cs_common[1]; /**< Common fragment info */
+ sip_error_t *cs_next; /**< Link to next (dummy) */
+ uint32_t cs_seq; /**< Sequence number */
+ sip_method_t cs_method; /**< Method enum */
+ char const *cs_method_name; /**< Method name */
+};
+
+/**@ingroup sip_contact
+ * @brief Structure for @Contact header field.
+ */
+struct sip_contact_s
+{
+ sip_common_t m_common[1]; /**< Common fragment info */
+ sip_contact_t *m_next; /**< Link to next @Contact header */
+ char const *m_display; /**< Display name */
+ url_t m_url[1]; /**< SIP URL */
+ msg_param_t const *m_params; /**< List of contact-params */
+ char const *m_comment; /**< Comment */
+
+ char const *m_q; /**< @Priority */
+ char const *m_expires; /**< Expiration time */
+};
+
+/**@ingroup sip_content_length
+ * @brief Structure for @ContentLength header.
+ */
+struct sip_content_length_s
+{
+ sip_common_t l_common[1]; /**< Common fragment info */
+ sip_error_t *l_next; /**< Link to next (dummy) */
+ uint32_t l_length; /**< Length in bytes */
+};
+
+#if DOCUMENTATION_ONLY
+/**@ingroup sip_content_type
+ *
+ * @brief Structure for @ContentType header.
+ */
+struct sip_content_type_s
+{
+ sip_common_t c_common[1]; /**< Common fragment info */
+ sip_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 */
+};
+#endif
+
+/**@ingroup sip_date
+ * @brief Structure for @Date header.
+ */
+struct sip_date_s
+{
+ sip_common_t d_common[1]; /**< Common fragment info */
+ sip_date_t *d_next; /**< Link to next (dummy) */
+ sip_time_t d_time; /**< Seconds since Jan 1, 1900 */
+};
+
+/**@ingroup sip_error_info
+ * @brief Structure for @ErrorInfo header.
+ */
+struct sip_error_info_s
+{
+ sip_common_t ei_common[1]; /**< Common fragment info */
+ sip_call_info_t *ei_next; /**< Link to next @ErrorInfo */
+ url_t ei_url[1]; /**< URI to error description */
+ msg_param_t const *ei_params; /**< List of parameters */
+};
+
+/**@ingroup sip_event
+ * @brief Structure for @Event header.
+ */
+struct sip_event_s
+{
+ sip_common_t o_common[1]; /**< Common fragment info */
+ sip_error_t *o_next; /**< Link to next (dummy) */
+ char const * o_type; /**< @Event type */
+ msg_param_t const *o_params; /**< List of parameters */
+ char const *o_id; /**< @Event ID */
+};
+
+/**@ingroup sip_expires
+ * @brief Structure for @Expires header.
+ */
+struct sip_expires_s
+{
+ sip_common_t ex_common[1]; /**< Common fragment info */
+ sip_error_t *ex_next; /**< Link to next (dummy) */
+ sip_time_t ex_date; /**< Seconds since Jan 1, 1900 */
+# define ex_time ex_date
+ sip_time_t ex_delta; /**< Delta seconds */
+};
+
+/**@ingroup sip_max_forwards
+ * @brief Structure for @MaxForwards header.
+ */
+struct sip_max_forwards_s
+{
+ sip_common_t mf_common[1]; /**< Common fragment info */
+ sip_error_t *mf_next; /**< Link to next (dummy) */
+ unsigned long mf_count; /**< Forwarding count */
+};
+
+/**@ingroup sip_min_expires
+ * @brief Structure for @MinExpires header.
+ */
+struct sip_min_expires_s
+{
+ sip_common_t me_common[1]; /**< Common fragment info */
+ sip_error_t *me_next; /**< Link to next (dummy) */
+ unsigned long me_delta; /**< Seconds */
+};
+
+/**@ingroup sip_rack
+ * @brief Structure for @b Rack header.
+ */
+struct sip_rack_s
+{
+ sip_common_t ra_common; /**< Common fragment info */
+ sip_error_t *ra_next; /**< Dummy link to next */
+ uint32_t ra_response; /**< Sequence number of response */
+ uint32_t ra_cseq; /**< Sequence number of request */
+ sip_method_t ra_method; /**< Original request method */
+ char const *ra_method_name; /**< Original request method name */
+};
+
+/**@ingroup sip_refer_to
+ * @brief Structure for @ReferTo header.
+ */
+struct sip_refer_to_s
+{
+ sip_common_t r_common[1]; /**< Common fragment info */
+ sip_error_t *r_next; /**< Link to next (dummy) */
+ char const *r_display;
+ url_t r_url[1]; /**< URI to reference */
+ msg_param_t const *r_params; /**< List of parameters */
+};
+
+/**@ingroup sip_referred_by
+ * @brief Structure for @ReferredBy header.
+ */
+struct sip_referred_by_s
+{
+ sip_common_t b_common[1]; /**< Common fragment info */
+ sip_error_t *b_next; /**< Link to next (dummy) */
+ char const *b_display;
+ url_t b_url[1]; /**< Referrer-URI */
+ msg_param_t const *b_params; /**< List of parameters */
+ char const *b_cid; /**< The cid parameter */
+};
+
+
+/**@ingroup sip_replaces
+ * @brief Structure for @Replaces header.
+ */
+struct sip_replaces_s
+{
+ sip_common_t rp_common[1]; /**< Common fragment info */
+ sip_error_t *rp_next; /**< Link to next (dummy) */
+ char const *rp_call_id; /**< @CallID of dialog to replace */
+ msg_param_t const *rp_params; /**< List of parameters */
+ char const *rp_to_tag; /**< Value of "to-tag" parameter */
+ char const *rp_from_tag; /**< Value of "from-tag" parameter */
+ unsigned rp_early_only; /**< early-only parameter */
+};
+
+
+/**@ingroup sip_retry_after
+ * @brief Structure for @RetryAfter header.
+ */
+struct sip_retry_after_s {
+ sip_common_t af_common[1]; /**< Common fragment info */
+ sip_error_t *af_next; /**< Link to next (dummy) */
+ sip_time_t af_delta; /**< Seconds to before retry */
+ char const *af_comment; /**< Comment string */
+ msg_param_t const *af_params; /**< List of parameters */
+ char const *af_duration; /**< Value of "duration" parameter */
+};
+
+/**@ingroup sip_request_disposition
+ * @brief Structure for @RequestDisposition header.
+ */
+struct sip_request_disposition_s
+{
+ sip_common_t rd_common[1]; /**< Common fragment info */
+ sip_error_t *rd_next; /**< Link to next (dummy) */
+ msg_param_t *rd_items; /**< List of directives */
+};
+
+/**@ingroup sip_caller_preferences
+ * @brief Structure for @AcceptContact and @RejectContact header fields.
+ */
+struct sip_caller_prefs_s
+{
+ sip_common_t cp_common[1]; /**< Common fragment info */
+ sip_caller_prefs_t *cp_next; /**< Link to next (dummy) */
+ msg_param_t const *cp_params; /**< List of parameters */
+ char const *cp_q; /**< @Priority */
+ unsigned cp_require :1; /**< Value of "require" parameter */
+ unsigned cp_explicit :1; /**< Value of "explicit" parameter */
+};
+
+/**@ingroup sip_reason
+ * @brief Structure for @Reason header field.
+ */
+struct sip_reason_s
+{
+ sip_common_t re_common[1]; /**< Common fragment info */
+ sip_reason_t *re_next; /**< Link to next */
+ char const *re_protocol; /**< Protocol */
+ msg_param_t const *re_params; /**< List of reason parameters */
+ char const *re_cause; /**< Value of cause parameter */
+ char const *re_text; /**< Value of text parameter */
+};
+
+/**@ingroup sip_route
+ * @brief Structure for @Route and @RecordRoute header fields.
+ */
+struct sip_route_s
+{
+ sip_common_t r_common[1]; /**< Common fragment info */
+ sip_route_t *r_next; /**< Link to next */
+ char const *r_display; /**< Display name */
+ url_t r_url[1]; /**< @Route URL */
+ msg_param_t const *r_params; /**< List of route parameters */
+};
+
+/**@ingroup sip_rseq
+ * @brief Structure for @RSeq header.
+ */
+struct sip_rseq_s
+{
+ sip_common_t rs_common[1]; /**< Common fragment info */
+ sip_error_t *rs_next; /**< Dummy link to next */
+ unsigned long rs_response; /**< Sequence number of response */
+};
+
+/**@ingroup sip_session_expires
+ * @brief Structure for @SessionExpires header.
+ */
+struct sip_session_expires_s
+{
+ sip_common_t x_common[1]; /**< Common fragment info */
+ sip_error_t *x_next; /**< Dummy link to next */
+ unsigned long x_delta; /**< Delta-seconds */
+ msg_param_t const *x_params; /**< List of parameters */
+ char const *x_refresher; /**< Value of "refresher"
+ * parameter: UAS or UAC */
+};
+
+/**@ingroup sip_min_se
+ * @brief Structure for @MinSE header.
+ */
+struct sip_min_se_s
+{
+ sip_common_t min_common[1]; /**< Common fragment info */
+ sip_error_t *min_next; /**< Dummy link to next */
+ unsigned long min_delta; /**< Delta-seconds */
+ msg_param_t const *min_params; /**< List of extension parameters */
+};
+
+/**@ingroup sip_subscription_state
+ * @brief Structure for @SubscriptionState header.
+ */
+struct sip_subscription_state_s
+{
+ sip_common_t ss_common[1]; /**< Common fragment info */
+ sip_error_t *ss_next; /**< Dummy link to next */
+ /** Subscription state: "pending", "active" or "terminated" */
+ char const *ss_substate;
+ msg_param_t const *ss_params; /**< List of parameters */
+ char const *ss_reason; /**< Reason for termination */
+ char const *ss_expires; /**< Subscription lifetime */
+ char const *ss_retry_after; /**< Value of retry-after parameter */
+};
+
+/**@ingroup sip_timestamp
+ * @brief Structure for @Timestamp header.
+ */
+struct sip_timestamp_s
+{
+ sip_common_t ts_common[1]; /**< Common fragment info */
+ sip_error_t *ts_next; /**< Dummy link to next */
+ char const *ts_stamp; /**< Original timestamp */
+ char const *ts_delay; /**< Delay at UAS */
+};
+
+/**@ingroup sip_via
+ * @brief Structure for @Via header field.
+ */
+struct sip_via_s
+{
+ sip_common_t v_common[1]; /**< Common fragment info */
+ sip_via_t *v_next; /**< Link to next @Via header */
+ char const *v_protocol; /**< Application and transport protocol */
+ char const *v_host; /**< Hostname */
+ char const *v_port; /**< Port number */
+ msg_param_t const *v_params; /**< List of via-params */
+ char const *v_comment; /**< Comment */
+ char const *v_ttl; /**< Value of "ttl" parameter */
+ char const *v_maddr; /**< Value of "maddr" parameter */
+ char const *v_received; /**< Value of "received" parameter*/
+ char const *v_branch; /**< Value of "branch" parameter */
+ char const *v_rport; /**< Value of "rport" parameter */
+ char const *v_comp; /**< Value of "comp" parameter */
+};
+
+/**@ingroup sip_security_client
+ * @brief Structure for @SecurityClient, @SecurityServer, and
+ * @SecurityVerify headers.
+ */
+struct sip_security_agree_s
+{
+ sip_common_t sa_common[1]; /**< Common fragment info */
+ struct sip_security_agree_s
+ *sa_next; /**< Link to next mechanism */
+ char const *sa_mec; /**< Security mechanism */
+ msg_param_t const *sa_params; /**< List of mechanism parameters */
+ char const *sa_q; /**< Value of q (preference) parameter */
+ char const *sa_d_alg; /**< Value of d-alg parameter */
+ char const *sa_d_qop; /**< Value of d-qop parameter */
+ char const *sa_d_ver; /**< Value of d-ver parameter */
+};
+
+/**@ingroup sip_privacy
+ * @brief Structure for @Privacy header.
+ */
+struct sip_privacy_s
+{
+ sip_common_t priv_common[1];/**< Common fragment info */
+ sip_error_t *priv_next; /**< Dummy link */
+ msg_param_t const *priv_values; /**< @Privacy values */
+};
+
+/* union representing any SIP header
+ * these are arrays of size 1 for easy casting
+ */
+union sip_header_u
+{
+ sip_common_t sh_common[1];
+ struct
+ {
+ sip_common_t shn_common;
+ sip_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
+
+ sip_addr_t sh_addr[1];
+ sip_auth_t sh_auth[1];
+ sip_generic_t sh_generic[1];
+
+ sip_request_t sh_request[1];
+ sip_status_t sh_status[1];
+
+ sip_error_t sh_error[1];
+
+ sip_via_t sh_via[1];
+ sip_route_t sh_route[1];
+ sip_record_route_t sh_record_route[1];
+ sip_max_forwards_t sh_max_forwards[1];
+
+ sip_from_t sh_from[1];
+ sip_to_t sh_to[1];
+ sip_contact_t sh_contact[1];
+ sip_call_id_t sh_call_id[1];
+ sip_cseq_t sh_cseq[1];
+ sip_rseq_t sh_rseq[1];
+ sip_rack_t sh_rack[1];
+
+ sip_subject_t sh_subject[1];
+ sip_priority_t sh_priority[1];
+
+ sip_date_t sh_date[1];
+ sip_retry_after_t sh_retry_after[1];
+ sip_timestamp_t sh_timestamp[1];
+ sip_expires_t sh_expires[1];
+ sip_min_expires_t sh_min_expires[1];
+
+ sip_call_info_t sh_call_info[1];
+ sip_organization_t sh_organization[1];
+ sip_server_t sh_server[1];
+ sip_user_agent_t sh_user_agent[1];
+ sip_in_reply_to_t sh_in_reply_to[1];
+
+ sip_accept_t sh_accept[1];
+ sip_accept_encoding_t sh_accept_encoding[1];
+ sip_accept_language_t sh_accept_language[1];
+
+ sip_allow_t sh_allow[1];
+ sip_require_t sh_require[1];
+ sip_proxy_require_t sh_proxy_require[1];
+ sip_supported_t sh_supported[1];
+ sip_unsupported_t sh_unsupported[1];
+
+ sip_event_t sh_event[1];
+ sip_allow_events_t sh_allow_events[1];
+ sip_subscription_state_t sh_subscription_state[1];
+
+ sip_proxy_authenticate_t sh_proxy_authenticate[1];
+ sip_proxy_authentication_info_t sh_proxy_authentication_info[1];
+ sip_proxy_authorization_t sh_proxy_authorization[1];
+
+ sip_authorization_t sh_authorization[1];
+ sip_www_authenticate_t sh_www_authenticate[1];
+ sip_authentication_info_t sh_authentication_info[1];
+
+ sip_error_info_t sh_error_info[1];
+ sip_warning_t sh_warning[1];
+
+ sip_refer_to_t sh_refer_to[1];
+ sip_referred_by_t sh_referred_by[1];
+ sip_replaces_t sh_replaces[1];
+
+ /* Caller-Preferences */
+ sip_caller_prefs_t sh_caller_prefs[1];
+ sip_request_disposition_t sh_request_disposition[1];
+ sip_accept_contact_t sh_accept_contact[1];
+ sip_reject_contact_t sh_reject_contact[1];
+
+ sip_session_expires_t sh_session_expires[1];
+ sip_min_se_t sh_min_se[1];
+
+ sip_path_t sh_path[1];
+ sip_service_route_t sh_service_route[1];
+
+ sip_reason_t sh_reason[1];
+
+ sip_security_client_t sh_security_client[1];
+ sip_security_server_t sh_security_server[1];
+ sip_security_verify_t sh_security_verify[1];
+
+ sip_privacy_t sh_privacy[1];
+
+ sip_etag_t sh_etag[1];
+ sip_if_match_t sh_if_match[1];
+
+ /* Entity headers */
+ sip_mime_version_t sh_mime_version[1];
+ sip_content_type_t sh_content_type[1];
+ sip_content_encoding_t sh_content_encoding[1];
+ sip_content_language_t sh_content_language[1];
+ sip_content_length_t sh_content_length[1];
+ sip_content_disposition_t sh_content_disposition[1];
+
+ sip_unknown_t sh_unknown[1];
+
+ sip_separator_t sh_separator[1];
+ sip_payload_t sh_payload[1];
+};
+
+SOFIA_END_DECLS
+
+#endif /* !defined(SIP_H) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_extra.h.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_extra.h.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1,98 @@
+/**@file sofia-sip/sip_extra.h.in
+ * -*- C -*-
+ * Template for <sofia-sip/sip_extra.h>.
+ *
+ * @date Created: Thu Oct 5 19:10:58 EEST 2006
+ */
+
+/* -*- C -*-
+ *
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SIP_EXTRA_H
+/** Defined when <sofia-sip/sip_extra.h> has been included. */
+#define SIP_EXTRA_H
+
+/**@file sofia-sip/sip_extra.h
+*
+ * @brief Extension headers for SIP.
+ *
+ * #AUTO#
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ */
+
+#ifndef SIP_H
+#include <sofia-sip/sip.h>
+#endif
+
+#ifndef SIP_HEADER_H
+#include <sofia-sip/sip_header.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+typedef struct sip_refer_sub_s sip_refer_sub_t;
+
+/**@ingroup sip_refer_sub
+ * @brief Structure for @ReferSub header.
+ */
+struct sip_refer_sub_s
+{
+ sip_common_t rs_common[1]; /**< Common fragment info */
+ sip_error_t *rs_next; /**< Dummy link to next */
+ char const *rs_value; /**< "true" or "false" */
+ msg_param_t const *rs_params; /**< List of extension parameters */
+};
+
+typedef struct sip_suppress_body_if_match_s sip_suppress_body_if_match_t;
+
+/**@ingroup sip_suppress_body_if_match
+ * @brief Structure for @SuppressBodyIfMatch header.
+ */
+struct sip_suppress_body_if_match_s
+{
+ sip_common_t sbim_common[1]; /**< Common fragment info */
+ sip_error_t *sbim_next; /**< Dummy link to next header */
+ char const *sbim_tag; /**< Entity-tag */
+};
+
+typedef struct sip_suppress_notify_if_match_s sip_suppress_notify_if_match_t;
+
+/**@ingroup sip_suppress_notify_if_match
+ * @brief Structure for @SuppressNotifyIfMatch header.
+ */
+struct sip_suppress_notify_if_match_s
+{
+ sip_common_t snim_common[1]; /**< Common fragment info */
+ sip_error_t *snim_next; /**< Dummy link to next header */
+ char const *snim_tag; /**< Entity-tag */
+};
+
+
+
+
+SOFIA_END_DECLS
+
+#endif /** !defined(SIP_EXTRA_H) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_hclasses.h.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_hclasses.h.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1,78 @@
+/** -*- C -*-
+ *
+ * @file sofia-sip/sip_hclasses.h.in
+ *
+ * Template for <sip_hclasses.h>.
+ */
+
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SIP_HCLASSES_H
+/** Defined when <sofia-sip/sip_hclasses.h> has been included. */
+#define SIP_HCLASSES_H
+
+/**@file sofia-sip/sip_hclasses.h
+ * @brief Declarations of SIP header classes.
+ *
+ * #AUTO#
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Jan 23 19:26:31 2003 ppessi
+ */
+
+#ifndef MSG_TYPES_H
+#include <sofia-sip/msg_types.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+
+enum {
+ /**@ingroup sip_#xxxxxx# @internal
+ *
+ * Hash of @ref sip_#xxxxxx# "#xxxxxxx_xxxxxxx#".
+ *
+ * @since New in #version#.
+ */
+ sip_#xxxxxx#_hash = #hash#
+};
+
+/**Header class for @ref sip_#xxxxxx# "#xxxxxxx_xxxxxxx#".
+ *
+ * The header class sip_#xxxxxx#_class defines how a SIP
+ * @ref sip_#xxxxxx# "#xxxxxxx_xxxxxxx#" is parsed and printed.
+ * It also contains methods used by SIP parser and other functions to
+ * manipulate the #sip_#xxxxxx#_t header structure.
+ *
+ * @ingroup sip_#xxxxxx#
+ *
+ * @since New in #version#.
+ */
+SIP_DLL extern msg_hclass_t sip_#xxxxxx#_class[];
+
+
+SOFIA_END_DECLS
+#endif /* !defined SIP_HCLASSES_H */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_header.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_header.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,416 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SIP_HEADER_H
+/**Defined when <sofia-sip/sip_header.h> has been included.*/
+#define SIP_HEADER_H
+
+/**@file sofia-sip/sip_header.h
+ *
+ * SIP parser library prototypes.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Tue Jun 13 02:58:26 2000 ppessi
+ */
+
+#ifndef SU_ALLOC_H
+#include <sofia-sip/su_alloc.h>
+#endif
+
+#ifndef SU_TAG_H
+#include <sofia-sip/su_tag.h>
+#endif
+
+#ifndef SIP_H
+#include <sofia-sip/sip.h>
+#endif
+
+#ifndef MSG_HEADER_H
+#include <sofia-sip/msg_header.h>
+#endif
+
+#ifndef _STRING_H
+#include <string.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** Return built-in SIP parser object. */
+SOFIAPUBFUN msg_mclass_t *sip_default_mclass(void);
+
+/** Check that sip_t is a SIP structure (not RTSP or HTTP). @HIDE */
+#define sip_is_sip(sip) ((sip) && (sip)->sip_ident == SIP_PROTOCOL_TAG)
+
+/** Initializer for a SIP header object. @HIDE */
+#define SIP_HDR_INIT(name) {{{ 0, 0, sip_##name##_class }}}
+
+/** Initialize a SIP header structure. @HIDE */
+#define SIP_HEADER_INIT(h, sip_class, size) \
+ ((void)memset((h), 0, (size)), \
+ (void)(((sip_common_t *)(h))->h_class = (sip_class)), \
+ (h))
+
+/** Serialize headers into the fragment chain. */
+SOFIAPUBFUN int sip_serialize(msg_t *msg, sip_t *sip);
+
+/** Encode a SIP message. */
+SOFIAPUBFUN issize_t sip_e(sip_t const *sip, int flags, char b[], isize_t size);
+
+/** Test if @a header is a pointer to a SIP header object. */
+SOFIAPUBFUN int sip_is_header(sip_header_t const *header);
+
+/** Convert the header @a h to a string allocated from @a home. */
+SOFIAPUBFUN char *sip_header_as_string(su_home_t *home,
+ sip_header_t const *h);
+
+/** Add a duplicate of header object to a SIP message. */
+SOFIAPUBFUN int sip_add_dup(msg_t *, sip_t *, sip_header_t const *);
+
+/** Add a duplicate of header object to the SIP message. */
+SOFIAPUBFUN int sip_add_dup_as(msg_t *msg, sip_t *sip,
+ msg_hclass_t *hc, sip_header_t const *o);
+
+/** Add duplicates of headers to the SIP message. */
+SOFIAPUBFUN int sip_add_headers(msg_t *msg, sip_t *sip,
+ void const *extra, va_list headers);
+
+/** Add duplicates of headers from taglist to the SIP message. */
+SOFIAPUBFUN int sip_add_tl(msg_t *msg, sip_t *sip,
+ tag_type_t tag, tag_value_t value, ...);
+
+/** Add duplicates of headers from taglist to the SIP message. */
+SOFIAPUBFUN int sip_add_tagis(msg_t *, sip_t *, tagi_t const **inout_list);
+
+/** Parse a string as a header and add it to the SIP message. */
+SOFIAPUBFUN int sip_add_make(msg_t *, sip_t *, msg_hclass_t *hc, char const *s);
+
+/** Convert headers from taglist as URL query. */
+SOFIAPUBFUN char *sip_headers_as_url_query(su_home_t *home,
+ tag_type_t tag, tag_value_t value,
+ ...);
+
+/** Convert URL query to a tag list. */
+SOFIAPUBFUN tagi_t *sip_url_query_as_taglist(su_home_t *home,
+ char const *query,
+ msg_mclass_t const *parser);
+
+/** Complete SIP message. */
+SOFIAPUBFUN int sip_complete_message(msg_t *msg);
+
+/** Clear encoded data. @HIDE */
+#define sip_fragment_clear(a) ((a)->h_data = NULL, (a)->h_len = 0)
+
+/* Use __attribute__ to allow argument checking for sip_header_format() */
+#if !defined(__GNUC__) && !defined(__attribute__)
+#define __attribute__(x)
+#endif
+
+/** Make a SIP header with formatting provided. */
+SOFIAPUBFUN sip_header_t *sip_header_format(su_home_t *home,
+ msg_hclass_t *hc,
+ char const *fmt,
+ ...)
+ __attribute__((__format__ (printf, 3, 4)));
+
+/** Return current time */
+SOFIAPUBFUN sip_time_t sip_now(void);
+
+SOFIAPUBVAR char const sip_method_name_ack[];
+SOFIAPUBVAR char const sip_method_name_bye[];
+SOFIAPUBVAR char const sip_method_name_cancel[];
+SOFIAPUBVAR char const sip_method_name_invite[];
+SOFIAPUBVAR char const sip_method_name_options[];
+SOFIAPUBVAR char const sip_method_name_register[];
+SOFIAPUBVAR char const sip_method_name_info[];
+SOFIAPUBVAR char const sip_method_name_prack[];
+SOFIAPUBVAR char const sip_method_name_comet[];
+SOFIAPUBVAR char const sip_method_name_message[];
+SOFIAPUBVAR char const sip_method_name_subscribe[];
+SOFIAPUBVAR char const sip_method_name_notify[];
+SOFIAPUBVAR char const sip_method_name_refer[];
+
+/** @internal UDP transport version string. */
+SOFIAPUBVAR char const sip_transport_udp[];
+/** @internal TCP transport version string. */
+SOFIAPUBVAR char const sip_transport_tcp[];
+/** @internal SCTP transport version string. */
+SOFIAPUBVAR char const sip_transport_sctp[];
+/** @internal TLS transport version string. */
+SOFIAPUBVAR char const sip_transport_tls[];
+/** @internal SIP version string. */
+SOFIAPUBVAR char const sip_version_2_0[];
+
+#define SIP_VERSION_CURRENT sip_version_2_0
+
+/** SIP parser version */
+SOFIAPUBVAR char const sip_parser_version[];
+
+/** Get SIP service name */
+#define SIP_PORT(s) ((s) ? (s) : "5060")
+
+/** Get SIPS service name */
+#define SIPS_PORT(s) ((s) ? (s) : "5061")
+
+/** Return string corresponding to the method. */
+SOFIAPUBFUN char const *sip_method_name(sip_method_t method, char const *name);
+
+/** Return code corresponding to the method code */
+SOFIAPUBFUN sip_method_t sip_method_code(char const *name);
+
+SOFIAPUBVAR char const * const sip_method_names[];
+
+#define SIP_METHOD_NAME(method, name) \
+ ((method) == sip_method_unknown ? (name) : sip_method_name(method, name))
+
+#define sip_header_make(h, c, s) \
+ ((sip_header_t *)msg_header_make((h), (c), (s)))
+#define sip_header_vformat(h, c, f, a) \
+ ((sip_header_t *)msg_header_vformat((h), (c), (f), (a)))
+
+SOFIA_END_DECLS
+#ifndef SIP_PROTOS_H
+#include <sofia-sip/sip_protos.h>
+#endif
+SOFIA_BEGIN_DECLS
+
+/** Create a request line object. */
+SOFIAPUBFUN
+sip_request_t *sip_request_create(su_home_t *home,
+ sip_method_t method, const char *name,
+ url_string_t const *url,
+ char const *version);
+
+/** Create a status line object. */
+SOFIAPUBFUN
+sip_status_t *sip_status_create(su_home_t *home,
+ unsigned status,
+ char const *phrase,
+ char const *version);
+
+/** Create a @CallID header object. */
+SOFIAPUBFUN sip_call_id_t *sip_call_id_create(su_home_t *home,
+ char const *domain);
+
+/** Create a @CSeq header object. */
+SOFIAPUBFUN sip_cseq_t *sip_cseq_create(su_home_t *, uint32_t seq,
+ unsigned method, char const *name);
+
+/** Create a @Contact header object. */
+SOFIAPUBFUN sip_contact_t * sip_contact_create(su_home_t *,
+ url_string_t const *url,
+ char const *param,
+ /* char const *params, */
+ ...);
+
+/** Calculate expiration time of a @Contact header. */
+SOFIAPUBFUN sip_time_t sip_contact_expires(sip_contact_t const *m,
+ sip_expires_t const *ex,
+ sip_date_t const *date,
+ sip_time_t def,
+ sip_time_t now);
+
+/** Create a @ContentLength header object. */
+SOFIAPUBFUN
+sip_content_length_t *sip_content_length_create(su_home_t *, uint32_t n);
+
+/** Create an @Date header object. */
+SOFIAPUBFUN sip_date_t *sip_date_create(su_home_t *, sip_time_t t);
+
+/** Create an @Expires header object. */
+SOFIAPUBFUN sip_expires_t *sip_expires_create(su_home_t *, sip_time_t delta);
+
+/** Create a @Route header object. */
+SOFIAPUBFUN sip_route_t *sip_route_create(su_home_t *home, url_t const *url,
+ url_t const *maddr);
+
+/** Create a @RecordRoute header object. */
+SOFIAPUBFUN sip_record_route_t *sip_record_route_create(su_home_t *,
+ url_t const *rq_url,
+ url_t const *m_url);
+
+/** Create a @From header object. */
+SOFIAPUBFUN sip_from_t *sip_from_create(su_home_t *, url_string_t const *url);
+
+SOFIAPUBFUN int sip_from_tag(su_home_t *, sip_from_t *from, char const *tag);
+
+/** Create a @To header object. */
+SOFIAPUBFUN sip_to_t *sip_to_create(su_home_t *, url_string_t const *url);
+
+SOFIAPUBFUN int sip_to_tag(su_home_t *, sip_to_t *to, char const *tag);
+
+/** Create a @Via object. */
+SOFIAPUBFUN sip_via_t *sip_via_create(su_home_t *h,
+ char const *host,
+ char const *port,
+ char const *transport,
+ /* char const *params */
+ ...);
+
+/** Get transport protocol name. */
+#if SU_HAVE_INLINE
+su_inline char const *sip_via_transport(sip_via_t const *v)
+{
+ char const *tp = v->v_protocol;
+ if (tp) {
+ tp = strchr(tp, '/');
+ if (tp) {
+ tp = strchr(tp + 1, '/');
+ if (tp)
+ return tp + 1;
+ }
+ }
+ return NULL;
+}
+#else
+char const *sip_via_transport(sip_via_t const *v);
+#endif
+
+SOFIAPUBFUN char const *sip_via_port(sip_via_t const *v, int *using_rport);
+
+SOFIAPUBFUN
+sip_payload_t *sip_payload_create(su_home_t *, void const *data, isize_t len);
+
+/**@ingroup sip_payload
+ *
+ * Initialize a SIP payload structure with pointer to data and its length.
+ *
+ * The SIP_PAYLOAD_INIT2() macro initializes a #sip_payload_t header
+ * structure with a pointer to data and its length in octets. For
+ * instance,
+ * @code
+ * sip_payload_t txt_payload = SIP_PAYLOAD_INIT2(txt, strlen(txt));
+ * @endcode
+ *
+ * The SIP_PAYLOAD_INIT2() macro can be used when creating a new payload
+ * from heap is not required, for instance, when the resulting payload
+ * structure is immediately copied.
+ *
+ * @HIDE
+ */
+#define SIP_PAYLOAD_INIT2(data, length) \
+ {{{ 0, 0, sip_payload_class, data, length }, NULL, data, length }}
+
+/** Create a SIP separator line structure. */
+SOFIAPUBFUN sip_separator_t *sip_separator_create(su_home_t *home);
+
+/** Check that a required feature is supported. */
+SOFIAPUBFUN
+sip_unsupported_t *sip_has_unsupported(su_home_t *,
+ sip_supported_t const *support,
+ sip_require_t const *require);
+
+SOFIAPUBFUN
+sip_unsupported_t *sip_has_unsupported2(su_home_t *,
+ sip_supported_t const *support,
+ sip_require_t const *by_require,
+ sip_require_t const *require);
+
+SOFIAPUBFUN
+sip_unsupported_t *
+sip_has_unsupported_any(su_home_t *,
+ sip_supported_t const *support,
+ sip_require_t const *by_require,
+ sip_proxy_require_t const *by_proxy_require,
+ sip_require_t const *require,
+ sip_require_t const *require2,
+ sip_require_t const *require3);
+
+/** Check that a feature is supported. */
+SOFIAPUBFUN
+int sip_has_supported(sip_supported_t const *support, char const *feature);
+
+/** Check that a feature is in the list. */
+SOFIAPUBFUN
+int sip_has_feature(msg_list_t const *supported, char const *feature);
+
+SOFIAPUBFUN int sip_is_allowed(sip_allow_t const *allow,
+ sip_method_t method, char const *name);
+
+/* ---------------------------------------------------------------------------
+ * Bitmasks for header classifications
+ */
+enum {
+ sip_mask_request = 1,
+ sip_mask_response = 2,
+ sip_mask_ua = 4,
+ sip_mask_proxy = 8,
+ sip_mask_registrar = 16,
+ sip_mask_100rel = 32,
+ sip_mask_events = 64,
+ sip_mask_timer = 128,
+ sip_mask_privacy = 256,
+ sip_mask_pref = 512,
+ sip_mask_publish = 1024
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* Here are @deprecated functions and names for compatibility */
+
+/** Encode a SIP header field (name: contents CRLF). */
+SOFIAPUBFUN issize_t sip_header_e(char[], isize_t, sip_header_t const *, int);
+
+/** Decode a SIP header string (name: contents CRLF?). */
+SOFIAPUBFUN
+sip_header_t *sip_header_d(su_home_t *, msg_t const *, char const *);
+
+/** Encode contents of a SIP header field. */
+SOFIAPUBFUN issize_t sip_header_field_e(char[], isize_t, sip_header_t const *, int);
+
+/** Decode the string containing header field */
+SOFIAPUBFUN issize_t sip_header_field_d(su_home_t *, sip_header_t *, char *, isize_t);
+
+/** Calculate the size of a SIP header and associated memory areas. */
+SOFIAPUBFUN isize_t sip_header_size(sip_header_t const *h);
+
+/** Duplicate (deep copy) a SIP header or whole list. */
+SOFIAPUBFUN sip_header_t *sip_header_dup(su_home_t *, sip_header_t const *);
+
+/** Copy a SIP header or whole list. */
+SOFIAPUBFUN sip_header_t *sip_header_copy(su_home_t *, sip_header_t const *o);
+
+/** Add an event to @AllowEvents header. */
+SOFIAPUBFUN int sip_allow_events_add(su_home_t *,
+ sip_allow_events_t *ae,
+ char const *e);
+
+/** Add a parameter to a @Contact header object. */
+SOFIAPUBFUN int sip_contact_add_param(su_home_t *, sip_contact_t *,
+ char const *param);
+
+SOFIAPUBFUN int sip_to_add_param(su_home_t *, sip_to_t *, char const *);
+
+SOFIAPUBFUN int sip_from_add_param(su_home_t *, sip_from_t *, char const *);
+
+/** Add a parameter to a @Via header object. */
+SOFIAPUBFUN int sip_via_add_param(su_home_t *, sip_via_t *, char const *);
+
+#define sip_from_make_url sip_from_create
+#define sip_to_make_url sip_to_create
+#define sip_params_find msg_params_find
+
+SOFIA_END_DECLS
+
+#endif
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_parser.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_parser.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,211 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SIP_PARSER_H
+/** Defined when <sofia-sip/sip_parser.h> has been included.*/
+#define SIP_PARSER_H
+
+
+/**@ingroup sip_parser
+ * @file sofia-sip/sip_parser.h
+ *
+ * SIP parser provider interface.
+ *
+ * This file contains functions and macros used to create a SIP parser using
+ * generic text message parser, and to define new SIP header classes.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Thu Mar 8 15:13:11 2001 ppessi
+ */
+
+#ifndef SU_ALLOC_H
+#include <sofia-sip/su_alloc.h>
+#endif
+
+#ifndef MSG_H
+#include <sofia-sip/msg.h>
+#endif
+
+#ifndef MSG_PARSER_H
+#include <sofia-sip/msg_parser.h>
+#endif
+
+#ifndef SIP_H
+#include <sofia-sip/sip.h>
+#endif
+
+#ifndef SIP_HEADER_H
+#include <sofia-sip/sip_header.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/* ---------------------------------------------------------------------------
+ * 1) Macros for defining boilerplate functions and structures for each header
+ */
+
+#define SIP_HDR_TEST(x) ((x)->sh_class)
+
+/** Define a header class for a SIP header. @HIDE */
+#define SIP_HEADER_CLASS(c, l, s, params, kind, dup) \
+ MSG_HEADER_CLASS(sip_, c, l, s, params, kind, sip_ ## dup, sip_ ## dup)
+
+/** Define a header class for a critical SIP header. @HIDE */
+#define SIP_HEADER_CLASS_C(c, l, s, params, kind, dup) \
+ MSG_HEADER_CLASS_C(sip_, c, l, s, params, kind, sip_ ## dup, sip_ ## dup)
+
+/** Define a header class for headers without any extra data to copy. @HIDE */
+#define SIP_HEADER_CLASS_G(c, l, s, kind) \
+ MSG_HEADER_CLASS(sip_, c, l, s, g_common, kind, msg_generic, sip_null)
+
+/** Define a header class for a msg_list_t kind of header. @HIDE */
+#define SIP_HEADER_CLASS_LIST(c, l, s, kind) \
+ MSG_HEADER_CLASS(sip_, c, l, s, k_items, kind, msg_list, sip_null)
+
+/** Define a authorization header class. @HIDE */
+#define SIP_HEADER_CLASS_AUTH(c, l, kind) \
+ MSG_HEADER_CLASS(sip_, c, l, "", au_params, kind, msg_auth, sip_null)
+
+#define sip_null_update NULL
+#define sip_any_update NULL
+
+/* ---------------------------------------------------------------------------
+ * 2) Prototypes for internal decoding/encoding functions
+ */
+
+/* Version string */
+SOFIAPUBFUN int sip_version_d(char **ss, char const **ver);
+SOFIAPUBFUN isize_t sip_version_xtra(char const *version);
+SOFIAPUBFUN void sip_version_dup(char **pp, char const **dd, char const *s);
+
+/* Transport identifiers */
+#define SIP_TRANSPORT_LEN(s) SIP_STRING_SIZE((s))
+SOFIAPUBFUN issize_t sip_transport_d(char **ss, char const **ttransport);
+SOFIAPUBFUN isize_t sip_transport_xtra(char const *transport);
+SOFIAPUBFUN void sip_transport_dup(char **pp, char const **dd, char const *s);
+
+/* Method */
+SOFIAPUBFUN sip_method_t sip_method_d(char **ss, char const **nname);
+
+/* Call-ID */
+SOFIAPUBFUN char *sip_word_at_word_d(char **ss);
+
+/** Extract SIP message body, including separator line. */
+SOFIAPUBFUN issize_t sip_extract_body(msg_t *, sip_t *, char b[], isize_t bsiz, int eos);
+
+SOFIAPUBFUN issize_t sip_any_route_d(su_home_t *, sip_header_t *, char *s, isize_t slen);
+SOFIAPUBFUN issize_t sip_any_route_e(char [], isize_t, sip_header_t const *, int flags);
+SOFIAPUBFUN isize_t sip_any_route_dup_xtra(sip_header_t const *h, isize_t offset);
+SOFIAPUBFUN char *sip_any_route_dup_one(sip_header_t *dst,
+ sip_header_t const *src,
+ char *b, isize_t xtra);
+#define sip_any_route_update NULL
+
+SOFIAPUBFUN issize_t sip_name_addr_d(su_home_t *home,
+ char **inout_s,
+ char const **return_display,
+ url_t *out_url,
+ msg_param_t const **return_params,
+ char const **return_comment);
+
+SOFIAPUBFUN issize_t sip_name_addr_e(char b[], isize_t bsiz,
+ int flags,
+ char const *display,
+ int always_ltgt, url_t const url[],
+ msg_param_t const params[],
+ char const *comment);
+
+/* ---------------------------------------------------------------------------
+ * 3) Compatibility macros and functions
+ */
+
+#define sip_generic_d msg_generic_d
+#define sip_generic_e msg_generic_e
+
+#define sip_numeric_d msg_numeric_d
+#define sip_numeric_e msg_numeric_e
+
+#define sip_any_copy_xtra msg_default_copy_xtra
+#define sip_any_copy_one msg_default_copy_one
+#define sip_any_dup_xtra msg_default_dup_xtra
+#define sip_any_dup_one msg_default_dup_one
+
+#define sip_generic_dup_xtra msg_generic_dup_xtra
+#define sip_generic_dup_one msg_generic_dup_one
+
+
+#define sip_auth_d msg_auth_d
+#define sip_auth_e msg_auth_e
+
+#define sip_header_dup_as msg_header_dup_as
+#define sip_header_alloc msg_header_alloc
+#define sip_header_copy_as msg_header_copy_as
+
+#define SIP_ALIGN MSG_ALIGN
+#define SIP_STRUCT_SIZE_ALIGN MSG_STRUCT_SIZE_ALIGN
+#define SIP_STRUCT_ALIGN MSG_STRUCT_ALIGN
+
+#define sip_comment_d msg_comment_d
+#define sip_quoted_d(ss, qq) msg_quoted_d(ss, qq)
+
+#define SIP_CHAR_E MSG_CHAR_E
+#define SIP_STRING_LEN MSG_STRING_LEN
+#define SIP_STRING_E MSG_STRING_E
+#define SIP_STRING_DUP MSG_STRING_DUP
+#define SIP_STRING_SIZE MSG_STRING_SIZE
+#define SIP_NAME_E MSG_NAME_E
+
+/* Parameters */
+#define SIP_PARAM_MATCH MSG_PARAM_MATCH
+#define SIP_PARAM_MATCH_P MSG_PARAM_MATCH_P
+
+/* Parameter lists */
+#define SIP_N_PARAMS MSG_N_PARAMS
+#define sip_params_d msg_params_d
+#define sip_params_dup msg_params_dup
+#define SIP_PARAMS_NUM MSG_PARAMS_NUM
+#define SIP_PARAMS_E MSG_PARAMS_E
+#define SIP_PARAMS_SIZE MSG_PARAMS_SIZE
+#define sip_params_count msg_params_count
+#define sip_params_copy_xtra msg_params_copy_xtra
+#define sip_params_copy msg_params_copy
+
+#define sip_params_add msg_params_add
+#define sip_params_cmp msg_params_cmp
+#define sip_params_replace msg_params_replace
+
+SOFIAPUBFUN int sip_generic_xtra(sip_generic_t const *g);
+
+SOFIAPUBFUN sip_generic_t *sip_generic_dup(su_home_t *home,
+ msg_hclass_t *hc,
+ sip_generic_t const *u);
+
+SOFIAPUBFUN sip_generic_t *sip_generic_copy(su_home_t *home,
+ msg_hclass_t *hc,
+ sip_generic_t const *o);
+
+SOFIA_END_DECLS
+
+#endif
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_protos.h.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_protos.h.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1,367 @@
+/**@file sofia-sip/sip_protos.h.in
+ *
+ * Template for <sip_protos.h>.
+ */
+
+/* -*- C -*-
+ *
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SIP_PROTOS_H
+/** Defined when <sofia-sip/sip_protos.h> has been included. */
+#define SIP_PROTOS_H
+
+/**@file sofia-sip/sip_protos.h
+ *
+ * SIP prototypes and macros for each header.
+ *
+ * #AUTO#
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ */
+
+#include <sofia-sip/su_config.h>
+
+#ifndef SIP_HEADER_H
+#include <sofia-sip/sip_header.h>
+#endif
+
+#ifndef SIP_HCLASSES_H
+#include <sofia-sip/sip_hclasses.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+#if SU_HAVE_INLINE
+/** Get SIP structure from msg. */
+su_inline
+sip_t *sip_object(msg_t const *msg)
+{
+ return (sip_t *)msg_public(msg, SIP_PROTOCOL_TAG);
+}
+
+/** Insert a (list of) header(s) to the header structure and fragment chain.
+ *
+ * The function @c sip_header_insert() inserts header or list of headers
+ * into a SIP message. It also inserts them into the the message fragment
+ * chain, if it exists.
+ *
+ * When inserting headers into the fragment chain, a request (or status) is
+ * inserted first and replaces the existing request (or status). The Via
+ * headers are inserted after the request or status, and rest of the headers
+ * after request, status, or Via headers.
+ *
+ * If the header is a singleton, existing headers with the same class are
+ * removed.
+ *
+ * @param msg message owning the fragment chain
+ * @param sip SIP message structure to which header is added
+ * @param h list of header(s) to be added
+ */
+su_inline
+int sip_header_insert(msg_t *msg, sip_t *sip, sip_header_t *h)
+{
+ return msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)h);
+}
+
+/** Remove a header from a SIP message. */
+su_inline
+int sip_header_remove(msg_t *msg, sip_t *sip, sip_header_t *h)
+{
+ return msg_header_remove(msg, (msg_pub_t *)sip, (msg_header_t *)h);
+}
+
+/** Return name of the header. */
+su_inline
+char const *sip_header_name(sip_header_t const *h, int compact)
+{
+ if (compact && h->sh_class->hc_short[0])
+ return h->sh_class->hc_short;
+ else
+ return h->sh_class->hc_name;
+}
+
+/** Return data after header structure. */
+su_inline
+void *sip_header_data(sip_header_t *h)
+{
+ return h && h != SIP_NONE ? h->sh_class->hc_size + (char *)h : NULL;
+}
+#else
+sip_t *sip_object(msg_t *msg);
+int sip_header_insert(msg_t *msg, sip_t *sip, sip_header_t *h);
+int sip_header_remove(msg_t *msg, sip_t *sip, sip_header_t *h);
+char const *sip_header_name(sip_header_t const *h, int compact);
+void *sip_header_data(sip_header_t *h);
+#endif
+
+/**@addtogroup sip_#xxxxxx#
+ * @{
+ */
+
+/** Parse a SIP @ref sip_#xxxxxx# "#xxxxxxx_xxxxxxx#". @internal */
+SOFIAPUBFUN issize_t sip_#xxxxxx#_d(su_home_t *, msg_header_t *,
+ char *s, isize_t slen);
+
+/** Print a SIP @ref sip_#xxxxxx# "#xxxxxxx_xxxxxxx#". @internal */
+SOFIAPUBFUN issize_t sip_#xxxxxx#_e(char b[], isize_t bsiz,
+ msg_header_t const *h, int flags);
+
+/**Access a SIP @ref sip_#xxxxxx# "#xxxxxxx_xxxxxxx#"
+ * structure #sip_#xxxxxx#_t from #sip_t.
+ *
+ * @since New in #version#.
+ */
+#define sip_#xxxxxx#(sip) \
+ ((sip_#xxxxxx#_t *)msg_header_access((msg_pub_t*)(sip), sip_#xxxxxx#_class))
+
+/**Initializer for structure #sip_#xxxxxx#_t.
+ *
+ * A static #sip_#xxxxxx#_t structure for
+ * @ref sip_#xxxxxx# "#xxxxxxx_xxxxxxx#" must be initialized with
+ * the SIP_#XXXXXX#_INIT() macro.
+ * For instance,
+ * @code
+ *
+ * sip_#xxxxxx#_t sip_#xxxxxx# = SIP_#XXXXXX#_INIT;
+ *
+ * @endcode
+ * @HI
+ *
+ * @since New in #version#.
+ */
+#define SIP_#XXXXXX#_INIT() SIP_HDR_INIT(#xxxxxx#)
+
+/**Initialize a structure #sip_#xxxxxx#_t.
+ *
+ * An #sip_#xxxxxx#_t structure for
+ * @ref sip_#xxxxxx# "#xxxxxxx_xxxxxxx#" can be initialized with the
+ * sip_#xxxxxx#_init() function/macro. For instance,
+ * @code
+ *
+ * sip_#xxxxxx#_t sip_#xxxxxx#;
+ *
+ * sip_#xxxxxx#_init(&sip_#xxxxxx#);
+ *
+ * @endcode
+ * @HI
+ *
+ * @since New in #version#.
+ */
+#if SU_HAVE_INLINE
+su_inline sip_#xxxxxx#_t *sip_#xxxxxx#_init(sip_#xxxxxx#_t x[1])
+{
+ return SIP_HEADER_INIT(x, sip_#xxxxxx#_class, sizeof(sip_#xxxxxx#_t));
+}
+#else
+#define sip_#xxxxxx#_init(x) \
+ SIP_HEADER_INIT(x, sip_#xxxxxx#_class, sizeof(sip_#xxxxxx#_t))
+#endif
+
+/**Test if header object is instance of #sip_#xxxxxx#_t.
+ *
+ * Check if the header class is an instance of
+ * @ref sip_#xxxxxx# "#xxxxxxx_xxxxxxx#" object and return true (nonzero),
+ * otherwise return false (zero).
+ *
+ * @param header pointer to the header structure to be tested
+ *
+ * @retval 1 (true) if the @a header is an instance of header #xxxxxx#
+ * @retval 0 (false) otherwise
+ *
+ * @since New in #version#.
+ */
+#if SU_HAVE_INLINE
+su_inline int sip_is_#xxxxxx#(sip_header_t const *header)
+{
+ return header && header->sh_class->hc_hash == sip_#xxxxxx#_hash;
+}
+#else
+int sip_is_#xxxxxx#(sip_header_t const *header);
+#endif
+
+#define sip_#xxxxxx#_p(h) sip_is_#xxxxxx#((h))
+
+
+/**Duplicate a list of @ref sip_#xxxxxx# "#xxxxxxx_xxxxxxx#" header structures #sip_#xxxxxx#_t.
+ *
+ * Duplicate 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# = sip_#xxxxxx#_dup(home, sip->sip_#xxxxxx#);
+ *
+ * @endcode
+ *
+ * @return
+ * A pointer to the
+ * newly duplicated #sip_#xxxxxx#_t header structure, or NULL
+ * upon an error.
+ *
+ * @since New in #version#.
+ */
+#if SU_HAVE_INLINE
+su_inline
+#endif
+sip_#xxxxxx#_t *sip_#xxxxxx#_dup(su_home_t *home, sip_#xxxxxx#_t const *hdr)
+ __attribute__((__malloc__));
+
+#if SU_HAVE_INLINE
+su_inline
+sip_#xxxxxx#_t *sip_#xxxxxx#_dup(su_home_t *home, sip_#xxxxxx#_t const *hdr)
+{
+ return (sip_#xxxxxx#_t *)
+ msg_header_dup_as(home, sip_#xxxxxx#_class, (msg_header_t const *)hdr);
+}
+#endif
+
+/**Copy a list of @ref sip_#xxxxxx# "#xxxxxxx_xxxxxxx#" header structures #sip_#xxxxxx#_t.
+ *
+ * The function sip_#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 list of header
+ * structure @a hdr.
+ *
+ * @param home memory home used to allocate new structure
+ * @param hdr pointer to the header structure to be copied
+ *
+ * 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 hdr header, including the encoding of the
+ * old header, if present.
+ *
+ * @par Example
+ * @code
+ *
+ * #xxxxxx# = sip_#xxxxxx#_copy(home, sip->sip_#xxxxxx#);
+ *
+ * @endcode
+ *
+ * @return
+ * A pointer to newly copied header structure, or NULL upon an error.
+ *
+ * @since New in #version#.
+ */
+#if SU_HAVE_INLINE
+su_inline
+#endif
+sip_#xxxxxx#_t *sip_#xxxxxx#_copy(su_home_t *home, sip_#xxxxxx#_t const *hdr)
+ __attribute__((__malloc__));
+
+#if SU_HAVE_INLINE
+su_inline
+sip_#xxxxxx#_t *sip_#xxxxxx#_copy(su_home_t *home, sip_#xxxxxx#_t const *hdr)
+{
+ return (sip_#xxxxxx#_t *)
+ msg_header_copy_as(home, sip_#xxxxxx#_class, (msg_header_t const *)hdr);
+}
+#endif
+
+/**Make a @ref sip_#xxxxxx# "#xxxxxxx_xxxxxxx#" structure #sip_#xxxxxx#_t.
+ *
+ * The function sip_#xxxxxx#_make() makes a new
+ * #sip_#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
+ *
+ * @return
+ * A pointer to newly maked #sip_#xxxxxx#_t header structure, or NULL upon an
+ * error.
+ *
+ * @since New in #version#.
+ */
+#if SU_HAVE_INLINE
+su_inline
+#endif
+sip_#xxxxxx#_t *sip_#xxxxxx#_make(su_home_t *home, char const *s)
+ __attribute__((__malloc__));
+
+#if SU_HAVE_INLINE
+su_inline sip_#xxxxxx#_t *sip_#xxxxxx#_make(su_home_t *home, char const *s)
+{
+ return (sip_#xxxxxx#_t *)sip_header_make(home, sip_#xxxxxx#_class, s);
+}
+#endif
+
+/**Make a @ref sip_#xxxxxx# "#xxxxxxx_xxxxxxx#" from formatting result.
+ *
+ * Make a new #sip_#xxxxxx#_t 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 parses the
+ * formatting result to the structure #sip_#xxxxxx#_t.
+ *
+ * @param home memory home used to allocate new header structure.
+ * @param fmt string used as a printf()-style format
+ * @param ... argument list for format
+ *
+ * @return
+ * A pointer to newly
+ * makes header structure, or NULL upon an error.
+ *
+ * @HIDE
+ *
+ * @since New in #version#.
+ */
+#if SU_HAVE_INLINE
+su_inline
+#endif
+sip_#xxxxxx#_t *sip_#xxxxxx#_format(su_home_t *home, char const *fmt, ...)
+ __attribute__((__malloc__, __format__ (printf, 2, 3)));
+
+#if SU_HAVE_INLINE
+su_inline sip_#xxxxxx#_t *sip_#xxxxxx#_format(su_home_t *home, char const *fmt, ...)
+{
+ sip_header_t *h;
+ va_list ap;
+
+ va_start(ap, fmt);
+ h = sip_header_vformat(home, sip_#xxxxxx#_class, fmt, ap);
+ va_end(ap);
+
+ return (sip_#xxxxxx#_t *)h;
+}
+#endif
+
+/** @} */
+
+SOFIA_END_DECLS
+#endif /* !defined(SIP_PROTOS_H) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_status.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_status.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,245 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SIP_STATUS_H
+/** Defined when <sofia-sip/sip_status.h> has been included. */
+#define SIP_STATUS_H
+
+/**@addtogroup sip_status_codes
+ * @{
+ */
+/**@file sofia-sip/sip_status.h
+ *
+ * SIP status codes and standard phrases.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Tue Jun 6 17:43:46 2000 ppessi
+ */
+
+#include <sofia-sip/su_config.h>
+
+SOFIA_BEGIN_DECLS
+
+SOFIAPUBFUN char const *sip_status_phrase(int status);
+
+/** 100 Trying @HIDE */
+#define SIP_100_TRYING 100, sip_100_Trying
+/** 180 Ringing @HIDE */
+#define SIP_180_RINGING 180, sip_180_Ringing
+/** 181 Call Is Being Forwarded @HIDE */
+#define SIP_181_CALL_IS_BEING_FORWARDED 181, sip_181_Call_is_being_forwarded
+/** 182 Queued @HIDE */
+#define SIP_182_QUEUED 182, sip_182_Queued
+/** 183 Session Progress @HIDE */
+#define SIP_183_SESSION_PROGRESS 183, sip_183_Session_progress
+/** 200 OK @HIDE */
+#define SIP_200_OK 200, sip_200_OK
+/** 202 Accepted @HIDE */
+#define SIP_202_ACCEPTED 202, sip_202_Accepted
+/** 300 Multiple Choices @HIDE */
+#define SIP_300_MULTIPLE_CHOICES 300, sip_300_Multiple_choices
+/** 301 Moved Permanently @HIDE */
+#define SIP_301_MOVED_PERMANENTLY 301, sip_301_Moved_permanently
+/** 302 Moved Temporarily @HIDE */
+#define SIP_302_MOVED_TEMPORARILY 302, sip_302_Moved_temporarily
+/** 305 Use Proxy @HIDE */
+#define SIP_305_USE_PROXY 305, sip_305_Use_proxy
+/** 380 Alternative Service @HIDE */
+#define SIP_380_ALTERNATIVE_SERVICE 380, sip_380_Alternative_service
+/** 400 Bad Request @HIDE */
+#define SIP_400_BAD_REQUEST 400, sip_400_Bad_request
+/** 401 Unauthorized @HIDE */
+#define SIP_401_UNAUTHORIZED 401, sip_401_Unauthorized
+/** 402 Payment Required @HIDE */
+#define SIP_402_PAYMENT_REQUIRED 402, sip_402_Payment_required
+/** 403 Forbidden @HIDE */
+#define SIP_403_FORBIDDEN 403, sip_403_Forbidden
+/** 404 Not Found @HIDE */
+#define SIP_404_NOT_FOUND 404, sip_404_Not_found
+/** 405 Method Not Allowed @HIDE */
+#define SIP_405_METHOD_NOT_ALLOWED 405, sip_405_Method_not_allowed
+/** 406 Not Acceptable @HIDE */
+#define SIP_406_NOT_ACCEPTABLE 406, sip_406_Not_acceptable
+/** 407 Proxy Authentication Required @HIDE */
+#define SIP_407_PROXY_AUTH_REQUIRED 407, sip_407_Proxy_auth_required
+/** 408 Request Timeout @HIDE */
+#define SIP_408_REQUEST_TIMEOUT 408, sip_408_Request_timeout
+/** 409 Conflict @HIDE */
+#define SIP_409_CONFLICT 409, sip_409_Conflict
+/** 410 Gone @HIDE */
+#define SIP_410_GONE 410, sip_410_Gone
+/** 411 Length Required @HIDE */
+#define SIP_411_LENGTH_REQUIRED 411, sip_411_Length_required
+/** 412 Precondition Failed @HIDE */
+#define SIP_412_PRECONDITION_FAILED 412, sip_412_Precondition_failed
+/** 413 Request Entity Too Large @HIDE */
+#define SIP_413_REQUEST_TOO_LARGE 413, sip_413_Request_too_large
+/** 414 Request-URI Too Long @HIDE */
+#define SIP_414_REQUEST_URI_TOO_LONG 414, sip_414_Request_uri_too_long
+/** 415 Unsupported Media Type @HIDE */
+#define SIP_415_UNSUPPORTED_MEDIA 415, sip_415_Unsupported_media
+/** 416 Unsupported URI Scheme @HIDE */
+#define SIP_416_UNSUPPORTED_URI 416, sip_416_Unsupported_uri
+/** 417 Unknown Resource-Priority @HIDE */
+#define SIP_417_RESOURCE_PRIORITY 417, sip_417_Resource_priority
+/** 420 Bad Extension @HIDE */
+#define SIP_420_BAD_EXTENSION 420, sip_420_Bad_extension
+/** 421 Extension Required @HIDE */
+#define SIP_421_EXTENSION_REQUIRED 421, sip_421_Extension_required
+/** 422 Session Timer Too Small @HIDE */
+#define SIP_422_SESSION_TIMER_TOO_SMALL 422, sip_422_Session_timer
+/** 423 Interval Too Brief @HIDE */
+#define SIP_423_INTERVAL_TOO_BRIEF 423, sip_423_Interval_too_brief
+#define SIP_423_REGISTRATION_TOO_BRIEF 423, sip_423_Interval_too_brief
+/** 480 Temporarily Unavailable @HIDE */
+#define SIP_480_TEMPORARILY_UNAVAILABLE 480, sip_480_Temporarily_unavailable
+/** 481 Call/Transaction Does Not Exist @HIDE */
+#define SIP_481_NO_TRANSACTION 481, sip_481_No_transaction
+#define SIP_481_NO_CALL 481, sip_481_No_transaction
+/** 482 Loop Detected @HIDE */
+#define SIP_482_LOOP_DETECTED 482, sip_482_Loop_detected
+/** 483 Too Many Hops @HIDE */
+#define SIP_483_TOO_MANY_HOPS 483, sip_483_Too_many_hops
+/** 484 Address Incomplete @HIDE */
+#define SIP_484_ADDRESS_INCOMPLETE 484, sip_484_Address_incomplete
+/** 485 Ambiguous @HIDE */
+#define SIP_485_AMBIGUOUS 485, sip_485_Ambiguous
+/** 486 Busy Here @HIDE */
+#define SIP_486_BUSY_HERE 486, sip_486_Busy_here
+/** 487 Request Terminated @HIDE */
+#define SIP_487_REQUEST_TERMINATED 487, sip_487_Request_terminated
+#define SIP_487_REQUEST_CANCELLED 487, sip_487_Request_terminated
+/** 488 Not acceptable here @HIDE */
+#define SIP_488_NOT_ACCEPTABLE 488, sip_488_Not_acceptable
+/** 489 Bad Event @HIDE */
+#define SIP_489_BAD_EVENT 489, sip_489_Bad_event
+/** 490 Request Updated @HIDE */
+#define SIP_490_REQUEST_UPDATED 490, sip_490_Request_updated
+/** 491 Request Pending @HIDE */
+#define SIP_491_REQUEST_PENDING 491, sip_491_Request_pending
+/** 493 Undecipherable @HIDE */
+#define SIP_493_UNDECIPHERABLE 493, sip_493_Undecipherable
+/** 494 Security Agreement Required @HIDE */
+#define SIP_494_SECAGREE_REQUIRED 494, sip_494_Secagree_required
+
+/** 500 Internal Server Error @HIDE */
+#define SIP_500_INTERNAL_SERVER_ERROR 500, sip_500_Internal_server_error
+/** 501 Not Implemented @HIDE */
+#define SIP_501_NOT_IMPLEMENTED 501, sip_501_Not_implemented
+/** 502 Bad Gateway @HIDE */
+#define SIP_502_BAD_GATEWAY 502, sip_502_Bad_gateway
+/** 503 Service Unavailable @HIDE */
+#define SIP_503_SERVICE_UNAVAILABLE 503, sip_503_Service_unavailable
+/** 504 Gateway Time-out @HIDE */
+#define SIP_504_GATEWAY_TIME_OUT 504, sip_504_Gateway_time_out
+/** 505 Version Not Supported @HIDE */
+#define SIP_505_VERSION_NOT_SUPPORTED 505, sip_505_Version_not_supported
+/** 513 Message Too Large @HIDE */
+#define SIP_513_MESSAGE_TOO_LARGE 513, sip_513_Message_too_large
+/** 580 Precondition Failure @HIDE */
+#define SIP_580_PRECONDITION 580, sip_580_Precondition
+
+/** 600 Busy Everywhere @HIDE */
+#define SIP_600_BUSY_EVERYWHERE 600, sip_600_Busy_everywhere
+/** 603 Decline @HIDE */
+#define SIP_603_DECLINE 603, sip_603_Decline
+/** 604 Does Not Exist Anywhere @HIDE */
+#define SIP_604_DOES_NOT_EXIST_ANYWHERE 604, sip_604_Does_not_exist_anywhere
+/** 606 Not Acceptable @HIDE */
+#define SIP_606_NOT_ACCEPTABLE 606, sip_606_Not_acceptable
+/** 687 Dialog terminated @HIDE */
+#define SIP_687_DIALOG_TERMINATED 687, sip_687_Dialog_terminated
+
+SOFIAPUBVAR char const sip_100_Trying[];
+
+SOFIAPUBVAR char const sip_180_Ringing[];
+SOFIAPUBVAR char const sip_181_Call_is_being_forwarded[];
+SOFIAPUBVAR char const sip_182_Queued[];
+SOFIAPUBVAR char const sip_183_Session_progress[];
+
+SOFIAPUBVAR char const sip_200_OK[];
+SOFIAPUBVAR char const sip_202_Accepted[];
+
+SOFIAPUBVAR char const sip_300_Multiple_choices[];
+SOFIAPUBVAR char const sip_301_Moved_permanently[];
+SOFIAPUBVAR char const sip_302_Moved_temporarily[];
+SOFIAPUBVAR char const sip_305_Use_proxy[];
+SOFIAPUBVAR char const sip_380_Alternative_service[];
+
+SOFIAPUBVAR char const sip_400_Bad_request[];
+SOFIAPUBVAR char const sip_401_Unauthorized[];
+SOFIAPUBVAR char const sip_402_Payment_required[];
+SOFIAPUBVAR char const sip_403_Forbidden[];
+SOFIAPUBVAR char const sip_404_Not_found[];
+SOFIAPUBVAR char const sip_405_Method_not_allowed[];
+SOFIAPUBVAR char const sip_406_Not_acceptable[];
+SOFIAPUBVAR char const sip_407_Proxy_auth_required[];
+SOFIAPUBVAR char const sip_408_Request_timeout[];
+SOFIAPUBVAR char const sip_409_Conflict[];
+SOFIAPUBVAR char const sip_410_Gone[];
+SOFIAPUBVAR char const sip_411_Length_required[];
+SOFIAPUBVAR char const sip_412_Precondition_failed[];
+SOFIAPUBVAR char const sip_413_Request_too_large[];
+SOFIAPUBVAR char const sip_414_Request_uri_too_long[];
+SOFIAPUBVAR char const sip_415_Unsupported_media[];
+SOFIAPUBVAR char const sip_416_Unsupported_uri[];
+SOFIAPUBVAR char const sip_417_Resource_priority[];
+SOFIAPUBVAR char const sip_420_Bad_extension[];
+SOFIAPUBVAR char const sip_421_Extension_required[];
+SOFIAPUBVAR char const sip_422_Session_timer[];
+SOFIAPUBVAR char const sip_423_Interval_too_brief[];
+SOFIAPUBVAR char const sip_480_Temporarily_unavailable[];
+SOFIAPUBVAR char const sip_481_No_transaction[];
+SOFIAPUBVAR char const sip_482_Loop_detected[];
+SOFIAPUBVAR char const sip_483_Too_many_hops[];
+SOFIAPUBVAR char const sip_484_Address_incomplete[];
+SOFIAPUBVAR char const sip_485_Ambiguous[];
+SOFIAPUBVAR char const sip_486_Busy_here[];
+SOFIAPUBVAR char const sip_487_Request_terminated[];
+SOFIAPUBVAR char const sip_488_Not_acceptable[];
+SOFIAPUBVAR char const sip_489_Bad_event[];
+SOFIAPUBVAR char const sip_490_Request_updated[];
+SOFIAPUBVAR char const sip_491_Request_pending[];
+SOFIAPUBVAR char const sip_493_Undecipherable[];
+SOFIAPUBVAR char const sip_494_Secagree_required[];
+
+SOFIAPUBVAR char const sip_500_Internal_server_error[];
+SOFIAPUBVAR char const sip_501_Not_implemented[];
+SOFIAPUBVAR char const sip_502_Bad_gateway[];
+SOFIAPUBVAR char const sip_503_Service_unavailable[];
+SOFIAPUBVAR char const sip_504_Gateway_time_out[];
+SOFIAPUBVAR char const sip_505_Version_not_supported[];
+SOFIAPUBVAR char const sip_513_Message_too_large[];
+SOFIAPUBVAR char const sip_580_Precondition[];
+
+SOFIAPUBVAR char const sip_600_Busy_everywhere[];
+SOFIAPUBVAR char const sip_603_Decline[];
+SOFIAPUBVAR char const sip_604_Does_not_exist_anywhere[];
+SOFIAPUBVAR char const sip_606_Not_acceptable[];
+SOFIAPUBVAR char const sip_687_Dialog_terminated[];
+
+SOFIA_END_DECLS
+
+#endif /** @} !defined(SIP_STATUS_H) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_tag.h.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_tag.h.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1,256 @@
+/**@file sofia-sip/sip_tag.h.in
+ *
+ * Template for <sip_tag.h>.
+ *
+ * @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 at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SIP_TAG_H
+/** Defined when <sofia-sip/sip_tag.h> has been included. */
+#define SIP_TAG_H
+
+/**@file sofia-sip/sip_tag.h
+ * @brief Tag class for SIP headers
+ *
+ * #AUTO#
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ */
+
+#ifndef SU_TAG_H
+#include <sofia-sip/su_tag.h>
+#endif
+#ifndef SU_TAG_CLASS_H
+#include <sofia-sip/su_tag_class.h>
+#endif
+
+#ifndef SIP_H
+#include <sofia-sip/sip.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** Test if tag type marks a sip_t structure. @HIDE */
+#define SIPTAG_P(tt) ((tt)->tt_class == siphdrtag_class)
+/** Test if tag type marks a SIP header string. @HIDE */
+#define SIPTAG_STR_P(tt) ((tt)->tt_class == sipstrtag_class)
+/** Test if tag type marks a SIP header structure. @HIDE */
+#define SIPTAG_SIP_P(tt) ((tt)->tt_class == sipmsgtag_class)
+
+/** Test if tag item contains sip_t structure. @HIDE */
+#define SIPTAGI_P(t) (SIPTAG_P((t)->t_tag))
+/** Test if tag item contains a SIP header string. @HIDE */
+#define SIPTAGI_STR_P(t) (SIPTAG_STR_P((t)->t_tag))
+/** Test if tag item contains a SIP header structure. @HIDE */
+#define SIPTAGI_SIP_P(t) (SIPTAG_SIP_P((t)->t_tag))
+
+/** Tag class for SIP headers */
+SOFIAPUBVAR tag_class_t siphdrtag_class[1];
+/** Tag class for string values of SIP headers */
+SOFIAPUBVAR tag_class_t sipstrtag_class[1];
+/** Tag class for SIP message */
+SOFIAPUBVAR tag_class_t sipmsgtag_class[1];
+
+/** Lists of SIP tags. */
+SOFIAPUBVAR tag_type_t sip_tag_list[], sip_tag_str_list[];
+
+/** Filter tag matching any sip tag. */
+#define SIPTAG_ANY() siptag_any, ((tag_value_t)0)
+SOFIAPUBVAR tag_typedef_t siptag_any;
+
+/** End of SIP headers */
+#define SIPTAG_END() siptag_end, (tag_value_t)0
+SOFIAPUBVAR tag_typedef_t siptag_end;
+
+/**Tag list item for #sip_t object.
+ *
+ * The SIPTAG_SIP() macro is used to include a tag item for a #sip_t struct
+ * in the tag list.
+ *
+ * @param x pointer to a #sip_t message structure, or NULL.
+ *
+ * @HIDE
+ */
+#define SIPTAG_SIP(x) siptag_sip, siptag_sip_v((x))
+
+/** Tag for @c sip_t */
+SOFIAPUBVAR tag_typedef_t siptag_sip;
+
+#define SIPTAG_SIP_REF(x) siptag_sip_ref, siptag_sip_vr(&(x))
+SOFIAPUBVAR tag_typedef_t siptag_sip_ref;
+
+#if SU_HAVE_INLINE
+static inline
+tag_value_t siptag_sip_v(sip_t const *v) { return (tag_value_t)v; }
+static inline
+tag_value_t siptag_sip_vr(sip_t const **vp) { return (tag_value_t)vp; }
+#else
+#define siptag_sip_v(v) (tag_value_t)(v)
+#define siptag_sip_vr(vp) (tag_value_t)(vp)
+#endif
+
+/**Tag list item for header string.
+ *
+ * The SIPTAG_HEADER() macro is used to include a tag item containing an
+ * unknown SIP header in the tag list, e.g.,
+ * @code
+ * sip_header_t *hdr;
+ *
+ * SIPTAG_HEADER(hdr).
+ * @endcode
+ *
+ * @param x pointer to a header structure, or NULL.
+ *
+ * @HIDE
+ */
+#define SIPTAG_HEADER(x) siptag_header, siptag_header_v((x))
+
+/** Tag for header string */
+SOFIAPUBVAR tag_typedef_t siptag_header;
+
+#define SIPTAG_HEADER_REF(x) siptag_header_ref, siptag_header_vr(&(x))
+SOFIAPUBVAR tag_typedef_t siptag_header_ref;
+
+#if SU_HAVE_INLINE
+static inline tag_value_t
+siptag_header_v(sip_header_t const *v)
+{ return (tag_value_t)v; }
+static inline tag_value_t
+siptag_header_vr(sip_header_t const **vp)
+{ return (tag_value_t)vp; }
+#else
+#define siptag_header_v(v) (tag_value_t)(v)
+#define siptag_header_vr(vp) (tag_value_t)(vp)
+#endif
+
+/**Tag list item for header string.
+ *
+ * Macro is used to include a tag item containing an unknown extension
+ * header in the tag list, e.g.,
+ * @code
+ * SIPTAG_HEADER_STR("Remote-Party-ID: +358718008000")
+ * @endcode
+ *
+ * It is also possible to include multiple headers at once
+ * @code
+ * SIPTAG_HEADER_STR("P-Access-Network-Info: IEEE-802.11g;"
+ * " access-point-id=00:11:5C:34:E5:C0\r\n"
+ " "P-Visited-Network-ID: other.net\r\n")
+ * @endcode
+ *
+ * (See @RFC3455 for more information about these headers.)
+ *
+ * @param s pointer to a string, or NULL.
+ *
+ * The corresponding tag item taking reference parameter is
+ * SIPTAG_HEADER_STR_REF().
+ *
+ * @HIDE
+ */
+#define SIPTAG_HEADER_STR(s) siptag_header_str, tag_str_v((s))
+
+/** Tag for header string */
+SOFIAPUBVAR tag_typedef_t siptag_header_str;
+
+#define SIPTAG_HEADER_STR_REF(s) siptag_header_str_ref, tag_str_vr(&(s))
+SOFIAPUBVAR tag_typedef_t siptag_header_str_ref;
+
+/**@ingroup sip_#xxxxxx#
+ *
+ * Tag list item for pointer to a @ref sip_#xxxxxx# "#xxxxxxx_xxxxxxx#"
+ * structure #sip_#xxxxxx#_t.
+ *
+ * The SIPTAG_#XXXXXX#() macro is used to include a tag item with a
+ * pointer to a #sip_#xxxxxx#_t structure in a tag list.
+ *
+ * @param x pointer to a #sip_#xxxxxx#_t structure, or NULL.
+ *
+ * The corresponding tag taking reference parameter is
+ * SIPTAG_#XXXXXX#_REF().
+ *
+ * @since New in #version#.
+ *
+ * @HIDE
+ */
+#define SIPTAG_#XXXXXX#(x) siptag_#xxxxxx#, siptag_#xxxxxx#_v(x)
+
+SOFIAPUBVAR tag_typedef_t siptag_#xxxxxx#;
+
+/**@ingroup sip_#xxxxxx#
+ * Tag list item for reference to a
+ * @ref sip_#xxxxxx# "#xxxxxxx_xxxxxxx#" pointer.
+ */
+#define SIPTAG_#XXXXXX#_REF(x) siptag_#xxxxxx#_ref, siptag_#xxxxxx#_vr(&(x))
+SOFIAPUBVAR tag_typedef_t siptag_#xxxxxx#_ref;
+
+/**@ingroup sip_#xxxxxx#
+ *
+ * Tag list item for string with @ref sip_#xxxxxx# "#xxxxxxx_xxxxxxx#" value.
+ *
+ * The SIPTAG_#XXXXXX#_STR() macro is used to include a tag item with a
+ * string containing value of a #sip_#xxxxxx#_t header in a tag list.
+ *
+ * @param s pointer to a string containing
+ * @ref sip_#xxxxxx# "#xxxxxxx_xxxxxxx#" value, or NULL.
+ *
+ * The string in SIPTAG_#XXXXXX#_STR() can be converted to a
+ * #sip_#xxxxxx#_t header structure by giving the string @a s has
+ * second argument to function sip_#xxxxxx#_make().
+ *
+ * The corresponding tag taking reference parameter is
+ * SIPTAG_#XXXXXX#_STR_REF().
+ *
+ * @since New in #version#.
+ *
+ * @HIDE
+ */
+#define SIPTAG_#XXXXXX#_STR(s) siptag_#xxxxxx#_str, tag_str_v(s)
+
+SOFIAPUBVAR tag_typedef_t siptag_#xxxxxx#_str;
+
+/**@ingroup sip_#xxxxxx#
+ * Tag list item for reference to a
+ * @ref sip_#xxxxxx# "#xxxxxxx_xxxxxxx#" string.
+ */
+#define SIPTAG_#XXXXXX#_STR_REF(x) siptag_#xxxxxx#_str_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t siptag_#xxxxxx#_str_ref;
+
+#if SU_HAVE_INLINE
+static inline tag_value_t
+siptag_#xxxxxx#_v(sip_#xxxxxx#_t const *v)
+{ return (tag_value_t)v; }
+static inline tag_value_t
+siptag_#xxxxxx#_vr(sip_#xxxxxx#_t const **vp)
+{ return (tag_value_t)vp; }
+#else
+#define siptag_#xxxxxx#_v(v) (tag_value_t)(v)
+#define siptag_#xxxxxx#_vr(vp) (tag_value_t)(vp)
+#endif
+
+SOFIA_END_DECLS
+#endif
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_tag_class.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_tag_class.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,75 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SIP_TAG_CLASS_H
+/** Defined when <sip_tag_class.h> have been included */
+#define SIP_TAG_CLASS_H
+
+
+/**@SIP_TAG @{ */
+/**@file sofia-sip/sip_tag_class.h
+ *
+ * @brief Tag classes for SIP headers.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Wed Feb 21 11:01:45 2001 ppessi
+ */
+
+#ifndef SU_TAG_CLASS_H
+#include <sofia-sip/su_tag_class.h>
+#endif
+
+#ifndef MSG_TAG_CLASS_H
+#include <sofia-sip/msg_tag_class.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** Define a named tag type for SIP header @a t. */
+#define SIPHDRTAG_NAMED_TYPEDEF(n, t) \
+{{ TAG_NAMESPACE, #n, siphdrtag_class, \
+ (tag_value_t)sip_##t##_class }}
+
+/** Define a tag type for SIP header @a t. @HIDE */
+#define SIPHDRTAG_TYPEDEF(t) SIPHDRTAG_NAMED_TYPEDEF(t, t)
+
+/** Define a string tag type for SIP header @a t. @HIDE */
+#define SIPSTRTAG_TYPEDEF(t) \
+{{ TAG_NAMESPACE, #t "_str", sipstrtag_class, \
+ (tag_value_t)sip_##t##_class }}
+
+/** Define a tag type for SIP message @a t. @HIDE */
+#define SIPMSGTAG_TYPEDEF(t) \
+ {{ TAG_NAMESPACE, #t, sipmsgtag_class, \
+ (tag_value_t)SIP_PROTOCOL_TAG }}
+
+/**@internal Filter SIP header tag items. */
+SOFIAPUBFUN tagi_t *siptag_filter(tagi_t *dst, tagi_t const f[],
+ tagi_t const *src,
+ void **bb);
+
+SOFIA_END_DECLS
+
+#endif
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_util.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_util.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,215 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SIP_UTIL_H
+/** Defined when <sofia-sip/sip_util.h> has been included. */
+#define SIP_UTIL_H
+
+/**@file sofia-sip/sip_util.h
+ * @brief SIP utility functions
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Thu Jun 8 19:28:55 2000 ppessi
+ */
+
+#ifndef SIP_H
+#include <sofia-sip/sip.h>
+#endif
+
+#ifndef STRING0_H
+#include <sofia-sip/string0.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/* @deprecated
+ * These are just wrappers around msg_params_*() functions.
+ *
+ * Use msg_header_*_param() functions instead.
+ */
+SOFIAPUBFUN char const *sip_params_find(sip_param_t const pp[],
+ char const *token);
+SOFIAPUBFUN int sip_params_add(su_home_t *sh,
+ sip_param_t **pparams,
+ char const *param);
+SOFIAPUBFUN int sip_params_cmp(sip_param_t const a[], sip_param_t const b[]);
+SOFIAPUBFUN int sip_params_replace(su_home_t *,
+ sip_param_t **pparams, char const *param);
+
+SOFIAPUBFUN
+sip_contact_t *
+sip_contact_create_from_via_with_transport(su_home_t *home,
+ sip_via_t const *v,
+ char const *user,
+ char const *transport);
+
+SOFIAPUBFUN
+sip_contact_t *sip_contact_create_from_via(su_home_t *, sip_via_t const *,
+ char const *user);
+
+SOFIAPUBFUN
+char *
+sip_contact_string_from_via(su_home_t *home,
+ sip_via_t const *v,
+ char const *user,
+ char const *transport);
+
+SOFIAPUBFUN int sip_transport_has_tls(char const *transport_name);
+
+SOFIAPUBFUN int sip_response_terminates_dialog(int response_code,
+ sip_method_t method,
+ int *return_graceful_terminate);
+
+SOFIAPUBFUN int sip_sanity_check(sip_t const *sip);
+
+SOFIAPUBFUN unsigned sip_q_value(char const * q);
+
+SOFIAPUBFUN url_t *sip_url_dup(su_home_t *sh, url_t const *o);
+
+/**Add optional prefix and string to argument list if @a s is non-NULL.
+ * @HIDE
+ */
+#define SIP_STRLOG(prefix, s) ((s) ? (prefix) : ""), ((s) ? (s) : "")
+
+SOFIAPUBFUN int sip_addr_match(sip_addr_t const *a, sip_addr_t const *b);
+
+/* ----------------------------------------------------------------------
+ * Header-specific functions below
+ */
+
+SOFIAPUBFUN int sip_route_is_loose(sip_route_t const *r);
+SOFIAPUBFUN sip_route_t *sip_route_remove(msg_t *msg, sip_t *sip);
+SOFIAPUBFUN sip_route_t *sip_route_pop(msg_t *msg, sip_t *sip);
+SOFIAPUBFUN sip_route_t *sip_route_follow(msg_t *msg, sip_t *sip);
+SOFIAPUBFUN sip_route_t *sip_route_reverse(su_home_t *, sip_route_t const *);
+SOFIAPUBFUN sip_route_t *sip_route_fixdup(su_home_t *, sip_route_t const *);
+SOFIAPUBFUN sip_route_t *sip_route_fix(sip_route_t *route);
+
+SOFIAPUBFUN sip_route_t *sip_route_fixdup_as(su_home_t *,
+ msg_hclass_t *,
+ sip_route_t const *);
+SOFIAPUBFUN sip_route_t *sip_route_reverse_as(su_home_t *,
+ msg_hclass_t *,
+ sip_route_t const *);
+
+SOFIAPUBFUN sip_via_t *sip_via_remove(msg_t *msg, sip_t *sip);
+
+/* ---------------------------------------------------------------------- */
+/* Caller preferences */
+
+/** Check callerprefs. */
+SOFIAPUBFUN int sip_prefs_matching(char const *pvalue,
+ char const *nvalue,
+ int *return_parse_error);
+SOFIAPUBFUN int sip_is_callerpref(char const *param);
+
+/** Type of the SIP media tag */
+enum sp_type {
+ sp_error = -1,
+ sp_init,
+ sp_literal,
+ sp_string,
+ sp_range,
+};
+
+
+/** Possible values for SIP media tags */
+union sip_pref
+{
+ /** Type of the media tag */
+ enum sp_type sp_type;
+
+ /** Literal (tag="foo"). */
+ struct sp_literal {
+ enum sp_type spl_type;
+ char const *spl_value;
+ usize_t spl_length;
+ } sp_literal;
+
+ /** String (tag="<foo>"). */
+ struct sp_string {
+ enum sp_type sps_type;
+ char const *sps_value;
+ usize_t sps_length;
+ } sp_string;
+
+ /** Numeric value or range (tag="#=1"; tag="#<=3"; tag="#>=-2"; tag="#1:6").
+ */
+ struct sp_range {
+ enum sp_type spr_type;
+ double spr_lower;
+ double spr_upper;
+ } sp_range;
+};
+
+/** Parse a single preference */
+SOFIAPUBFUN int sip_prefs_parse(union sip_pref *sp,
+ char const **in_out_s,
+ int *return_negation);
+
+/** Match preferences */
+SOFIAPUBFUN int sip_prefs_match(union sip_pref const *, union sip_pref const *);
+
+SOFIAPUBFUN int sip_contact_is_immune(sip_contact_t const *m);
+
+/**@internal
+ * Check if contact is immune to calleprefs.
+ * @deprecated Use sip_contact_is_immune() instead.
+ */
+#define sip_contact_immune(m) sip_contact_is_immune(m)
+
+SOFIAPUBFUN sip_contact_t *sip_contact_immunize(su_home_t *home,
+ sip_contact_t const *m);
+
+SOFIAPUBFUN int sip_contact_reject(sip_contact_t const *m,
+ sip_reject_contact_t const *rc);
+
+SOFIAPUBFUN int sip_contact_accept(sip_contact_t const *m,
+ sip_accept_contact_t const *cp,
+ unsigned *return_S,
+ unsigned *return_N,
+ int *return_error);
+
+SOFIAPUBFUN int sip_contact_score(sip_contact_t const *m,
+ sip_accept_contact_t const *ac,
+ sip_reject_contact_t const *rc);
+
+
+SOFIAPUBFUN int sip_aor_strip(url_t *url);
+
+/* sec-agree utility functions. */
+
+SOFIAPUBFUN int sip_security_verify_compare(sip_security_server_t const *s,
+ sip_security_verify_t const *v,
+ char const **return_d_ver);
+
+SOFIAPUBFUN
+sip_security_client_t const *
+sip_security_client_select(sip_security_client_t const *client,
+ sip_security_server_t const *server);
+
+SOFIA_END_DECLS
+
+#endif /** !defined(SIP_UTIL_H) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own0.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own0.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,45 @@
+REGISTER sip:garage.sr.ntc.nokia.com SIP/2.0
+Via: SIP/2.0/UDP srlab.sr.ntc.nokia.com:5060;maddr=192.168.102.5
+Via: SIP/2.0/TCP srlab.sr.ntc.nokia.com:5060;maddr=192.168.102.5 (NTA 1.0)
+Via: SIP/2.0/UDP 192.2.2.1:5060;received=[ffe0::FAB1]
+Route: <sip:garage.sr.ntc.nokia.com:5060;maddr=srlab.sr.ntc.nokia.com>;foo=bar
+Record-Route: <sip:garage.sr.ntc.nokia.com:5060;maddr=srlab.sr.ntc.nokia.com>
+Hide: route
+Max-Forwards: 15
+From: sip:digest at garage.sr.ntc.nokia.com
+To: sip:digest at garage.sr.ntc.nokia.com
+Contact: sip:digest at 172.21.9.155
+Call-ID: 982773899-reg at 172.21.9.155
+CSeq: 2 REGISTER
+Subject: Barfoo
+Priority: emergency
+Date: Wed, 04 Apr 2001 17:38:38 GMT
+Retry-After: Wed, 04 Apr 2001 19:00:00 GMT (wake-up) ;duration=1800
+Timestamp: 986395257.13924321 3
+Expires: 180
+Also: sip:digestify at garage.sr.ntc.nokia.com
+Call-Info: <http://garage.sr.ntc.nokia.com/images/face.jpg>;purpose=icon
+Organization: Fuzzy Felines, Inc.
+Server: please
+User-Agent: Nokia Universal Killer Internet Application/2.0 (NUUKIA)
+In-Reply-To: 982773898-reg at 172.21.9.155
+Accept: text/plain
+Accept-Encoding: identity, deflate (???)
+Accept-Language: en
+Allow: any
+Require: all
+Proxy-Require: kinky, things
+Supported: sip-cc, sip-cc-01, timer
+Unsupported: everything
+Error-Info: <http://garage.sr.ntc.nokia.com/figure-1.jpg>
+Warning: 300 garage.sr.ntc.nokia.com IPv6 global addresses not available
+Warning: 330 garage.sr.ntc.nokia.com No IPv6 multicast, 330 garage.sr.ntc.nokia.com Only local IPv4 multicast available
+Authorization: Digest USERNAME="digest", REALM="garage.sr.ntc.nokia.com", NONCE="MjAwMS0wMS0yMSAxNTowODo1OA==", RESPONSE="d9d7f1ae99a013cb05f319f0f678251d", URI="sip:garage.sr.ntc.nokia.com"
+Via: SIP/2.0/UDP 172.21.9.155
+MIME-Version: 1.0
+Content-Type: text/plain;charset=US-ASCII
+Content-Encoding: identity
+Content-Disposition: render;handling=optional
+Content-Length: 31
+
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own1.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own1.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,18 @@
+INVITE sip:John_Smith at tct.hut.fi SIP/2.0
+To: John Smith <sip:John_Smith at tct.hut.fi:5066;user=ip;maddr=131.228.16.2>
+ ; tag = deadbeef
+From: http://www.cs.columbia.edu
+Call-ID: 0ha0isndaksdj at 10.1.2.3
+CSeq : 8 INVITE
+Via: SIP/2.0/UDP 135.180.130.133
+Content-Type: application/sdp
+Contact: Joe Bob Briggs <urn:ipaddr:122.1.2.3> ; bar="foo baa", sip:kuik at foo.invalid
+Via: SIP/2.0/UDP [aa:bb::1]:5061
+l: 138
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own2.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own2.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,12 @@
+SIP/2.0 401 Unauthorized
+Via: SIP/2.0/UDP srlab.sr.ntc.nokia.com:5060;maddr=192.168.102.5
+Via: SIP/2.0/UDP 172.21.9.155
+Record-Route: <sip:garage.sr.ntc.nokia.com:5060;maddr=srlab.sr.ntc.nokia.com>
+From: sip:digest at garage.sr.ntc.nokia.com
+To: sip:digest at garage.sr.ntc.nokia.com
+Call-ID: 982773899-reg at 172.21.9.155
+CSeq: 1 REGISTER
+WWW-Authenticate: Digest realm="garage.sr.ntc.nokia.com",
+ nonce="MjAwMS0wMS0yMSAxNTowODo1OA==", algorithm=MD5, qop="auth"
+Content-Length: 0
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own3.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own3.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,19 @@
+REGISTER sip:garage.sr.ntc.nokia.com SIP/2.0
+Via: SIP/2.0/UDP srlab.sr.ntc.nokia.com:5060;maddr=192.168.102.5
+Record-Route: <sip:garage.sr.ntc.nokia.com:5060;maddr=srlab.sr.ntc.nokia.com>
+From: sip:digest at garage.sr.ntc.nokia.com
+To: sip:digest at garage.sr.ntc.nokia.com
+Call-Id: 982773899-reg at 172.21.9.155
+Cseq: 2 REGISTER
+Contact: sip:digest at 172.21.9.155
+Expires: 180
+Content-Length: 0
+Accept-Language: en
+Supported: sip-cc, sip-cc-01, timer
+User-Agent: Pingtel/0.8.0 (WinNT)
+Authorization: DIGEST USERNAME="digest",
+ REALM="garage.sr.ntc.nokia.com", NONCE="MjAwMS0wMS0yMSAxNTowODo1OA==",
+ RESPONSE="d9d7f1ae99a013cb05f319f0f678251d",
+ URI="sip:garage.sr.ntc.nokia.com"
+Via: SIP/2.0/UDP 172.21.9.155
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own4.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own4.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,19 @@
+REGISTER sip:garage.sr.ntc.nokia.com SIP/2.0
+Via: SIP/2.0/UDP srlab.sr.ntc.nokia.com:5060;maddr=192.168.102.5
+Record-Route: <sip:garage.sr.ntc.nokia.com:5060;maddr=srlab.sr.ntc.nokia.com>
+From: sip:digest at garage.sr.ntc.nokia.com
+To: sip:digest at garage.sr.ntc.nokia.com
+Call-Id: 982773899-reg at 172.21.9.155
+Cseq: 2 REGISTER
+Contact: sip:digest at 172.21.9.155
+Expires: 180
+Content-Length: 0
+Accept-Language: en
+Supported: sip-cc, sip-cc-01, timer
+User-Agent: Pingtel/0.8.0 (WinNT)
+Authorization: Digest USERNAME="digest",
+ REALM="garage.sr.ntc.nokia.com", NONCE="MjAwMS0wMS0yMSAxNTowODo1OA==",
+ RESPONSE="d9d7f1ae99a013cb05f319f0f678251d",
+ URI="sip:garage.sr.ntc.nokia.com"
+Via: SIP/2.0/UDP 172.21.9.155
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own5.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own5.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,27 @@
+INVITE sip:bob@[3ffe:1200:3012:c006:206:5bff:fe55:462f] SIP/2.0
+Via: SIP/2.0/UDP [3ffe:1200:3012:c000:0030:e0ff:fe40:6297]:5062
+ ;branch=z9hG4bKuNCTHs8Lumv
+ ;received=3ffe:1200:3012:c006:0030:e0ff:fe40:6297
+Via: SIP/2.0/UDP [3ffe:1200:3012:c000:210:a4ff:fe8d:6a46]:5062
+ ;branch=z9hG4bKuNCTHs8Lumv
+ ;received=[3ffe:1200:3012:c006:210:a4ff:fe8d:6a46]
+From: <sip:alice@[3ffe:1200:3012:c000:210:a4ff:fe8d:6a46]>
+ ;tag=ud6a29947
+To: <sip:bob at example.com;maddr=[3ffe:1200:3012:c006:206:5bff:fe55:462f]>
+Call-ID: f89fa68e-5109-11d6-0581-0010A48D6A46
+CSeq: 2 INVITE
+Contact: <sip:[3ffe:1200:3012:c000:210:a4ff:fe8d:6a46]:5062>
+Call-Info: <http://[3ffe:1200:3012:c000:210:a4ff:fe8d:6a46]/alice.gif>
+ ;purpose=icon;g-param=[3ffe:1200:3012:c000:210:a4ff:fe8d:6a46]
+Content-Type: application/sdp
+Content-Length: 239
+
+v=0
+o=alice 1804289383 2 IN IP6 3ffe:1200:3012:c000:210:a4ff:fe8d:6a46
+s=-
+c=IN IP6 3ffe:1200:3012:c000:210:a4ff:fe8d:6a46
+t=0 0
+m=audio 5004 RTP/AVP 96 97 98
+a=rtpmap:96 AMR/8000
+a=rtpmap:97 AMR-WB/16000
+a=rtpmap:98 GSM-EFR/8000
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own6.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own6.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,17 @@
+OPTIONS sip:bob at example.com SIP/2.0
+Via: SIP/2.0/UDP 172.21.40.44;branch=z9hG4bKitIIzAialKS
+Via: SIP/2.0/UDP [3ffe:1200:3012:c000:210:a4ff:fe8d:6a46]:5062
+ ;branch=z9hG4bKJv+PsUQdfOb
+ ;received=172.21.40.24
+Record-Route: <sip:bob at example.com;maddr=172.21.40.44>
+Record-Route: <sip:bob at example.com
+ ;maddr=[3ffe:1200:3012:c000:210:a4ff:fe8d:6a46]>
+From: <sip:alice at example.com>;tag=ud6a29947
+To: <sip:bob at example.com>
+Call-ID: f3359e42-5109-11d6-998d-0010a47e1c0f
+CSeq: 1 OPTIONS
+Contact: <sip:[3ffe:1200:3012:c000:210:a4ff:fe8d:6a46]:5062>
+Content-Length: 0
+Accept:
+Allow:
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own8.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/own8.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,2 @@
+JUNK * SIP/1.0
+
\ No newline at end of file
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test-ack-1.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test-ack-1.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,8 @@
+ACK sip:company.com SIP/2.0
+To: sip:j.user at company.com
+From: sip:j.user at company.com
+Call-ID: 0ha0isndaksdj at 10.0.2.2
+Contact: sip:j.user at host.company.com
+CSeq: 8 NEWMETHOD
+Via: SIP/2.0/UDP 135.180.130.133
+Content-Length: 0
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test1.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test1.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,22 @@
+INVITE sip:vivekg at chair.dnrc.bell-labs.com SIP/2.0
+ To :
+ sip:vivekg at chair.dnrc.bell-labs.com ; tag = 1a1b1f1H33n
+From : "J Rosenberg \\\"" <sip:jdrosen at lucent.com>
+ ;
+ tag = 98asjd8
+CaLl-Id
+ : 0ha0isndaksdj at 10.1.1.1
+cseq: 8 INVITE
+Via : SIP / 2.0/ UDP
+ 135.180.130.133
+Subject :
+NewFangledHeader: newfangled value
+ more newfangled value
+Content-Type: application/sdp
+v: SIP / 2.0 / TCP 12.3.4.5 ;
+ branch = 9ikj8 ,
+ SIP / 2.0 / UDP 1.2.3.4 ; hidden
+m:"Quoted string \"\"" <sip:jdrosen at bell-labs.com> ; newparam = newvalue ;
+ secondparam = secondvalue ; q = 0.33
+ (((nested comments) and (more))) ,
+ tel:4443322
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test10.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test10.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,27 @@
+REGISTER sip:company.com SIP/2.0
+To: sip:j.user at company.com
+From: sip:j.user at company.com
+Call-ID: 0ha0isndaksdj at 10.0.2.2
+Contact: sip:j.user at host.company.com
+CSeq: 8 REGISTER
+Via: SIP/2.0/UDP 135.180.130.133
+Content-Length: 0
+
+
+
+INVITE sip:joe at company.com SIP/3.0
+To: sip:joe at company.com
+From: sip:caller at university.edu
+Call-ID: 0ha0isnda977644900765 at 10.0.0.1
+CSeq: 8 INVITE
+Via: SIP/2.0/UDP 135.180.130.133
+Content-Type: application/sdp
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC
+
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test10b.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test10b.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,8 @@
+REGISTER sip:company.com SIP/2.0
+To: sip:j.user at COMPANY.COM;maddr=135.180.130.133;tag=foo
+From: sip:j.user at COMPANY.COM;x-param-0=0;x-param-1=1;x-param-2=2;x-param-3=3;x-param-4=4;x-param-5=5;x-param-6=6;x-param-7=7;x-param-8=8
+Call-ID: 0ha0isndaksdj at 10.0.2.2
+Contact: *
+CSeq: 9 REGISTER
+Via: SIP/2.0/UDP 135.180.130.133
+Content-Length: 0
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test10c.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test10c.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,9 @@
+REGISTER sip:company.com SIP/2.0
+Via: SIP/2.0/UDP rama.research.nokia.com
+Via: SIP/2.0/UDP 135.180.130.133
+To: sip:j.user at COMPANY.COM;maddr=135.180.130.133;tag=foo
+From: sip:j.user at COMPANY.COM;tag=bar
+Call-ID: 0ha0isndaksdj at 10.0.2.2
+Contact: *
+CSeq: 9 REGISTER
+Content-Length: 0
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test11.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test11.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,11 @@
+INVITE sip:user at company.com SIP/2.0
+CSeq: 0 INVITE
+Via: SIP/2.0/UDP 135.180.130.133
+Content-Type: application/sdp
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test12.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test12.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,18 @@
+INVITE sip:user at company.com SIP/2.0
+Via: SIP/2.0/UDP 135.180.130.133
+CSeq: 0 INVITE
+Call-ID: 98asdh at 10.1.1.1
+Call-ID: 98asdh at 10.1.1.2
+From: sip:caller at university.edu
+From: sip:caller at organization.org
+To: sip:user at company.com
+Content-Type: application/sdp
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+s=My sesion
+t=2873397496 2873404696
+a=rtpmap:31 LPC
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test13.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test13.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,15 @@
+INVITE sip:user at company.com SIP/2.0
+Via: SIP/2.0/UDP 135.180.130.133
+CSeq: 0 INVITE
+Call-ID: 98asdh at 10.1.1.2
+Expires: Thu, 44 Dec 19999 16:00:00 EDT
+From: sip:caller at university.edu
+To: sip:user at company.com
+Content-Type: application/sdp
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test14-req.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test14-req.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,15 @@
+INVITE sip:user at company.com SIP/2.0
+Via: SIP/2.0/UDP 255.255.255.255;branch=0
+Via: SIP/2.0/UDP 135.180.130.57;branch=0
+Call-ID: 0384840201 at 10.1.1.1
+CSeq: 0 INVITE
+To: sip:user at company.com
+From: sip:user at university.edu;tag=2229
+Content-Type: application/sdp
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+c=IN IP4 224.2.17.12/127
+m=audio 492170 RTP/AVP 0 4 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test14.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test14.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,16 @@
+SIP/2.0 200 OK
+Via: SIP/2.0/UDP 135.180.130.57;branch=0
+Via: SIP/2.0/UDP 255.255.255.255;branch=0
+Call-ID: 0384840201 at 10.1.1.1
+CSeq: 0 INVITE
+From: sip:user at company.com
+To: sip:user at university.edu;tag=2229
+Content-Type: application/sdp
+Content-Length: 139
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+c=IN IP4 224.2.17.12/127
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test15.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test15.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,15 @@
+INVITE sip:user at company.com SIP/2.0
+To: <sip:j.user at company.com> ;tag=23444
+From: sip:caller at university.edu
+Call-ID: 0ha0isndaksdj at 10.0.0.1
+CSeq: 8 INVITE
+Via: SIP/2.0/UDP 135.180.130.133;;,;
+Contact: "" <> ;,"Joe" <sip:joe at org.org>;;,,;;
+Content-Type: application/sdp
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test16.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test16.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,15 @@
+INVITE sip:user at company.com SIP/2.0
+To: sip:j.user at company.com
+From: sip:caller at university.edu
+Call-ID: 0ha0isndaksdj at 10.0.0.1
+CSeq: 8 INVITE
+Via: SIP/2.0/UDP 135.180.130.133
+Content-Type: application/sdp
+Content-Length: 9999
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test17.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test17.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,15 @@
+INVITE sip:user at company.com SIP/2.0
+To: sip:j.user at company.com
+From: sip:caller at university.edu
+Call-ID: 0ha0isndaksdj at 10.0.0.1
+CSeq: 8 INVITE
+Via: SIP/2.0/UDP 135.180.130.133
+Content-Type: application/sdp
+Content-Length: -999
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test18.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test18.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,19 @@
+INVITE sip:user at company.com SIP/2.0
+To: sip:j.user at company.com
+From: sip:caller at university.edu
+Call-ID: 0ha0isndaksdj at 10.0.0.1
+CSeq: 8 INVITE
+Via: SIP/2.0/UDP 135.180.130.133
+Content-Type: application/sdp
+Content-Length: 138
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC
+asdpasd08asdsdk:;;asd
+ a0sdjhg8a0''...'';;;;
+
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test19.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test19.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,15 @@
+INVITE sip:user at company.com SIP/2.0
+To: "Mr. J. User <sip:j.user at company.com>
+From: sip:caller at university.edu
+Call-ID: 0ha0isndaksdj at 10.0.0.1
+CSeq: 8 INVITE
+Via: SIP/2.0/UDP 135.180.130.133:5050;branch=z9hG4bKkdjuw
+Content-Type: application/sdp
+Content-Length: 138
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test1a.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test1a.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,21 @@
+INVITE sip:vivekg at chair.dnrc.bell-labs.com SIP/2.0
+ To :
+ sip:vivekg at chair.dnrc.bell-labs.com ; tag = 1a1b1f1H33n
+From : "J Rosenberg \\\"" <sip:jdrosen at lucent.com>
+ ;
+ tag = 98asjd8
+CaLl-Id
+ : 0ha0isndaksdj at 10.1.1.1
+cseq: 8 INVITE
+Via : SIP / 2.0/ UDP
+ 135.180.130.133
+Subject :
+Content-Type: application/sdp
+
+v: SIP / 2.0 / TCP 12.3.4.5 ;
+ branch = 9ikj8 ,
+ SIP / 2.0 / UDP 1.2.3.4 ; hidden
+m:"Quoted string \"\"" <sip:jdrosen at bell-labs.com> ; newparam = newvalue ;
+ secondparam = secondvalue ; q = 0.33
+ (((nested comments) and (more))) ,
+ tel:4443322
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test2.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test2.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,10 @@
+INVITE sip:user at company.com SIP/2.0
+To: sip:j_user at company.com
+From: sip:caller at university.edu;tag=242etr
+Max-Forward: 6
+Call-ID: 0ha0isndaksdj at 10.1.1.1
+Require: newfeature1, newfeature2
+Proxy-Require: newfeature3, newfeature4
+CSeq: 8 INVITE
+Via: SIP/2.0/UDP 135.180.130.133;branch=z9hG4bKkdjuw
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test20.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test20.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,9 @@
+INVITE sip:user;par=u%40h.com at company.com SIP/2.0
+To: sip:j_user at company.com
+From: sip:caller at university.edu;tag=33242
+Max-Forwards: 3
+Call-ID: 0ha0isndaksdj at 10.1.1.1
+CSeq: 8 INVITE
+Via: SIP/2.0/UDP 135.180.130.133;branch=z9hG4bKkdjuw
+Content-Length: 0
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test21.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test21.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,17 @@
+INVITE <sip:user at company.com> SIP/2.0
+To: sip:user at company.com
+From: sip:caller at university.edu
+Call-ID: 1 at 10.0.0.1
+CSeq: 1 INVITE
+Via: SIP/2.0/UDP 135.180.130.133
+Content-Type: application/sdp
+Content-Length: 163
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+s=SIP Call
+t=0 0
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test22.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test22.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,17 @@
+INVITE sip:user at company.com; transport=udp SIP/2.0
+To: sip:user at company.com
+From: sip:caller at university.edu
+Call-ID: 2 at 10.0.0.1
+CSeq: 1 INVITE
+Via: SIP/2.0/UDP 135.180.130.133
+Content-Type: application/sdp
+Content-Length: 163
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+s=SIP Call
+t=0 0
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test23.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test23.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,17 @@
+INVITE sip:user at company.com SIP/2.0
+To: sip:user at company.com
+From: sip:caller at university.edu
+Call-ID: 3 at 10.0.0.1
+CSeq: 1 INVITE
+Via: SIP/2.0/UDP 135.180.130.133
+Content-Type: application/sdp
+Content-Length: 163
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+s=SIP Call
+t=0 0
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test24.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test24.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,17 @@
+INVITE sip:sip%3Auser%40example.com at company.com;other-param=summit SIP/2.0
+To: sip:user at company.com
+From: sip:caller at university.edu
+Call-ID: 4 at 10.0.0.1
+CSeq: 1 INVITE
+Via: SIP/2.0/UDP 135.180.130.133
+Content-Type: application/sdp
+Content-Length: 163
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+s=SIP Call
+t=0 0
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test25.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test25.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,17 @@
+INVITE sip:user at company.com?Route=%3Csip:sip.example.com%3E SIP/2.0
+To: sip:user at company.com
+From: sip:caller at university.edu
+Call-ID: 5 at 10.0.0.1
+CSeq: 1 INVITE
+Via: SIP/2.0/UDP 135.180.130.133
+Content-Type: application/sdp
+Content-Length: 163
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+s=SIP Call
+t=0 0
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test26.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test26.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,17 @@
+INVITE name:user SIP/2.0
+To: sip:user at company.com
+From: sip:caller at university.edu
+Call-ID: 6 at 10.0.0.1
+CSeq: 1 INVITE
+Via: SIP/2.0/UDP 135.180.130.133
+Content-Type: application/sdp
+Content-Length: 163
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+s=SIP Call
+t=0 0
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test27.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test27.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,8 @@
+OPTIONS sip:user at company.com SIP/2.0
+To: sip:user at company.com
+From: "caller"<sip:caller at example.com>
+Call-ID: 1234abcd at 10.0.0.1
+CSeq: 1 OPTIONS
+Via: SIP/2.0/UDP 135.180.130.133
+
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test28.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test28.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,8 @@
+OPTIONS sip:user at company.com SIP/2.0
+To: sip:user at company.com
+From: "caller" <sip:caller at example.com>
+Call-ID: 1234abcd at 10.0.0.1
+CSeq: 2 OPTIONS
+Via: SIP/2.0/UDP 135.180.130.133
+
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test29.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test29.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,18 @@
+INVITE sip:user at company.com SIP/2.0
+To: sip:user at company.com
+From: sip:caller at university.edu
+Call-ID: 7 at 10.0.0.1
+CSeq: 1 INVITE
+Via: SIP/2.0/UDP 135.180.130.133
+Expires: Fri, 01 Jan 2010 16:00:00 EST
+Content-Type: application/sdp
+Content-Length: 163
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+s=SIP Call
+t=0 0
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test3.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test3.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,16 @@
+INVITE sip:John_Smith at tct.hut.fi SIP/2.0
+To: isbn:2983792873
+From: http://www.cs.columbia.edu
+Call-ID: 0ha0isndaksdj at 10.1.2.3
+CSeq : 8 INVITE
+Via: SIP/2.0/UDP 135.180.130.133
+Content-Type: application/sdp
+Contact: Joe Bob Briggs <urn:ipaddr:122.1.2.3>
+Content-Length: 138
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test30.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test30.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,18 @@
+INVITE sip:user at company.com SIP/2.0
+To: sip:user at company.com
+From: sip:caller at university.edu
+Call-ID: 8 at 10.0.0.1
+CSeq: 1 INVITE
+Via: SIP/2.0/UDP 135.180.130.133
+Expires: Thu, 01 Dec 1994 16:00:00 GMT
+Content-Type: application/sdp
+Content-Length: 163
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+s=SIP Call
+t=0 0
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test31.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test31.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,18 @@
+INVITE sip:user at company.com SIP/2.0
+To: sip:user at company.com
+From: sip:caller at university.edu
+Call-ID: 9 at 10.0.0.1
+CSeq: 1 INVITE
+Via: SIP/2.0/UDP 135.180.130.133
+Max-Forwards: 0
+Content-Type: application/sdp
+Content-Length: 163
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+s=SIP Call
+t=0 0
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test32.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test32.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,10 @@
+REGISTER sip:company.com SIP/2.0
+To: sip:user at company.com
+From: sip:user at company.com
+Contact: sip:user at host.company.com
+Call-ID: k345asrl3fdbv at 10.0.0.1
+CSeq: 1 REGISTER
+Via: SIP/2.0/UDP 135.180.130.133
+Contact: <sip:user at example.com?Route=%3Csip:sip.example.com%3E>
+
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test33.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test33.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,10 @@
+REGISTER sip:company.com SIP/2.0
+To: sip:user at company.com
+From: sip:user at company.com
+Contact: sip:user at host.company.com
+Call-ID: k345asrl3fdbv at 10.0.0.1
+CSeq: 1 REGISTER
+Via: SIP/2.0/UDP 135.180.130.133
+Contact: sip:user at example.com?Route=%3Csip:sip.example.com%3E
+
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test34.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test34.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,52 @@
+INVITE sip:user at company.com SIP/2.0
+To: "I have a user name of extreme proportion" <sip:user at company.com:6000;other-param=1234567890somethingelselong1234567890>
+From: sip:caller at university.edu
+Call-ID: kl24ahsd546folnyt2vbak9sad98u23naodiunzds09a3bqw0sdfbsk34poouymnae0043nsed09mfkvc74bd0cuwnms05dknw87hjpobd76f
+CSeq: 1 INVITE
+My-State: sldkjflzdsfaret0803adgaasd0afds0asdaasd
+Via: SIP/2.0/UDP sip33.example.com
+Via: SIP/2.0/UDP sip32.example.com
+Via: SIP/2.0/UDP sip31.example.com
+Via: SIP/2.0/UDP sip30.example.com
+Via: SIP/2.0/UDP sip29.example.com
+Via: SIP/2.0/UDP sip28.example.com
+Via: SIP/2.0/UDP sip27.example.com
+Via: SIP/2.0/UDP sip26.example.com
+Via: SIP/2.0/UDP sip25.example.com
+Via: SIP/2.0/UDP sip24.example.com
+Via: SIP/2.0/UDP sip23.example.com
+Via: SIP/2.0/UDP sip22.example.com
+Via: SIP/2.0/UDP sip21.example.com
+Via: SIP/2.0/UDP sip20.example.com
+Via: SIP/2.0/UDP sip19.example.com
+Via: SIP/2.0/UDP sip18.example.com
+Via: SIP/2.0/UDP sip17.example.com
+Via: SIP/2.0/UDP sip16.example.com
+Via: SIP/2.0/UDP sip15.example.com
+Via: SIP/2.0/UDP sip14.example.com
+Via: SIP/2.0/UDP sip13.example.com
+Via: SIP/2.0/UDP sip12.example.com
+Via: SIP/2.0/UDP sip11.example.com
+Via: SIP/2.0/UDP sip10.example.com
+Via: SIP/2.0/UDP sip9.example.com
+Via: SIP/2.0/UDP sip8.example.com
+Via: SIP/2.0/UDP sip7.example.com
+Via: SIP/2.0/UDP sip6.example.com
+Via: SIP/2.0/UDP sip5.example.com
+Via: SIP/2.0/UDP sip4.example.com
+Via: SIP/2.0/UDP sip3.example.com
+Via: SIP/2.0/UDP sip2.example.com
+Via: SIP/2.0/UDP sip1.example.com
+Via: SIP/2.0/UDP host.example.com;received=135.180.130.133;branch=C1C3344E2710000000E299E568E7potato10potato0potato0
+Content-Type: application/sdp
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+s=SIP Call
+t=3149328700 0
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC
+
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test35.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test35.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,16 @@
+OPTIONS sip:135.180.130.133 SIP/2.0
+Via: SIP/2.0/UDP company.com:5604
+From: sip:iuser at company.com
+To: sip:user at 135.180.130.133
+Call-ID: 1804928587 at company.com
+CSeq: 1 OPTIONS
+Expires: 0 0l at company.com
+To: sip:user at 135.180.130.133
+Call-ID: 1804928587 at company.com
+CSeq: 1 OPTIONS
+Contact: sip:host.company.com
+Expires: 0xpires: 0sip:host.company.com
+Expires: 0
+Contact: sip:host.company.com
+
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test36.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test36.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,23 @@
+INVITE sip:+1-972-555-2222;phone-context=name%40domain;new=user?%22Route%3a%20X%40Y%3bZ=W%22 at gw1.wcom.com;user=phone SIP/2.0
+Via: SIP/2.0/UDP iftgw.there.com:5060
+From: sip:+1-303-555-1111 at ift.here.com;user=phone
+To: sip:+1-650-555-2222 at ss1.wcom.com;user=phone
+Call-ID: 1717 at ift.here.com
+CSeq: 56 INVITE
+Content-Type: application/sdp
+Content-Length: 348
+
+v=0
+o=faxgw1 2890844527 2890844527 IN IP4 iftgw.there.com
+s=Session SDP
+c=IN IP4 iftmg.there.com
+t=0 0
+m=image 49172 udptl t38
+a=T38FaxVersion:0
+a=T38maxBitRate:14400
+a=T38FaxFillBitRemoval:0
+a=T38FaxTranscodingMMR:0
+a=T38FaxTranscodingJBIG:0
+a=T38FaxRateManagement:transferredTCF
+a=T38FaxMaxBuffer:260
+a=T38FaxUdpEC:t38UDPRedundancy
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test37.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test37.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,9 @@
+REGISTER sip:bell-tel.com SIP/2.0
+Via: SIP/2.0/UDP saturn.bell-tel.com
+From: sip:watson at bell-tel.com
+To: sip:watson at bell-tel.com
+Call-ID: 70710 at saturn.bell-tel.com
+CSeq: 2 REGISTER
+Contact: sip:+1-972-555-2222 at gw1.wcom.com;user=phone
+
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test38.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test38.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,9 @@
+REGISTER sip:bell-tel.com SIP/2.0
+Via: SIP/2.0/UDP saturn.bell-tel.com
+From: sip:watson at bell-tel.com
+To: sip:watson at bell-tel.com
+Call-ID: 70710 at saturn.bell-tel.com
+CSeq: 3 REGISTER
+Contact: <sip:+1-972-555-2222 at gw1.wcom.com;user=phone>
+
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test39.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test39.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,8 @@
+INVITE sip:t.watson at ieee.org SIP/2.0
+Via: SIP/2.0/UDP c.bell-tel.com
+From: A. Bell <sip:a.g.bell at bell-tel.com>
+To: T. Watson <sip:t.watson at ieee.org>
+Call-ID: 31414 at c.bell-tel.com
+CSeq: 1 INVITE
+
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test4.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test4.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,9 @@
+REGISTER sip:company.com SIP/2.0
+To: sip:user at company.com
+From: sip:user at company.com
+Contact: sip:user at host.company.com
+Call-ID: 0ha0isndaksdj at 10.0.0.1
+CSeq: 8 REGISTER
+Via: SIP/2.0/UDP 135.180.130.133
+Expires: Thu, 01 Dec 2040 16:00:00 GMT
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test40.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test40.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,8 @@
+INVITE sip:t.watson at ieee.org SIP/2.0
+Via: SIP/2.0/UDP c.bell-tel.com
+From: Bell, Alexander <sip:a.g.bell at bell-tel.com>
+To: Watson, Thomas <sip:t.watson at ieee.org>
+Call-ID: 31415 at c.bell-tel.com
+CSeq: 1 INVITE
+
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test41.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test41.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,8 @@
+INVITE sip:t.watson at ieee.org SIP/7.0
+Max-Forwards: 70
+Via: SIP/2.0/UDP c.bell-tel.com
+From: A. Bell <sip:a.g.bell at bell-tel.com>
+To: T. Watson <sip:t.watson at ieee.org>
+Call-ID: 31416 at c.bell-tel.com
+CSeq: 1 INVITE
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test42.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test42.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,11 @@
+INVITE sip:t.watson at ieee.org SIP/7.0
+Via: SIP/2.0/UDP c.bell-tel.com
+From: A. Bell <sip:a.g.bell at bell-tel.com>
+To: T. Watson <sip:t.watson at ieee.org>
+Call-ID: 31417 at c.bell-tel.com
+CSeq: 1 INVITE
+
+
+
+
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test5.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test5.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,16 @@
+INVITE sip:user at company.com SIP/2.0
+To: sip:j_user at company.com
+From: sip:caller at university.edu
+Call-ID: 0ha0isndaksdj at 10.0.0.1
+Accept: text/newformat
+CSeq: 8 INVITE
+Via: SIP/2.0/UDP 135.180.130.133
+Content-Type: application/sdp
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+c=IN IP4 135.180.130.88/127
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+b=CT:3455
+a=rtpmap:31 LPC
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test6.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test6.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,12 @@
+INVITE sip:user at comapny.com SIP/2.0
+To: sip:j.user at company.com
+From: sip:caller at university.edu
+Call-ID: 0ha0isndaksdj at 10.0.0.1
+CSeq: 8 INVITE
+Via: SIP/2.0/UDP 135.180.130.133
+Content-Type: application/newformat
+Content-Length: 37
+
+<audio>
+ <pcmu port="443"/>
+</audio>
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test7.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test7.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,15 @@
+NEWMETHOD sip:user at comapny.com SIP/2.0
+To: sip:j.user at company.com
+From: sip:caller at university.edu
+Call-ID: 0ha0isndaksdj at 10.0.0.1
+CSeq: 8 NEWMETHOD
+Via: SIP/2.0/UDP 135.180.130.133
+Content-Type: application/sdp
+Content-Length: 138
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test8.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test8.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,15 @@
+NEWMETHOD sip:user at comapny.com SIP/2.0
+To: sip:j.user at company.com
+From: sip:caller at university.edu;tag=34525
+Max-Forwards: 6
+Call-ID: 0ha0isndaksdj at 10.0.1.1
+CSeq: 8 NEWMETHOD
+Via: SIP/2.0/UDP 135.180.130.133;branch=z9hG4bKkdjuw
+Content-Type: application/sdp
+
+v=0
+o=mhandley 29739 7272939 IN IP4 126.5.4.3
+c=IN IP4 135.180.130.88
+m=audio 492170 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test9.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/tests/test9.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,7 @@
+REGISTER sip:company.com SIP/2.0
+To: sip:j.user at company.com
+From: sip:j.user at company.com
+Call-ID: 0ha0isndaksdj at 10.0.1.1
+CSeq: 8 REGISTER
+Via: SIP/2.0/UDP 135.180.130.133
+Authorization: Super-PGP ajsohdaosdh0asyhdaind08yasdknasd09asidhas0d8
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/torture_sip.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/torture_sip.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,3276 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup sip_test @internal
+ *
+ * @CFILE torture_sip.c
+ *
+ * Unit-testing functions for SIP.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Tue Mar 6 18:33:42 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+/* Avoid casting sip_t to msg_pub_t and sip_header_t to msg_header_t */
+#define MSG_PUB_T struct sip_s
+#define MSG_HDR_T union sip_header_u
+
+#include <sofia-sip/su_types.h>
+
+#include <sofia-sip/su_tag.h>
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/su_tag_io.h>
+
+#include "sofia-sip/sip_parser.h"
+#include <sofia-sip/sip_util.h>
+#include <sofia-sip/sip_status.h>
+
+#include <sofia-sip/sip_tag.h>
+#include <sofia-sip/url_tag.h>
+#include <sofia-sip/msg_addr.h>
+#include <sofia-sip/msg_mclass.h>
+#include <sofia-sip/msg_mclass_hash.h>
+
+#include <sofia-sip/sip_extra.h>
+
+int tstflags;
+
+#define TSTFLAGS tstflags
+
+#include <sofia-sip/tstdef.h>
+
+char const *name = "torture_sip.c";
+
+msg_mclass_t *test_mclass = NULL;
+
+static msg_t *read_message(int flags, char const string[]);
+
+int test_url_headers(void)
+{
+ BEGIN();
+ su_home_t *home;
+ char *s, *d;
+ tagi_t *t;
+ url_t *url;
+ sip_from_t const *f;
+ sip_accept_t const *ac;
+ sip_payload_t const *body;
+
+ TEST_1(home = su_home_new(sizeof *home));
+
+ s = sip_headers_as_url_query
+ (home,
+ SIPTAG_SUBJECT_STR(";"),
+ TAG_END());
+
+ TEST_1(s);
+ TEST_S(s, "subject=;");
+
+ s = sip_headers_as_url_query
+ (home,
+ SIPTAG_TO_STR("\"Joe\" <sip:joe at example.com>;tag=foofaa"),
+ SIPTAG_SUBJECT_STR("foo"),
+ TAG_END());
+
+ TEST_1(s);
+ TEST_S(s, "to=%22Joe%22%20%3Csip%3Ajoe at example.com%3E;tag%3Dfoofaa"
+ "&subject=foo");
+
+ url = url_format(home, "sip:test at example.net?%s", s); TEST_1(url);
+
+ TEST_S(url->url_headers, s);
+
+ s = sip_headers_as_url_query
+ (home,
+ SIPTAG_FROM_STR("<sip:joe at example.com>"),
+ SIPTAG_ACCEPT_STR(""),
+ SIPTAG_PAYLOAD_STR("hello"),
+ SIPTAG_ACCEPT_STR(""),
+ TAG_END());
+
+ TEST_S(s, "from=%3Csip%3Ajoe at example.com%3E"
+ "&accept="
+ "&body=hello"
+ "&accept=");
+
+ d = url_query_as_header_string(home, s);
+ TEST_S(d, "from:<sip:joe at example.com>\n"
+ "accept:\n"
+ "accept:\n"
+ "\n"
+ "hello");
+
+ t = sip_url_query_as_taglist(home, s, NULL); TEST_1(t);
+
+ TEST_P(t[0].t_tag, siptag_from); TEST_1(f = (void *)t[0].t_value);
+ TEST_P(t[1].t_tag, siptag_accept); TEST_1(ac = (void *)t[1].t_value);
+ TEST_P(t[2].t_tag, siptag_payload); TEST_1(body = (void *)t[2].t_value);
+ TEST_P(t[3].t_tag, siptag_accept);
+
+ s = "xyzzy=foo";
+
+ t = sip_url_query_as_taglist(home, s, NULL); TEST_1(t);
+
+ TEST_P(t[0].t_tag, siptag_header_str);
+ TEST_1(d = (void *)t[0].t_value);
+ TEST_S(d, "foo");
+
+ TEST_1(!sip_headers_as_url_query(home, SIPTAG_SEPARATOR_STR(""), TAG_END()));
+
+ TEST_VOID(su_home_unref(home));
+
+ END();
+}
+
+int test_manipulation(void)
+{
+ BEGIN();
+
+ sip_content_length_t *l;
+ sip_payload_t *pl;
+ msg_t *msg, *msg0;
+ sip_t *sip;
+
+ msg0 = read_message(MSG_DO_EXTRACT_COPY,
+ "MESSAGE sip:foo at bar SIP/2.0\r\n"
+ "To: Joe User <sip:foo at bar>\r\n"
+ "From: \"Bar Owner\" <sip:bar at foo>;tag=foobar\r\n"
+ "Call-ID: 0ha0isndaksdj at 10.1.2.3\r\n"
+ "CSeq: 8 MESSAGE\r\n"
+ "Via: SIP/2.0/UDP 135.180.130.133\r\n"
+ "Content-Length: 7\r\n"
+ "Content-Type: text/plain\r\n"
+ "\r\n"
+ "Heippa!");
+ TEST_1(msg0);
+ TEST_1(msg = msg_copy(msg0));
+ TEST_1(sip = sip_object(msg));
+
+ TEST_1(l = sip_content_length_make(msg_home(msg), "6"));
+ TEST_1(pl = sip_payload_make(msg_home(msg), "hello!"));
+
+ TEST_1(msg_header_replace(msg, NULL,
+ (void *)sip->sip_content_length,
+ (void *)l) >= 0);
+ TEST_1(msg_header_replace(msg, NULL,
+ (void *)sip->sip_payload,
+ (void *)pl) >= 0);
+
+ TEST(msg_serialize(msg, NULL), 0);
+ TEST_1(msg_prepare(msg) > 0);
+
+ msg_destroy(msg);
+ msg_destroy(msg0);
+
+ END();
+}
+
+int test_methods(void)
+{
+ int i;
+ char name[32];
+
+ BEGIN();
+
+ for (i = 1; sip_method_names[i]; i++) {
+ TEST_S(sip_method_names[i], sip_method_name(i, "foo"));
+ }
+
+ {
+ char version[] = "protocol / version ";
+ char *end = version + strlen(version);
+ char *s = version;
+ char const *result = NULL;
+
+ TEST(sip_version_d(&s, &result), 0);
+ TEST_P(s, end);
+ TEST_S(result, "protocol/version");
+ }
+
+ {
+ char udp[] = "SIP/ 2.0 / udp";
+ char tcp[] = "SIP / 2.0 / tcp";
+ char tls[] = "SIP / 2.0 / tls";
+ char sctp[] = "SIP / 2.0 / scTp";
+ char dtls[] = "SIP/2.0/TLS-UDP";
+ char tls_sctp[] = "SIP/2.0/TLS-SCTP";
+ char *s, *end;
+ char const *result = NULL;
+
+ s = udp; end = s + strlen(s);
+ TEST_SIZE(sip_transport_d(&s, &result), 0); TEST_P(s, end);
+ TEST_S(result, sip_transport_udp);
+
+ s = tcp; end = s + strlen(s);
+ TEST_SIZE(sip_transport_d(&s, &result), 0); TEST_P(s, end);
+ TEST_S(result, sip_transport_tcp);
+
+ s = tls; end = s + strlen(s);
+ TEST_SIZE(sip_transport_d(&s, &result), 0); TEST_P(s, end);
+ TEST_S(result, sip_transport_tls);
+
+ s = sctp; end = s + strlen(s);
+ TEST_SIZE(sip_transport_d(&s, &result), 0); TEST_P(s, end);
+ TEST_S(result, sip_transport_sctp);
+
+ s = dtls; end = s + strlen(s);
+ TEST_SIZE(sip_transport_d(&s, &result), 0); TEST_P(s, end);
+ TEST_S(result, "SIP/2.0/TLS-UDP");
+
+ s = tls_sctp; end = s + strlen(s);
+ TEST_SIZE(sip_transport_d(&s, &result), 0); TEST_P(s, end);
+ TEST_S(result, "SIP/2.0/TLS-SCTP");
+ }
+ END();
+}
+
+/* Test <sip_basic.c> functions. */
+int test_basic(void)
+{
+ su_home_t *home = su_home_new(sizeof *home);
+
+ BEGIN();
+
+ TEST_1(home);
+
+ {
+ sip_request_t *rq, *rq1;
+
+ rq = sip_request_make(home, "INVITE sip:joe at example.com SIP/2.1");
+ TEST_1(rq);
+ TEST(rq->rq_method, sip_method_invite);
+ TEST_S(rq->rq_method_name, "INVITE");
+ TEST_1(rq1 = sip_request_dup(home, rq));
+
+ su_free(home, rq);
+ su_free(home, rq1);
+
+ rq = sip_request_make(home, "invite sip:joe at example.com SIP/2.0");
+ TEST_1(rq);
+ TEST(rq->rq_method, sip_method_unknown);
+ TEST_S(rq->rq_method_name, "invite");
+
+ TEST_1(rq1 = sip_request_dup(home, rq));
+
+ su_free(home, rq);
+ su_free(home, rq1);
+
+ TEST_1(!sip_request_create(home, sip_method_unknown, NULL,
+ (void *)"sip:joe at example.com", NULL));
+ TEST_1(rq = sip_request_create(home, sip_method_unknown, "invite",
+ (void *)"sip:joe at example.com", NULL));
+ TEST(rq->rq_method, sip_method_unknown);
+ TEST_S(rq->rq_method_name, "invite");
+ su_free(home, rq);
+
+ TEST_1(rq = sip_request_create(home, sip_method_unknown, "INVITE",
+ (void *)"sip:joe at example.com", NULL));
+ TEST(rq->rq_method, sip_method_invite);
+ TEST_S(rq->rq_method_name, "INVITE");
+
+ su_free(home, rq);
+
+ TEST_1(rq = sip_request_create(home, sip_method_invite, "foobar",
+ (void *)"sip:joe at example.com", NULL));
+ TEST(rq->rq_method, sip_method_invite);
+ TEST_S(rq->rq_method_name, "INVITE");
+
+ su_free(home, rq);
+ }
+
+ {
+ sip_status_t *st;
+
+ TEST_1(st = sip_status_make(home, "SIP/2.0 200 OK"));
+ su_free(home, st);
+
+ TEST_1(st = sip_status_make(home, "SIP/2.0 200"));
+ su_free(home, st);
+
+ TEST_1(!sip_status_make(home, "SIP2.0 200 OK"));
+ TEST_1(!sip_status_create(home, 99, NULL, "SIP/2.1"));
+ TEST_1(!sip_status_create(home, 700, NULL, "SIP/2.1"));
+ TEST_1(st = sip_status_create(home, 200, "Ok", "SIP/2.2"));
+ su_free(home, st);
+
+ TEST_1(st = sip_status_create(home, 200, NULL, "SIP/2.0"));
+ su_free(home, st);
+ TEST_1(st = sip_status_create(home, 200, NULL, NULL));
+ su_free(home, st);
+ TEST_1(st = sip_status_create(home, 699, NULL, NULL));
+ su_free(home, st);
+ }
+
+ {
+ sip_payload_t *pl;
+
+ TEST_1(pl = sip_payload_create(home, "foo", 3));
+ su_free(home, pl);
+
+ TEST_1(pl = sip_payload_create(home, NULL, 3));
+ su_free(home, pl);
+ }
+
+ {
+ sip_separator_t *sep;
+
+ TEST_1(!sip_separator_make(home, "foo"));
+ TEST_1(sep = sip_separator_create(home));
+ su_free(home, sep);
+ }
+
+
+ /* Test name-addr things */
+ {
+ su_home_t home[1] = { SU_HOME_INIT(home) };
+ char const *display;
+ url_t url[1];
+ char const * const *params;
+ char const *comment;
+ char const na[] = "Raaka Arska <tel:+358501970>;param=1;humppa (test) ";
+ char const na2[] = "tel:+358501970;param=1;humppa (test) ";
+ char *s, buf[sizeof(na)], ebuf[sizeof(na) + 32];
+
+ s = strcpy(buf, na);
+
+ TEST_1(sip_name_addr_d(home, &s, &display, url, ¶ms, &comment) >= 0);
+ TEST_P(s, buf + strlen(na));
+ TEST_1(display);
+ TEST(url->url_type, url_tel);
+ TEST_1(params);
+ TEST_1(comment);
+
+ TEST_SIZE(sip_name_addr_e(ebuf, sizeof(ebuf), 0, display, 0, url,
+ params, comment),
+ strlen(na) - 1);
+ TEST_1(strncmp(na, ebuf, strlen(na) - 1) == 0);
+
+ s = strcpy(buf, na2);
+
+ TEST_1(sip_name_addr_d(home, &s, &display, url, ¶ms, &comment) >= 0);
+ TEST_S(s, "");
+ TEST_P(s, buf + strlen(na2));
+ TEST_1(!display);
+ TEST(url->url_type, url_tel);
+ TEST_1(params);
+ TEST_1(comment);
+
+ su_home_deinit(home);
+ }
+
+ {
+ sip_from_t *f; sip_to_t *t, *t2;
+
+ TEST_1(f = sip_from_create(home, (void *)"sip:joe at bar"));
+ TEST_1(sip_from_add_param(home, f, NULL) == -1);
+ TEST_1(sip_from_add_param(home, f, "tag=tagged") == 0);
+ TEST_S(f->a_tag, "tagged");
+ TEST_1(sip_from_tag(home, f, "jxahudsf") == -1);
+ while (f->a_params && f->a_params[0])
+ msg_header_remove_param(f->a_common, f->a_params[0]);
+ TEST_P(f->a_tag, NULL);
+ TEST_1(sip_from_add_param(home, f, "test=1") == 0);
+ TEST_1(sip_from_tag(home, f, "jxahudsf") == 0);
+ TEST_S(f->a_tag, "jxahudsf");
+ su_free(home, f);
+
+ TEST_1(!sip_from_create(home, (void *)"sip:joe@[baa"));
+
+ TEST_1(f = sip_from_make(home, (void *)"sip:joe at bar (foo)"));
+ su_free(home, f);
+
+ TEST_1(f = sip_from_make(home, (void *)"<sip:joe at bar;tag=bar> (joe)"));
+ TEST_1(sip_from_tag(home, f, "tag=jxahudsf") == 0);
+ su_free(home, f);
+
+ TEST_1(t = sip_to_create(home, (void *)"<sip:joe at bar;tag=bar> (joe)"));
+ TEST_1(sip_to_tag(home, t, "tag=jxahudsf") == 0);
+ TEST_S(t->a_tag, "jxahudsf");
+ TEST(msg_header_replace_param(home, t->a_common, "tag=bar"), 1);
+ TEST_S(t->a_tag, "bar");
+
+ TEST_1(t2 = sip_to_dup(home, t));
+ TEST_S(t2->a_tag, "bar");
+
+ TEST(msg_header_remove_param(t->a_common, "tag"), 1);
+ TEST_P(t->a_tag, NULL);
+ TEST_1(sip_to_add_param(home, t, "tst=1") == 0);
+ TEST_P(t->a_tag, NULL);
+
+ su_free(home, t);
+ }
+
+ {
+ sip_call_id_t *i, *i0;
+ TEST_1(i = sip_call_id_create(home, "example.com"));
+ i->i_hash = 0;
+ TEST_1(i0 = sip_call_id_dup(home, i));
+ su_free(home, i);
+ TEST_1(i = sip_call_id_make(home, i0->i_id));
+ TEST(i->i_hash, i0->i_hash);
+ su_free(home, i);
+ su_free(home, i0);
+ }
+
+ {
+ sip_cseq_t *cs, *cs0;
+
+ TEST_1(cs = sip_cseq_create(home, 123456789, sip_method_invite, "1nvite"));
+ TEST(cs->cs_seq, 123456789);
+ TEST(cs->cs_method, sip_method_invite);
+ TEST_S(cs->cs_method_name, "INVITE");
+
+ su_free(home, cs);
+
+ TEST_1(cs = sip_cseq_create(home, 123456789, sip_method_invite, NULL));
+ TEST(cs->cs_seq, 123456789);
+ TEST(cs->cs_method, sip_method_invite);
+ TEST_S(cs->cs_method_name, "INVITE");
+ TEST_1(cs0 = sip_cseq_dup(home, cs));
+
+ su_free(home, cs);
+ su_free(home, cs0);
+
+ TEST_1(!sip_cseq_create(home, 123456789, sip_method_unknown, NULL));
+
+ TEST_1(cs = sip_cseq_create(home, 123456789, sip_method_unknown,
+ "invite"));
+ TEST(cs->cs_seq, 123456789);
+ TEST(cs->cs_method, sip_method_unknown);
+ TEST_S(cs->cs_method_name, "invite");
+ TEST_1(cs0 = sip_cseq_dup(home, cs));
+
+ su_free(home, cs);
+ su_free(home, cs0);
+ }
+
+ {
+ sip_contact_t *m, *m0;
+
+ TEST_1(!sip_contact_make(home, ",,"));
+
+ TEST_1(m = sip_contact_create(home, (void *)"sip:joe at bar",
+ "q=0.2",
+ "+message",
+ NULL));
+ TEST_S(m->m_q, "0.2");
+
+ TEST_1(m0 = sip_contact_dup(home, m));
+
+ TEST_1(sip_contact_add_param(home, m, "q=0.5") >= 0);
+ TEST_1(sip_contact_add_param(home, m, "video=FALSE") >= 0);
+ TEST_1(sip_contact_add_param(home, m, NULL) == -1);
+ TEST_1(sip_contact_add_param(home, NULL, "video=FALSE") == -1);
+ TEST_1(sip_contact_add_param(home, m, "audio=FALSE") == 0);
+ TEST_1(sip_contact_add_param(home, m, "expires=0") == 0);
+
+ TEST_S(m->m_q, "0.5");
+ TEST_S(m->m_expires, "0");
+
+ TEST_1(!sip_contact_create(home, (void *)"sip:joe@[baa",
+ "audio", "video", NULL));
+
+ TEST_1(sip_header_format(home, sip_contact_class, "*"));
+
+ su_free(home, m);
+ su_free(home, m0);
+ }
+
+ {
+ sip_via_t *v;
+ char *s;
+
+ v = sip_via_make(home, "SIP/2.0/UDP domain.invalid:5060"); TEST_1(v);
+ s = sip_contact_string_from_via(home, v, NULL, v->v_protocol);
+ TEST_S(s, "<sip:domain.invalid:5060;transport=udp>");
+ su_free(home, v), su_free(home, s);
+
+ TEST_1(sip_transport_has_tls("SIP/2.0/TLS-SCTP"));
+ TEST_1(sip_transport_has_tls("TLS-UDP"));
+
+ v = sip_via_make(home, "SIP/2.0/TLS-SCTP domain.invalid"); TEST_1(v);
+ s = sip_contact_string_from_via(home, v, NULL, v->v_protocol);
+ TEST_S(s, "<sips:domain.invalid;transport=tls-sctp>");
+ su_free(home, v), su_free(home, s);
+ }
+
+ {
+ sip_expires_t *ex;
+
+ TEST_1(!sip_expires_make(home, "-12+1"));
+
+ TEST_1(ex = sip_expires_make(home, "4294967297")); /* XXX */
+ su_free(home, ex);
+
+ TEST_1(ex = sip_expires_make(home, "Wed, 25 Mar 2004 14:49:29 GMT"));
+ su_free(home, ex);
+
+ TEST_1(ex = sip_expires_create(home, 3600));
+ su_free(home, ex);
+ }
+
+ {
+ sip_retry_after_t *ra;
+ char const *s;
+
+ TEST_1(!(ra = sip_retry_after_make(home, "50 (foo")));
+ TEST_1(ra = sip_retry_after_make(home, "50 (foo) ; duration = 13"));
+ TEST_S(ra->af_duration, "13");
+ TEST_S(ra->af_comment, "foo");
+ TEST(msg_header_remove_param(ra->af_common, "duration"), 1);
+ TEST_P(ra->af_duration, NULL);
+
+ s = sip_header_as_string(home, (void*)ra);
+ TEST_S(s, "50 (foo)");
+
+ TEST(msg_header_add_param(home, ra->af_common, "x=z"), 0);
+ s = sip_header_as_string(home, (void*)ra);
+ TEST_S(s, "50 (foo) ;x=z");
+
+ su_free(home, ra);
+ }
+
+ {
+ sip_date_t *d;
+
+ TEST_1(!(d = sip_date_make(home, "Mon, 30 Feb 1896 23:59:59 GMT")));
+ su_free(home, d);
+
+ TEST_1(d = sip_date_create(home, (1<<30)));
+ su_free(home, d);
+
+ TEST_1(d = sip_date_create(home, 0));
+ TEST_1(d->d_time != 0);
+ su_free(home, d);
+ }
+
+ {
+ sip_route_t *r, *r0;
+
+ TEST_1(!sip_route_make(home, "<sip:foo@[bar:50>;lr"));
+ TEST_1(r = sip_route_make(home, "<sip:foo@[baa::1]:5060>;lr"));
+ TEST_1(r0 = sip_route_dup(home, r));
+
+ TEST_1(sip_route_fix(r));
+ TEST_1(url_has_param(r->r_url, "lr"));
+
+ su_free(home, r);
+ TEST_1(r = sip_route_create(home, r0->r_url, r0->r_url));
+
+ su_free(home, r); su_free(home, r0);
+ }
+
+ {
+ sip_record_route_t *r, *r0;
+
+ TEST_1(!sip_record_route_make(home, "<sip:foo@[bar:50>;lr"));
+ TEST_1(!sip_record_route_make(home, "<sip:foo@[baa::1]>;lr bar, sip:foo"));
+ TEST_1(r = sip_record_route_make(home, "<sip:foo@[baa::1]:5060>;lr"));
+ TEST_1(r0 = sip_record_route_dup(home, r));
+ su_free(home, r);
+
+ TEST_1(r = sip_route_create(home, r0->r_url, r0->r_url));
+
+ su_free(home, r), su_free(home, r0);
+ }
+
+ {
+ sip_via_t *v, *v0;
+
+ TEST_1(!sip_via_make(home, ",,"));
+ TEST_1(!sip_via_make(home, "SIP// host:5060 (foo),"));
+ TEST_1(!sip_via_make(home, "SIP/2.0/TCP host:5060 (foo) bar,"));
+ TEST_1(!sip_via_make(home, "SIP/2.0/TCP [3ffe::1:5060 (foo),"));
+
+ TEST_1(v = sip_via_create(home, "bar.com",
+ "50600",
+ "SIP/2.0/UDP",
+ "hidden",
+ "rport=50601",
+ "comp=sigcomp",
+ "branch=1",
+ "q=0.2",
+ NULL));
+ TEST_S(v->v_branch, "1");
+ TEST_S(v->v_rport, "50601");
+ TEST_S(v->v_comp, "sigcomp");
+
+ TEST_1(v = sip_via_make(home, "SIP/2.0/UDP bar.com:50600"
+ " ;hidden;rport=50601;comp=sigcomp;branch=1;ttl=15"
+ " ; maddr=[::227.0.0.1]"
+ " (This is a comment) "));
+ TEST_S(v->v_ttl, "15");
+ TEST_S(v->v_maddr, "[::227.0.0.1]");
+ TEST_S(v->v_branch, "1");
+ TEST_S(v->v_rport, "50601");
+ TEST_S(v->v_comp, "sigcomp");
+
+ TEST_1(v0 = sip_via_dup(home, v));
+
+ TEST(msg_header_add_param(home, v->v_common, "rport"), 0);
+ TEST_S(v->v_rport, "");
+ TEST(msg_header_remove_param(v->v_common, "comp"), 1);
+ TEST_P(v->v_comp, NULL);
+ TEST(msg_header_remove_param(v->v_common, "ttl"), 1);
+ TEST_P(v->v_ttl, NULL);
+ TEST(msg_header_remove_param(v->v_common, "maddr"), 1);
+ TEST_P(v->v_maddr, NULL);
+ TEST(msg_header_remove_param(v->v_common, "rport"), 1);
+ TEST_P(v->v_rport, NULL);
+ TEST(msg_header_remove_param(v->v_common, "branch"), 1);
+ TEST_P(v->v_branch, NULL);
+
+ TEST_1(sip_via_add_param(home, v, "video=FALSE") == 0);
+ TEST_1(sip_via_add_param(home, v, NULL) == -1);
+ TEST_1(sip_via_add_param(home, NULL, "video=FALSE") == -1);
+ TEST_1(sip_via_add_param(home, v, "audio=FALSE") == 0);
+ TEST_1(sip_via_add_param(home, v, "branch=0") == 0);
+
+ su_free(home, v);
+ su_free(home, v0);
+
+ TEST_1(v = sip_via_create(home, "bar.com",
+ "50600",
+ NULL,
+ "rport=50601",
+ "branch=1",
+ "q=0.2",
+ NULL));
+ TEST_S(v->v_protocol, "SIP/2.0/UDP");
+ su_free(home, v);
+
+ }
+
+ {
+ sip_call_info_t *ci, *ci0;
+
+ TEST_1(ci = sip_call_info_make(home,
+ "<http://www.nokia.com>;purpose=info"));
+ TEST_S(ci->ci_purpose, "info");
+ TEST_1(ci0 = sip_call_info_dup(home, ci));
+ TEST_S(ci0->ci_purpose, "info");
+ TEST_1(ci->ci_purpose != ci0->ci_purpose);
+
+ TEST(msg_header_remove_param(ci->ci_common, "purpose"), 1);
+ TEST_P(ci->ci_purpose, NULL);
+
+ su_free(home, ci);
+ su_free(home, ci0);
+ }
+
+ su_home_check(home);
+ su_home_zap(home);
+
+ END();
+}
+
+int test_sip_msg_class(msg_mclass_t const *mc)
+{
+ int i, j, N;
+ msg_hclass_t *hc;
+
+ BEGIN();
+
+ N = mc->mc_hash_size;
+
+ /* check hashes */
+ for (i = 0; i < N; i++) {
+ if (!(hc = mc->mc_hash[i].hr_class))
+ continue;
+ for (j = i + 1; j < N; j++) {
+ if (!mc->mc_hash[j].hr_class)
+ continue;
+ if (hc->hc_hash == mc->mc_hash[j].hr_class->hc_hash) {
+ fprintf(stderr, "\t%s and %s have same hash\n",
+ hc->hc_name, mc->mc_hash[j].hr_class->hc_name);
+ return 1;
+ }
+ }
+ }
+
+ /* Check parser table sanity */
+ for (i = 0; i < N; i++) {
+ /* Verify each header entry */
+ hc = mc->mc_hash[i].hr_class;
+
+ if (hc == NULL)
+ continue;
+
+ /* Short form */
+ if (hc->hc_short[0])
+ TEST_P(mc->mc_short[hc->hc_short[0] - 'a'].hr_class, hc);
+
+ /* Long form */
+ j = msg_header_name_hash(hc->hc_name, NULL);
+ TEST(j, hc->hc_hash);
+
+ for (j = MC_HASH(hc->hc_name, N); j != i; j = (j + 1) % N)
+ TEST_1(mc->mc_hash[j].hr_class);
+
+ }
+
+ END();
+
+ return 0;
+}
+
+msg_t *read_message(int flags, char const buffer[])
+{
+ size_t n;
+ int m;
+ msg_t *msg;
+ msg_iovec_t iovec[2];
+
+ n = strlen(buffer);
+ if (n == 0)
+ return NULL;
+
+ msg = msg_create(test_mclass, flags);
+ if (msg_recv_iovec(msg, iovec, 2, n, 1) < 0) {
+ perror("msg_recv_iovec");
+ }
+ memcpy(iovec->mv_base, buffer, n);
+ msg_recv_commit(msg, n, 1);
+
+ m = msg_extract(msg);
+
+ return msg;
+}
+
+static int test_encoding(void)
+{
+ msg_header_t *h, *h1;
+ msg_common_t *c;
+ msg_t *msg;
+ sip_t *sip;
+ su_home_t *home;
+
+ BEGIN();
+
+ TEST_1(home = su_home_new(sizeof *home));
+
+ msg = read_message(MSG_DO_EXTRACT_COPY,
+ "SUBSCRIBE sip:foo at bar SIP/2.0\r\n"
+ "To: Joe User <sip:foo at bar>\r\n"
+ "From: \"Bar Owner\" <sip:bar at foo>;tag=foobar\r\n"
+ "P-Asserted-Identity: <sip:bar at foo>\r\n"
+ "P-Preferred-Identity: <sip:bar-owner at foo>\r\n"
+ "Call-ID: 0ha0isndaksdj at 10.1.2.3\r\n"
+ "CSeq: 8 SUBSCRIBE\r\n"
+ "Via: SIP/2.0/UDP 135.180.130.133\r\n"
+ "Extension-Header: extended, more\r\n"
+ "Reason: Q.850;cause=16;text=\"Terminated\"\r\n"
+ "Contact: <sip:bar at pc.foo:5060>\r\n"
+ "Date: Wed, 25 Mar 2004 14:49:29 GMT\r\n"
+ "Max-Forwards: 80\r\n"
+ "Min-Expires: 30\r\n"
+ "Retry-After: 48 (this is a comment) ;duration=321\r\n"
+ "Route: <sip:proxy.bar;maddr=172.21.40.40>\r\n"
+ "Request-Disposition: proxy\r\n"
+ "Accept-Contact: *;audio\r\n"
+ "Reject-Contact: *;video\r\n"
+ "Expires: 1200\r\n"
+ "Event: presence;id=1\r\n"
+ "In-Reply-To: {0h!a0i\"sndaksdj}@[kjsafi3], {0h!a0i\"snj}@[kjsfi3]\r\n"
+ "Organization: Nuoret Banaani-Kotkat y.r.\r\n"
+ "Priority: urgent\r\n"
+ "Subject: ynk\r\n"
+ "Timestamp: 3289129810.798259\r\n"
+ "SIP-If-Match: foobar\r\n"
+ "Proxy-Requires: prefs\r\n"
+ "Supported: vnd.nokia\r\n"
+ "User-Agent: Unknown Subscriber (1.0) Tonto (2.0)\r\n"
+ "Accept: application/pidf+xml;version=1.0\r\n"
+ "Accept-Encoding: gzip\r\n"
+ /* Test loop below cannot encode multiple Accept-Language on one line */
+ "Accept-Language: "/* "fi, "*/"en;q=0.2\r\n"
+ "RAck: 421413 214214 INVITE\r\n"
+ "Referred-By: <sips:bob at biloxi.example.com>\r\n"
+ "Replaces: 12345601 at atlanta.example.com;from-tag=314159;to-tag=1234567\r\n"
+ "Authorization: Digest realm=\"foo\"\r\n"
+ "Proxy-Authorization: Digest realm=\"foo\"\r\n"
+ "Security-Client: tls\r\n"
+ "Security-Verify: tls;q=0.2\r\n"
+ "Privacy: none\r\n"
+ "Content-Length: 7\r\n"
+ "Content-Encoding: gzip, deflate, identity\r\n"
+ "Content-Disposition: filter\r\n"
+ "Content-Language: fi\r\n"
+ "MIME-Version: 1.0\r\n"
+ "Min-SE: 123\r\n"
+ "Session-Expires: 1200\r\n"
+ "Content-Type: text/plain\r\n"
+ "Refer-Sub: true\r\n"
+ "Suppress-Body-If-Match: humppa\r\n"
+ "Suppress-Notify-If-Match: zumppa\r\n"
+ "\r\n"
+ "Heippa!");
+ sip = sip_object(msg);
+
+ TEST_1(msg); TEST_1(sip); TEST_1(!sip->sip_error);
+
+ for (h = (msg_header_t *)sip->sip_request; h; h = h->sh_succ) {
+ char b[80];
+ size_t n;
+
+ if (h == (msg_header_t*)sip->sip_payload)
+ break;
+
+ TEST_1(h1 = msg_header_dup(home, h));
+ n = msg_header_e(b, sizeof b, h1, 0);
+ TEST_SIZE(n, h->sh_len);
+ TEST_M(b, h->sh_data, n);
+ su_free(home, h1);
+ }
+
+ msg_destroy(msg), msg = NULL;
+
+ /* Note: this should be canonic! */
+ msg = read_message(MSG_DO_EXTRACT_COPY,
+ "SIP/2.0 200 Ok\r\n"
+ "To: Joe User <sip:foo at bar>;tag=deadbeef\r\n"
+ "From: sip:bar at foo;tag=foobar\r\n"
+ "Call-ID: {0h!a0i\"sndaksdj}@[kjsafi3]\r\n"
+ "CSeq: 8912734 SUBSCRIBE\r\n"
+ "Via: SIP/2.0/UDP 135.180.130.133\r\n"
+ "Extension-Header: extended, more\r\n"
+ "Reason: SIP;cause=400;text=\"Bad Message\"\r\n"
+ "Contact: <sip:bar at pc.foo:5060>;audio\r\n"
+ "Date: Wed, 25 Mar 2004 14:49:29 GMT\r\n"
+ "Max-Forwards: 80\r\n"
+ "Min-Expires: 30\r\n"
+ "Expires: Wed, 25 Mar 2004 15:49:29 GMT\r\n"
+ "Retry-After: 48;duration=321\r\n"
+ "Record-Route: <sip:record-route at proxy.bar;maddr=172.21.40.40>\r\n"
+ "Event: presence;id=1\r\n"
+ "Allow-Events: presence, presence.winfo\r\n"
+ "Subscription-State: active;expires=1800\r\n"
+ "Call-Info: <http://www.bar.com/xcap/joe/>;purpose=xcap\r\n"
+ "Error-Info: <http://www.bar.com/xcap/joe/errors>;param=xcap\r\n"
+ "Server: None\r\n"
+ "Timestamp: 3289129810.798259 0.084054\r\n"
+ "SIP-ETag: foobar\r\n"
+ "SIP-If-Match: foobar\r\n"
+ "Requires: vnd.nokia\r\n"
+ "Unsupported: vnd.nokia.pic\r\n"
+ "Accept-Disposition: filter\r\n"
+ "Warning: 399 presence.bar:5060 \"Unimplemented filter\"\r\n"
+ "RSeq: 421414\r\n"
+ "Refer-To: <sip:hsdf at cdwf.xcfw.com?Subject=test&Organization=Bar>\r\n"
+ "WWW-Authenticate: Digest realm=\"foo\"\r\n"
+ "Proxy-Authenticate: Digest realm=\"foo\"\r\n"
+ "Security-Server: tls;q=0.2\r\n"
+ "Session-Expires: 1200;refresher=uac\r\n"
+ "Content-Length: 7\r\n"
+ "Content-Type: text/plain;charset=iso8859-1\r\n"
+ "\r\n"
+ "Heippa!");
+ sip = sip_object(msg);
+
+ TEST_1(msg); TEST_1(sip); TEST_1(!sip->sip_error);
+
+ for (h = (msg_header_t *)sip->sip_status; h; h = h->sh_succ) {
+ char b[80];
+ size_t n;
+
+ if (h == (sip_header_t*)sip->sip_payload)
+ break;
+
+ TEST_1(h1 = sip_header_dup(home, h));
+ n = sip_header_e(b, sizeof b, h1, 0);
+ TEST_SIZE(n, h->sh_len);
+ TEST_M(b, h->sh_data, n);
+ su_free(home, h1);
+ }
+
+ TEST_1(sip->sip_etag);
+ TEST_S(sip->sip_etag->g_value, "foobar");
+ TEST_1(sip->sip_if_match);
+
+ msg_destroy(msg), msg = NULL;
+
+ su_home_check(home);
+ su_home_zap(home);
+
+ msg = read_message(0,
+ "SIP/2.0 200 Ok\r\n"
+ "Via: SIP/2.0/UDP 135.180.130.133\r\n"
+ "Via: SIP/2.0/UDP 135.180.130.130:5060\r\n"
+ "To: Joe User <sip:foo at bar>;tag=deadbeef\r\n"
+ "From: sip:bar at foo;tag=foobar\r\n"
+ "Call-ID: {0h!a0i\"sndaksdj}@[kjsafi3]\r\n"
+ "CSeq: 8912734 SUBSCRIBE\r\n"
+ "Record-Route: <sip:135.180.130.133;lr>\r\n"
+ "Record-Route: <sip:135.180.130.130;lr>\r\n"
+ "Content-Length: 0\r\n"
+ "\r\n");
+
+ sip = sip_object(msg);
+
+ TEST_1(msg); TEST_1(sip); TEST_1(!sip->sip_error);
+
+ sip->sip_flags |= MSG_FLG_COMPACT;
+
+ TEST_1(msg_prepare(msg) != 0);
+
+ TEST_1(c = sip->sip_status->st_common);
+ TEST_M(c->h_data, "SIP/2.0 200 Ok\r\n", c->h_len);
+
+ TEST_1(c = sip->sip_to->a_common);
+ TEST_M(c->h_data, "t:Joe User<sip:foo at bar>;tag=deadbeef\r\n", c->h_len);
+
+ TEST_1(c = sip->sip_from->a_common);
+ TEST_M(c->h_data, "f:sip:bar at foo;tag=foobar\r\n", c->h_len);
+
+ TEST_1(c = sip->sip_call_id->i_common);
+ TEST_M(c->h_data, "i:{0h!a0i\"sndaksdj}@[kjsafi3]\r\n", c->h_len);
+
+ TEST_1(c = sip->sip_cseq->cs_common);
+ TEST_M(c->h_data, "CSeq:8912734 SUBSCRIBE\r\n", c->h_len);
+
+ TEST_1(c = sip->sip_via->v_common);
+ TEST_M(c->h_data, "v:SIP/2.0/UDP 135.180.130.133,SIP/2.0/UDP 135.180.130.130:5060\r\n", c->h_len);
+
+ TEST_1(c = sip->sip_via->v_next->v_common);
+ TEST_SIZE(c->h_len, 0); TEST_1(c->h_data);
+
+ TEST_1(c = sip->sip_record_route->r_common);
+ TEST_M(c->h_data, "Record-Route:<sip:135.180.130.133;lr>,<sip:135.180.130.130;lr>\r\n", c->h_len);
+
+ TEST_1(c = sip->sip_record_route->r_next->r_common);
+ TEST_SIZE(c->h_len, 0); TEST_1(c->h_data);
+
+ TEST_1(c = sip->sip_content_length->l_common);
+ TEST_M(c->h_data, "l:0\r\n", c->h_len);
+
+ END();
+}
+
+#define XTRA(xtra, h) SU_ALIGN(xtra) + sip_header_size((sip_header_t*)h)
+
+/** Test header filtering and duplicating */
+int tag_test(void)
+{
+ su_home_t *home = su_home_new(sizeof(*home));
+ sip_request_t *request =
+ sip_request_make(home, "INVITE sip:joe at example.com SIP/2.0");
+ sip_to_t *to = sip_to_make(home,
+ "Joe User <sip:joe.user at example.com;param=1>"
+ ";tag=12345678");
+ sip_via_t *via = sip_via_make(home,
+ "SIP/2.0/UDP sip.example.com"
+ ";maddr=128.12.9.254"
+ ";branch=289412978y641.321312");
+ url_t *url = url_hdup(home,
+ (url_t *)"sip:test:pass at example.com;baz=1?foo&bar");
+
+ tagi_t *lst, *dup;
+ size_t xtra;
+ tag_value_t v;
+
+ BEGIN();
+
+ su_home_check(home);
+
+ TEST_1(home && request && to && via);
+
+ lst = tl_list(SIPTAG_REQUEST(request),
+ SIPTAG_TO(to),
+ SIPTAG_VIA(via),
+ URLTAG_URL(url),
+ TAG_NULL());
+
+ xtra = 0;
+ xtra += XTRA(xtra, request);
+ xtra += XTRA(xtra, to);
+ xtra += XTRA(xtra, via);
+ xtra += SU_ALIGN(xtra) + sizeof(*url) + url_xtra(url);
+
+ TEST_SIZE(tl_len(lst), 5 * sizeof(tagi_t));
+ TEST_SIZE(tl_xtra(lst, 0), xtra);
+
+ dup = tl_adup(NULL, lst);
+
+ TEST(dup != NULL, 1);
+ TEST_SIZE(tl_len(dup), 5 * sizeof(tagi_t));
+ TEST_SIZE(tl_xtra(dup, 0), xtra);
+
+ if (tstflags & tst_verbatim)
+ tl_print(stdout, "dup:\n", dup);
+
+ su_free(NULL, dup);
+ tl_vfree(lst);
+
+ TEST_1(t_scan(siptag_request, home, "INVITE sip:example.org SIP/2.0", &v));
+ TEST_1(request = (void *)v);
+ TEST_1(request->rq_common->h_class == sip_request_class);
+ TEST_S(request->rq_method_name, "INVITE");
+ TEST_S(request->rq_version, "SIP/2.0");
+
+ TEST_1(t_scan(siptag_to, home, "Example <sip:example.org>;tag=foo", &v));
+ TEST_1(to = (void *)v);
+ TEST_1(to->a_common->h_class == sip_to_class);
+ TEST_S(to->a_display, "Example");
+ TEST_S(to->a_tag, "foo");
+
+ su_home_check(home);
+ su_home_zap(home);
+
+ END();
+}
+
+/** Test advanced tag features */
+static int parser_tag_test(void)
+{
+ tagi_t *lst, *dup, *filter1, *filter2, *filter3, *filter4;
+ tagi_t *b1, *b2, *b3, *b4;
+
+ msg_t *msg;
+ sip_t *sip;
+ su_home_t *home;
+ size_t xtra;
+
+ BEGIN();
+
+ home = su_home_new(sizeof *home);
+
+ msg = read_message(MSG_DO_EXTRACT_COPY,
+"SIP/2.0 401 Unauthorized\r\n"
+"Via: SIP/2.0/UDP srlab.sr.ntc.nokia.com:5060;maddr=192.168.102.5\r\n"
+"Via: SIP/2.0/UDP 172.21.9.155\r\n"
+"Record-Route: <sip:garage.sr.ntc.nokia.com:5060;maddr=srlab.sr.ntc.nokia.com>\r\n"
+"From: sip:digest at garage.sr.ntc.nokia.com\r\n"
+"To: sip:digest at garage.sr.ntc.nokia.com\r\n"
+"Call-ID: 982773899-reg at 172.21.9.155\r\n"
+"CSeq: 1 REGISTER\r\n"
+"WWW-Authenticate: Digest realm=\"garage.sr.ntc.nokia.com\",\r\n"
+" nonce=\"MjAwMS0wMS0yMSAxNTowODo1OA==\", algorithm=MD5, qop=\"auth\"\r\n"
+"Proxy-Authenticate: Digest realm=\"IndigoSw\", domain=\"sip:indigosw.com\", "
+"nonce=\"V2VkIEF1ZyAxNSAxODoxMzozMiBCU1QgMjAwMVtCQDJkYjE5ZA==\", "
+"opaque=\"NzA3ZjJhYzU4MGY3MzU0MQ==\", stale=false, "
+"algorithm=md5, algorithm=sha1, qop=\"auth\"\r\n"
+/* , qop=\"auth, auth-int\"\r */
+"\r\n");
+
+ sip = sip_object(msg);
+
+ TEST_1(home && msg && sip);
+ TEST_1(sip->sip_size >= sizeof *sip);
+
+ TEST_1(sip_is_status((sip_header_t *)sip->sip_status));
+ TEST_1(sip_is_via((sip_header_t *)sip->sip_via));
+ TEST_1(sip_is_via((sip_header_t *)sip->sip_via->v_next));
+ TEST_1(sip_is_record_route((sip_header_t *)sip->sip_record_route));
+ TEST_1(sip_is_from((sip_header_t *)sip->sip_from));
+ TEST_1(sip_is_to((sip_header_t *)sip->sip_to));
+ TEST_1(sip_is_call_id((sip_header_t *)sip->sip_call_id));
+ TEST_1(sip_is_cseq((sip_header_t *)sip->sip_cseq));
+ TEST_1(sip_is_www_authenticate(
+ (sip_header_t *)sip->sip_www_authenticate));
+
+ TEST_1(sip_complete_message(msg) == 0);
+
+ TEST_1(sip_is_content_length((sip_header_t *)sip->sip_content_length));
+
+ TEST_P(sip->sip_content_length->l_common->h_succ, sip->sip_separator);
+
+ lst = tl_list(SIPTAG_VIA(sip->sip_via),
+ SIPTAG_RECORD_ROUTE(sip->sip_record_route),
+ TAG_SKIP(2),
+ SIPTAG_CSEQ(sip->sip_cseq),
+ SIPTAG_PAYLOAD(sip->sip_payload),
+ TAG_NULL());
+ filter1 = tl_list(SIPTAG_VIA(0),
+ TAG_NULL());
+ filter2 = tl_list(SIPTAG_CALL_ID(0),
+ SIPTAG_FROM(0),
+ SIPTAG_ROUTE(0),
+ SIPTAG_CSEQ(0),
+ TAG_NULL());
+ filter3 = tl_list(SIPTAG_CSEQ(0),
+ SIPTAG_CONTENT_LENGTH(0),
+ TAG_NULL());
+ filter4 = tl_list(SIPTAG_STATUS(0),
+ SIPTAG_VIA(0),
+ SIPTAG_RECORD_ROUTE(0),
+ SIPTAG_FROM(0),
+ SIPTAG_TO(0),
+ SIPTAG_CALL_ID(0),
+ SIPTAG_CSEQ(0),
+ SIPTAG_WWW_AUTHENTICATE(0),
+ SIPTAG_PROXY_AUTHENTICATE(0),
+ SIPTAG_CONTENT_LENGTH(0),
+ TAG_NULL());
+
+ TEST_1(lst && filter1 && filter2 && filter3 && filter4);
+
+ b1 = tl_afilter(home, filter1, lst);
+ TEST_SIZE(tl_len(b1), 2 * sizeof(tagi_t));
+ TEST_1(((sip_via_t *)b1->t_value)->v_next);
+ xtra = sip_header_size((sip_header_t *)sip->sip_via);
+ xtra += SU_ALIGN(xtra);
+ xtra += sip_header_size((sip_header_t *)sip->sip_via->v_next);
+ TEST_SIZE(tl_xtra(b1, 0), xtra);
+
+ dup = tl_adup(home, lst);
+
+ TEST_SIZE(tl_len(dup), tl_len(lst));
+ TEST_SIZE(tl_xtra(dup, 0), tl_xtra(lst, 0));
+
+ tl_vfree(lst);
+
+ lst = tl_list(SIPTAG_SIP(sip), TAG_NULL());
+
+ b2 = tl_afilter(home, filter2, lst);
+ TEST_SIZE(tl_len(b2), 4 * sizeof(tagi_t));
+ xtra = 0;
+ xtra += XTRA(xtra, sip->sip_call_id);
+ xtra += XTRA(xtra, sip->sip_from);
+ xtra += XTRA(xtra, sip->sip_cseq);
+ TEST_SIZE(tl_xtra(b2, 0), xtra);
+
+ b3 = tl_afilter(home, filter3, lst);
+
+ TEST_SIZE(tl_len(b3), 3 * sizeof(tagi_t));
+ TEST_SIZE(tl_xtra(b3, 0),
+ sizeof(sip_content_length_t) + sizeof(sip_cseq_t));
+
+ b4 = tl_afilter(home, filter4, lst);
+ TEST_SIZE(tl_len(b4), 11 * sizeof(tagi_t));
+ xtra = 0;
+ xtra += XTRA(xtra, sip->sip_status);
+ xtra += XTRA(xtra, sip->sip_via);
+ xtra += XTRA(xtra, sip->sip_via->v_next);
+ xtra += XTRA(xtra, sip->sip_record_route);
+ xtra += XTRA(xtra, sip->sip_from);
+ xtra += XTRA(xtra, sip->sip_to);
+ xtra += XTRA(xtra, sip->sip_call_id);
+ xtra += XTRA(xtra, sip->sip_cseq);
+ xtra += XTRA(xtra, sip->sip_www_authenticate);
+ xtra += XTRA(xtra, sip->sip_proxy_authenticate);
+ xtra += XTRA(xtra, sip->sip_content_length);
+ TEST_SIZE(tl_xtra(b4, 0), xtra);
+
+ tl_vfree(filter1); tl_vfree(filter2); tl_vfree(filter3); tl_vfree(filter4);
+ tl_vfree(lst);
+
+ su_home_check(home);
+
+ su_free(home, b4);
+ su_free(home, b3);
+ su_free(home, b2);
+ su_free(home, dup);
+ su_free(home, b1);
+
+ su_home_check(home);
+
+ su_home_unref(home);
+
+ msg_destroy(msg);
+
+ END();
+}
+
+/** Test error messages */
+static int response_phrase_test(void)
+{
+ BEGIN();
+ {
+ struct { int status; char const *phrase; } const errors[] =
+ {
+ { SIP_100_TRYING },
+ { SIP_180_RINGING },
+ { SIP_181_CALL_IS_BEING_FORWARDED },
+ { SIP_182_QUEUED },
+ { SIP_183_SESSION_PROGRESS },
+ { SIP_200_OK },
+ { SIP_202_ACCEPTED },
+ { SIP_300_MULTIPLE_CHOICES },
+ { SIP_301_MOVED_PERMANENTLY },
+ { SIP_302_MOVED_TEMPORARILY },
+ { SIP_305_USE_PROXY },
+ { SIP_380_ALTERNATIVE_SERVICE },
+ { SIP_400_BAD_REQUEST },
+ { SIP_401_UNAUTHORIZED },
+ { SIP_402_PAYMENT_REQUIRED },
+ { SIP_403_FORBIDDEN },
+ { SIP_404_NOT_FOUND },
+ { SIP_405_METHOD_NOT_ALLOWED },
+ { SIP_406_NOT_ACCEPTABLE },
+ { SIP_407_PROXY_AUTH_REQUIRED },
+ { SIP_408_REQUEST_TIMEOUT },
+ { SIP_409_CONFLICT },
+ { SIP_410_GONE },
+ { SIP_411_LENGTH_REQUIRED },
+ { SIP_413_REQUEST_TOO_LARGE },
+ { SIP_414_REQUEST_URI_TOO_LONG },
+ { SIP_415_UNSUPPORTED_MEDIA },
+ { SIP_416_UNSUPPORTED_URI },
+ { SIP_420_BAD_EXTENSION },
+ { SIP_421_EXTENSION_REQUIRED },
+ { SIP_422_SESSION_TIMER_TOO_SMALL },
+ { SIP_423_INTERVAL_TOO_BRIEF },
+ { SIP_423_REGISTRATION_TOO_BRIEF },
+ { SIP_480_TEMPORARILY_UNAVAILABLE },
+ { SIP_481_NO_TRANSACTION },
+ { SIP_481_NO_CALL },
+ { SIP_482_LOOP_DETECTED },
+ { SIP_483_TOO_MANY_HOPS },
+ { SIP_484_ADDRESS_INCOMPLETE },
+ { SIP_485_AMBIGUOUS },
+ { SIP_486_BUSY_HERE },
+ { SIP_487_REQUEST_TERMINATED },
+ { SIP_487_REQUEST_CANCELLED },
+ { SIP_488_NOT_ACCEPTABLE },
+ { SIP_489_BAD_EVENT },
+ { SIP_491_REQUEST_PENDING },
+ { SIP_493_UNDECIPHERABLE },
+ { SIP_500_INTERNAL_SERVER_ERROR },
+ { SIP_501_NOT_IMPLEMENTED },
+ { SIP_502_BAD_GATEWAY },
+ { SIP_503_SERVICE_UNAVAILABLE },
+ { SIP_504_GATEWAY_TIME_OUT },
+ { SIP_505_VERSION_NOT_SUPPORTED },
+ { SIP_513_MESSAGE_TOO_LARGE },
+ { SIP_600_BUSY_EVERYWHERE },
+ { SIP_603_DECLINE },
+ { SIP_604_DOES_NOT_EXIST_ANYWHERE },
+ { SIP_606_NOT_ACCEPTABLE },
+ { 0, NULL }
+ };
+ int i;
+
+ for (i = 0; errors[i].status; i++)
+ TEST_S(errors[i].phrase, sip_status_phrase(errors[i].status));
+ }
+ END();
+}
+
+/** Test parser and header manipulation */
+static int parser_test(void)
+{
+ msg_t *msg;
+ sip_t *sip;
+ su_home_t *home;
+
+ sip_route_t *r;
+
+ sip_request_t sip_request[1] = { SIP_REQUEST_INIT() };
+ sip_status_t sip_status[1] = { SIP_STATUS_INIT() };
+ sip_header_t sip_unknown[1] = { SIP_UNKNOWN_INIT() };
+ sip_separator_t sip_separator[1] = { SIP_SEPARATOR_INIT() };
+ sip_payload_t sip_payload[1] = { SIP_PAYLOAD_INIT() };
+ sip_via_t sip_via[1] = { SIP_VIA_INIT() };
+ sip_route_t sip_route[1] = { SIP_ROUTE_INIT() };
+ sip_record_route_t sip_record_route[1] = { SIP_RECORD_ROUTE_INIT() };
+ sip_max_forwards_t sip_max_forwards[1] = { SIP_MAX_FORWARDS_INIT() };
+ sip_from_t sip_from[1] = { SIP_FROM_INIT() };
+ sip_to_t sip_to[1] = { SIP_TO_INIT() };
+ sip_call_id_t sip_call_id[1] = { SIP_CALL_ID_INIT() };
+ sip_cseq_t sip_cseq[1] = { SIP_CSEQ_INIT() };
+ sip_contact_t sip_contact[1] = { SIP_CONTACT_INIT() };
+
+ sip_expires_t sip_expires[1] = { SIP_EXPIRES_INIT() };
+ sip_date_t sip_date[1] = { SIP_DATE_INIT() };
+ sip_retry_after_t sip_retry_after[1] = { SIP_RETRY_AFTER_INIT() };
+ sip_timestamp_t sip_timestamp[1] = { SIP_TIMESTAMP_INIT() };
+ sip_subject_t sip_subject[1] = { SIP_SUBJECT_INIT() };
+ sip_priority_t sip_priority[1] = { SIP_PRIORITY_INIT() };
+
+ sip_call_info_t sip_call_info[1] = { SIP_CALL_INFO_INIT() };
+ sip_organization_t sip_organization[1] = { SIP_ORGANIZATION_INIT() };
+ sip_server_t sip_server[1] = { SIP_SERVER_INIT() };
+ sip_user_agent_t sip_user_agent[1] = { SIP_USER_AGENT_INIT() };
+ sip_in_reply_to_t sip_in_reply_to[1] = { SIP_IN_REPLY_TO_INIT() };
+
+ sip_accept_t sip_accept[1] = { SIP_ACCEPT_INIT() };
+ sip_accept_encoding_t sip_accept_encoding[1] = { SIP_ACCEPT_ENCODING_INIT() };
+ sip_accept_language_t sip_accept_language[1] = { SIP_ACCEPT_LANGUAGE_INIT() };
+
+ sip_session_expires_t sip_session_expires[1] = { SIP_SESSION_EXPIRES_INIT() };
+ sip_min_se_t sip_min_se[1] = { SIP_MIN_SE_INIT() };
+
+ sip_allow_t sip_allow[1] = { SIP_ALLOW_INIT() };
+ sip_require_t sip_require[1] = { SIP_REQUIRE_INIT() };
+ sip_proxy_require_t sip_proxy_require[1] = { SIP_PROXY_REQUIRE_INIT() };
+ sip_supported_t sip_supported[1] = { SIP_SUPPORTED_INIT() };
+ sip_unsupported_t sip_unsupported[1] = { SIP_UNSUPPORTED_INIT() };
+#if SIP_HAVE_ENCRYPTION
+ sip_encryption_t sip_encryption[1] = { SIP_ENCRYPTION_INIT() };
+#endif
+#if SIP_HAVE_RESPONSE_KEY
+ sip_response_key_t sip_response_key[1] = { SIP_RESPONSE_KEY_INIT() };
+#endif
+
+ sip_proxy_authenticate_t sip_proxy_authenticate[1] = { SIP_PROXY_AUTHENTICATE_INIT() };
+ sip_proxy_authorization_t sip_proxy_authorization[1] = { SIP_PROXY_AUTHORIZATION_INIT() };
+ sip_authorization_t sip_authorization[1] = { SIP_AUTHORIZATION_INIT() };
+ sip_www_authenticate_t sip_www_authenticate[1] = { SIP_WWW_AUTHENTICATE_INIT() };
+ sip_error_info_t sip_error_info[1] = { SIP_ERROR_INFO_INIT() };
+ sip_warning_t sip_warning[1] = { SIP_WARNING_INIT() };
+
+ sip_mime_version_t sip_mime_version[1] = { SIP_MIME_VERSION_INIT() };
+ sip_content_type_t sip_content_type[1] = { SIP_CONTENT_TYPE_INIT() };
+ sip_content_encoding_t sip_content_encoding[1] = { SIP_CONTENT_ENCODING_INIT() };
+ sip_content_disposition_t sip_content_disposition[1] = { SIP_CONTENT_DISPOSITION_INIT() };
+ sip_content_length_t sip_content_length[1] = { SIP_CONTENT_LENGTH_INIT() };
+
+ BEGIN();
+
+ home = su_home_new(sizeof *home);
+
+ msg = read_message(MSG_DO_EXTRACT_COPY,
+ "INVITE sip:John_Smith at tct.hut.fi SIP/2.0\r\n"
+ "To: John Smith <sip:John_Smith at tct.hut.fi:5066;user=ip;maddr=131.228.16.2>\r\n"
+ " ; tag = deadbeef\r\n"
+ "From: http://www.cs.columbia.edu\r\n"
+ "Call-ID: 0ha0isndaksdj at 10.1.2.3\r\n"
+ "CSeq : 8 INVITE\r\n"
+ "Via: SIP/2.0/UDP 135.180.130.133\r\n"
+ "Route: <sip:1 at a;lr>, sip:2 at b;lr=2, <sip:3 at c;lr=3>\r\n"
+ "Route: <sip:1 at d;lr=4>\r\n"
+ "Route: sip:2 at e;lr=5, <sip:3 at f;lr=6>\r\n"
+ "Route: <sip:1 at g;lr=7>, <sip:2 at h>;lr=8\r\n"
+ "Content-Type: application/sdp\r\n"
+ "Contact: Joe Bob Briggs <urn:ipaddr:122.1.2.3> ; bar=\"foo baa\", sip:kuik at foo.invalid\r\n"
+ "Via: SIP/2.0/UDP [aa:bb::1]:5061\r\n"
+ "\r\n"
+ "v=0\r\n"
+ "o=mhandley 29739 7272939 IN IP4 126.5.4.3\r\n"
+ "c=IN IP4 135.180.130.88\r\n"
+ "m=audio 492170 RTP/AVP 0 12\r\n"
+ "m=video 3227 RTP/AVP 31\r\n"
+ "a=rtpmap:31 LPC\r\n");
+
+ sip = sip_object(msg);
+
+ TEST_1(home && msg && sip);
+
+ TEST_1(sip_is_request((sip_header_t *)sip->sip_request));
+ TEST_1(sip->sip_via); TEST_1(sip->sip_via->v_next);
+ TEST_1(sip->sip_via->v_next->v_next == NULL);
+ TEST_1(sip_sanity_check(sip) == 0);
+
+ TEST_1(r = sip->sip_route); TEST_1(r->r_common->h_data);
+ TEST_1(r = r->r_next); TEST_1(r->r_common->h_data);
+ TEST_1(r = r->r_next); TEST_1(r->r_common->h_data);
+ TEST_1(r = r->r_next); TEST_1(r->r_common->h_data);
+ TEST_1(r = r->r_next); TEST_1(r->r_common->h_data);
+ TEST_1(r = r->r_next); TEST_1(r->r_common->h_data);
+ TEST_1(r = r->r_next); TEST_1(r->r_common->h_data);
+ TEST_1(r = r->r_next); TEST_1(r->r_common->h_data);
+ TEST_1(!r->r_next);
+
+ TEST_1(r = sip_route_fix(sip->sip_route)); TEST_1(!r->r_common->h_data);
+ TEST_1(r = r->r_next); TEST_1(!r->r_common->h_data);
+ TEST_1(r = r->r_next); TEST_1(!r->r_common->h_data);
+ TEST_1(r = r->r_next); TEST_1(r->r_common->h_data);
+ TEST_1(r = r->r_next); TEST_1(!r->r_common->h_data);
+ TEST_1(r = r->r_next); TEST_1(!r->r_common->h_data);
+ TEST_1(r = r->r_next); TEST_1(!r->r_common->h_data);
+ TEST_1(r = r->r_next); TEST_1(!r->r_common->h_data);
+ TEST_1(!r->r_next);
+
+ /* Quiet lots of warnings */
+ #define _msg_header_offset msg_header_offset
+ #define msg_header_offset(msg, sip, h) \
+ _msg_header_offset(msg, (msg_pub_t *)sip, (msg_header_t *)h)
+
+ TEST_P(msg_header_offset(msg, sip, sip_request), &sip->sip_request);
+ TEST_P(msg_header_offset(msg, sip, sip_status), &sip->sip_status);
+ TEST_P(msg_header_offset(msg, sip, sip_unknown), &sip->sip_unknown);
+ TEST_P(msg_header_offset(msg, sip, sip_separator), &sip->sip_separator);
+ TEST_P(msg_header_offset(msg, sip, sip_payload), &sip->sip_payload);
+ TEST_P(msg_header_offset(msg, sip, sip_via), &sip->sip_via);
+ TEST_P(msg_header_offset(msg, sip, sip_route), &sip->sip_route);
+ TEST_P(msg_header_offset(msg, sip, sip_record_route),
+ &sip->sip_record_route);
+ TEST_P(msg_header_offset(msg, sip, sip_max_forwards),
+ &sip->sip_max_forwards);
+ TEST_P(msg_header_offset(msg, sip, sip_from), &sip->sip_from);
+ TEST_P(msg_header_offset(msg, sip, sip_to), &sip->sip_to);
+ TEST_P(msg_header_offset(msg, sip, sip_call_id), &sip->sip_call_id);
+ TEST_P(msg_header_offset(msg, sip, sip_cseq), &sip->sip_cseq);
+ TEST_P(msg_header_offset(msg, sip, sip_contact), &sip->sip_contact);
+
+ TEST_P(msg_header_offset(msg, sip, sip_expires), &sip->sip_expires);
+ TEST_P(msg_header_offset(msg, sip, sip_date), &sip->sip_date);
+ TEST_P(msg_header_offset(msg, sip, sip_retry_after), &sip->sip_retry_after);
+ TEST_P(msg_header_offset(msg, sip, sip_timestamp), &sip->sip_timestamp);
+ TEST_P(msg_header_offset(msg, sip, sip_subject), &sip->sip_subject);
+ TEST_P(msg_header_offset(msg, sip, sip_priority), &sip->sip_priority);
+
+ TEST_P(msg_header_offset(msg, sip, sip_call_info), &sip->sip_call_info);
+ TEST_P(msg_header_offset(msg, sip, sip_organization),
+ &sip->sip_organization);
+ TEST_P(msg_header_offset(msg, sip, sip_server), &sip->sip_server);
+ TEST_P(msg_header_offset(msg, sip, sip_user_agent), &sip->sip_user_agent);
+ TEST_P(msg_header_offset(msg, sip, sip_in_reply_to), &sip->sip_in_reply_to);
+
+ TEST_P(msg_header_offset(msg, sip, sip_accept), &sip->sip_accept);
+ TEST_P(msg_header_offset(msg, sip, sip_accept_encoding),
+ &sip->sip_accept_encoding);
+ TEST_P(msg_header_offset(msg, sip, sip_accept_language),
+ &sip->sip_accept_language);
+
+ TEST_P(msg_header_offset(msg, sip, sip_session_expires),
+ &sip->sip_session_expires);
+ TEST_P(msg_header_offset(msg, sip, sip_min_se), &sip->sip_min_se);
+
+ TEST_P(msg_header_offset(msg, sip, sip_allow), &sip->sip_allow);
+ TEST_P(msg_header_offset(msg, sip, sip_require), &sip->sip_require);
+ TEST_P(msg_header_offset(msg, sip, sip_proxy_require),
+ &sip->sip_proxy_require);
+ TEST_P(msg_header_offset(msg, sip, sip_supported), &sip->sip_supported);
+ TEST_P(msg_header_offset(msg, sip, sip_unsupported), &sip->sip_unsupported);
+#if SIP_HAVE_ENCRYPTION
+ TEST(msg_header_offset(msg, sip, sip_encryption), &sip->sip_encryption);
+#endif
+#if SIP_HAVE_RESPONSE_KEY
+ TEST(msg_header_offset(msg, sip, sip_response_key), &sip->sip_response_key);
+#endif
+
+ TEST_P(msg_header_offset(msg, sip, sip_proxy_authenticate),
+ &sip->sip_proxy_authenticate);
+ TEST_P(msg_header_offset(msg, sip, sip_proxy_authorization),
+ &sip->sip_proxy_authorization);
+ TEST_P(msg_header_offset(msg, sip, sip_authorization),
+ &sip->sip_authorization);
+ TEST_P(msg_header_offset(msg, sip, sip_www_authenticate),
+ &sip->sip_www_authenticate);
+ TEST_P(msg_header_offset(msg, sip, sip_error_info), &sip->sip_error_info);
+ TEST_P(msg_header_offset(msg, sip, sip_warning), &sip->sip_warning);
+
+ TEST_P(msg_header_offset(msg, sip, sip_mime_version), &sip->sip_mime_version);
+ TEST_P(msg_header_offset(msg, sip, sip_content_type), &sip->sip_content_type);
+ TEST_P(msg_header_offset(msg, sip, sip_content_encoding),
+ &sip->sip_content_encoding);
+ TEST_P(msg_header_offset(msg, sip, sip_content_disposition),
+ &sip->sip_content_disposition);
+ TEST_P(msg_header_offset(msg, sip, sip_content_length),
+ &sip->sip_content_length);
+
+ TEST_SIZE(sip_request_class->hc_params, 0);
+ TEST_SIZE(sip_status_class->hc_params, 0);
+ TEST_SIZE(sip_unknown_class->hc_params, 0);
+ TEST_SIZE(sip_separator_class->hc_params, 0);
+ TEST_SIZE(sip_payload_class->hc_params, 0);
+ TEST_SIZE(sip_via_class->hc_params, offsetof(sip_via_t, v_params));
+ TEST_SIZE(sip_route_class->hc_params, offsetof(sip_route_t, r_params));
+ TEST_SIZE(sip_record_route_class->hc_params,
+ offsetof(sip_record_route_t, r_params));
+
+ TEST_SIZE(sip_max_forwards_class->hc_params, 0);
+ TEST_SIZE(sip_from_class->hc_params, offsetof(sip_from_t, a_params));
+ TEST_SIZE(sip_to_class->hc_params, offsetof(sip_to_t, a_params));
+ TEST_SIZE(sip_call_id_class->hc_params, 0);
+ TEST_SIZE(sip_cseq_class->hc_params, 0);
+ TEST_SIZE(sip_contact_class->hc_params, offsetof(sip_contact_t, m_params));
+
+ TEST_SIZE(sip_expires_class->hc_params, 0);
+ TEST_SIZE(sip_date_class->hc_params, 0);
+ TEST_SIZE(sip_retry_after_class->hc_params,
+ offsetof(sip_retry_after_t, af_params));
+ TEST_SIZE(sip_timestamp_class->hc_params, 0);
+ TEST_SIZE(sip_subject_class->hc_params, 0);
+ TEST_SIZE(sip_priority_class->hc_params, 0);
+
+ TEST_SIZE(sip_call_info_class->hc_params,
+ offsetof(sip_call_info_t, ci_params));
+ TEST_SIZE(sip_organization_class->hc_params, 0);
+ TEST_SIZE(sip_server_class->hc_params, 0);
+ TEST_SIZE(sip_user_agent_class->hc_params, 0);
+
+ TEST_SIZE(sip_in_reply_to_class->hc_params,
+ offsetof(sip_in_reply_to_t, k_items));
+ TEST_SIZE(sip_accept_class->hc_params, offsetof(sip_accept_t, ac_params));
+ TEST_SIZE(sip_accept_encoding_class->hc_params,
+ offsetof(sip_accept_encoding_t, aa_params));
+ TEST_SIZE(sip_accept_language_class->hc_params,
+ offsetof(sip_accept_language_t, aa_params));
+
+ TEST_SIZE(sip_session_expires_class->hc_params,
+ offsetof(sip_session_expires_t, x_params));
+ TEST_SIZE(sip_min_se_class->hc_params, offsetof(sip_min_se_t, min_params));
+
+ TEST_SIZE(sip_allow_class->hc_params, offsetof(sip_allow_t, k_items));
+ TEST_SIZE(sip_require_class->hc_params, offsetof(sip_require_t, k_items));
+ TEST_SIZE(sip_proxy_require_class->hc_params,
+ offsetof(sip_proxy_require_t, k_items));
+ TEST_SIZE(sip_supported_class->hc_params,
+ offsetof(sip_supported_t, k_items));
+ TEST_SIZE(sip_unsupported_class->hc_params,
+ offsetof(sip_unsupported_t, k_items));
+
+#if SIP_HAVE_ENCRYPTION
+ TEST_SIZE(sip_encryption_class->hc_params,
+ offsetof(sip_encryption_t, au_params));
+#endif
+#if SIP_HAVE_RESPONSE_KEY
+ TEST_SIZE(sip_response_key_class->hc_params,
+ offsetof(sip_response_key_t, au_params));
+#endif
+ TEST_SIZE(sip_proxy_authenticate_class->hc_params,
+ offsetof(sip_proxy_authenticate_t, au_params));
+ TEST_SIZE(sip_proxy_authorization_class->hc_params,
+ offsetof(sip_proxy_authorization_t, au_params));
+ TEST_SIZE(sip_authorization_class->hc_params,
+ offsetof(sip_authorization_t, au_params));
+ TEST_SIZE(sip_www_authenticate_class->hc_params,
+ offsetof(sip_www_authenticate_t, au_params));
+
+ TEST_SIZE(sip_error_info_class->hc_params,
+ offsetof(sip_error_info_t, ei_params));
+ TEST_SIZE(sip_warning_class->hc_params, 0);
+
+ TEST_SIZE(sip_mime_version_class->hc_params, 0);
+ TEST_SIZE(sip_content_type_class->hc_params,
+ offsetof(sip_content_type_t, c_params));
+ TEST_SIZE(sip_content_encoding_class->hc_params,
+ offsetof(sip_content_encoding_t, k_items));
+ TEST_SIZE(sip_content_disposition_class->hc_params,
+ offsetof(sip_content_disposition_t, cd_params));
+ TEST_SIZE(sip_content_length_class->hc_params, 0);
+
+ msg_destroy(msg);
+
+ su_home_unref(home);
+
+ END();
+}
+
+static int count(sip_common_t *h)
+{
+ sip_header_t *sh = (sip_header_t *)h;
+ unsigned n;
+
+ for (n = 0; sh; sh = sh->sh_next)
+ n++;
+
+ return n;
+}
+
+static int len(sip_common_t *h)
+{
+ sip_header_t *sh = (sip_header_t *)h;
+ unsigned n;
+
+ for (n = 0; sh; sh = sh->sh_next) {
+ if (n) n +=2;
+ n += sip_header_field_e(NULL, 0, sh, 0);
+ }
+
+ return n;
+}
+
+static int sip_header_test(void)
+{
+ msg_t *msg;
+ sip_t *sip;
+ su_home_t *home;
+ void const *x;
+ sip_via_t *v, *v0;
+ tagi_t const *tl;
+ tagi_t *tl0;
+
+ BEGIN();
+
+ home = su_home_new(sizeof *home);
+
+ TEST_1(msg = read_message(MSG_DO_EXTRACT_COPY,
+ "MESSAGE sip:John_Smith at tct.hut.fi SIP/2.0\r\n"
+ "To: John Smith <sip:John_Smith at tct.hut.fi:5066;user=ip;maddr=131.228.16.2>\r\n"
+ " ; tag = deadbeef\r\n"
+ "From:h<http://www.cs.columbia.edu>\r\n"
+ "Call-ID: 0ha0isndaksdj at 10.1.2.3\r\n"
+ "CSeq : 8 MESSAGE\r\n"
+ "Via: SIP/2.0/UDP 135.180.130.133;received=defa:daf::00:12\r\n"
+ "Via: SIP/2.0/TCP 135.180.130.131;branch=deadbeef.barf;ttl=3;hidden,,"
+ "SIP/2.0/UDP\r\n 135.180.130.131:5061;received=[defa::00:12]\r\n"
+ "Contact: Joe Bob Briggs <urn:ipaddr:122.1.2.3> ; bar=\042foo baa\042, <sip:kuik at foo.invalid>, sip:barf\r\n"
+ "Via: SIP/2.0/UDP [aa:bb::1]:5061\r\n"
+ "Record-Route: Test Element <sip:[defa::00:12]:5061>;param=12+1\r\n"
+ "Record-Route: sip:135.180.130.133,<sip:135.180.130.131;transport=tcp>,\r\n"
+ "\t,Test Element <sip:[defa::00:12]:5061>;param=12+1\r\n"
+ "Path: Test <sip:[defa::00:12]:5061>\r\n"
+ "Service-Route: Test <sip:[defa::00:12]:5061>\r\n"
+ "Route: ,\r\n"
+ "Unknown-Extension: hip\r\n"
+ "Hide: hop\r\n"
+ "Max-Forwards: 12\r\n"
+ "Min-Expires: 150\r\n"
+ "Timestamp: 10.010 0.000100\r\n"
+ "Suppress-Body-If-Match: humppa \t\r\n"
+ "Suppress-Notify-If-Match: zumppa\r\n"
+ " \r\n"
+ "Content-Type: application/sdp\r\n"
+ "\r\n"
+ "v=0\r\n"
+ "o=mhandley 29739 7272939 IN IP4 126.5.4.3\r\n"
+ "c=IN IP4 135.180.130.88\r\n"
+ "m=audio 492170 RTP/AVP 0 12\r\n"
+ "m=video 3227 RTP/AVP 31\r\n"
+ "a=rtpmap:31 LPC\r\n"));
+
+ TEST_1(sip = sip_object(msg));
+
+ TEST(count(sip->sip_request->rq_common), 1);
+ TEST(count(sip->sip_to->a_common), 1);
+ TEST(count(sip->sip_from->a_common), 1);
+ TEST(count(sip->sip_cseq->cs_common), 1);
+ TEST(count(sip->sip_call_id->i_common), 1);
+ TEST(count(sip->sip_via->v_common), 4);
+ TEST(count(sip->sip_contact->m_common), 3);
+ TEST(count(sip->sip_content_type->c_common), 1);
+ TEST(count(sip->sip_route->r_common), 0);
+ TEST(count(sip->sip_record_route->r_common), 4);
+ TEST(count(sip->sip_unknown->un_common), 2);
+ TEST(count(sip->sip_error->er_common), 1);
+ TEST(count(sip->sip_max_forwards->mf_common), 1);
+ TEST(count(sip->sip_min_expires->me_common), 1);
+ TEST(count(sip->sip_timestamp->ts_common), 1);
+
+ TEST_S(sip->sip_contact->m_display, "Joe Bob Briggs");
+ TEST_1(sip->sip_contact->m_next->m_display != NULL);
+ TEST_S(sip->sip_contact->m_next->m_display, "");
+ TEST_1(sip->sip_contact->m_next->m_next->m_display == NULL);
+
+ TEST(sip->sip_max_forwards->mf_count, 12);
+ TEST(sip->sip_min_expires->me_delta, 150);
+
+ {
+ sip_suppress_body_if_match_t *sbim;
+ sip_suppress_notify_if_match_t *snim;
+
+ TEST_1(sbim = sip_suppress_body_if_match(sip));
+ TEST_S(sbim->sbim_tag, "humppa");
+
+ TEST_SIZE(offsetof(msg_generic_t, g_value),
+ offsetof(sip_suppress_body_if_match_t, sbim_tag));
+
+ TEST_1(snim = sip_suppress_notify_if_match(sip));
+ TEST_S(snim->snim_tag, "zumppa");
+
+ TEST_SIZE(offsetof(msg_generic_t, g_value),
+ offsetof(sip_suppress_notify_if_match_t, snim_tag));
+ }
+
+ TEST_1(sip->sip_from->a_display);
+ TEST_S(sip->sip_from->a_display, "h");
+
+ v0 = sip->sip_via;
+
+ TEST_1(v = sip_via_copy(home, v0));
+ TEST(len(v->v_common), len(v0->v_common));
+ for (; v && v0; v = v->v_next, v0 = v0->v_next) {
+ if (v->v_params)
+ TEST_1(v->v_params != v0->v_params);
+ if (v->v_branch)
+ TEST_1(v->v_branch == v0->v_branch);
+ }
+ TEST_1(v == NULL && v0 == NULL);
+
+ v0 = sip->sip_via;
+
+ TEST_1(v = sip_via_dup(home, v0));
+ TEST(len(v->v_common), len(v0->v_common));
+ for (; v && v0; v = v->v_next, v0 = v0->v_next) {
+ if (v->v_params)
+ TEST_1(v->v_params != v0->v_params);
+ if (v->v_branch)
+ TEST_1(v->v_branch != v0->v_branch);
+ }
+ TEST_1(v == NULL && v0 == NULL);
+
+ TEST(sip_add_dup(msg, sip, (sip_header_t *)sip->sip_max_forwards), 0);
+ /* Max-Forwards is last header? */
+ TEST_P(sip->sip_max_forwards, sip->sip_content_type->c_common->h_succ);
+
+ TEST(sip_to_tag(home, sip->sip_to, sip->sip_to->a_tag), 0);
+ TEST(sip_to_tag(home, sip->sip_to, "tag=deadbeef"), 0);
+ TEST(sip_to_tag(home, sip->sip_to, "foofaa"), -1);
+
+ msg_header_remove(msg, (msg_pub_t *)sip, (msg_header_t *)sip->sip_payload);
+
+ TEST(sip_add_tl(msg, sip,
+ SIPTAG_FROM(SIP_NONE),
+ SIPTAG_VIA(SIP_NONE),
+ SIPTAG_VIA_STR("SIP/2.0/SCTP foo.bar.com:5060;branch=foo"),
+ SIPTAG_TO_STR("<sip:foo at bar>"),
+ SIPTAG_HEADER_STR("Authorization: Basic foobar\n"
+ "Priority:\n urgent"),
+ SIPTAG_HEADER_STR("Accept: foo/bar\n"
+ "\n"
+ "test payload\n"),
+ SIPTAG_TIMESTAMP(sip->sip_timestamp),
+ SIPTAG_END(),
+ SIPTAG_REFER_TO_STR("<sip:foo at bar>"),
+ TAG_END()), 0);
+ TEST_1(sip->sip_from == NULL);
+ TEST_1(sip->sip_via); TEST_1(sip->sip_via->v_next == NULL);
+ TEST_S(sip->sip_via->v_protocol, "SIP/2.0/SCTP");
+ TEST_1(sip->sip_authorization);
+ TEST_1(sip->sip_priority);
+ TEST_1(sip->sip_payload);
+ TEST_S(sip->sip_payload->pl_data, "test payload\n");
+ TEST_1(sip->sip_timestamp);
+ TEST_S(sip->sip_timestamp->ts_stamp, "10.010");
+ TEST_S(sip->sip_timestamp->ts_delay, "0.000100");
+ TEST_1(!sip->sip_refer_to);
+
+ TEST_1(tl = tl0 = tl_list(SIPTAG_TO_STR("<sip:foo at bar>"),
+ SIPTAG_END(),
+ SIPTAG_REFER_TO_STR("<sip:foo at bar>"),
+ TAG_END()));
+ /* sip_add_tagis should stop after SIPTAG_END() */
+ TEST(sip_add_tagis(msg, sip, &tl), 0);
+ TEST_P(tl, tl0 + 2);
+
+ tl_free(tl0);
+
+ TEST_P(sip_timestamp_make(home, "+1"), NULL);
+ TEST_P(sip_timestamp_make(home, "1.0e6 13.0"), NULL);
+ TEST_1(sip_timestamp_make(home, "1.0 .001"));
+ TEST_P(sip_timestamp_make(home, ".0001 13.0"), NULL);
+
+ TEST_1(x = sip->sip_path);
+ TEST_1(sip_add_make(msg, sip, sip_path_class, "<sip:135.180.130.133>") == 0);
+ TEST_P(x, sip->sip_path->r_next);
+
+ TEST_1(x = sip->sip_service_route);
+ TEST_1(sip_add_make(msg, sip, sip_service_route_class,
+ "<sip:135.180.130.133>") == 0);
+ TEST_P(x, sip->sip_service_route);
+ TEST_1(sip->sip_service_route->r_next);
+
+ /* Detect parsing errors */
+ TEST_1(!sip_cseq_make(home, "21874624876976 INVITE"));
+ TEST_1(!sip_cseq_make(home, "218746INVITE"));
+
+ msg_destroy(msg), msg = NULL;
+
+ su_home_unref(home), home = NULL;
+
+ END();
+}
+
+static int test_bad_packet(void)
+{
+ msg_t *msg;
+ sip_t *sip;
+ su_home_t *home;
+
+ BEGIN();
+
+ home = su_home_new(sizeof *home);
+
+ TEST_1(msg = read_message(MSG_DO_EXTRACT_COPY,
+ "MESSAGE <sip:John_Smith at tct.hut.fi> SIP/2.0\r\n"
+ "To: John Smith <sip:John_Smith at tct.hut.fi:5066;user=ip;maddr=131.228.16.2>\r\n"
+ " ; tag = deadbeef\r\n"
+ "From:h<http://www.cs.columbia.edu>\r\n"
+ "Call-ID: 0ha0isndaksdj at 10.1.2.3\r\n"
+ "CSeq : 8 MESSAGE\r\n"
+ "Via: SIP/2.0/UDP 135.180.130.133;received=defa:daf::00:12\r\n"
+ "Via: SIP/2.0/TCP 135.180.130.131;branch=deadbeef.barf;ttl=3;hidden,,"
+ "SIP/2.0/UDP\r\n 135.180.130.131:5061;received=[defa::00:12]\r\n"
+ "Contact: Joe Bob Briggs <urn:ipaddr:122.1.2.3> ; bar=\042foo baa\042, sip:kuik at foo.invalid\r\n"
+ "Via: SIP/2.0/UDP [aa:bb::1]:5061\0\0"));
+
+ TEST_1(sip = sip_object(msg));
+
+ TEST(count(sip->sip_request->rq_common), 1);
+ TEST(count(sip->sip_to->a_common), 1);
+ TEST(count(sip->sip_from->a_common), 1);
+ TEST(count(sip->sip_cseq->cs_common), 1);
+ TEST(count(sip->sip_call_id->i_common), 1);
+ TEST(count(sip->sip_via->v_common), 4);
+ TEST(count(sip->sip_route->r_common), 0);
+
+ TEST(sip->sip_request->rq_url->url_type, url_invalid);
+
+ su_home_unref(home), home = NULL;
+
+ msg_destroy(msg), msg = NULL;
+
+ END();
+}
+
+static int test_sip_list_header(void)
+{
+ msg_t *msg;
+ sip_t *sip;
+ su_home_t *home;
+ sip_allow_t *a;
+
+ BEGIN();
+
+ home = su_home_new(sizeof *home);
+
+ TEST_1(msg = read_message(0,
+ "MESSAGE sip:John_Smith at tct.hut.fi SIP/2.0\r\n"
+ "To: John Smith <sip:John_Smith at tct.hut.fi:5066;user=ip;maddr=131.228.16.2>\r\n"
+ "From: <sip:joe at doe.org>;tag=foobar\r\n"
+ "Call-ID: 0ha0isndaksdj at 10.1.2.3\r\n"
+ "CSeq : 8 MESSAGE\r\n"
+ "Via: SIP/2.0/UDP 135.180.130.133;received=defa:daf::00:12\r\n"
+ "Via: SIP/2.0/TCP 135.180.130.131;branch=deadbeef.barf;ttl=3;hidden,,"
+ "SIP/2.0/UDP\r\n 135.180.130.131:5061;received=[defa::00:12]\r\n"
+ "Contact: Joe Bob Briggs <urn:ipaddr:122.1.2.3> ; bar=\042foo baa\042, <sip:kuik at foo.invalid>, sip:barf\r\n"
+ "Allow: INVITE\r\n"
+ "Allow: ACK\r\n"
+ "Allow: CANCEL\r\n"
+ "Allow: BYE\r\n"
+ "Allow: OPTIONS\r\n"
+ "Allow: MESSAGE\r\n"
+ "Allow: KUIK\r\n"
+ "Max-Forwards: 12\r\n"
+ "Content-Type: text/plain\r\n"
+ "\r\n"
+ "hello\r\n"));
+
+ TEST_1(sip = sip_object(msg));
+ TEST_1(a = sip->sip_allow);
+ TEST_1(a->k_items);
+ TEST_1(a->k_next == NULL);
+
+ TEST_1(sip_is_allowed(a, SIP_METHOD_INVITE));
+ TEST_1(!sip_is_allowed(a, SIP_METHOD_PUBLISH));
+ TEST_1(sip_is_allowed(a, SIP_METHOD(KUIK)));
+ TEST_1(!sip_is_allowed(a, SIP_METHOD(kuik)));
+
+ TEST_1(a = sip_allow_make(home, ""));
+ TEST_S(sip_header_as_string(home, (void *)a), "");
+
+ TEST_1(a = sip_allow_make(home, "INVITE, PUBLISH"));
+
+ TEST_1(sip_is_allowed(a, SIP_METHOD_INVITE));
+
+ /* Test with list header */
+ TEST_1(msg_header_add_dup(msg, NULL, (msg_header_t *)a) == 0);
+
+ TEST_1(a = sip_allow_make(home, "MESSAGE, SUBSCRIBE"));
+
+ TEST_1(msg_header_add_dup(msg, NULL, (msg_header_t *)a) == 0);
+
+ TEST_1(msg_header_add_make(msg, NULL, sip_allow_class, "kuik") == 0);
+
+ TEST_1(a = sip->sip_allow);
+ TEST_1(a->k_items);
+ TEST_S(a->k_items[0], "INVITE");
+ TEST_S(a->k_items[1], "ACK");
+ TEST_S(a->k_items[2], "CANCEL");
+ TEST_S(a->k_items[3], "BYE");
+ TEST_S(a->k_items[4], "OPTIONS");
+ TEST_S(a->k_items[5], "MESSAGE");
+ TEST_S(a->k_items[6], "KUIK");
+ TEST_S(a->k_items[7], "PUBLISH");
+ TEST_S(a->k_items[8], "SUBSCRIBE");
+ TEST_S(a->k_items[9], "kuik");
+ TEST_P(a->k_items[10], NULL);
+
+ msg_destroy(msg), msg = NULL;
+
+ su_home_unref(home), home = NULL;
+
+ END();
+}
+
+static int test_prack(void)
+{
+ /* Test RAck and RSeq */
+ su_home_t *home;
+ sip_rack_t *rack, *rack0;
+ sip_rseq_t *rseq, *rseq0;
+
+ BEGIN();
+
+ TEST_1(home = su_home_create());
+ TEST_1(rack = sip_rack_make(home, "1 2 INVITE"));
+ TEST(rack->ra_response, 1);
+ TEST(rack->ra_cseq, 2);
+ TEST(rack->ra_method, sip_method_invite);
+ TEST_S(rack->ra_method_name, "INVITE");
+ TEST_1(rseq = sip_rseq_make(home, "3"));
+ TEST(rseq->rs_response, 3);
+
+ TEST_1(rack0 = sip_rack_dup(home, rack));
+ TEST_P(rack0->ra_method_name, rack->ra_method_name);
+ TEST_1(rseq0 = sip_rseq_dup(home, rseq));
+
+ TEST_1(rack = sip_rack_make(home, "4\r\n\t5\r\n\tEXTRA"));
+ TEST(rack->ra_response, 4);
+ TEST(rack->ra_cseq, 5);
+ TEST(rack->ra_method, sip_method_unknown);
+ TEST_S(rack->ra_method_name, "EXTRA");
+ TEST_1(rseq = sip_rseq_make(home, " 6 "));
+ TEST(rseq->rs_response, 6);
+
+ TEST_1(rack0 = sip_rack_dup(home, rack));
+ TEST_1(rack0->ra_method_name != rack->ra_method_name);
+ TEST_1(rseq0 = sip_rseq_dup(home, rseq));
+
+ su_home_unref(home);
+
+ END();
+}
+
+/* Test MIME headers */
+static int test_accept(void)
+{
+ /* Test Accept header */
+ sip_accept_t *ac, *ac0;
+ sip_accept_encoding_t *aa;
+ su_home_t *home;
+
+ BEGIN();
+
+ TEST_1(home = su_home_create());
+ TEST_1(ac = ac0 = sip_accept_make(home, "image / jpeg ; q = 0.6,, image/png, image/*, */* "));
+ TEST_S(ac->ac_type, "image/jpeg");
+ TEST_S(ac->ac_subtype, "jpeg");
+ TEST_1(ac->ac_params && ac->ac_params[0]);
+ TEST_S(ac->ac_params[0], "q=0.6");
+ TEST_S(ac->ac_q, "0.6");
+
+ TEST_1(ac = ac->ac_next);
+ TEST_S(ac->ac_type, "image/png");
+ TEST_S(ac->ac_subtype, "png");
+
+ TEST_1(ac = ac->ac_next);
+ TEST_S(ac->ac_type, "image/*");
+ TEST_S(ac->ac_subtype, "*");
+
+ TEST_1(aa = sip_accept_encoding_make(home, "gzip"));
+ TEST_1(aa = sip_accept_encoding_make(home, "gzip;q=1.0,deflate;q=1.0"));
+ TEST_S(aa->aa_value, "gzip"); TEST_S(aa->aa_q, "1.0");
+ TEST_1(aa->aa_next);
+ TEST_S(aa->aa_next->aa_value, "deflate");
+ TEST_1(aa = sip_accept_encoding_make(home, ","));
+ TEST_S(aa->aa_value, ""); TEST_1(!aa->aa_next);
+ TEST_1(aa = sip_accept_encoding_make(home, ""));
+ TEST_S(aa->aa_value, ""); TEST_1(!aa->aa_next);
+
+ TEST_1(aa = sip_accept_language_make(home, "fi"));
+ TEST_1(aa = sip_accept_language_make(home, "fi;q=1.0,sv;q=1.0"));
+ TEST_S(aa->aa_value, "fi"); TEST_S(aa->aa_q, "1.0");
+ TEST_1(aa->aa_next);
+ TEST_S(aa->aa_next->aa_value, "sv");
+ TEST_1(aa = sip_accept_language_make(home, ","));
+ TEST_S(aa->aa_value, ""); TEST_1(!aa->aa_next);
+ TEST_1(aa = sip_accept_language_make(home, ""));
+ TEST_S(aa->aa_value, ""); TEST_1(!aa->aa_next);
+
+ su_home_unref(home);
+
+ END();
+}
+
+static int test_content_disposition(void)
+{
+ /* Test Accept header */
+ sip_content_disposition_t *cd, *cd0;
+ su_home_t *home;
+
+ BEGIN();
+
+ TEST_1(home = su_home_create());
+ TEST_1(cd = cd0 = sip_content_disposition_make(home, "sip-cgi ; action = store;handling=required "));
+ TEST_S(cd->cd_type, "sip-cgi");
+ TEST_1(cd->cd_params && cd->cd_params[0] && cd->cd_params[1] && !cd->cd_params[2]);
+ TEST_S(cd->cd_params[0], "action=store");
+ TEST_S(cd->cd_params[1], "handling=required");
+ TEST_S(cd->cd_handling, "required");
+ TEST_1(cd->cd_required);
+ TEST_1(!cd->cd_optional);
+
+ su_home_unref(home);
+ END();
+}
+
+int test_retry_after(void)
+{
+ /* Test Session-Expires header */
+ sip_retry_after_t *af, *af0;
+ su_home_t *home;
+ char buf[64];
+
+ BEGIN();
+
+ TEST_1(home = su_home_create());
+ TEST_1(af = sip_retry_after_make(home, "1800"));
+ TEST(af->af_delta, 1800);
+ TEST_1(af = sip_retry_after_make(home, "1800(foo); duration = 3600"));
+ TEST_1(af->af_params && af->af_params[0]);
+ TEST_S(af->af_comment, "foo");
+ TEST_S(af->af_params[0], "duration=3600");
+ TEST_S(af->af_duration, "3600");
+
+ TEST_1(af0 = sip_retry_after_dup(home, af));
+ TEST_1(af0->af_params && af0->af_params[0]);
+ TEST_S(af0->af_comment, "foo");
+ TEST_S(af0->af_params[0], "duration=3600");
+ TEST_S(af0->af_duration, "3600");
+
+ TEST_1(sip_retry_after_e(buf, sizeof(buf), (sip_header_t *)af0, 0));
+
+ TEST_S(buf, "1800 (foo) ;duration=3600");
+
+ su_home_unref(home);
+
+ END();
+}
+
+int test_session_expires(void)
+{
+ /* Test Session-Expires header */
+ sip_session_expires_t *x, *x0;
+ su_home_t *home;
+
+ BEGIN();
+
+ TEST_1(home = su_home_create());
+ TEST_1(x = x0 = sip_session_expires_make(home, "1800"));
+ TEST(x->x_delta, 1800);
+ TEST_1(x = x0 = sip_session_expires_make(home, "1800 ; refresher = uas"));
+ TEST_1(x->x_params && x->x_params[0]);
+ TEST_S(x->x_params[0], "refresher=uas");
+ TEST_S(x->x_refresher, "uas");
+
+ su_home_unref(home);
+
+ END();
+}
+
+int test_min_se(void)
+{
+ /* Test Min-SE header */
+ sip_min_se_t *min, *min0;
+ su_home_t *home;
+
+ BEGIN();
+
+ TEST_1(home = su_home_create());
+ TEST_1(min = min0 = sip_min_se_make(home, "1800"));
+ TEST(min->min_delta, 1800);
+ TEST_1(min = sip_min_se_dup(home, min0));
+ TEST(min->min_delta, 1800);
+ TEST_1(min = sip_min_se_copy(home, min0));
+ TEST(min->min_delta, 1800);
+
+ TEST_1(min = sip_min_se_make(home, "1999 ; foo = bar"));
+ TEST(min->min_delta, 1999);
+ TEST_1(min->min_params);
+ TEST_S(min->min_params[0], "foo=bar");
+
+ TEST_1(min0 = sip_min_se_dup(home, min));
+ TEST(min0->min_delta, 1999);
+ TEST_1(min0->min_params);
+ TEST_S(min0->min_params[0], "foo=bar");
+
+ su_home_unref(home);
+
+ END();
+}
+
+int test_refer(void)
+{
+ sip_refer_to_t *r, *r0;
+ sip_referred_by_t *b, *b0;
+ sip_replaces_t *rp, *rp0;
+ char const *s0;
+
+ su_home_t *home;
+
+ BEGIN();
+
+ char const m[] =
+ "REFER sip:10.3.3.104 SIP/2.0\r\n"
+ "Via: SIP/2.0/UDP 10.3.3.8;branch=z9hG4bKb8389b4c1BA8899\r\n"
+ "From: \"Anthony Minessale\" <sip:polycom500 at 10.3.3.104>;tag=5AA04E0-66CFC37F\r\n"
+ "To: <sip:3001 at 10.3.3.104>;user=phone;tag=j6Fg9y7t8KNrF\r\n"
+ "CSeq: 4 REFER\r\n"
+ "Call-ID: a14822a4-5932e3ea-d7f37191 at 10.3.3.8\r\n"
+ "Contact: <sip:polycom500 at 10.3.3.8>\r\n"
+ "User-Agent: PolycomSoundPointIP-SPIP_500-UA/1.4.1\r\n"
+ "Refer-To: <sip:2000 at 10.3.3.104?Replaces=7d84c014-321368da-efa90f41%40"
+ "10.3.3.8%3Bto-tag%3DpaNKgBB9vQe3D%3Bfrom-tag%3D93AC8D50-7CF6DAAF>\r\n"
+ "Referred-By: \"Anthony Minessale\" <sip:polycom500 at 10.3.3.104>\r\n"
+ "Refer-Sub: true\r\n"
+ "Max-Forwards: 70\r\n"
+ "Content-Length: 0\r\n"
+ "\r\n";
+ msg_t *msg;
+ sip_t *sip;
+ msg_iovec_t *iovec;
+ isize_t veclen, i, size;
+ char *back;
+ sip_refer_sub_t *rs;
+
+ TEST_1(home = su_home_create());
+
+ /* Check that Refer-Sub has already been added to our parser */
+ TEST_1(msg_mclass_insert_with_mask(test_mclass, sip_refer_sub_class,
+ 0, 0) == -1);
+
+ msg = read_message(0, m); TEST_1(msg); TEST_1(sip = sip_object(msg));
+ TEST_1(sip->sip_refer_to);
+ TEST_S(sip->sip_refer_to->r_url->url_headers,
+ "Replaces=7d84c014-321368da-efa90f41%40"
+ "10.3.3.8%3Bto-tag%3DpaNKgBB9vQe3D%3Bfrom-tag%3D93AC8D50-7CF6DAAF");
+
+ TEST_1(rs = sip_refer_sub(sip));
+ TEST_S(rs->rs_value, "true");
+
+ TEST_SIZE(msg_prepare(msg), strlen(m));
+ TEST_1(veclen = msg_iovec(msg, NULL, ISIZE_MAX));
+ TEST_1(iovec = su_zalloc(msg_home(home), veclen * (sizeof iovec[0])));
+ TEST_SIZE(msg_iovec(msg, iovec, veclen), veclen);
+
+ for (i = 0, size = 0; i < veclen; i++)
+ size += iovec[i].mv_len;
+
+ TEST_1(back = su_zalloc(msg_home(msg), size + 1));
+
+ for (i = 0, size = 0; i < veclen; i++) {
+ memcpy(back + size, iovec[i].mv_base, iovec[i].mv_len);
+ size += iovec[i].mv_len;
+ }
+ back[size] = '\0';
+
+ TEST_S(back, m);
+
+ TEST_1(r = r0 = sip_refer_to_make(home, "http://example.com;foo=bar"));
+ TEST(r->r_url->url_type, url_http);
+ TEST_1(r->r_params);
+ TEST_S(r->r_params[0], "foo=bar");
+ r = sip_refer_to_dup(home, r0);
+ TEST(r->r_url->url_type, url_http);
+ TEST_1(r->r_params);
+ TEST_S(r->r_params[0], "foo=bar");
+
+ TEST_1(r = r0 = sip_refer_to_make(home, s0 = "<http://example.com>"));
+ TEST_S(r->r_display, "");
+ TEST(r->r_url->url_type, url_http);
+ TEST_P(r->r_params, NULL);
+ r = sip_refer_to_dup(home, r0);
+ TEST_S(r->r_display, "");
+ TEST(r->r_url->url_type, url_http);
+ TEST_P(r->r_params, NULL);
+ TEST_S(sip_header_as_string(home, (sip_header_t*)r), s0);
+
+ TEST_1(r = r0 = sip_refer_to_make(home,
+ "Web Site <http://example.com>;foo=bar"));
+ TEST_S(r->r_display, "Web Site");
+ TEST(r->r_url->url_type, url_http);
+ TEST_1(r->r_params);
+ TEST_S(r->r_params[0], "foo=bar");
+ TEST_P(r->r_params[1], NULL);
+ r = sip_refer_to_dup(home, r0);
+ TEST(r->r_url->url_type, url_http);
+ TEST_1(r->r_params);
+ TEST_S(r->r_params[0], "foo=bar");
+ TEST_P(r->r_params[1], NULL);
+
+ /* Test bad replaces without <> */
+ {
+ char const s[] =
+ "sip:2000 at 10.3.3.104?Replaces=7d84c014-321368da-efa90f41%4010.3.3.8"
+ "%3Bto-tag%3DpaNKgBB9vQe3D%3Bfrom-tag%3D93AC8D50-7CF6DAAF" "\r\n";
+ char *str;
+
+ TEST_1(r = r0 = sip_refer_to_make(home, s));
+ msg_fragment_clear(r->r_common);
+ TEST_1(str = sip_header_as_string(home, (void *)r));
+ TEST_S(str,
+ "<"
+ "sip:2000 at 10.3.3.104?Replaces=7d84c014-321368da-efa90f41%4010.3.3.8"
+ "%3Bto-tag%3DpaNKgBB9vQe3D%3Bfrom-tag%3D93AC8D50-7CF6DAAF"
+ ">");
+ }
+
+ su_home_unref(home);
+
+ TEST_1(home = su_home_create());
+ TEST_1(b = b0 = sip_referred_by_make(home,
+ "sip:joe at example.edu;param=value"));
+ TEST_P(b->b_display, NULL);
+ TEST_1(b->b_params);
+ TEST_P(b->b_cid, NULL);
+
+ TEST_1(b = sip_referred_by_make(home,
+ "John Doe <sip:joe at example.edu>"
+ ";cid=\"foo at bar\""));
+ TEST_S(b->b_display, "John Doe");
+ TEST_1(b->b_params);
+ TEST_1(b->b_cid);
+ TEST_S(b->b_params[0] + 4, b->b_cid);
+
+ b = sip_referred_by_dup(home, b0 = b);
+
+ TEST_1(b);
+ TEST_S(b->b_display, "John Doe");
+ TEST_1(b->b_cid);
+ TEST_S(b->b_params[0] + 4, b->b_cid);
+ TEST_S(b->b_cid, b0->b_cid);
+
+ TEST(msg_header_replace_param(home, b->b_common, "cid=cid:8u432658725"), 1);
+ TEST_S(b->b_cid, "cid:8u432658725");
+ TEST(msg_header_remove_param(b->b_common, "cid"), 1);
+ TEST_P(b->b_cid, NULL);
+
+ /* XXX */
+#define WORD ALPHA DIGIT "-.!%*_+`'~()<>:\\\"/[]?{}"
+ rp = sip_replaces_make(home, WORD "@" WORD ";to-tag=foo;from-tag=bar"
+ ";early-only = yes-please ");
+
+ TEST_1(rp);
+ TEST_S(rp->rp_call_id, WORD "@" WORD);
+ TEST_S(rp->rp_to_tag, "foo");
+ TEST_S(rp->rp_from_tag, "bar");
+ TEST(rp->rp_early_only, 1);
+
+ rp = sip_replaces_dup(home, rp0 = rp);
+
+ TEST_1(rp);
+ TEST_S(rp->rp_call_id, WORD "@" WORD);
+ TEST_S(rp->rp_to_tag, "foo");
+ TEST_S(rp->rp_from_tag, "bar");
+ TEST(rp->rp_early_only, 1);
+
+ TEST(msg_header_replace_param(home, rp->rp_common, "early-only"), 1);
+ TEST(rp->rp_early_only, 1);
+ TEST(msg_header_remove_param(rp->rp_common, "from-tag"), 1);
+ TEST_P(rp->rp_from_tag, NULL);
+ TEST(msg_header_remove_param(rp->rp_common, "to-tag"), 1);
+ TEST_P(rp->rp_to_tag, NULL);
+
+ su_home_unref(home);
+
+ END();
+}
+
+static int test_features(void)
+{
+ /* Test Proxy-Required, Require, Supported, and Unsupported headers */
+ sip_proxy_require_t *pr;
+ sip_require_t *r;
+ sip_supported_t *s;
+ sip_unsupported_t *u, *u1;
+ su_home_t *home;
+
+ BEGIN();
+
+ TEST_1(home = su_home_create());
+ TEST_1(pr = sip_proxy_require_make(home, "foo, bar, baz, dig, dug"));
+ TEST_1(r = sip_require_make(home, "dig, dug"));
+ TEST_1(s = sip_supported_make(home, "foo, baz, dug"));
+
+ TEST_1(pr->k_items); TEST_S(pr->k_items[0], "foo");
+ TEST_1(r->k_items); TEST_S(r->k_items[0], "dig");
+ TEST_1(s->k_items); TEST_S(s->k_items[0], "foo");
+
+ TEST_1(u = sip_has_unsupported(home, s, pr));
+ TEST_1(u->k_items);
+ TEST_S(u->k_items[0], "bar");
+ TEST_S(u->k_items[1], "dig");
+ TEST_P(u->k_items[2], NULL);
+
+ TEST_1(u1 = sip_has_unsupported(home, s, r));
+ TEST_1(u1->k_items); TEST_S(u1->k_items[0], "dig"); TEST_1(!u1->k_items[1]);
+
+ TEST_1(sip_has_supported(s, "foo"));
+ TEST_1(sip_has_supported(s, "baz"));
+ TEST_1(sip_has_supported(s, "dug"));
+ TEST_1(!sip_has_supported(s, "dig"));
+ TEST_1(!sip_has_supported(s, "dag.2"));
+ TEST_1(sip_has_supported(s, NULL));
+ TEST_1(sip_has_supported(NULL, NULL));
+ TEST_1(!sip_has_supported(NULL, "foo"));
+
+ su_home_unref(home);
+ END();
+}
+
+#if 0
+static int sip_time_test(void)
+{
+ sip_contact_t *m;
+ sip_expires_t *ex;
+ sip_date_t *date = NULL;
+ sip_time_t default = 3600;
+ BEGIN();
+
+ sip_time_t sip_contact_expires(sip_contact_t const *m,
+ sip_expires_t const *ex,
+ sip_date_t const *date,
+ sip_time_t def,
+ sip_time_t now);
+
+
+ END();
+}
+#endif
+
+static int test_events(void)
+{
+ sip_event_t *o;
+ sip_allow_events_t *ae;
+ sip_subscription_state_t *ss;
+ su_home_t *home;
+ msg_t *msg;
+ sip_t *sip;
+
+ BEGIN();
+
+ TEST_1(home = su_home_create());
+
+ TEST_1((o = sip_event_make(home, "presence;id=1")));
+ TEST_S(o->o_type, "presence");
+ TEST_S(o->o_id, "1");
+
+ TEST(msg_header_remove_param(o->o_common, "ix=0"), 0);
+ TEST_S(o->o_id, "1");
+ TEST(msg_header_remove_param(o->o_common, "id"), 1);
+ TEST_P(o->o_id, NULL);
+ TEST(msg_header_replace_param(home, o->o_common, "id=32"), 0);
+ TEST_S(o->o_id, "32");
+
+ TEST_1((ae = sip_allow_events_make(home, "presence, presence.winfo, foo")));
+ TEST_1(ae->k_items);
+ TEST_S(ae->k_items[0], "presence");
+ TEST_S(ae->k_items[1], "presence.winfo");
+ TEST_S(ae->k_items[2], "foo");
+ TEST_P(ae->k_items[3], 0);
+ TEST(sip_allow_events_add(home, ae, "event3"), 0);
+ TEST_S(ae->k_items[3], "event3");
+ TEST(sip_allow_events_add(home, ae, "event4"), 0);
+ TEST_S(ae->k_items[4], "event4");
+ TEST(sip_allow_events_add(home, ae, "event5"), 0);
+ TEST_S(ae->k_items[5], "event5");
+ TEST(sip_allow_events_add(home, ae, "event6"), 0);
+ TEST_S(ae->k_items[6], "event6");
+ TEST(sip_allow_events_add(home, ae, "event7"), 0);
+ TEST_S(ae->k_items[7], "event7");
+ TEST(sip_allow_events_add(home, ae, "event8"), 0);
+ TEST_S(ae->k_items[8], "event8");
+
+ TEST_1((ss =
+ sip_subscription_state_make(home, "terminated ; reason=timeout")));
+ TEST_S(ss->ss_substate, "terminated");
+ TEST_S(ss->ss_reason, "timeout");
+
+ TEST(msg_header_replace_param(home, ss->ss_common, "reason=TimeOut"), 1);
+ TEST_S(ss->ss_reason, "TimeOut");
+ TEST(msg_header_remove_param(ss->ss_common, "reasom"), 0);
+ TEST_S(ss->ss_reason, "TimeOut");
+ TEST(msg_header_remove_param(ss->ss_common, "reason"), 1);
+ TEST_P(ss->ss_reason, NULL);
+ TEST(msg_header_replace_param(home, ss->ss_common, "expires=200"), 0);
+ TEST(msg_header_replace_param(home, ss->ss_common, "retry-after=10"), 0);
+ TEST_S(ss->ss_expires, "200");
+ TEST_S(ss->ss_retry_after, "10");
+
+ TEST_1((ss =
+ sip_subscription_state_make(home, "active;expires=2")));
+ TEST_S(ss->ss_substate, "active");
+ TEST_S(ss->ss_expires, "2");
+
+ TEST_1((ss =
+ sip_subscription_state_make(home, "terminated;retry-after=3600")));
+ TEST_S(ss->ss_substate, "terminated");
+ TEST_P(ss->ss_expires, NULL);
+ TEST_S(ss->ss_retry_after, "3600");
+
+ TEST_1((ss = sip_subscription_state_dup(home, ss)));
+ TEST_S(ss->ss_substate, "terminated");
+ TEST_P(ss->ss_expires, NULL);
+ TEST_S(ss->ss_retry_after, "3600");
+
+ msg = read_message(MSG_DO_EXTRACT_COPY,
+ "SIP/2.0 202 Accepted\r\n"
+ "To: <sip:foo at bar>;tag=deadbeef\r\n"
+ "From: <sip:bar at foo>;\r\n"
+ "Call-ID: 0ha0isndaksdj at 10.1.2.3\r\n"
+ "CSeq: 8 SUBSCRIBE\r\n"
+ "Via: SIP/2.0/UDP 135.180.130.133\r\n"
+ "Event: foo;id=1\r\n"
+ "Allow-Events: bar, foo, zap\r\n"
+ "Subscription-State: terminated;reason=probation;retry-after=100000\r\n"
+ "Content-Length: 0\r\n"
+ "\r\n");
+
+ sip = sip_object(msg);
+
+ TEST_1(msg);
+ TEST_1(sip);
+ TEST_1(sip->sip_event);
+ TEST_1(sip->sip_allow_events);
+ TEST_1(sip->sip_event->o_type);
+ TEST_S(sip->sip_event->o_type, "foo");
+ TEST_1(sip->sip_event->o_id);
+ TEST_S(sip->sip_event->o_id, "1");
+ TEST_1(sip->sip_allow_events);
+
+ su_home_unref(home);
+ msg_destroy(msg), msg = NULL;
+
+ END();
+}
+
+static int test_route(void)
+{
+ sip_record_route_t *r0, *r1;
+ sip_record_route_t *rr;
+ sip_path_t *p, *p0;
+ sip_service_route_t *sr, *sr0;
+
+ su_home_t *home;
+
+ BEGIN();
+
+ TEST_1(home = su_home_create());
+
+ TEST_1((rr = sip_record_route_make(home, "sip:foo.bar;lr")));
+ TEST_1(rr->r_params);
+
+ TEST_1((r0 = sip_record_route_make(home, "<sip:0 at foo.bar:555;lr>")));
+ TEST_P(r0->r_params, NULL);
+ TEST_1(r0->r_url->url_params);
+
+ TEST_1((r1 = sip_record_route_make(home, "<sip:1 at foo.bar:666"
+ ";maddr=127.0.0.1>")));
+ TEST_P(r1->r_params, NULL);
+ TEST_1(r1->r_url->url_params);
+
+ TEST_1((rr = sip_record_route_create(home, r0->r_url, r1->r_url)));
+ TEST_S(rr->r_url->url_user, "0");
+ TEST_S(rr->r_url->url_port, "666");
+ TEST_S(rr->r_url->url_params, "maddr=127.0.0.1");
+
+ TEST_1((rr = sip_record_route_create(home, r1->r_url, r0->r_url)));
+ TEST_S(rr->r_url->url_user, "1");
+ TEST_S(rr->r_url->url_port, "555");
+ TEST_S(rr->r_url->url_params, "lr;maddr=foo.bar");
+
+ TEST_1(!sip_path_make(home, "<sip:foo@[bar:50>;lr"));
+ TEST_1(p = sip_path_make(home, "<sip:foo@[baa::1]:5060>;lr"));
+ TEST_1(p0 = sip_path_dup(home, p));
+
+ su_free(home, p);
+ su_free(home, p0);
+
+ TEST_1(!sip_service_route_make(home, "<sip:foo@[bar:50>;lr"));
+ TEST_1(!sip_service_route_make(home,
+ "<sip:foo@[baa::1]>;lr bar, sip:foo"));
+
+ TEST_1(sr = sip_service_route_make(home, "<sip:foo@[baa::1]:5060>;lr"));
+ TEST_1(sr0 = sip_service_route_dup(home, sr));
+ su_free(home, sr);
+
+ TEST_1(sr = sip_service_route_make(home, "sip:foo@[baa::1]:5060;lr"));
+
+ su_free(home, sr);
+ su_free(home, sr0);
+
+ su_home_unref(home);
+
+ END();
+}
+
+/* Test Request-Disposition header */
+int test_request_disposition(void)
+{
+ sip_request_disposition_t *rd;
+ su_home_t *home;
+
+ BEGIN();
+
+ TEST_1(home = su_home_create());
+
+ TEST_1(rd = sip_request_disposition_make(home, "proxy, recurse, parallel"));
+ TEST_S(rd->rd_items[1], "recurse");
+
+ su_home_unref(home);
+
+ END();
+}
+
+#include <float.h>
+
+int test_caller_prefs(void)
+{
+ sip_accept_contact_t *ac;
+ sip_accept_contact_t *cp;
+ sip_reject_contact_t *rejc;
+ su_home_t *home;
+ char const *s;
+ int negate, error;
+ unsigned S, N;
+ union sip_pref sp[1], a[1];
+ sip_contact_t *m, *m0, *m1, *m2;
+
+ BEGIN();
+
+ TEST_1(home = su_home_new(sizeof *home));
+
+ TEST_1(!sip_is_callerpref("attendant"));
+ TEST_1(sip_is_callerpref("audio"));
+ TEST_1(sip_is_callerpref("automata"));
+ TEST_1(sip_is_callerpref("class"));
+ TEST_1(sip_is_callerpref("duplex"));
+ TEST_1(sip_is_callerpref("data"));
+ TEST_1(sip_is_callerpref("control"));
+ TEST_1(sip_is_callerpref("mobility"));
+ TEST_1(sip_is_callerpref("description"));
+ TEST_1(sip_is_callerpref("events"));
+ TEST_1(sip_is_callerpref("priority"));
+ TEST_1(sip_is_callerpref("methods"));
+ TEST_1(sip_is_callerpref("schemes"));
+ TEST_1(sip_is_callerpref("application"));
+ TEST_1(sip_is_callerpref("video"));
+ TEST_1(sip_is_callerpref("actor"));
+ TEST_1(!sip_is_callerpref("+actor"));
+ TEST_1(!sip_is_callerpref("msgserver"));
+ TEST_1(sip_is_callerpref("language"));
+ TEST_1(sip_is_callerpref("isfocus"));
+ TEST_1(sip_is_callerpref("type"));
+ TEST_1(!sip_is_callerpref("uri-user"));
+ TEST_1(!sip_is_callerpref("uri-domain"));
+ TEST_1(!sip_is_callerpref(NULL));
+ TEST_1(sip_is_callerpref("+"));
+ TEST_1(sip_is_callerpref("+foo"));
+
+ /* Booleans (treated as literals) */
+ s = "TRUE";
+ negate = 2; memset(sp, 0, sizeof sp);
+ TEST_1(sip_prefs_parse(sp, &s, &negate));
+ TEST(sp->sp_type, sp_literal);
+ TEST_S(sp->sp_literal.spl_value, "TRUE"); TEST_1(!negate);
+ TEST_1(sip_prefs_match(sp, sp));
+ TEST_1(!sip_prefs_parse(sp, &s, &negate));
+ TEST(sp->sp_type, sp_init);
+
+ s = "FALSE";
+ negate = 2; memset(sp, 0, sizeof sp);
+ TEST_1(sip_prefs_parse(sp, &s, &negate));
+ TEST(sp->sp_type, sp_literal);
+ TEST_S(sp->sp_literal.spl_value, "FALSE"); TEST_1(!negate);
+ TEST_1(sip_prefs_match(sp, sp));
+ TEST_1(!sip_prefs_parse(sp, &s, &negate));
+ TEST(sp->sp_type, sp_init);
+
+ s = "\"!TRUE,!FALSE\""; negate = 0;
+ TEST_1(sip_prefs_parse(sp, &s, &negate));
+ TEST(sp->sp_type, sp_literal); TEST_1(negate);
+
+ /* Literal */
+ s = "\" !oukki , doukki \""; negate = 0; memset(sp, 0, sizeof sp);
+
+ TEST_1(sip_prefs_parse(sp, &s, &negate));
+ TEST(sp->sp_type, sp_literal);
+ TEST_SIZE(sp->sp_literal.spl_length, 5);
+ TEST_M(sp->sp_literal.spl_value, "oukki", 5); TEST_1(negate);
+
+ TEST_1(sip_prefs_parse(sp, &s, &negate));
+ TEST(sp->sp_type, sp_literal);
+ TEST_SIZE(sp->sp_literal.spl_length, 6);
+ TEST_M(sp->sp_literal.spl_value, "doukki", 6); TEST_1(!negate);
+
+ TEST_1(!sip_prefs_parse(sp, &s, &negate));
+ TEST(sp->sp_type, sp_init);
+
+ /* Strings */
+ s = "\" !<oukki> , <douK\\\"ki >\"";
+ negate = 0; memset(sp, 0, sizeof sp);
+
+ TEST_1(sip_prefs_parse(sp, &s, &negate));
+ TEST(sp->sp_type, sp_string);
+ TEST_SIZE(sp->sp_string.sps_length, 5);
+ TEST_M(sp->sp_string.sps_value, "oukki", 5); TEST_1(negate);
+
+ TEST_1(sip_prefs_parse(sp, &s, &negate));
+ TEST(sp->sp_type, sp_string);
+ TEST_SIZE(sp->sp_string.sps_length, 10);
+ TEST_M(sp->sp_string.sps_value, "douK\\\"ki ", 10); TEST_1(!negate);
+
+ TEST_1(!sip_prefs_parse(sp, &s, &negate));
+ TEST(sp->sp_type, sp_init);
+
+ /* Numeric */
+ s = "\" !#=6, #<=3, #>=6, !#<=6, #1:6.5\"";
+ negate = 0; memset(sp, 0, sizeof sp);
+
+ TEST_1(sip_prefs_parse(sp, &s, &negate));
+ TEST(sp->sp_type, sp_range);
+ TEST_D(sp->sp_range.spr_lower, 6.0);
+ TEST_D(sp->sp_range.spr_upper, 6.0);
+ TEST_1(sip_prefs_match(sp, sp));
+ TEST_1(negate);
+
+ *a = *sp;
+
+ TEST_1(sip_prefs_parse(sp, &s, &negate));
+ TEST(sp->sp_type, sp_range);
+ TEST_D(sp->sp_range.spr_lower, DBL_MIN);
+ TEST_D(sp->sp_range.spr_upper, 3.0);
+ TEST_1(sip_prefs_match(sp, sp));
+ TEST_1(!negate);
+
+ TEST_1(!sip_prefs_match(a, sp));
+
+ TEST_1(sip_prefs_parse(sp, &s, &negate));
+ TEST(sp->sp_type, sp_range);
+ TEST_D(sp->sp_range.spr_lower, 6.0);
+ TEST_D(sp->sp_range.spr_upper, DBL_MAX);
+ TEST_1(sip_prefs_match(sp, sp));
+ TEST_1(!negate);
+
+ TEST_1(sip_prefs_match(a, sp));
+
+ TEST_1(sip_prefs_parse(sp, &s, &negate));
+ TEST(sp->sp_type, sp_range);
+ TEST_D(sp->sp_range.spr_lower, DBL_MIN);
+ TEST_D(sp->sp_range.spr_upper, 6.0);
+ TEST_1(sip_prefs_match(sp, sp));
+ TEST_1(negate);
+
+ TEST_1(sip_prefs_match(a, sp));
+
+ TEST_1(sip_prefs_parse(sp, &s, &negate));
+ TEST(sp->sp_type, sp_range);
+ TEST_D(sp->sp_range.spr_lower, 1.0);
+ TEST_D(sp->sp_range.spr_upper, 6.5);
+ TEST_1(sip_prefs_match(sp, sp));
+ TEST_1(!negate);
+
+ TEST_1(sip_prefs_match(a, sp));
+
+ TEST_1(!sip_prefs_parse(sp, &s, &negate));
+ TEST(sp->sp_type, sp_init);
+
+ error = 12;
+
+ TEST_1(sip_prefs_matching("\"INVITE,MESSAGE,SUBSCRIBE\"",
+ "\"INVITE\"", &error));
+ TEST_1(!sip_prefs_matching("\"INVITE,MESSAGE,SUBSCRIBE\"",
+ "\"BYE\"", &error));
+ TEST(error, 12);
+ TEST_1(sip_prefs_matching("\"INVITE,MESSAGE,SUBSCRIBE\"",
+ "\"invite\"", &error));
+ TEST_1(sip_prefs_matching("\"!INVITE,MESSAGE,SUBSCRIBE\"",
+ "\"foo\"", &error));
+ TEST_1(sip_prefs_matching("TRUE", "", &error));
+ TEST_1(sip_prefs_matching("", "", &error));
+ TEST_1(!sip_prefs_matching("FALSE", "", &error));
+ TEST(error, 12);
+ TEST_1(sip_prefs_matching("FALSE", "FALSE", &error));
+
+ /* Lax when receiving... */
+ TEST_1(sip_prefs_matching("\"FALSE\"", "FALSE", &error)); /* XXX */
+ TEST_1(sip_prefs_matching("\"TRUE\"", "TRUE", &error)); /* XXX */
+
+ TEST_1(!sip_prefs_matching("\"!INVITE\"", "\"INVITE\"", &error));
+ TEST_1(!sip_prefs_matching("\"!INVITE\"", "\"invite\"", &error));
+ TEST_1(sip_prefs_matching("\"!<INVITE>\"", "\"<invite>\"", &error));
+ TEST_1(!sip_prefs_matching("\"INVITE\"", "\"!INVITE\"", &error));
+ TEST_1(sip_prefs_matching("\"!INVITE\"", "\"INVITE,MESSAGE\"", &error));
+ TEST_1(sip_prefs_matching("\"!INVITE,!MESSAGE\"",
+ "\"INVITE,MESSAGE\"", &error));
+ TEST_1(sip_prefs_matching("\"!MESSAGE\"", "\"INVITE,MESSAGE\"", &error));
+ TEST_1(!sip_prefs_matching("\"<foo>,<bar>\"",
+ "\"<FOO>,<BAR>\"", &error));
+ TEST_1(!sip_prefs_matching("\"<FOO>,<BAR>\"", "\"foo,bar\"", &error));
+ TEST_1(sip_prefs_matching("\"#=1\"", "\"#<=2\"", &error));
+ TEST_1(sip_prefs_matching("\"#1:2\"", "\"#<=2\"", &error));
+ TEST_1(!sip_prefs_matching("\"#1:2\"", "\"!#>=1,!#<=2\"", &error));
+ TEST_1(!sip_prefs_matching("\"#=0,#=1\"", "\"<FOO>,<BAR>\"", &error));
+ TEST(error, 12);
+
+ error = 12;
+ TEST_1(!sip_prefs_matching("\"<foo>,#=1\"", "\"<FOO>,<BAR>\"", &error));
+ TEST(error, -1);
+
+ error = 12;
+ TEST_1(!sip_prefs_matching("\"<FOO>,<BAR>\"", "\"<foo>,#=1\"", &error));
+ TEST(error, -1);
+
+ error = 12;
+ TEST_1(!sip_prefs_matching("\"<foo>,bar\"", "\"<FOO>,<BAR>\"", &error));
+ TEST(error, -1);
+
+ error = 12;
+ TEST_1(!sip_prefs_matching("\"<FOO>,<BAR>\"", "\"<foo>,#12:12\"", &error));
+ TEST(error, -1);
+
+ {
+ char const *params[] = {
+ "methods=\"INVITE,MESSAGE,SUBSCRIBE\"",
+ "events=\"presence,presence.winfo\"",
+ "description=\"<PC>\"",
+ "language=\"!en,de\"",
+ "schemes=\"sip\"",
+ "+res-x=\"#=640\"",
+ "+res-y=\"#=480\"",
+ NULL
+ };
+
+ TEST_1(sip_is_callerpref(params[0]));
+ TEST_1(sip_is_callerpref(params[1]));
+ TEST_1(sip_is_callerpref(params[2]));
+ TEST_1(sip_is_callerpref(params[3]));
+ TEST_1(sip_is_callerpref(params[4]));
+ TEST_1(sip_is_callerpref(params[5]));
+ TEST_1(sip_is_callerpref(params[6]));
+ TEST_1(!sip_is_callerpref(params[7])); /* NULL */
+ TEST_1(!sip_is_callerpref("method=\"foo\""));
+ TEST_1(!sip_is_callerpref("+methods=\"foo\""));
+ }
+
+ TEST_1(m = sip_contact_make(home,
+ "<sip:1 at domain>;video;audio;type=\"<video/H263>\","
+ "<sip:2 at domain>;video=FALSE;audio;text,"
+ "<sip:3 at domain>;text;audio=FALSE"));
+
+ m0 = m, m1 = m->m_next, m2 = m->m_next->m_next;
+
+ TEST_1(ac = sip_accept_contact_make(home, "*;type=\"<video/H263>\";video"));
+ TEST_S(ac->cp_params[0], "type=\"<video/H263>\"");
+ TEST_S(ac->cp_params[1], "video");
+ TEST_P(ac->cp_params[2], NULL);
+
+ TEST_1(sip_contact_accept(m0, ac, &S, &N, &error)); TEST(S, 2); TEST(N, 2);
+ TEST_1(!sip_contact_accept(m1, ac, &S, &N, &error));
+ TEST_1(sip_contact_accept(m2, ac, &S, &N, &error)); TEST(S, 0); TEST(N, 2);
+
+ TEST_1(ac = sip_accept_contact_make(home, "sip:127.0.0.1:5060;video;audio"));
+ TEST_S(ac->cp_params[0], "video");
+ TEST_S(ac->cp_params[1], "audio");
+ TEST_P(ac->cp_params[2], NULL);
+
+ TEST_1(sip_contact_accept(m0, ac, &S, &N, &error)); TEST(S, 2); TEST(N, 2);
+ TEST_1(!sip_contact_accept(m1, ac, &S, &N, &error));
+ TEST_1(!sip_contact_accept(m2, ac, &S, &N, &error));
+
+ TEST_1(ac = sip_accept_contact_make(home,
+ "Joe the Luser "
+ "<sip:127.0.0.1:5060>;video;audio"));
+ TEST_S(ac->cp_params[0], "video");
+ TEST_S(ac->cp_params[1], "audio");
+ TEST_P(ac->cp_params[2], NULL);
+
+ TEST_1(ac = sip_accept_contact_make(home,
+ "video;audio;explicit"));
+ TEST_S(ac->cp_params[0], "video");
+ TEST_S(ac->cp_params[1], "audio");
+ TEST_S(ac->cp_params[2], "explicit");
+ TEST_P(ac->cp_params[3], NULL);
+
+ TEST_1(ac = sip_accept_contact_make(home,
+ "video = foo ;audio;explicit"));
+ TEST_S(ac->cp_params[0], "video=foo");
+ TEST_S(ac->cp_params[1], "audio");
+ TEST_S(ac->cp_params[2], "explicit");
+ TEST_P(ac->cp_params[3], NULL);
+
+ TEST_1(ac = sip_accept_contact_make(home,
+ "video = \"bar\" ;audio;explicit"));
+ TEST_S(ac->cp_params[0], "video=\"bar\"");
+ TEST_S(ac->cp_params[1], "audio");
+ TEST_S(ac->cp_params[2], "explicit");
+ TEST_P(ac->cp_params[3], NULL);
+
+ TEST_1(cp = sip_accept_contact_make(home,
+ "*;audio;video;require;explicit;q=1.0,"
+ "*;audio;require;q=0.8"
+ ));
+
+ TEST_1(ac = sip_accept_contact_dup(home, cp));
+
+ TEST_S(ac->cp_params[0], "audio");
+ TEST_S(ac->cp_params[1], "video");
+ TEST_S(ac->cp_params[2], "require");
+ TEST_S(ac->cp_params[3], "explicit");
+ TEST_S(ac->cp_params[4], "q=1.0");
+ TEST_P(ac->cp_params[5], NULL);
+
+ /* TEST_S(ac->cp_q, "1.0"); */
+ TEST(ac->cp_require, 1);
+ TEST(ac->cp_explicit, 1);
+
+ TEST_1(sip_contact_accept(m0, ac, &S, &N, &error)); TEST(S, 2); TEST(N, 2);
+ /* Explicit has short-circuit evaluation */
+ TEST_1(!sip_contact_accept(m1, ac, &S, &N, &error));
+ TEST_1(!sip_contact_accept(m2, ac, &S, &N, &error));
+
+ TEST_1(ac = ac->cp_next);
+
+ TEST_S(ac->cp_params[0], "audio");
+ TEST_S(ac->cp_params[1], "require");
+ TEST_S(ac->cp_params[2], "q=0.8");
+ TEST_P(ac->cp_params[3], NULL);
+
+ TEST(ac->cp_explicit, 0);
+
+ TEST_1(sip_contact_accept(m0, ac, &S, &N, &error)); TEST(S, 1); TEST(N, 1);
+ TEST_1(sip_contact_accept(m1, ac, &S, &N, &error)); TEST(S, 1); TEST(N, 1);
+ TEST_1(!sip_contact_accept(m2, ac, &S, &N, &error));
+
+ TEST_P(ac->cp_next, NULL);
+
+ TEST_1(rejc = sip_reject_contact_make(home,
+ "*;type=\"<video/H263>\";video=TRUE"));
+ TEST_S(rejc->cp_params[0], "type=\"<video/H263>\"");
+ TEST_S(rejc->cp_params[1], "video=TRUE");
+
+ TEST_1(sip_contact_reject(m0, rejc));
+ TEST_1(!sip_contact_reject(m1, rejc));
+ TEST_1(!sip_contact_reject(m2, rejc));
+
+ TEST_1(!sip_contact_immune(m0));
+ m0 = sip_contact_immunize(home, m0); TEST_1(m0);
+ TEST_1(sip_contact_immune(m0));
+
+ TEST_1(!sip_contact_immune(m1));
+ m1 = sip_contact_immunize(home, m1); TEST_1(m1);
+ TEST_1(sip_contact_immune(m1));
+
+ TEST_1(!sip_contact_immune(m2));
+ m2 = sip_contact_immunize(home, m2); TEST_1(m2);
+ TEST_1(sip_contact_immune(m2));
+
+ m = sip_contact_make(home, "<sip:test.domain>;+test;+audio");
+ TEST_1(!sip_contact_immune(m));
+ m1 = sip_contact_immunize(home, m); TEST_1(m1);
+ TEST_1(sip_contact_immune(m1));
+
+ TEST_S(m->m_params[0], "+test");
+ TEST_S(m->m_params[1], "+audio");
+ TEST_P(m->m_params[2], NULL);
+
+ TEST_S(m1->m_params[0], "+audio");
+ TEST_P(m1->m_params[1], NULL);
+
+ TEST_1(ac = sip_accept_contact_make(home, "*;q=0.9;require;explicit"));
+ /* TEST_S(ac->cp_q, "0.9"); */
+ TEST_1(ac->cp_require);
+ TEST_1(ac->cp_explicit);
+
+ TEST(msg_header_remove_param(ac->cp_common, "Q"), 1);
+ /* TEST(ac->cp_q, NULL); */
+ TEST(msg_header_remove_param(ac->cp_common, "require="), 1);
+ TEST(ac->cp_require, 0);
+ TEST(msg_header_remove_param(ac->cp_common, "require="), 0);
+ TEST(ac->cp_require, 0);
+ TEST(msg_header_remove_param(ac->cp_common, "explicit=true"), 1);
+ TEST(ac->cp_explicit, 0);
+ TEST(msg_header_replace_param(home, ac->cp_common, "explicit=true"), 0);
+ TEST(ac->cp_explicit, 1);
+
+ su_home_zap(home);
+
+ END();
+}
+
+
+static int test_callerpref_scoring(void)
+{
+ sip_accept_contact_t *ac;
+ sip_reject_contact_t *rejc;
+ su_home_t *home;
+ int S;
+ sip_contact_t *m, *m1, *m2, *m3, *m4, *m5;
+
+ char const contact[] =
+ "sip:u1 at h.example.com;audio;video;methods=\"INVITE,BYE\";q=0.2,"
+ "sip:u2 at h.example.com;audio=\"FALSE\";"
+ "methods=\"INVITE\";actor=\"msg-taker\";q=0.2,"
+ "sip:u3 at h.example.com;audio;actor=\"msg-taker\";"
+ "methods=\"INVITE\";video;q=0.3,"
+ "sip:u4 at h.example.com;audio;methods=\"INVITE,OPTIONS\";q=0.2,"
+ "sip:u5 at h.example.com;q=0.5";
+
+ char const reject[] =
+ "*;actor=\"msg-taker\";video";
+
+ char const accept[] =
+ "*;audio;require,"
+ "*;video;explicit,"
+ "*;methods=\"BYE\";class=\"business\";q=1.0";
+
+ BEGIN();
+
+ TEST_1(home = su_home_new(sizeof *home));
+
+ TEST_1(m = sip_contact_make(home, contact));
+ m1 = m, m2 = m->m_next, m3 = m->m_next->m_next, m4 = m->m_next->m_next->m_next,
+ m5 = m->m_next->m_next->m_next->m_next;
+ TEST_1(rejc = sip_reject_contact_make(home, reject));
+ TEST_1(ac = sip_accept_contact_make(home, accept));
+
+ S = sip_contact_score(m1, ac, rejc); TEST(S, 1000 * 5 / 6 + 1);
+ S = sip_contact_score(m2, ac, rejc); TEST(S, 0);
+ S = sip_contact_score(m3, ac, rejc); TEST_1(S < 0);
+ S = sip_contact_score(m4, ac, rejc); TEST(S, 1000 / 2);
+ S = sip_contact_score(m5, ac, rejc); TEST(S, 1000);
+
+ su_home_zap(home);
+
+ END();
+}
+
+static int test_reason(void)
+{
+ sip_reason_t *re;
+ su_home_t *home;
+ msg_t *msg;
+ sip_t *sip;
+
+ BEGIN();
+
+ TEST_1(home = su_home_create());
+
+ TEST_1((re = sip_reason_make(home, "SIP;cause=200;text=\"Ok\"")));
+ TEST_S(re->re_protocol, "SIP");
+ TEST_S(re->re_cause, "200");
+ TEST_S(re->re_text, "\"Ok\"");
+
+ msg = read_message(MSG_DO_EXTRACT_COPY,
+ "BYE sip:foo at bar SIP/2.0\r\n"
+ "To: <sip:foo at bar>;tag=deadbeef\r\n"
+ "From: <sip:bar at foo>;\r\n"
+ "Call-ID: 0ha0isndaksdj at 10.1.2.3\r\n"
+ "CSeq: 8 SUBSCRIBE\r\n"
+ "Via: SIP/2.0/UDP 135.180.130.133\r\n"
+ "Reason: SIP ;cause=200 ;text=\"Call completed elsewhere\"\r\n"
+ "Reason: Q.850 ;cause=16 ;text=\"Terminated\"\r\n ,,"
+ "SIP ; cause = 600 ;text\t\r\n = \"Busy Everywhere\" \t \r\n"
+ "Reason: SIP ;cause=580 ;text=\"Precondition Failure\"\r\n"
+ "Content-Length: 0\r\n"
+ "\r\n");
+
+ sip = sip_object(msg);
+
+ TEST_1(msg);
+ TEST_1(sip);
+ TEST_1(re = sip->sip_reason);
+ TEST_S(re->re_protocol, "SIP");
+ TEST_S(re->re_cause, "200");
+ TEST_S(re->re_text, "\"Call completed elsewhere\"");
+ TEST_1(re = re->re_next);
+ TEST_S(re->re_protocol, "Q.850");
+ TEST_S(re->re_cause, "16");
+ TEST_S(re->re_text, "\"Terminated\"");
+ TEST_1(re = re->re_next);
+ TEST_S(re->re_protocol, "SIP");
+ TEST_S(re->re_cause, "600");
+ TEST_S(re->re_text, "\"Busy Everywhere\"");
+ TEST_1(re = re->re_next);
+ TEST_S(re->re_protocol, "SIP");
+ TEST_S(re->re_cause, "580");
+ TEST_S(re->re_text, "\"Precondition Failure\"");
+ TEST_1(!(re = re->re_next));
+
+ TEST_1(re = sip->sip_reason);
+ TEST(msg_header_replace_param(home, re->re_common, "cause=202"), 1);
+ TEST_S(re->re_cause, "202");
+ TEST(msg_header_replace_param(home, re->re_common, "text=\"foo\""), 1);
+ TEST_S(re->re_text, "\"foo\"");
+ TEST(msg_header_remove_param(re->re_common, "cause=444"), 1);
+ TEST_P(re->re_cause, NULL);
+ TEST(msg_header_remove_param(re->re_common, "text=\"bar\""), 1);
+ TEST_P(re->re_text, NULL);
+ TEST(msg_header_remove_param(re->re_common, "cause=444"), 0);
+ TEST(msg_header_remove_param(re->re_common, "text=\"bar\""), 0);
+
+ /* Not a token */
+ TEST_1(!sip_reason_make(home, "\"nSIP\";cause=200;text=\"Ok\""));
+ /* Empty list */
+ TEST_1(!sip_reason_make(home, ","));
+ /* no protocol token */
+ TEST_1(!sip_reason_make(home, "cause=16;text=\"call cleared\""));
+
+ /* Empty parameter */
+ TEST_1(!sip_reason_make(home, "SIP;cause=200;;text=\"Ok\""));
+ /* no semicolon after token */
+ TEST_1(!sip_reason_make(home, "SIP cause=200;text=\"Ok\""));
+ /* extra semicolon after parameters */
+ TEST_1(!sip_reason_make(home, "SIP ;cause=200;text=\"Ok\";"));
+
+ su_home_unref(home);
+ msg_destroy(msg), msg = NULL;
+
+ END();
+}
+
+static int test_warning(void)
+{
+ sip_warning_t *w;
+ su_home_t *home;
+
+ BEGIN();
+
+ TEST_1(home = su_home_create());
+
+ TEST_1((w = sip_warning_make(home,
+ "399 host:5060 \"Ok\", "
+ "399 [::1]:39999 \"foo\\\" bar\"")));
+ TEST(w->w_code, 399);
+ TEST_S(w->w_host, "host");
+ TEST_S(w->w_port, "5060");
+ TEST_S(w->w_text, "Ok");
+ TEST_1(w = w->w_next);
+
+ TEST(w->w_code, 399);
+ TEST_S(w->w_host, "[::1]");
+ TEST_S(w->w_port, "39999");
+ TEST_S(w->w_text, "foo\" bar");
+ TEST_1(w->w_next == NULL);
+
+ TEST_S(sip_header_as_string(home, (sip_header_t *)w),
+ "399 [::1]:39999 \"foo\\\" bar\"");
+
+ su_home_unref(home);
+
+ END();
+}
+
+
+static int test_sec_ext(void)
+{
+ su_home_t *home;
+
+ sip_security_client_t *sac;
+ sip_security_server_t *sas;
+ sip_security_verify_t *sav;
+ sip_privacy_t *priv;
+
+ msg_t *msg;
+ sip_t *sip;
+
+ BEGIN();
+
+ msg = read_message(MSG_DO_EXTRACT_COPY,
+ "BYE sip:foo at bar SIP/2.0\r\n"
+ "To: <sip:foo at bar>;tag=deadbeef\r\n"
+ "From: <sip:bar at foo>;\r\n"
+ "Call-ID: 0ha0isndaksdj at 10.1.2.3\r\n"
+ "CSeq: 8 SUBSCRIBE\r\n"
+ "Via: SIP/2.0/UDP 135.180.130.133\r\n"
+ "Content-Length: 0\r\n"
+ "\r\n");
+
+ sip = sip_object(msg);
+
+ TEST_1(home = msg_home(msg));
+
+ TEST_1(sac = sip_security_client_make(home, "digest;q=0.5,ipsec-3gpp"));
+ TEST_S(sac->sa_mec, "digest");
+ TEST_S(sac->sa_q, "0.5");
+ TEST_1(sac = sac->sa_next);
+ TEST_S(sac->sa_mec, "ipsec-3gpp");
+
+ TEST_1((sas = sip_security_server_make(home, "digest;q=0.5")));
+ TEST_S(sas->sa_mec, "digest");
+ TEST_S(sas->sa_q, "0.5");
+
+ TEST_1((sav = sip_security_verify_make(home, "digest;q=0.5")));
+ TEST_S(sav->sa_mec, "digest");
+ TEST_S(sav->sa_q, "0.5");
+
+ TEST_1((sav = sip_security_verify_make
+ (home, "digest;q=0.1;d-alg=SHA1;d-qop=auth;"
+ "d-ver=\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"")));
+ TEST_S(sav->sa_mec, "digest");
+ TEST_S(sav->sa_q, "0.1");
+ TEST_S(sav->sa_d_alg, "SHA1");
+ TEST_S(sav->sa_d_qop, "auth");
+ TEST_S(sav->sa_d_ver, "\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"");
+
+ /* Test for accepting liberally.. */
+ TEST_1(priv = sip_privacy_make(home, "header,media"));
+ TEST_1(priv = sip_privacy_make(home, ";header;media"));
+
+ TEST_1(!(priv = sip_privacy_make(home, "none explicit")));
+
+ TEST_1((priv = sip_privacy_make(home, "header;media")));
+ TEST_1(priv->priv_values);
+ TEST_S(priv->priv_values[0], "header");
+ TEST_S(priv->priv_values[1], "media");
+
+ msg_destroy(msg);
+
+ END();
+}
+
+
+static int test_utils(void)
+{
+ sip_from_t *f;
+ su_home_t *home;
+ sip_security_server_t *secs;
+ sip_security_verify_t *secv;
+ msg_param_t d_ver = NULL;
+
+ BEGIN();
+
+ TEST_1(home = su_home_new(sizeof *home));
+ TEST_1(f = sip_from_make(home, "<sip:u:p at h.com:5555"
+ ";ttl=1;user=IP;maddr=::1;lr=TRUE;transport=TCP"
+ ";test=1?accept-contact=*;audio;video;explicit>"));
+ TEST_1(sip_aor_strip(f->a_url) == 0);
+ TEST_1(f->a_url->url_port == NULL);
+ TEST_S(f->a_url->url_params, "user=IP;test=1");
+ TEST_1(f->a_url->url_headers == NULL);
+
+ TEST_1(f = sip_from_make(home, "<sip:u:p at h.com:5555;ttl=1>"));
+ TEST_1(sip_aor_strip(f->a_url) == 0);
+ TEST_1(f->a_url->url_params == NULL);
+
+ TEST_1(f = sip_from_make(home, "<sip:u:p at h.com:5555;test=1;ttl=1>"));
+ TEST_1(sip_aor_strip(f->a_url) == 0);
+ TEST_S(f->a_url->url_params, "test=1");
+
+ TEST_1(f = sip_from_make(home, "<sip:u:p at h.com:5555;;test=1;>"));
+ TEST_1(sip_aor_strip(f->a_url) == 0);
+ TEST_S(f->a_url->url_params, "test=1");
+
+ TEST_1(secs = sip_security_server_make(home, "Digest"));
+ TEST_1(secv =
+ sip_security_verify_make(home,
+ "Digest;"
+ "d-ver=\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\""));
+
+ TEST_1(sip_security_verify_compare(secs, secv, &d_ver) == 0);
+ TEST_S(d_ver, "\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"");
+
+ TEST_1(secs =
+ sip_security_server_make(home,
+ "TLS;q=1,"
+ "Digest;q=0.1;"
+ "d-alg=MD5;d-qop=\"auth,auth-int\","
+ "Digest;d-alg=AKA-MD5;q=0.9"
+ ));
+ TEST_1(secv =
+ sip_security_verify_make(home,
+ "TLS;q=1,"
+ "Digest ; q = 0.1;"
+ "d-ver=\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\";"
+ "d-alg = MD5 ; d-qop = \"auth,auth-int\","
+ "Digest ; d-alg=AKA-MD5;q=0.9"));
+
+ TEST_1(sip_security_verify_compare(secs, secv, &d_ver) == 0);
+ TEST_S(d_ver, "\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"");
+
+ TEST_1(sip_security_verify_compare(secs->sa_next, secv, &d_ver) != 0);
+ TEST_1(sip_security_verify_compare(secs, secv->sa_next, &d_ver) != 0);
+ d_ver = "kuik";
+ TEST_1(sip_security_verify_compare(secs->sa_next, secv->sa_next, &d_ver)
+ == 0);
+ TEST_S(d_ver, "\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"");
+ d_ver = "kuik";
+ TEST_1(sip_security_verify_compare(secs->sa_next->sa_next,
+ secv->sa_next->sa_next, &d_ver)
+ == 0);
+ TEST_1(d_ver == NULL);
+
+ END();
+}
+
+void usage(void)
+{
+ fprintf(stderr,
+ "usage: %s [-v]\n",
+ name);
+}
+
+char *lastpart(char *path)
+{
+ if (strchr(path, '/'))
+ return strrchr(path, '/') + 1;
+ else
+ return path;
+}
+
+int main(int argc, char *argv[])
+{
+ int retval = 0;
+ int i;
+
+ name = lastpart(argv[0]); /* Set our name */
+
+ for (i = 1; argv[i]; i++) {
+ if (strcmp(argv[i], "-v") == 0)
+ tstflags |= tst_verbatim;
+ else
+ usage();
+ }
+
+ if (!test_mclass)
+ test_mclass = msg_mclass_clone(sip_default_mclass(), 0, 0);
+
+ retval |= test_url_headers(); fflush(stdout);
+ retval |= test_manipulation(); fflush(stdout);
+ retval |= test_methods(); fflush(stdout);
+ retval |= test_basic(); fflush(stdout);
+ retval |= test_sip_msg_class(test_mclass); fflush(stdout);
+ retval |= test_encoding(); fflush(stdout);
+ retval |= test_events(); fflush(stdout);
+ retval |= test_reason(); fflush(stdout);
+ retval |= tag_test(); fflush(stdout);
+ retval |= parser_tag_test(); fflush(stdout);
+ retval |= response_phrase_test(); fflush(stdout);
+ retval |= parser_test(); fflush(stdout);
+ retval |= sip_header_test(); fflush(stdout);
+ retval |= test_bad_packet(); fflush(stdout);
+ retval |= test_sip_list_header(); fflush(stdout);
+ retval |= test_prack(); fflush(stdout);
+ retval |= test_accept(); fflush(stdout);
+ retval |= test_content_disposition(); fflush(stdout);
+ retval |= test_features(); fflush(stdout);
+ retval |= test_retry_after(); fflush(stdout);
+ retval |= test_session_expires(); fflush(stdout);
+ retval |= test_min_se(); fflush(stdout);
+ retval |= test_refer(); fflush(stdout);
+ retval |= test_route(); fflush(stdout);
+ retval |= test_request_disposition(); fflush(stdout);
+ retval |= test_caller_prefs(); fflush(stdout);
+ retval |= test_callerpref_scoring(); fflush(stdout);
+ retval |= test_warning(); fflush(stdout);
+
+ retval |= test_sec_ext(); fflush(stdout);
+
+ retval |= test_utils(); fflush(stdout);
+
+ return retval;
+}
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/validator.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/validator.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,645 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@IFILE validator.c
+ *
+ * SIP parser tester. This uses output
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Wed Mar 21 19:12:13 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <assert.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifndef _WIN32
+#include <sys/mman.h>
+#endif
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <sofia-sip/su_types.h>
+#include <sofia-sip/su_alloc_stat.h>
+
+#include <sofia-sip/su_time.h>
+
+#include <sofia-sip/su_tag.h>
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/su_tag_io.h>
+
+#include <sofia-sip/sip_tag.h>
+#include <sofia-sip/url_tag.h>
+
+#include <sofia-sip/sip.h>
+#include <sofia-sip/sip_header.h>
+
+#include <sofia-sip/msg_buffer.h>
+
+char const *name = "validator";
+
+typedef struct {
+ unsigned o_verbose : 1; /**< Be verbose */
+ unsigned o_very_verbose : 1; /**< Be very verbose */
+ unsigned o_requests : 1; /**< Only requests */
+ unsigned o_responses : 1; /**< Only responses */
+ unsigned o_decode : 1; /**< Only try to decode,
+ print error if unknown headers */
+ unsigned o_print : 1; /**< Print whole message */
+ unsigned o_times : 1; /**< Generate timing information */
+ unsigned o_memstats : 1; /**< Generate memory statistics */
+ unsigned o_histogram : 1; /**< Generate histograms */
+ unsigned o_sipstats : 1; /**< Generate header statistics */
+ unsigned o_vsipstats : 1; /**< Generate verbatim header statistics */
+ unsigned : 0;
+ unsigned o_flags; /**< Message flags */
+} options_t;
+
+typedef struct {
+ size_t N;
+ uint32_t bsize;
+ double buckets[32768];
+} histogram_t;
+
+static
+histogram_t *histogram_create(uint64_t max, uint32_t bsize)
+{
+ size_t N = (max + bsize - 1) / bsize;
+ histogram_t *h = calloc(1, offsetof(histogram_t, buckets[N + 1]));
+ if (!h) { perror("calloc"); exit(1); }
+ h->N = N, h->bsize = bsize;
+ return h;
+}
+
+static
+double *histogram_update(histogram_t *h, uint32_t n)
+{
+ if (h->bsize > 1)
+ n /= h->bsize;
+
+ if (n < h->N)
+ return &h->buckets[n];
+ else
+ return &h->buckets[h->N];
+}
+
+static void
+histogram_div(histogram_t *h, histogram_t const *n)
+{
+ size_t i;
+ assert(h->N == n->N); assert(h->bsize == n->bsize);
+
+ for (i = 0; i <= h->N; i++) {
+ if (n->buckets[i]) {
+ h->buckets[i] /= n->buckets[i];
+ }
+ else {
+ assert(h->buckets[i] == 0);
+ }
+ }
+}
+
+typedef struct {
+ uint64_t number;
+ uint64_t headers;
+ uint64_t payloads;
+ uint64_t pl_bytes;
+} sipstat_t;
+
+typedef struct {
+ sipstat_t req, resp;
+ histogram_t *hist_headers;
+} sipstats_t;
+
+typedef struct {
+ char const *name;
+ char const *sep;
+ uint64_t messages;
+ uint64_t bytes;
+ uint64_t errors;
+ uint32_t files;
+ double time;
+ options_t options[1];
+
+ /* Statistics */
+ histogram_t *hist_msgsize;
+ histogram_t *hist_mallocs;
+ histogram_t *hist_memsize;
+ histogram_t *hist_nheaders;
+ sipstats_t sipstats[1];
+ su_home_stat_t hs[1];
+
+ uint64_t est_fail, est_succ, est_slack;
+} context_t;
+
+void usage(void)
+{
+ fprintf(stderr,
+ "usage: %s [-vdp]\n",
+ name);
+ exit(2);
+}
+
+char *lastpart(char *path)
+{
+ char *p = strrchr(path, '/');
+
+ if (p)
+ return p + 1;
+ else
+ return path;
+}
+
+msg_mclass_t *mclass = NULL;
+
+int validate_file(int fd, char const *name, context_t *ctx);
+int validate_dump(char *, off_t, context_t *ctx);
+int report(context_t const *ctx);
+static void memstats(msg_t *, uint32_t msize, context_t *ctx);
+static void sipstats(msg_t *, uint32_t msize, sipstats_t *ss, context_t *ctx);
+
+int main(int argc, char *argv[])
+{
+ context_t ctx[1] = {{ 0 }};
+ options_t *o = ctx->options;
+
+ name = lastpart(argv[0]); /* Set our name */
+
+ for (; argv[1]; argv++) {
+ if (argv[1][0] == 0)
+ usage();
+ else if (argv[1][0] != '-')
+ break;
+ else if (argv[1][1] == 0) {
+ argv++; break;
+ }
+ else if (strcmp(argv[1], "-v") == 0)
+ o->o_very_verbose = o->o_verbose, o->o_verbose = 1;
+ else if (strcmp(argv[1], "-d") == 0)
+ o->o_decode = 1; /* Decode only */
+ else if (strcmp(argv[1], "-p") == 0)
+ o->o_print = 1;
+ else if (strcmp(argv[1], "-q") == 0)
+ o->o_requests = 1;
+ else if (strcmp(argv[1], "-Q") == 0)
+ o->o_responses = 1;
+ else if (strcmp(argv[1], "-t") == 0)
+ o->o_times = 1;
+ else if (strcmp(argv[1], "-m") == 0)
+ o->o_memstats = 1;
+ else if (strcmp(argv[1], "-s") == 0)
+ o->o_vsipstats = o->o_sipstats, o->o_sipstats = 1;
+ else if (strcmp(argv[1], "-h") == 0)
+ o->o_histogram = 1;
+ else
+ usage();
+ }
+
+ if (o->o_requests && o->o_responses)
+ usage();
+
+ if (!mclass)
+ mclass = sip_default_mclass();
+
+ if (argv[1]) {
+ for (; argv[1]; argv++) {
+ int fd = open(argv[1], O_RDONLY, 000);
+ if (fd == -1)
+ perror(argv[1]), exit(1);
+ if (validate_file(fd, argv[1], ctx))
+ exit(1);
+ close(fd);
+ }
+ }
+ else
+ validate_file(0, "", ctx);
+
+ report(ctx);
+
+ exit(0);
+}
+
+
+int validate_file(int fd, char const *name, context_t *ctx)
+{
+ void *p;
+ off_t size;
+ int retval;
+
+ ctx->name = name;
+ if (strlen(name))
+ ctx->sep = ": ";
+ else
+ ctx->sep = "";
+
+ ctx->files++;
+
+ size = lseek(fd, 0, SEEK_END);
+
+ if (size < 1)
+ return 0;
+ if (size > INT_MAX) {
+ fprintf(stderr, "%s%stoo large file to map\n", ctx->name, ctx->sep);
+ return -1;
+ }
+
+#ifndef _WIN32
+ p = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0L);
+ if (p == NULL) {
+ perror("mmap");
+ return -1;
+ }
+
+ retval = validate_dump(p, size, ctx);
+ munmap(p, size);
+ return retval;
+
+#else
+ errno = EINVAL;
+ perror("mmap not implemented");
+ return -1;
+#endif
+
+}
+
+static inline
+void nul_terminate(char *b, off_t size)
+{
+ char *end;
+
+ /* NUL-terminate */
+ for (end = b + size - 1; end != b; end--)
+ if (*end == '\v')
+ break;
+
+ *end = '\0';
+}
+
+static inline
+int search_msg(char **bb, char const *protocol)
+{
+ int linelen, plen = strlen(protocol);
+ char *b = *bb;
+
+ for (;;) {
+ if (!b[0])
+ return 0;
+
+ if (strncmp(b, protocol, plen) == 0 && b[plen] == ' ')
+ return 1; /* status */
+
+ linelen = strcspn(b, "\r\n");
+
+ if (linelen > plen + 1 &&
+ b[linelen - plen - 1] == ' ' &&
+ strncmp(b + linelen - plen, protocol, plen) == 0)
+ return 1; /* request */
+
+ b += linelen + strspn(b + linelen, "\r\n");
+ *bb = b;
+ }
+}
+
+int validate_dump(char *b, off_t size, context_t *ctx)
+{
+ size_t n = 0, N = 0;
+ struct message {
+ char *b;
+ int size;
+ } *msgs = NULL;
+ uint64_t time0, time1;
+ options_t *o = ctx->options;
+ int maxsize = 0;
+
+ nul_terminate(b, size);
+
+ /* Split dump file to messages */
+ while (search_msg(&b, SIP_VERSION_CURRENT)) {
+ int msize = strcspn(b, "\v");
+ int linelen = strcspn(b, "\r\n");
+
+ if (o->o_responses &&
+ memcmp(b, SIP_VERSION_CURRENT, strlen(SIP_VERSION_CURRENT)) != 0)
+ ;
+ else if (o->o_requests &&
+ memcmp(b, SIP_VERSION_CURRENT, strlen(SIP_VERSION_CURRENT)) == 0)
+ ;
+ else {
+ if (o->o_very_verbose)
+ printf("message "MOD_ZU": %.*s\n", n, linelen, b);
+
+ if (n == N) {
+ N *= 2; if (n == N) N = 16;
+
+ msgs = realloc(msgs, sizeof(*msgs) * N);
+ if (msgs == NULL) {
+ perror("realloc");
+ exit(1);
+ }
+ }
+ msgs[n].b = b; msgs[n].size = msize;
+ n++;
+
+ ctx->bytes += msize;
+
+ if (msize > maxsize)
+ maxsize = msize;
+ }
+
+ b += msize; if (*b) *b++ = '\0';
+ }
+
+ ctx->messages += N = n;
+
+ if (o->o_histogram) {
+ ctx->hist_msgsize = histogram_create(maxsize, 64);
+
+ if (o->o_memstats) {
+ ctx->hist_mallocs = histogram_create(maxsize, 64);
+ ctx->hist_memsize = histogram_create(maxsize, 64);
+ }
+
+ if (o->o_sipstats) {
+ ctx->sipstats->hist_headers = histogram_create(64, 1);
+ ctx->hist_nheaders = histogram_create(maxsize, 64);
+ }
+ }
+
+ time0 = su_nanocounter();
+
+ for (n = 0; n < N; n++) {
+ msg_t *msg = msg_create(mclass, o->o_flags);
+ int m;
+
+ if (msg == NULL) {
+ perror("msg_create"); exit(1);
+ }
+
+ if (o->o_memstats)
+ su_home_init_stats(msg_home(msg));
+
+ msg_buf_set(msg, msgs[n].b, msgs[n].size + 1);
+ msg_buf_commit(msg, msgs[n].size, 1);
+
+ su_home_preload(msg_home(msg), 1, msgs[n].size + 384);
+
+ m = msg_extract(msg);
+
+ if (m < 0) {
+ fprintf(stderr, "%s%sparsing error in message "MOD_ZU"\n",
+ ctx->name, ctx->sep, n);
+ ctx->errors++;
+ }
+ else {
+ if (ctx->hist_msgsize)
+ *histogram_update(ctx->hist_msgsize, msgs[n].size) += 1;
+
+ if (o->o_sipstats)
+ sipstats(msg, msgs[n].size, ctx->sipstats, ctx);
+
+ if (o->o_memstats)
+ memstats(msg, msgs[n].size, ctx);
+ }
+
+ msg_destroy(msg);
+ }
+
+ time1 = su_nanocounter();
+
+ if (o->o_times) {
+ double dur = (time1 - time0) * 1E-9;
+
+ ctx->time += dur;
+
+ printf("%s%s"MOD_ZU" messages in %g seconds (%g msg/sec)\n"
+ " parse speed %.1f Mb/s (on Ethernet wire %.1f Mb/s)\n",
+ ctx->name, ctx->sep, N, dur, (double)N / dur,
+ (double)ctx->bytes * 8 / ctx->time / 1e6,
+ ((double)ctx->bytes + N * (16 + 20 + 8)) * 8 / ctx->time / 1e6);
+ }
+
+ free(msgs);
+
+ return 0;
+}
+
+typedef unsigned longlong ull;
+
+static
+void report_memstats(char const *title, su_home_stat_t const hs[1])
+{
+ printf("%s%smemory statistics\n", title, strlen(title) ? " " : "");
+ if (hs->hs_allocs.hsa_number)
+ printf("\t"LLU" allocs, "LLU" bytes, "LLU" rounded,"
+ " "LLU" max\n",
+ (ull)hs->hs_allocs.hsa_number, (ull)hs->hs_allocs.hsa_bytes,
+ (ull)hs->hs_allocs.hsa_rbytes, (ull)hs->hs_allocs.hsa_maxrbytes);
+ if (hs->hs_frees.hsf_number)
+ printf("\t"LLU" frees, "LLU" bytes, rounded to "LLU" bytes\n",
+ (ull)hs->hs_frees.hsf_number, (ull)hs->hs_frees.hsf_bytes,
+ (ull)hs->hs_frees.hsf_rbytes);
+ if (hs->hs_rehash || hs->hs_clones)
+ printf("\t"LLU" rehashes, "LLU" clones\n",
+ (ull)hs->hs_rehash, (ull)hs->hs_clones);
+}
+
+void memstats(msg_t *msg, uint32_t msize, context_t *ctx)
+{
+ options_t *o = ctx->options;
+ su_home_stat_t hs[1];
+
+ su_home_get_stats(msg_home(msg), 1, hs, sizeof(hs));
+ su_home_stat_add(ctx->hs, hs);
+
+ if (o->o_histogram) {
+ *histogram_update(ctx->hist_mallocs, msize) += hs->hs_allocs.hsa_number;
+ *histogram_update(ctx->hist_memsize, msize) += hs->hs_allocs.hsa_maxrbytes;
+ }
+
+ {
+ int estimate = msize + 384;
+ int slack = estimate - hs->hs_allocs.hsa_maxrbytes;
+
+ if (slack < 0)
+ ctx->est_fail++;
+ else {
+ ctx->est_succ++;
+ ctx->est_slack += slack;
+ }
+ }
+
+ if (o->o_very_verbose)
+ report_memstats(ctx->name, hs);
+}
+
+void report_sipstat(char const *what, sipstat_t const *sss)
+{
+ printf("%s: "LLU" with %.1f headers (total "LLU")\n",
+ what, (ull)sss->number, (double)sss->headers / sss->number,
+ (ull)sss->headers);
+ if (sss->payloads)
+ printf("\t"LLU" with body of %.1f bytes (total "LLU")\n",
+ (ull)sss->payloads, (double)sss->pl_bytes / sss->payloads,
+ (ull)sss->payloads);
+}
+
+void sipstats(msg_t *msg, uint32_t msize, sipstats_t *ss, context_t *ctx)
+{
+ options_t *o = ctx->options;
+ msg_pub_t *m = msg_object(msg);
+ sip_t const *sip = sip_object(msg);
+ msg_header_t *h;
+ sipstat_t *sss;
+ size_t n, bytes;
+
+ if (!sip)
+ return;
+
+ if (m->msg_request) {
+ sss = &ss->req;
+ h = m->msg_request;
+ }
+ else if (m->msg_status) {
+ sss = &ss->resp;
+ h = m->msg_status;
+ }
+ else {
+ return;
+ }
+
+ sss->number++;
+
+ /* Count headers */
+ for (n = 0, h = h->sh_succ; h && !sip_is_separator((sip_header_t *)h); h = h->sh_succ)
+ n++;
+
+ sss->headers += n;
+
+ bytes = sip->sip_payload ? (size_t)sip->sip_payload->pl_len : 0;
+
+ if (bytes) {
+ sss->payloads++;
+ sss->pl_bytes += bytes;
+ }
+
+ if (ctx->hist_nheaders) {
+ *histogram_update(ctx->hist_nheaders, msize) += n;
+ *histogram_update(ss->hist_headers, n) += 1;
+ }
+
+ if (o->o_very_verbose)
+ printf("%s%s"MOD_ZU" headers, "MOD_ZU" bytes in payload\n",
+ ctx->name, ctx->sep, n, bytes);
+}
+
+void report_histogram(char const *title, histogram_t const *h)
+{
+ size_t i, min_i, max_i;
+
+ for (i = 0; i < h->N && h->buckets[i] == 0.0; i++)
+ ;
+ min_i = i;
+
+ for (i = h->N - 1; i >= 0 && h->buckets[i] == 0.0; i--)
+ ;
+ max_i = i;
+
+ if (min_i >= max_i)
+ return;
+
+ printf("%s histogram\n", title);
+ for (i = min_i; i < max_i; i++)
+ printf("\t"MOD_ZU".."MOD_ZU": %.1f\n", i * h->bsize, (i + 1) * h->bsize, h->buckets[i]);
+
+ if (h->buckets[h->N])
+ printf("\t"MOD_ZU"..: %.1f\n", h->N * h->bsize, h->buckets[h->N]);
+}
+
+int report(context_t const *ctx)
+{
+ const options_t *o = ctx->options;
+ uint64_t n = ctx->messages;
+
+ if (!n)
+ return -1;
+
+ printf("total "LLU" messages with "LLU" bytes (mean size "LLU")\n",
+ (ull)n, (ull)ctx->bytes, (ull)(ctx->bytes / n));
+
+ if (ctx->hist_msgsize)
+ report_histogram("Message size", ctx->hist_msgsize);
+
+ if (o->o_times && ctx->files > 1)
+ printf("total "LLU" messages in %g seconds (%g msg/sec)\n",
+ (ull)n, ctx->time, (double)n / ctx->time);
+
+ if (o->o_sipstats) {
+ const sipstats_t *ss = ctx->sipstats;
+ report_sipstat("requests", &ss->req);
+ report_sipstat("responses", &ss->resp);
+
+ if (ctx->hist_nheaders) {
+ histogram_div(ctx->hist_nheaders, ctx->hist_msgsize);
+ report_histogram("Number of headers", ctx->hist_nheaders);
+ }
+ }
+
+ if (o->o_memstats) {
+ su_home_stat_t hs[1];
+
+ *hs = *ctx->hs;
+ report_memstats("total", hs);
+
+ /* Calculate mean */
+ hs->hs_clones /= n; hs->hs_rehash /= n;
+ hs->hs_allocs.hsa_number /= n; hs->hs_allocs.hsa_bytes /= n;
+ hs->hs_allocs.hsa_rbytes /= n; hs->hs_allocs.hsa_maxrbytes /= n;
+ hs->hs_frees.hsf_number /= n; hs->hs_frees.hsf_bytes /= n;
+ hs->hs_frees.hsf_rbytes /= n;
+ hs->hs_blocks.hsb_number /= n; hs->hs_blocks.hsb_bytes /= n;
+ hs->hs_blocks.hsb_rbytes /= n;
+
+ report_memstats("mean", hs);
+
+ printf("\testimator fails %.1f%% times (mean slack %.0f bytes)\n",
+ 100 * (double)ctx->est_fail / (ctx->est_fail + ctx->est_succ),
+ (double)ctx->est_slack / ctx->est_succ);
+
+ if (ctx->hist_memsize) {
+ histogram_div(ctx->hist_memsize, ctx->hist_msgsize);
+ report_histogram("Allocated memory", ctx->hist_memsize);
+ }
+ }
+
+ return 0;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/ChangeLog Thu Dec 21 01:30:28 2006
@@ -0,0 +1,325 @@
+2006-01-18 Martti Mela <martti.mela at nokia.com>
+
+ * soa.c: removed #include <netat/sysglue.h> (with __APPLE_CC__)
+
+2006-01-17 Martti Mela <martti.mela at nokia.com>
+
+ * if no EPROTO is found in OS X, redefine to EPROTOTYPE
+
+ M ./libsofia-sip-ua/soa/soa.c +8
+
+2005-10-17 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Restore version numbers after our offer is rejected.
+
+ M ./libsofia-sip-ua/soa/soa_static.c +3
+
+2005-10-15 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Updated API of soa_get_local_sdp() and friends.
+
+ Added parameter for returning SDP C structure to soa_get_capability_sdp(),
+ soa_get_remote_sdp(), soa_get_user_sdp(), and soa_get_local_sdp().
+
+ M ./libsofia-sip-ua/soa/soa.c -35 +58
+ M ./libsofia-sip-ua/soa/soa.h -4 +8
+ M ./libsofia-sip-ua/soa/test_soa.c -17 +18
+
+ * Updated SOA_VALID_ACTIONS().
+
+ M ./libsofia-sip-ua/soa/soa.c -1 +13
+
+ * Added soa_name.
+
+ M ./libsofia-sip-ua/soa/soa.c +1
+ M ./libsofia-sip-ua/soa/soa_session.h +1
+ M ./libsofia-sip-ua/soa/soa_static.c +1
+
+ * Removed annoying "last modified".
+
+ M ./libsofia-sip-ua/soa/soa.c -1
+ M ./libsofia-sip-ua/soa/soa.h -1
+ M ./libsofia-sip-ua/soa/soa_add.h -1
+ M ./libsofia-sip-ua/soa/soa_asynch.c -1
+ M ./libsofia-sip-ua/soa/soa_session.h -1
+ M ./libsofia-sip-ua/soa/soa_static.c -1
+ M ./libsofia-sip-ua/soa/soa_tag.c -1
+ M ./libsofia-sip-ua/soa/soa_tag.h -1
+ M ./libsofia-sip-ua/soa/test_soa.c -1
+
+ * Logging each API call except predicates.
+
+ M ./libsofia-sip-ua/soa/soa.c -5 +99
+
+ * Naming soa_sip_require() and soa_sip_supported() consistently.
+ The SIP headers are called Require and Supported.
+
+ M ./libsofia-sip-ua/soa/soa.c -6 +6
+ M ./libsofia-sip-ua/soa/soa.h -2 +2
+ M ./libsofia-sip-ua/soa/soa_asynch.c -2 +2
+ M ./libsofia-sip-ua/soa/soa_session.h -4 +4
+ M ./libsofia-sip-ua/soa/soa_static.c -2 +2
+ M ./libsofia-sip-ua/soa/test_soa.c -2 +2
+
+2005-10-12 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Updated SOA_VALID_ACTIONS().
+
+ M ./libsofia-sip-ua/soa/soa.c -1 +13
+
+ * Added soa_name.
+
+ M ./libsofia-sip-ua/soa/soa.c +1
+ M ./libsofia-sip-ua/soa/soa_session.h +1
+ M ./libsofia-sip-ua/soa/soa_static.c +1
+
+ * Removed annoying "last modified".
+
+ M ./libsofia-sip-ua/soa/soa.c -1
+ M ./libsofia-sip-ua/soa/soa.h -1
+ M ./libsofia-sip-ua/soa/soa_add.h -1
+ M ./libsofia-sip-ua/soa/soa_asynch.c -1
+ M ./libsofia-sip-ua/soa/soa_session.h -1
+ M ./libsofia-sip-ua/soa/soa_static.c -1
+ M ./libsofia-sip-ua/soa/soa_tag.c -1
+ M ./libsofia-sip-ua/soa/soa_tag.h -1
+ M ./libsofia-sip-ua/soa/test_soa.c -1
+
+ * Logging each API call except predicates.
+
+ M ./libsofia-sip-ua/soa/soa.c -5 +99
+
+
+ * Naming soa_sip_require() and soa_sip_supported() consistently.
+ The SIP headers are called Require and Supported.
+
+ M ./libsofia-sip-ua/soa/soa.c -6 +6
+ M ./libsofia-sip-ua/soa/soa.h -2 +2
+ M ./libsofia-sip-ua/soa/soa_asynch.c -2 +2
+ M ./libsofia-sip-ua/soa/soa_session.h -4 +4
+ M ./libsofia-sip-ua/soa/soa_static.c -2 +2
+ M ./libsofia-sip-ua/soa/test_soa.c -2 +2
+
+2005-10-12 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Added more logging.
+
+ M ./libsofia-sip-ua/soa/soa_static.c -1 +17
+
+ * Using SDP O/A result to determine media activity.
+
+ M ./libsofia-sip-ua/soa/soa.c -2 +2
+
+ * Sanitized soa_sdp_upgrade_is_needed().
+
+ M ./libsofia-sip-ua/soa/soa_static.c -27 +11
+
+ * Fixed active tests.
+
+ M ./libsofia-sip-ua/soa/test_soa.c -36 +36
+
+ * Fixed soa_get_paramlist() for complex cases.
+
+ M ./libsofia-sip-ua/soa/soa.c -1 +1
+
+2005-09-29 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Added SOATAG_ACTIVE_* stuff.
+
+ M ./libsofia-sip-ua/soa/soa_tag.c +98
+ M ./libsofia-sip-ua/soa/soa_tag.h +31
+
+ * Removed mss-related tags.
+
+ M ./libsofia-sip-ua/soa/soa_tag.c -263
+ M ./libsofia-sip-ua/soa/soa_tag.h -89
+
+ * Using sdp tags to pass session descriptions.
+
+ M ./libsofia-sip-ua/soa/soa.c -1 +1
+ M ./libsofia-sip-ua/soa/soa_tag.c -6 +5
+ M ./libsofia-sip-ua/soa/soa_tag.h -17 +20
+ M ./libsofia-sip-ua/soa/test_soa.c +20
+
+2005-09-28 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Returning remote sdp via soa_get_paramlist().
+
+ M soa.c +5
+
+ * soa_get_paramlist() just returns NULL if given NULL session.
+
+ M soa.c -6 +4
+
+ * Returning local and user SDP via tags.
+
+ M soa.c -5 +17
+
+ * Keeping track of soa instance name.
+
+ M soa.c -2 +13
+ M soa_session.h +1
+
+ * Always upgrading a freshly created session.
+
+ M soa_static.c -1 +1
+
+ * Updated documentation. Glare.
+
+ M soa.docs -10 +79
+
+ * Added (selective!) hold, media upgrade.
+
+ M soa_session.h +2
+ M soa_static.c -52 +174
+ M test_soa.c -4 +65
+
+ * Added more bits to activity (so we can indicate SOA_ACTIVE_REJECTED).
+
+ M soa_session.h -4 +4
+
+ * Updated the mode update: keep track of rejected status, too.
+
+ M soa.c -20 +28
+
+ * Bump ss_user_version if parameters change.
+
+ M soa.c -2 +9
+
+ * Removed soa_static_actions.
+
+ M soa_static.c -24
+
+ * Updated API to handle separately user-supplied SDP and negotiated SDP.
+
+ M soa.c -146 +180
+ M soa.h -11 +18
+ M soa_session.h -36 +30
+ M soa_static.c -73 +475
+ M test_soa.c -22 +40
+
+ * Not using soa_static_actions.
+
+ M test_soa.c -1 +1
+
+ * Updated soa_static_get_paramlist() prototype.
+
+ M soa_static.c -3 +16
+
+ * Removed last traces of "default".
+
+ M soa.c -51 +1
+ M soa_add.h -2
+
+ * Added tag parameters to soa_get_paramlist() prototype.
+
+ M soa.c -9 +23
+ M soa.h -1 +2
+ M soa_session.h -2 +4
+ M test_soa.c -1 +1
+
+ * Not testing asynch.
+
+ M test_soa.c +6
+
+ * Not testing removed parameters.
+
+ M test_soa.c -13 +20
+
+ * Not compiling soa_asynch.c
+
+ M Makefile.am -1 +1
+
+ * Include "soa_tag.h" in "soa_session.h", too.
+
+ M soa_session.h +3
+
+ * Moved tags to soa_tag.h
+
+ M soa.h -200
+
+ * Removed mss-related parameters. Added hold.
+
+ M soa.c -117 +12
+ M soa_session.h -13 +1
+
+ * Renamed "local" as "user".
+
+ M soa_asynch.c -7 +7
+
+ * Added soatag_user_sdp().
+
+ M soa_tag.c -10 +42
+
+ * Added soa_tag.h.
+
+ A soa_tag.h
+
+2005-09-26 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Updated call flows.
+
+ M soa.docs -57 +67
+
+ * Added some code for soa_static_generate_offer().
+
+ M soa_static.c -18 +60
+
+ * Fixed soa_static_set_local_sdp().
+
+ M soa_static.c -1 +1
+
+ * Added setter functions for sdp in soa_static.
+
+ M soa_static.c -6 +44
+
+ * Using explicit soa_set_local_sdp() with "static" soa instance.
+
+ M test_soa.c -3 +9
+
+ * Added session sdp: soa_get_session_sdp(), soatag_session_sdp.
+
+ M soa.h +16
+
+ * Comments.
+
+ M soa.c -2 +2
+
+ * Not expanding "local" sdp with o=, s=, t= and c=.
+
+ M soa.c -45
+
+ * Added local/remote/session sdp to soa_get_params().
+
+ M soa.c +11
+
+ * Added handling of soatag_local_sdp tag.
+
+ M soa.c -2 +25
+
+ * Added session description ss_desc
+
+ M soa_session.h +2
+
+ * Added soatag_local_sdp and soatag_remote_sdp.
+
+ M soa.h +12
+ M soa_tag.c +32
+
+2005-09-22 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * soa.c (soa_get_remote_version): Added.
+
+ * soa.c (soa_get_local_version): Added.
+
+ * soa_session.h: Added ssd_version field to
+ soa_description struct.
+
+2005-09-19 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * soa_static.c: Fix generating offers.
+
+2005-08-17 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Updated API. Added tester.
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/Doxyfile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/Doxyfile Thu Dec 21 01:30:28 2006
@@ -0,0 +1,28 @@
+PROJECT_NAME = "soa"
+OUTPUT_DIRECTORY = ../docs/html/soa
+
+INPUT = soa.docs sofia-sip/soa.h sofia-sip/soa_add.h soa.c
+INPUT += sofia-sip/soa_tag.h soa_tag.c
+
+ at INCLUDE = ../docs/Doxyfile.conf
+
+TAGFILES += ../docs/docs.doxytags=../docs
+TAGFILES += ../docs/su.doxytags=../su
+TAGFILES += ../docs/ipt.doxytags=../ipt
+TAGFILES += ../docs/bnf.doxytags=../bnf
+TAGFILES += ../docs/url.doxytags=../url
+TAGFILES += ../docs/msg.doxytags=../msg
+TAGFILES += ../docs/sip.doxytags=../sip
+TAGFILES += ../docs/sresolv.doxytags=../sresolv
+TAGFILES += ../docs/tport.doxytags=../tport
+TAGFILES += ../docs/nta.doxytags=../nta
+TAGFILES += ../docs/sdp.doxytags=../sdp
+TAGFILES += ../docs/nua.doxytags=../nua
+
+GENERATE_TAGFILE = ../docs/soa.doxytags
+
+ALIASES += soa="@ref index \"soa\""
+# When GENERATE_TAGFILE=YES, we should use \ref main
+#ALIASES += soa="@ref main \"soa\""
+
+ at INCLUDE = ../sip/sip.doxyaliases
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/Makefile.am Thu Dec 21 01:30:28 2006
@@ -0,0 +1,63 @@
+#
+# Makefile.am for soa module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+INCLUDES = -I$(srcdir)/../sdp -I../sdp \
+ -I$(srcdir)/../sip -I../sip \
+ -I$(srcdir)/../msg -I../msg \
+ -I$(srcdir)/../url -I../url \
+ -I$(srcdir)/../ipt -I../ipt \
+ -I$(srcdir)/../bnf -I../bnf \
+ -I$(srcdir)/../su -I../su
+
+# ----------------------------------------------------------------------
+# Build targets
+
+noinst_LTLIBRARIES = libsoa.la
+
+check_PROGRAMS = test_soa
+
+TESTS = test_soa
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+
+BUILT_SOURCES = soa_tag_ref.c
+
+nobase_include_sofia_HEADERS = \
+ sofia-sip/soa.h sofia-sip/soa_session.h \
+ sofia-sip/soa_add.h sofia-sip/soa_tag.h
+
+libsoa_la_SOURCES = soa.c soa_static.c \
+ soa_tag.c soa_tag_ref.c
+
+COVERAGE_INPUT = $(libsoa_la_SOURCES) $(include_sofia_HEADERS)
+
+LDADD = libsoa.la \
+ ../sip/libsip.la \
+ ../msg/libmsg.la \
+ ../url/liburl.la \
+ ../sdp/libsdp.la \
+ ../ipt/libipt.la \
+ ../bnf/libbnf.la \
+ ../su/libsu.la
+
+test_soa_LDFLAGS = -static
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+
+EXTRA_DIST = Doxyfile soa.docs $(BUILT_SOURCES)
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+
+include ../sofia.am
+
+TAG_DLL_FLAGS = LIST=soa_tag_list
\ No newline at end of file
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/Makefile.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1,713 @@
+# 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.
+
+ at SET_MAKE@
+
+#
+# Makefile.am for soa module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+# common Makefile targets for libsofia-sip-ua modules
+# ---------------------------------------------------
+
+
+SOURCES = $(libsoa_la_SOURCES) test_soa.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 = test_soa$(EXEEXT)
+DIST_COMMON = $(nobase_include_sofia_HEADERS) $(srcdir)/../sofia.am \
+ $(srcdir)/Makefile.am $(srcdir)/Makefile.in ChangeLog
+subdir = libsofia-sip-ua/soa
+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 =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libsoa_la_LIBADD =
+am_libsoa_la_OBJECTS = soa.lo soa_static.lo soa_tag.lo soa_tag_ref.lo
+libsoa_la_OBJECTS = $(am_libsoa_la_OBJECTS)
+test_soa_SOURCES = test_soa.c
+test_soa_OBJECTS = test_soa.$(OBJEXT)
+test_soa_LDADD = $(LDADD)
+test_soa_DEPENDENCIES = libsoa.la ../sip/libsip.la ../msg/libmsg.la \
+ ../url/liburl.la ../sdp/libsdp.la ../ipt/libipt.la \
+ ../bnf/libbnf.la ../su/libsu.la
+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 = $(libsoa_la_SOURCES) test_soa.c
+DIST_SOURCES = $(libsoa_la_SOURCES) test_soa.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|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(include_sofiadir)"
+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)/../sdp -I../sdp \
+ -I$(srcdir)/../sip -I../sip \
+ -I$(srcdir)/../msg -I../msg \
+ -I$(srcdir)/../url -I../url \
+ -I$(srcdir)/../ipt -I../ipt \
+ -I$(srcdir)/../bnf -I../bnf \
+ -I$(srcdir)/../su -I../su
+
+
+# ----------------------------------------------------------------------
+# Build targets
+noinst_LTLIBRARIES = libsoa.la
+TESTS = test_soa
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+BUILT_SOURCES = soa_tag_ref.c
+nobase_include_sofia_HEADERS = \
+ sofia-sip/soa.h sofia-sip/soa_session.h \
+ sofia-sip/soa_add.h sofia-sip/soa_tag.h
+
+libsoa_la_SOURCES = soa.c soa_static.c \
+ soa_tag.c soa_tag_ref.c
+
+COVERAGE_INPUT = $(libsoa_la_SOURCES) $(include_sofia_HEADERS)
+LDADD = libsoa.la \
+ ../sip/libsip.la \
+ ../msg/libmsg.la \
+ ../url/liburl.la \
+ ../sdp/libsdp.la \
+ ../ipt/libipt.la \
+ ../bnf/libbnf.la \
+ ../su/libsu.la
+
+test_soa_LDFLAGS = -static
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+EXTRA_DIST = Doxyfile soa.docs $(BUILT_SOURCES)
+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
+TAG_DLL_FLAGS = LIST=soa_tag_list
+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/soa/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu libsofia-sip-ua/soa/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-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
+libsoa.la: $(libsoa_la_OBJECTS) $(libsoa_la_DEPENDENCIES)
+ $(LINK) $(libsoa_la_LDFLAGS) $(libsoa_la_OBJECTS) $(libsoa_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
+test_soa$(EXEEXT): $(test_soa_OBJECTS) $(test_soa_DEPENDENCIES)
+ @rm -f test_soa$(EXEEXT)
+ $(LINK) $(test_soa_LDFLAGS) $(test_soa_OBJECTS) $(test_soa_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/soa.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/soa_static.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/soa_tag.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/soa_tag_ref.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_soa.Po at am__quote@
+
+.c.o:
+ at am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+ at am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ at am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at 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 $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(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-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-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-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-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-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-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) $<
+
+ at ENABLE_COVERAGE_TRUE@coverage:
+ at 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)
+# 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:
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/soa.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/soa.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,2318 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE soa.c
+ * @brief Sofia SDP Offer/Answer Engine interface
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Aug 3 20:27:15 EEST 2005
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <assert.h>
+
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/su_wait.h>
+
+#include "sofia-sip/soa.h"
+#include "sofia-sip/sdp.h"
+#include "sofia-sip/soa_session.h"
+#include "sofia-sip/soa_add.h"
+
+#include <sofia-sip/hostdomain.h>
+#include <sofia-sip/su_tagarg.h>
+#include <sofia-sip/su_localinfo.h>
+#include <sofia-sip/su_uniqueid.h>
+
+#include <sofia-sip/string0.h>
+#include <sofia-sip/su_errno.h>
+
+#define NONE ((void *)-1)
+#define XXX assert(!"implemented")
+
+typedef unsigned longlong ull;
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+static char const __func__[] = "soa";
+#endif
+
+/* ======================================================================== */
+
+/* Internal prototypes */
+void soa_set_activity(soa_session_t *ss,
+ sdp_media_t const *,
+ int remote);
+
+static inline int soa_media_is_ready(soa_session_t const *ss);
+
+enum soa_sdp_kind {
+ soa_capability_sdp_kind,
+ soa_user_sdp_kind,
+ soa_remote_sdp_kind
+};
+
+static int soa_set_sdp(soa_session_t *ss,
+ enum soa_sdp_kind what,
+ sdp_session_t const *sdp0,
+ char const *sdp_str, issize_t str_len);
+
+/* ======================================================================== */
+
+#define SOA_VALID_ACTIONS(a) \
+ ((a)->sizeof_soa_session_actions >= (int)sizeof (*actions) && \
+ (a)->sizeof_soa_session >= (int)sizeof(soa_session_t) && \
+ (a)->soa_name != NULL && \
+ (a)->soa_init != NULL && \
+ (a)->soa_deinit != NULL && \
+ (a)->soa_set_params != NULL && \
+ (a)->soa_get_params != NULL && \
+ (a)->soa_get_paramlist != NULL && \
+ (a)->soa_media_features != NULL && \
+ (a)->soa_sip_require != NULL && \
+ (a)->soa_sip_supported != NULL && \
+ (a)->soa_remote_sip_features != NULL && \
+ (a)->soa_set_capability_sdp != NULL && \
+ (a)->soa_set_remote_sdp != NULL && \
+ (a)->soa_set_user_sdp != NULL && \
+ (a)->soa_generate_offer != NULL && \
+ (a)->soa_generate_answer != NULL && \
+ (a)->soa_process_answer != NULL && \
+ (a)->soa_process_reject != NULL && \
+ (a)->soa_activate_session != NULL && \
+ (a)->soa_deactivate_session != NULL && \
+ (a)->soa_terminate_session != NULL)
+
+/* ======================================================================== */
+
+/**@var SOA_DEBUG
+ *
+ * Environment variable determining the default debug log level.
+ *
+ * The SOA_DEBUG environment variable is used to determine the default
+ * debug logging level. The normal level is 3.
+ *
+ * @sa <su_debug.h>, su_log_global, SOFIA_DEBUG
+ */
+extern char const SOA_DEBUG[];
+
+#ifndef SU_DEBUG
+#define SU_DEBUG 3
+#endif
+
+/**Debug log for @b soa module.
+ *
+ * The soa_log is the log object used by @b soa module. The level of
+ * #soa_log is set using #SOA_DEBUG environment variable.
+ */
+su_log_t soa_log[] = { SU_LOG_INIT("soa", "SOA_DEBUG", SU_DEBUG) };
+
+/* Add " around string */
+#define NICE(s) s ? "\"" : "", s ? s : "(nil)", s ? "\"" : ""
+
+/* ======================================================================== */
+
+/* API Functions */
+
+struct soa_namenode
+{
+ struct soa_namenode const *next;
+ char const *basename;
+ struct soa_session_actions const *actions;
+};
+
+#define SOA_NAMELISTLEN (16)
+
+static struct soa_namenode const soa_default_node =
+ {
+ NULL, "default", &soa_default_actions
+ };
+
+static struct soa_namenode const *soa_namelist = &soa_default_node;
+
+/** Add a named soa backend */
+int soa_add(char const *name,
+ struct soa_session_actions const *actions)
+{
+ struct soa_namenode const *n;
+ struct soa_namenode *e;
+
+ SU_DEBUG_9(("soa_add(%s%s%s, %p) called\n", NICE(name), actions));
+
+ if (name == NULL || actions == NULL)
+ return su_seterrno(EFAULT);
+
+ if (!SOA_VALID_ACTIONS(actions))
+ return su_seterrno(EINVAL);
+
+ for (n = soa_namelist; n; n = n->next) {
+ if (strcasecmp(name, n->basename) == 0)
+ return 0;
+ }
+
+ e = malloc(sizeof *e); if (!e) return -1;
+
+ e->next = soa_namelist;
+ e->basename = name;
+ e->actions = actions;
+
+ soa_namelist = e;
+
+ return 0;
+}
+
+/** Search for a named backend */
+struct soa_session_actions const *soa_find(char const *name)
+{
+ SU_DEBUG_9(("soa_find(%s%s%s) called\n", NICE(name)));
+
+ if (name) {
+ struct soa_namenode const *n;
+ size_t baselen = strcspn(name, ":/");
+
+ for (n = soa_namelist; n; n = n->next) {
+ if (strncasecmp(name, n->basename, baselen) == 0)
+ break;
+ }
+
+ if (n == NULL)
+ return (void)su_seterrno(ENOENT), NULL;
+
+ return n->actions;
+ }
+
+ return NULL;
+}
+
+/* ======================================================================== */
+
+/** Create a soa session. */
+soa_session_t *soa_create(char const *name,
+ su_root_t *root,
+ soa_magic_t *magic)
+{
+ struct soa_session_actions const *actions = &soa_default_actions;
+
+ soa_session_t *ss;
+ size_t namelen;
+
+ SU_DEBUG_9(("soa_create(\"%s\", %p, %p) called\n",
+ name ? name : "default", root, magic));
+
+ if (name && name[0]) {
+ struct soa_namenode const *n;
+ size_t baselen = strcspn(name, ":/");
+
+ for (n = soa_namelist; n; n = n->next) {
+ if (strncasecmp(name, n->basename, baselen) == 0)
+ break;
+ }
+ if (n == NULL)
+ return (void)su_seterrno(ENOENT), NULL;
+
+ actions = n->actions; assert(actions);
+ }
+ else
+ name = "default";
+
+ assert(SOA_VALID_ACTIONS(actions));
+
+ if (root == NULL)
+ return (void)su_seterrno(EFAULT), NULL;
+
+ namelen = strlen(name) + 1;
+
+ ss = su_home_new(actions->sizeof_soa_session + namelen);
+ if (ss) {
+ ss->ss_root = root;
+ ss->ss_magic = magic;
+ ss->ss_actions = actions;
+ ss->ss_name = strcpy((char *)ss + actions->sizeof_soa_session, name);
+
+ if (ss->ss_actions->soa_init(name, ss, NULL) < 0)
+ ss->ss_actions->soa_deinit(ss), ss = NULL;
+ }
+
+ return ss;
+}
+
+/** Create a copy of a @soa session object. */
+soa_session_t *soa_clone(soa_session_t *parent_ss,
+ su_root_t *root,
+ soa_magic_t *magic)
+{
+ soa_session_t *ss;
+ size_t namelen;
+
+ SU_DEBUG_9(("soa_clone(%s::%p, %p, %p) called\n",
+ parent_ss ? parent_ss->ss_actions->soa_name : "",
+ parent_ss, root, magic));
+
+ if (parent_ss == NULL || root == NULL)
+ return (void)su_seterrno(EFAULT), NULL;
+
+ namelen = strlen(parent_ss->ss_name) + 1;
+
+ ss = su_home_new(parent_ss->ss_actions->sizeof_soa_session + namelen);
+ if (ss) {
+ ss->ss_root = root;
+ ss->ss_magic = magic;
+ ss->ss_actions = parent_ss->ss_actions;
+ ss->ss_name = strcpy((char *)ss + ss->ss_actions->sizeof_soa_session,
+ parent_ss->ss_name);
+
+ if (ss->ss_actions->soa_init(NULL, ss, parent_ss) < 0)
+ ss->ss_actions->soa_deinit(ss), ss = NULL;
+ }
+
+ return ss;
+}
+
+/** Increase reference count */
+soa_session_t *soa_session_ref(soa_session_t *ss)
+{
+ SU_DEBUG_9(("soa_session_ref(%s::%p) called\n",
+ ss ? ss->ss_actions->soa_name : "", ss));
+ return su_home_ref(ss->ss_home);
+}
+
+/** Decrease reference count */
+void soa_session_unref(soa_session_t *ss)
+{
+ SU_DEBUG_9(("soa_session_unref(%s::%p) called\n",
+ ss ? ss->ss_actions->soa_name : "", ss));
+ su_home_unref(ss->ss_home);
+}
+
+/* Initialize session */
+int soa_base_init(char const *name,
+ soa_session_t *ss,
+ soa_session_t *parent)
+{
+ if (parent) {
+#define DUP(d, dup, s) if ((s) && !((d) = dup(ss->ss_home, (s)))) return -1
+ su_home_t *home = ss->ss_home;
+
+ if (soa_description_dup(home, ss->ss_caps, parent->ss_caps) < 0)
+ return -1;
+ if (soa_description_dup(home, ss->ss_user, parent->ss_user) < 0)
+ return -1;
+ if (soa_description_dup(home, ss->ss_local, parent->ss_local) < 0)
+ return -1;
+ if (soa_description_dup(home, ss->ss_remote, parent->ss_remote) < 0)
+ return -1;
+
+ DUP(ss->ss_address, su_strdup, parent->ss_address);
+ ss->ss_af = parent->ss_af;
+ DUP(ss->ss_hold, su_strdup, parent->ss_hold);
+
+ DUP(ss->ss_cname, su_strdup, parent->ss_cname);
+
+ ss->ss_srtp_enable = parent->ss_srtp_enable;
+ ss->ss_srtp_confidentiality = parent->ss_srtp_confidentiality;
+ ss->ss_srtp_integrity = parent->ss_srtp_integrity;
+ }
+
+ return 0;
+}
+
+/** Destroy a session. */
+void soa_destroy(soa_session_t *ss)
+{
+ SU_DEBUG_9(("soa_destroy(%s::%p) called\n",
+ ss ? ss->ss_actions->soa_name : "", ss));
+
+ if (ss) {
+ ss->ss_active = 0;
+ ss->ss_terminated++;
+ ss->ss_actions->soa_deinit(ss);
+ su_home_unref(ss->ss_home);
+ }
+}
+
+void soa_base_deinit(soa_session_t *ss)
+{
+ (void)ss;
+}
+
+/** Set parameters.
+ *
+ * @param ss soa session object
+ * @param tag, value, ... tagged parameter list
+ *
+ * @return Number of parameters set, or -1 upon an error.
+ *
+ * @TAGS
+ * SOATAG_CAPS_SDP(),
+ * SOATAG_CAPS_SDP_STR(),
+ * SOATAG_USER_SDP(),
+ * SOATAG_USER_SDP_STR(),
+ * SOATAG_REMOTE_SDP(),
+ * SOATAG_REMOTE_SDP_STR(),
+ * SOATAG_AF(),
+ * SOATAG_ADDRESS(),
+ * SOATAG_AUDIO_AUX() (currently for "default" only),
+ * SOATAG_HOLD(),
+ * SOATAG_RTP_SELECT(),
+ * SOATAG_RTP_SORT(),
+ * SOATAG_RTP_MISMATCH(),
+ * SOATAG_SRTP_ENABLE(),
+ * SOATAG_SRTP_CONFIDENTIALITY(), and
+ * SOATAG_SRTP_INTEGRITY().
+ */
+int soa_set_params(soa_session_t *ss, tag_type_t tag, tag_value_t value, ...)
+{
+ ta_list ta;
+ int n;
+
+ SU_DEBUG_9(("soa_set_params(%s::%p, ...) called\n",
+ ss ? ss->ss_actions->soa_name : "", ss));
+
+ if (ss == NULL)
+ return su_seterrno(EFAULT), -1;
+
+ ta_start(ta, tag, value);
+
+ n = ss->ss_actions->soa_set_params(ss, ta_args(ta));
+
+ ta_end(ta);
+
+ return n;
+}
+
+/**Base method for setting parameters.
+ *
+ * @param ss soa session object
+ * @param tags tag item list
+ *
+ * @return Number of parameters set, or -1 upon an error.
+ *
+ * @TAGS
+ * SOATAG_CAPS_SDP(),
+ * SOATAG_CAPS_SDP_STR(),
+ * SOATAG_USER_SDP(),
+ * SOATAG_USER_SDP_STR(),
+ * SOATAG_REMOTE_SDP(),
+ * SOATAG_REMOTE_SDP_STR(),
+ * SOATAG_AF(),
+ * SOATAG_ADDRESS(),
+ * SOATAG_HOLD(),
+ * SOATAG_RTP_SELECT(),
+ * SOATAG_RTP_SORT(),
+ * SOATAG_RTP_MISMATCH(),
+ * SOATAG_SRTP_ENABLE(),
+ * SOATAG_SRTP_CONFIDENTIALITY(), and
+ * SOATAG_SRTP_INTEGRITY().
+ */
+int soa_base_set_params(soa_session_t *ss, tagi_t const *tags)
+{
+ int n, change_session = 0;
+
+ sdp_session_t const *caps_sdp, *user_sdp;
+ char const *caps_sdp_str, *user_sdp_str;
+
+ int af;
+ char const *media_address, *hold;
+ int rtp_select, rtp_sort;
+ int rtp_mismatch;
+ int srtp_enable, srtp_confidentiality, srtp_integrity;
+
+ af = ss->ss_af;
+
+ hold = ss->ss_hold;
+ media_address = ss->ss_address;
+
+ rtp_select = (int)ss->ss_rtp_select;
+ rtp_sort = (int)ss->ss_rtp_sort;
+ rtp_mismatch = ss->ss_rtp_mismatch;
+
+ srtp_enable = ss->ss_srtp_enable;
+ srtp_confidentiality = ss->ss_srtp_confidentiality;
+ srtp_integrity = ss->ss_srtp_integrity;
+
+ caps_sdp = user_sdp = NONE;
+ caps_sdp_str = user_sdp_str = NONE;
+
+ n = tl_gets(tags,
+
+ SOATAG_CAPS_SDP_REF(caps_sdp),
+ SOATAG_CAPS_SDP_STR_REF(caps_sdp_str),
+
+ SOATAG_USER_SDP_REF(user_sdp),
+ SOATAG_USER_SDP_STR_REF(user_sdp_str),
+
+ SOATAG_AF_REF(af),
+ SOATAG_ADDRESS_REF(media_address),
+ SOATAG_HOLD_REF(hold),
+
+ SOATAG_RTP_SELECT_REF(rtp_select),
+ SOATAG_RTP_SORT_REF(rtp_sort),
+ SOATAG_RTP_MISMATCH_REF(rtp_mismatch),
+
+ SOATAG_SRTP_ENABLE_REF(srtp_enable),
+ SOATAG_SRTP_CONFIDENTIALITY_REF(srtp_confidentiality),
+ SOATAG_SRTP_INTEGRITY_REF(srtp_integrity),
+
+ TAG_END());
+
+ if (n <= 0)
+ return n;
+
+ if (caps_sdp != NONE || caps_sdp_str != NONE) {
+ if (caps_sdp == NONE) caps_sdp = NULL;
+ if (caps_sdp_str == NONE) caps_sdp_str = NULL;
+
+ if (caps_sdp || caps_sdp_str) {
+ if (soa_set_capability_sdp(ss, caps_sdp, caps_sdp_str, -1) < 0) {
+ return -1;
+ }
+ }
+ else {
+ soa_description_free(ss, ss->ss_caps);
+ }
+ }
+
+ if (user_sdp != NONE || user_sdp_str != NONE) {
+ if (user_sdp == NONE) user_sdp = NULL;
+ if (user_sdp_str == NONE) user_sdp_str = NULL;
+
+ if (user_sdp || user_sdp_str) {
+ if (soa_set_user_sdp(ss, user_sdp, user_sdp_str, -1) < 0) {
+ return -1;
+ }
+ if (ss->ss_caps->ssd_str == NULL)
+ soa_set_capability_sdp(ss, user_sdp, user_sdp_str, -1);
+ }
+ else {
+ soa_description_free(ss, ss->ss_user);
+ }
+ }
+
+ if (af < SOA_AF_ANY || af > SOA_AF_IP6_IP4)
+ af = ss->ss_af;
+
+ if (rtp_select < SOA_RTP_SELECT_SINGLE || rtp_select > SOA_RTP_SELECT_ALL)
+ rtp_select = (int)ss->ss_rtp_select;
+ if (rtp_sort < SOA_RTP_SORT_DEFAULT || rtp_sort > SOA_RTP_SORT_REMOTE)
+ rtp_sort = (int)ss->ss_rtp_sort;
+ rtp_mismatch = rtp_mismatch != 0;
+
+ srtp_enable = srtp_enable != 0;
+ srtp_confidentiality = srtp_confidentiality != 0;
+ srtp_integrity = srtp_integrity != 0;
+
+ change_session
+ = af != (int)ss->ss_af
+ || rtp_select != (int)ss->ss_rtp_select
+ || rtp_sort != (int)ss->ss_rtp_sort
+ || rtp_mismatch != (int)ss->ss_rtp_mismatch
+ || srtp_enable != (int)ss->ss_srtp_enable
+ || srtp_confidentiality != (int)ss->ss_srtp_confidentiality
+ || srtp_integrity != (int)ss->ss_srtp_integrity
+ ;
+
+ ss->ss_af = af;
+
+ ss->ss_rtp_select = rtp_select;
+ ss->ss_rtp_sort = rtp_sort;
+ ss->ss_rtp_mismatch = rtp_mismatch;
+
+ ss->ss_srtp_enable = srtp_enable;
+ ss->ss_srtp_confidentiality = srtp_confidentiality;
+ ss->ss_srtp_integrity = srtp_integrity;
+
+ if (str0casecmp(media_address, ss->ss_address)) {
+ su_free(ss->ss_home, (void *)ss->ss_address);
+ ss->ss_address = su_strdup(ss->ss_home, media_address);
+ change_session = 1;
+ }
+
+ if (hold == (char const *)1)
+ hold = "*";
+
+ if (str0casecmp(hold, ss->ss_hold)) {
+ su_free(ss->ss_home, (void *)ss->ss_hold);
+ ss->ss_hold = su_strdup(ss->ss_home, hold);
+ change_session = 1;
+ }
+
+ if (change_session)
+ ss->ss_user_version++;
+
+ return n;
+}
+
+/** Get tagged parameters.
+ *
+ * @param ss soa session object
+ * @param tag, value, ... tagged parameter list
+ *
+ * @return Number of parameters get, or -1 upon an error.
+ *
+ * @TAGS
+ * SOATAG_CAPS_SDP(),
+ * SOATAG_CAPS_SDP_STR(),
+ * SOATAG_USER_SDP(),
+ * SOATAG_USER_SDP_STR(),
+ * SOATAG_LOCAL_SDP(),
+ * SOATAG_LOCAL_SDP_STR(),
+ * SOATAG_REMOTE_SDP(),
+ * SOATAG_REMOTE_SDP_STR(),
+ * SOATAG_AF(),
+ * SOATAG_ADDRESS(),
+ * SOATAG_AUDIO_AUX() (currently for "default" only),
+ * SOATAG_HOLD(),
+ * SOATAG_RTP_SELECT(),
+ * SOATAG_RTP_SORT(),
+ * SOATAG_RTP_MISMATCH(),
+ * SOATAG_SRTP_ENABLE(),
+ * SOATAG_SRTP_CONFIDENTIALITY(), and
+ * SOATAG_SRTP_INTEGRITY().
+ */
+int soa_get_params(soa_session_t const *ss,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ ta_list ta;
+ int n;
+
+ SU_DEBUG_9(("soa_get_params(%s::%p, ...) called\n",
+ ss ? ss->ss_actions->soa_name : "", ss));
+
+ if (ss == NULL)
+ return su_seterrno(EFAULT), -1;
+
+ ta_start(ta, tag, value);
+
+ n = ss->ss_actions->soa_get_params(ss, ta_args(ta));
+
+ ta_end(ta);
+
+ return n;
+}
+
+/**Base method for getting tagged parameters.
+ *
+ * @param ss soa session object
+ * @param tags tag item list
+ *
+ * @return Number of parameters get, or -1 upon an error.
+ *
+ * @TAGS
+ * SOATAG_CAPS_SDP(),
+ * SOATAG_CAPS_SDP_STR(),
+ * SOATAG_USER_SDP(),
+ * SOATAG_USER_SDP_STR(),
+ * SOATAG_LOCAL_SDP(),
+ * SOATAG_LOCAL_SDP_STR(),
+ * SOATAG_REMOTE_SDP(),
+ * SOATAG_REMOTE_SDP_STR(),
+ * SOATAG_AF(),
+ * SOATAG_ADDRESS(),
+ * SOATAG_HOLD(),
+ * SOATAG_RTP_SELECT(),
+ * SOATAG_RTP_SORT(),
+ * SOATAG_RTP_MISMATCH(),
+ * SOATAG_SRTP_ENABLE(),
+ * SOATAG_SRTP_CONFIDENTIALITY(), and
+ * SOATAG_SRTP_INTEGRITY().
+ */
+int soa_base_get_params(soa_session_t const *ss, tagi_t *tags)
+{
+ int n;
+
+ n = tl_tgets(tags,
+ SOATAG_CAPS_SDP(ss->ss_caps->ssd_sdp),
+ SOATAG_CAPS_SDP_STR(ss->ss_caps->ssd_str),
+
+ SOATAG_USER_SDP(ss->ss_user->ssd_sdp),
+ SOATAG_USER_SDP_STR(ss->ss_user->ssd_str),
+
+ SOATAG_LOCAL_SDP(ss->ss_local->ssd_sdp),
+ SOATAG_LOCAL_SDP_STR(ss->ss_local->ssd_str),
+
+ SOATAG_REMOTE_SDP(ss->ss_remote->ssd_sdp),
+ SOATAG_REMOTE_SDP_STR(ss->ss_remote->ssd_unparsed),
+
+ SOATAG_AF(ss->ss_af),
+ SOATAG_ADDRESS(ss->ss_address),
+ SOATAG_HOLD(ss->ss_hold),
+
+ SOATAG_RTP_SELECT((int)ss->ss_rtp_select),
+ SOATAG_RTP_SORT((int)ss->ss_rtp_sort),
+ SOATAG_RTP_MISMATCH(ss->ss_rtp_mismatch),
+
+ SOATAG_SRTP_ENABLE(ss->ss_srtp_enable),
+ SOATAG_SRTP_CONFIDENTIALITY(ss->ss_srtp_confidentiality),
+ SOATAG_SRTP_INTEGRITY(ss->ss_srtp_integrity),
+
+ TAG_END());
+
+ return n;
+}
+
+/** Return a list of parameters. */
+tagi_t *soa_get_paramlist(soa_session_t const *ss,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ ta_list ta;
+ tagi_t *params = NULL;
+
+ SU_DEBUG_9(("soa_get_paramlist(%s::%p, ...) called\n",
+ ss ? ss->ss_actions->soa_name : "", ss));
+
+ if (ss) {
+ ta_start(ta, tag, value);
+ params = ss->ss_actions->soa_get_paramlist(ss, ta_tags(ta));
+ ta_end(ta);
+ }
+
+ return params;
+}
+
+
+/** Base bethod for getting list of parameters. */
+tagi_t *soa_base_get_paramlist(soa_session_t const *ss,
+ tag_type_t tag, tag_value_t value,
+ ...)
+{
+ ta_list ta;
+ tagi_t *params;
+
+ if (ss == NULL)
+ return NULL;
+
+ ta_start(ta, tag, value);
+
+ params = tl_llist(
+ TAG_IF(ss->ss_caps->ssd_sdp,
+ SOATAG_CAPS_SDP(ss->ss_caps->ssd_sdp)),
+ TAG_IF(ss->ss_caps->ssd_str,
+ SOATAG_CAPS_SDP_STR(ss->ss_caps->ssd_str)),
+
+ TAG_IF(ss->ss_user->ssd_sdp,
+ SOATAG_USER_SDP(ss->ss_user->ssd_sdp)),
+ TAG_IF(ss->ss_user->ssd_str,
+ SOATAG_USER_SDP_STR(ss->ss_user->ssd_str)),
+
+ TAG_IF(ss->ss_local->ssd_sdp,
+ SOATAG_LOCAL_SDP(ss->ss_local->ssd_sdp)),
+ TAG_IF(ss->ss_user->ssd_str,
+ SOATAG_LOCAL_SDP_STR(ss->ss_local->ssd_str)),
+
+ TAG_IF(ss->ss_remote->ssd_sdp,
+ SOATAG_REMOTE_SDP(ss->ss_remote->ssd_sdp)),
+ TAG_IF(ss->ss_remote->ssd_str,
+ SOATAG_REMOTE_SDP_STR(ss->ss_remote->ssd_unparsed)),
+
+ SOATAG_AF(ss->ss_af),
+ TAG_IF(ss->ss_address,
+ SOATAG_ADDRESS(ss->ss_address)),
+
+ SOATAG_SRTP_ENABLE(ss->ss_srtp_enable),
+ SOATAG_SRTP_CONFIDENTIALITY(ss->ss_srtp_confidentiality),
+ SOATAG_SRTP_INTEGRITY(ss->ss_srtp_integrity),
+
+ ta_tags(ta));
+
+ ta_end(ta);
+
+ return params;
+}
+
+#include <sofia-sip/sip_status.h>
+
+/** Convert @soa error to a SIP response code and phrase. */
+int soa_error_as_sip_response(soa_session_t *ss,
+ char const **return_phrase)
+{
+ SU_DEBUG_9(("soa_error_as_sip_response(%s::%p, ...) called\n",
+ ss ? ss->ss_actions->soa_name : "", ss));
+
+ if (ss == NULL || ss->ss_status < 400 || ss->ss_status >= 700) {
+ if (return_phrase)
+ *return_phrase = sip_500_Internal_server_error;
+ return 500;
+ }
+
+ if (return_phrase)
+ *return_phrase = ss->ss_phrase;
+ return ss->ss_status;
+}
+
+/** Convert @soa error to a SIP @Reason header. */
+char const *soa_error_as_sip_reason(soa_session_t *ss)
+{
+ char const *phrase;
+ int status;
+ char *reason;
+
+ SU_DEBUG_9(("soa_error_as_sip_reason(%s::%p) called\n",
+ ss ? ss->ss_actions->soa_name : "", ss));
+
+ if (ss == NULL)
+ return "SIP;cause=500;text=\"Internal Server Error\"";
+
+ status = soa_error_as_sip_response(ss, &phrase);
+
+ reason = su_sprintf(ss->ss_home, "SIP;cause=%u;text=\"%s\"", status, phrase);
+
+ if (ss->ss_reason)
+ su_free(ss->ss_home, reason);
+
+ return ss->ss_reason = reason;
+}
+
+
+/** Return SIP @Warning code and text. */
+int soa_get_warning(soa_session_t *ss, char const **return_text)
+{
+ if (!ss)
+ return 0;
+
+ if (!ss->ss_wcode)
+ return 0;
+
+ if (return_text)
+ *return_text = ss->ss_warning;
+
+ return ss->ss_wcode;
+}
+
+/** Return SDP description of capabilities.
+ *
+ * @param ss pointer to @soa session
+ * @param return_sdp return value for capability SDP structure
+ * @param return_sdp_str return value for capability SDP string
+ * @param return_len return value for length of capability SDP string
+ *
+ * @retval 0 if there is no description to return
+ * @retval 1 if description is returned
+ * @retval -1 upon an error
+ *
+ * @sa @RFC3261 section 11, soa_set_capability_sdp(),
+ * SOATAG_CAPS_SDP(), SOATAG_CAPS_SDP_STR(),
+ * nua_options(), #nua_i_options
+ */
+int soa_get_capability_sdp(soa_session_t const *ss,
+ sdp_session_t const **return_sdp,
+ char const **return_sdp_str,
+ isize_t *return_len)
+{
+ sdp_session_t const *sdp;
+ char const *sdp_str;
+
+ SU_DEBUG_9(("soa_get_capability_sdp(%s::%p, [%p], [%p], [%p]) called\n",
+ ss ? ss->ss_actions->soa_name : "", ss,
+ return_sdp, return_sdp_str, return_len));
+
+ if (ss == NULL)
+ return (void)su_seterrno(EFAULT), -1;
+
+ sdp = ss->ss_caps->ssd_sdp;
+ sdp_str = ss->ss_caps->ssd_str;
+
+ if (sdp == NULL)
+ return 0;
+ if (return_sdp)
+ *return_sdp = sdp;
+ if (return_sdp_str)
+ *return_sdp_str = sdp_str;
+ if (return_len)
+ *return_len = strlen(sdp_str);
+
+ return 1;
+}
+
+
+/** Set capability SDP.
+ *
+ * Capability SDP is used instead of user SDP when generating OPTIONS
+ * responses describing media capabilities.
+ *
+ * @param ss pointer to @soa session
+ * @param sdp pointer to SDP session structure
+ * @param str pointer to string containing SDP session description
+ * @param len lenght of string @a str
+ *
+ * @retval 1 when SDP is stored and it differs from previously stored
+ * @retval 0 when SDP is identical to previously stored one (and user version
+ * returned by soa_get_user_version() is not incremented)
+ * @retval -1 upon an error
+ *
+ * @sa @RFC3261 section 11, soa_get_capability_sdp(),
+ * SOATAG_CAPS_SDP(), SOATAG_CAPS_SDP_STR(),
+ * nua_options(), #nua_i_options
+ */
+int soa_set_capability_sdp(soa_session_t *ss,
+ sdp_session_t const *sdp,
+ char const *str, issize_t len)
+{
+ SU_DEBUG_9(("soa_set_capability_sdp(%s::%p, %p, %p, "MOD_ZD") called\n",
+ ss ? ss->ss_actions->soa_name : "", ss, sdp, str, (ssize_t)len));
+
+ return soa_set_sdp(ss, soa_capability_sdp_kind, sdp, str, len);
+}
+
+/** Set capabilities */
+int
+soa_base_set_capability_sdp(soa_session_t *ss,
+ sdp_session_t *sdp, char const *str0, isize_t len0)
+{
+ sdp_origin_t o[1] = {{ sizeof(o) }};
+ sdp_connection_t *c, c0[1] = {{ sizeof(c0) }};
+ char c_address[64];
+ sdp_time_t t[1] = {{ sizeof(t) }};
+ sdp_media_t *m;
+
+ if (sdp->sdp_origin)
+ *o = *sdp->sdp_origin;
+ else
+ o->o_address = c0;
+
+ sdp->sdp_origin = o;
+
+ if (soa_init_sdp_origin(ss, o, c_address) < 0)
+ return -1;
+
+ if (!sdp->sdp_subject)
+ sdp->sdp_subject = "-";
+
+ sdp->sdp_time = t;
+
+ /* Set port to zero - or should we check that port is already zero? */
+ for (m = sdp->sdp_media; m; m = m->m_next)
+ m->m_port = 0;
+
+ c = sdp->sdp_origin->o_address;
+
+ if (sdp->sdp_connection == NULL) {
+ for (m = sdp->sdp_media; m; m = m->m_next)
+ if (m->m_connections == NULL)
+ break;
+ if (m)
+ sdp->sdp_connection = c;
+ }
+
+ return soa_description_set(ss, ss->ss_caps, sdp, str0, len0);
+}
+
+/**Return user SDP description.
+ *
+ * <i>User SDP</i> is used as basis for SDP Offer/Answer negotiation. It can
+ * be very minimal template, consisting just m= line containing media name,
+ * transport protocol port number and list of supported codecs.
+ *
+ * The SDP used as an offer or answer (generated by soa_generate_answer() or
+ * soa_generate_offer()) is known as <i>local SDP</i> and it is available
+ * with soa_get_local_sdp() or SOATAG_LOCAL_SDP()/SOATAG_LOCAL_SDP_STR()
+ * tags.
+ *
+ * @param ss pointer to @soa session
+ * @param return_sdp SDP session structure return value
+ * @param return_sdp_str return value for pointer to string
+ * containing the user SDP session description
+ * @param return_len return value for user SDP session description string
+ * length
+ *
+ * Any of the parameters @a return_sdp, @a return_sdp_str, or @a return_len
+ * may be NULL.
+ *
+ * @retval 0 if there is no description to return
+ * @retval 1 if description is returned
+ * @retval -1 upon an error
+ *
+ * @sa soa_get_local_sdp(), soa_set_user_sdp(), soa_get_user_version(),
+ * SOATAG_USER_SDP(), SOATAG_USER_SDP_STR(), soa_get_remote_sdp(),
+ * soa_get_capability_sdp()
+ */
+int soa_get_user_sdp(soa_session_t const *ss,
+ sdp_session_t const **return_sdp,
+ char const **return_sdp_str,
+ isize_t *return_len)
+{
+ sdp_session_t const *sdp;
+ char const *sdp_str;
+
+ SU_DEBUG_9(("soa_get_user_sdp(%s::%p, [%p], [%p], [%p]) called\n",
+ ss ? ss->ss_actions->soa_name : "", ss,
+ return_sdp, return_sdp_str, return_len));
+
+ if (ss == NULL)
+ return (void)su_seterrno(EFAULT), -1;
+
+ sdp = ss->ss_user->ssd_sdp;
+ sdp_str = ss->ss_user->ssd_str;
+
+ if (sdp == NULL)
+ return 0;
+ if (return_sdp)
+ *return_sdp = sdp;
+ if (return_sdp_str)
+ *return_sdp_str = sdp_str;
+ if (return_len)
+ *return_len = strlen(sdp_str);
+
+ return 1;
+}
+
+/**Returns the version number of user session description. The version
+ * numbering starts from zero and it is incremented each time
+ * soa_set_user_sdp() or soa_set_params() modifies user SDP.
+ *
+ * @param ss pointer to @soa session
+
+ * @return Sequence number of user SDP.
+ *
+ * @sa soa_set_user_sdp(), soa_get_user_sdp(), soa_set_params(),
+ * SOATAG_USER_SDP(), SOATAG_USER_SDP_STR()
+ */
+int soa_get_user_version(soa_session_t const *ss)
+{
+ assert(ss != NULL);
+ return ss ? (int)ss->ss_user_version : -1;
+}
+
+/**Store user SDP to soa session.
+ *
+ * User SDP is used as basis for SDP Offer/Answer negotiation. It can be
+ * very minimal, consisting just m= line containing media name, transport
+ * protocol port number and list of supported codecs.
+ *
+ * The SDP used as an offer or answer (generated by soa_generate_answer() or
+ * soa_generate_offer()) is known as <i>local SDP</i> and it is available
+ * with soa_get_local_sdp() or SOATAG_LOCAL_SDP()/SOATAG_LOCAL_SDP_STR()
+ * tags.
+ *
+ * @param ss pointer to @soa session
+ * @param sdp pointer to SDP session structure
+ * @param str pointer to string containing SDP session description
+ * @param len lenght of string @a str
+ *
+ * Either @a sdp or @a str must be non-NULL. If @a len is -1, length of
+ * string @a str is calculated using strlen().
+ *
+ * @retval 1 when SDP is stored and it differs from previously stored
+ * @retval 0 when SDP is identical to previously stored one (and user version
+ * returned by soa_get_user_version() is not incremented)
+ * @retval -1 upon an error
+ *
+ * @sa soa_get_user_sdp(), soa_get_user_version(), soa_set_params(),
+ * SOATAG_USER_SDP(), SOATAG_USER_SDP_STR(), soa_generate_offer(),
+ * soa_generate_answer(), soa_get_local_sdp(), soa_set_capability_sdp(),
+ * soa_set_remote_sdp()
+ */
+int soa_set_user_sdp(soa_session_t *ss,
+ sdp_session_t const *sdp,
+ char const *str, issize_t len)
+{
+ SU_DEBUG_9(("soa_set_user_sdp(%s::%p, %p, %p, "MOD_ZD") called\n",
+ ss ? ss->ss_actions->soa_name : "", ss, sdp, str, (ssize_t)len));
+
+ return soa_set_sdp(ss, soa_user_sdp_kind, sdp, str, len);
+}
+
+/** Set user SDP (base version). */
+int soa_base_set_user_sdp(soa_session_t *ss,
+ sdp_session_t *sdp, char const *str0, isize_t len0)
+{
+ ++ss->ss_user_version;
+ return soa_description_set(ss, ss->ss_user, sdp, str0, len0);
+}
+
+/**Return remote SDP description of the session.
+ *
+ * <i>Remote SDP</i> is used, together with <i>User SDP</i> as basis for SDP
+ * Offer/Answer negotiation.
+ *
+ * @param ss pointer to @soa session
+ * @param return_sdp SDP session structure return value
+ * @param return_sdp_str return value for pointer to string
+ * containing the user SDP session description
+ * @param return_len return value for user SDP session descrioption string
+ * length
+ *
+ * Any of the parameters @a return_sdp, @a return_sdp_str, or @a return_len
+ * may be NULL.
+ *
+ * @retval 0 if there is no description to return
+ * @retval 1 if description is returned
+ * @retval -1 upon an error
+ *
+ * @sa soa_set_remote_sdp(), soa_get_remote_version(), soa_get_params(),
+ * soa_get_paramlist(), SOATAG_REMOTE_SDP(), SOATAG_REMOTE_SDP_STR(),
+ * soa_get_local_sdp(), soa_get_user_sdp(), soa_get_capability_sdp().
+ */
+int soa_get_remote_sdp(soa_session_t const *ss,
+ sdp_session_t const **return_sdp,
+ char const **return_sdp_str,
+ isize_t *return_len)
+{
+ sdp_session_t const *sdp;
+ char const *sdp_str;
+
+ SU_DEBUG_9(("soa_get_remote_sdp(%s::%p, [%p], [%p], [%p]) called\n",
+ ss ? ss->ss_actions->soa_name : "", ss,
+ return_sdp, return_sdp_str, return_len));
+
+ if (ss == NULL)
+ return (void)su_seterrno(EFAULT), -1;
+
+ sdp = ss->ss_remote->ssd_sdp;
+ sdp_str = ss->ss_remote->ssd_str;
+
+ if (sdp == NULL)
+ return 0;
+ if (return_sdp)
+ *return_sdp = sdp;
+ if (return_sdp_str)
+ *return_sdp_str = sdp_str;
+ if (return_len)
+ *return_len = strlen(sdp_str);
+
+ return 1;
+}
+
+/**Returns the version number of remote session description. The version
+ * numbering starts from zero and it is incremented each time
+ * soa_set_remote_sdp() or soa_set_params() modifies remote SDP.
+ *
+ * @param ss pointer to @soa session
+
+ * @return Sequence number of remote SDP.
+ *
+ * @sa soa_set_remote_sdp(), soa_get_remote_sdp(), soa_set_params(),
+ * SOATAG_REMOTE_SDP(), SOATAG_REMOTE_SDP_STR()
+ */
+int soa_get_remote_version(soa_session_t const *ss)
+{
+ assert(ss != NULL);
+ return ss->ss_remote_version;
+}
+
+/** Set remote SDP (offer or answer).
+ *
+ * <i>Remote SDP</i> is an SDP offer or answer received from the remote end.
+ * It is used together with <i>User SDP</i> as basis for SDP Offer/Answer
+ * negotiation in soa_generate_answer() or soa_process_answer(). Remote SDP
+ * can be set using soa_set_params() and SOATAG_REMOTE_SDP() or
+ * SOATAG_REMOTE_SDP_STR() tags, too.
+ *
+ * If the SDP Offer/Answer negotiation step cannot be completed and the
+ * received remote offer or answer should be ignored, call
+ * soa_clear_remote_sdp().
+ *
+ * @param ss pointer to @soa session
+ * @param sdp pointer to SDP session structure
+ * @param str pointer to string containing SDP session description
+ * @param len lenght of string @a str
+ *
+ * Either @a sdp or @a str must be non-NULL. If @a len is -1, length of
+ * string @a str is calculated using strlen().
+ *
+ * @retval 1 when SDP is stored and it differs from previously stored
+ * @retval 0 when SDP is identical to previously stored one (and remote version
+ * returned by soa_get_remote_version() is not incremented)
+ * @retval -1 upon an error
+ *
+ * @sa soa_has_received_sdp(), soa_get_remote_sdp(),
+ * soa_get_remote_version(), soa_set_params(), SOATAG_REMOTE_SDP(),
+ * SOATAG_REMOTE_SDP_STR(), soa_generate_answer(), soa_process_answer(),
+ * soa_clear_remote_sdp(), soa_init_offer_answer(), soa_get_local_sdp(),
+ * soa_set_user_sdp(), soa_set_capability_sdp().
+ */
+int soa_set_remote_sdp(soa_session_t *ss,
+ sdp_session_t const *sdp,
+ char const *str, issize_t len)
+{
+ SU_DEBUG_9(("soa_set_remote_sdp(%s::%p, %p, %p, "MOD_ZD") called\n",
+ ss ? ss->ss_actions->soa_name : "", ss, sdp, str, (ssize_t)len));
+
+ return soa_set_sdp(ss, soa_remote_sdp_kind, sdp, str, len);
+}
+
+/** Base method for setting the remote SDP (offer or answer). */
+int soa_base_set_remote_sdp(soa_session_t *ss,
+ int new_version,
+ sdp_session_t *sdp, char const *str0, isize_t len0)
+{
+ /* This is cleared in soa_generate_answer() or soa_process_answer(). */
+ ss->ss_unprocessed_remote = 1;
+
+ if (!new_version)
+ return 0;
+
+ soa_set_activity(ss, sdp->sdp_media, 1);
+
+ ss->ss_remote_version++;
+
+ return soa_description_set(ss, ss->ss_remote, sdp, str0, len0);
+}
+
+/** Clear remote SDP.
+ *
+ * Remote SDP (offer or answer) should be cleared after a it has been stored
+ * in the SDP session object using soa_set_remote_sdp() or soa_set_params(),
+ * but the SDP Offer/Answer negotiation step (soa_generate_answer() or
+ * soa_process_answer()) cannot be completed.
+ *
+ * @param ss pointer to @soa session
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error
+ *
+ * @sa soa_init_offer_answer(), soa_set_remote_sdp(),
+ * soa_has_received_sdp(), soa_set_params(), SOATAG_REMOTE_SDP(),
+ * SOATAG_REMOTE_SDP_STR(), soa_generate_answer(), soa_process_answer(),
+ * soa_process_reject().
+ */
+int soa_clear_remote_sdp(soa_session_t *ss)
+{
+ SU_DEBUG_9(("soa_clear_remote_sdp(%s::%p) called\n",
+ ss ? ss->ss_actions->soa_name : "", ss));
+
+ if (!ss)
+ return (void)su_seterrno(EFAULT), -1;
+
+ ss->ss_unprocessed_remote = 0;
+
+ return 0;
+}
+
+/** Check if remote SDP has been saved but it has not been processed.
+ *
+ * @sa soa_init_offer_answer(), soa_set_remote_sdp(), soa_generate_answer(),
+ * soa_process_answer(), soa_clear_remote_sdp().
+ */
+int soa_has_received_sdp(soa_session_t const *ss)
+{
+ return ss && ss->ss_unprocessed_remote;
+}
+
+
+/**Get local SDP.
+ *
+ * The <i>local SDP</i> is used as an offer or answer and it is generated by
+ * soa_generate_offer() or soa_generate_answer(), respectively. It can be
+ * retrieved using soa_get_params() or soa_get_paramlist() with
+ * SOATAG_LOCAL_SDP() or SOATAG_LOCAL_SDP_STR() tags.
+ *
+ * @param ss pointer to @soa session
+ * @param return_sdp SDP session structure return value
+ * @param return_sdp_str return value for pointer to string
+ * containing the user SDP session description
+ * @param return_len return value for user SDP session descrioption string
+ * length
+ *
+ * Any of the parameters @a return_sdp, @a return_sdp_str, or @a return_len
+ * may be NULL.
+ *
+ * @retval 0 if there is no description to return
+ * @retval 1 if description is returned
+ * @retval -1 upon an error
+ *
+ * @sa soa_generate_offer(), soa_generate_answer(), soa_get_params(),
+ * soa_get_paramlist(), SOATAG_LOCAL_SDP(), SOATAG_LOCAL_SDP_STR(),
+ * soa_get_user_sdp(), soa_get_remote_sdp(), soa_get_capability_sdp().
+ */
+int soa_get_local_sdp(soa_session_t const *ss,
+ sdp_session_t const **return_sdp,
+ char const **return_sdp_str,
+ isize_t *return_len)
+{
+ sdp_session_t const *sdp;
+ char const *sdp_str;
+
+ SU_DEBUG_9(("soa_get_local_sdp(%s::%p, [%p], [%p], [%p]) called\n",
+ ss ? ss->ss_actions->soa_name : "", ss,
+ return_sdp, return_sdp_str, return_len));
+
+ if (ss == NULL)
+ return (void)su_seterrno(EFAULT), -1;
+
+ sdp = ss->ss_local->ssd_sdp;
+ sdp_str = ss->ss_local->ssd_str;
+
+ if (sdp == NULL)
+ return 0;
+ if (return_sdp)
+ *return_sdp = sdp;
+ if (return_sdp_str)
+ *return_sdp_str = sdp_str;
+ if (return_len)
+ *return_len = strlen(sdp_str);
+
+ return 1;
+}
+
+/**Initialize the offer/answer state machine.
+ *
+ * @param ss pointer to @soa session
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error
+ */
+int soa_init_offer_answer(soa_session_t *ss)
+{
+ int complete;
+
+ SU_DEBUG_9(("soa_init_offer_answer(%s::%p) called\n",
+ ss ? ss->ss_actions->soa_name : "", ss));
+
+ if (!ss)
+ return 0;
+
+ complete = ss->ss_complete;
+
+ ss->ss_complete = 0;
+ ss->ss_offer_sent = 0;
+ ss->ss_offer_recv = 0;
+ ss->ss_answer_sent = 0;
+ ss->ss_answer_recv = 0;
+
+ ss->ss_unprocessed_remote = 0;
+
+ return complete;
+}
+
+/** Return list of media fetures. */
+char **soa_media_features(soa_session_t *ss, int live, su_home_t *home)
+{
+ SU_DEBUG_9(("soa_media_features(%s::%p, %u, %p) called\n",
+ ss ? ss->ss_actions->soa_name : "", ss, live, home));
+
+ if (ss)
+ return ss->ss_actions->soa_media_features(ss, live, home);
+ else
+ return (void)su_seterrno(EFAULT), NULL;
+}
+
+char **soa_base_media_features(soa_session_t *ss, int live, su_home_t *home)
+{
+ return su_zalloc(home, 8 * sizeof (char **));
+}
+
+char const * const * soa_sip_require(soa_session_t const *ss)
+{
+ SU_DEBUG_9(("soa_sip_require(%s::%p) called\n",
+ ss ? ss->ss_actions->soa_name : "", ss));
+
+ if (ss)
+ return ss->ss_actions->soa_sip_require(ss);
+ else
+ return (void)su_seterrno(EFAULT), NULL;
+}
+
+char const * const * soa_base_sip_require(soa_session_t const *ss)
+{
+ static char const *null = NULL;
+ return &null;
+}
+
+char const * const * soa_sip_supported(soa_session_t const *ss)
+{
+ SU_DEBUG_9(("soa_sip_supported(%s::%p) called\n",
+ ss ? ss->ss_actions->soa_name : "", ss));
+
+ if (ss)
+ return ss->ss_actions->soa_sip_supported(ss);
+ else
+ return (void)su_seterrno(EFAULT), NULL;
+}
+
+char const * const * soa_base_sip_supported(soa_session_t const *ss)
+{
+ static char const *null = NULL;
+ return &null;
+}
+
+int soa_remote_sip_features(soa_session_t *ss,
+ char const * const * supported,
+ char const * const * require)
+{
+ SU_DEBUG_9(("soa_remote_sip_features(%s::%p, %p, %p) called\n",
+ ss ? ss->ss_actions->soa_name : "", ss, supported, require));
+
+ if (ss)
+ return ss->ss_actions->soa_remote_sip_features(ss, supported, require);
+ else
+ return (void)su_seterrno(EFAULT), -1;
+}
+
+int soa_base_remote_sip_features(soa_session_t *ss,
+ char const * const * supported,
+ char const * const * require)
+{
+ return 0;
+}
+
+
+/**Generate offer.
+ *
+ * When generating the offer the user SDP is augmented with the required SDP
+ * lines (v=, o=, t=, c=, a=rtpmap, etc.).
+ *
+ * The resulting SDP is also known as <i>local SDP</i>. It is available with
+ * soa_get_local_sdp() or with soa_get_params() and soa_get_paramlist() tags
+ * SOATAG_LOCAL_SDP() or SOATAG_LOCAL_SDP_STR().
+ *
+ * The user SDP has been stored to the soa session with soa_set_user_sdp()
+ * or with soa_set_params() tags SOATAG_USER_SDP() or SOATAG_USER_SDP_STR().
+ * There are various other parameters directing the generation of offer, set
+ * by soa_set_params().
+ *
+ * @param ss pointer to session object
+ * @param always always send offer (even if offer/answer has been completed)
+ * @param completed pointer to callback function which is invoked when
+ * operation is completed (currently not in use)
+ *
+ * @retval 1 when operation is successful
+ * @retval 0 when operation was not needed
+ * @retval -1 upon an error
+ *
+ * @ERRORS
+ */
+int soa_generate_offer(soa_session_t *ss,
+ int always,
+ soa_callback_f *completed)
+{
+ SU_DEBUG_9(("soa_generate_offer(%s::%p, %u, %p) called\n",
+ ss ? ss->ss_actions->soa_name : "", ss, always, completed));
+
+ /** @ERROR EFAULT Bad address. */
+ if (ss == NULL)
+ return su_seterrno(EFAULT), -1;
+
+ /** @ERROR An operation is already in progress */
+ if (ss->ss_in_progress)
+ return su_seterrno(EALREADY), -1;
+
+ /** @ERROR EPROTO We have received offer, now we should send answer */
+ if (ss->ss_offer_recv && !ss->ss_answer_sent)
+ return su_seterrno(EPROTO), -1;
+
+ /** @ERROR EPROTO We have received SDP, but it has not been processed */
+ if (soa_has_received_sdp(ss))
+ return su_seterrno(EPROTO), -1;
+
+ /** @ERROR EPROTO We have sent an offer, but have received no answer */
+ if (ss->ss_offer_sent && !ss->ss_answer_recv)
+ return su_seterrno(EPROTO), -1;
+
+ /** @ERROR EPROTO We have received offer. */
+ if (ss->ss_unprocessed_remote)
+ return su_seterrno(EPROTO), -1;
+
+ /* We should avoid actual operation unless always is true */
+ (void)always; /* We always regenerate offer */
+
+ return ss->ss_actions->soa_generate_offer(ss, completed);
+ /** @sa soa_init_offer_answer(), soa_set_user_sdp(), soa_get_local_sdp(),
+ * soa_set_remote_sdp(), soa_process_answer(), soa_process_reject(),
+ * soa_generate_answer(), soa_set_params(), soa_get_params(),
+ * soa_get_paramlist(), SOATAG_USER_SDP(), SOATAG_USER_SDP_STR(),
+ * SOATAG_REMOTE_SDP(), SOATAG_REMOTE_SDP_STR().
+ */
+}
+
+int soa_base_generate_offer(soa_session_t *ss,
+ soa_callback_f *completed)
+{
+ sdp_session_t const *sdp = ss->ss_local->ssd_sdp;
+
+ (void)completed;
+
+ if (!sdp)
+ return -1;
+
+ soa_set_activity(ss, sdp->sdp_media, 0);
+
+ ss->ss_offer_sent = 1;
+ ss->ss_answer_recv = 0;
+
+ return 0;
+}
+
+/**Process offer, generate answer.
+ *
+ * When generating the offer the soa session combines remote offer with
+ * <i>user SDP</i>. There are various other parameters directing the
+ * generation of answer, set by soa_set_params().
+ *
+ * Before calling soa_generate_answer() the remote SDP offer should have
+ * been stored into the soa session @a ss with soa_set_remote_sdp() or with
+ * the soa_set_params() tags SOATAG_REMOTE_SDP() or SOATAG_REMOTE_SDP_STR().
+ *
+ * Also, the <i>user SDP</i> should have been stored into @a ss with
+ * soa_set_user_sdp() or with the soa_set_params() tags SOATAG_USER_SDP() or
+ * SOATAG_USER_SDP_STR().
+ *
+ * The resulting SDP is also known as <i>local SDP</i>. It is available with
+ * soa_get_local_sdp() or with the soa_get_params() or soa_get_paramlist()
+ * tags SOATAG_LOCAL_SDP() and SOATAG_LOCAL_SDP_STR().
+ *
+ * @param ss pointer to session object
+ * @param completed pointer to callback function which is invoked when
+ * operation is completed (currently not in use)
+ *
+ * @retval 1 when operation is successful
+ * @retval 0 when operation was not needed
+ * @retval -1 upon an error
+ *
+ * @ERRORS
+ */
+int soa_generate_answer(soa_session_t *ss,
+ soa_callback_f *completed)
+{
+ SU_DEBUG_9(("soa_generate_answer(%s::%p, %p) called\n",
+ ss ? ss->ss_actions->soa_name : "", ss, completed));
+
+ /** @ERROR EFAULT Bad address as @a ss. */
+ if (ss == NULL)
+ return su_seterrno(EFAULT), -1;
+
+ /** @ERROR An operation is already in progress. */
+ if (ss->ss_in_progress)
+ return su_seterrno(EALREADY), -1;
+
+ /** @ERROR EPROTO We have sent an offer, but have received no answer. */
+ if (ss->ss_offer_sent && !ss->ss_answer_recv)
+ return su_seterrno(EPROTO), -1;
+
+ /** @ERROR EPROTO We have not received offer. */
+ if (!ss->ss_unprocessed_remote)
+ return su_seterrno(EPROTO), -1;
+
+ return ss->ss_actions->soa_generate_answer(ss, completed);
+
+ /**@sa soa_init_offer_answer(), soa_set_user_sdp(), soa_set_remote_sdp(),
+ * soa_get_local_sdp(), soa_process_reject(), soa_generate_offer(),
+ * soa_set_params(), soa_get_params(), soa_get_paramlist(),
+ * SOATAG_USER_SDP(), SOATAG_USER_SDP_STR(), SOATAG_REMOTE_SDP(),
+ * SOATAG_REMOTE_SDP_STR().
+ */
+}
+
+/** Base method for processing offer, generating answer. */
+int soa_base_generate_answer(soa_session_t *ss,
+ soa_callback_f *completed)
+{
+ sdp_session_t const *l_sdp = ss->ss_local->ssd_sdp;
+ sdp_session_t const *r_sdp = ss->ss_remote->ssd_sdp;
+ sdp_session_t *rsession;
+
+ (void)completed;
+
+ if (!l_sdp || !r_sdp)
+ return -1;
+ rsession = sdp_session_dup(ss->ss_home, r_sdp);
+ if (!rsession)
+ return -1;
+
+ if (ss->ss_rsession)
+ su_free(ss->ss_home, ss->ss_rsession);
+ ss->ss_rsession = rsession;
+
+ soa_set_activity(ss, l_sdp->sdp_media, 0);
+ soa_set_activity(ss, r_sdp->sdp_media, 1);
+
+ ss->ss_offer_recv = 1;
+ ss->ss_answer_sent = 1;
+ ss->ss_complete = 1;
+ ss->ss_unprocessed_remote = 0;
+
+ return 0;
+}
+
+/** Complete offer-answer after receiving answer.
+ *
+ * The SDP offer/answer negotiation is completed after receiving answer from
+ * remote end. The answer is combined with the offer, and the application
+ * should activate the media and codecs according to the negotiation result,
+ * available as <i>local SDP</i>.
+ *
+ * @param ss pointer to session object
+ * @param completed pointer to callback function which is invoked when
+ * operation is completed (currently not in use)
+ *
+ * @retval 1 when operation is successful
+ * @retval 0 when operation was not needed
+ * @retval -1 upon an error
+ *
+ * @ERRORS
+ */
+int soa_process_answer(soa_session_t *ss,
+ soa_callback_f *completed)
+{
+ SU_DEBUG_9(("soa_process_answer(%s::%p, %p) called\n",
+ ss ? ss->ss_actions->soa_name : "", ss, completed));
+
+ /** @ERROR EFAULT Bad address as @a ss. */
+ if (ss == NULL)
+ return su_seterrno(EFAULT), -1;
+
+ /** @ERROR An operation is already in progress. */
+ if (ss->ss_in_progress)
+ return su_seterrno(EALREADY), -1;
+
+ /** @ERROR EPROTO We have not sent an offer
+ or already have received answer. */
+ if (!ss->ss_offer_sent || ss->ss_answer_recv)
+ return su_seterrno(EPROTO), -1;
+
+ /** @ERROR EPROTO We have not received answer. */
+ if (!ss->ss_unprocessed_remote)
+ return su_seterrno(EPROTO), -1;
+
+ /**@sa soa_init_offer_answer(), soa_set_user_sdp(), soa_set_remote_sdp(),
+ * soa_get_local_sdp(), soa_generate_offer(), soa_generate_answer(),
+ * soa_process_reject(), soa_set_params(), soa_get_params(),
+ * soa_get_paramlist(), SOATAG_USER_SDP(), SOATAG_USER_SDP_STR(),
+ * SOATAG_REMOTE_SDP(), SOATAG_REMOTE_SDP_STR().
+ */
+
+ return ss->ss_actions->soa_process_answer(ss, completed);
+}
+
+/** Base method for completing offer-answer after receiving answer.
+ */
+int soa_base_process_answer(soa_session_t *ss,
+ soa_callback_f *completed)
+{
+ sdp_session_t const *l_sdp = ss->ss_local->ssd_sdp;
+ sdp_session_t const *r_sdp = ss->ss_remote->ssd_sdp;
+ sdp_session_t *rsession;
+
+ (void)completed;
+
+ if (!l_sdp || !r_sdp)
+ return -1;
+ rsession = sdp_session_dup(ss->ss_home, r_sdp);
+ if (!rsession)
+ return -1;
+
+ if (ss->ss_rsession)
+ su_free(ss->ss_home, ss->ss_rsession);
+ ss->ss_rsession = rsession;
+
+ soa_set_activity(ss, l_sdp->sdp_media, 0);
+ soa_set_activity(ss, r_sdp->sdp_media, 1);
+
+ ss->ss_answer_recv = 1;
+ ss->ss_complete = 1;
+ ss->ss_unprocessed_remote = 0;
+
+ return 0;
+}
+
+/** Process rejection of offer.
+ *
+ * If the SDP offer was rejected (e.g., an offer in re-INVITE asked remote
+ * end to add video to the session but the request was rejected), the
+ * session should be restored to the state it was before last offer-answer
+ * negotation round with soa_process_reject().
+ *
+ * @param ss pointer to session object
+ * @param completed pointer to callback function which is invoked when
+ * operation is completed (currently not in use)
+ *
+ * @retval 1 when operation is successful
+ * @retval 0 when operation was not needed
+ * @retval -1 upon an error
+ *
+ * @ERRORS
+ */
+int soa_process_reject(soa_session_t *ss,
+ soa_callback_f *completed)
+{
+ SU_DEBUG_9(("soa_process_reject(%s::%p, %p) called\n",
+ ss ? ss->ss_actions->soa_name : "", ss, completed));
+
+ /** @ERROR EFAULT Bad address as @a ss. */
+ if (ss == NULL)
+ return su_seterrno(EFAULT), -1;
+
+ /** @ERROR An operation is already in progress. */
+ if (ss->ss_in_progress)
+ return su_seterrno(EALREADY), -1;
+
+ /** @ERROR EPROTO We have not sent an offer
+ or already have received answer. */
+ if (!ss->ss_offer_sent || ss->ss_answer_recv)
+ return su_seterrno(EPROTO), -1;
+
+ /**@sa soa_init_offer_answer(), soa_set_user_sdp(), soa_set_remote_sdp(),
+ * soa_get_local_sdp(), soa_generate_offer(), soa_generate_answer(),
+ * soa_process_answer(), soa_set_params(), soa_get_params(),
+ * soa_get_paramlist(), SOATAG_USER_SDP(), SOATAG_USER_SDP_STR(),
+ * SOATAG_REMOTE_SDP(), SOATAG_REMOTE_SDP_STR().
+ */
+
+ return ss->ss_actions->soa_process_reject(ss, completed);
+}
+
+/** Base method for processing rejection of offer.
+ */
+int soa_base_process_reject(soa_session_t *ss,
+ soa_callback_f *completed)
+{
+ sdp_session_t const *l_sdp = ss->ss_local->ssd_sdp;
+
+ (void)completed;
+
+ if (!l_sdp)
+ return -1;
+
+ soa_set_activity(ss, l_sdp->sdp_media, 0);
+
+ ss->ss_offer_sent = 0;
+
+ return 0;
+}
+
+/** Activate session.
+ *
+ * Mark soa session as active.
+ *
+ * @retval 0 when operation was successful
+ * @retval -1 upon an error
+ *
+ * @ERRORS
+ */
+int soa_activate(soa_session_t *ss, char const *option)
+{
+ SU_DEBUG_9(("soa_activate(%s::%p, %s%s%s) called\n",
+ ss ? ss->ss_actions->soa_name : "", ss, NICE(option)));
+
+ /** @ERROR EFAULT Bad address as @a ss. */
+ if (ss == NULL)
+ return -1;
+
+ ss->ss_active = 1;
+
+ return ss->ss_actions->soa_activate_session(ss, option);
+}
+
+int soa_base_activate(soa_session_t *ss, char const *option)
+{
+ (void)ss;
+ (void)option;
+ return 0;
+}
+
+/** Deactivate session.
+ *
+ * Mark soa session as inactive.
+ *
+ * @retval 0 when operation was successful
+ * @retval -1 upon an error
+ *
+ * @ERRORS
+ */
+int soa_deactivate(soa_session_t *ss, char const *option)
+{
+ SU_DEBUG_9(("soa_deactivate(%s::%p, %s%s%s) called\n",
+ ss ? ss->ss_actions->soa_name : "", ss, NICE(option)));
+
+ /** @ERROR EFAULT Bad address as @a ss. */
+ if (ss == NULL)
+ return -1;
+
+ ss->ss_active = 0;
+
+ return ss->ss_actions->soa_deactivate_session(ss, option);
+}
+
+int soa_base_deactivate(soa_session_t *ss, char const *option)
+{
+ (void)ss;
+ (void)option;
+ return 0;
+}
+
+/** Terminate session. */
+void soa_terminate(soa_session_t *ss, char const *option)
+{
+ SU_DEBUG_9(("soa_terminate(%s::%p) called\n",
+ ss ? ss->ss_actions->soa_name : "", ss));
+
+ /** @ERROR EFAULT Bad address as @a ss. */
+ if (ss == NULL)
+ return;
+
+ ss->ss_active = 0;
+ ss->ss_terminated++;
+
+ ss->ss_actions->soa_terminate_session(ss, option);
+}
+
+void soa_base_terminate(soa_session_t *ss, char const *option)
+{
+ (void)option;
+
+ soa_init_offer_answer(ss);
+ ss->ss_oa_rounds = 0;
+
+ soa_description_free(ss, ss->ss_remote);
+ soa_set_activity(ss, NULL, 0);
+ soa_set_activity(ss, NULL, 1);
+}
+
+/** Return true if the SDP Offer/Answer negotation is complete.
+ *
+ * The soa_init_offer_answer() clears the completion flag.
+ */
+int soa_is_complete(soa_session_t const *ss)
+{
+ return ss && ss->ss_complete;
+}
+
+/** Return true if audio has been activated. */
+int soa_is_audio_active(soa_session_t const *ss)
+{
+ return ss ? ss->ss_local_activity->ma_audio : SOA_ACTIVE_DISABLED;
+}
+
+/** Return true if video has been activated. */
+int soa_is_video_active(soa_session_t const *ss)
+{
+ return ss ? ss->ss_local_activity->ma_video : SOA_ACTIVE_DISABLED;
+}
+
+/** Return true if image sharing has been activated. */
+int soa_is_image_active(soa_session_t const *ss)
+{
+ return ss ? ss->ss_local_activity->ma_image : SOA_ACTIVE_DISABLED;
+}
+
+/** Return true if messaging session has been activated. */
+int soa_is_chat_active(soa_session_t const *ss)
+{
+ return ss ? ss->ss_local_activity->ma_chat : SOA_ACTIVE_DISABLED;
+}
+
+/** Return true if remote audio is active (not on hold). */
+int soa_is_remote_audio_active(soa_session_t const *ss)
+{
+ return ss ? ss->ss_remote_activity->ma_audio : SOA_ACTIVE_DISABLED;
+}
+
+/** Return true if remote video is active (not on hold). */
+int soa_is_remote_video_active(soa_session_t const *ss)
+{
+ return ss ? ss->ss_remote_activity->ma_video : SOA_ACTIVE_DISABLED;
+}
+
+/** Return true if image sharing is active (not on hold). */
+int soa_is_remote_image_active(soa_session_t const *ss)
+{
+ return ss ? ss->ss_remote_activity->ma_image : SOA_ACTIVE_DISABLED;
+}
+
+/** Return true if chat session is active (not on hold). */
+int soa_is_remote_chat_active(soa_session_t const *ss)
+{
+ return ss ? ss->ss_remote_activity->ma_chat : SOA_ACTIVE_DISABLED;
+}
+
+/* ======================================================================== */
+/* Methods used by soa instances */
+
+int soa_set_status(soa_session_t *ss, int status, char const *phrase)
+{
+ if (ss) {
+ ss->ss_status = status, ss->ss_phrase = phrase;
+ ss->ss_wcode = 0, ss->ss_warning = NULL;
+ }
+ return -1;
+}
+
+int soa_set_warning(soa_session_t *ss, int code, char const *text)
+{
+ if (ss)
+ ss->ss_wcode = code, ss->ss_warning = text;
+ return -1;
+}
+
+static inline
+int soa_media_is_ready(soa_session_t const *ss)
+{
+ XXX;
+ return 0;
+ /* return ss && ss->ss_session != NULL; */
+}
+
+void soa_set_activity(soa_session_t *ss,
+ sdp_media_t const *m,
+ int remote)
+{
+ struct soa_media_activity *ma;
+ sdp_connection_t const *c;
+ int mode;
+ int ma_audio = SOA_ACTIVE_DISABLED;
+ int ma_video = SOA_ACTIVE_DISABLED;
+ int ma_chat = SOA_ACTIVE_DISABLED;
+ int ma_image = SOA_ACTIVE_DISABLED;
+ int *p;
+
+ remote = !!remote;
+
+ ma = remote ? ss->ss_remote_activity : ss->ss_local_activity;
+
+ for (; m; m = m->m_next) {
+ if (m->m_type == sdp_media_audio)
+ p = &ma_audio;
+ else if (m->m_type == sdp_media_video)
+ p = &ma_video;
+ else if (m->m_type == sdp_media_image)
+ p = &ma_image;
+ else if (strcasecmp(m->m_type_name, "message") == 0)
+ p = &ma_chat;
+ else
+ continue;
+
+ if (m->m_rejected) {
+ if (*p < 0)
+ *p = SOA_ACTIVE_REJECTED;
+ continue;
+ }
+
+ mode = m->m_mode;
+
+ c = sdp_media_connections((sdp_media_t *)m);
+
+ if (remote != (c && c->c_mcast))
+ mode = ((mode << 1) & 2) | ((mode >> 1) & 1);
+
+ if (*p < 0)
+ *p = mode;
+ else
+ *p |= mode;
+ }
+
+ ma->ma_audio = ma_audio;
+ ma->ma_video = ma_video;
+ ma->ma_image = ma_image;
+ ma->ma_chat = ma_chat;
+}
+
+/* ----------------------------------------------------------------------*/
+/* Handle SDP */
+
+
+/**
+ * Parses and stores session description
+ *
+ * @param ss instance pointer
+ * @param what caps, local or remote
+ * @param sdp0 new sdp (parsed)
+ * @param sdp_str new sdp (unparsed)
+ * @param str_len length on unparsed data
+ **/
+static
+int soa_set_sdp(soa_session_t *ss,
+ enum soa_sdp_kind what,
+ sdp_session_t const *sdp0,
+ char const *sdp_str, issize_t str_len)
+{
+ struct soa_description *ssd;
+ int flags, new_version, retval;
+ sdp_parser_t *parser = NULL;
+ sdp_session_t sdp[1];
+
+ switch (what) {
+ case soa_capability_sdp_kind:
+ ssd = ss->ss_caps;
+ flags = sdp_f_config;
+ break;
+ case soa_user_sdp_kind:
+ ssd = ss->ss_user;
+ flags = sdp_f_config;
+ break;
+ case soa_remote_sdp_kind:
+ ssd = ss->ss_remote;
+ flags = sdp_f_mode_0000;
+ break;
+ default:
+ return -1;
+ }
+
+ if (sdp_str && str_len == -1)
+ str_len = strlen(sdp_str);
+
+ if (sdp0)
+ new_version = sdp_session_cmp(sdp0, ssd->ssd_sdp) != 0;
+ else if (sdp_str)
+ new_version = !ssd->ssd_unparsed ||
+ str0ncmp(sdp_str, ssd->ssd_unparsed, str_len) != 0 ||
+ ssd->ssd_unparsed[str_len] != '\0';
+ else
+ return (void)su_seterrno(EINVAL), -1;
+
+ if (!new_version) {
+ if (what == soa_remote_sdp_kind) {
+ *sdp = *ssd->ssd_sdp;
+ /* XXX - should check changes by soa_set_remote_sdp */
+ return ss->ss_actions->soa_set_remote_sdp(ss, new_version,
+ sdp, sdp_str, str_len);
+ }
+ return 0;
+ }
+
+ if (sdp0) {
+ /* note: case 1 - src in parsed form */
+ *sdp = *sdp0;
+ }
+ else /* if (sdp_str) */ {
+ /* note: case 2 - src in unparsed form */
+ parser = sdp_parse(ss->ss_home, sdp_str, str_len, flags | sdp_f_anynet);
+
+ if (sdp_parsing_error(parser)) {
+ sdp_parser_free(parser);
+ return soa_set_status(ss, 400, "Bad Session Description");
+ }
+
+ *sdp = *sdp_session(parser);
+ }
+
+ switch (what) {
+ case soa_capability_sdp_kind:
+ retval = ss->ss_actions->soa_set_capability_sdp(ss, sdp, sdp_str, str_len);
+ break;
+ case soa_user_sdp_kind:
+ retval = ss->ss_actions->soa_set_user_sdp(ss, sdp, sdp_str, str_len);
+ break;
+ case soa_remote_sdp_kind:
+ retval = ss->ss_actions->soa_set_remote_sdp(ss, 1, sdp, sdp_str, str_len);
+ break;
+ default:
+ retval = soa_set_status(ss, 500, "Internal Error");
+ break;
+ }
+
+ if (parser)
+ sdp_parser_free(parser);
+
+ return retval;
+}
+
+
+/** Set session descriptions. */
+int soa_description_set(soa_session_t *ss,
+ struct soa_description *ssd,
+ sdp_session_t *sdp,
+ char const *sdp_str,
+ isize_t str_len)
+{
+ int retval = -1;
+
+ sdp_printer_t *printer = NULL;
+ sdp_session_t *sdp_new;
+ char *sdp_str_new;
+ char *sdp_str0_new;
+
+ void *tbf1, *tbf2, *tbf3, *tbf4;
+
+ /* Store description in three forms: unparsed, parsed and reprinted */
+
+ sdp_new = sdp_session_dup(ss->ss_home, sdp);
+ printer = sdp_print(ss->ss_home, sdp, NULL, 0, 0);
+ sdp_str_new = (char *)sdp_message(printer);
+ if (sdp_str)
+ sdp_str0_new = su_strndup(ss->ss_home, sdp_str, str_len);
+ else
+ sdp_str0_new = sdp_str_new;
+
+ if (sdp_new && printer && sdp_str_new && sdp_str0_new) {
+ tbf1 = ssd->ssd_sdp, tbf2 = ssd->ssd_printer;
+ tbf3 = (void *)ssd->ssd_str, tbf4 = (void *)ssd->ssd_unparsed;
+
+ ssd->ssd_sdp = sdp_new;
+ ssd->ssd_printer = printer;
+ ssd->ssd_str = sdp_str_new;
+ ssd->ssd_unparsed = sdp_str0_new;
+
+ retval = 1;
+ }
+ else {
+ tbf1 = sdp_new, tbf2 = printer, tbf3 = sdp_str_new, tbf4 = sdp_str0_new;
+ }
+
+ su_free(ss->ss_home, tbf1);
+ sdp_printer_free(tbf2);
+ if (tbf3 != tbf4)
+ su_free(ss->ss_home, tbf4);
+
+ return retval;
+}
+
+
+/** Duplicate a session descriptions. */
+int soa_description_dup(su_home_t *home,
+ struct soa_description *ssd,
+ struct soa_description const *ssd0)
+{
+ if (ssd0->ssd_sdp) {
+ ssd->ssd_sdp = sdp_session_dup(home, ssd0->ssd_sdp);
+ ssd->ssd_printer = sdp_print(home, ssd->ssd_sdp, NULL, 0, 0);
+ ssd->ssd_str = (char *)sdp_message(ssd->ssd_printer);
+ if (ssd0->ssd_str != ssd0->ssd_unparsed)
+ ssd->ssd_unparsed = su_strdup(home, ssd0->ssd_unparsed);
+ else
+ ssd->ssd_unparsed = ssd->ssd_str;
+ }
+
+ return 0;
+}
+
+/** Free session descriptions. */
+void soa_description_free(soa_session_t *ss,
+ struct soa_description *ssd)
+{
+ void *tbf1, *tbf2, *tbf3, *tbf4;
+
+ tbf1 = ssd->ssd_sdp, tbf2 = ssd->ssd_printer;
+ tbf3 = (void *)ssd->ssd_str, tbf4 = (void *)ssd->ssd_unparsed;
+
+ memset(ssd, 0, sizeof *ssd);
+
+ su_free(ss->ss_home, tbf1);
+ sdp_printer_free(tbf2);
+ if (tbf3 != tbf4)
+ su_free(ss->ss_home, tbf4);
+}
+
+
+/** Initialize SDP o= line */
+int
+soa_init_sdp_origin(soa_session_t *ss, sdp_origin_t *o, char buffer[64])
+{
+ sdp_connection_t *c;
+
+ if (ss == NULL || o == NULL)
+ return su_seterrno(EFAULT), -1;
+
+ assert(o->o_address);
+
+ if (!o->o_username)
+ o->o_username = "-";
+
+ if (o->o_id == 0)
+ su_randmem(&o->o_id, sizeof o->o_id);
+ o->o_id &= ((unsigned longlong)1 << 63) - 1;
+
+ if (o->o_version == 0)
+ su_randmem(&o->o_version, sizeof o->o_version);
+ o->o_version &= ((unsigned longlong)1 << 63) - 1;
+
+ c = o->o_address;
+
+ if (!c->c_nettype ||
+ !c->c_address ||
+ strcmp(c->c_address, "") == 0 ||
+ strcmp(c->c_address, "0.0.0.0") == 0 ||
+ strcmp(c->c_address, "::") == 0 ||
+ !host_is_local(c->c_address)) {
+ return soa_init_sdp_connection(ss, c, buffer);
+ }
+
+ return 0;
+}
+
+/** Search for an local address item from string provided by user */
+static
+su_localinfo_t *li_in_list(su_localinfo_t *li0, char const **llist)
+{
+ char const *list = *llist;
+ size_t n;
+
+ if (!list)
+ return NULL;
+
+ while ((n = strcspn(list, ", "))) {
+ su_localinfo_t *li;
+
+ for (li = li0; li; li = li->li_next) {
+ if (strncasecmp(li->li_canonname, list, n) == 0 &&
+ li->li_canonname[n] == '\0')
+ break;
+ }
+
+ list += n; while (list[0] == ' ' || list[0] == ',') list++;
+ *llist = list;
+
+ if (li)
+ return li;
+ }
+
+ return NULL;
+}
+
+
+/** Obtain a local address for SDP connection structure */
+int
+soa_init_sdp_connection(soa_session_t *ss,
+ sdp_connection_t *c,
+ char buffer[64])
+{
+ su_localinfo_t *res, hints[1] = {{ LI_CANONNAME | LI_NUMERIC }};
+ su_localinfo_t *li, *li4, *li6;
+ char const *address;
+ int ip4, ip6, error;
+
+ if (ss == NULL || c == NULL)
+ return su_seterrno(EFAULT), -1;
+
+ address = ss->ss_address;
+
+ if (host_is_ip_address(address)) {
+ /* Use the application-specified address -
+ * do not check that it is found from the local address list */
+ c->c_nettype = sdp_net_in;
+
+ if (host_is_ip4_address(address))
+ c->c_addrtype = sdp_addr_ip4;
+ else
+ c->c_addrtype = sdp_addr_ip6;
+
+ if (!host_is_ip6_reference(address)) {
+ c->c_address = strcpy(buffer, address);
+ }
+ else {
+ /* Remove brackets [] around the reference */
+ size_t len = strlen(address + 1);
+ c->c_address = memcpy(buffer, address + 1, len - 1);
+ buffer[len - 1] = '\0';
+ }
+ return 0;
+ }
+
+ /* XXX - using LI_SCOPE_LINK requires some tweaking */
+ hints->li_scope = LI_SCOPE_GLOBAL | LI_SCOPE_SITE /* | LI_SCOPE_LINK */;
+
+ switch (ss->ss_af) {
+ case SOA_AF_IP4_ONLY:
+ hints->li_family = AF_INET, ip4 = 1, ip6 = 0;
+ break;
+
+#if HAVE_SIN6
+ case SOA_AF_IP6_ONLY:
+ hints->li_family = AF_INET6, ip6 = 1, ip4 = 0;
+ break;
+ case SOA_AF_IP4_IP6:
+ ip4 = 2, ip6 = 1;
+ break;
+ case SOA_AF_IP6_IP4:
+ ip4 = 1, ip6 = 2;
+ break;
+#endif
+ default:
+ ip4 = ip6 = 1;
+ }
+
+ for (res = NULL; res == NULL;) {
+ if ((error = su_getlocalinfo(hints, &res)) < 0
+ && error != ELI_NOADDRESS) {
+ SU_DEBUG_1(("%s: su_localinfo: %s\n", __func__,
+ su_gli_strerror(error)));
+ return -1;
+ }
+ if (hints->li_scope & LI_SCOPE_HOST)
+ break;
+ hints->li_scope |= LI_SCOPE_HOST;
+ }
+
+ if (!(ip4 & ip6 && c->c_nettype == sdp_net_in))
+ /* Use ss_af preference */;
+ else if (c->c_addrtype == sdp_addr_ip4)
+ ip4 = 2, ip6 = 1;
+ else if (c->c_addrtype == sdp_addr_ip6)
+ ip6 = 2, ip4 = 1;
+
+ if (address)
+ SU_DEBUG_3(("%s: searching for %s from list \"%s\"\n",
+ __func__, ip6 && !ip4 ? "IP6 " : !ip6 && ip4 ? "IP4 " : "",
+ address));
+
+ li = res, li4 = NULL, li6 = NULL;
+
+ for (;;) {
+ if (address)
+ li = li_in_list(li, &address);
+
+ if (!li)
+ break;
+#if HAVE_SIN6
+ else if (li->li_family == AF_INET6) {
+ if (ip6 >= ip4)
+ break;
+ else if (!li6)
+ li6 = li; /* Best IP6 address */
+ }
+#endif
+ else if (li->li_family == AF_INET) {
+ if (ip4 > ip6)
+ break;
+ else if (!li4)
+ li4 = li; /* Best IP4 address */
+ }
+
+ if (!address)
+ li = li->li_next;
+ }
+
+ if (li == NULL)
+ li = li4;
+ if (li == NULL)
+ li = li6;
+
+ if (li == NULL)
+ ;
+ else if (li->li_family == AF_INET)
+ c->c_nettype = sdp_net_in, c->c_addrtype = sdp_addr_ip4;
+#if HAVE_SIN6
+ else if (li->li_family == AF_INET6)
+ c->c_nettype = sdp_net_in, c->c_addrtype = sdp_addr_ip6;
+#endif
+
+ if (li) {
+ assert(strlen(li->li_canonname) < 64);
+ c->c_address = strcpy(buffer, li->li_canonname);
+ }
+
+ su_freelocalinfo(res);
+
+ if (!li)
+ return -1;
+ else
+ return 0;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/soa.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/soa.docs Thu Dec 21 01:30:28 2006
@@ -0,0 +1,887 @@
+/**@MODULEPAGE "soa" - SDP Offer/Answer Engine Module
+
+ at section soa_meta Module Information
+
+The Sofia SIP @b soa module consists of an asynchronous SDP Offer/Answer engine
+library. The interface to library is defined in <soa.h>.
+
+ at CONTACT Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ at STATUS @SofiaSIP Core library
+
+ at LICENSE LGPL
+
+ at section soa_oveview Using soa engine
+
+SIP uses SDP and a negotiation procedure known as "SDP
+Offer-Answer Model" to establish the multimedia sessions. The
+SDP Offer-Answer negotiation is specified in
+<a href="http://ietf.org/rfc/rfc3264.txt">RFC 3264</a>.
+
+The soa engine is implemented in object-oriented manner. The default soa
+object just implements the basic SDP negotiation and basic SIP call model. A
+more complex soa object implementation can manipulate the call model and
+initiate actions on behalf of application.
+
+ at section soa_model SDP Offer/Answer Model
+
+The basic capabilities provided by Offer/Answer mechanism include
+-# generating SDP offer (section 5)
+-# processing SDP offer, generating SDP answer (section 6)
+-# processing SDP answer (section 7)
+-# modifying session (section 8)
+-# indicating capabilities (section 9)
+
+The offerer indicates its capabilities in the offer:
+- the media streams it wants to establish
+- transport addresses it uses to receive by media streams
+ (IP addresses, port numbers, transport protocols)
+- the codecs used by particular streams
+- codec parameters (for instance, codec profile used by H.263)
+
+The answerer indicates which parts of the offer are acceptable to
+it in the answer:
+- the media streams it agrees to establish
+- transport addresses answerer uses to receive by media streams
+- the codecs and codec parameters used by particular streams
+
+Note that the capabilites indicate what the party generating the
+SDP is prepared to receive. They can send anything the other end
+accepts.
+
+There may be other things, like encryption keys included in the
+session description.
+
+The advanced capabilities are required by more complicated negotiation
+involving two or more offer-answer rounds. For instance, an extension known
+as session <i>preconditions</i> is defined
+<a href="http://ietf.org/rfc/rfc3312.txt">RFC 3312</a>.
+Another example of two-phase negotiation is presented in RFC
+3264 section 10.2, showing how a single codec can be selected.
+
+ at section soa_motivation SOA Design
+
+Why to have simple interface? Is it not simple enough to include SDP offer
+with your INVITE, and act on SDP answer in 200 OK?
+
+Our design goal is to allow application to follow the simple call
+model, regardless of the underlying complications - early
+sessions, preconditions, session timers, 3rd party call control.
+In other words, we would like a have a simple "cooked" interface
+toward naive applications even if the underlying call follows the
+byzantine call model chosen by 3GPP.
+
+ at section soa_with_sip Using SDP Offer/Answer with SIP
+
+Using SDP Offer/Answer with SIP is specified in
+<a href="http://ietf.org/rfc/rfc3261.txt">RFC 3261</a>,
+<a href="http://ietf.org/rfc/rfc3262.txt">RFC 3262 (100rel and PRACK)</a>, and
+<a href="http://ietf.org/rfc/rfc3211.txt">RFC 3311 (UPDATE)</a>.
+
+There is a @ref soa_sdp_oa_use_cases "separate page listing scenarios".
+
+The rules for sending offers:
+- offer may be sent in INVITE
+- if there was no offer in INVITE, offer MUST be sent in first
+ reliable response to INVITE
+- offer may be sent in 100rel (reliable 1XX series response)
+- offer may be sent in PRACK
+- offer may be sent in UPDATE
+
+PRACK may only be sent when an unacknowledged 100rel (reliable 1XX
+series response) is received. UPDATE may be sent during early or
+established dialog.
+
+Only one INVITE request may be pending within a dialog. Only one
+non-INVITE request may be pending within a dialog (in one
+direction): it is not possible to send UPDATE if no final response
+has been received to PRACK.
+
+If there is already an offer/answer exchange in progress, no offer
+MUST be sent. Offer/answer exchange is in progress if offer has
+been sent but no answer has been received, or if an offer has been
+received but no answer has been generated.
+
+The rules for sending answer:
+- when offer is received with INVITE
+ - answer MAY be sent with next end-to-end 1XX or 2XX response
+ - answer MUST be sent in a reliable response (100rel or 2XX)
+- when offer is received in 2XX response
+ - answer MUST be sent in ACK
+- when offer is received with 100rel response
+ - answer MUST be sent with PRACK
+- when offer is received with PRACK or UPDATE
+ - answer MUST be sent with 2XX response to PRACK or UPDATE
+
+Offer or answer in PRACK MUST be processed even if we have already
+sent 2XX to INVITE.
+
+The rules for receiving answer:
+- if offer was sent in INVITE, first session description in any
+ non-error response to INVITE is treated as the answer
+- if offer was sent in 2XX response, session description in
+ ACK is answer
+- if offer was sent in 100rel response, session description in
+ PRACK is answer
+- if offer was sent in PRACK or UPDATE, session description in
+ 2XX response is answer
+
+Rules for situations when endpoint MUST ignore the SDP:
+- If offer was sent in INVITE, only the first session description in
+ any non-error (1XX or 2XX) response to INVITE is processed, rest
+ are ignored
+- If no offer was sent in 2XX response to INVITE, SDP in ACK is ignored
+- If no offer was sent in PRACK, SDP in response to it is ignored
+- If no offer was sent in UPDATE, SDP in response to it is ignored
+
+The re-INVITEs and UPDATEs are sent for two different purposes:
+updating or modifying SIP state, or updating or modifying the
+associated session. Session timer extension (not yet an rfc) is an
+example of the first. Putting a call on hold, or adding video to
+audio-only call is an example of the second. So, upon receiving
+re-INVITE, there might be quite different things happening. The
+application can just return a 200 OK with previous SDP, sometimes
+it must indicate call being on hold and sometimes ask user for
+permission (for adding video).
+
+Rules for resolving glare (both endpoints trying to send offer at the same
+time):
+- if a offer is received while UAS has generated an offer,
+ it must be rejected (with SIP 491 response).
+
+ at section soa_use_cases SOA and SDP Offer/Answer Scenarios
+
+Note that due to limitations in space
+- soa_set_params() is referred as @c set_params
+- soa_set_remote_sdp() is referred as @c set_remote
+- soa_generate_offer() followed by soa_get_session_sdp()
+ is referred as @c gen_offer
+- soa_generate_answer() followed by soa_get_session_sdp()
+ is referred as @c gen_answer
+- soa_process_answer() is referred as @c proc_answer
+
+ at subsection soa_uc_basic_out Basic Call Out
+
+This is the "basic" outbound call model.
+
+<pre>
+ APPL NUA SOA REMOTE
+ | | | |
+ 0 | | | |
+ 1 |----INVITE---->| | |
+ 2 | |--set_params-->| |
+ 3 | |---gen_offer-->| |
+ 4 | | | |
+ 5 | |-------------------INVITE(sdp offer)-->|
+ 6 | | | |
+ 7 | | | |
+ 8 | | | |
+ 9 | |< - - - - - - - - - - 180 Ringing - - -|
+10 |< - - 180 - - -| | |
+11 | | | |
+12 | |<-------------------200(sdp answer)----|
+13 | |--set_remote-->| |
+14 | |--proc_answer->| |
+15 |<-----200------| | |
+16 | | | |
+17 | |----activate-->| |
+18 |<----active----| | |
+19 | |-------------------------ACK---------->|
+20 | | | |
+21 | | | |
+22 | | | |
+ | | | |
+</pre>
+
+ at subsection soa_uc_basic_in Basic Call In
+
+This is the "basic" inbound call model.
+
+<pre>
+ APPL NUA SOA REMOTE
+ | | | |
+ 0 | | | |
+ 1 | |<------------------INVITE(sdp offer)---|
+ 2 | | | |
+ 3 | |--set_remote-->| |
+ 4 | | | |
+ 5 |<---INVITE-----| | |
+ 6 | | | |
+ 7 | | | |
+ 8 |- - -180- - - >| | |
+ 9 | |- - - - - - - - - - 180 Ringing - - - >|
+10 | | | |
+11 | | | |
+12 |-----200------>| | |
+13 | |--set_params-->| |
+14 | | | |
+15 | |--gen_answer-->| |
+16 | | | |
+17 |<----active----| | |
+18 | |----activate-->| |
+19 | |--------------------200 (sdp answer)-->|
+20 | | | |
+21 | | | |
+22 | |<------------------------ACK-----------|
+23 |<-----ACK------| | |
+24 | | | |
+ | | | |
+</pre>
+
+ at subsection soa_uc_basic_3p 3rd Party Call In
+
+The 3rd-party call model just reverses the O/A roles of callee and caller.
+
+<pre>
+ t APPL NUA SOA REMOTE
+ | | | |
+ 0 | | | |
+ 1 | |<----------------------INVITE----------|
+ 2 | | | |
+ 3 |<---INVITE-----| | |
+ 4 | | | |
+ 5 | | | |
+ 6 | | | |
+ 7 |----200 OK---->| | |
+ 8 | |--set_params-->| |
+ 9 | | | |
+10 | |--gen_offer--->| |
+11 | | | |
+12 | | | |
+13 | |----------------------200 (off) ------>|
+14 | | | |
+15 | | | |
+16 | |<---------------------ACK (ans)--------|
+17 | |--set_remote-->| |
+18 | |--proc_answer->| |
+19 |<----ACK-------| | |
+20 |<----active----| | |
+21 | |----activate-->| |
+22 | | | |
+ | | | |
+</pre>
+
+ at subsection soa_uc_early_out Callout with Early Media
+
+It is possible to establish media session before call is completed. In this
+case, the 180 Ringing contains the SDP answer. A copy of SDP answer is
+included in the 200 OK response, too, because the 180 Ringing is not
+acknowledged and it may be lost.
+
+This is preferred to the basic call model above, as the endpoints has more
+time to establish the media session.
+
+<pre>
+ t APPL NUA SOA REMOTE
+ | | | |
+ 0 | | | |
+ 1 |----INVITE---->| | |
+ 2 | |--set_params-->| |
+ 3 | | | |
+ 4 | |--gen_offer--->| |
+ 5 | | | |
+ 6 | | | |
+ 7 | |-------------------INVITE(sdp offer)-->|
+ 8 | | | |
+ 9 | | | |
+10 | | | |
+11 | |<-------------------180(sdp answer)----|
+12 | |--set_remote-->| |
+13 |<-----180------|--proc_answer->| |
+14 | | | |
+15 | | | |
+16 | | | |
+17 | |<-----------------200(copy of answer)--|
+18 | (copy is ignored) | |
+19 | | | |
+20 |<-----200------| | |
+21 | |----activate-->| |
+22 |<----active----| | |
+23 | |-------------------------ACK---------->|
+24 | | | |
+ | | | |
+</pre>
+
+ at subsection soa_uc_early_in Call In Establishing Early Media
+
+The mirror of the previous scenario:
+
+<pre>
+ t APPL NUA SOA REMOTE
+ | | | |
+ 0 | | | |
+ 1 | |<------------------INVITE(sdp offer)---|
+ 2 | |--set_remote-->| |
+ 3 |<---INVITE-----| | |
+ 4 | | | |
+ 5 | | | |
+ 6 |---180 Ring--->| | |
+ 7 | |--set_params-->| |
+ 8 | |--gen_offer--->| |
+ 9 | | (Note 1) |
+10 | | | |
+11 | |-------------------180 (sdp answer)--->|
+12 | | | |
+13 | | | |
+14 | | | |
+15 |----200 OK---->| | |
+16 | |--set_params-->| |
+17 | | | |
+18 | | | |
+19 | |-----------------200 (copy of answer)->|
+20 | |----activate-->| |
+21 |<----active----| | |
+22 | |<------------------------ACK-----------|
+23 |<-----ACK------| | |
+24 | | | |
+ | | | |
+</pre>
+<b>Note 1:</b> the user expectation (set by ordinary telephone) here is
+that callee sends a ringing tone towards caller and discards any media sent
+by caller until the call is accepted (200 OK is sent towards caller).
+
+ at subsection soa_uc_100rel_out Call Out with PRACK
+
+Here is second alternative establishing media session before call is
+completed. In this case, the 180 Ringing contains the SDP answer. The 180
+Ringing is now sent reliably. In other words, it is acknowledged by a PRACK
+request.
+
+<pre>
+ t APPL NUA SOA REMOTE
+ | | | |
+ 0 | | | |
+ 1 |----INVITE---->| | |
+ 2 | |--set_params-->| |
+ 3 | | | |
+ 4 | |--gen_offer--->| |
+ 5 | | | |
+ 6 | | | |
+ 7 | |-------------------INVITE(sdp offer)-->|
+ 8 | | | |
+ 9 | | | |
+10 | |<-------------------183(sdp answer)----|
+11 | |--set_remote-->| |
+12 | |--proc_answer->| |
+13 |<-----183------| | |
+14 | | | |
+15 | |-----------------------PRACK---------->|
+16 | |<--------------------200/PRACK---------|
+17 |<--200/PRACK---| | |
+18 | | | |
+19 | | | |
+20 | |<--------------------180 Ringing-------|
+21 |<-----180------| | |
+22 | |-----------------------PRACK---------->|
+23 | |<--------------------200/PRACK---------|
+24 |<--200/PRACK---| | |
+25 | | | |
+26 | | | |
+27 | |<----------------------200 OK----------|
+28 |<--200/INVITE--| | |
+29 | |----activate-->| |
+30 |<----active----| | |
+31 | |-----------------------ACK------------>|
+32 | | | |
+ | | | |
+</pre>
+
+ at subsection soa_uc_100rel_in Call In with PRACK
+
+The mirror of the previous scenario:
+
+<pre>
+ t APPL NUA SOA REMOTE
+ | | | |
+ 0 | | | |
+ 1 | |<------------------INVITE(sdp offer)---|
+ 2 | |--set_remote-->| |
+ 3 |<---INVITE-----| | |
+ 4 | | | |
+ 5 | | | |
+ 6 |-183 Progress->| | |
+ 7 | |--set_params-->| |
+ 8 | |--gen_answer-->| |
+ 9 | | | |
+10 | |-------------------183 (sdp answer)--->|
+11 | | | |
+12 | |<----------------------PRACK-----------|
+13 |<----PRACK-----| | |
+14 | |---------------------200/PRACK-------->|
+15 | | | |
+16 |--180 Ringing->| | |
+17 | |---------------------180 Ringing------>|
+18 | | | |
+19 | |<----------------------PRACK-----------|
+20 |<----PRACK-----| | |
+21 | |---------------------200/PRACK-------->|
+22 | | | |
+23 | | | |
+24 | | | |
+25 |----200 OK---->| | |
+26 | |----activate-->| |
+27 |<----active----| | |
+28 | |---------------------200/INVITE------->|
+29 | | | |
+30 | |<-----------------------ACK------------|
+31 |<-----ACK------| | |
+32 | | | |
+ | | | |
+</pre>
+
+<b>Note 1:</b> the user expectation (set by ordinary telephone) here is that
+callee sends a ringing tone towards caller and discards any media sent by
+callee until the call is accepted at t=26 (200 OK is sent towards caller).
+
+The application starts to alert user at t=13 when it knows that the
+media session has been successfully established.
+
+*/
+
+/**
+ at page soa_sdp_oa_use_cases Use Cases for SIP and SDP Offer/Answer
+
+This page contains a list of use cases or call scenarios for SIP and SDP
+Offer/Answer.
+
+There are a few call scenarios that we expect to see when dealing with more
+telephone-like side of SIP:
+- calling to existing PSTN networks (early session)
+- doing resource reservations
+- calling to 3G IMS
+- call hunting
+- having external party setting up your call, etc.
+
+ at section soa_use_case_1 Case #1: Basic Call
+
+This is the basic SIP call model with the most simple offer-answer exchange.
+
+<pre>
+ A B
+ | |
+ |----INVITE (offer)---->|
+ | |
+ | |
+ |< - - 180 Ringing - - -|
+ | |
+ | |
+ |<----200 (answer)------|
+ |----------ACK--------->|
+ | |
+ | |
+</pre>
+
+ at section soa_use_case_2 Case #2: Early Media
+
+Another case, slightly more complex. The SDP answer is sent with
+180 Ringing in order to establish an "early session". B might
+not be a SIP phone, but a gateway to PSTN, for instance. Using this
+"early session" B can play tones like "burr-burr" or "the
+subscriber you tried to reach is not in the coverage...":
+
+<pre>
+ A B
+ | |
+ |----INVITE (offer)---->|
+ | |
+ | |
+ |<----180 (answer)------|
+ | |
+ | |
+ |<----200 (answer')-----|
+ |----------ACK--------->|
+ | |
+ | |
+</pre>
+
+After receiving answer in 180 Ringing, A simply ignores SDP in
+subsequent responses.
+
+Nothing special here, right? But SIP is not so simple,
+unfortunately. There are hairy cases because of "early sessions",
+"forking", "preconditions" and other reasons.
+
+Now lets go through some hairy cases.
+
+ at section soa_use_case_3 Case #3: Early Dialog, Early Media
+
+This case is a call using 100rel, early dialog and early media. It
+is used when the session should be established before call alerts.
+
+<pre>
+ A B
+ | |
+ |----INVITE (offer)---->|
+ | |
+ |<----183 (answer)------|
+ |--------PRACK--------->|
+ |<-----200/PRACK------->|
+ | |
+ |<---------180----------|
+ |--------PRACK--------->|
+ |<-----200/PRACK------->|
+ | |
+ | |
+ | |
+ |<---------200----------|
+ |----------ACK--------->|
+ | |
+ | |
+</pre>
+
+ at section soa_use_case_4 Case #4: UPDATE with Offer
+
+This is a call model with two rounds of offer/answer and 100rel.
+It can be used, for instance, when the endpoints have to make sure
+that there are enough network capacity for the call to succeed.
+They can establish a new radio bearer, for instance, before
+progressing with the call. The initial offer would contain SDP
+attribute "inactive", the second "sendrev":
+
+<pre>
+ A B
+ | |
+ |----INVITE (offer)---->|
+ | |
+ | |
+ |<----183 (answer)------|
+ |--------PRACK--------->|
+ |<-----200/PRACK--------|
+ | |
+ | |
+ |----UPDATE (offer2)--->|
+ |<-200/UPDATE (answer2)-|
+ | |
+ |<---------180----------|
+ |--------PRACK--------->|
+ |<-----200/PRACK------->|
+ | |
+ | |
+ |<---------200----------|
+ |----------ACK--------->|
+ | |
+ | |
+</pre>
+
+
+ at section soa_use_case_5 Case #5: 2nd Offer in PRACK
+
+Alternative 1 to above, two rounds of offer/answer and 100rel, no
+UPDATE. It can used, for instance, when caller wants to make sure
+there is only one audio or video codec that is used during the
+call. The initial offer would contain SDP attribute "inactive";
+the second "sendrev":
+
+<pre>
+ A B
+ | |
+ |----INVITE (offer)---->|
+ | |
+ |<----183 (answer)------|
+ |-----PRACK(offer2)---->|
+ |<--200/PRACK(answer2)--|
+ | |
+ | |
+ |<---------180----------|
+ |--------PRACK--------->|
+ |<-----200/PRACK------->|
+ | |
+ | |
+ |<---------200----------|
+ |----------ACK--------->|
+ | |
+ | |
+</pre>
+
+
+ at section soa_use_case_6 Case #6: Callee Making 2nd Offer
+
+Alternative 2 to above: two rounds of offer/answer and 100rel, but
+now it is B who wants to do two rounds and initiates second
+Offer-Answer exchange:
+
+<pre>
+ A B
+ | |
+ |----INVITE (offer)---->|
+ | |
+ |<----183 (answer)------|
+ |--------PRACK--------->|
+ |<-----200/PRACK------->|
+ | |
+ | |
+ |<---UPDATE (offer2)----|
+ |-200/UPDATE (answer2)->|
+ | |
+ |<---------180----------|
+ |--------PRACK--------->|
+ |<-----200/PRACK------->|
+ | |
+ | |
+ |<---------200----------|
+ |----------ACK--------->|
+ | |
+ | |
+</pre>
+
+
+ at section soa_use_case_7 Case #7: 3GPP Call Model
+
+Here is a third alternative, know as "3GPP call model", where
+there is not 2 but 3 offer-answer rounds, allowing A and B to do
+precise resource reservations after they have agreed on media,
+codecs and transport addresses used during the call:
+
+<pre>
+ A B
+ | |
+ |----INVITE (offer)---->|
+ | |
+ | |
+ |<----183 (answer)------|
+ |-----PRACK(offer2)---->|
+ |<--200/PRACK(answer2)--|
+ | |
+ << resource reservations are done now >>
+ | |
+ |----UPDATE (offer3)--->|
+ |<-200/UPDATE (answer3)-|
+ | |
+ |<---------180----------|
+ |--------PRACK--------->|
+ |<-----200/PRACK------->|
+ | |
+ | |
+ |<---------200----------|
+ |----------ACK--------->|
+ | |
+ | |
+</pre>
+
+
+ at section soa_use_case_8 Case #8: Forking
+
+Now, another complication. Here B has two terminals, let say,
+fixed (B1) and mobile (B2) phone, both alert when B receives a
+call using procedure known as forking:
+
+<pre>
+ A B's proxy B1 B2
+ | | | |
+ |----INVITE (offer)---->| | |
+ | |-INVITE (off)->| |
+ | |-----------INVITE (off)------->|
+ | | | |
+ | |<--180 (ans1)--| |
+ |<------180 (ans1)------| | |
+ | | | |
+ | |<----------180 (ans2)----------|
+ |<------180 (ans2)------| | |
+ | | | |
+ | | | |
+ | |<----------200 (ans2')---------|
+ |<------200 (ans2')-----| | |
+ | |----CANCEL---->| |
+ | |<--200/CANCEL--| |
+ | |<-----487------| |
+ | | | |
+ |----------ACK----------------------------------------->|
+ | | | |
+ | | | |
+</pre>
+
+Here we have two calls initially established, but the call to B1
+along with "early session" is should be dropped when B2 picks up
+the call (and 200 OK is returned).
+
+ at section soa_use_case_9 Case #9: 3rd Party Call Control
+
+Now something different: 3rd party call model, where "C"
+establishes the call:
+
+<pre>
+ A C B
+ | | |
+ |<-------INVITE---------| |
+ | | |
+ | | |
+ |------200 (offer)----->| |
+ | |----INVITE (offer)---->|
+ | | |
+ | | |
+ | |<-----200 (answer)-----|
+ |<-----ACK (answer)-----| |
+ | | |
+ | |----------ACK--------->|
+ | | |
+</pre>
+
+ at section soa_use_case_10 Case #10: Upgrade Session with Re-INVITE
+
+The session is upgraded: a new media is added to the session.
+
+<pre>
+ A B
+ | |
+ |----INVITE (offer1)--->|
+ | |
+ | |
+ |< - - 180 Ringing - - -|
+ | |
+ | |
+ |<----200 (answer2)-----|
+ |----------ACK--------->|
+ | |
+ | |
+ | |
+ | |
+ |----INVITE (offer2)--->|
+ | |
+ |<----200 (answer2)-----|
+ |----------ACK--------->|
+ | |
+ | |
+</pre>
+
+ at section soa_use_case_10 Case #10: Upgrade Session with Re-INVITE
+
+The session upgraded is rejected.
+
+<pre>
+ A B
+ | |
+ |----INVITE (offer1)--->|
+ | |
+ | |
+ |< - - 180 Ringing - - -|
+ | |
+ | |
+ |<----200 (answer2)-----|
+ |----------ACK--------->|
+ | |
+ | |
+ | |
+ | |
+ |----INVITE (offer2)--->|
+ | |
+ |<---------488----------|
+ |----------ACK--------->|
+ | |
+ | |
+</pre>
+
+
+*/
+
+/** @typedef struct soa_session soa_session_t;
+
+ at brief "soa" session object.
+
+The @soa session object is responsible for
+ at ref soa_with_sip "SDP offer/answer negotiation"
+defined in @RFC3264. The session object is used to
+store the SDP template from user, remote SDP received from the network and
+the negotiation result, local SDP.
+
+ at par Functions used to create, copy and destroy "soa" session objects:
+ at code
+soa_session_t *soa_create(char const *name, su_root_t *, soa_magic_t *);
+
+soa_session_t *soa_clone(soa_session_t *, su_root_t *, soa_magic_t *);
+
+void soa_destroy(soa_session_t *);
+ at endcode
+
+ at par Functions used to set and get parameters for "soa" session objects:
+ at code
+int soa_set_params(soa_session_t *ss,
+ tag_type_t tag, tag_value_t value, ...);
+int soa_get_params(soa_session_t const *ss,
+ tag_type_t tag, tag_value_t value, ...);
+
+tagi_t *soa_get_paramlist(soa_session_t const *ss,
+ tag_type_t tag, tag_value_t value, ...);
+ at endcode
+
+ at par Functions used to obtain status information from "soa" session objects:
+ at code
+int soa_error_as_sip_response(soa_session_t *soa,
+ char const **return_phrase);
+
+char const *soa_error_as_sip_reason(soa_session_t *soa);
+
+int soa_get_warning(soa_session_t *ss, char const **return_phrase);
+ at endcode
+
+
+ at par Functions used to store and retrieve SDP descriptions:
+ at code
+int soa_set_capability_sdp(soa_session_t *ss,
+ struct sdp_session_s const *sdp,
+ char const *str, issize_t len);
+
+int soa_get_capability_sdp(soa_session_t const *ss,
+ struct sdp_session_s const **return_sdp,
+ char const **return_sdp_str,
+ isize_t *return_len);
+
+int soa_set_remote_sdp(soa_session_t *ss,
+ struct sdp_session_s const *sdp,
+ char const *str, issize_t len);
+
+int soa_get_remote_sdp(soa_session_t const *ss,
+ struct sdp_session_s const **return_sdp,
+ char const **return_sdp_str,
+ isize_t *return_len);
+
+int soa_clear_remote_sdp(soa_session_t *ss);
+
+int soa_get_remote_version(soa_session_t const *ss);
+
+int soa_set_user_sdp(soa_session_t *ss,
+ struct sdp_session_s const *sdp,
+ char const *str, issize_t len);
+
+int soa_get_user_sdp(soa_session_t const *ss,
+ struct sdp_session_s const **return_sdp,
+ char const **return_sdp_str,
+ isize_t *return_len);
+
+int soa_get_user_version(soa_session_t const *ss);
+
+int soa_get_local_sdp(soa_session_t const *ss,
+ struct sdp_session_s const **return_sdp,
+ char const **return_sdp_str,
+ isize_t *return_len);
+ at endcode
+
+
+ at par Functions for executing Offer/Answer negotiation steps:
+ at code
+int soa_init_offer_answer(soa_session_t *ss);
+int soa_generate_offer(soa_session_t *, int always, soa_callback_f *);
+int soa_generate_answer(soa_session_t *, soa_callback_f *);
+int soa_process_answer(soa_session_t *, soa_callback_f *);
+int soa_process_reject(soa_session_t *, soa_callback_f *);
+int soa_is_complete(soa_session_t const *ss);
+ at endcode
+
+ at par Functions for signaling events of session signaling:
+ at code
+int soa_activate(soa_session_t *, char const *option);
+int soa_deactivate(soa_session_t *, char const *option);
+void soa_terminate(soa_session_t *, char const *option);
+ at endcode
+These functions are used to activate actions taken by @soa, for instance,
+a COMEDIA connection is established with soa_activate().
+
+ at par Functions for Checking Activated Media:
+ at code
+int soa_is_audio_active(soa_session_t const *ss);
+int soa_is_video_active(soa_session_t const *ss);
+
+int soa_is_remote_audio_active(soa_session_t const *ss);
+int soa_is_remote_video_active(soa_session_t const *ss);
+ at endcode
+
+*/
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/soa_asynch.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/soa_asynch.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,289 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE soa_asynch.c
+ *
+ * @brief Static implementation of Sofia SDP Offer/Answer Engine
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Aug 16 17:06:06 EEST 2005
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <assert.h>
+
+struct soa_asynch_complete;
+
+#define SU_MSG_ARG_T struct soa_asynch_completed
+
+#include <sofia-sip/su_wait.h>
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/su_tagarg.h>
+#include <sofia-sip/su_strlst.h>
+
+#include "sofia-sip/soa.h"
+#include <sofia-sip/sdp.h>
+#include "sofia-sip/soa_session.h"
+
+#define NONE ((void *)-1)
+#define XXX assert(!"implemented")
+
+typedef struct soa_asynch_session
+{
+ soa_session_t sss_session[1];
+}
+soa_asynch_session_t;
+
+struct soa_asynch_completed
+{
+ soa_session_t *completed_session;
+ unsigned completed_terminated;
+ int (*completed_call)(soa_session_t *, soa_callback_f *);
+};
+
+static int soa_asynch_init(char const *, soa_session_t *, soa_session_t *);
+static void soa_asynch_deinit(soa_session_t *);
+static int soa_asynch_set_params(soa_session_t *ss, tagi_t const *tags);
+static int soa_asynch_get_params(soa_session_t const *ss, tagi_t *tags);
+static tagi_t *soa_asynch_get_paramlist(soa_session_t const *ss);
+static int soa_asynch_generate_offer(soa_session_t *ss,
+ soa_callback_f *completed);
+static int soa_asynch_generate_answer(soa_session_t *ss,
+ soa_callback_f *completed);
+static int soa_asynch_process_answer(soa_session_t *ss,
+ soa_callback_f *completed);
+static int soa_asynch_activate(soa_session_t *ss, char const *option);
+static int soa_asynch_deactivate(soa_session_t *ss, char const *option);
+static void soa_asynch_terminate(soa_session_t *ss, char const *option);
+
+struct soa_session_actions const soa_asynch_actions =
+ {
+ (sizeof soa_asynch_actions),
+ sizeof (struct soa_asynch_session),
+ soa_asynch_init,
+ soa_asynch_deinit,
+ soa_asynch_set_params,
+ soa_asynch_get_params,
+ soa_asynch_get_paramlist,
+ soa_base_media_features,
+ soa_base_sip_require,
+ soa_base_sip_supported,
+ soa_base_remote_sip_features,
+ soa_base_set_capability_sdp,
+ soa_base_set_remote_sdp,
+ soa_base_set_local_sdp,
+ soa_asynch_generate_offer,
+ soa_asynch_generate_answer,
+ soa_asynch_process_answer,
+ soa_asynch_activate,
+ soa_asynch_deactivate,
+ soa_asynch_terminate
+ };
+
+/* Initialize session */
+static int soa_asynch_init(char const *name,
+ soa_session_t *ss,
+ soa_session_t *parent)
+{
+ return soa_base_init(name, ss, parent);
+}
+
+static void soa_asynch_deinit(soa_session_t *ss)
+{
+ soa_base_deinit(ss);
+}
+
+static int soa_asynch_set_params(soa_session_t *ss, tagi_t const *tags)
+{
+ return soa_base_set_params(ss, tags);
+}
+
+static int soa_asynch_get_params(soa_session_t const *ss, tagi_t *tags)
+{
+ return soa_base_get_params(ss, tags);
+}
+
+static tagi_t *soa_asynch_get_paramlist(soa_session_t const *ss)
+{
+ return soa_base_get_paramlist(ss);
+}
+
+static void soa_asynch_completed(su_root_magic_t *magic,
+ su_msg_r msg,
+ struct soa_asynch_completed *arg)
+{
+ soa_session_t *ss = arg->completed_session;
+
+ if (arg->completed_terminated == ss->ss_terminated) {
+ if (ss->ss_in_progress) {
+ soa_callback_f *completed = ss->ss_in_progress;
+ ss->ss_in_progress = NULL;
+
+ /* Update local activity */
+ if (arg->completed_call(ss, NULL) < 0)
+ /* XXX - Process error */;
+
+ completed(ss->ss_magic, ss);
+ }
+ }
+
+ soa_session_unref(ss);
+}
+
+static int soa_asynch_generate_offer(soa_session_t *ss,
+ soa_callback_f *completed)
+{
+ sdp_session_t *sdp;
+ sdp_media_t *m;
+ uint16_t port = 5004;
+ su_msg_r msg;
+
+ if (ss->ss_user->ssd_sdp == NULL) {
+ if (ss->ss_caps->ssd_unparsed == NULL)
+ return soa_set_status(ss, 500, "No local session available");
+ }
+
+ if (ss->ss_user->ssd_sdp)
+ return 0; /* We are done */
+
+ /* Generate a dummy SDP offer based on our capabilities */
+ if (soa_set_local_sdp(ss, ss->ss_caps->ssd_unparsed, -1) < 0)
+ return -1;
+ sdp = ss->ss_user->ssd_sdp; assert(ss->ss_user->ssd_sdp);
+
+ for (m = sdp->sdp_media; m; m = m->m_next)
+ if (m->m_port == 0)
+ m->m_port = port, port += 2;
+
+ /* We pretend to be asynchronous */
+ if (su_msg_create(msg,
+ su_root_task(ss->ss_root),
+ su_root_task(ss->ss_root),
+ soa_asynch_completed,
+ sizeof (struct soa_asynch_completed)) == -1)
+ return soa_set_status(ss, 500, "Internal error");
+
+ su_msg_data(msg)->completed_session = soa_session_ref(ss);
+ su_msg_data(msg)->completed_terminated = ss->ss_terminated;
+ su_msg_data(msg)->completed_call = soa_base_generate_offer;
+
+ su_msg_send(msg);
+
+ ss->ss_in_progress = completed;
+
+ return 1; /* Indicate caller of async operation */
+}
+
+static int soa_asynch_generate_answer(soa_session_t *ss,
+ soa_callback_f *completed)
+{
+ sdp_session_t *sdp;
+ sdp_media_t *m;
+ uint16_t port = 5004;
+ su_msg_r msg;
+
+ if (ss->ss_user->ssd_sdp == NULL) {
+ if (ss->ss_caps->ssd_unparsed == NULL)
+ return soa_set_status(ss, 500, "No local session available");
+ }
+
+ if (ss->ss_user->ssd_sdp)
+ return 0; /* We are done */
+
+ /* Generate a dummy SDP offer based on our capabilities */
+ if (soa_set_local_sdp(ss, ss->ss_caps->ssd_unparsed, -1) < 0)
+ return -1;
+ sdp = ss->ss_user->ssd_sdp; assert(ss->ss_user->ssd_sdp);
+
+ for (m = sdp->sdp_media; m; m = m->m_next)
+ if (m->m_port == 0)
+ m->m_port = port, port += 2;
+
+ /* We pretend to be asynchronous */
+ if (su_msg_create(msg,
+ su_root_task(ss->ss_root),
+ su_root_task(ss->ss_root),
+ soa_asynch_completed,
+ sizeof (struct soa_asynch_completed)) == -1)
+ return soa_set_status(ss, 500, "Internal error");
+
+ su_msg_data(msg)->completed_session = soa_session_ref(ss);
+ su_msg_data(msg)->completed_terminated = ss->ss_terminated;
+ su_msg_data(msg)->completed_call = soa_base_generate_answer;
+
+ su_msg_send(msg);
+
+ ss->ss_in_progress = completed;
+
+ return 1; /* Indicate caller of async operation */
+}
+
+static int soa_asynch_process_answer(soa_session_t *ss,
+ soa_callback_f *completed)
+{
+ su_msg_r msg;
+
+ /* We pretend to be asynchronous */
+ if (su_msg_create(msg,
+ su_root_task(ss->ss_root),
+ su_root_task(ss->ss_root),
+ soa_asynch_completed,
+ sizeof (struct soa_asynch_completed)) == -1)
+ return soa_set_status(ss, 500, "Internal error");
+
+ su_msg_data(msg)->completed_session = soa_session_ref(ss);
+ su_msg_data(msg)->completed_terminated = ss->ss_terminated;
+ su_msg_data(msg)->completed_call = soa_base_process_answer;
+
+ su_msg_send(msg);
+
+ ss->ss_in_progress = completed;
+
+ return 1; /* Indicate caller of async operation */
+}
+
+
+static int soa_asynch_activate(soa_session_t *ss, char const *option)
+{
+ return soa_base_activate(ss, option);
+}
+
+static int soa_asynch_deactivate(soa_session_t *ss, char const *option)
+{
+ return soa_base_deactivate(ss, option);
+}
+
+static void soa_asynch_terminate(soa_session_t *ss, char const *option)
+{
+ ss->ss_in_progress = NULL;
+ soa_description_free(ss, ss->ss_user);
+ soa_base_terminate(ss, option);
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/soa_static.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/soa_static.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1251 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE soa_static.c
+ *
+ * @brief Static implementation of Sofia SDP Offer/Answer Engine
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Aug 16 17:06:06 EEST 2005
+ *
+ * @par Use-cases
+ * 1. no existing session
+ * a) generating offer (upgrade with user-SDP)
+ * b) generating answer (upgrade with remote-SDP, rejects with user-SDP)
+ * 2. session exists
+ * a) generating offer:
+ * upgrades with user-SDP
+ * b) generating answer:
+ * upgrades with remote-SDP, rejects with user-SDP
+ * c) processing answer:
+ * rejects with user-SDP, no upgrades
+ *
+ * Upgrading session with user SDP:
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <assert.h>
+
+struct soa_static_complete;
+
+#define SU_MSG_ARG_T struct soa_static_completed
+
+#include <sofia-sip/su_wait.h>
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/su_tagarg.h>
+#include <sofia-sip/su_strlst.h>
+#include <sofia-sip/string0.h>
+#include <sofia-sip/bnf.h>
+
+#include "sofia-sip/soa.h"
+#include <sofia-sip/sdp.h>
+#include "sofia-sip/soa_session.h"
+
+#define NONE ((void *)-1)
+#define XXX assert(!"implemented")
+
+#if !HAVE_STRCASESTR
+char *strcasestr(const char *haystack, const char *needle);
+#endif
+
+typedef struct soa_static_session
+{
+ soa_session_t sss_session[1];
+ char *sss_audio_aux;
+}
+soa_static_session_t;
+
+static int soa_static_init(char const *, soa_session_t *, soa_session_t *);
+static void soa_static_deinit(soa_session_t *);
+static int soa_static_set_params(soa_session_t *ss, tagi_t const *tags);
+static int soa_static_get_params(soa_session_t const *ss, tagi_t *tags);
+static tagi_t *soa_static_get_paramlist(soa_session_t const *ss,
+ tag_type_t tag, tag_value_t value,
+ ...);
+static int soa_static_set_capability_sdp(soa_session_t *ss,
+ sdp_session_t *sdp,
+ char const *, isize_t);
+static int soa_static_set_remote_sdp(soa_session_t *ss,
+ int new_version,
+ sdp_session_t *sdp,
+ char const *, isize_t);
+static int soa_static_set_user_sdp(soa_session_t *ss,
+ sdp_session_t *sdp,
+ char const *, isize_t);
+static int soa_static_generate_offer(soa_session_t *ss, soa_callback_f *);
+static int soa_static_generate_answer(soa_session_t *ss, soa_callback_f *);
+static int soa_static_process_answer(soa_session_t *ss, soa_callback_f *);
+static int soa_static_process_reject(soa_session_t *ss, soa_callback_f *);
+
+static int soa_static_activate(soa_session_t *ss, char const *option);
+static int soa_static_deactivate(soa_session_t *ss, char const *option);
+static void soa_static_terminate(soa_session_t *ss, char const *option);
+
+struct soa_session_actions const soa_default_actions =
+ {
+ (sizeof soa_default_actions),
+ sizeof (struct soa_static_session),
+ "static",
+ soa_static_init,
+ soa_static_deinit,
+ soa_static_set_params,
+ soa_static_get_params,
+ soa_static_get_paramlist,
+ soa_base_media_features,
+ soa_base_sip_require,
+ soa_base_sip_supported,
+ soa_base_remote_sip_features,
+ soa_static_set_capability_sdp,
+ soa_static_set_remote_sdp,
+ soa_static_set_user_sdp,
+ soa_static_generate_offer,
+ soa_static_generate_answer,
+ soa_static_process_answer,
+ soa_static_process_reject,
+ soa_static_activate,
+ soa_static_deactivate,
+ soa_static_terminate
+ };
+
+/* Initialize session */
+static int soa_static_init(char const *name,
+ soa_session_t *ss,
+ soa_session_t *parent)
+{
+ return soa_base_init(name, ss, parent);
+}
+
+static void soa_static_deinit(soa_session_t *ss)
+{
+ soa_base_deinit(ss);
+}
+
+static int soa_static_set_params(soa_session_t *ss, tagi_t const *tags)
+{
+ soa_static_session_t *sss = (soa_static_session_t *)ss;
+ char const *audio_aux = sss->sss_audio_aux;
+ int n, m;
+
+ n = tl_gets(tags,
+ SOATAG_AUDIO_AUX_REF(audio_aux),
+ TAG_END());
+
+ if (n > 0 && str0casecmp(audio_aux, sss->sss_audio_aux)) {
+ char *s = su_strdup(ss->ss_home, audio_aux), *tbf = sss->sss_audio_aux;
+ if (s == NULL && audio_aux != NULL)
+ return -1;
+ sss->sss_audio_aux = s;
+ if (tbf)
+ su_free(ss->ss_home, tbf);
+ }
+
+ m = soa_base_set_params(ss, tags);
+ if (m < 0)
+ return m;
+
+ return n + m;
+}
+
+static int soa_static_get_params(soa_session_t const *ss, tagi_t *tags)
+{
+ soa_static_session_t *sss = (soa_static_session_t *)ss;
+
+ int n, m;
+
+ n = tl_tgets(tags,
+ SOATAG_AUDIO_AUX(sss->sss_audio_aux),
+ TAG_END());
+ m = soa_base_get_params(ss, tags);
+ if (m < 0)
+ return m;
+
+ return n + m;
+}
+
+static tagi_t *soa_static_get_paramlist(soa_session_t const *ss,
+ tag_type_t tag, tag_value_t value,
+ ...)
+{
+ soa_static_session_t *sss = (soa_static_session_t *)ss;
+
+ ta_list ta;
+ tagi_t *tl;
+
+ ta_start(ta, tag, value);
+
+ tl = soa_base_get_paramlist(ss,
+ TAG_IF(sss->sss_audio_aux,
+ SOATAG_AUDIO_AUX(sss->sss_audio_aux)),
+ TAG_NEXT(ta_args(ta)));
+
+ ta_end(ta);
+
+ return tl;
+}
+
+static int soa_static_set_capability_sdp(soa_session_t *ss,
+ sdp_session_t *sdp,
+ char const *sdp_str,
+ isize_t sdp_len)
+{
+ return soa_base_set_capability_sdp(ss, sdp, sdp_str, sdp_len);
+}
+
+
+static int soa_static_set_remote_sdp(soa_session_t *ss,
+ int new_version,
+ sdp_session_t *sdp,
+ char const *sdp_str,
+ isize_t sdp_len)
+{
+ return soa_base_set_remote_sdp(ss, new_version, sdp, sdp_str, sdp_len);
+}
+
+
+static int soa_static_set_user_sdp(soa_session_t *ss,
+ sdp_session_t *sdp,
+ char const *sdp_str,
+ isize_t sdp_len)
+{
+ return soa_base_set_user_sdp(ss, sdp, sdp_str, sdp_len);
+}
+
+/** Generate a rejected m= line */
+sdp_media_t *soa_sdp_make_rejected_media(su_home_t *home,
+ sdp_media_t const *m,
+ sdp_session_t *sdp,
+ int include_all_codecs)
+{
+ sdp_media_t rejected[1] = {{ sizeof (rejected) }};
+
+ rejected->m_type = m->m_type;
+ rejected->m_type_name = m->m_type_name;
+ rejected->m_port = 0;
+ rejected->m_proto = m->m_proto;
+ rejected->m_proto_name = m->m_proto_name;
+
+ if (include_all_codecs) {
+ rejected->m_rtpmaps = m->m_rtpmaps;
+ }
+
+ rejected->m_rejected = 1;
+
+ return sdp_media_dup(home, rejected, sdp);
+}
+
+/** Expand a @a truncated SDP.
+ */
+sdp_session_t *soa_sdp_expand_media(su_home_t *home,
+ sdp_session_t const *truncated,
+ sdp_session_t const *complete)
+{
+ sdp_session_t *expanded;
+ sdp_media_t **m0;
+ sdp_media_t * const *m1;
+
+ expanded = sdp_session_dup(home, truncated);
+
+ if (expanded) {
+ for (m0 = &expanded->sdp_media, m1 = &complete->sdp_media;
+ *m1;
+ m1 = &(*m1)->m_next) {
+ if (!*m0) {
+ *m0 = soa_sdp_make_rejected_media(home, *m1, expanded, 0);
+ if (!*m0)
+ return NULL;
+ }
+ m0 = &(*m0)->m_next;
+ }
+ }
+
+ return expanded;
+}
+
+/** Check if @a session should be upgraded with @a remote */
+int soa_sdp_upgrade_is_needed(sdp_session_t const *session,
+ sdp_session_t const *remote)
+{
+ sdp_media_t const *rm, *lm;
+
+ if (!remote)
+ return 0;
+ if (!session)
+ return 1;
+
+ for (rm = remote->sdp_media, lm = session->sdp_media;
+ rm && lm ; rm = rm->m_next, lm = lm->m_next) {
+ if (rm->m_rejected)
+ continue;
+ if (lm->m_rejected)
+ break;
+ }
+
+ return rm != NULL;
+}
+
+/** Check if codec is in auxiliary list */
+int soa_sdp_is_auxiliary_codec(sdp_rtpmap_t const *rm, char const *auxiliary)
+{
+ char const *codec;
+ size_t clen, alen;
+ char const *match;
+
+ if (!rm || !rm->rm_encoding || !auxiliary)
+ return 0;
+
+ codec = rm->rm_encoding;
+
+ clen = strlen(codec), alen = strlen(auxiliary);
+
+ if (clen > alen)
+ return 0;
+
+ for (match = auxiliary;
+ (match = strcasestr(match, codec));
+ match = match + 1) {
+ if (IS_ALPHANUM(match[clen]) || match[clen] == '-')
+ continue;
+ if (match != auxiliary &&
+ (IS_ALPHANUM(match[-1]) || match[-1] == '-'))
+ continue;
+ return 1;
+ }
+
+ return 0;
+}
+
+
+/** Find first matching media in table. */
+sdp_media_t *soa_sdp_matching(soa_session_t *ss,
+ sdp_media_t *mm[],
+ sdp_media_t const *with,
+ int *return_common_codecs)
+{
+ int i, j = -1;
+ sdp_media_t *m;
+ sdp_rtpmap_t const *rm;
+ soa_static_session_t *sss = (soa_static_session_t *)ss;
+ char const *auxiliary;
+
+ auxiliary = with->m_type == sdp_media_audio ? sss->sss_audio_aux : NULL;
+
+ /* Looking for a single codec */
+ if (with->m_rtpmaps && with->m_rtpmaps->rm_next == NULL)
+ auxiliary = NULL;
+
+ for (i = 0; mm[i]; i++) {
+ if (!sdp_media_match_with(mm[i], with))
+ continue;
+
+ if (!sdp_media_uses_rtp(with))
+ break;
+
+ if (!return_common_codecs)
+ break;
+
+ /* Check also rtpmaps */
+ for (rm = mm[i]->m_rtpmaps; rm; rm = rm->rm_next) {
+ /* Ignore auxiliary codecs */
+ if (auxiliary && soa_sdp_is_auxiliary_codec(rm, auxiliary))
+ continue;
+
+ if (sdp_rtpmap_find_matching(with->m_rtpmaps, rm))
+ break;
+ }
+ if (rm)
+ break;
+ if (j == -1)
+ j = i;
+ }
+
+ if (return_common_codecs)
+ *return_common_codecs = mm[i] != NULL;
+
+ if (mm[i] == NULL && j != -1)
+ i = j; /* return m= line without common codecs */
+
+ m = mm[i];
+
+ for (; mm[i]; i++)
+ mm[i] = mm[i + 1];
+
+ return m;
+}
+
+/** Set payload types in @a l_m according to the values in @a r_m.
+ *
+ * @retval number of common codecs
+ */
+int soa_sdp_set_rtpmap_pt(sdp_media_t *l_m,
+ sdp_media_t const *r_m)
+{
+ sdp_rtpmap_t *lrm, **next_lrm;
+ sdp_rtpmap_t const *rrm;
+
+ int local_codecs = 0, common_codecs = 0;
+
+ unsigned char dynamic_pt[128];
+ unsigned pt;
+
+ for (next_lrm = &l_m->m_rtpmaps; (lrm = *next_lrm); ) {
+ if (lrm->rm_any) {
+ /* Remove codecs known only by pt number */
+ *next_lrm = lrm->rm_next;
+ continue;
+ }
+ else {
+ next_lrm = &lrm->rm_next;
+ }
+
+ local_codecs++;
+
+ rrm = sdp_rtpmap_find_matching(r_m->m_rtpmaps, lrm);
+
+ /* XXX - do fmtp comparison */
+
+ if (rrm) {
+ /* Use same payload type as remote */
+ if (lrm->rm_pt != rrm->rm_pt) {
+ lrm->rm_predef = 0;
+ lrm->rm_pt = rrm->rm_pt;
+ }
+ common_codecs++;
+ }
+ else {
+ /* Determine payload type later */
+ lrm->rm_any = 1;
+ }
+ }
+
+ if (local_codecs == common_codecs)
+ return common_codecs;
+
+ /* Select unique dynamic payload type for each payload */
+
+ memset(dynamic_pt, 0, sizeof dynamic_pt);
+
+ for (lrm = l_m->m_rtpmaps; lrm; lrm = lrm->rm_next) {
+ if (!lrm->rm_any)
+ dynamic_pt[lrm->rm_pt] = 1;
+ }
+
+ for (rrm = r_m->m_rtpmaps; rrm; rrm = rrm->rm_next) {
+ dynamic_pt[rrm->rm_pt] = 1;
+ }
+
+ for (next_lrm = &l_m->m_rtpmaps; (lrm = *next_lrm); ) {
+ if (!lrm->rm_any) {
+ next_lrm = &lrm->rm_next;
+ continue;
+ }
+
+ lrm->rm_any = 0;
+
+ pt = lrm->rm_pt;
+
+ if (dynamic_pt[pt]) {
+ for (pt = 96; pt < 128; pt++)
+ if (!dynamic_pt[pt])
+ break;
+
+ if (pt == 128) {
+ for (pt = 0; pt < 128; pt++)
+ if (!sdp_rtpmap_well_known[pt] && !dynamic_pt[pt])
+ break;
+ }
+
+ if (pt == 128) {
+ for (pt = 0; pt < 128; pt++)
+ if (!dynamic_pt[pt])
+ break;
+ }
+
+ if (pt == 128) {
+ /* Too many payload types */
+ *next_lrm = lrm->rm_next;
+ continue;
+ }
+
+ lrm->rm_pt = pt;
+ lrm->rm_predef = 0;
+ }
+
+ dynamic_pt[pt] = 1;
+
+ next_lrm = &lrm->rm_next;
+ }
+
+ return common_codecs;
+}
+
+
+/** Sort rtpmaps in @a inout_list according to the values in @a rrm.
+ *
+ * @return Number of common codecs
+ */
+int soa_sdp_sort_rtpmap(sdp_rtpmap_t **inout_list,
+ sdp_rtpmap_t const *rrm,
+ char const *auxiliary)
+{
+ sdp_rtpmap_t *sorted = NULL, **next = &sorted, **left;
+ sdp_rtpmap_t *aux = NULL, **next_aux = &aux;
+
+ int common_codecs = 0;
+
+ assert(inout_list);
+ if (!inout_list)
+ return 0;
+
+ /* If remote has only single codec, ignore list of auxiliary codecs */
+ if (rrm && !rrm->rm_next)
+ auxiliary = NULL;
+
+ /* Insertion sort from *inout_list to sorted */
+ for (; rrm && *inout_list; rrm = rrm->rm_next) {
+ for (left = inout_list; *left; left = &(*left)->rm_next) {
+ if (sdp_rtpmap_match(rrm, (*left)))
+ break;
+ }
+ if (!*left)
+ continue;
+
+ if (auxiliary && soa_sdp_is_auxiliary_codec(rrm, auxiliary)) {
+ *next_aux = *left, next_aux = &(*next_aux)->rm_next;
+ }
+ else {
+ common_codecs++;
+ *next = *left; next = &(*next)->rm_next;
+ }
+ *left = (*left)->rm_next;
+ }
+
+ /* Append common auxiliary codecs */
+ if (aux)
+ *next = aux, next = next_aux;
+
+ /* Append leftover codecs */
+ *next = *inout_list;
+
+ *inout_list = sorted;
+
+ return common_codecs;
+}
+
+
+/** Select rtpmaps in @a inout_list according to the values in @a rrm.
+ *
+ * @return Number of common codecs
+ */
+int soa_sdp_select_rtpmap(sdp_rtpmap_t **inout_list,
+ sdp_rtpmap_t const *rrm,
+ char const *auxiliary,
+ int select_single)
+{
+ sdp_rtpmap_t **left;
+ sdp_rtpmap_t *aux = NULL, **next_aux = &aux;
+
+ int common_codecs = 0;
+
+ assert(inout_list);
+ if (!inout_list)
+ return 0;
+
+ for (left = inout_list; *left; ) {
+ if (auxiliary && soa_sdp_is_auxiliary_codec(*left, auxiliary))
+ /* Insert into list of auxiliary codecs */
+ *next_aux = *left, *left = (*left)->rm_next,
+ next_aux = &(*next_aux)->rm_next;
+ else if (!(select_single && common_codecs > 0)
+ && sdp_rtpmap_find_matching(rrm, (*left)))
+ /* Select */
+ left = &(*left)->rm_next, common_codecs++;
+ else
+ /* Remove */
+ *left = (*left)->rm_next;
+ }
+
+ *left = aux, *next_aux = NULL;
+
+ return common_codecs;
+}
+
+/** Sort and select rtpmaps within session */
+int soa_sdp_upgrade_rtpmaps(soa_session_t *ss,
+ sdp_session_t *session,
+ sdp_session_t const *remote)
+{
+ soa_static_session_t *sss = (soa_static_session_t *)ss;
+ sdp_media_t *sm;
+ sdp_media_t const *rm;
+
+ for (sm = session->sdp_media, rm = remote->sdp_media;
+ sm && rm;
+ sm = sm->m_next, rm = rm->m_next) {
+ if (sm->m_rejected)
+ continue;
+ if (sdp_media_uses_rtp(sm)) {
+ int common_codecs = soa_sdp_set_rtpmap_pt(sm, rm);
+
+ char const *auxiliary =
+ rm->m_type == sdp_media_audio ? sss->sss_audio_aux : NULL;
+
+ if (ss->ss_rtp_sort == SOA_RTP_SORT_REMOTE ||
+ (ss->ss_rtp_sort == SOA_RTP_SORT_DEFAULT &&
+ rm->m_mode == sdp_recvonly)) {
+ soa_sdp_sort_rtpmap(&sm->m_rtpmaps, rm->m_rtpmaps, auxiliary);
+ }
+
+ if (common_codecs == 0)
+ ;
+ else if (ss->ss_rtp_select == SOA_RTP_SELECT_SINGLE) {
+ soa_sdp_select_rtpmap(&sm->m_rtpmaps, rm->m_rtpmaps, auxiliary, 1);
+ }
+ else if (ss->ss_rtp_select == SOA_RTP_SELECT_COMMON) {
+ soa_sdp_select_rtpmap(&sm->m_rtpmaps, rm->m_rtpmaps, auxiliary, 0);
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+/** Upgrade m= lines within session */
+int soa_sdp_upgrade(soa_session_t *ss,
+ su_home_t *home,
+ sdp_session_t *session,
+ sdp_session_t const *caps,
+ sdp_session_t const *upgrader)
+{
+ soa_static_session_t *sss = (soa_static_session_t *)ss;
+
+ int Ns, Nc, Nu, size, i, j;
+ sdp_media_t *m, **mm, *cm;
+ sdp_media_t **s_media, **o_media, **c_media;
+ sdp_media_t const **u_media;
+
+ Ns = sdp_media_count(session, sdp_media_any, 0, 0, 0);
+ Nc = sdp_media_count(caps, sdp_media_any, 0, 0, 0);
+ Nu = sdp_media_count(upgrader, sdp_media_any, 0, 0, 0);
+
+ if (caps == upgrader)
+ size = Ns + Nc + 1;
+ else if (Ns < Nu)
+ size = Nu + 1;
+ else
+ size = Ns + 1;
+
+ s_media = su_zalloc(home, size * (sizeof *s_media));
+ o_media = su_zalloc(home, (Ns + 1) * (sizeof *o_media));
+ c_media = su_zalloc(home, (Nc + 1) * (sizeof *c_media));
+ u_media = su_zalloc(home, (Nu + 1) * (sizeof *u_media));
+
+ cm = sdp_media_dup_all(home, caps->sdp_media, session);
+
+ if (!s_media || !c_media || !u_media || !cm)
+ return -1;
+
+ for (i = 0, m = session->sdp_media; m && i < Ns; m = m->m_next)
+ o_media[i++] = m;
+ assert(i == Ns);
+ for (i = 0, m = cm; m && i < Nc; m = m->m_next)
+ c_media[i++] = m;
+ assert(i == Nc);
+ for (i = 0, m = upgrader->sdp_media; m && i < Nu; m = m->m_next)
+ u_media[i++] = m;
+ assert(i == Nu);
+
+ if (caps != upgrader) {
+ /* Update session according to remote */
+ for (i = 0; i < Nu; i++) {
+ int common_codecs = 0;
+
+ m = soa_sdp_matching(ss, c_media, u_media[i], &common_codecs);
+
+ if (!m || u_media[i]->m_rejected) {
+ m = soa_sdp_make_rejected_media(home, u_media[i], session, 0);
+ }
+ else if (sdp_media_uses_rtp(m)) {
+ /* Process rtpmaps */
+ char const *auxiliary =
+ m->m_type == sdp_media_audio ? sss->sss_audio_aux : NULL;
+
+ if (!common_codecs && !ss->ss_rtp_mismatch)
+ m = soa_sdp_make_rejected_media(home, m, session, 1);
+ soa_sdp_set_rtpmap_pt(m, u_media[i]);
+
+ if (ss->ss_rtp_sort == SOA_RTP_SORT_REMOTE ||
+ (ss->ss_rtp_sort == SOA_RTP_SORT_DEFAULT &&
+ u_media[i]->m_mode == sdp_recvonly)) {
+ soa_sdp_sort_rtpmap(&m->m_rtpmaps, u_media[i]->m_rtpmaps, auxiliary);
+ }
+
+ if (common_codecs &&
+ (ss->ss_rtp_select == SOA_RTP_SELECT_SINGLE ||
+ ss->ss_rtp_select == SOA_RTP_SELECT_COMMON)) {
+ soa_sdp_select_rtpmap(&m->m_rtpmaps, u_media[i]->m_rtpmaps, auxiliary,
+ ss->ss_rtp_select == SOA_RTP_SELECT_SINGLE);
+ }
+ }
+
+ s_media[i] = m;
+ }
+ }
+ else {
+ /* Update session according to local */
+ for (i = 0; i < Ns; i++) {
+ m = soa_sdp_matching(ss, c_media, o_media[i], NULL);
+ if (!m)
+ m = soa_sdp_make_rejected_media(home, o_media[i], session, 0);
+ s_media[i] = m;
+ }
+ /* Here we just append new media at the end */
+ for (j = 0; c_media[j]; j++)
+ s_media[i++] = c_media[j];
+ assert(i <= size);
+ }
+
+ mm = &session->sdp_media;
+ for (i = 0; s_media[i]; i++) {
+ m = s_media[i]; *mm = m; mm = &m->m_next;
+ }
+ *mm = NULL;
+
+ return 0;
+}
+
+/** Check if @a session contains media that are rejected by @a remote. */
+int soa_sdp_reject_is_needed(sdp_session_t const *session,
+ sdp_session_t const *remote)
+{
+ sdp_media_t const *sm, *rm;
+
+ if (!remote)
+ return 1;
+ if (!session)
+ return 0;
+
+ for (sm = session->sdp_media, rm = remote->sdp_media;
+ sm && rm; sm = sm->m_next, rm = rm->m_next) {
+ if (rm->m_rejected) {
+ if (!sm->m_rejected)
+ return 1;
+ }
+ else {
+ /* Mode bits do not match */
+ if (((rm->m_mode & sdp_recvonly) == sdp_recvonly)
+ != ((sm->m_mode & sdp_sendonly) == sdp_sendonly))
+ return 1;
+ }
+ }
+
+ if (sm)
+ return 1;
+
+ return 0;
+}
+
+/** If m= line is rejected by remote mark m= line rejected within session */
+int soa_sdp_reject(su_home_t *home,
+ sdp_session_t *session,
+ sdp_session_t const *remote)
+{
+ sdp_media_t *sm;
+ sdp_media_t const *rm;
+
+ if (!session || !session->sdp_media || !remote)
+ return 0;
+
+ rm = remote->sdp_media;
+
+ for (sm = session->sdp_media; sm; sm = sm->m_next) {
+ if (!rm || rm->m_rejected) {
+ sm->m_rejected = 1;
+ sm->m_mode = 0;
+ sm->m_port = 0;
+ sm->m_number_of_ports = 1;
+ if (sm->m_format)
+ sm->m_format->l_next = NULL;
+ if (sm->m_rtpmaps)
+ sm->m_rtpmaps->rm_next = NULL;
+ sm->m_information = NULL;
+ if (sm->m_connections)
+ sm->m_connections->c_next = NULL;
+ sm->m_bandwidths = NULL;
+ sm->m_key = NULL;
+ sm->m_attributes = NULL;
+ sm->m_user = NULL;
+ }
+
+ if (rm)
+ rm = rm->m_next;
+ }
+
+ return 0;
+}
+
+/** Check if @a session mode should be changed. */
+int soa_sdp_mode_set_is_needed(sdp_session_t const *session,
+ sdp_session_t const *remote,
+ char const *hold)
+{
+ sdp_media_t const *sm, *rm, *rm_next;
+ int hold_all;
+ sdp_mode_t recv_mode;
+
+ SU_DEBUG_7(("soa_sdp_mode_set_is_needed(%p, %p, \"%s\"): called\n",
+ session, remote, hold ? hold : ""));
+
+ if (!session )
+ return 0;
+
+ hold_all = str0cmp(hold, "*") == 0;
+
+ rm = remote ? remote->sdp_media : NULL, rm_next = NULL;
+
+ for (sm = session->sdp_media; sm; sm = sm->m_next, rm = rm_next) {
+ rm_next = rm ? rm->m_next : NULL;
+
+ if (sm->m_rejected)
+ continue;
+
+ if (rm) {
+ /* Mode bits do not match */
+ if (((rm->m_mode & sdp_recvonly) == sdp_recvonly)
+ != ((sm->m_mode & sdp_sendonly) == sdp_sendonly))
+ return 1;
+ }
+
+ recv_mode = sm->m_mode & sdp_recvonly;
+ if (recv_mode && hold &&
+ (hold_all || strcasestr(hold, sm->m_type_name)))
+ return 1;
+ }
+
+ return 0;
+}
+
+
+/** Update mode within session */
+int soa_sdp_mode_set(sdp_session_t *session,
+ sdp_session_t const *remote,
+ char const *hold)
+{
+ sdp_media_t *sm;
+ sdp_media_t const *rm, *rm_next;
+ int hold_all;
+ sdp_mode_t send_mode, recv_mode;
+
+ SU_DEBUG_7(("soa_sdp_mode_set(%p, %p, \"%s\"): called\n",
+ session, remote, hold ? hold : ""));
+
+ if (!session || !session->sdp_media)
+ return 0;
+
+ rm = remote ? remote->sdp_media : NULL, rm_next = NULL;
+
+ hold_all = str0cmp(hold, "*") == 0;
+
+ for (sm = session->sdp_media; sm; sm = sm->m_next, rm = rm_next) {
+ rm_next = rm ? rm->m_next : NULL;
+
+ if (sm->m_rejected)
+ continue;
+
+ send_mode = sdp_sendonly;
+ if (rm)
+ send_mode = (rm->m_mode & sdp_recvonly) ? sdp_sendonly : 0;
+
+ recv_mode = sm->m_mode & sdp_recvonly;
+ if (recv_mode && hold && (hold_all || strcasestr(hold, sm->m_type_name)))
+ recv_mode = 0;
+
+ sm->m_mode = recv_mode | send_mode;
+ }
+
+ return 0;
+}
+
+enum offer_answer_action {
+ generate_offer,
+ generate_answer,
+ process_answer
+};
+
+/**
+ * Updates the modified copy of local SDP based
+ * on application provided local SDP and remote SDP.
+ */
+static int offer_answer_step(soa_session_t *ss,
+ enum offer_answer_action action,
+ char const *by)
+{
+ char c_address[64];
+ sdp_session_t *local = ss->ss_local->ssd_sdp;
+ sdp_session_t local0[1];
+
+ sdp_session_t *user = ss->ss_user->ssd_sdp;
+ unsigned user_version = ss->ss_user_version;
+
+ sdp_session_t *remote = ss->ss_remote->ssd_sdp;
+ unsigned remote_version = ss->ss_remote_version;
+
+ sdp_origin_t o[1] = {{ sizeof(o) }};
+ sdp_connection_t *c, c0[1] = {{ sizeof(c0) }};
+ sdp_time_t t[1] = {{ sizeof(t) }};
+
+ char const *phrase = "Internal Media Error";
+
+ su_home_t tmphome[SU_HOME_AUTO_SIZE(8192)];
+
+ su_home_auto(tmphome, sizeof tmphome);
+
+ SU_DEBUG_7(("soa_static_offer_answer_action(%p, %s): called\n", ss, by));
+
+ if (user == NULL)
+ return soa_set_status(ss, 500, "No session set by user");
+
+ if (action == generate_offer)
+ remote = NULL;
+
+ /* Pre-negotiation Step: Expand truncated remote SDP */
+ if (local && remote) switch (action) {
+ case generate_answer:
+ case process_answer:
+ if (sdp_media_count(remote, sdp_media_any, "*", 0, 0) <
+ sdp_media_count(local, sdp_media_any, "*", 0, 0)) {
+ SU_DEBUG_5(("%s: remote %s is truncated: expanding\n",
+ by, action == generate_answer ? "offer" : "answer"));
+ remote = soa_sdp_expand_media(tmphome, remote, local);
+ }
+ default:
+ break;
+ }
+
+ /* Step A: Create local SDP session (based on user-supplied SDP) */
+ if (local == NULL) switch (action) {
+ case generate_offer:
+ case generate_answer:
+ SU_DEBUG_7(("soa_static(%p, %s): generating local description\n", ss, by));
+
+ local = local0;
+ *local = *user, local->sdp_media = NULL;
+
+ if (local->sdp_origin) {
+ o->o_username = local->sdp_origin->o_username;
+ /* o->o_address = local->sdp_origin->o_address; */
+ }
+ if (!o->o_address)
+ o->o_address = c0;
+ local->sdp_origin = o;
+
+ if (soa_init_sdp_origin(ss, o, c_address) < 0) {
+ phrase = "Cannot Get IP Address for Media";
+ goto internal_error;
+ }
+
+ break;
+
+ case process_answer:
+ default:
+ goto internal_error;
+ }
+
+ /* Step B: upgrade local SDP (add m= lines to it) */
+ switch (action) {
+ case generate_offer:
+ /* Upgrade local SDP based on user SDP */
+ if (local != local0 && ss->ss_local_user_version == user_version)
+ break;
+ if (local != local0)
+ *local0 = *local, local = local0;
+ SU_DEBUG_7(("soa_static(%p, %s): %s\n", ss, by,
+ "upgrade with local description"));
+ soa_sdp_upgrade(ss, tmphome, local, user, user);
+ break;
+ case generate_answer:
+ /* Upgrade local SDP based on remote SDP */
+ if (ss->ss_local_user_version == user_version &&
+ ss->ss_local_remote_version == remote_version)
+ break;
+ if (1) {
+ if (local != local0)
+ *local0 = *local, local = local0;
+ SU_DEBUG_7(("soa_static(%p, %s): %s\n", ss, by,
+ "upgrade with remote description"));
+ soa_sdp_upgrade(ss, tmphome, local, user, remote);
+ }
+ break;
+ case process_answer:
+ default:
+ break;
+ }
+
+
+ /* Step C: reject media */
+ switch (action) {
+ case generate_offer:
+ /* Local media is marked as rejected already in upgrade phase */
+ break;
+ case generate_answer:
+ case process_answer:
+ if (ss->ss_local_remote_version == remote_version)
+ break;
+ if (soa_sdp_reject_is_needed(local, remote)) {
+ if (local != local0) {
+ *local0 = *local, local = local0;
+#define DUP_LOCAL(local) \
+ do { \
+ if (!local->sdp_media) break; \
+ local->sdp_media = \
+ sdp_media_dup_all(tmphome, local->sdp_media, local); \
+ if (!local->sdp_media) \
+ goto internal_error; \
+ } while (0)
+ DUP_LOCAL(local);
+ }
+ SU_DEBUG_7(("soa_static(%p, %s): marking rejected media\n", ss, by));
+ soa_sdp_reject(tmphome, local, remote);
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* Step D: Set media mode bits */
+ switch (action) {
+ case generate_offer:
+ case generate_answer:
+ case process_answer:
+ if (soa_sdp_mode_set_is_needed(local, remote, ss->ss_hold)) {
+ if (local != local0) {
+ *local0 = *local, local = local0;
+ DUP_LOCAL(local);
+ }
+
+ soa_sdp_mode_set(local, remote, ss->ss_hold);
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* Step E: Upgrade codecs by answer. */
+ switch (action) {
+ case process_answer:
+ /* Upgrade local SDP based on remote SDP */
+ if (ss->ss_local_remote_version == remote_version)
+ break;
+ if (1 /* We don't have good test for codecs */) {
+ SU_DEBUG_7(("soa_static(%p, %s): %s\n", ss, by,
+ "upgrade codecs with remote description"));
+ if (local != local0) {
+ *local0 = *local, local = local0;
+ DUP_LOCAL(local);
+ }
+ soa_sdp_upgrade_rtpmaps(ss, local, remote);
+ }
+ break;
+ case generate_offer:
+ case generate_answer:
+ default:
+ break;
+ }
+
+ /* Step F: Update c= line */
+ switch (action) {
+ case generate_offer:
+ case generate_answer:
+ /* Upgrade local SDP based of user SDP */
+ if (ss->ss_local_user_version == user_version &&
+ local->sdp_connection)
+ break;
+
+ if (local->sdp_connection == NULL ||
+ (user->sdp_connection != NULL &&
+ sdp_connection_cmp(local->sdp_connection, user->sdp_connection))) {
+ sdp_media_t *m;
+
+ /* Every m= line (even rejected one) must have a c= line
+ * or there must be a c= line at session level
+ */
+ if (user->sdp_connection)
+ c = user->sdp_connection;
+ else
+ c = local->sdp_origin->o_address;
+
+ for (m = local->sdp_media; m; m = m->m_next)
+ if (m->m_connections == NULL)
+ break;
+
+ if (m) {
+ if (local != local0) {
+ *local0 = *local, local = local0;
+ DUP_LOCAL(local);
+ }
+ local->sdp_connection = c;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ soa_description_free(ss, ss->ss_previous);
+
+ if (ss->ss_local->ssd_sdp != local &&
+ sdp_session_cmp(ss->ss_local->ssd_sdp, local)) {
+ /* We have modfied local session: update origin-line */
+ if (local->sdp_origin != o)
+ *o = *local->sdp_origin, local->sdp_origin = o;
+ o->o_version++;
+
+ /* Do sanity checks for the created SDP */
+ if (!local->sdp_subject) /* s= is mandatory */
+ local->sdp_subject = "-";
+ if (!local->sdp_time) /* t= is mandatory */
+ local->sdp_time = t;
+
+ if (action == generate_offer) {
+ /* Keep a copy of previous session state */
+ *ss->ss_previous = *ss->ss_local;
+ memset(ss->ss_local, 0, (sizeof *ss->ss_local));
+ ss->ss_previous_user_version = ss->ss_local_user_version;
+ ss->ss_previous_remote_version = ss->ss_local_remote_version;
+ }
+
+ SU_DEBUG_7(("soa_static(%p, %s): storing local description\n", ss, by));
+
+ /* Update the unparsed and pretty-printed descriptions */
+ if (soa_description_set(ss, ss->ss_local, local, NULL, 0) < 0) {
+ goto internal_error;
+ }
+ }
+
+ /* Update version numbers */
+ switch (action) {
+ case generate_offer:
+ ss->ss_local_user_version = user_version;
+ break;
+ case generate_answer:
+ ss->ss_local_user_version = user_version;
+ ss->ss_local_remote_version = remote_version;
+ break;
+ case process_answer:
+ ss->ss_local_remote_version = remote_version;
+ default:
+ break;
+ }
+
+ su_home_deinit(tmphome);
+ return 0;
+
+ internal_error:
+ su_home_deinit(tmphome);
+ return soa_set_status(ss, 500, phrase);
+}
+
+/**
+ * Generates offer based on local SDP.
+ */
+static int soa_static_generate_offer(soa_session_t *ss,
+ soa_callback_f *completed)
+{
+ if (!ss->ss_user->ssd_sdp)
+ return soa_set_status(ss, 500, "No session set by user");
+
+ if (offer_answer_step(ss, generate_offer, "soa_generate_offer") < 0)
+ return -1;
+
+ return soa_base_generate_offer(ss, NULL);
+}
+
+static int soa_static_generate_answer(soa_session_t *ss,
+ soa_callback_f *completed)
+{
+ /* NOTE:
+ * - local SDP might have changed
+ * - remote SDP might have been updated
+ */
+
+ if (offer_answer_step(ss, generate_answer, "soa_generate_answer") < 0)
+ return -1;
+
+ return soa_base_generate_answer(ss, NULL);
+}
+
+static int soa_static_process_answer(soa_session_t *ss,
+ soa_callback_f *completed)
+{
+ /* NOTE:
+ * - both local and remote information is available
+ * - local SDP might have changed
+ * - remote SDP might have been updated
+ */
+ if (offer_answer_step(ss, process_answer, "soa_process_answer") < 0)
+ return -1;
+
+ return soa_base_process_answer(ss, NULL);
+}
+
+/** Process rejected offer */
+static int soa_static_process_reject(soa_session_t *ss,
+ soa_callback_f *completed)
+{
+ struct soa_description d[1];
+
+ *d = *ss->ss_local;
+ *ss->ss_local = *ss->ss_previous;
+ ss->ss_local_user_version = ss->ss_previous_user_version;
+ ss->ss_local_remote_version = ss->ss_previous_remote_version;
+
+ memset(ss->ss_previous, 0, (sizeof *ss->ss_previous));
+ soa_description_free(ss, d);
+
+ return soa_base_process_reject(ss, NULL);
+}
+
+static int soa_static_activate(soa_session_t *ss, char const *option)
+{
+ return soa_base_activate(ss, option);
+}
+
+static int soa_static_deactivate(soa_session_t *ss, char const *option)
+{
+ return soa_base_deactivate(ss, option);
+}
+
+static void soa_static_terminate(soa_session_t *ss, char const *option)
+{
+ soa_description_free(ss, ss->ss_user);
+ soa_base_terminate(ss, option);
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/soa_tag.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/soa_tag.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,606 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE soa_tag.c Tags and tag lists for Offer/Answer Engine
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Aug 3 20:28:17 EEST 2005
+ */
+
+#include "config.h"
+
+#include <sofia-sip/su.h>
+
+#if 1
+#define TAG_NAMESPACE soa_tag_namespace
+#else
+/* Definition used by tag_dll.awk */
+#define TAG_NAMESPACE "soa"
+#endif
+
+#include <sofia-sip/soa.h>
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/sdp_tag.h>
+
+#include <string.h>
+
+char const soa_tag_namespace[] = "soa";
+
+/** Filter soa tags. */
+int soa_tag_filter(tagi_t const *f, tagi_t const *t)
+{
+ char const *ns;
+
+ if (!t || !t->t_tag)
+ return 0;
+
+ ns = t->t_tag->tt_ns;
+ if (!ns)
+ return 0;
+
+ return ns == soa_tag_namespace || strcmp(ns, soa_tag_namespace) == 0;
+}
+
+/**@def SOATAG_ANY()
+ *
+ * Filter tag matching any SOATAG_*() item.
+ */
+tag_typedef_t soatag_any = NSTAG_TYPEDEF(*);
+
+/**@def SOATAG_CAPS_SDP(x)
+ * Pass parsed capability description to soa session object.
+ *
+ * @par Used with
+ * soa_set_params() \n
+ * soa_get_params() \n
+ *
+ * @par Parameter type
+ * #sdp_session_t *
+ *
+ * @par Values
+ * #sdp_session_t describing @soa capabilities
+ *
+ * Corresponding tag taking reference parameter is SOATAG_CAPS_SDP_REF()
+ */
+tag_typedef_t soatag_caps_sdp = SDPTAG_TYPEDEF(caps_sdp);
+
+/**@def SOATAG_CAPS_SDP_STR(x)
+ * Pass capability description to @soa session object.
+ *
+ * @par Used with
+ * soa_set_param() \n
+ * soa_get_params() \n
+ *
+ * @par Parameter type
+ * char const *
+ *
+ * @par Values
+ * String containing SDP description of @soa capabilities
+ *
+ * Corresponding tag taking reference parameter is SOATAG_CAPS_SDP_STR_REF()
+ */
+tag_typedef_t soatag_caps_sdp_str = STRTAG_TYPEDEF(caps_sdp_str);
+
+/**@def SOATAG_LOCAL_SDP(x)
+ * Get parsed local session description from soa session object.
+ *
+ * @par Used with
+ * soa_get_params(), soa_get_paramlist() \n
+ *
+ * @par Parameter type
+ * #sdp_session_t *
+ *
+ * @par Values
+ * pointer to #sdp_session_t.
+ *
+ * Corresponding tag taking reference parameter is SOATAG_LOCAL_SDP_REF()
+ *
+ * @sa soa_get_local_sdp(), SOATAG_LOCAL_SDP_STR(), SOATAG_USER_SDP(),
+ * SOATAG_USER_SDP_STR().
+ */
+tag_typedef_t soatag_local_sdp = SDPTAG_TYPEDEF(local_sdp);
+
+/**@def SOATAG_LOCAL_SDP_STR(x)
+ * Get local session description as a string from soa session object.
+ *
+ * @par Used with
+ * soa_get_params(), soa_get_paramlist() \n
+ *
+ * @par Parameter type
+ * char const *
+ *
+ * @par Values
+ * String containing SDP offer or answer.
+ *
+ * Corresponding tag taking reference parameter is SOATAG_LOCAL_SDP_STR_REF()..
+ *
+ * @sa soa_get_local_sdp(), SOATAG_LOCAL_SDP(),
+ * SOATAG_USER_SDP(), SOATAG_USER_SDP_STR().
+ */
+tag_typedef_t soatag_local_sdp_str = STRTAG_TYPEDEF(local_sdp_str);
+
+/**@def SOATAG_REMOTE_SDP(x)
+ * Pass parsed remote session description to soa session object.
+ *
+ * @par Used with
+ * soa_get_params(), soa_get_paramlist() \n
+ *
+ * @par Parameter type
+ * #sdp_session_t *
+ *
+ * @par Values
+ * pointer to #sdp_session_t.
+ *
+ * Corresponding tag taking reference parameter is SOATAG_REMOTE_SDP_REF()
+ *
+ * @sa soa_set_remote_sdp(), soa_get_remote_sdp(), SOATAG_REMOTE_SDP_STR(),
+ * SOATAG_LOCAL_SDP(), SOATAG_LOCAL_SDP_STR().
+ */
+tag_typedef_t soatag_remote_sdp = SDPTAG_TYPEDEF(remote_sdp);
+
+/**@def SOATAG_REMOTE_SDP_STR(x)
+ * Pass media description file name to the NUA stack.
+ *
+ * Pass name of media description file that contains media templates
+ * (normally mss.sdp) to the NUA stack.
+ *
+ * @par Used with
+ * soa_get_params(), soa_get_paramlist() \n
+ *
+ * @par Parameter type
+ * char const *
+ *
+ * @par Values
+ * String containing SDP description received from remote end.
+ *
+ * Corresponding tag taking reference parameter is SOATAG_REMOTE_SDP_STR_REF()
+ *
+ * @sa soa_set_remote_sdp(), soa_get_remote_sdp(), SOATAG_REMOTE_SDP(),
+ * SOATAG_LOCAL_SDP(), SOATAG_LOCAL_SDP_STR().
+ */
+tag_typedef_t soatag_remote_sdp_str = STRTAG_TYPEDEF(remote_sdp_str);
+
+/**@def SOATAG_USER_SDP(x)
+ * Pass parsed user session description to soa session object.
+ *
+ * User SDP is used as basis for SDP Offer/Answer negotiation. It can be
+ * very minimal, consisting just sdp_session_t structures, sdp_media_t
+ * structures and sdp_rtpmap_t structures listing te supported media, used
+ * RTP port number, and RTP payload descriptions of supported codecs.
+ *
+ * When generating the offer or answer the user SDP is augmented with the
+ * required SDP lines (v=, o=, t=, c=, a=rtpmap, etc.) as required. The
+ * complete offer or answer generated by @soa is passed in
+ * SOATAG_LOCAL_SDP() (SOATAG_LOCAL_SDP_STR() contains same in text format).
+ *
+ * @par Used with
+ * soa_set_params(), soa_get_params(), soa_get_paramlist() \n
+ *
+ * @par Parameter type
+ * #sdp_session_t *
+ *
+ * @par Values
+ * pointer to #sdp_session_t.
+ *
+ * Corresponding tag taking reference parameter is SOATAG_USER_SDP_REF()
+ *
+ * @sa soa_set_user_sdp(), soa_get_user_sdp(), SOATAG_USER_SDP_STR(),
+ * SOATAG_LOCAL_SDP(), SOATAG_LOCAL_SDP_STR().
+ */
+tag_typedef_t soatag_user_sdp = SDPTAG_TYPEDEF(user_sdp);
+
+/**@def SOATAG_USER_SDP_STR(x)
+ * Pass unparsed user session description to soa session object.
+ *
+ * User SDP is used as basis for SDP Offer/Answer negotiation. It can be
+ * very minimal, listing just m= lines with the port numbers and RTP payload
+ * numbers of supported codecs, like
+ * @code
+ * SOATAG_USER_SDP_STR("m=audio 5004 RTP/AVP 0 8")
+ * @endcode
+ * When generating the offer or answer the user SDP is augmented with the
+ * required SDP lines (v=, o=, t=, c=, a=rtpmap, etc.) as required. The
+ * complete offer or answer generated by @soa is passed in
+ * SOATAG_LOCAL_SDP_STR() (SOATAG_LOCAL_SDP() contains session in parsed
+ * format).
+ *
+ * @par Used with
+ * soa_set_params(), soa_get_params(), soa_get_paramlist() \n
+ *
+ * @par Parameter type
+ * char const *
+ *
+ * @par Values
+ * String containing minimal SDP description.
+ *
+ * Corresponding tag taking reference parameter is SOATAG_USER_SDP_STR_REF()
+ *
+ * @sa soa_set_user_sdp(), soa_get_user_sdp(), SOATAG_USER_SDP(),
+ * SOATAG_LOCAL_SDP(), SOATAG_LOCAL_SDP_STR()
+ */
+tag_typedef_t soatag_user_sdp_str = STRTAG_TYPEDEF(user_sdp_str);
+
+/**@def SOATAG_AF(x)
+ *
+ * Preferred address family for media.
+ *
+ * @par Used with
+ * soa_set_params(), soa_get_params(), soa_get_paramlist() \n
+ *
+ * @par Parameter type
+ * enum #soa_af {
+ * #SOA_AF_ANY,
+ * #SOA_AF_IP4_ONLY, #SOA_AF_IP6_ONLY,
+ * #SOA_AF_IP4_IP6, #SOA_AF_IP6_IP4
+ * }
+ *
+ * @par Values
+ * - #SOA_AF_ANY (0) any address family (default)
+ * - #SOA_AF_IP4_ONLY (1) only IP version 4
+ * - #SOA_AF_IP6_ONLY (2) only IP version 6
+ * - #SOA_AF_IP4_IP6 (3) either IP version 4 or 6, version 4 preferred
+ * - #SOA_AF_IP6_IP4 (4) either IP version 4 or 6, version 6 preferred
+ *
+ * Corresponding tag taking reference parameter is SOATAG_AF_REF()
+ *
+ * @sa SOATAG_ADDRESS()
+ */
+tag_typedef_t soatag_af = INTTAG_TYPEDEF(af);
+
+
+/**@def SOATAG_ADDRESS(x)
+ *
+ * Pass media address.
+ *
+ * @par Used with
+ * soa_set_params(), soa_get_params(), soa_get_paramlist() \n
+ *
+ * @par Parameter type
+ * char const *
+ *
+ * @par Values
+ * NUL-terminated C string containing a domain name,
+ * IPv4 address, or IPv6 address.
+ *
+ * Corresponding tag taking reference parameter is SOATAG_ADDRESS_REF()
+ *
+ * @sa SOATAG_AF()
+ */
+tag_typedef_t soatag_address = STRTAG_TYPEDEF(address);
+
+
+/**@def SOATAG_RTP_SELECT(x)
+ *
+ * When generating answer or second offer, @soa can include all the supported
+ * codecs, only one codec, or only the codecs supported by both ends in the
+ * list of payload types on the m= line.
+ *
+ * @par Used with
+ * soa_set_params(), soa_get_params(), soa_get_paramlist() \n
+ *
+ * @par Parameter type
+ * enum {
+ * #SOA_RTP_SELECT_SINGLE, #SOA_RTP_SELECT_COMMON, #SOA_RTP_SELECT_ALL
+ * } \n
+ * (int in range 0..2)
+ *
+ * @par Values
+ * - #SOA_RTP_SELECT_SINGLE (0) - select the best common codec
+ * - #SOA_RTP_SELECT_COMMON (1) - select all common codecs
+ * - #SOA_RTP_SELECT_ALL (2) - select all local codecs
+ *
+ * The default value is 0, only one RTP codec is selected. Note, however,
+ * that if there is no common codec (no local codec is supported by remote
+ * end), all the codecs are included in the list. In that case the media
+ * line is rejected, too, unless SOATAG_RTP_MISMATCH(1) has been used.
+ *
+ * Corresponding tag taking a reference parameter is SOATAG_RTP_SELECT_REF().
+ *
+ * @sa SOATAG_RTP_MISMATCH(), SOATAG_RTP_SORT(), SOATAG_AUDIO_AUX()
+ */
+tag_typedef_t soatag_rtp_select = INTTAG_TYPEDEF(rtp_select);
+
+
+/**@def SOATAG_AUDIO_AUX(x)
+ *
+ * The named audio codecs are considered auxiliary, that is, they are
+ * considered as common codec only when they are the only codec listed on
+ * the media line.
+ *
+ * When generating answer or second offer soa includes auxiliary audio
+ * codecs in the list of codecs even if it is selecting only one codec or
+ * common codecs.
+ *
+ * @par Used with
+ * soa_set_params(), soa_get_params(), soa_get_paramlist() \n
+ *
+ * @par Parameter type
+ * A string with whitespace separated list of codec names.
+ *
+ * @par Values
+ * E.g., "telephone-event cn".
+ *
+ * By default, there are no auxiliary audio codecs.
+ *
+ * Corresponding tag taking a reference parameter is
+ * SOATAG_AUDIO_AUX_REF().
+ *
+ * @since New in @VERSION_1_12_2.
+ *
+ * @sa SOATAG_RTP_SELECT(), SOATAG_RTP_MISMATCH(), SOATAG_RTP_SORT()
+ */
+tag_typedef_t soatag_audio_aux = STRTAG_TYPEDEF(audio_aux);
+
+/**@def SOATAG_RTP_SORT(x)
+ *
+ * When selecting the common codecs, soa can either select first local codec
+ * supported by remote end, or first remote codec supported by local codecs.
+ * The preference is indicated with ordering: the preferred codec is
+ * first and so on.
+ *
+ * The auxiliary audio codecs (specified with SOATAG_AUDIO_AUX()) are listed
+ * after other codecs.
+ *
+ * @par Used with
+ * soa_set_params(), soa_get_params(), soa_get_paramlist() \n
+ *
+ * @par Parameter type
+ * enum {
+ * #SOA_RTP_SORT_DEFAULT, #SOA_RTP_SORT_LOCAL, #SOA_RTP_SORT_REMOTE
+ * } \n
+ * (int in range 0..2)
+ *
+ * @par Values
+ * - #SOA_RTP_SORT_DEFAULT (0) - select by local preference
+ * if media is recvonly, remote preference othewise
+ * - #SOA_RTP_SORT_LOCAL (1) - always select by local preference
+ * - #SOA_RTP_SORT_REMOTE (2) - always select by remote preference
+ *
+ * The default value is #SOA_RTP_SORT_DEFAULT (0).
+ *
+ * Corresponding tag taking reference parameter is SOATAG_RTP_SORT_REF()
+ *
+ * @sa SOATAG_RTP_SELECT(), SOATAG_RTP_MISMATCH(), SOATAG_AUDIO_AUX()
+*/
+tag_typedef_t soatag_rtp_sort = INTTAG_TYPEDEF(rtp_sort);
+
+
+/**@def SOATAG_RTP_MISMATCH(x)
+ *
+ * Accept media line even if the SDP negotation code determines that there
+ * are no common codecs between local and remote media. Normally, if the soa
+ * determines there are no common codecs, the media line is rejected.
+ *
+ * @par Used with
+ * soa_set_params(), soa_get_params(), soa_get_paramlist() \n
+ *
+ * @par Parameter type
+ * Boolean (int)
+ *
+ * @par Values
+ * 0 - reject media if there are no common codecs \n
+ * 1 (!= 0) - accept media even if there are no common codecs \n
+ *
+ * Default value is 0.
+ *
+ * Corresponding tag taking reference parameter is SOATAG_RTP_MISMATCH_REF()
+ *
+ * @sa SOATAG_RTP_SELECT(), SOATAG_RTP_MISMATCH(), SOATAG_AUDIO_AUX()
+ */
+tag_typedef_t soatag_rtp_mismatch = BOOLTAG_TYPEDEF(rtp_mismatch);
+
+
+/**@def SOATAG_ACTIVE_AUDIO(x)
+ *
+ * Audio session status.
+ *
+ * @par Used with
+ *
+ * @par Parameter type
+ * enum { #SOA_ACTIVE_DISABLED, #SOA_ACTIVE_REJECTED,
+ * #SOA_ACTIVE_INACTIVE, #SOA_ACTIVE_SENDONLY,
+ * #SOA_ACTIVE_RECVONLY, #SOA_ACTIVE_SENDRECV }
+ *
+ * @par Values
+ * - #SOA_ACTIVE_REJECTED (-8)
+ * - #SOA_ACTIVE_INACTIVE (0)
+ * - #SOA_ACTIVE_SENDONLY (1)
+ * - #SOA_ACTIVE_RECVONLY (2)
+ * - #SOA_ACTIVE_SENDRECV (3)
+ *
+ * Corresponding tag taking reference parameter is SOATAG_ACTIVE_AUDIO_REF()
+ *
+ */
+tag_typedef_t soatag_active_audio = INTTAG_TYPEDEF(active_audio);
+
+/**@def SOATAG_ACTIVE_VIDEO(x)
+ *
+ * Video session status
+ *
+ * @par Used with
+ *
+ * @par Parameter type
+ * enum { #SOA_ACTIVE_DISABLED, #SOA_ACTIVE_REJECTED,
+ * #SOA_ACTIVE_INACTIVE, #SOA_ACTIVE_SENDONLY,
+ * #SOA_ACTIVE_RECVONLY, #SOA_ACTIVE_SENDRECV }
+ *
+ * @par Values
+ * - #SOA_ACTIVE_REJECTED (-8)
+ * - #SOA_ACTIVE_INACTIVE (0)
+ * - #SOA_ACTIVE_SENDONLY (1)
+ * - #SOA_ACTIVE_RECVONLY (2)
+ * - #SOA_ACTIVE_SENDRECV (3)
+ *
+ * Corresponding tag taking reference parameter is SOATAG_ACTIVE_VIDEO_REF()
+ */
+tag_typedef_t soatag_active_video = INTTAG_TYPEDEF(active_video);
+
+/**@def SOATAG_ACTIVE_IMAGE(x)
+ *
+ * Active image session status
+ *
+ * @par Used with
+ * #nua_i_active \n
+ * #nua_i_state \n
+ *
+ * @par Parameter type
+ * enum { #SOA_ACTIVE_DISABLED, #SOA_ACTIVE_REJECTED,
+ * #SOA_ACTIVE_INACTIVE, #SOA_ACTIVE_SENDONLY,
+ * #SOA_ACTIVE_RECVONLY, #SOA_ACTIVE_SENDRECV }
+ *
+ * @par Values
+ * - #SOA_ACTIVE_REJECTED (-8)
+ * - #SOA_ACTIVE_INACTIVE (0)
+ * - #SOA_ACTIVE_SENDONLY (1)
+ * - #SOA_ACTIVE_RECVONLY (2)
+ * - #SOA_ACTIVE_SENDRECV (3)
+ *
+ * @par Parameter type
+ * enum { #SOA_ACTIVE_DISABLED, #SOA_ACTIVE_REJECTED,
+ * #SOA_ACTIVE_INACTIVE, #SOA_ACTIVE_SENDONLY,
+ * #SOA_ACTIVE_RECVONLY, #SOA_ACTIVE_SENDRECV }
+ *
+ * @par Values
+ * - #SOA_ACTIVE_REJECTED (-8)
+ * - #SOA_ACTIVE_INACTIVE (0)
+ * - #SOA_ACTIVE_SENDONLY (1)
+ * - #SOA_ACTIVE_RECVONLY (2)
+ * - #SOA_ACTIVE_SENDRECV (3)
+ *
+ * Corresponding tag taking reference parameter is SOATAG_ACTIVE_IMAGE_REF()
+ */
+tag_typedef_t soatag_active_image = INTTAG_TYPEDEF(active_image);
+
+/**@def SOATAG_ACTIVE_CHAT(x)
+ *
+ * Active chat session status.
+ *
+ * @par Used with
+ * #nua_i_active \n
+ * #nua_i_state \n
+ *
+ * @par Parameter type
+ * enum { #SOA_ACTIVE_DISABLED, #SOA_ACTIVE_REJECTED,
+ * #SOA_ACTIVE_INACTIVE, #SOA_ACTIVE_SENDONLY,
+ * #SOA_ACTIVE_RECVONLY, #SOA_ACTIVE_SENDRECV }
+ *
+ * @par Values
+ * - #SOA_ACTIVE_REJECTED (-8)
+ * - #SOA_ACTIVE_INACTIVE (0)
+ * - #SOA_ACTIVE_SENDONLY (1)
+ * - #SOA_ACTIVE_RECVONLY (2)
+ * - #SOA_ACTIVE_SENDRECV (3)
+ *
+ * Corresponding tag taking reference parameter is SOATAG_ACTIVE_CHAT_REF()
+ */
+tag_typedef_t soatag_active_chat = INTTAG_TYPEDEF(active_chat);
+
+/**@def SOATAG_SRTP_ENABLE(x)
+ *
+ * Enable SRTP
+ *
+ * @par Used with
+ * soa_set_params(), soa_get_params(), soa_get_paramlist() \n
+ *
+ * @par Parameter type
+ * boolean (int)
+ *
+ * @par Values
+ * @c !=0 enable \n
+ * @c 0 disable
+ *
+ * Corresponding tag taking reference parameter is
+ * SOATAG_SRTP_ENABLE_REF()
+ *
+ * @todo SRTP functionality is not implemented.
+ */
+tag_typedef_t soatag_srtp_enable = BOOLTAG_TYPEDEF(srtp_enable);
+
+/**@def SOATAG_SRTP_CONFIDENTIALITY(x)
+ *
+ * Enable SRTP confidentiality negotiation.
+ *
+ * @par Used with
+ * soa_set_params(), soa_get_params(), soa_get_paramlist() \n
+ *
+ * @par Parameter type
+ * boolean (int)
+ *
+ * @par Values
+ * @c != 0 enable SRTP confidentiality \n
+ * @c 0 disable SRTP conidentiality
+ *
+ * Corresponding tag taking reference parameter is
+ * SOATAG_SRTP_CONFIDENTIALITY_REF()
+ *
+ * @todo SRTP functionality is not implemented.
+ */
+tag_typedef_t soatag_srtp_confidentiality =
+ BOOLTAG_TYPEDEF(srtp_confidentiality);
+
+/**@def SOATAG_SRTP_INTEGRITY(x)
+ *
+ * Enable SRTP integrity protection
+ *
+ * @par Used with
+ * soa_set_params(), soa_get_params(), soa_get_paramlist() \n
+ *
+ * @par Parameter type
+ * boolean (int)
+ *
+ * @par Values
+ * @c !=0 enable \n
+ * @c 0 disable
+ *
+ * Corresponding tag taking reference parameter is
+ * SOATAG_SRTP_INTEGRITY_REF()
+ *
+ * @todo SRTP functionality is not implemented.
+ */
+tag_typedef_t soatag_srtp_integrity = BOOLTAG_TYPEDEF(srtp_integrity);
+
+/**@def SOATAG_HOLD(x)
+ *
+ * Hold media stream or streams. When putting a SIP session on hold, the
+ * application can include, e.g., SOATAG_HOLD("audio") or
+ * SOATAG_HOLD("video") or SOATAG_HOLD("audio, video") or SOATAG_HOLD("*")
+ * as @soa parameters. When resuming the session, it can include
+ * SOATAG_HOLD(NULL). Note that last SOATAG_HOLD() in the tag list will
+ * override the SOATAG_HOLD() tags before it.
+ *
+ * @par Used with
+ * soa_set_params(), soa_get_params(), soa_get_paramlist() \n
+ *
+ * @par Parameter type
+ * character string
+ *
+ * @par Values
+ * Comma-separated media name ("audio", "video") or wildcard ("*").
+ *
+ * Corresponding tag taking reference parameter is SOATAG_HOLD_REF()
+ *
+ * @sa soa_set_params(), nua_invite(), @ref nua_event_diagram_call_hold
+ */
+tag_typedef_t soatag_hold = STRTAG_TYPEDEF(hold);
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,153 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SOA_H
+/** Defined when <sofia-sip/soa.h> has been included. */
+#define SOA_H
+/**@file sofia-sip/soa.h SDP Offer/Answer (RFC 3264) Interface.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Kai Vehmanen <Kai.Vehmanen at nokia.com>
+ *
+ * @date Created: Fri Jul 15 15:43:53 EEST 2005 ppessi
+ */
+
+#ifndef SU_WAIT_H
+#include <sofia-sip/su_wait.h>
+#endif
+#ifndef SU_TAG_H
+#include <sofia-sip/su_tag.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+typedef struct soa_session soa_session_t;
+
+struct sdp_session_s;
+
+#ifndef SOA_MAGIC_T
+#define SOA_MAGIC_T void
+#endif
+
+typedef SOA_MAGIC_T soa_magic_t;
+
+typedef int soa_callback_f(soa_magic_t *arg, soa_session_t *session);
+
+SOFIAPUBFUN soa_session_t *soa_create(char const *name, su_root_t *, soa_magic_t *);
+
+SOFIAPUBFUN soa_session_t *soa_clone(soa_session_t *, su_root_t *, soa_magic_t *);
+
+SOFIAPUBFUN void soa_destroy(soa_session_t *);
+
+SOFIAPUBFUN int soa_set_params(soa_session_t *ss,
+ tag_type_t tag, tag_value_t value, ...);
+SOFIAPUBFUN int soa_get_params(soa_session_t const *ss,
+ tag_type_t tag, tag_value_t value, ...);
+
+SOFIAPUBFUN tagi_t *soa_get_paramlist(soa_session_t const *ss,
+ tag_type_t tag, tag_value_t value, ...);
+
+SOFIAPUBFUN int soa_error_as_sip_response(soa_session_t *soa,
+ char const **return_phrase);
+
+SOFIAPUBFUN char const *soa_error_as_sip_reason(soa_session_t *soa);
+
+SOFIAPUBFUN int soa_get_warning(soa_session_t *ss, char const **return_phrase);
+
+SOFIAPUBFUN int soa_set_capability_sdp(soa_session_t *ss,
+ struct sdp_session_s const *sdp,
+ char const *str, issize_t len);
+
+SOFIAPUBFUN int soa_get_capability_sdp(soa_session_t const *ss,
+ struct sdp_session_s const **return_sdp,
+ char const **return_sdp_str,
+ isize_t *return_len);
+
+SOFIAPUBFUN int soa_set_remote_sdp(soa_session_t *ss,
+ struct sdp_session_s const *sdp,
+ char const *str, issize_t len);
+
+SOFIAPUBFUN int soa_get_remote_sdp(soa_session_t const *ss,
+ struct sdp_session_s const **return_sdp,
+ char const **return_sdp_str,
+ isize_t *return_len);
+
+SOFIAPUBFUN int soa_clear_remote_sdp(soa_session_t *ss);
+
+SOFIAPUBFUN int soa_get_remote_version(soa_session_t const *ss);
+
+SOFIAPUBFUN int soa_set_user_sdp(soa_session_t *ss,
+ struct sdp_session_s const *sdp,
+ char const *str, issize_t len);
+
+SOFIAPUBFUN int soa_get_user_sdp(soa_session_t const *ss,
+ struct sdp_session_s const **return_sdp,
+ char const **return_sdp_str,
+ isize_t *return_len);
+
+SOFIAPUBFUN int soa_get_user_version(soa_session_t const *ss);
+
+SOFIAPUBFUN int soa_get_local_sdp(soa_session_t const *ss,
+ struct sdp_session_s const **return_sdp,
+ char const **return_sdp_str,
+ isize_t *return_len);
+
+SOFIAPUBFUN char const * const * soa_sip_require(soa_session_t const *ss);
+SOFIAPUBFUN char const * const * soa_sip_supported(soa_session_t const *ss);
+
+SOFIAPUBFUN int soa_remote_sip_features(soa_session_t *ss,
+ char const * const * support,
+ char const * const * required);
+
+SOFIAPUBFUN char **soa_media_features(soa_session_t *ss, int live, su_home_t *home);
+
+SOFIAPUBFUN int soa_generate_offer(soa_session_t *, int always, soa_callback_f *);
+SOFIAPUBFUN int soa_generate_answer(soa_session_t *, soa_callback_f *);
+SOFIAPUBFUN int soa_process_answer(soa_session_t *, soa_callback_f *);
+SOFIAPUBFUN int soa_process_reject(soa_session_t *, soa_callback_f *);
+
+SOFIAPUBFUN int soa_activate(soa_session_t *, char const *option);
+SOFIAPUBFUN int soa_deactivate(soa_session_t *, char const *option);
+
+SOFIAPUBFUN void soa_terminate(soa_session_t *, char const *option);
+
+SOFIAPUBFUN int soa_is_complete(soa_session_t const *ss);
+
+SOFIAPUBFUN int soa_init_offer_answer(soa_session_t *ss);
+
+SOFIAPUBFUN int soa_is_audio_active(soa_session_t const *ss);
+SOFIAPUBFUN int soa_is_video_active(soa_session_t const *ss);
+SOFIAPUBFUN int soa_is_image_active(soa_session_t const *ss);
+SOFIAPUBFUN int soa_is_chat_active(soa_session_t const *ss);
+
+SOFIAPUBFUN int soa_is_remote_audio_active(soa_session_t const *ss);
+SOFIAPUBFUN int soa_is_remote_video_active(soa_session_t const *ss);
+SOFIAPUBFUN int soa_is_remote_image_active(soa_session_t const *ss);
+SOFIAPUBFUN int soa_is_remote_chat_active(soa_session_t const *ss);
+
+SOFIAPUBFUN int soa_tag_filter(tagi_t const *f, tagi_t const *t);
+
+SOFIA_END_DECLS
+
+#endif
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa_add.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa_add.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,48 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SOA_ADD_H
+#define SOA_ADD_H
+/**@file sofia-sip/soa_add.h Register SDP Offer/Answer Interface Instances.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Mon Aug 1 15:43:53 EEST 2005 ppessi
+ */
+
+#include <sofia-sip/su_config.h>
+
+SOFIA_BEGIN_DECLS
+
+struct soa_session_actions;
+
+SOFIAPUBVAR struct soa_session_actions const soa_default_actions;
+
+SOFIAPUBFUN int soa_add(char const *name, struct soa_session_actions const *handler);
+
+SOFIAPUBFUN struct soa_session_actions const *soa_find(char const *name);
+
+SOFIA_END_DECLS
+
+#endif /* SOA_ADD_H */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa_session.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa_session.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,275 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SOA_SESSION_H
+#define SOA_SESSION_H
+/**@file sofia-sip/soa_session.h
+ *
+ * Internal API for SDP Offer/Answer Interface.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Mon Aug 1 15:43:53 EEST 2005 ppessi
+ */
+
+#ifndef SOA_H
+#include "sofia-sip/soa.h"
+#endif
+#ifndef SOA_TAG_H
+#include "sofia-sip/soa_tag.h"
+#endif
+#ifndef SDP_H
+#include <sofia-sip/sdp.h>
+#endif
+#ifndef SU_STRLST_H
+#include <sofia-sip/su_strlst.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+struct soa_session_actions
+{
+ int sizeof_soa_session_actions;
+ int sizeof_soa_session;
+ char const *soa_name;
+ int (*soa_init)(char const *name, soa_session_t *ss, soa_session_t *parent);
+ void (*soa_deinit)(soa_session_t *ss);
+ int (*soa_set_params)(soa_session_t *ss, tagi_t const *tags);
+ int (*soa_get_params)(soa_session_t const *ss, tagi_t *tags);
+ tagi_t *(*soa_get_paramlist)(soa_session_t const *ss,
+ tag_type_t, tag_value_t, ...);
+ char **(*soa_media_features)(soa_session_t *, int live, su_home_t *);
+ char const * const *(*soa_sip_require)(soa_session_t const *ss);
+ char const * const *(*soa_sip_supported)(soa_session_t const *ss);
+ int (*soa_remote_sip_features)(soa_session_t *ss,
+ char const * const * support,
+ char const * const * required);
+ int (*soa_set_capability_sdp)(soa_session_t *, sdp_session_t *,
+ char const *, isize_t);
+ int (*soa_set_remote_sdp)(soa_session_t *, int new_version,
+ sdp_session_t *, char const *, isize_t);
+ int (*soa_set_user_sdp)(soa_session_t *, sdp_session_t *,
+ char const *, isize_t);
+ int (*soa_generate_offer)(soa_session_t *ss, soa_callback_f *completed);
+ int (*soa_generate_answer)(soa_session_t *ss, soa_callback_f *completed);
+ int (*soa_process_answer)(soa_session_t *ss, soa_callback_f *completed);
+ int (*soa_process_reject)(soa_session_t *ss, soa_callback_f *completed);
+ int (*soa_activate_session)(soa_session_t *ss, char const *option);
+ int (*soa_deactivate_session)(soa_session_t *ss, char const *option);
+ void (*soa_terminate_session)(soa_session_t *ss, char const *option);
+};
+
+SOFIAPUBFUN soa_session_t *soa_session_ref(soa_session_t *ss);
+SOFIAPUBFUN void soa_session_unref(soa_session_t *ss);
+
+SOFIAPUBFUN int soa_base_init(char const *name, soa_session_t *,
+ soa_session_t *parent);
+SOFIAPUBFUN void soa_base_deinit(soa_session_t *ss);
+SOFIAPUBFUN int soa_base_set_params(soa_session_t *ss, tagi_t const *tags);
+SOFIAPUBFUN int soa_base_get_params(soa_session_t const *ss, tagi_t *tags);
+SOFIAPUBFUN tagi_t *soa_base_get_paramlist(soa_session_t const *ss,
+ tag_type_t, tag_value_t, ...);
+SOFIAPUBFUN char **soa_base_media_features(soa_session_t *,
+ int live, su_home_t *);
+SOFIAPUBFUN char const * const *soa_base_sip_require(soa_session_t const *ss);
+SOFIAPUBFUN char const * const *soa_base_sip_supported(soa_session_t const *ss);
+
+SOFIAPUBFUN int soa_base_remote_sip_features(soa_session_t *ss,
+ char const * const *support,
+ char const * const *required);
+SOFIAPUBFUN int soa_base_set_capability_sdp(soa_session_t *ss,
+ sdp_session_t *sdp,
+ char const *, isize_t);
+SOFIAPUBFUN int soa_base_set_remote_sdp(soa_session_t *ss,
+ int new_version,
+ sdp_session_t *sdp, char const *, isize_t);
+SOFIAPUBFUN int soa_base_set_user_sdp(soa_session_t *ss,
+ sdp_session_t *sdp, char const *, isize_t);
+
+SOFIAPUBFUN int soa_base_generate_offer(soa_session_t *ss,
+ soa_callback_f *completed);
+SOFIAPUBFUN int soa_base_generate_answer(soa_session_t *ss,
+ soa_callback_f *completed);
+SOFIAPUBFUN int soa_base_process_answer(soa_session_t *ss,
+ soa_callback_f *completed);
+SOFIAPUBFUN int soa_base_process_reject(soa_session_t *ss,
+ soa_callback_f *completed);
+
+SOFIAPUBFUN int soa_base_activate(soa_session_t *ss, char const *option);
+SOFIAPUBFUN int soa_base_deactivate(soa_session_t *ss, char const *option);
+SOFIAPUBFUN void soa_base_terminate(soa_session_t *ss, char const *option);
+
+struct soa_description
+{
+ sdp_session_t *ssd_sdp; /**< Session description */
+ char const *ssd_unparsed; /**< Original session description as string */
+ char const *ssd_str; /**< Session description as string */
+ sdp_printer_t *ssd_printer; /**< SDP printer object */
+};
+
+struct soa_session
+{
+ su_home_t ss_home[1];
+
+ struct soa_session_actions const *ss_actions;
+ char const *ss_name; /**< Our name */
+
+ su_root_t *ss_root;
+ soa_magic_t *ss_magic; /**< Application data */
+
+ soa_callback_f *ss_in_progress;/**< Operation in progress */
+
+ /** Incremented once each time session is terminated */
+ unsigned ss_terminated;
+
+ /* XXX - this is part of public API. we should have no bitfields here */
+
+ unsigned ss_active:1; /**< Session has been activated */
+
+ /* Current Offer-Answer status */
+ unsigned ss_complete:1; /**< Completed SDP offer-answer */
+
+ unsigned ss_unprocessed_remote:1; /**< We have received remote SDP */
+
+ unsigned ss_offer_sent:2; /**< We have offered SDP */
+ unsigned ss_answer_recv:2; /**< We have received SDP answer */
+
+ unsigned ss_offer_recv:2; /**< We have received an offer */
+ unsigned ss_answer_sent:2; /**< We have answered (reliably, if >1) */
+ unsigned :0; /* Pad */
+
+ unsigned ss_oa_rounds; /**< Number of O/A rounds completed */
+
+ struct soa_media_activity
+ {
+ int ma_audio:4; /**< Audio activity (send/recv) */
+ int ma_video:4; /**< Video activity (send/recv) */
+ int ma_image:4; /**< Image activity (send/recv) for JPIP */
+ int ma_chat:4; /**< Chat activity (send/recv) */
+ } ss_local_activity[1], ss_remote_activity[1];
+
+ /** Capabilities as specified by application */
+ struct soa_description ss_caps[1];
+
+ /** Session description provided by user */
+ struct soa_description ss_user[1];
+ unsigned ss_user_version; /**< Version incremented at each change */
+
+ /** Remote session description */
+ struct soa_description ss_remote[1];
+ unsigned ss_remote_version; /**< Version incremented at each change */
+
+ /** Local session description */
+ struct soa_description ss_local[1];
+ unsigned ss_local_user_version, ss_local_remote_version;
+ char const *ss_hold_local;
+
+ /** Previous session description (return to this if offer is rejected) */
+ struct soa_description ss_previous[1];
+ unsigned ss_previous_user_version, ss_previous_remote_version;
+ char const *ss_hold_previous;
+
+ sdp_session_t *ss_rsession; /**< Processed remote SDP */
+
+ /** SIP features required */
+ char const * const *ss_local_required;
+ /** SIP features supported */
+ char const * const *ss_local_support;
+
+ /** SIP features required by remote */
+ char const **ss_remote_required;
+ /** SIP features supported */
+ char const **ss_remote_support;
+
+ int ss_status; /**< Status from last media operation */
+ char const *ss_phrase; /**< Phrase from last media operation */
+ char *ss_reason; /**< Reason generated by media operation */
+
+
+ /* Media parameters */
+ char const *ss_address;
+ enum soa_af ss_af;
+ char const *ss_hold; /**< Media on hold locally */
+
+ char const *ss_cname;
+
+ /* XXX - this is part of public API. we should have no bitfields here */
+
+ /* Codec handling during negotiation */
+ unsigned ss_rtp_select:2;
+ unsigned ss_rtp_sort:2;
+ unsigned ss_rtp_mismatch:1;
+
+ unsigned ss_srtp_enable:1,
+ ss_srtp_confidentiality:1,
+ ss_srtp_integrity:1;
+
+ unsigned :0; /* Pad */
+
+ int ss_wcode; /**< Warning code from last media operation */
+ char const *ss_warning; /**< Warnings text from last media operation */
+};
+
+/* ====================================================================== */
+
+SOFIAPUBFUN int soa_has_received_sdp(soa_session_t const *ss);
+
+SOFIAPUBFUN int soa_set_status(soa_session_t *ss,
+ int status, char const *phrase);
+
+SOFIAPUBFUN void soa_set_activity(soa_session_t *ss,
+ sdp_media_t const *m, int remote);
+
+SOFIAPUBFUN int soa_description_set(soa_session_t *ss,
+ struct soa_description *ssd,
+ sdp_session_t *sdp,
+ char const *sdp_str,
+ isize_t sdp_len);
+
+SOFIAPUBFUN void soa_description_free(soa_session_t *,
+ struct soa_description *ssd);
+
+SOFIAPUBFUN int soa_description_dup(su_home_t *,
+ struct soa_description *ssd,
+ struct soa_description const *ssd0);
+
+SOFIAPUBFUN int soa_init_sdp_origin(soa_session_t *ss,
+ sdp_origin_t *o, char buf[64]);
+SOFIAPUBFUN int soa_init_sdp_connection(soa_session_t *,
+ sdp_connection_t *, char buf[64]);
+
+/* ====================================================================== */
+/* Debug log settings */
+
+#define SU_LOG soa_log
+
+#ifdef SU_DEBUG_H
+#error <su_debug.h> included directly.
+#endif
+#include <sofia-sip/su_debug.h>
+SOFIAPUBVAR su_log_t soa_log[];
+
+SOFIA_END_DECLS
+
+#endif
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa_tag.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa_tag.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,249 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SOA_TAG_H
+#define SOA_TAG_H
+/**@file sofia-sip/soa_tag.h Tags for SDP Offer/Answer Application Interface.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Mon Aug 1 15:43:53 EEST 2005 ppessi
+ */
+
+#ifndef SU_TAG_H
+#include <sofia-sip/su_tag.h>
+#endif
+#ifndef SDP_TAG_H
+#include <sofia-sip/sdp_tag.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** List of base SOA tags (defined in base SOA module). */
+SOFIAPUBVAR tagi_t soa_tag_list[];
+
+/** Filter tag matching any soa tag. */
+#define SOATAG_ANY() soatag_any, ((tag_value_t)0)
+SOFIAPUBVAR tag_typedef_t soatag_any;
+
+/**
+ * Media states
+ */
+enum {
+ SOA_ACTIVE_REJECTED = -8, /**< Media rejected in negotiation */
+ SOA_ACTIVE_DISABLED = -4, /**< Media not negotiated */
+ SOA_ACTIVE_INACTIVE = 0, /**< Media is inactive: no RTP */
+ SOA_ACTIVE_SENDONLY = 1, /**< Media is sent only */
+ SOA_ACTIVE_RECVONLY = 2, /**< Media is received only */
+ SOA_ACTIVE_SENDRECV = SOA_ACTIVE_SENDONLY | SOA_ACTIVE_RECVONLY
+ /**< Media is bidirectional */
+};
+
+#define SOA_ACTIVE_DISABLED SOA_ACTIVE_DISABLED
+#define SOA_ACTIVE_REJECTED SOA_ACTIVE_REJECTED
+#define SOA_ACTIVE_INACTIVE SOA_ACTIVE_INACTIVE
+#define SOA_ACTIVE_SENDONLY SOA_ACTIVE_SENDONLY
+#define SOA_ACTIVE_RECVONLY SOA_ACTIVE_RECVONLY
+#define SOA_ACTIVE_SENDRECV SOA_ACTIVE_SENDRECV
+
+/*
+ * SOA engine and media parameters set by soa_set_params(), get by
+ * soa_get_params() or soa_get_paramlist()
+ */
+
+#define SOATAG_LOCAL_SDP(x) soatag_local_sdp, sdptag_session_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_local_sdp;
+#define SOATAG_LOCAL_SDP_REF(x) \
+ soatag_local_sdp_ref, sdptag_session_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_local_sdp_ref;
+
+#define SOATAG_LOCAL_SDP_STR(x) soatag_local_sdp_str, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_local_sdp_str;
+#define SOATAG_LOCAL_SDP_STR_REF(x) \
+ soatag_local_sdp_str_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_local_sdp_str_ref;
+
+#define SOATAG_USER_SDP(x) soatag_user_sdp, sdptag_session_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_user_sdp;
+#define SOATAG_USER_SDP_REF(x) \
+ soatag_user_sdp_ref, sdptag_session_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_user_sdp_ref;
+
+#define SOATAG_USER_SDP_STR(x) soatag_user_sdp_str, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_user_sdp_str;
+#define SOATAG_USER_SDP_STR_REF(x) \
+ soatag_user_sdp_str_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_user_sdp_str_ref;
+
+#define SOATAG_CAPS_SDP(x) soatag_caps_sdp, sdptag_session_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_caps_sdp;
+#define SOATAG_CAPS_SDP_REF(x) \
+ soatag_caps_sdp_ref, sdptag_session_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_caps_sdp_ref;
+
+#define SOATAG_CAPS_SDP_STR(x) soatag_caps_sdp_str, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_caps_sdp_str;
+#define SOATAG_CAPS_SDP_STR_REF(x) \
+ soatag_caps_sdp_str_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_caps_sdp_str_ref;
+
+#define SOATAG_REMOTE_SDP(x) soatag_remote_sdp, sdptag_session_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_remote_sdp;
+#define SOATAG_REMOTE_SDP_REF(x) \
+ soatag_remote_sdp_ref, sdptag_session_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_remote_sdp_ref;
+
+#define SOATAG_REMOTE_SDP_STR(x) soatag_remote_sdp_str, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_remote_sdp_str;
+#define SOATAG_REMOTE_SDP_STR_REF(x) \
+ soatag_remote_sdp_str_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_remote_sdp_str_ref;
+
+#define SOATAG_LOCAL_SDP(x) soatag_local_sdp, sdptag_session_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_local_sdp;
+#define SOATAG_LOCAL_SDP_REF(x) \
+ soatag_local_sdp_ref, sdptag_session_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_local_sdp_ref;
+
+#define SOATAG_LOCAL_SDP_STR(x) soatag_local_sdp_str, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_local_sdp_str;
+#define SOATAG_LOCAL_SDP_STR_REF(x) \
+ soatag_local_sdp_str_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_session_sdp_str_ref;
+
+#define SOATAG_AF(x) soatag_af, tag_int_v((x))
+SOFIAPUBVAR tag_typedef_t soatag_af;
+
+#define SOATAG_AF_REF(x) soatag_af_ref, tag_int_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_af_ref;
+
+/** SOATAG_AF() parameter type */
+enum soa_af {
+ SOA_AF_ANY, /**< Use any address family. */
+ SOA_AF_IP4_ONLY, /**< Use IP version 4 only */
+ SOA_AF_IP6_ONLY, /**< Use IP version 6 only */
+ SOA_AF_IP4_IP6, /**< Prefer IP4 to IP6 */
+ SOA_AF_IP6_IP4 /**< Prefer IP6 to IP4 */
+};
+
+#define SOA_AF_ANY SOA_AF_ANY
+#define SOA_AF_IP4_ONLY SOA_AF_IP4_ONLY
+#define SOA_AF_IP6_ONLY SOA_AF_IP6_ONLY
+#define SOA_AF_IP4_IP6 SOA_AF_IP4_IP6
+#define SOA_AF_IP6_IP4 SOA_AF_IP6_IP4
+
+#define SOATAG_ADDRESS(x) soatag_address, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_address;
+#define SOATAG_ADDRESS_REF(x) soatag_address_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_address_ref;
+
+#define SOATAG_RTP_SELECT(x) soatag_rtp_select, tag_int_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_rtp_select;
+#define SOATAG_RTP_SELECT_REF(x) soatag_rtp_select_ref, tag_int_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_rtp_select_ref;
+
+/** Parameter type for SOATAG_RTP_SELECT() */
+enum {
+ SOA_RTP_SELECT_SINGLE, /**< Select the best common codec */
+ SOA_RTP_SELECT_COMMON, /**< Select all common codecs */
+ SOA_RTP_SELECT_ALL /**< Select all local codecs */
+ };
+
+#define SOATAG_AUDIO_AUX(x) soatag_audio_aux, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_audio_aux;
+#define SOATAG_AUDIO_AUX_REF(x) soatag_audio_aux_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_audio_aux_ref;
+
+#define SOATAG_RTP_SORT(x) soatag_rtp_sort, tag_int_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_rtp_sort;
+#define SOATAG_RTP_SORT_REF(x) soatag_rtp_sort_ref, tag_int_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_rtp_sort_ref;
+
+/** Parameter type for SOATAG_RTP_SORT() */
+enum {
+ SOA_RTP_SORT_DEFAULT, /**< Select codecs by local preference
+ * when media is recvonly,
+ * remote preference othewise.
+ */
+ SOA_RTP_SORT_LOCAL, /**< Select codecs by local preference. */
+ SOA_RTP_SORT_REMOTE /**< Select codecs by remote preference. */
+ };
+
+#define SOATAG_RTP_MISMATCH(x) soatag_rtp_mismatch, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_rtp_mismatch;
+#define SOATAG_RTP_MISMATCH_REF(x) soatag_rtp_mismatch_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_rtp_mismatch_ref;
+
+#define SOATAG_ACTIVE_AUDIO(x) soatag_active_audio, tag_int_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_active_audio;
+
+#define SOATAG_ACTIVE_AUDIO_REF(x) soatag_active_audio_ref, tag_int_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_active_audio_ref;
+
+#define SOATAG_ACTIVE_VIDEO(x) soatag_active_video, tag_int_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_active_video;
+
+#define SOATAG_ACTIVE_VIDEO_REF(x) soatag_active_video_ref, tag_int_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_active_video_ref;
+
+#define SOATAG_ACTIVE_IMAGE(x) soatag_active_image, tag_int_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_active_image;
+
+#define SOATAG_ACTIVE_IMAGE_REF(x) soatag_active_image_ref, tag_int_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_active_image_ref;
+
+#define SOATAG_ACTIVE_CHAT(x) soatag_active_chat, tag_int_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_active_chat;
+
+#define SOATAG_ACTIVE_CHAT_REF(x) soatag_active_chat_ref, tag_int_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_active_chat_ref;
+
+/** Enable SRTP */
+#define SOATAG_SRTP_ENABLE(x) soatag_srtp_enable, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_srtp_enable;
+
+#define SOATAG_SRTP_ENABLE_REF(x) soatag_srtp_enable_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_srtp_enable_ref;
+
+#define SOATAG_SRTP_CONFIDENTIALITY(x) soatag_srtp_confidentiality, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_srtp_confidentiality;
+#define SOATAG_SRTP_CONFIDENTIALITY_REF(x) soatag_srtp_confidentiality_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_srtp_confidentiality_ref;
+
+/** Enable SRTP integrity protection */
+#define SOATAG_SRTP_INTEGRITY(x) soatag_srtp_integrity, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_srtp_integrity;
+
+#define SOATAG_SRTP_INTEGRITY_REF(x) \
+ soatag_srtp_integrity_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_srtp_integrity_ref;
+
+#define SOATAG_HOLD(x) soatag_hold, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t soatag_hold;
+#define SOATAG_HOLD_REF(x) soatag_hold_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t soatag_hold_ref;
+
+SOFIA_END_DECLS
+
+#endif /* SOA_TAG_H */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/test_soa.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/test_soa.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1339 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE test_soa.c
+ * @brief High-level tester for Sofia SDP Offer/Answer Engine
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Aug 17 12:12:12 EEST 2005 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <assert.h>
+
+#if HAVE_ALARM
+#include <unistd.h>
+#include <signal.h>
+#endif
+
+struct context;
+#define SOA_MAGIC_T struct context
+
+#include "sofia-sip/soa.h"
+#include "sofia-sip/soa_tag.h"
+#include "sofia-sip/soa_add.h"
+
+#include <sofia-sip/sdp.h>
+
+#include <sofia-sip/su_log.h>
+#include <sofia-sip/sip_tag.h>
+
+extern su_log_t soa_log[];
+
+char const name[] = "test_soa";
+int tstflags = 0;
+#define TSTFLAGS tstflags
+
+#include <sofia-sip/tstdef.h>
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+#define __func__ name
+#endif
+
+#define NONE ((void*)-1)
+
+struct context
+{
+ su_home_t home[1];
+ su_root_t *root;
+
+ struct {
+ soa_session_t *a;
+ soa_session_t *b;
+ } asynch;
+
+ soa_session_t *a;
+ soa_session_t *b;
+
+ soa_session_t *completed;
+};
+
+int test_api_completed(struct context *arg, soa_session_t *session)
+{
+ return 0;
+}
+
+int test_api_errors(struct context *ctx)
+{
+ BEGIN();
+
+ char const *phrase = NULL;
+ char const *null = NULL;
+
+ TEST_1(!soa_create("default", NULL, NULL));
+ TEST_1(!soa_clone(NULL, NULL, NULL));
+ TEST_VOID(soa_destroy(NULL));
+
+ TEST_1(-1 == soa_set_params(NULL, TAG_END()));
+ TEST_1(-1 == soa_get_params(NULL, TAG_END()));
+
+ TEST_1(!soa_get_paramlist(NULL, TAG_END()));
+
+ TEST(soa_error_as_sip_response(NULL, &phrase), 500);
+ TEST_S(phrase, "Internal Server Error");
+
+ TEST_1(soa_error_as_sip_reason(NULL));
+
+ TEST_1(!soa_media_features(NULL, 0, NULL));
+
+ TEST_1(!soa_sip_require(NULL));
+ TEST_1(!soa_sip_supported(NULL));
+
+ TEST_1(-1 == soa_remote_sip_features(NULL, &null, &null));
+
+ TEST_1(soa_set_capability_sdp(NULL, NULL, NULL, -1) < 0);
+ TEST_1(soa_set_remote_sdp(NULL, NULL, NULL, -1) < 0);
+ TEST_1(soa_set_user_sdp(NULL, NULL, NULL, -1) < 0);
+
+ TEST_1(soa_get_capability_sdp(NULL, NULL, NULL, NULL) < 0);
+ TEST_1(soa_get_remote_sdp(NULL, NULL, NULL, NULL) < 0);
+ TEST_1(soa_get_user_sdp(NULL, NULL, NULL, NULL) < 0);
+ TEST_1(soa_get_local_sdp(NULL, NULL, NULL, NULL) < 0);
+
+ TEST_1(-1 == soa_generate_offer(NULL, 0, test_api_completed));
+
+ TEST_1(-1 == soa_generate_answer(NULL, test_api_completed));
+
+ TEST_1(-1 == soa_process_answer(NULL, test_api_completed));
+
+ TEST_1(-1 == soa_process_reject(NULL, test_api_completed));
+
+ TEST(soa_activate(NULL, "both"), -1);
+ TEST(soa_deactivate(NULL, "both"), -1);
+ TEST_VOID(soa_terminate(NULL, "both"));
+
+ TEST_1(!soa_is_complete(NULL));
+
+ TEST_1(!soa_init_offer_answer(NULL));
+
+ TEST(soa_is_audio_active(NULL), SOA_ACTIVE_DISABLED);
+ TEST(soa_is_video_active(NULL), SOA_ACTIVE_DISABLED);
+ TEST(soa_is_image_active(NULL), SOA_ACTIVE_DISABLED);
+ TEST(soa_is_chat_active(NULL), SOA_ACTIVE_DISABLED);
+
+ TEST(soa_is_remote_audio_active(NULL), SOA_ACTIVE_DISABLED);
+ TEST(soa_is_remote_video_active(NULL), SOA_ACTIVE_DISABLED);
+ TEST(soa_is_remote_image_active(NULL), SOA_ACTIVE_DISABLED);
+ TEST(soa_is_remote_chat_active(NULL), SOA_ACTIVE_DISABLED);
+
+ END();
+}
+
+int test_soa_tags(struct context *ctx)
+{
+ BEGIN();
+
+ su_home_t home[1] = { SU_HOME_INIT(home) };
+ tagi_t *t;
+
+ tagi_t const soafilter[] = {
+ { TAG_FILTER(soa_tag_filter) },
+ { TAG_NULL() }
+ };
+
+ t = tl_filtered_tlist(home, soafilter,
+ SIPTAG_FROM_STR("sip:my.domain"),
+ SOATAG_USER_SDP_STR("v=0"),
+ SOATAG_HOLD("*"),
+ TAG_END());
+ TEST_1(t);
+ TEST_P(t[0].t_tag, soatag_user_sdp_str);
+ TEST_P(t[1].t_tag, soatag_hold);
+ TEST_1(t[2].t_tag == NULL || t[2].t_tag == tag_null);
+
+ su_home_deinit(home);
+
+ END();
+}
+
+int test_init(struct context *ctx, char *argv[])
+{
+ BEGIN();
+
+ int n;
+
+ ctx->root = su_root_create(ctx); TEST_1(ctx->root);
+
+ ctx->asynch.a = soa_create("asynch", ctx->root, ctx);
+ TEST_1(!ctx->asynch.a);
+
+#if 0
+ TEST_1(!soa_find("asynch"));
+ TEST_1(soa_find("default"));
+
+ n = soa_add("asynch", &soa_asynch_actions); TEST(n, 0);
+
+ TEST_1(soa_find("asynch"));
+
+ ctx->asynch.a = soa_create("asynch", ctx->root, ctx);
+ TEST_1(ctx->asynch.a);
+
+ ctx->asynch.b = soa_create("asynch", ctx->root, ctx);
+ TEST_1(ctx->asynch.b);
+#endif
+
+ /* Create asynchronous endpoints */
+
+ ctx->a = soa_create("static", ctx->root, ctx);
+ TEST_1(!ctx->a);
+
+ TEST_1(!soa_find("static"));
+ TEST_1(soa_find("default"));
+
+ n = soa_add("static", &soa_default_actions); TEST(n, 0);
+
+ TEST_1(soa_find("static"));
+
+ ctx->a = soa_create("static", ctx->root, ctx);
+ TEST_1(ctx->a);
+
+ ctx->b = soa_create("static", ctx->root, ctx);
+ TEST_1(ctx->b);
+
+ END();
+}
+
+int test_params(struct context *ctx)
+{
+ BEGIN();
+ int n;
+ int af;
+ char const *address;
+ char const *hold;
+ int rtp_select, rtp_sort;
+ int rtp_mismatch;
+ int srtp_enable, srtp_confidentiality, srtp_integrity;
+ soa_session_t *a = ctx->a, *b = ctx->b;
+
+ n = soa_set_params(a, TAG_END()); TEST(n, 0);
+ n = soa_set_params(b, TAG_END()); TEST(n, 0);
+
+ af = -42;
+ address = NONE;
+ hold = NONE;
+
+ rtp_select = -1, rtp_sort = -1, rtp_mismatch = -1;
+ srtp_enable = -1, srtp_confidentiality = -1, srtp_integrity = -1;
+
+ TEST(soa_get_params(a,
+ SOATAG_AF_REF(af),
+ SOATAG_ADDRESS_REF(address),
+ SOATAG_HOLD_REF(hold),
+
+ SOATAG_RTP_SELECT_REF(rtp_select),
+ SOATAG_RTP_SORT_REF(rtp_sort),
+ SOATAG_RTP_MISMATCH_REF(rtp_mismatch),
+
+ SOATAG_SRTP_ENABLE_REF(srtp_enable),
+ SOATAG_SRTP_CONFIDENTIALITY_REF(srtp_confidentiality),
+ SOATAG_SRTP_INTEGRITY_REF(srtp_integrity),
+ TAG_END()),
+ 9);
+ TEST(af, SOA_AF_ANY);
+ TEST_P(address, 0);
+ TEST_P(hold, 0);
+ TEST(rtp_select, SOA_RTP_SELECT_SINGLE);
+ TEST(rtp_sort, SOA_RTP_SORT_DEFAULT);
+ TEST(rtp_mismatch, 0);
+ TEST(srtp_enable, 0);
+ TEST(srtp_confidentiality, 0);
+ TEST(srtp_integrity, 0);
+
+ TEST(soa_set_params(a,
+ SOATAG_AF(SOA_AF_IP4_IP6),
+ SOATAG_ADDRESS("127.0.0.1"),
+ SOATAG_HOLD("audio"),
+
+ SOATAG_RTP_SELECT(SOA_RTP_SELECT_ALL),
+ SOATAG_RTP_SORT(SOA_RTP_SORT_LOCAL),
+ SOATAG_RTP_MISMATCH(1),
+
+ SOATAG_SRTP_ENABLE(1),
+ SOATAG_SRTP_CONFIDENTIALITY(1),
+ SOATAG_SRTP_INTEGRITY(1),
+
+ TAG_END()),
+ 9);
+ TEST(soa_get_params(a,
+ SOATAG_AF_REF(af),
+ SOATAG_ADDRESS_REF(address),
+ SOATAG_HOLD_REF(hold),
+
+ SOATAG_RTP_SELECT_REF(rtp_select),
+ SOATAG_RTP_SORT_REF(rtp_sort),
+ SOATAG_RTP_MISMATCH_REF(rtp_mismatch),
+
+ SOATAG_SRTP_ENABLE_REF(srtp_enable),
+ SOATAG_SRTP_CONFIDENTIALITY_REF(srtp_confidentiality),
+ SOATAG_SRTP_INTEGRITY_REF(srtp_integrity),
+ TAG_END()),
+ 9);
+ TEST(af, SOA_AF_IP4_IP6);
+ TEST_S(address, "127.0.0.1");
+ TEST_S(hold, "audio");
+ TEST(rtp_select, SOA_RTP_SELECT_ALL);
+ TEST(rtp_sort, SOA_RTP_SORT_LOCAL);
+ TEST(rtp_mismatch, 1);
+ TEST(srtp_enable, 1);
+ TEST(srtp_confidentiality, 1);
+ TEST(srtp_integrity, 1);
+
+ /* Restore defaults */
+ TEST(soa_set_params(a,
+ SOATAG_AF(SOA_AF_IP4_IP6),
+ SOATAG_ADDRESS(NULL),
+ SOATAG_HOLD(NULL),
+
+ SOATAG_RTP_SELECT(SOA_RTP_SELECT_SINGLE),
+ SOATAG_RTP_SORT(SOA_RTP_SORT_DEFAULT),
+ SOATAG_RTP_MISMATCH(0),
+
+ SOATAG_SRTP_ENABLE(0),
+ SOATAG_SRTP_CONFIDENTIALITY(0),
+ SOATAG_SRTP_INTEGRITY(0),
+
+ TAG_END()),
+ 9);
+
+ END();
+}
+
+int test_completed(struct context *ctx, soa_session_t *session)
+{
+ ctx->completed = session;
+ su_root_break(ctx->root);
+ return 0;
+}
+
+int test_static_offer_answer(struct context *ctx)
+{
+ BEGIN();
+ int n;
+
+ soa_session_t *a, *b;
+
+ char const *caps = NONE, *offer = NONE, *answer = NONE;
+ isize_t capslen = -1, offerlen = -1, answerlen = -1;
+
+ su_home_t home[1] = { SU_HOME_INIT(home) };
+
+ char const a_caps[] =
+ "v=0\r\n"
+ "o=left 219498671 2 IN IP4 127.0.0.2\r\n"
+ "c=IN IP4 127.0.0.2\r\n"
+ "m=audio 0 RTP/AVP 0 8\r\n";
+
+ char const b_caps[] =
+ "m=audio 5004 RTP/AVP 96 8\n"
+ "m=rtpmap:96 GSM/8000\n";
+
+ TEST(soa_set_capability_sdp(ctx->a, 0, "m=audio 0 RTP/AVP 0 8", -1),
+ 1);
+ TEST(soa_set_capability_sdp(ctx->a, 0, a_caps, strlen(a_caps)),
+ 1);
+ TEST(soa_get_capability_sdp(ctx->a, NULL, &caps, &capslen), 1);
+
+ TEST_1(caps != NULL && caps != NONE);
+ TEST_1(capslen > 0);
+
+ TEST(soa_set_user_sdp(ctx->b, 0, b_caps, strlen(b_caps)), 1);
+ TEST(soa_get_capability_sdp(ctx->a, NULL, &caps, &capslen), 1);
+
+ TEST_1(a = soa_clone(ctx->a, ctx->root, ctx));
+ TEST_1(b = soa_clone(ctx->b, ctx->root, ctx));
+
+ n = soa_get_local_sdp(a, NULL, &offer, &offerlen); TEST(n, 0);
+
+ n = soa_set_user_sdp(a, 0, "m=audio 5004 RTP/AVP 0 8", -1); TEST(n, 1);
+
+ n = soa_generate_offer(a, 1, test_completed); TEST(n, 0);
+
+ n = soa_get_local_sdp(a, NULL, &offer, &offerlen); TEST(n, 1);
+ TEST_1(offer != NULL && offer != NONE);
+
+ n = soa_set_remote_sdp(b, 0, offer, offerlen); TEST(n, 1);
+
+ n = soa_get_local_sdp(b, NULL, &answer, &answerlen); TEST(n, 0);
+
+ n = soa_set_params(b,
+ SOATAG_LOCAL_SDP_STR("m=audio 5004 RTP/AVP 8"),
+ SOATAG_AF(SOA_AF_IP4_ONLY),
+ SOATAG_ADDRESS("1.2.3.4"),
+ TAG_END());
+
+ n = soa_generate_answer(b, test_completed); TEST(n, 0);
+
+ TEST_1(soa_is_complete(b));
+ TEST(soa_activate(b, NULL), 0);
+
+ n = soa_get_local_sdp(b, NULL, &answer, &answerlen); TEST(n, 1);
+ TEST_1(answer != NULL && answer != NONE);
+ TEST_1(strstr(answer, "c=IN IP4 1.2.3.4"));
+
+ n = soa_set_remote_sdp(a, 0, answer, -1); TEST(n, 1);
+
+ n = soa_process_answer(a, test_completed); TEST(n, 0);
+
+ TEST_1(soa_is_complete(a));
+ TEST(soa_activate(a, NULL), 0);
+
+ TEST(soa_is_audio_active(a), SOA_ACTIVE_SENDRECV);
+ TEST(soa_is_video_active(a), SOA_ACTIVE_DISABLED);
+ TEST(soa_is_image_active(a), SOA_ACTIVE_DISABLED);
+ TEST(soa_is_chat_active(a), SOA_ACTIVE_DISABLED);
+
+ TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_SENDRECV);
+ TEST(soa_is_remote_video_active(a), SOA_ACTIVE_DISABLED);
+ TEST(soa_is_remote_image_active(a), SOA_ACTIVE_DISABLED);
+ TEST(soa_is_remote_chat_active(a), SOA_ACTIVE_DISABLED);
+
+ /* 'A' will put call on hold */
+ offer = NONE;
+ TEST(soa_set_params(a, SOATAG_HOLD("*"), TAG_END()), 1);
+
+ TEST(soa_generate_offer(a, 1, test_completed), 0);
+ TEST(soa_get_local_sdp(a, NULL, &offer, &offerlen), 1);
+ TEST_1(offer != NULL && offer != NONE);
+ TEST_1(strstr(offer, "a=sendonly"));
+ TEST(soa_set_remote_sdp(b, 0, offer, offerlen), 1);
+ TEST(soa_generate_answer(b, test_completed), 0);
+ TEST_1(soa_is_complete(b));
+ TEST(soa_activate(b, NULL), 0);
+ TEST(soa_get_local_sdp(b, NULL, &answer, &answerlen), 1);
+ TEST_1(answer != NULL && answer != NONE);
+ TEST_1(strstr(answer, "a=recvonly"));
+ TEST(soa_set_remote_sdp(a, 0, answer, -1), 1);
+ TEST(soa_process_answer(a, test_completed), 0);
+ TEST(soa_activate(a, NULL), 0);
+
+ TEST(soa_is_audio_active(a), SOA_ACTIVE_SENDONLY);
+ TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_SENDONLY);
+
+ /* 'A' will release hold. */
+ TEST(soa_set_params(a, SOATAG_HOLD(NULL), TAG_END()), 1);
+
+ TEST(soa_generate_offer(a, 1, test_completed), 0);
+ TEST(soa_get_local_sdp(a, NULL, &offer, &offerlen), 1);
+ TEST_1(offer != NULL && offer != NONE);
+ TEST_1(!strstr(offer, "a=sendonly"));
+ TEST(soa_set_remote_sdp(b, 0, offer, offerlen), 1);
+ TEST(soa_generate_answer(b, test_completed), 0);
+ TEST_1(soa_is_complete(b));
+ TEST(soa_activate(b, NULL), 0);
+ TEST(soa_get_local_sdp(b, NULL, &answer, &answerlen), 1);
+ TEST_1(answer != NULL && answer != NONE);
+ TEST_1(!strstr(answer, "a=recvonly"));
+ TEST(soa_set_remote_sdp(a, 0, answer, -1), 1);
+ TEST(soa_process_answer(a, test_completed), 0);
+ TEST(soa_activate(a, NULL), 0);
+
+ TEST(soa_is_audio_active(a), SOA_ACTIVE_SENDRECV);
+ TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_SENDRECV);
+
+ /* 'A' will put B on hold but this time with c=IN IP4 0.0.0.0 */
+ TEST(soa_set_params(a, SOATAG_HOLD("*"), TAG_END()), 1);
+ TEST(soa_generate_offer(a, 1, test_completed), 0);
+
+ {
+ sdp_session_t const *o_sdp;
+ sdp_session_t *sdp;
+ sdp_printer_t *p;
+ sdp_connection_t *c;
+
+ TEST(soa_get_local_sdp(a, &o_sdp, NULL, NULL), 1);
+ TEST_1(o_sdp != NULL && o_sdp != NONE);
+ TEST_1(sdp = sdp_session_dup(home, o_sdp));
+
+ /* Remove mode, change c=, encode offer */
+ if (sdp->sdp_media->m_connections)
+ c = sdp->sdp_media->m_connections;
+ else
+ c = sdp->sdp_connection;
+ TEST_1(c);
+ c->c_address = "0.0.0.0";
+
+ TEST_1(p = sdp_print(home, sdp, NULL, 0, sdp_f_realloc));
+ TEST_1(sdp_message(p));
+ offer = sdp_message(p); offerlen = strlen(offer);
+ }
+
+ TEST(soa_set_remote_sdp(b, 0, offer, -1), 1);
+ TEST(soa_generate_answer(b, test_completed), 0);
+ TEST_1(soa_is_complete(b));
+ TEST(soa_activate(b, NULL), 0);
+ TEST(soa_get_local_sdp(b, NULL, &answer, &answerlen), 1);
+ TEST_1(answer != NULL && answer != NONE);
+ TEST_1(strstr(answer, "a=recvonly"));
+ TEST(soa_set_remote_sdp(a, 0, answer, -1), 1);
+ TEST(soa_process_answer(a, test_completed), 0);
+ TEST(soa_activate(a, NULL), 0);
+
+ TEST(soa_is_audio_active(a), SOA_ACTIVE_SENDONLY);
+ TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_SENDONLY);
+ TEST(soa_is_audio_active(b), SOA_ACTIVE_RECVONLY);
+ TEST(soa_is_remote_audio_active(b), SOA_ACTIVE_RECVONLY);
+
+ /* 'A' will propose adding video. */
+ /* 'B' will reject. */
+ TEST(soa_set_params(a,
+ SOATAG_HOLD(NULL), /* 'A' will release hold. */
+ SOATAG_USER_SDP_STR("m=audio 5004 RTP/AVP 0 8\r\n"
+ "m=video 5006 RTP/AVP 34\r\n"),
+ TAG_END()), 2);
+
+ TEST(soa_generate_offer(a, 1, test_completed), 0);
+ TEST(soa_get_local_sdp(a, NULL, &offer, &offerlen), 1);
+ TEST_1(offer != NULL && offer != NONE);
+ TEST_1(!strstr(offer, "a=sendonly"));
+ TEST_1(strstr(offer, "m=video"));
+ TEST(soa_set_remote_sdp(b, 0, offer, offerlen), 1);
+ TEST(soa_generate_answer(b, test_completed), 0);
+ TEST_1(soa_is_complete(b));
+ TEST(soa_activate(b, NULL), 0);
+ TEST(soa_get_local_sdp(b, NULL, &answer, &answerlen), 1);
+ TEST_1(answer != NULL && answer != NONE);
+ TEST_1(!strstr(answer, "a=recvonly"));
+ TEST_1(strstr(answer, "m=video"));
+ TEST(soa_set_remote_sdp(a, 0, answer, -1), 1);
+ TEST(soa_process_answer(a, test_completed), 0);
+ TEST(soa_activate(a, NULL), 0);
+
+ TEST(soa_is_audio_active(a), SOA_ACTIVE_SENDRECV);
+ TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_SENDRECV);
+ TEST(soa_is_video_active(a), SOA_ACTIVE_REJECTED);
+
+ {
+ /* Test tags */
+ sdp_session_t const *l = NULL, *u = NULL, *r = NULL;
+ sdp_media_t const *m;
+
+ TEST(soa_get_params(b,
+ SOATAG_LOCAL_SDP_REF(l),
+ SOATAG_USER_SDP_REF(u),
+ SOATAG_REMOTE_SDP_REF(r),
+ TAG_END()), 3);
+
+ TEST_1(l); TEST_1(u); TEST_1(r);
+ TEST_1(m = l->sdp_media); TEST(m->m_type, sdp_media_audio);
+ TEST_1(!m->m_rejected);
+ TEST_1(m = m->m_next); TEST(m->m_type, sdp_media_video);
+ TEST_1(m->m_rejected);
+ }
+
+ /* 'B' will now propose adding video. */
+ /* 'A' will accept. */
+ TEST(soa_set_params(b,
+ SOATAG_USER_SDP_STR("m=audio 5004 RTP/AVP 0 8\r\n"
+ "m=video 5006 RTP/AVP 34\r\n"),
+ TAG_END()), 1);
+
+ TEST(soa_generate_offer(b, 1, test_completed), 0);
+ TEST(soa_get_local_sdp(b, NULL, &offer, &offerlen), 1);
+ TEST_1(offer != NULL && offer != NONE);
+ TEST_1(!strstr(offer, "b=sendonly"));
+ TEST_1(strstr(offer, "m=video"));
+ TEST(soa_set_remote_sdp(a, 0, offer, offerlen), 1);
+ TEST(soa_generate_answer(a, test_completed), 0);
+ TEST_1(soa_is_complete(a));
+ TEST(soa_activate(a, NULL), 0);
+ TEST(soa_get_local_sdp(a, NULL, &answer, &answerlen), 1);
+ TEST_1(answer != NULL && answer != NONE);
+ TEST_1(!strstr(answer, "b=recvonly"));
+ TEST_1(strstr(answer, "m=video"));
+ TEST(soa_set_remote_sdp(b, 0, answer, -1), 1);
+ TEST(soa_process_answer(b, test_completed), 0);
+ TEST(soa_activate(b, NULL), 0);
+
+ TEST(soa_is_audio_active(a), SOA_ACTIVE_SENDRECV);
+ TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_SENDRECV);
+ TEST(soa_is_video_active(a), SOA_ACTIVE_SENDRECV);
+
+ TEST_VOID(soa_terminate(a, NULL));
+
+ TEST(soa_is_audio_active(a), SOA_ACTIVE_DISABLED);
+ TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_DISABLED);
+
+ TEST_VOID(soa_terminate(b, NULL));
+
+ TEST_VOID(soa_destroy(a));
+ TEST_VOID(soa_destroy(b));
+
+ su_home_deinit(home);
+
+ END();
+}
+
+int test_codec_selection(struct context *ctx)
+{
+ BEGIN();
+ int n;
+
+ soa_session_t *a, *b;
+
+ char const *offer = NONE, *answer = NONE;
+ isize_t offerlen = -1, answerlen = -1;
+
+ sdp_session_t const *a_sdp, *b_sdp;
+ sdp_media_t const *m;
+ sdp_rtpmap_t const *rm;
+
+ char const a_caps[] =
+ "v=0\r\n"
+ "o=left 219498671 2 IN IP4 127.0.0.2\r\n"
+ "c=IN IP4 127.0.0.2\r\n"
+ "m=audio 5008 RTP/AVP 0 8 97\r\n"
+ "a=rtpmap:97 GSM/8000\n"
+ ;
+
+ char const b_caps[] =
+ "m=audio 5004 RTP/AVP 96 97\n"
+ "a=rtpmap:96 G7231/8000\n"
+ "a=rtpmap:97 G729/8000\n";
+
+ TEST_1(a = soa_create("static", ctx->root, ctx));
+ TEST_1(b = soa_create("static", ctx->root, ctx));
+
+ TEST(soa_set_user_sdp(a, 0, a_caps, strlen(a_caps)), 1);
+ TEST(soa_set_user_sdp(b, 0, b_caps, strlen(b_caps)), 1);
+
+ TEST(soa_set_params(a, SOATAG_AUDIO_AUX("cn telephone-event"), TAG_END()), 1);
+
+ n = soa_generate_offer(a, 1, test_completed); TEST(n, 0);
+ n = soa_get_local_sdp(a, NULL, &offer, &offerlen); TEST(n, 1);
+ TEST_1(offer != NULL && offer != NONE);
+ n = soa_set_remote_sdp(b, 0, offer, offerlen); TEST(n, 1);
+ n = soa_get_local_sdp(b, NULL, &answer, &answerlen); TEST(n, 0);
+ n = soa_generate_answer(b, test_completed); TEST(n, 0);
+ n = soa_get_local_sdp(b, &b_sdp, &answer, &answerlen); TEST(n, 1);
+ TEST_1(answer != NULL && answer != NONE);
+ n = soa_set_remote_sdp(a, 0, answer, -1); TEST(n, 1);
+ n = soa_process_answer(a, test_completed); TEST(n, 0);
+
+ TEST_1(soa_is_complete(b));
+ TEST(soa_activate(b, NULL), 0);
+
+ TEST_1(soa_is_complete(a));
+ TEST(soa_activate(a, NULL), 0);
+
+ TEST(soa_is_audio_active(a), SOA_ACTIVE_REJECTED);
+ TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_REJECTED);
+
+ TEST_1(m = b_sdp->sdp_media); TEST_1(m->m_rejected);
+ TEST_1(rm = m->m_rtpmaps); TEST(rm->rm_pt, 96);
+ TEST_S(rm->rm_encoding, "G7231");
+ /* Not using payload type 97 from offer */
+ TEST_1(rm = rm->rm_next); TEST(rm->rm_pt, 98);
+ TEST_S(rm->rm_encoding, "G729");
+ TEST_1(!rm->rm_next);
+
+ /* ---------------------------------------------------------------------- */
+
+ /* Re-O/A: A generates new SDP */
+ n = soa_generate_offer(a, 1, test_completed); TEST(n, 0);
+ n = soa_get_local_sdp(a, &a_sdp, &offer, &offerlen); TEST(n, 1);
+ TEST_1(offer != NULL && offer != NONE);
+ n = soa_set_remote_sdp(b, 0, offer, offerlen); TEST(n, 1);
+ n = soa_generate_answer(b, test_completed); TEST(n, 0);
+ n = soa_get_local_sdp(b, &b_sdp, &answer, &answerlen); TEST(n, 1);
+ TEST_1(answer != NULL && answer != NONE);
+ n = soa_set_remote_sdp(a, 0, answer, -1); TEST(n, 0);
+ n = soa_process_answer(a, test_completed); TEST(n, 0);
+
+ TEST_1(soa_is_complete(b));
+ TEST(soa_activate(b, NULL), 0);
+
+ TEST_1(soa_is_complete(a));
+ TEST(soa_activate(a, NULL), 0);
+
+ /* Re-O/A: no-one regenerates new SDP */
+ n = soa_generate_offer(a, 1, test_completed); TEST(n, 0);
+ n = soa_get_local_sdp(a, &a_sdp, &offer, &offerlen); TEST(n, 1);
+ TEST_1(offer != NULL && offer != NONE);
+ n = soa_set_remote_sdp(b, 0, offer, offerlen); TEST(n, 0);
+ n = soa_generate_answer(b, test_completed); TEST(n, 0);
+ n = soa_get_local_sdp(b, &b_sdp, &answer, &answerlen); TEST(n, 1);
+ TEST_1(answer != NULL && answer != NONE);
+ n = soa_set_remote_sdp(a, 0, answer, -1); TEST(n, 0);
+ n = soa_process_answer(a, test_completed); TEST(n, 0);
+
+ TEST_1(soa_is_complete(b));
+ TEST(soa_activate(b, NULL), 0);
+
+ TEST_1(soa_is_complete(a));
+ TEST(soa_activate(a, NULL), 0);
+
+ /* ---------------------------------------------------------------------- */
+
+ /* Re-O/A: accept media without common codecs */
+
+ /* Accept media without common codecs */
+ TEST_1(soa_set_params(a, SOATAG_RTP_MISMATCH(1), TAG_END()));
+ TEST_1(soa_set_params(b, SOATAG_RTP_MISMATCH(1), TAG_END()));
+
+ n = soa_generate_offer(a, 1, test_completed); TEST(n, 0);
+ n = soa_get_local_sdp(a, &a_sdp, &offer, &offerlen); TEST(n, 1);
+ TEST_1(offer != NULL && offer != NONE);
+ n = soa_set_remote_sdp(b, 0, offer, offerlen); TEST(n, 1);
+ n = soa_generate_answer(b, test_completed); TEST(n, 0);
+ n = soa_get_local_sdp(b, &b_sdp, &answer, &answerlen); TEST(n, 1);
+ TEST_1(answer != NULL && answer != NONE);
+ n = soa_set_remote_sdp(a, 0, answer, -1); TEST(n, 1);
+ n = soa_process_answer(a, test_completed); TEST(n, 0);
+
+ TEST_1(soa_is_complete(b));
+ TEST(soa_activate(b, NULL), 0);
+
+ TEST_1(soa_is_complete(a));
+ TEST(soa_activate(a, NULL), 0);
+
+ TEST(soa_is_audio_active(a), SOA_ACTIVE_SENDRECV);
+ TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_SENDRECV);
+
+ TEST_1(m = b_sdp->sdp_media); TEST_1(!m->m_rejected);
+ TEST_1(rm = m->m_rtpmaps); TEST(rm->rm_pt, 96);
+ TEST_S(rm->rm_encoding, "G7231");
+ /* Not using payload type 97 from offer */
+ TEST_1(rm = rm->rm_next); TEST(rm->rm_pt, 98);
+ TEST_S(rm->rm_encoding, "G729");
+ TEST_1(!rm->rm_next);
+
+ /* ---------------------------------------------------------------------- */
+
+ /* Re-O/A: add a common codec */
+
+ /* Accept media without common codecs */
+ TEST_1(soa_set_params(a, SOATAG_RTP_MISMATCH(0),
+ SOATAG_USER_SDP_STR(
+ "v=0\r\n"
+ "o=left 219498671 2 IN IP4 127.0.0.2\r\n"
+ "c=IN IP4 127.0.0.2\r\n"
+ "m=audio 5008 RTP/AVP 0 8 96 3 127\r\n"
+ "a=rtpmap:96 G729/8000\n"
+ "a=rtpmap:127 CN/8000\n"
+ ),
+ SOATAG_RTP_SORT(SOA_RTP_SORT_REMOTE),
+ SOATAG_RTP_SELECT(SOA_RTP_SELECT_ALL),
+ TAG_END()));
+ TEST_1(soa_set_params(b, SOATAG_RTP_MISMATCH(0),
+ SOATAG_USER_SDP_STR(
+ "v=0\r\n"
+ "o=left 219498671 2 IN IP4 127.0.0.2\r\n"
+ "c=IN IP4 127.0.0.2\r\n"
+ "m=audio 5004 RTP/AVP 96 3 97 111\r\n"
+ "a=rtpmap:96 G7231/8000\n"
+ "a=rtpmap:97 G729/8000\n"
+ "a=rtpmap:111 telephone-event/8000\n"
+ "a=fmtp:111 0-15\n"
+ ),
+ SOATAG_AUDIO_AUX("cn telephone-event"),
+ SOATAG_RTP_SORT(SOA_RTP_SORT_LOCAL),
+ SOATAG_RTP_SELECT(SOA_RTP_SELECT_COMMON),
+ TAG_END()));
+
+ n = soa_generate_offer(a, 1, test_completed); TEST(n, 0);
+ n = soa_get_local_sdp(a, &a_sdp, &offer, &offerlen); TEST(n, 1);
+ TEST_1(offer != NULL && offer != NONE);
+ n = soa_set_remote_sdp(b, 0, offer, offerlen); TEST(n, 1);
+ n = soa_generate_answer(b, test_completed); TEST(n, 0);
+ n = soa_get_local_sdp(b, &b_sdp, &answer, &answerlen); TEST(n, 1);
+ TEST_1(answer != NULL && answer != NONE);
+ n = soa_set_remote_sdp(a, 0, answer, -1); TEST(n, 1);
+ n = soa_process_answer(a, test_completed); TEST(n, 0);
+ n = soa_get_local_sdp(a, &a_sdp, NULL, NULL); TEST(n, 1);
+
+ TEST_1(soa_is_complete(b));
+ TEST(soa_activate(b, NULL), 0);
+
+ TEST_1(soa_is_complete(a));
+ TEST(soa_activate(a, NULL), 0);
+
+ TEST(soa_is_audio_active(a), SOA_ACTIVE_SENDRECV);
+ TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_SENDRECV);
+
+ TEST_1(m = a_sdp->sdp_media); TEST_1(!m->m_rejected);
+ TEST_1(rm = m->m_rtpmaps); TEST(rm->rm_pt, 3);
+ TEST_S(rm->rm_encoding, "GSM");
+ TEST_1(rm = rm->rm_next); TEST(rm->rm_pt, 96);
+ TEST_S(rm->rm_encoding, "G729");
+ TEST_1(rm = rm->rm_next); TEST(rm->rm_pt, 0);
+ TEST_S(rm->rm_encoding, "PCMU");
+ TEST_1(rm = rm->rm_next); TEST(rm->rm_pt, 8);
+ TEST_S(rm->rm_encoding, "PCMA");
+ TEST_1(rm = rm->rm_next); TEST(rm->rm_pt, 127);
+ TEST_S(rm->rm_encoding, "CN");
+ TEST_1(!rm->rm_next);
+
+ TEST_1(m = b_sdp->sdp_media); TEST_1(!m->m_rejected);
+ TEST_1(rm = m->m_rtpmaps); TEST(rm->rm_pt, 3);
+ TEST_S(rm->rm_encoding, "GSM");
+ /* Using payload type 96 from offer */
+ TEST_1(rm = rm->rm_next); TEST(rm->rm_pt, 96);
+ TEST_S(rm->rm_encoding, "G729");
+ TEST_1(rm = rm->rm_next); TEST(rm->rm_pt, 111);
+ TEST_S(rm->rm_encoding, "telephone-event");
+ TEST_1(!rm->rm_next);
+
+ /* ---------------------------------------------------------------------- */
+ /* Re-O/A: prune down to single codec. */
+
+ TEST_1(soa_set_params(a,
+ SOATAG_USER_SDP_STR(
+ "v=0\r\n"
+ "o=left 219498671 2 IN IP4 127.0.0.2\r\n"
+ "c=IN IP4 127.0.0.2\r\n"
+ "m=audio 5008 RTP/AVP 0 8 97 96 127\r\n"
+ "a=rtpmap:96 G729/8000\n"
+ "a=rtpmap:97 GSM/8000\n"
+ "a=rtpmap:127 CN/8000\n"
+ ),
+ SOATAG_RTP_MISMATCH(0),
+ SOATAG_RTP_SELECT(SOA_RTP_SELECT_COMMON),
+ TAG_END()));
+ TEST_1(soa_set_params(b,
+ SOATAG_RTP_MISMATCH(0),
+ SOATAG_RTP_SORT(SOA_RTP_SORT_LOCAL),
+ SOATAG_RTP_SELECT(SOA_RTP_SELECT_SINGLE),
+ TAG_END()));
+
+ n = soa_generate_offer(a, 1, test_completed); TEST(n, 0);
+ n = soa_get_local_sdp(a, &a_sdp, &offer, &offerlen); TEST(n, 1);
+ TEST_1(offer != NULL && offer != NONE);
+ n = soa_set_remote_sdp(b, 0, offer, offerlen); TEST(n, 1);
+ n = soa_generate_answer(b, test_completed); TEST(n, 0);
+ n = soa_get_local_sdp(b, &b_sdp, &answer, &answerlen); TEST(n, 1);
+ TEST_1(answer != NULL && answer != NONE);
+ n = soa_set_remote_sdp(a, 0, answer, -1); TEST(n, 1);
+ n = soa_process_answer(a, test_completed); TEST(n, 0);
+ n = soa_get_local_sdp(a, &a_sdp, &offer, &offerlen); TEST(n, 1);
+
+ TEST_1(soa_is_complete(b));
+ TEST(soa_activate(b, NULL), 0);
+
+ TEST_1(soa_is_complete(a));
+ TEST(soa_activate(a, NULL), 0);
+
+ TEST(soa_is_audio_active(a), SOA_ACTIVE_SENDRECV);
+ TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_SENDRECV);
+
+ TEST_1(m = a_sdp->sdp_media); TEST_1(!m->m_rejected);
+ TEST_1(rm = m->m_rtpmaps); TEST(rm->rm_pt, 97);
+ TEST_S(rm->rm_encoding, "GSM");
+ TEST_1(rm = rm->rm_next); TEST(rm->rm_pt, 127);
+ TEST_S(rm->rm_encoding, "CN");
+ TEST_1(!rm->rm_next);
+
+ /* Answering end matches payload types
+ then sorts by local preference,
+ then select best codec => GSM with pt 97 */
+ TEST_1(m = b_sdp->sdp_media); TEST_1(!m->m_rejected);
+ TEST_1(rm = m->m_rtpmaps); TEST(rm->rm_pt, 97);
+ TEST_S(rm->rm_encoding, "GSM");
+ TEST_1(rm = rm->rm_next); TEST(rm->rm_pt, 111);
+ TEST_S(rm->rm_encoding, "telephone-event");
+ TEST_1(!rm->rm_next);
+
+ /* ---------------------------------------------------------------------- */
+ /* Re-O/A: A generates new SDP offer with single codec only */
+ n = soa_generate_offer(a, 1, test_completed); TEST(n, 0);
+ n = soa_get_local_sdp(a, &a_sdp, &offer, &offerlen); TEST(n, 1);
+ TEST_1(offer != NULL && offer != NONE);
+ TEST_1(m = a_sdp->sdp_media); TEST_1(!m->m_rejected);
+ TEST_1(rm = m->m_rtpmaps); TEST(rm->rm_pt, 97);
+ TEST_S(rm->rm_encoding, "GSM");
+ TEST_1(rm = rm->rm_next); TEST(rm->rm_pt, 127);
+ TEST_S(rm->rm_encoding, "CN");
+ TEST_1(!rm->rm_next);
+ n = soa_set_remote_sdp(b, 0, offer, offerlen); TEST(n, 1);
+ /* Answer from B is identical to previous one */
+ n = soa_generate_answer(b, test_completed); TEST(n, 0);
+ n = soa_get_local_sdp(b, &b_sdp, &answer, &answerlen); TEST(n, 1);
+ TEST_1(answer != NULL && answer != NONE);
+ n = soa_set_remote_sdp(a, 0, answer, -1); TEST(n, 0);
+ n = soa_process_answer(a, test_completed); TEST(n, 0);
+
+ TEST_1(soa_is_complete(b));
+ TEST(soa_activate(b, NULL), 0);
+
+ TEST_1(soa_is_complete(a));
+ TEST(soa_activate(a, NULL), 0);
+
+ /* ---------------------------------------------------------------------- */
+
+ /* Add new media - without common codecs */
+ TEST_1(soa_set_params(a,
+ SOATAG_RTP_MISMATCH(0),
+ SOATAG_USER_SDP_STR(
+ "v=0\r\n"
+ "o=left 219498671 2 IN IP4 127.0.0.2\r\n"
+ "c=IN IP4 127.0.0.2\r\n"
+ "m=audio 5008 RTP/AVP 0 8 96 3 127\r\n"
+ "a=rtpmap:96 G729/8000\n"
+ "a=rtpmap:127 CN/8000\n"
+ "m=video 5010 RTP/AVP 31\r\n"
+ "m=audio 6008 RTP/SAVP 3\n"
+ ),
+ TAG_END()));
+ TEST_1(soa_set_params(b,
+ SOATAG_RTP_MISMATCH(0),
+ SOATAG_USER_SDP_STR(
+ "v=0\r\n"
+ "o=left 219498671 2 IN IP4 127.0.0.2\r\n"
+ "c=IN IP4 127.0.0.2\r\n"
+ "m=audio 5004 RTP/AVP 96 3 97 111\r\n"
+ "a=rtpmap:96 G7231/8000\n"
+ "a=rtpmap:97 G729/8000\n"
+ "a=rtpmap:111 telephone-event/8000\n"
+ "a=fmtp:111 0-15\n"
+ "m=audio 6004 RTP/SAVP 96\n"
+ "a=rtpmap:96 G729/8000\n"
+ "m=video 5006 RTP/AVP 34\n"
+ ),
+ TAG_END()));
+
+ n = soa_generate_offer(a, 1, test_completed); TEST(n, 0);
+ n = soa_get_local_sdp(a, &a_sdp, &offer, &offerlen); TEST(n, 1);
+ TEST_1(offer != NULL && offer != NONE);
+ TEST_1(m = a_sdp->sdp_media); TEST_1(!m->m_rejected);
+ TEST_1(m = m->m_next); TEST_1(!m->m_rejected);
+ TEST_1(m = m->m_next); TEST_1(!m->m_rejected);
+ TEST_1(!m->m_next);
+ n = soa_set_remote_sdp(b, 0, offer, offerlen); TEST(n, 1);
+ n = soa_generate_answer(b, test_completed); TEST(n, 0);
+ /* Answer from B rejects video */
+ n = soa_get_local_sdp(b, &b_sdp, &answer, &answerlen); TEST(n, 1);
+ TEST_1(answer != NULL && answer != NONE);
+ n = soa_set_remote_sdp(a, 0, answer, -1); TEST(n, 1);
+ n = soa_process_answer(a, test_completed); TEST(n, 0);
+ n = soa_get_local_sdp(a, &a_sdp, &offer, &offerlen); TEST(n, 1);
+
+ TEST_1(soa_is_complete(b));
+ TEST(soa_activate(b, NULL), 0);
+
+ TEST_1(soa_is_complete(a));
+ TEST(soa_activate(a, NULL), 0);
+
+ TEST(soa_is_audio_active(a), SOA_ACTIVE_SENDRECV);
+ TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_SENDRECV);
+ TEST(soa_is_video_active(a), SOA_ACTIVE_REJECTED);
+ TEST(soa_is_remote_video_active(a), SOA_ACTIVE_REJECTED);
+
+ TEST_1(m = a_sdp->sdp_media); TEST_1(!m->m_rejected);
+ TEST_1(m = m->m_next); TEST_1(m->m_rejected);
+ TEST_1(m = m->m_next); TEST_1(m->m_rejected);
+ TEST_1(!m->m_next);
+
+ TEST_1(m = b_sdp->sdp_media); TEST_1(!m->m_rejected);
+ TEST_1(m = m->m_next); TEST_1(m->m_rejected);
+ /* Rejected but tell what we support */
+ TEST_1(rm = m->m_rtpmaps); TEST(rm->rm_pt, 34);
+ TEST_S(rm->rm_encoding, "H263");
+ TEST_1(m = m->m_next); TEST_1(m->m_rejected);
+ TEST_1(!m->m_next);
+
+ /* ---------------------------------------------------------------------- */
+ /* A adds H.263 to video */
+ TEST_1(soa_set_params(a,
+ SOATAG_USER_SDP_STR(
+ "v=0\r\n"
+ "o=left 219498671 2 IN IP4 127.0.0.2\r\n"
+ "c=IN IP4 127.0.0.2\r\n"
+ "m=audio 5008 RTP/AVP 0 8 96 3 127\r\n"
+ "a=rtpmap:96 G729/8000\n"
+ "a=rtpmap:127 CN/8000\n"
+ "m=video 5010 RTP/AVP 31 34\r\n"
+ "m=audio 6008 RTP/SAVP 3\n"
+ ),
+ TAG_END()));
+
+ /* B adds GSM to SRTP */
+ TEST_1(soa_set_params(b,
+ SOATAG_USER_SDP_STR(
+ "v=0\r\n"
+ "o=left 219498671 2 IN IP4 127.0.0.2\r\n"
+ "c=IN IP4 127.0.0.2\r\n"
+ "m=audio 5004 RTP/AVP 96 3 97 111\r\n"
+ "a=rtpmap:96 G7231/8000\n"
+ "a=rtpmap:97 G729/8000\n"
+ "a=rtpmap:111 telephone-event/8000\n"
+ "a=fmtp:111 0-15\n"
+ "m=audio 6004 RTP/SAVP 96 3\n"
+ "a=rtpmap:96 G729/8000\n"
+ "m=video 5006 RTP/AVP 34\n"
+ ),
+ TAG_END()));
+
+ n = soa_generate_offer(a, 1, test_completed); TEST(n, 0);
+ n = soa_get_local_sdp(a, &a_sdp, &offer, &offerlen); TEST(n, 1);
+ TEST_1(offer != NULL && offer != NONE);
+ TEST_1(m = a_sdp->sdp_media); TEST_1(!m->m_rejected);
+ TEST_1(m = m->m_next); TEST_1(!m->m_rejected);
+ TEST_1(m = m->m_next); TEST_1(!m->m_rejected);
+ TEST_1(!m->m_next);
+ n = soa_set_remote_sdp(b, 0, offer, offerlen); TEST(n, 1);
+ n = soa_generate_answer(b, test_completed); TEST(n, 0);
+ /* Answer from B now accepts video */
+ n = soa_get_local_sdp(b, &b_sdp, &answer, &answerlen); TEST(n, 1);
+ TEST_1(answer != NULL && answer != NONE);
+ n = soa_set_remote_sdp(a, 0, answer, -1); TEST(n, 1);
+ n = soa_process_answer(a, test_completed); TEST(n, 0);
+ n = soa_get_local_sdp(a, &a_sdp, &offer, &offerlen); TEST(n, 1);
+
+ TEST_1(soa_is_complete(b));
+ TEST(soa_activate(b, NULL), 0);
+
+ TEST_1(soa_is_complete(a));
+ TEST(soa_activate(a, NULL), 0);
+
+ TEST(soa_is_audio_active(a), SOA_ACTIVE_SENDRECV);
+ TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_SENDRECV);
+ TEST(soa_is_video_active(a), SOA_ACTIVE_SENDRECV);
+ TEST(soa_is_remote_video_active(a), SOA_ACTIVE_SENDRECV);
+
+ TEST_1(m = a_sdp->sdp_media); TEST_1(!m->m_rejected);
+ TEST_1(m = m->m_next); TEST_1(!m->m_rejected);
+ TEST_1(rm = m->m_rtpmaps); TEST(rm->rm_pt, 34);
+ TEST_S(rm->rm_encoding, "H263");
+ TEST_1(m = m->m_next); TEST_1(!m->m_rejected);
+ TEST_1(!m->m_next);
+
+ TEST_1(m = b_sdp->sdp_media); TEST_1(!m->m_rejected);
+ TEST_1(m = m->m_next); TEST_1(!m->m_rejected);
+ TEST_1(rm = m->m_rtpmaps); TEST(rm->rm_pt, 34);
+ TEST_S(rm->rm_encoding, "H263");
+ TEST_1(m = m->m_next); TEST_1(!m->m_rejected);
+ TEST_1(!m->m_next);
+
+ /* ---------------------------------------------------------------------- */
+ /* A drops GSM support */
+
+ TEST_1(soa_set_params(a,
+ SOATAG_USER_SDP_STR(
+ "v=0\r\n"
+ "o=left 219498671 2 IN IP4 127.0.0.2\r\n"
+ "c=IN IP4 127.0.0.2\r\n"
+ "m=audio 5008 RTP/AVP 0 8 96 127\r\n"
+ "a=rtpmap:96 G729/8000\n"
+ "a=rtpmap:127 CN/8000\n"
+ "m=video 5010 RTP/AVP 31 34\r\n"
+ "m=audio 6008 RTP/SAVP 3\n"
+ ),
+ TAG_END()));
+
+ /* B adds GSM to SRTP, changes IP address */
+ TEST_1(soa_set_params(b,
+ SOATAG_USER_SDP_STR(
+ "v=0\r\n"
+ "o=left 219498671 2 IN IP4 127.0.0.2\r\n"
+ "c=IN IP4 127.0.0.3\r\n"
+ "m=audio 5004 RTP/AVP 96 3 97 111\r\n"
+ "a=rtpmap:96 G7231/8000\n"
+ "a=rtpmap:97 G729/8000\n"
+ "a=rtpmap:111 telephone-event/8000\n"
+ "a=fmtp:111 0-15\n"
+ "m=audio 6004 RTP/SAVP 96 3\n"
+ "a=rtpmap:96 G729/8000\n"
+ "m=video 5006 RTP/AVP 34\n"
+ ),
+ TAG_END()));
+
+ n = soa_generate_offer(a, 1, test_completed); TEST(n, 0);
+ n = soa_get_local_sdp(a, &a_sdp, &offer, &offerlen); TEST(n, 1);
+ TEST_1(offer != NULL && offer != NONE);
+ TEST_1(m = a_sdp->sdp_media); TEST_1(!m->m_rejected);
+ TEST_1(m = m->m_next); TEST_1(!m->m_rejected);
+ TEST_1(m = m->m_next); TEST_1(!m->m_rejected);
+ TEST_1(!m->m_next);
+ n = soa_set_remote_sdp(b, 0, offer, offerlen); TEST(n, 1);
+ n = soa_generate_answer(b, test_completed); TEST(n, 0);
+ /* Answer from B now accepts video */
+ n = soa_get_local_sdp(b, &b_sdp, &answer, &answerlen); TEST(n, 1);
+ TEST_1(answer != NULL && answer != NONE);
+ /* Check that updated c= line is propagated */
+ TEST_1(b_sdp->sdp_connection);
+ TEST_S(b_sdp->sdp_connection->c_address, "127.0.0.3");
+ n = soa_set_remote_sdp(a, 0, answer, -1); TEST(n, 1);
+ n = soa_process_answer(a, test_completed); TEST(n, 0);
+ n = soa_get_local_sdp(a, &a_sdp, &offer, &offerlen); TEST(n, 1);
+
+ TEST_1(soa_is_complete(b));
+ TEST(soa_activate(b, NULL), 0);
+
+ TEST_1(soa_is_complete(a));
+ TEST(soa_activate(a, NULL), 0);
+
+ TEST(soa_is_audio_active(a), SOA_ACTIVE_SENDRECV);
+ TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_SENDRECV);
+ TEST(soa_is_video_active(a), SOA_ACTIVE_SENDRECV);
+ TEST(soa_is_remote_video_active(a), SOA_ACTIVE_SENDRECV);
+
+ TEST_1(m = a_sdp->sdp_media); TEST_1(!m->m_rejected);
+ TEST_1(rm = m->m_rtpmaps); TEST(rm->rm_pt, 96);
+ TEST_S(rm->rm_encoding, "G729");
+ TEST_1(rm = rm->rm_next); TEST(rm->rm_pt, 127);
+ TEST_S(rm->rm_encoding, "CN");
+ TEST_1(m = m->m_next); TEST_1(!m->m_rejected);
+ TEST_1(rm = m->m_rtpmaps); TEST(rm->rm_pt, 34);
+ TEST_S(rm->rm_encoding, "H263");
+ TEST_1(m = m->m_next); TEST_1(!m->m_rejected);
+ TEST_1(!m->m_next);
+
+ TEST_1(m = b_sdp->sdp_media); TEST_1(!m->m_rejected);
+ TEST_1(rm = m->m_rtpmaps); TEST(rm->rm_pt, 96);
+ TEST_S(rm->rm_encoding, "G729");
+ TEST_1(rm = rm->rm_next); TEST(rm->rm_pt, 111);
+ TEST_S(rm->rm_encoding, "telephone-event");
+ TEST_1(m = m->m_next); TEST_1(!m->m_rejected);
+ TEST_1(rm = m->m_rtpmaps); TEST(rm->rm_pt, 34);
+ TEST_S(rm->rm_encoding, "H263");
+ TEST_1(m = m->m_next); TEST_1(!m->m_rejected);
+ TEST_1(!m->m_next);
+
+ /* ---------------------------------------------------------------------- */
+
+ TEST_VOID(soa_terminate(a, NULL));
+ TEST_VOID(soa_terminate(b, NULL));
+
+ TEST_VOID(soa_destroy(a));
+ TEST_VOID(soa_destroy(b));
+
+ END();
+}
+
+
+int test_asynch_offer_answer(struct context *ctx)
+{
+ BEGIN();
+
+#if 0
+ int n;
+
+ char const *caps = NONE, *offer = NONE, *answer = NONE;
+ isize_t capslen = -1, offerlen = -1, answerlen = -1;
+
+ char const a[] =
+ "v=0\r\n"
+ "o=left 219498671 2 IN IP4 127.0.0.2\r\n"
+ "c=IN IP4 127.0.0.2\r\n"
+ "m=audio 5004 RTP/AVP 0 8\r\n";
+
+ char const b[] =
+ "v=0\n"
+ "o=right 93298573265 321974 IN IP4 127.0.0.3\n"
+ "c=IN IP4 127.0.0.3\n"
+ "m=audio 5006 RTP/AVP 96\n"
+ "m=rtpmap:96 GSM/8000\n";
+
+ n = soa_set_capability_sdp(ctx->asynch.a, 0,
+ "m=audio 5004 RTP/AVP 0 8", -1);
+ TEST(n, 1);
+
+ n = soa_set_capability_sdp(ctx->asynch.a, 0, a, strlen(a)); TEST(n, 1);
+ n = soa_get_capability_sdp(ctx->asynch.a, 0, &caps, &capslen); TEST(n, 1);
+
+ TEST_1(caps != NULL && caps != NONE);
+ TEST_1(capslen > 0);
+
+ n = soa_set_capability_sdp(ctx->asynch.b, 0, b, strlen(b)); TEST(n, 1);
+
+ n = soa_generate_offer(ctx->asynch.a, 1, test_completed); TEST(n, 1);
+
+ su_root_run(ctx->root); TEST(ctx->completed, ctx->asynch.a);
+ ctx->completed = NULL;
+
+ n = soa_get_local_sdp(ctx->asynch.a, 0, &offer, &offerlen); TEST(n, 1);
+
+ n = soa_set_remote_sdp(ctx->asynch.b, 0, offer, offerlen); TEST(n, 1);
+
+ n = soa_generate_answer(ctx->asynch.b, test_completed); TEST(n, 1);
+
+ su_root_run(ctx->root); TEST(ctx->completed, ctx->asynch.b);
+ ctx->completed = NULL;
+
+ TEST_1(soa_is_complete(ctx->asynch.b));
+ TEST(soa_activate(ctx->asynch.b, NULL), 0);
+
+ n = soa_get_local_sdp(ctx->asynch.b, 0, &answer, &answerlen); TEST(n, 1);
+
+ n = soa_set_remote_sdp(ctx->asynch.a, 0, answer, answerlen); TEST(n, 1);
+
+ n = soa_process_answer(ctx->asynch.a, test_completed); TEST(n, 1);
+
+ su_root_run(ctx->root); TEST(ctx->completed, ctx->asynch.a);
+ ctx->completed = NULL;
+
+ TEST_1(soa_is_complete(ctx->asynch.a));
+ TEST(soa_activate(ctx->asynch.a, NULL), 0);
+
+ TEST(soa_is_audio_active(ctx->asynch.a), SOA_ACTIVE_SENDRECV);
+ TEST(soa_is_video_active(ctx->asynch.a), SOA_ACTIVE_DISABLED);
+ TEST(soa_is_image_active(ctx->asynch.a), SOA_ACTIVE_DISABLED);
+ TEST(soa_is_chat_active(ctx->asynch.a), SOA_ACTIVE_DISABLED);
+
+ TEST(soa_is_remote_audio_active(ctx->asynch.a), SOA_ACTIVE_SENDRECV);
+ TEST(soa_is_remote_video_active(ctx->asynch.a), SOA_ACTIVE_DISABLED);
+ TEST(soa_is_remote_image_active(ctx->asynch.a), SOA_ACTIVE_DISABLED);
+ TEST(soa_is_remote_chat_active(ctx->asynch.a), SOA_ACTIVE_DISABLED);
+
+ TEST(soa_deactivate(ctx->asynch.a, NULL), 0);
+ TEST(soa_deactivate(ctx->asynch.b, NULL), 0);
+
+ TEST_VOID(soa_terminate(ctx->asynch.a, NULL));
+
+ TEST(soa_is_audio_active(ctx->asynch.a), SOA_ACTIVE_DISABLED);
+ TEST(soa_is_remote_audio_active(ctx->asynch.a), SOA_ACTIVE_DISABLED);
+
+ TEST_VOID(soa_terminate(ctx->asynch.b, NULL));
+
+#endif
+
+ END();
+}
+
+int test_deinit(struct context *ctx)
+{
+ BEGIN();
+ END();
+}
+
+#if HAVE_ALARM
+static RETSIGTYPE sig_alarm(int s)
+{
+ fprintf(stderr, "%s: FAIL! test timeout!\n", name);
+ exit(1);
+}
+#endif
+
+void usage(void)
+{
+ fprintf(stderr,
+ "usage: %s [-v|-q] [-l level] [-p outbound-proxy-uri]\n",
+ name);
+ exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+ int retval = 0, quit_on_single_failure = 0;
+ int i, o_attach = 0, o_alarm = 1;
+
+ struct context ctx[1] = {{{ SU_HOME_INIT(ctx) }}};
+
+ for (i = 1; argv[i]; i++) {
+ if (strcmp(argv[i], "-v") == 0)
+ tstflags |= tst_verbatim;
+ else if (strcmp(argv[i], "-q") == 0)
+ tstflags &= ~tst_verbatim;
+ else if (strcmp(argv[i], "-1") == 0)
+ quit_on_single_failure = 1;
+ else if (strncmp(argv[i], "-l", 2) == 0) {
+ int level = 3;
+ char *rest = NULL;
+
+ if (argv[i][2])
+ level = strtol(argv[i] + 2, &rest, 10);
+ else if (argv[i + 1])
+ level = strtol(argv[i + 1], &rest, 10), i++;
+ else
+ level = 3, rest = "";
+
+ if (rest == NULL || *rest)
+ usage();
+
+ su_log_set_level(soa_log, level);
+ }
+ else if (strcmp(argv[i], "--attach") == 0) {
+ o_attach = 1;
+ }
+ else if (strcmp(argv[i], "--no-alarm") == 0) {
+ o_alarm = 0;
+ }
+ else if (strcmp(argv[i], "-") == 0) {
+ i++; break;
+ }
+ else if (argv[i][0] != '-') {
+ break;
+ }
+ else
+ usage();
+ }
+
+ if (o_attach) {
+ char line[10];
+ printf("%s: pid %u\n", name, getpid());
+ printf("<Press RETURN to continue>\n");
+ fgets(line, sizeof line, stdin);
+ }
+#if HAVE_ALARM
+ else if (o_alarm) {
+ alarm(60);
+ signal(SIGALRM, sig_alarm);
+ }
+#endif
+
+ su_init();
+
+ if (!(TSTFLAGS & tst_verbatim)) {
+ su_log_soft_set_level(soa_log, 0);
+ }
+
+#define SINGLE_FAILURE_CHECK() \
+ do { fflush(stdout); \
+ if (retval && quit_on_single_failure) { su_deinit(); return retval; } \
+ } while(0)
+
+ retval |= test_api_errors(ctx); SINGLE_FAILURE_CHECK();
+ retval |= test_soa_tags(ctx); SINGLE_FAILURE_CHECK();
+ retval |= test_init(ctx, argv + i); SINGLE_FAILURE_CHECK();
+ if (retval == 0) {
+ retval |= test_params(ctx); SINGLE_FAILURE_CHECK();
+ retval |= test_static_offer_answer(ctx); SINGLE_FAILURE_CHECK();
+ retval |= test_codec_selection(ctx); SINGLE_FAILURE_CHECK();
+
+ retval |= test_asynch_offer_answer(ctx); SINGLE_FAILURE_CHECK();
+ }
+ retval |= test_deinit(ctx); SINGLE_FAILURE_CHECK();
+
+ su_deinit();
+
+ return retval;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sofia.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sofia.am Thu Dec 21 01:30:28 2006
@@ -0,0 +1,53 @@
+# common Makefile targets for libsofia-sip-ua modules
+# ---------------------------------------------------
+
+AM_CFLAGS = $(CWFLAG) $(SOFIA_CFLAGS)
+
+built-sources: $(BUILT_SOURCES)
+
+DISTCLEANFILES = $(BUILT_SOURCES)
+
+clean-built-sources:
+ -rm -rf $(BUILT_SOURCES) $(BUILT_SOURCES:%=$(srcdir)/%)
+
+# rules for building tag files
+
+TAG_AWK=$(top_srcdir)/libsofia-sip-ua/su/tag_dll.awk
+
+*_tag_ref.c: $(TAG_AWK)
+
+%_tag_ref.c: %_tag.c
+ $(AWK) -f $(TAG_AWK) NODLL=1 $(TAG_DLL_FLAGS) $<
+
+if ENABLE_COVERAGE
+coverage:
+ @$(top_srcdir)/scripts/coverage $(COVERAGE_FLAGS) $(COVERAGE_INPUT)
+endif
+
+../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)
+
+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
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/127.zone
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/127.zone Thu Dec 21 01:30:28 2006
@@ -0,0 +1,13 @@
+$TTL 86400
+@ IN SOA localhost. root.localhost (
+ 1 ; serial
+ 28800 ; refresh
+ 7200 ; retry
+ 604800 ; expire
+ 86400 ; ttk
+ )
+
+
+@ IN NS localhost.
+
+1 IN PTR localhost.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/194.2.188
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/194.2.188 Thu Dec 21 01:30:28 2006
@@ -0,0 +1,14 @@
+$ORIGIN 188.2.194.in-addr.arpa.
+$TTL 60
+@ IN SOA ns root (
+ 2002042901 ; SERIAL
+ 7200 ; REFRESH
+ 600 ; RETRY
+ 36000000 ; EXPIRE
+ 120 ; MINIMUM
+ )
+
+ NS ns.example.com.
+
+133 PTR sip00.example.com.
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/3.f.f.e.1.2.0.0.3.0.1.2.c.0.0.0
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/3.f.f.e.1.2.0.0.3.0.1.2.c.0.0.0 Thu Dec 21 01:30:28 2006
@@ -0,0 +1,13 @@
+$ORIGIN 0.0.0.c.2.1.0.3.0.0.2.1.e.f.f.3.ip6.int.
+$TTL 60
+@ IN SOA ns root (
+ 2002042901 ; SERIAL
+ 7200 ; REFRESH
+ 600 ; RETRY
+ 36000000 ; EXPIRE
+ 120 ; MINIMUM
+ )
+
+ NS ns.example.com.
+
+c.a.7.e.d.7.e.f.f.f.0.2.8.0.a.0 PTR sip01.example.com.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/3.f.f.e.1.2.0.0.3.0.1.2.c.0.0.0.arpa
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/3.f.f.e.1.2.0.0.3.0.1.2.c.0.0.0.arpa Thu Dec 21 01:30:28 2006
@@ -0,0 +1,13 @@
+$ORIGIN 0.0.0.c.2.1.0.3.0.0.2.1.e.f.f.3.ip6.arpa.
+$TTL 60
+@ IN SOA ns root (
+ 2002042901 ; SERIAL
+ 7200 ; REFRESH
+ 600 ; RETRY
+ 36000000 ; EXPIRE
+ 120 ; MINIMUM
+ )
+
+ NS ns.example.com.
+
+c.a.7.e.d.7.e.f.f.f.0.2.8.0.a.0 PTR sip01.example.com.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/ChangeLog Thu Dec 21 01:30:28 2006
@@ -0,0 +1,10 @@
+2006-05-03 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * sres.c: Added win32 registry name server discovery. Based on a
+ patch from Dimitri E. Prado.
+
+ * sres.c: Decreased update interval to 180secs (SRES_UPDATE_INTERVAL_SECS).
+
+2005-07-18 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * Initial import of the module to Sofia-SIP tree.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/Doxyfile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/Doxyfile Thu Dec 21 01:30:28 2006
@@ -0,0 +1,13 @@
+PROJECT_NAME = "sresolv"
+OUTPUT_DIRECTORY = ../docs/html/sresolv
+
+INPUT = sofia-sip sofia-resolv sresolv.docs .
+
+ at INCLUDE = ../docs/Doxyfile.conf
+
+ALIASES += CFILE="@internal @file" IFILE="@internal @file"
+
+TAGFILES += ../docs/su.doxytags=../su
+GENERATE_TAGFILE = ../docs/sresolv.doxytags
+
+PREDEFINED += SRES_CONTEXT_T="struct sres_context_s"
\ No newline at end of file
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/Makefile.am Thu Dec 21 01:30:28 2006
@@ -0,0 +1,64 @@
+#
+# Makefile.am for sresolv module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at 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 = libsresolv.la
+
+check_PROGRAMS = test_sresolv
+
+TESTS = run_test_sresolv
+
+TESTS_ENVIRONMENT = $(SHELL)
+
+CLEANFILES = resolv.conf error.conf named.conf.tmp \
+ .test_sresolv.api.conf.?????? \
+ named.run
+
+LDADD = ../url/liburl.la ../bnf/libbnf.la \
+ libsresolv.la \
+ ../su/libsu.la
+
+test_sresolv_LDFLAGS = -static
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+
+nobase_include_sofia_HEADERS = \
+ sofia-sip/sresolv.h \
+ sofia-resolv/sres.h \
+ sofia-resolv/sres_config.h \
+ sofia-resolv/sres_async.h \
+ sofia-resolv/sres_cache.h \
+ sofia-resolv/sres_record.h
+
+libsresolv_la_SOURCES = sres.c sres_cache.c sres_blocking.c sresolv.c
+
+COVERAGE_INPUT = $(libsresolv_la_SOURCES) $(include_sofia_HEADERS)
+
+# ----------------------------------------------------------------------
+# Distribution
+
+EXTRA_DIST = Doxyfile sresolv.docs
+
+dist_noinst_DATA = run_test_sresolv \
+ root.zone rndc.conf \
+ 127.zone 194.2.188 3.f.f.e.1.2.0.0.3.0.1.2.c.0.0.0 example.com \
+ 3.f.f.e.1.2.0.0.3.0.1.2.c.0.0.0.arpa
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+
+include ../sofia.am
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/Makefile.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1,713 @@
+# 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.
+
+ at SET_MAKE@
+
+#
+# Makefile.am for sresolv module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+# common Makefile targets for libsofia-sip-ua modules
+# ---------------------------------------------------
+
+
+
+SOURCES = $(libsresolv_la_SOURCES) test_sresolv.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 = test_sresolv$(EXEEXT)
+DIST_COMMON = $(dist_noinst_DATA) $(nobase_include_sofia_HEADERS) \
+ $(srcdir)/../sofia.am $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in ChangeLog
+subdir = libsofia-sip-ua/sresolv
+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 =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libsresolv_la_LIBADD =
+am_libsresolv_la_OBJECTS = sres.lo sres_cache.lo sres_blocking.lo \
+ sresolv.lo
+libsresolv_la_OBJECTS = $(am_libsresolv_la_OBJECTS)
+test_sresolv_SOURCES = test_sresolv.c
+test_sresolv_OBJECTS = test_sresolv.$(OBJEXT)
+test_sresolv_LDADD = $(LDADD)
+test_sresolv_DEPENDENCIES = ../url/liburl.la ../bnf/libbnf.la \
+ libsresolv.la ../su/libsu.la
+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 = $(libsresolv_la_SOURCES) test_sresolv.c
+DIST_SOURCES = $(libsresolv_la_SOURCES) test_sresolv.c
+DATA = $(dist_noinst_DATA)
+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|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(include_sofiadir)"
+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 = $(SHELL)
+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 = libsresolv.la
+TESTS = run_test_sresolv
+CLEANFILES = resolv.conf error.conf named.conf.tmp \
+ .test_sresolv.api.conf.?????? \
+ named.run
+
+LDADD = ../url/liburl.la ../bnf/libbnf.la \
+ libsresolv.la \
+ ../su/libsu.la
+
+test_sresolv_LDFLAGS = -static
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+nobase_include_sofia_HEADERS = \
+ sofia-sip/sresolv.h \
+ sofia-resolv/sres.h \
+ sofia-resolv/sres_config.h \
+ sofia-resolv/sres_async.h \
+ sofia-resolv/sres_cache.h \
+ sofia-resolv/sres_record.h
+
+libsresolv_la_SOURCES = sres.c sres_cache.c sres_blocking.c sresolv.c
+COVERAGE_INPUT = $(libsresolv_la_SOURCES) $(include_sofia_HEADERS)
+
+# ----------------------------------------------------------------------
+# Distribution
+EXTRA_DIST = Doxyfile sresolv.docs
+dist_noinst_DATA = run_test_sresolv \
+ root.zone rndc.conf \
+ 127.zone 194.2.188 3.f.f.e.1.2.0.0.3.0.1.2.c.0.0.0 example.com \
+ 3.f.f.e.1.2.0.0.3.0.1.2.c.0.0.0.arpa
+
+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
+
+all: 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/sresolv/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu libsofia-sip-ua/sresolv/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-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
+libsresolv.la: $(libsresolv_la_OBJECTS) $(libsresolv_la_DEPENDENCIES)
+ $(LINK) $(libsresolv_la_LDFLAGS) $(libsresolv_la_OBJECTS) $(libsresolv_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
+test_sresolv$(EXEEXT): $(test_sresolv_OBJECTS) $(test_sresolv_DEPENDENCIES)
+ @rm -f test_sresolv$(EXEEXT)
+ $(LINK) $(test_sresolv_LDFLAGS) $(test_sresolv_OBJECTS) $(test_sresolv_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sres.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sres_blocking.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sres_cache.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sresolv.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_sresolv.Po at am__quote@
+
+.c.o:
+ at am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+ at am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ at am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at 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-resolv $(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: check-am
+all-am: Makefile $(LTLIBRARIES) $(DATA) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(include_sofiadir)"; do \
+ test -z "$$dir" || $(mkdir_p) "$$dir"; \
+ done
+install: 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:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+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."
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+ 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-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-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-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-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-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) $<
+
+ at ENABLE_COVERAGE_TRUE@coverage:
+ at 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)
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+# 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:
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/example.com
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/example.com Thu Dec 21 01:30:28 2006
@@ -0,0 +1,88 @@
+;
+; Zone file for example.com
+;
+$TTL 60
+@ IN SOA ns root (
+ 2002042901 ; SERIAL
+ 7200 ; REFRESH
+ 600 ; RETRY
+ 36000000 ; EXPIRE
+ 60 ; MINIMUM
+ )
+ NS ns.example.com.
+ ;; order pref flags service regexp replacement
+ NAPTR 20 50 "s" "SIPS+D2T" "" _sips._tcp
+ NAPTR 80 25 "s" "SIP+D2T" "" _sip._tcp
+ NAPTR 40 15 "s" "SIP+D2U" "" _sip._udp
+ NAPTR 50 15 "u" "TEST+D2U" "/(tst:([^@]+@))?example.com$/\\1operator.com/i" .
+ MX 10 mgw00
+ MX 10 mgw01
+ MX 10 mgw02
+ MX 100 smtp.example.net.
+ TXT foobar
+
+ns A 127.0.0.2
+ AAAA ::2
+ A6 0 ::2
+
+oldns A 194.2.188.133
+ A6 0 3ffe:1200:3012:c000:210:a4ff:fe8d:6a46
+
+_sip._udp SRV 1 100 5060 sip00
+ SRV 1 100 5060 sip01
+ SRV 1 50 5060 sip02
+_sips._tcp SRV 3 100 5061 sip00
+ SRV 5 10 5060 sip01
+ SRV 4 50 5050 sip02
+_sip._tcp SRV 2 100 5060 sip00
+ SRV 2 100 5060 sip01
+ SRV 2 50 5060 sip02
+
+_sips._udp SRV 3 100 5061 sip00
+ SRV 4 50 5051 sip02
+ SRV 5 10 5061 sip01
+
+sip CNAME sip00
+
+subnet A6 0 3ff0:0::
+labnet A6 23 0:12:3012:: subnet
+sublab A6 48 0:0:0:c006:: labnet
+mynet A6 56 0:0:0:c006:: sublab
+a6 A6 64 ::0a08:20ff:fe7d:e7ac mynet
+alias6 A6 128 a6
+full A6 0 3ff0:12:3012:c006:0a08:20ff:fe7d:e7ac
+
+sip00 A 194.2.188.133
+ AAAA 3ff0:0010:3012:c000:02c0:95ff:fee2:4b78
+
+sip01 A 194.2.188.134
+ AAAA 3ff0:0012:3012:c006:0a08:20ff:fe7d:e7ac
+
+sip02 A 194.2.188.135
+ AAAA 3ffe:1200:3012:c006:0206:5bff:fe55:462f
+
+sip03 A 194.2.188.136
+ AAAA 3ffe:1200:3012:c000:0206:5bff:fe55:4630
+
+mgw00 A 194.2.188.130
+ AAAA 3ffe:1200:3012:c000:02c0:95ff:fee2:4b78
+
+mgw01 A 194.2.188.131
+ AAAA 3ffe:1200:3012:c000:0a08:20ff:fe7d:e7ac
+
+mgw02 A 194.2.188.132
+ AAAA 3ffe:1200:3012:c000:0206:5bff:fe55:462f
+
+a A 194.2.188.137
+aaaa AAAA 3ffe:1200:3012:c000:0206:5bff:fe55:462f
+
+$ORIGIN iptel
+@ A 194.2.188.133
+ AAAA 3ffe:1200:3012:c000:200:5eff:fe00:106
+ NAPTR 50 50 "s" "SIPS+D2T" "" _sips._tcp.iptel
+ NAPTR 90 50 "s" "SIP+D2T" "" _sip._tcp.iptel
+ NAPTR 80 50 "s" "SIP+D2U" "" _sip._udp.iptel
+
+_sip._udp SRV 0 100 5060 iptel
+_sip._tcp SRV 1 100 5060 iptel
+_sips._tcp SRV 1 100 5061 iptel
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/named.conf
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/named.conf Thu Dec 21 01:30:28 2006
@@ -0,0 +1,33 @@
+options {
+ pid-file "/tmp/named.pid";
+};
+
+zone "example.com" in {
+ type master;
+ file "example.com";
+};
+
+zone "." in {
+ type master;
+ file "root.zone";
+};
+
+zone "188.2.194.in-addr.arpa" in {
+ type master;
+ file "194.2.188";
+};
+
+zone "0.0.127.in-addr.arpa" in {
+ type master;
+ file "127.zone";
+};
+
+zone "0.0.0.c.2.1.0.3.0.0.2.1.e.f.f.3.ip6.int" in {
+ type master;
+ file "3.f.f.e.1.2.0.0.3.0.1.2.c.0.0.0";
+};
+
+zone "0.0.0.c.2.1.0.3.0.0.2.1.e.f.f.3.ip6.arpa" in {
+ type master;
+ file "3.f.f.e.1.2.0.0.3.0.1.2.c.0.0.0.arpa";
+};
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/resolv_timeout.conf
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/resolv_timeout.conf Thu Dec 21 01:30:28 2006
@@ -0,0 +1,5 @@
+foo bar foobar
+nameserver 137.0.0.1
+nameserver 182.21.40.170
+#nameserver 127.0.0.1
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/resolve_sip.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/resolve_sip.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,321 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@file resolve_sip.c Use sresolv library to resolve a SIP or SIPS domain.
+ *
+ * This is an example program for @b sresolv library.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @par Created: Tue Jul 16 18:50:14 2002 ppessi
+ *
+ *
+ */
+
+#include <stdint.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+/* Typesafe */
+#define SRES_CONTEXT_T struct context
+
+#include "sofia-sip/sresolv.h"
+
+char const name[] = "sip_resolve";
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <poll.h>
+
+enum progress {
+ querying_naptr,
+ querying_srv,
+ querying_cname,
+ querying_a6,
+ querying_aaaa,
+ querying_a
+};
+
+/* Application context */
+struct context
+{
+ sres_resolver_t *sres;
+ int sr_exitcode;
+ int sr_ready;
+
+ char const *sr_canon;
+ int sr_sips;
+ char const *sr_tport;
+
+ sres_query_t *sr_query;
+ unsigned short sr_port;
+
+ int sr_n_sockets;
+ sres_socket_t *sr_sockets;
+ struct pollfd *sr_pollfds;
+
+#if 0
+ char const *sr_domain;
+
+ enum progress sr_progress;
+ sres_naptr_record_t *sr_naptr;
+ sres_srv_record_t *sr_srv;
+ sres_cname_record_t *sr_cname;
+ sres_aaaa_record_t *sr_aaaa;
+ sres_a6_record_t *sr_a6;
+ sres_a_record_t *sr_a;
+#endif
+};
+
+static int query_srv(struct context *sr, char const *domain);
+static int query_a(struct context *sr, char const *domain);
+
+/* Process NAPTR records */
+static
+void answer_to_naptr_query(sres_context_t *sr,
+ sres_query_t *q,
+ sres_record_t *answers[])
+{
+ int i;
+
+ sr->sr_query = NULL;
+
+ /* Sort NAPTR records by the order. */
+ sres_sort_answers(sr->sres, answers);
+
+ for (i = 0; answers && answers[i]; i++) {
+ sres_naptr_record_t const *na = answers[i]->sr_naptr;
+
+ if (na->na_record->r_status)
+ /* There was an error */
+ continue;
+
+ printf("naptr: %s\n\t%d IN NAPTR %u %u \"%s\" \"%s\" \"%s\" %s\n",
+ na->na_record->r_name, na->na_record->r_ttl,
+ na->na_order, na->na_prefer,
+ na->na_flags, na->na_services,
+ na->na_regexp, na->na_replace);
+
+ switch (na->na_flags[0]) {
+ case 's': /* srv */
+ if (strncasecmp("SIP+", na->na_services, 4))
+ /* Something else but SIP */
+ break;
+ query_srv(sr, na->na_replace);
+ sres_free_answers(sr->sres, answers);
+ return;
+
+ case 'a':
+ if (strncasecmp("SIP+", na->na_services, 4))
+ /* Something else but SIP */
+ break;
+ query_a(sr, na->na_replace);
+ sres_free_answers(sr->sres, answers);
+ return;
+ }
+ }
+
+ query_a(sr, /* sr->sr_uri->url_host */ sr->sr_canon);
+
+ sres_free_answers(sr->sres, answers);
+}
+
+static
+int query_naptr(struct context *sr, char const *domain)
+{
+ sres_record_t **answers;
+
+ answers = sres_cached_answers(sr->sres, sres_type_naptr, domain);
+
+ if (answers) {
+ answer_to_naptr_query(sr, NULL, answers);
+ return 0;
+ }
+ else {
+ sr->sr_query = sres_query_make(sr->sres, answer_to_naptr_query, sr,
+ sr->sr_sockets[0], sres_type_naptr, domain);
+ return sr->sr_query ? 0 : -1;
+ }
+}
+
+/* Process SRV records */
+static
+void answer_to_srv_query(sres_context_t *sr, sres_query_t *q,
+ sres_record_t *answers[])
+{
+ int i;
+
+ sr->sr_query = NULL;
+
+ sres_sort_answers(sr->sres, answers); /* Sort SRV records by the priority. */
+
+ for (i = 0; answers && answers[i]; i++) {
+ sres_srv_record_t const *srv = answers[i]->sr_srv;
+ if (srv->srv_record->r_status)
+ /* There was an error */
+ continue;
+ sr->sr_port = srv->srv_port;
+ query_a(sr, srv->srv_target);
+ return;
+ }
+
+ query_a(sr, /* sr->sr_uri->url_host */ sr->sr_canon);
+
+ sres_free_answers(sr->sres, answers);
+}
+
+static
+int query_srv(struct context *sr, char const *domain)
+{
+ sres_record_t **answers;
+
+ answers = sres_cached_answers(sr->sres, sres_type_srv, domain);
+
+ if (answers) {
+ answer_to_srv_query(sr, NULL, answers);
+ return 0;
+ }
+ else {
+ sr->sr_query = sres_query_make(sr->sres, answer_to_srv_query, sr,
+ sr->sr_sockets[0], sres_type_srv, domain);
+ return sr->sr_query ? 0 : -1;
+ }
+}
+
+/* Process A records */
+static
+void answer_to_a_query(sres_context_t *sr, sres_query_t *q,
+ sres_record_t *answers[])
+{
+ int i;
+
+ sr->sr_query = NULL;
+
+ for (i = 0; answers && answers[i]; i++) {
+ char addr[64];
+ sres_a_record_t const *a = answers[i]->sr_a;
+
+ if (a->a_record->r_status)
+ continue; /* There was an error */
+
+ inet_ntop(AF_INET, &a->a_addr, addr, sizeof(addr));
+ printf("%s@%s:%u\n", sr->sr_tport, addr, sr->sr_port);
+ sr->sr_exitcode = 0;
+ }
+
+ sres_free_answers(sr->sres, answers);
+
+ sr->sr_ready = 1;
+}
+
+static
+int query_a(struct context *sr, char const *domain)
+{
+ sres_record_t **answers;
+
+ answers = sres_cached_answers(sr->sres, sres_type_a, domain);
+
+ if (answers) {
+ answer_to_a_query(sr, NULL, answers);
+ return 0;
+ }
+ else {
+ sr->sr_query = sres_query_make(sr->sres, answer_to_a_query, sr,
+ sr->sr_sockets[0], sres_type_a, domain);
+ return sr->sr_query ? 0 : -1;
+ }
+}
+
+void usage(void)
+{
+ fprintf(stderr, "usage: resolve_sip [-s] [@dnsserver] domain\n");
+ exit(1);
+}
+
+int prepare_run(struct context *sr)
+{
+ sr->sr_n_sockets = 1;
+ sr->sr_sockets = calloc(1, sizeof(*sr->sr_sockets));
+ sr->sr_pollfds = calloc(1, sizeof(*sr->sr_pollfds));
+
+ if (!sr->sr_sockets || !sr->sr_pollfds ||
+ (sres_resolver_sockets(sr->sres, sr->sr_sockets, 1) == -1))
+ return 0;
+
+ sr->sr_pollfds[0].fd = sr->sr_sockets[0];
+ sr->sr_pollfds[0].events = POLLIN | POLLERR;
+
+ return 1;
+}
+
+void run(struct context *sr)
+{
+ int i, n, events;
+
+ n = sr->sr_n_sockets;
+
+ while (!sr->sr_ready) {
+ events = poll(sr->sr_pollfds, n, 500);
+
+ if (events)
+ for (i = 0; i < n; i++) {
+ if (sr->sr_pollfds[i].revents)
+ sres_resolver_receive(sr->sres, sr->sr_pollfds[i].fd);
+ }
+
+ /* No harm is done (except wasted CPU) if timer is called more often */
+ sres_resolver_timer(sr->sres, sr->sr_sockets[0]);
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ struct context sr[1] = {{ 0 }};
+ char const *dnsserver = NULL;
+
+ sr->sr_exitcode = 1;
+ sr->sr_tport = "*";
+
+ if (argv[1] && strcmp(argv[1], "-s") == 0)
+ sr->sr_sips = 1, argv++;
+
+ if (argv[1] && argv[1][0] == '@')
+ dnsserver = argv++[1] + 1;
+
+ if (argv[1] == NULL)
+ usage();
+
+ sr->sres = sres_resolver_new(getenv("SRESOLV_CONF"));
+
+ if (sr->sres)
+ if (prepare_run(sr))
+ if (query_naptr(sr, sr->sr_canon = argv[1]) == 0)
+ run(sr);
+
+ sres_resolver_unref(sr->sres), sr->sres = NULL;
+
+ return sr->sr_exitcode;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/rfc1034.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/rfc1034.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,3077 @@
+Network Working Group P. Mockapetris
+Request for Comments: 1034 ISI
+Obsoletes: RFCs 882, 883, 973 November 1987
+
+
+ DOMAIN NAMES - CONCEPTS AND FACILITIES
+
+
+
+1. STATUS OF THIS MEMO
+
+This RFC is an introduction to the Domain Name System (DNS), and omits
+many details which can be found in a companion RFC, "Domain Names -
+Implementation and Specification" [RFC-1035]. That RFC assumes that the
+reader is familiar with the concepts discussed in this memo.
+
+A subset of DNS functions and data types constitute an official
+protocol. The official protocol includes standard queries and their
+responses and most of the Internet class data formats (e.g., host
+addresses).
+
+However, the domain system is intentionally extensible. Researchers are
+continuously proposing, implementing and experimenting with new data
+types, query types, classes, functions, etc. Thus while the components
+of the official protocol are expected to stay essentially unchanged and
+operate as a production service, experimental behavior should always be
+expected in extensions beyond the official protocol. Experimental or
+obsolete features are clearly marked in these RFCs, and such information
+should be used with caution.
+
+The reader is especially cautioned not to depend on the values which
+appear in examples to be current or complete, since their purpose is
+primarily pedagogical. Distribution of this memo is unlimited.
+
+2. INTRODUCTION
+
+This RFC introduces domain style names, their use for Internet mail and
+host address support, and the protocols and servers used to implement
+domain name facilities.
+
+2.1. The history of domain names
+
+The impetus for the development of the domain system was growth in the
+Internet:
+
+ - Host name to address mappings were maintained by the Network
+ Information Center (NIC) in a single file (HOSTS.TXT) which
+ was FTPed by all hosts [RFC-952, RFC-953]. The total network
+
+
+
+Mockapetris [Page 1]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+ bandwidth consumed in distributing a new version by this
+ scheme is proportional to the square of the number of hosts in
+ the network, and even when multiple levels of FTP are used,
+ the outgoing FTP load on the NIC host is considerable.
+ Explosive growth in the number of hosts didn't bode well for
+ the future.
+
+ - The network population was also changing in character. The
+ timeshared hosts that made up the original ARPANET were being
+ replaced with local networks of workstations. Local
+ organizations were administering their own names and
+ addresses, but had to wait for the NIC to change HOSTS.TXT to
+ make changes visible to the Internet at large. Organizations
+ also wanted some local structure on the name space.
+
+ - The applications on the Internet were getting more
+ sophisticated and creating a need for general purpose name
+ service.
+
+
+The result was several ideas about name spaces and their management
+[IEN-116, RFC-799, RFC-819, RFC-830]. The proposals varied, but a
+common thread was the idea of a hierarchical name space, with the
+hierarchy roughly corresponding to organizational structure, and names
+using "." as the character to mark the boundary between hierarchy
+levels. A design using a distributed database and generalized resources
+was described in [RFC-882, RFC-883]. Based on experience with several
+implementations, the system evolved into the scheme described in this
+memo.
+
+The terms "domain" or "domain name" are used in many contexts beyond the
+DNS described here. Very often, the term domain name is used to refer
+to a name with structure indicated by dots, but no relation to the DNS.
+This is particularly true in mail addressing [Quarterman 86].
+
+2.2. DNS design goals
+
+The design goals of the DNS influence its structure. They are:
+
+ - The primary goal is a consistent name space which will be used
+ for referring to resources. In order to avoid the problems
+ caused by ad hoc encodings, names should not be required to
+ contain network identifiers, addresses, routes, or similar
+ information as part of the name.
+
+ - The sheer size of the database and frequency of updates
+ suggest that it must be maintained in a distributed manner,
+ with local caching to improve performance. Approaches that
+
+
+
+Mockapetris [Page 2]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+ attempt to collect a consistent copy of the entire database
+ will become more and more expensive and difficult, and hence
+ should be avoided. The same principle holds for the structure
+ of the name space, and in particular mechanisms for creating
+ and deleting names; these should also be distributed.
+
+ - Where there tradeoffs between the cost of acquiring data, the
+ speed of updates, and the accuracy of caches, the source of
+ the data should control the tradeoff.
+
+ - The costs of implementing such a facility dictate that it be
+ generally useful, and not restricted to a single application.
+ We should be able to use names to retrieve host addresses,
+ mailbox data, and other as yet undetermined information. All
+ data associated with a name is tagged with a type, and queries
+ can be limited to a single type.
+
+ - Because we want the name space to be useful in dissimilar
+ networks and applications, we provide the ability to use the
+ same name space with different protocol families or
+ management. For example, host address formats differ between
+ protocols, though all protocols have the notion of address.
+ The DNS tags all data with a class as well as the type, so
+ that we can allow parallel use of different formats for data
+ of type address.
+
+ - We want name server transactions to be independent of the
+ communications system that carries them. Some systems may
+ wish to use datagrams for queries and responses, and only
+ establish virtual circuits for transactions that need the
+ reliability (e.g., database updates, long transactions); other
+ systems will use virtual circuits exclusively.
+
+ - The system should be useful across a wide spectrum of host
+ capabilities. Both personal computers and large timeshared
+ hosts should be able to use the system, though perhaps in
+ different ways.
+
+2.3. Assumptions about usage
+
+The organization of the domain system derives from some assumptions
+about the needs and usage patterns of its user community and is designed
+to avoid many of the the complicated problems found in general purpose
+database systems.
+
+The assumptions are:
+
+ - The size of the total database will initially be proportional
+
+
+
+Mockapetris [Page 3]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+ to the number of hosts using the system, but will eventually
+ grow to be proportional to the number of users on those hosts
+ as mailboxes and other information are added to the domain
+ system.
+
+ - Most of the data in the system will change very slowly (e.g.,
+ mailbox bindings, host addresses), but that the system should
+ be able to deal with subsets that change more rapidly (on the
+ order of seconds or minutes).
+
+ - The administrative boundaries used to distribute
+ responsibility for the database will usually correspond to
+ organizations that have one or more hosts. Each organization
+ that has responsibility for a particular set of domains will
+ provide redundant name servers, either on the organization's
+ own hosts or other hosts that the organization arranges to
+ use.
+
+ - Clients of the domain system should be able to identify
+ trusted name servers they prefer to use before accepting
+ referrals to name servers outside of this "trusted" set.
+
+ - Access to information is more critical than instantaneous
+ updates or guarantees of consistency. Hence the update
+ process allows updates to percolate out through the users of
+ the domain system rather than guaranteeing that all copies are
+ simultaneously updated. When updates are unavailable due to
+ network or host failure, the usual course is to believe old
+ information while continuing efforts to update it. The
+ general model is that copies are distributed with timeouts for
+ refreshing. The distributor sets the timeout value and the
+ recipient of the distribution is responsible for performing
+ the refresh. In special situations, very short intervals can
+ be specified, or the owner can prohibit copies.
+
+ - In any system that has a distributed database, a particular
+ name server may be presented with a query that can only be
+ answered by some other server. The two general approaches to
+ dealing with this problem are "recursive", in which the first
+ server pursues the query for the client at another server, and
+ "iterative", in which the server refers the client to another
+ server and lets the client pursue the query. Both approaches
+ have advantages and disadvantages, but the iterative approach
+ is preferred for the datagram style of access. The domain
+ system requires implementation of the iterative approach, but
+ allows the recursive approach as an option.
+
+
+
+
+
+Mockapetris [Page 4]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+The domain system assumes that all data originates in master files
+scattered through the hosts that use the domain system. These master
+files are updated by local system administrators. Master files are text
+files that are read by a local name server, and hence become available
+through the name servers to users of the domain system. The user
+programs access name servers through standard programs called resolvers.
+
+The standard format of master files allows them to be exchanged between
+hosts (via FTP, mail, or some other mechanism); this facility is useful
+when an organization wants a domain, but doesn't want to support a name
+server. The organization can maintain the master files locally using a
+text editor, transfer them to a foreign host which runs a name server,
+and then arrange with the system administrator of the name server to get
+the files loaded.
+
+Each host's name servers and resolvers are configured by a local system
+administrator [RFC-1033]. For a name server, this configuration data
+includes the identity of local master files and instructions on which
+non-local master files are to be loaded from foreign servers. The name
+server uses the master files or copies to load its zones. For
+resolvers, the configuration data identifies the name servers which
+should be the primary sources of information.
+
+The domain system defines procedures for accessing the data and for
+referrals to other name servers. The domain system also defines
+procedures for caching retrieved data and for periodic refreshing of
+data defined by the system administrator.
+
+The system administrators provide:
+
+ - The definition of zone boundaries.
+
+ - Master files of data.
+
+ - Updates to master files.
+
+ - Statements of the refresh policies desired.
+
+The domain system provides:
+
+ - Standard formats for resource data.
+
+ - Standard methods for querying the database.
+
+ - Standard methods for name servers to refresh local data from
+ foreign name servers.
+
+
+
+
+
+Mockapetris [Page 5]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+2.4. Elements of the DNS
+
+The DNS has three major components:
+
+ - The DOMAIN NAME SPACE and RESOURCE RECORDS, which are
+ specifications for a tree structured name space and data
+ associated with the names. Conceptually, each node and leaf
+ of the domain name space tree names a set of information, and
+ query operations are attempts to extract specific types of
+ information from a particular set. A query names the domain
+ name of interest and describes the type of resource
+ information that is desired. For example, the Internet
+ uses some of its domain names to identify hosts; queries for
+ address resources return Internet host addresses.
+
+ - NAME SERVERS are server programs which hold information about
+ the domain tree's structure and set information. A name
+ server may cache structure or set information about any part
+ of the domain tree, but in general a particular name server
+ has complete information about a subset of the domain space,
+ and pointers to other name servers that can be used to lead to
+ information from any part of the domain tree. Name servers
+ know the parts of the domain tree for which they have complete
+ information; a name server is said to be an AUTHORITY for
+ these parts of the name space. Authoritative information is
+ organized into units called ZONEs, and these zones can be
+ automatically distributed to the name servers which provide
+ redundant service for the data in a zone.
+
+ - RESOLVERS are programs that extract information from name
+ servers in response to client requests. Resolvers must be
+ able to access at least one name server and use that name
+ server's information to answer a query directly, or pursue the
+ query using referrals to other name servers. A resolver will
+ typically be a system routine that is directly accessible to
+ user programs; hence no protocol is necessary between the
+ resolver and the user program.
+
+These three components roughly correspond to the three layers or views
+of the domain system:
+
+ - From the user's point of view, the domain system is accessed
+ through a simple procedure or OS call to a local resolver.
+ The domain space consists of a single tree and the user can
+ request information from any section of the tree.
+
+ - From the resolver's point of view, the domain system is
+ composed of an unknown number of name servers. Each name
+
+
+
+Mockapetris [Page 6]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+ server has one or more pieces of the whole domain tree's data,
+ but the resolver views each of these databases as essentially
+ static.
+
+ - From a name server's point of view, the domain system consists
+ of separate sets of local information called zones. The name
+ server has local copies of some of the zones. The name server
+ must periodically refresh its zones from master copies in
+ local files or foreign name servers. The name server must
+ concurrently process queries that arrive from resolvers.
+
+In the interests of performance, implementations may couple these
+functions. For example, a resolver on the same machine as a name server
+might share a database consisting of the the zones managed by the name
+server and the cache managed by the resolver.
+
+3. DOMAIN NAME SPACE and RESOURCE RECORDS
+
+3.1. Name space specifications and terminology
+
+The domain name space is a tree structure. Each node and leaf on the
+tree corresponds to a resource set (which may be empty). The domain
+system makes no distinctions between the uses of the interior nodes and
+leaves, and this memo uses the term "node" to refer to both.
+
+Each node has a label, which is zero to 63 octets in length. Brother
+nodes may not have the same label, although the same label can be used
+for nodes which are not brothers. One label is reserved, and that is
+the null (i.e., zero length) label used for the root.
+
+The domain name of a node is the list of the labels on the path from the
+node to the root of the tree. By convention, the labels that compose a
+domain name are printed or read left to right, from the most specific
+(lowest, farthest from the root) to the least specific (highest, closest
+to the root).
+
+Internally, programs that manipulate domain names should represent them
+as sequences of labels, where each label is a length octet followed by
+an octet string. Because all domain names end at the root, which has a
+null string for a label, these internal representations can use a length
+byte of zero to terminate a domain name.
+
+By convention, domain names can be stored with arbitrary case, but
+domain name comparisons for all present domain functions are done in a
+case-insensitive manner, assuming an ASCII character set, and a high
+order zero bit. This means that you are free to create a node with
+label "A" or a node with label "a", but not both as brothers; you could
+refer to either using "a" or "A". When you receive a domain name or
+
+
+
+Mockapetris [Page 7]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+label, you should preserve its case. The rationale for this choice is
+that we may someday need to add full binary domain names for new
+services; existing services would not be changed.
+
+When a user needs to type a domain name, the length of each label is
+omitted and the labels are separated by dots ("."). Since a complete
+domain name ends with the root label, this leads to a printed form which
+ends in a dot. We use this property to distinguish between:
+
+ - a character string which represents a complete domain name
+ (often called "absolute"). For example, "poneria.ISI.EDU."
+
+ - a character string that represents the starting labels of a
+ domain name which is incomplete, and should be completed by
+ local software using knowledge of the local domain (often
+ called "relative"). For example, "poneria" used in the
+ ISI.EDU domain.
+
+Relative names are either taken relative to a well known origin, or to a
+list of domains used as a search list. Relative names appear mostly at
+the user interface, where their interpretation varies from
+implementation to implementation, and in master files, where they are
+relative to a single origin domain name. The most common interpretation
+uses the root "." as either the single origin or as one of the members
+of the search list, so a multi-label relative name is often one where
+the trailing dot has been omitted to save typing.
+
+To simplify implementations, the total number of octets that represent a
+domain name (i.e., the sum of all label octets and label lengths) is
+limited to 255.
+
+A domain is identified by a domain name, and consists of that part of
+the domain name space that is at or below the domain name which
+specifies the domain. A domain is a subdomain of another domain if it
+is contained within that domain. This relationship can be tested by
+seeing if the subdomain's name ends with the containing domain's name.
+For example, A.B.C.D is a subdomain of B.C.D, C.D, D, and " ".
+
+3.2. Administrative guidelines on use
+
+As a matter of policy, the DNS technical specifications do not mandate a
+particular tree structure or rules for selecting labels; its goal is to
+be as general as possible, so that it can be used to build arbitrary
+applications. In particular, the system was designed so that the name
+space did not have to be organized along the lines of network
+boundaries, name servers, etc. The rationale for this is not that the
+name space should have no implied semantics, but rather that the choice
+of implied semantics should be left open to be used for the problem at
+
+
+
+Mockapetris [Page 8]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+hand, and that different parts of the tree can have different implied
+semantics. For example, the IN-ADDR.ARPA domain is organized and
+distributed by network and host address because its role is to translate
+from network or host numbers to names; NetBIOS domains [RFC-1001, RFC-
+1002] are flat because that is appropriate for that application.
+
+However, there are some guidelines that apply to the "normal" parts of
+the name space used for hosts, mailboxes, etc., that will make the name
+space more uniform, provide for growth, and minimize problems as
+software is converted from the older host table. The political
+decisions about the top levels of the tree originated in RFC-920.
+Current policy for the top levels is discussed in [RFC-1032]. MILNET
+conversion issues are covered in [RFC-1031].
+
+Lower domains which will eventually be broken into multiple zones should
+provide branching at the top of the domain so that the eventual
+decomposition can be done without renaming. Node labels which use
+special characters, leading digits, etc., are likely to break older
+software which depends on more restrictive choices.
+
+3.3. Technical guidelines on use
+
+Before the DNS can be used to hold naming information for some kind of
+object, two needs must be met:
+
+ - A convention for mapping between object names and domain
+ names. This describes how information about an object is
+ accessed.
+
+ - RR types and data formats for describing the object.
+
+These rules can be quite simple or fairly complex. Very often, the
+designer must take into account existing formats and plan for upward
+compatibility for existing usage. Multiple mappings or levels of
+mapping may be required.
+
+For hosts, the mapping depends on the existing syntax for host names
+which is a subset of the usual text representation for domain names,
+together with RR formats for describing host addresses, etc. Because we
+need a reliable inverse mapping from address to host name, a special
+mapping for addresses into the IN-ADDR.ARPA domain is also defined.
+
+For mailboxes, the mapping is slightly more complex. The usual mail
+address <local-part>@<mail-domain> is mapped into a domain name by
+converting <local-part> into a single label (regardles of dots it
+contains), converting <mail-domain> into a domain name using the usual
+text format for domain names (dots denote label breaks), and
+concatenating the two to form a single domain name. Thus the mailbox
+
+
+
+Mockapetris [Page 9]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+HOSTMASTER at SRI-NIC.ARPA is represented as a domain name by
+HOSTMASTER.SRI-NIC.ARPA. An appreciation for the reasons behind this
+design also must take into account the scheme for mail exchanges [RFC-
+974].
+
+The typical user is not concerned with defining these rules, but should
+understand that they usually are the result of numerous compromises
+between desires for upward compatibility with old usage, interactions
+between different object definitions, and the inevitable urge to add new
+features when defining the rules. The way the DNS is used to support
+some object is often more crucial than the restrictions inherent in the
+DNS.
+
+3.4. Example name space
+
+The following figure shows a part of the current domain name space, and
+is used in many examples in this RFC. Note that the tree is a very
+small subset of the actual name space.
+
+ |
+ |
+ +---------------------+------------------+
+ | | |
+ MIL EDU ARPA
+ | | |
+ | | |
+ +-----+-----+ | +------+-----+-----+
+ | | | | | | |
+ BRL NOSC DARPA | IN-ADDR SRI-NIC ACC
+ |
+ +--------+------------------+---------------+--------+
+ | | | | |
+ UCI MIT | UDEL YALE
+ | ISI
+ | |
+ +---+---+ |
+ | | |
+ LCS ACHILLES +--+-----+-----+--------+
+ | | | | | |
+ XX A C VAXA VENERA Mockapetris
+
+In this example, the root domain has three immediate subdomains: MIL,
+EDU, and ARPA. The LCS.MIT.EDU domain has one immediate subdomain named
+XX.LCS.MIT.EDU. All of the leaves are also domains.
+
+3.5. Preferred name syntax
+
+The DNS specifications attempt to be as general as possible in the rules
+
+
+
+Mockapetris [Page 10]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+for constructing domain names. The idea is that the name of any
+existing object can be expressed as a domain name with minimal changes.
+However, when assigning a domain name for an object, the prudent user
+will select a name which satisfies both the rules of the domain system
+and any existing rules for the object, whether these rules are published
+or implied by existing programs.
+
+For example, when naming a mail domain, the user should satisfy both the
+rules of this memo and those in RFC-822. When creating a new host name,
+the old rules for HOSTS.TXT should be followed. This avoids problems
+when old software is converted to use domain names.
+
+The following syntax will result in fewer problems with many
+applications that use domain names (e.g., mail, TELNET).
+
+<domain> ::= <subdomain> | " "
+
+<subdomain> ::= <label> | <subdomain> "." <label>
+
+<label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
+
+<ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
+
+<let-dig-hyp> ::= <let-dig> | "-"
+
+<let-dig> ::= <letter> | <digit>
+
+<letter> ::= any one of the 52 alphabetic characters A through Z in
+upper case and a through z in lower case
+
+<digit> ::= any one of the ten digits 0 through 9
+
+Note that while upper and lower case letters are allowed in domain
+names, no significance is attached to the case. That is, two names with
+the same spelling but different case are to be treated as if identical.
+
+The labels must follow the rules for ARPANET host names. They must
+start with a letter, end with a letter or digit, and have as interior
+characters only letters, digits, and hyphen. There are also some
+restrictions on the length. Labels must be 63 characters or less.
+
+For example, the following strings identify hosts in the Internet:
+
+A.ISI.EDU XX.LCS.MIT.EDU SRI-NIC.ARPA
+
+3.6. Resource Records
+
+A domain name identifies a node. Each node has a set of resource
+
+
+
+Mockapetris [Page 11]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+information, which may be empty. The set of resource information
+associated with a particular name is composed of separate resource
+records (RRs). The order of RRs in a set is not significant, and need
+not be preserved by name servers, resolvers, or other parts of the DNS.
+
+When we talk about a specific RR, we assume it has the following:
+
+owner which is the domain name where the RR is found.
+
+type which is an encoded 16 bit value that specifies the type
+ of the resource in this resource record. Types refer to
+ abstract resources.
+
+ This memo uses the following types:
+
+ A a host address
+
+ CNAME identifies the canonical name of an
+ alias
+
+ HINFO identifies the CPU and OS used by a host
+
+ MX identifies a mail exchange for the
+ domain. See [RFC-974 for details.
+
+ NS
+ the authoritative name server for the domain
+
+ PTR
+ a pointer to another part of the domain name space
+
+ SOA
+ identifies the start of a zone of authority]
+
+class which is an encoded 16 bit value which identifies a
+ protocol family or instance of a protocol.
+
+ This memo uses the following classes:
+
+ IN the Internet system
+
+ CH the Chaos system
+
+TTL which is the time to live of the RR. This field is a 32
+ bit integer in units of seconds, an is primarily used by
+ resolvers when they cache RRs. The TTL describes how
+ long a RR can be cached before it should be discarded.
+
+
+
+
+Mockapetris [Page 12]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+RDATA which is the type and sometimes class dependent data
+ which describes the resource:
+
+ A For the IN class, a 32 bit IP address
+
+ For the CH class, a domain name followed
+ by a 16 bit octal Chaos address.
+
+ CNAME a domain name.
+
+ MX a 16 bit preference value (lower is
+ better) followed by a host name willing
+ to act as a mail exchange for the owner
+ domain.
+
+ NS a host name.
+
+ PTR a domain name.
+
+ SOA several fields.
+
+The owner name is often implicit, rather than forming an integral part
+of the RR. For example, many name servers internally form tree or hash
+structures for the name space, and chain RRs off nodes. The remaining
+RR parts are the fixed header (type, class, TTL) which is consistent for
+all RRs, and a variable part (RDATA) that fits the needs of the resource
+being described.
+
+The meaning of the TTL field is a time limit on how long an RR can be
+kept in a cache. This limit does not apply to authoritative data in
+zones; it is also timed out, but by the refreshing policies for the
+zone. The TTL is assigned by the administrator for the zone where the
+data originates. While short TTLs can be used to minimize caching, and
+a zero TTL prohibits caching, the realities of Internet performance
+suggest that these times should be on the order of days for the typical
+host. If a change can be anticipated, the TTL can be reduced prior to
+the change to minimize inconsistency during the change, and then
+increased back to its former value following the change.
+
+The data in the RDATA section of RRs is carried as a combination of
+binary strings and domain names. The domain names are frequently used
+as "pointers" to other data in the DNS.
+
+3.6.1. Textual expression of RRs
+
+RRs are represented in binary form in the packets of the DNS protocol,
+and are usually represented in highly encoded form when stored in a name
+server or resolver. In this memo, we adopt a style similar to that used
+
+
+
+Mockapetris [Page 13]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+in master files in order to show the contents of RRs. In this format,
+most RRs are shown on a single line, although continuation lines are
+possible using parentheses.
+
+The start of the line gives the owner of the RR. If a line begins with
+a blank, then the owner is assumed to be the same as that of the
+previous RR. Blank lines are often included for readability.
+
+Following the owner, we list the TTL, type, and class of the RR. Class
+and type use the mnemonics defined above, and TTL is an integer before
+the type field. In order to avoid ambiguity in parsing, type and class
+mnemonics are disjoint, TTLs are integers, and the type mnemonic is
+always last. The IN class and TTL values are often omitted from examples
+in the interests of clarity.
+
+The resource data or RDATA section of the RR are given using knowledge
+of the typical representation for the data.
+
+For example, we might show the RRs carried in a message as:
+
+ ISI.EDU. MX 10 VENERA.ISI.EDU.
+ MX 10 VAXA.ISI.EDU.
+ VENERA.ISI.EDU. A 128.9.0.32
+ A 10.1.0.52
+ VAXA.ISI.EDU. A 10.2.0.27
+ A 128.9.0.33
+
+The MX RRs have an RDATA section which consists of a 16 bit number
+followed by a domain name. The address RRs use a standard IP address
+format to contain a 32 bit internet address.
+
+This example shows six RRs, with two RRs at each of three domain names.
+
+Similarly we might see:
+
+ XX.LCS.MIT.EDU. IN A 10.0.0.44
+ CH A MIT.EDU. 2420
+
+This example shows two addresses for XX.LCS.MIT.EDU, each of a different
+class.
+
+3.6.2. Aliases and canonical names
+
+In existing systems, hosts and other resources often have several names
+that identify the same resource. For example, the names C.ISI.EDU and
+USC-ISIC.ARPA both identify the same host. Similarly, in the case of
+mailboxes, many organizations provide many names that actually go to the
+same mailbox; for example Mockapetris at C.ISI.EDU, Mockapetris at B.ISI.EDU,
+
+
+
+Mockapetris [Page 14]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+and PVM at ISI.EDU all go to the same mailbox (although the mechanism
+behind this is somewhat complicated).
+
+Most of these systems have a notion that one of the equivalent set of
+names is the canonical or primary name and all others are aliases.
+
+The domain system provides such a feature using the canonical name
+(CNAME) RR. A CNAME RR identifies its owner name as an alias, and
+specifies the corresponding canonical name in the RDATA section of the
+RR. If a CNAME RR is present at a node, no other data should be
+present; this ensures that the data for a canonical name and its aliases
+cannot be different. This rule also insures that a cached CNAME can be
+used without checking with an authoritative server for other RR types.
+
+CNAME RRs cause special action in DNS software. When a name server
+fails to find a desired RR in the resource set associated with the
+domain name, it checks to see if the resource set consists of a CNAME
+record with a matching class. If so, the name server includes the CNAME
+record in the response and restarts the query at the domain name
+specified in the data field of the CNAME record. The one exception to
+this rule is that queries which match the CNAME type are not restarted.
+
+For example, suppose a name server was processing a query with for USC-
+ISIC.ARPA, asking for type A information, and had the following resource
+records:
+
+ USC-ISIC.ARPA IN CNAME C.ISI.EDU
+
+ C.ISI.EDU IN A 10.0.0.52
+
+Both of these RRs would be returned in the response to the type A query,
+while a type CNAME or * query should return just the CNAME.
+
+Domain names in RRs which point at another name should always point at
+the primary name and not the alias. This avoids extra indirections in
+accessing information. For example, the address to name RR for the
+above host should be:
+
+ 52.0.0.10.IN-ADDR.ARPA IN PTR C.ISI.EDU
+
+rather than pointing at USC-ISIC.ARPA. Of course, by the robustness
+principle, domain software should not fail when presented with CNAME
+chains or loops; CNAME chains should be followed and CNAME loops
+signalled as an error.
+
+3.7. Queries
+
+Queries are messages which may be sent to a name server to provoke a
+
+
+
+Mockapetris [Page 15]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+response. In the Internet, queries are carried in UDP datagrams or over
+TCP connections. The response by the name server either answers the
+question posed in the query, refers the requester to another set of name
+servers, or signals some error condition.
+
+In general, the user does not generate queries directly, but instead
+makes a request to a resolver which in turn sends one or more queries to
+name servers and deals with the error conditions and referrals that may
+result. Of course, the possible questions which can be asked in a query
+does shape the kind of service a resolver can provide.
+
+DNS queries and responses are carried in a standard message format. The
+message format has a header containing a number of fixed fields which
+are always present, and four sections which carry query parameters and
+RRs.
+
+The most important field in the header is a four bit field called an
+opcode which separates different queries. Of the possible 16 values,
+one (standard query) is part of the official protocol, two (inverse
+query and status query) are options, one (completion) is obsolete, and
+the rest are unassigned.
+
+The four sections are:
+
+Question Carries the query name and other query parameters.
+
+Answer Carries RRs which directly answer the query.
+
+Authority Carries RRs which describe other authoritative servers.
+ May optionally carry the SOA RR for the authoritative
+ data in the answer section.
+
+Additional Carries RRs which may be helpful in using the RRs in the
+ other sections.
+
+Note that the content, but not the format, of these sections varies with
+header opcode.
+
+3.7.1. Standard queries
+
+A standard query specifies a target domain name (QNAME), query type
+(QTYPE), and query class (QCLASS) and asks for RRs which match. This
+type of query makes up such a vast majority of DNS queries that we use
+the term "query" to mean standard query unless otherwise specified. The
+QTYPE and QCLASS fields are each 16 bits long, and are a superset of
+defined types and classes.
+
+
+
+
+
+Mockapetris [Page 16]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+The QTYPE field may contain:
+
+<any type> matches just that type. (e.g., A, PTR).
+
+AXFR special zone transfer QTYPE.
+
+MAILB matches all mail box related RRs (e.g. MB and MG).
+
+* matches all RR types.
+
+The QCLASS field may contain:
+
+<any class> matches just that class (e.g., IN, CH).
+
+* matches aLL RR classes.
+
+Using the query domain name, QTYPE, and QCLASS, the name server looks
+for matching RRs. In addition to relevant records, the name server may
+return RRs that point toward a name server that has the desired
+information or RRs that are expected to be useful in interpreting the
+relevant RRs. For example, a name server that doesn't have the
+requested information may know a name server that does; a name server
+that returns a domain name in a relevant RR may also return the RR that
+binds that domain name to an address.
+
+For example, a mailer tying to send mail to Mockapetris at ISI.EDU might
+ask the resolver for mail information about ISI.EDU, resulting in a
+query for QNAME=ISI.EDU, QTYPE=MX, QCLASS=IN. The response's answer
+section would be:
+
+ ISI.EDU. MX 10 VENERA.ISI.EDU.
+ MX 10 VAXA.ISI.EDU.
+
+while the additional section might be:
+
+ VAXA.ISI.EDU. A 10.2.0.27
+ A 128.9.0.33
+ VENERA.ISI.EDU. A 10.1.0.52
+ A 128.9.0.32
+
+Because the server assumes that if the requester wants mail exchange
+information, it will probably want the addresses of the mail exchanges
+soon afterward.
+
+Note that the QCLASS=* construct requires special interpretation
+regarding authority. Since a particular name server may not know all of
+the classes available in the domain system, it can never know if it is
+authoritative for all classes. Hence responses to QCLASS=* queries can
+
+
+
+Mockapetris [Page 17]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+never be authoritative.
+
+3.7.2. Inverse queries (Optional)
+
+Name servers may also support inverse queries that map a particular
+resource to a domain name or domain names that have that resource. For
+example, while a standard query might map a domain name to a SOA RR, the
+corresponding inverse query might map the SOA RR back to the domain
+name.
+
+Implementation of this service is optional in a name server, but all
+name servers must at least be able to understand an inverse query
+message and return a not-implemented error response.
+
+The domain system cannot guarantee the completeness or uniqueness of
+inverse queries because the domain system is organized by domain name
+rather than by host address or any other resource type. Inverse queries
+are primarily useful for debugging and database maintenance activities.
+
+Inverse queries may not return the proper TTL, and do not indicate cases
+where the identified RR is one of a set (for example, one address for a
+host having multiple addresses). Therefore, the RRs returned in inverse
+queries should never be cached.
+
+Inverse queries are NOT an acceptable method for mapping host addresses
+to host names; use the IN-ADDR.ARPA domain instead.
+
+A detailed discussion of inverse queries is contained in [RFC-1035].
+
+3.8. Status queries (Experimental)
+
+To be defined.
+
+3.9. Completion queries (Obsolete)
+
+The optional completion services described in RFCs 882 and 883 have been
+deleted. Redesigned services may become available in the future, or the
+opcodes may be reclaimed for other use.
+
+4. NAME SERVERS
+
+4.1. Introduction
+
+Name servers are the repositories of information that make up the domain
+database. The database is divided up into sections called zones, which
+are distributed among the name servers. While name servers can have
+several optional functions and sources of data, the essential task of a
+name server is to answer queries using data in its zones. By design,
+
+
+
+Mockapetris [Page 18]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+name servers can answer queries in a simple manner; the response can
+always be generated using only local data, and either contains the
+answer to the question or a referral to other name servers "closer" to
+the desired information.
+
+A given zone will be available from several name servers to insure its
+availability in spite of host or communication link failure. By
+administrative fiat, we require every zone to be available on at least
+two servers, and many zones have more redundancy than that.
+
+A given name server will typically support one or more zones, but this
+gives it authoritative information about only a small section of the
+domain tree. It may also have some cached non-authoritative data about
+other parts of the tree. The name server marks its responses to queries
+so that the requester can tell whether the response comes from
+authoritative data or not.
+
+4.2. How the database is divided into zones
+
+The domain database is partitioned in two ways: by class, and by "cuts"
+made in the name space between nodes.
+
+The class partition is simple. The database for any class is organized,
+delegated, and maintained separately from all other classes. Since, by
+convention, the name spaces are the same for all classes, the separate
+classes can be thought of as an array of parallel namespace trees. Note
+that the data attached to nodes will be different for these different
+parallel classes. The most common reasons for creating a new class are
+the necessity for a new data format for existing types or a desire for a
+separately managed version of the existing name space.
+
+Within a class, "cuts" in the name space can be made between any two
+adjacent nodes. After all cuts are made, each group of connected name
+space is a separate zone. The zone is said to be authoritative for all
+names in the connected region. Note that the "cuts" in the name space
+may be in different places for different classes, the name servers may
+be different, etc.
+
+These rules mean that every zone has at least one node, and hence domain
+name, for which it is authoritative, and all of the nodes in a
+particular zone are connected. Given, the tree structure, every zone
+has a highest node which is closer to the root than any other node in
+the zone. The name of this node is often used to identify the zone.
+
+It would be possible, though not particularly useful, to partition the
+name space so that each domain name was in a separate zone or so that
+all nodes were in a single zone. Instead, the database is partitioned
+at points where a particular organization wants to take over control of
+
+
+
+Mockapetris [Page 19]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+a subtree. Once an organization controls its own zone it can
+unilaterally change the data in the zone, grow new tree sections
+connected to the zone, delete existing nodes, or delegate new subzones
+under its zone.
+
+If the organization has substructure, it may want to make further
+internal partitions to achieve nested delegations of name space control.
+In some cases, such divisions are made purely to make database
+maintenance more convenient.
+
+4.2.1. Technical considerations
+
+The data that describes a zone has four major parts:
+
+ - Authoritative data for all nodes within the zone.
+
+ - Data that defines the top node of the zone (can be thought of
+ as part of the authoritative data).
+
+ - Data that describes delegated subzones, i.e., cuts around the
+ bottom of the zone.
+
+ - Data that allows access to name servers for subzones
+ (sometimes called "glue" data).
+
+All of this data is expressed in the form of RRs, so a zone can be
+completely described in terms of a set of RRs. Whole zones can be
+transferred between name servers by transferring the RRs, either carried
+in a series of messages or by FTPing a master file which is a textual
+representation.
+
+The authoritative data for a zone is simply all of the RRs attached to
+all of the nodes from the top node of the zone down to leaf nodes or
+nodes above cuts around the bottom edge of the zone.
+
+Though logically part of the authoritative data, the RRs that describe
+the top node of the zone are especially important to the zone's
+management. These RRs are of two types: name server RRs that list, one
+per RR, all of the servers for the zone, and a single SOA RR that
+describes zone management parameters.
+
+The RRs that describe cuts around the bottom of the zone are NS RRs that
+name the servers for the subzones. Since the cuts are between nodes,
+these RRs are NOT part of the authoritative data of the zone, and should
+be exactly the same as the corresponding RRs in the top node of the
+subzone. Since name servers are always associated with zone boundaries,
+NS RRs are only found at nodes which are the top node of some zone. In
+the data that makes up a zone, NS RRs are found at the top node of the
+
+
+
+Mockapetris [Page 20]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+zone (and are authoritative) and at cuts around the bottom of the zone
+(where they are not authoritative), but never in between.
+
+One of the goals of the zone structure is that any zone have all the
+data required to set up communications with the name servers for any
+subzones. That is, parent zones have all the information needed to
+access servers for their children zones. The NS RRs that name the
+servers for subzones are often not enough for this task since they name
+the servers, but do not give their addresses. In particular, if the
+name of the name server is itself in the subzone, we could be faced with
+the situation where the NS RRs tell us that in order to learn a name
+server's address, we should contact the server using the address we wish
+to learn. To fix this problem, a zone contains "glue" RRs which are not
+part of the authoritative data, and are address RRs for the servers.
+These RRs are only necessary if the name server's name is "below" the
+cut, and are only used as part of a referral response.
+
+4.2.2. Administrative considerations
+
+When some organization wants to control its own domain, the first step
+is to identify the proper parent zone, and get the parent zone's owners
+to agree to the delegation of control. While there are no particular
+technical constraints dealing with where in the tree this can be done,
+there are some administrative groupings discussed in [RFC-1032] which
+deal with top level organization, and middle level zones are free to
+create their own rules. For example, one university might choose to use
+a single zone, while another might choose to organize by subzones
+dedicated to individual departments or schools. [RFC-1033] catalogs
+available DNS software an discusses administration procedures.
+
+Once the proper name for the new subzone is selected, the new owners
+should be required to demonstrate redundant name server support. Note
+that there is no requirement that the servers for a zone reside in a
+host which has a name in that domain. In many cases, a zone will be
+more accessible to the internet at large if its servers are widely
+distributed rather than being within the physical facilities controlled
+by the same organization that manages the zone. For example, in the
+current DNS, one of the name servers for the United Kingdom, or UK
+domain, is found in the US. This allows US hosts to get UK data without
+using limited transatlantic bandwidth.
+
+As the last installation step, the delegation NS RRs and glue RRs
+necessary to make the delegation effective should be added to the parent
+zone. The administrators of both zones should insure that the NS and
+glue RRs which mark both sides of the cut are consistent and remain so.
+
+4.3. Name server internals
+
+
+
+
+Mockapetris [Page 21]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+4.3.1. Queries and responses
+
+The principal activity of name servers is to answer standard queries.
+Both the query and its response are carried in a standard message format
+which is described in [RFC-1035]. The query contains a QTYPE, QCLASS,
+and QNAME, which describe the types and classes of desired information
+and the name of interest.
+
+The way that the name server answers the query depends upon whether it
+is operating in recursive mode or not:
+
+ - The simplest mode for the server is non-recursive, since it
+ can answer queries using only local information: the response
+ contains an error, the answer, or a referral to some other
+ server "closer" to the answer. All name servers must
+ implement non-recursive queries.
+
+ - The simplest mode for the client is recursive, since in this
+ mode the name server acts in the role of a resolver and
+ returns either an error or the answer, but never referrals.
+ This service is optional in a name server, and the name server
+ may also choose to restrict the clients which can use
+ recursive mode.
+
+Recursive service is helpful in several situations:
+
+ - a relatively simple requester that lacks the ability to use
+ anything other than a direct answer to the question.
+
+ - a request that needs to cross protocol or other boundaries and
+ can be sent to a server which can act as intermediary.
+
+ - a network where we want to concentrate the cache rather than
+ having a separate cache for each client.
+
+Non-recursive service is appropriate if the requester is capable of
+pursuing referrals and interested in information which will aid future
+requests.
+
+The use of recursive mode is limited to cases where both the client and
+the name server agree to its use. The agreement is negotiated through
+the use of two bits in query and response messages:
+
+ - The recursion available, or RA bit, is set or cleared by a
+ name server in all responses. The bit is true if the name
+ server is willing to provide recursive service for the client,
+ regardless of whether the client requested recursive service.
+ That is, RA signals availability rather than use.
+
+
+
+Mockapetris [Page 22]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+ - Queries contain a bit called recursion desired or RD. This
+ bit specifies specifies whether the requester wants recursive
+ service for this query. Clients may request recursive service
+ from any name server, though they should depend upon receiving
+ it only from servers which have previously sent an RA, or
+ servers which have agreed to provide service through private
+ agreement or some other means outside of the DNS protocol.
+
+The recursive mode occurs when a query with RD set arrives at a server
+which is willing to provide recursive service; the client can verify
+that recursive mode was used by checking that both RA and RD are set in
+the reply. Note that the name server should never perform recursive
+service unless asked via RD, since this interferes with trouble shooting
+of name servers and their databases.
+
+If recursive service is requested and available, the recursive response
+to a query will be one of the following:
+
+ - The answer to the query, possibly preface by one or more CNAME
+ RRs that specify aliases encountered on the way to an answer.
+
+ - A name error indicating that the name does not exist. This
+ may include CNAME RRs that indicate that the original query
+ name was an alias for a name which does not exist.
+
+ - A temporary error indication.
+
+If recursive service is not requested or is not available, the non-
+recursive response will be one of the following:
+
+ - An authoritative name error indicating that the name does not
+ exist.
+
+ - A temporary error indication.
+
+ - Some combination of:
+
+ RRs that answer the question, together with an indication
+ whether the data comes from a zone or is cached.
+
+ A referral to name servers which have zones which are closer
+ ancestors to the name than the server sending the reply.
+
+ - RRs that the name server thinks will prove useful to the
+ requester.
+
+
+
+
+
+
+Mockapetris [Page 23]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+4.3.2. Algorithm
+
+The actual algorithm used by the name server will depend on the local OS
+and data structures used to store RRs. The following algorithm assumes
+that the RRs are organized in several tree structures, one for each
+zone, and another for the cache:
+
+ 1. Set or clear the value of recursion available in the response
+ depending on whether the name server is willing to provide
+ recursive service. If recursive service is available and
+ requested via the RD bit in the query, go to step 5,
+ otherwise step 2.
+
+ 2. Search the available zones for the zone which is the nearest
+ ancestor to QNAME. If such a zone is found, go to step 3,
+ otherwise step 4.
+
+ 3. Start matching down, label by label, in the zone. The
+ matching process can terminate several ways:
+
+ a. If the whole of QNAME is matched, we have found the
+ node.
+
+ If the data at the node is a CNAME, and QTYPE doesn't
+ match CNAME, copy the CNAME RR into the answer section
+ of the response, change QNAME to the canonical name in
+ the CNAME RR, and go back to step 1.
+
+ Otherwise, copy all RRs which match QTYPE into the
+ answer section and go to step 6.
+
+ b. If a match would take us out of the authoritative data,
+ we have a referral. This happens when we encounter a
+ node with NS RRs marking cuts along the bottom of a
+ zone.
+
+ Copy the NS RRs for the subzone into the authority
+ section of the reply. Put whatever addresses are
+ available into the additional section, using glue RRs
+ if the addresses are not available from authoritative
+ data or the cache. Go to step 4.
+
+ c. If at some label, a match is impossible (i.e., the
+ corresponding label does not exist), look to see if a
+ the "*" label exists.
+
+ If the "*" label does not exist, check whether the name
+ we are looking for is the original QNAME in the query
+
+
+
+Mockapetris [Page 24]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+ or a name we have followed due to a CNAME. If the name
+ is original, set an authoritative name error in the
+ response and exit. Otherwise just exit.
+
+ If the "*" label does exist, match RRs at that node
+ against QTYPE. If any match, copy them into the answer
+ section, but set the owner of the RR to be QNAME, and
+ not the node with the "*" label. Go to step 6.
+
+ 4. Start matching down in the cache. If QNAME is found in the
+ cache, copy all RRs attached to it that match QTYPE into the
+ answer section. If there was no delegation from
+ authoritative data, look for the best one from the cache, and
+ put it in the authority section. Go to step 6.
+
+ 5. Using the local resolver or a copy of its algorithm (see
+ resolver section of this memo) to answer the query. Store
+ the results, including any intermediate CNAMEs, in the answer
+ section of the response.
+
+ 6. Using local data only, attempt to add other RRs which may be
+ useful to the additional section of the query. Exit.
+
+4.3.3. Wildcards
+
+In the previous algorithm, special treatment was given to RRs with owner
+names starting with the label "*". Such RRs are called wildcards.
+Wildcard RRs can be thought of as instructions for synthesizing RRs.
+When the appropriate conditions are met, the name server creates RRs
+with an owner name equal to the query name and contents taken from the
+wildcard RRs.
+
+This facility is most often used to create a zone which will be used to
+forward mail from the Internet to some other mail system. The general
+idea is that any name in that zone which is presented to server in a
+query will be assumed to exist, with certain properties, unless explicit
+evidence exists to the contrary. Note that the use of the term zone
+here, instead of domain, is intentional; such defaults do not propagate
+across zone boundaries, although a subzone may choose to achieve that
+appearance by setting up similar defaults.
+
+The contents of the wildcard RRs follows the usual rules and formats for
+RRs. The wildcards in the zone have an owner name that controls the
+query names they will match. The owner name of the wildcard RRs is of
+the form "*.<anydomain>", where <anydomain> is any domain name.
+<anydomain> should not contain other * labels, and should be in the
+authoritative data of the zone. The wildcards potentially apply to
+descendants of <anydomain>, but not to <anydomain> itself. Another way
+
+
+
+Mockapetris [Page 25]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+to look at this is that the "*" label always matches at least one whole
+label and sometimes more, but always whole labels.
+
+Wildcard RRs do not apply:
+
+ - When the query is in another zone. That is, delegation cancels
+ the wildcard defaults.
+
+ - When the query name or a name between the wildcard domain and
+ the query name is know to exist. For example, if a wildcard
+ RR has an owner name of "*.X", and the zone also contains RRs
+ attached to B.X, the wildcards would apply to queries for name
+ Z.X (presuming there is no explicit information for Z.X), but
+ not to B.X, A.B.X, or X.
+
+A * label appearing in a query name has no special effect, but can be
+used to test for wildcards in an authoritative zone; such a query is the
+only way to get a response containing RRs with an owner name with * in
+it. The result of such a query should not be cached.
+
+Note that the contents of the wildcard RRs are not modified when used to
+synthesize RRs.
+
+To illustrate the use of wildcard RRs, suppose a large company with a
+large, non-IP/TCP, network wanted to create a mail gateway. If the
+company was called X.COM, and IP/TCP capable gateway machine was called
+A.X.COM, the following RRs might be entered into the COM zone:
+
+ X.COM MX 10 A.X.COM
+
+ *.X.COM MX 10 A.X.COM
+
+ A.X.COM A 1.2.3.4
+ A.X.COM MX 10 A.X.COM
+
+ *.A.X.COM MX 10 A.X.COM
+
+This would cause any MX query for any domain name ending in X.COM to
+return an MX RR pointing at A.X.COM. Two wildcard RRs are required
+since the effect of the wildcard at *.X.COM is inhibited in the A.X.COM
+subtree by the explicit data for A.X.COM. Note also that the explicit
+MX data at X.COM and A.X.COM is required, and that none of the RRs above
+would match a query name of XX.COM.
+
+4.3.4. Negative response caching (Optional)
+
+The DNS provides an optional service which allows name servers to
+distribute, and resolvers to cache, negative results with TTLs. For
+
+
+
+Mockapetris [Page 26]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+example, a name server can distribute a TTL along with a name error
+indication, and a resolver receiving such information is allowed to
+assume that the name does not exist during the TTL period without
+consulting authoritative data. Similarly, a resolver can make a query
+with a QTYPE which matches multiple types, and cache the fact that some
+of the types are not present.
+
+This feature can be particularly important in a system which implements
+naming shorthands that use search lists beacuse a popular shorthand,
+which happens to require a suffix toward the end of the search list,
+will generate multiple name errors whenever it is used.
+
+The method is that a name server may add an SOA RR to the additional
+section of a response when that response is authoritative. The SOA must
+be that of the zone which was the source of the authoritative data in
+the answer section, or name error if applicable. The MINIMUM field of
+the SOA controls the length of time that the negative result may be
+cached.
+
+Note that in some circumstances, the answer section may contain multiple
+owner names. In this case, the SOA mechanism should only be used for
+the data which matches QNAME, which is the only authoritative data in
+this section.
+
+Name servers and resolvers should never attempt to add SOAs to the
+additional section of a non-authoritative response, or attempt to infer
+results which are not directly stated in an authoritative response.
+There are several reasons for this, including: cached information isn't
+usually enough to match up RRs and their zone names, SOA RRs may be
+cached due to direct SOA queries, and name servers are not required to
+output the SOAs in the authority section.
+
+This feature is optional, although a refined version is expected to
+become part of the standard protocol in the future. Name servers are
+not required to add the SOA RRs in all authoritative responses, nor are
+resolvers required to cache negative results. Both are recommended.
+All resolvers and recursive name servers are required to at least be
+able to ignore the SOA RR when it is present in a response.
+
+Some experiments have also been proposed which will use this feature.
+The idea is that if cached data is known to come from a particular zone,
+and if an authoritative copy of the zone's SOA is obtained, and if the
+zone's SERIAL has not changed since the data was cached, then the TTL of
+the cached data can be reset to the zone MINIMUM value if it is smaller.
+This usage is mentioned for planning purposes only, and is not
+recommended as yet.
+
+
+
+
+
+Mockapetris [Page 27]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+4.3.5. Zone maintenance and transfers
+
+Part of the job of a zone administrator is to maintain the zones at all
+of the name servers which are authoritative for the zone. When the
+inevitable changes are made, they must be distributed to all of the name
+servers. While this distribution can be accomplished using FTP or some
+other ad hoc procedure, the preferred method is the zone transfer part
+of the DNS protocol.
+
+The general model of automatic zone transfer or refreshing is that one
+of the name servers is the master or primary for the zone. Changes are
+coordinated at the primary, typically by editing a master file for the
+zone. After editing, the administrator signals the master server to
+load the new zone. The other non-master or secondary servers for the
+zone periodically check for changes (at a selectable interval) and
+obtain new zone copies when changes have been made.
+
+To detect changes, secondaries just check the SERIAL field of the SOA
+for the zone. In addition to whatever other changes are made, the
+SERIAL field in the SOA of the zone is always advanced whenever any
+change is made to the zone. The advancing can be a simple increment, or
+could be based on the write date and time of the master file, etc. The
+purpose is to make it possible to determine which of two copies of a
+zone is more recent by comparing serial numbers. Serial number advances
+and comparisons use sequence space arithmetic, so there is a theoretic
+limit on how fast a zone can be updated, basically that old copies must
+die out before the serial number covers half of its 32 bit range. In
+practice, the only concern is that the compare operation deals properly
+with comparisons around the boundary between the most positive and most
+negative 32 bit numbers.
+
+The periodic polling of the secondary servers is controlled by
+parameters in the SOA RR for the zone, which set the minimum acceptable
+polling intervals. The parameters are called REFRESH, RETRY, and
+EXPIRE. Whenever a new zone is loaded in a secondary, the secondary
+waits REFRESH seconds before checking with the primary for a new serial.
+If this check cannot be completed, new checks are started every RETRY
+seconds. The check is a simple query to the primary for the SOA RR of
+the zone. If the serial field in the secondary's zone copy is equal to
+the serial returned by the primary, then no changes have occurred, and
+the REFRESH interval wait is restarted. If the secondary finds it
+impossible to perform a serial check for the EXPIRE interval, it must
+assume that its copy of the zone is obsolete an discard it.
+
+When the poll shows that the zone has changed, then the secondary server
+must request a zone transfer via an AXFR request for the zone. The AXFR
+may cause an error, such as refused, but normally is answered by a
+sequence of response messages. The first and last messages must contain
+
+
+
+Mockapetris [Page 28]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+the data for the top authoritative node of the zone. Intermediate
+messages carry all of the other RRs from the zone, including both
+authoritative and non-authoritative RRs. The stream of messages allows
+the secondary to construct a copy of the zone. Because accuracy is
+essential, TCP or some other reliable protocol must be used for AXFR
+requests.
+
+Each secondary server is required to perform the following operations
+against the master, but may also optionally perform these operations
+against other secondary servers. This strategy can improve the transfer
+process when the primary is unavailable due to host downtime or network
+problems, or when a secondary server has better network access to an
+"intermediate" secondary than to the primary.
+
+5. RESOLVERS
+
+5.1. Introduction
+
+Resolvers are programs that interface user programs to domain name
+servers. In the simplest case, a resolver receives a request from a
+user program (e.g., mail programs, TELNET, FTP) in the form of a
+subroutine call, system call etc., and returns the desired information
+in a form compatible with the local host's data formats.
+
+The resolver is located on the same machine as the program that requests
+the resolver's services, but it may need to consult name servers on
+other hosts. Because a resolver may need to consult several name
+servers, or may have the requested information in a local cache, the
+amount of time that a resolver will take to complete can vary quite a
+bit, from milliseconds to several seconds.
+
+A very important goal of the resolver is to eliminate network delay and
+name server load from most requests by answering them from its cache of
+prior results. It follows that caches which are shared by multiple
+processes, users, machines, etc., are more efficient than non-shared
+caches.
+
+5.2. Client-resolver interface
+
+5.2.1. Typical functions
+
+The client interface to the resolver is influenced by the local host's
+conventions, but the typical resolver-client interface has three
+functions:
+
+ 1. Host name to host address translation.
+
+ This function is often defined to mimic a previous HOSTS.TXT
+
+
+
+Mockapetris [Page 29]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+ based function. Given a character string, the caller wants
+ one or more 32 bit IP addresses. Under the DNS, it
+ translates into a request for type A RRs. Since the DNS does
+ not preserve the order of RRs, this function may choose to
+ sort the returned addresses or select the "best" address if
+ the service returns only one choice to the client. Note that
+ a multiple address return is recommended, but a single
+ address may be the only way to emulate prior HOSTS.TXT
+ services.
+
+ 2. Host address to host name translation
+
+ This function will often follow the form of previous
+ functions. Given a 32 bit IP address, the caller wants a
+ character string. The octets of the IP address are reversed,
+ used as name components, and suffixed with "IN-ADDR.ARPA". A
+ type PTR query is used to get the RR with the primary name of
+ the host. For example, a request for the host name
+ corresponding to IP address 1.2.3.4 looks for PTR RRs for
+ domain name "4.3.2.1.IN-ADDR.ARPA".
+
+ 3. General lookup function
+
+ This function retrieves arbitrary information from the DNS,
+ and has no counterpart in previous systems. The caller
+ supplies a QNAME, QTYPE, and QCLASS, and wants all of the
+ matching RRs. This function will often use the DNS format
+ for all RR data instead of the local host's, and returns all
+ RR content (e.g., TTL) instead of a processed form with local
+ quoting conventions.
+
+When the resolver performs the indicated function, it usually has one of
+the following results to pass back to the client:
+
+ - One or more RRs giving the requested data.
+
+ In this case the resolver returns the answer in the
+ appropriate format.
+
+ - A name error (NE).
+
+ This happens when the referenced name does not exist. For
+ example, a user may have mistyped a host name.
+
+ - A data not found error.
+
+ This happens when the referenced name exists, but data of the
+ appropriate type does not. For example, a host address
+
+
+
+Mockapetris [Page 30]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+ function applied to a mailbox name would return this error
+ since the name exists, but no address RR is present.
+
+It is important to note that the functions for translating between host
+names and addresses may combine the "name error" and "data not found"
+error conditions into a single type of error return, but the general
+function should not. One reason for this is that applications may ask
+first for one type of information about a name followed by a second
+request to the same name for some other type of information; if the two
+errors are combined, then useless queries may slow the application.
+
+5.2.2. Aliases
+
+While attempting to resolve a particular request, the resolver may find
+that the name in question is an alias. For example, the resolver might
+find that the name given for host name to address translation is an
+alias when it finds the CNAME RR. If possible, the alias condition
+should be signalled back from the resolver to the client.
+
+In most cases a resolver simply restarts the query at the new name when
+it encounters a CNAME. However, when performing the general function,
+the resolver should not pursue aliases when the CNAME RR matches the
+query type. This allows queries which ask whether an alias is present.
+For example, if the query type is CNAME, the user is interested in the
+CNAME RR itself, and not the RRs at the name it points to.
+
+Several special conditions can occur with aliases. Multiple levels of
+aliases should be avoided due to their lack of efficiency, but should
+not be signalled as an error. Alias loops and aliases which point to
+non-existent names should be caught and an error condition passed back
+to the client.
+
+5.2.3. Temporary failures
+
+In a less than perfect world, all resolvers will occasionally be unable
+to resolve a particular request. This condition can be caused by a
+resolver which becomes separated from the rest of the network due to a
+link failure or gateway problem, or less often by coincident failure or
+unavailability of all servers for a particular domain.
+
+It is essential that this sort of condition should not be signalled as a
+name or data not present error to applications. This sort of behavior
+is annoying to humans, and can wreak havoc when mail systems use the
+DNS.
+
+While in some cases it is possible to deal with such a temporary problem
+by blocking the request indefinitely, this is usually not a good choice,
+particularly when the client is a server process that could move on to
+
+
+
+Mockapetris [Page 31]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+other tasks. The recommended solution is to always have temporary
+failure as one of the possible results of a resolver function, even
+though this may make emulation of existing HOSTS.TXT functions more
+difficult.
+
+5.3. Resolver internals
+
+Every resolver implementation uses slightly different algorithms, and
+typically spends much more logic dealing with errors of various sorts
+than typical occurances. This section outlines a recommended basic
+strategy for resolver operation, but leaves details to [RFC-1035].
+
+5.3.1. Stub resolvers
+
+One option for implementing a resolver is to move the resolution
+function out of the local machine and into a name server which supports
+recursive queries. This can provide an easy method of providing domain
+service in a PC which lacks the resources to perform the resolver
+function, or can centralize the cache for a whole local network or
+organization.
+
+All that the remaining stub needs is a list of name server addresses
+that will perform the recursive requests. This type of resolver
+presumably needs the information in a configuration file, since it
+probably lacks the sophistication to locate it in the domain database.
+The user also needs to verify that the listed servers will perform the
+recursive service; a name server is free to refuse to perform recursive
+services for any or all clients. The user should consult the local
+system administrator to find name servers willing to perform the
+service.
+
+This type of service suffers from some drawbacks. Since the recursive
+requests may take an arbitrary amount of time to perform, the stub may
+have difficulty optimizing retransmission intervals to deal with both
+lost UDP packets and dead servers; the name server can be easily
+overloaded by too zealous a stub if it interprets retransmissions as new
+requests. Use of TCP may be an answer, but TCP may well place burdens
+on the host's capabilities which are similar to those of a real
+resolver.
+
+5.3.2. Resources
+
+In addition to its own resources, the resolver may also have shared
+access to zones maintained by a local name server. This gives the
+resolver the advantage of more rapid access, but the resolver must be
+careful to never let cached information override zone data. In this
+discussion the term "local information" is meant to mean the union of
+the cache and such shared zones, with the understanding that
+
+
+
+Mockapetris [Page 32]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+authoritative data is always used in preference to cached data when both
+are present.
+
+The following resolver algorithm assumes that all functions have been
+converted to a general lookup function, and uses the following data
+structures to represent the state of a request in progress in the
+resolver:
+
+SNAME the domain name we are searching for.
+
+STYPE the QTYPE of the search request.
+
+SCLASS the QCLASS of the search request.
+
+SLIST a structure which describes the name servers and the
+ zone which the resolver is currently trying to query.
+ This structure keeps track of the resolver's current
+ best guess about which name servers hold the desired
+ information; it is updated when arriving information
+ changes the guess. This structure includes the
+ equivalent of a zone name, the known name servers for
+ the zone, the known addresses for the name servers, and
+ history information which can be used to suggest which
+ server is likely to be the best one to try next. The
+ zone name equivalent is a match count of the number of
+ labels from the root down which SNAME has in common with
+ the zone being queried; this is used as a measure of how
+ "close" the resolver is to SNAME.
+
+SBELT a "safety belt" structure of the same form as SLIST,
+ which is initialized from a configuration file, and
+ lists servers which should be used when the resolver
+ doesn't have any local information to guide name server
+ selection. The match count will be -1 to indicate that
+ no labels are known to match.
+
+CACHE A structure which stores the results from previous
+ responses. Since resolvers are responsible for
+ discarding old RRs whose TTL has expired, most
+ implementations convert the interval specified in
+ arriving RRs to some sort of absolute time when the RR
+ is stored in the cache. Instead of counting the TTLs
+ down individually, the resolver just ignores or discards
+ old RRs when it runs across them in the course of a
+ search, or discards them during periodic sweeps to
+ reclaim the memory consumed by old RRs.
+
+
+
+
+
+Mockapetris [Page 33]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+5.3.3. Algorithm
+
+The top level algorithm has four steps:
+
+ 1. See if the answer is in local information, and if so return
+ it to the client.
+
+ 2. Find the best servers to ask.
+
+ 3. Send them queries until one returns a response.
+
+ 4. Analyze the response, either:
+
+ a. if the response answers the question or contains a name
+ error, cache the data as well as returning it back to
+ the client.
+
+ b. if the response contains a better delegation to other
+ servers, cache the delegation information, and go to
+ step 2.
+
+ c. if the response shows a CNAME and that is not the
+ answer itself, cache the CNAME, change the SNAME to the
+ canonical name in the CNAME RR and go to step 1.
+
+ d. if the response shows a servers failure or other
+ bizarre contents, delete the server from the SLIST and
+ go back to step 3.
+
+Step 1 searches the cache for the desired data. If the data is in the
+cache, it is assumed to be good enough for normal use. Some resolvers
+have an option at the user interface which will force the resolver to
+ignore the cached data and consult with an authoritative server. This
+is not recommended as the default. If the resolver has direct access to
+a name server's zones, it should check to see if the desired data is
+present in authoritative form, and if so, use the authoritative data in
+preference to cached data.
+
+Step 2 looks for a name server to ask for the required data. The
+general strategy is to look for locally-available name server RRs,
+starting at SNAME, then the parent domain name of SNAME, the
+grandparent, and so on toward the root. Thus if SNAME were
+Mockapetris.ISI.EDU, this step would look for NS RRs for
+Mockapetris.ISI.EDU, then ISI.EDU, then EDU, and then . (the root).
+These NS RRs list the names of hosts for a zone at or above SNAME. Copy
+the names into SLIST. Set up their addresses using local data. It may
+be the case that the addresses are not available. The resolver has many
+choices here; the best is to start parallel resolver processes looking
+
+
+
+Mockapetris [Page 34]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+for the addresses while continuing onward with the addresses which are
+available. Obviously, the design choices and options are complicated
+and a function of the local host's capabilities. The recommended
+priorities for the resolver designer are:
+
+ 1. Bound the amount of work (packets sent, parallel processes
+ started) so that a request can't get into an infinite loop or
+ start off a chain reaction of requests or queries with other
+ implementations EVEN IF SOMEONE HAS INCORRECTLY CONFIGURED
+ SOME DATA.
+
+ 2. Get back an answer if at all possible.
+
+ 3. Avoid unnecessary transmissions.
+
+ 4. Get the answer as quickly as possible.
+
+If the search for NS RRs fails, then the resolver initializes SLIST from
+the safety belt SBELT. The basic idea is that when the resolver has no
+idea what servers to ask, it should use information from a configuration
+file that lists several servers which are expected to be helpful.
+Although there are special situations, the usual choice is two of the
+root servers and two of the servers for the host's domain. The reason
+for two of each is for redundancy. The root servers will provide
+eventual access to all of the domain space. The two local servers will
+allow the resolver to continue to resolve local names if the local
+network becomes isolated from the internet due to gateway or link
+failure.
+
+In addition to the names and addresses of the servers, the SLIST data
+structure can be sorted to use the best servers first, and to insure
+that all addresses of all servers are used in a round-robin manner. The
+sorting can be a simple function of preferring addresses on the local
+network over others, or may involve statistics from past events, such as
+previous response times and batting averages.
+
+Step 3 sends out queries until a response is received. The strategy is
+to cycle around all of the addresses for all of the servers with a
+timeout between each transmission. In practice it is important to use
+all addresses of a multihomed host, and too aggressive a retransmission
+policy actually slows response when used by multiple resolvers
+contending for the same name server and even occasionally for a single
+resolver. SLIST typically contains data values to control the timeouts
+and keep track of previous transmissions.
+
+Step 4 involves analyzing responses. The resolver should be highly
+paranoid in its parsing of responses. It should also check that the
+response matches the query it sent using the ID field in the response.
+
+
+
+Mockapetris [Page 35]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+The ideal answer is one from a server authoritative for the query which
+either gives the required data or a name error. The data is passed back
+to the user and entered in the cache for future use if its TTL is
+greater than zero.
+
+If the response shows a delegation, the resolver should check to see
+that the delegation is "closer" to the answer than the servers in SLIST
+are. This can be done by comparing the match count in SLIST with that
+computed from SNAME and the NS RRs in the delegation. If not, the reply
+is bogus and should be ignored. If the delegation is valid the NS
+delegation RRs and any address RRs for the servers should be cached.
+The name servers are entered in the SLIST, and the search is restarted.
+
+If the response contains a CNAME, the search is restarted at the CNAME
+unless the response has the data for the canonical name or if the CNAME
+is the answer itself.
+
+Details and implementation hints can be found in [RFC-1035].
+
+6. A SCENARIO
+
+In our sample domain space, suppose we wanted separate administrative
+control for the root, MIL, EDU, MIT.EDU and ISI.EDU zones. We might
+allocate name servers as follows:
+
+
+ |(C.ISI.EDU,SRI-NIC.ARPA
+ | A.ISI.EDU)
+ +---------------------+------------------+
+ | | |
+ MIL EDU ARPA
+ |(SRI-NIC.ARPA, |(SRI-NIC.ARPA, |
+ | A.ISI.EDU | C.ISI.EDU) |
+ +-----+-----+ | +------+-----+-----+
+ | | | | | | |
+ BRL NOSC DARPA | IN-ADDR SRI-NIC ACC
+ |
+ +--------+------------------+---------------+--------+
+ | | | | |
+ UCI MIT | UDEL YALE
+ |(XX.LCS.MIT.EDU, ISI
+ |ACHILLES.MIT.EDU) |(VAXA.ISI.EDU,VENERA.ISI.EDU,
+ +---+---+ | A.ISI.EDU)
+ | | |
+ LCS ACHILLES +--+-----+-----+--------+
+ | | | | | |
+ XX A C VAXA VENERA Mockapetris
+
+
+
+
+Mockapetris [Page 36]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+In this example, the authoritative name server is shown in parentheses
+at the point in the domain tree at which is assumes control.
+
+Thus the root name servers are on C.ISI.EDU, SRI-NIC.ARPA, and
+A.ISI.EDU. The MIL domain is served by SRI-NIC.ARPA and A.ISI.EDU. The
+EDU domain is served by SRI-NIC.ARPA. and C.ISI.EDU. Note that servers
+may have zones which are contiguous or disjoint. In this scenario,
+C.ISI.EDU has contiguous zones at the root and EDU domains. A.ISI.EDU
+has contiguous zones at the root and MIL domains, but also has a non-
+contiguous zone at ISI.EDU.
+
+6.1. C.ISI.EDU name server
+
+C.ISI.EDU is a name server for the root, MIL, and EDU domains of the IN
+class, and would have zones for these domains. The zone data for the
+root domain might be:
+
+ . IN SOA SRI-NIC.ARPA. HOSTMASTER.SRI-NIC.ARPA. (
+ 870611 ;serial
+ 1800 ;refresh every 30 min
+ 300 ;retry every 5 min
+ 604800 ;expire after a week
+ 86400) ;minimum of a day
+ NS A.ISI.EDU.
+ NS C.ISI.EDU.
+ NS SRI-NIC.ARPA.
+
+ MIL. 86400 NS SRI-NIC.ARPA.
+ 86400 NS A.ISI.EDU.
+
+ EDU. 86400 NS SRI-NIC.ARPA.
+ 86400 NS C.ISI.EDU.
+
+ SRI-NIC.ARPA. A 26.0.0.73
+ A 10.0.0.51
+ MX 0 SRI-NIC.ARPA.
+ HINFO DEC-2060 TOPS20
+
+ ACC.ARPA. A 26.6.0.65
+ HINFO PDP-11/70 UNIX
+ MX 10 ACC.ARPA.
+
+ USC-ISIC.ARPA. CNAME C.ISI.EDU.
+
+ 73.0.0.26.IN-ADDR.ARPA. PTR SRI-NIC.ARPA.
+ 65.0.6.26.IN-ADDR.ARPA. PTR ACC.ARPA.
+ 51.0.0.10.IN-ADDR.ARPA. PTR SRI-NIC.ARPA.
+ 52.0.0.10.IN-ADDR.ARPA. PTR C.ISI.EDU.
+
+
+
+Mockapetris [Page 37]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+ 103.0.3.26.IN-ADDR.ARPA. PTR A.ISI.EDU.
+
+ A.ISI.EDU. 86400 A 26.3.0.103
+ C.ISI.EDU. 86400 A 10.0.0.52
+
+This data is represented as it would be in a master file. Most RRs are
+single line entries; the sole exception here is the SOA RR, which uses
+"(" to start a multi-line RR and ")" to show the end of a multi-line RR.
+Since the class of all RRs in a zone must be the same, only the first RR
+in a zone need specify the class. When a name server loads a zone, it
+forces the TTL of all authoritative RRs to be at least the MINIMUM field
+of the SOA, here 86400 seconds, or one day. The NS RRs marking
+delegation of the MIL and EDU domains, together with the glue RRs for
+the servers host addresses, are not part of the authoritative data in
+the zone, and hence have explicit TTLs.
+
+Four RRs are attached to the root node: the SOA which describes the root
+zone and the 3 NS RRs which list the name servers for the root. The
+data in the SOA RR describes the management of the zone. The zone data
+is maintained on host SRI-NIC.ARPA, and the responsible party for the
+zone is HOSTMASTER at SRI-NIC.ARPA. A key item in the SOA is the 86400
+second minimum TTL, which means that all authoritative data in the zone
+has at least that TTL, although higher values may be explicitly
+specified.
+
+The NS RRs for the MIL and EDU domains mark the boundary between the
+root zone and the MIL and EDU zones. Note that in this example, the
+lower zones happen to be supported by name servers which also support
+the root zone.
+
+The master file for the EDU zone might be stated relative to the origin
+EDU. The zone data for the EDU domain might be:
+
+ EDU. IN SOA SRI-NIC.ARPA. HOSTMASTER.SRI-NIC.ARPA. (
+ 870729 ;serial
+ 1800 ;refresh every 30 minutes
+ 300 ;retry every 5 minutes
+ 604800 ;expire after a week
+ 86400 ;minimum of a day
+ )
+ NS SRI-NIC.ARPA.
+ NS C.ISI.EDU.
+
+ UCI 172800 NS ICS.UCI
+ 172800 NS ROME.UCI
+ ICS.UCI 172800 A 192.5.19.1
+ ROME.UCI 172800 A 192.5.19.31
+
+
+
+
+Mockapetris [Page 38]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+ ISI 172800 NS VAXA.ISI
+ 172800 NS A.ISI
+ 172800 NS VENERA.ISI.EDU.
+ VAXA.ISI 172800 A 10.2.0.27
+ 172800 A 128.9.0.33
+ VENERA.ISI.EDU. 172800 A 10.1.0.52
+ 172800 A 128.9.0.32
+ A.ISI 172800 A 26.3.0.103
+
+ UDEL.EDU. 172800 NS LOUIE.UDEL.EDU.
+ 172800 NS UMN-REI-UC.ARPA.
+ LOUIE.UDEL.EDU. 172800 A 10.0.0.96
+ 172800 A 192.5.39.3
+
+ YALE.EDU. 172800 NS YALE.ARPA.
+ YALE.EDU. 172800 NS YALE-BULLDOG.ARPA.
+
+ MIT.EDU. 43200 NS XX.LCS.MIT.EDU.
+ 43200 NS ACHILLES.MIT.EDU.
+ XX.LCS.MIT.EDU. 43200 A 10.0.0.44
+ ACHILLES.MIT.EDU. 43200 A 18.72.0.8
+
+Note the use of relative names here. The owner name for the ISI.EDU. is
+stated using a relative name, as are two of the name server RR contents.
+Relative and absolute domain names may be freely intermixed in a master
+
+6.2. Example standard queries
+
+The following queries and responses illustrate name server behavior.
+Unless otherwise noted, the queries do not have recursion desired (RD)
+in the header. Note that the answers to non-recursive queries do depend
+on the server being asked, but do not depend on the identity of the
+requester.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris [Page 39]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+6.2.1. QNAME=SRI-NIC.ARPA, QTYPE=A
+
+The query would look like:
+
+ +---------------------------------------------------+
+ Header | OPCODE=SQUERY |
+ +---------------------------------------------------+
+ Question | QNAME=SRI-NIC.ARPA., QCLASS=IN, QTYPE=A |
+ +---------------------------------------------------+
+ Answer | <empty> |
+ +---------------------------------------------------+
+ Authority | <empty> |
+ +---------------------------------------------------+
+ Additional | <empty> |
+ +---------------------------------------------------+
+
+The response from C.ISI.EDU would be:
+
+ +---------------------------------------------------+
+ Header | OPCODE=SQUERY, RESPONSE, AA |
+ +---------------------------------------------------+
+ Question | QNAME=SRI-NIC.ARPA., QCLASS=IN, QTYPE=A |
+ +---------------------------------------------------+
+ Answer | SRI-NIC.ARPA. 86400 IN A 26.0.0.73 |
+ | 86400 IN A 10.0.0.51 |
+ +---------------------------------------------------+
+ Authority | <empty> |
+ +---------------------------------------------------+
+ Additional | <empty> |
+ +---------------------------------------------------+
+
+The header of the response looks like the header of the query, except
+that the RESPONSE bit is set, indicating that this message is a
+response, not a query, and the Authoritative Answer (AA) bit is set
+indicating that the address RRs in the answer section are from
+authoritative data. The question section of the response matches the
+question section of the query.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris [Page 40]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+If the same query was sent to some other server which was not
+authoritative for SRI-NIC.ARPA, the response might be:
+
+ +---------------------------------------------------+
+ Header | OPCODE=SQUERY,RESPONSE |
+ +---------------------------------------------------+
+ Question | QNAME=SRI-NIC.ARPA., QCLASS=IN, QTYPE=A |
+ +---------------------------------------------------+
+ Answer | SRI-NIC.ARPA. 1777 IN A 10.0.0.51 |
+ | 1777 IN A 26.0.0.73 |
+ +---------------------------------------------------+
+ Authority | <empty> |
+ +---------------------------------------------------+
+ Additional | <empty> |
+ +---------------------------------------------------+
+
+This response is different from the previous one in two ways: the header
+does not have AA set, and the TTLs are different. The inference is that
+the data did not come from a zone, but from a cache. The difference
+between the authoritative TTL and the TTL here is due to aging of the
+data in a cache. The difference in ordering of the RRs in the answer
+section is not significant.
+
+6.2.2. QNAME=SRI-NIC.ARPA, QTYPE=*
+
+A query similar to the previous one, but using a QTYPE of *, would
+receive the following response from C.ISI.EDU:
+
+ +---------------------------------------------------+
+ Header | OPCODE=SQUERY, RESPONSE, AA |
+ +---------------------------------------------------+
+ Question | QNAME=SRI-NIC.ARPA., QCLASS=IN, QTYPE=* |
+ +---------------------------------------------------+
+ Answer | SRI-NIC.ARPA. 86400 IN A 26.0.0.73 |
+ | A 10.0.0.51 |
+ | MX 0 SRI-NIC.ARPA. |
+ | HINFO DEC-2060 TOPS20 |
+ +---------------------------------------------------+
+ Authority | <empty> |
+ +---------------------------------------------------+
+ Additional | <empty> |
+ +---------------------------------------------------+
+
+
+
+
+
+
+
+
+
+Mockapetris [Page 41]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+If a similar query was directed to two name servers which are not
+authoritative for SRI-NIC.ARPA, the responses might be:
+
+ +---------------------------------------------------+
+ Header | OPCODE=SQUERY, RESPONSE |
+ +---------------------------------------------------+
+ Question | QNAME=SRI-NIC.ARPA., QCLASS=IN, QTYPE=* |
+ +---------------------------------------------------+
+ Answer | SRI-NIC.ARPA. 12345 IN A 26.0.0.73 |
+ | A 10.0.0.51 |
+ +---------------------------------------------------+
+ Authority | <empty> |
+ +---------------------------------------------------+
+ Additional | <empty> |
+ +---------------------------------------------------+
+
+and
+
+ +---------------------------------------------------+
+ Header | OPCODE=SQUERY, RESPONSE |
+ +---------------------------------------------------+
+ Question | QNAME=SRI-NIC.ARPA., QCLASS=IN, QTYPE=* |
+ +---------------------------------------------------+
+ Answer | SRI-NIC.ARPA. 1290 IN HINFO DEC-2060 TOPS20 |
+ +---------------------------------------------------+
+ Authority | <empty> |
+ +---------------------------------------------------+
+ Additional | <empty> |
+ +---------------------------------------------------+
+
+Neither of these answers have AA set, so neither response comes from
+authoritative data. The different contents and different TTLs suggest
+that the two servers cached data at different times, and that the first
+server cached the response to a QTYPE=A query and the second cached the
+response to a HINFO query.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris [Page 42]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+6.2.3. QNAME=SRI-NIC.ARPA, QTYPE=MX
+
+This type of query might be result from a mailer trying to look up
+routing information for the mail destination HOSTMASTER at SRI-NIC.ARPA.
+The response from C.ISI.EDU would be:
+
+ +---------------------------------------------------+
+ Header | OPCODE=SQUERY, RESPONSE, AA |
+ +---------------------------------------------------+
+ Question | QNAME=SRI-NIC.ARPA., QCLASS=IN, QTYPE=MX |
+ +---------------------------------------------------+
+ Answer | SRI-NIC.ARPA. 86400 IN MX 0 SRI-NIC.ARPA.|
+ +---------------------------------------------------+
+ Authority | <empty> |
+ +---------------------------------------------------+
+ Additional | SRI-NIC.ARPA. 86400 IN A 26.0.0.73 |
+ | A 10.0.0.51 |
+ +---------------------------------------------------+
+
+This response contains the MX RR in the answer section of the response.
+The additional section contains the address RRs because the name server
+at C.ISI.EDU guesses that the requester will need the addresses in order
+to properly use the information carried by the MX.
+
+6.2.4. QNAME=SRI-NIC.ARPA, QTYPE=NS
+
+C.ISI.EDU would reply to this query with:
+
+ +---------------------------------------------------+
+ Header | OPCODE=SQUERY, RESPONSE, AA |
+ +---------------------------------------------------+
+ Question | QNAME=SRI-NIC.ARPA., QCLASS=IN, QTYPE=NS |
+ +---------------------------------------------------+
+ Answer | <empty> |
+ +---------------------------------------------------+
+ Authority | <empty> |
+ +---------------------------------------------------+
+ Additional | <empty> |
+ +---------------------------------------------------+
+
+The only difference between the response and the query is the AA and
+RESPONSE bits in the header. The interpretation of this response is
+that the server is authoritative for the name, and the name exists, but
+no RRs of type NS are present there.
+
+6.2.5. QNAME=SIR-NIC.ARPA, QTYPE=A
+
+If a user mistyped a host name, we might see this type of query.
+
+
+
+Mockapetris [Page 43]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+C.ISI.EDU would answer it with:
+
+ +---------------------------------------------------+
+ Header | OPCODE=SQUERY, RESPONSE, AA, RCODE=NE |
+ +---------------------------------------------------+
+ Question | QNAME=SIR-NIC.ARPA., QCLASS=IN, QTYPE=A |
+ +---------------------------------------------------+
+ Answer | <empty> |
+ +---------------------------------------------------+
+ Authority | . SOA SRI-NIC.ARPA. HOSTMASTER.SRI-NIC.ARPA. |
+ | 870611 1800 300 604800 86400 |
+ +---------------------------------------------------+
+ Additional | <empty> |
+ +---------------------------------------------------+
+
+This response states that the name does not exist. This condition is
+signalled in the response code (RCODE) section of the header.
+
+The SOA RR in the authority section is the optional negative caching
+information which allows the resolver using this response to assume that
+the name will not exist for the SOA MINIMUM (86400) seconds.
+
+6.2.6. QNAME=BRL.MIL, QTYPE=A
+
+If this query is sent to C.ISI.EDU, the reply would be:
+
+ +---------------------------------------------------+
+ Header | OPCODE=SQUERY, RESPONSE |
+ +---------------------------------------------------+
+ Question | QNAME=BRL.MIL, QCLASS=IN, QTYPE=A |
+ +---------------------------------------------------+
+ Answer | <empty> |
+ +---------------------------------------------------+
+ Authority | MIL. 86400 IN NS SRI-NIC.ARPA. |
+ | 86400 NS A.ISI.EDU. |
+ +---------------------------------------------------+
+ Additional | A.ISI.EDU. A 26.3.0.103 |
+ | SRI-NIC.ARPA. A 26.0.0.73 |
+ | A 10.0.0.51 |
+ +---------------------------------------------------+
+
+This response has an empty answer section, but is not authoritative, so
+it is a referral. The name server on C.ISI.EDU, realizing that it is
+not authoritative for the MIL domain, has referred the requester to
+servers on A.ISI.EDU and SRI-NIC.ARPA, which it knows are authoritative
+for the MIL domain.
+
+
+
+
+
+Mockapetris [Page 44]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+6.2.7. QNAME=USC-ISIC.ARPA, QTYPE=A
+
+The response to this query from A.ISI.EDU would be:
+
+ +---------------------------------------------------+
+ Header | OPCODE=SQUERY, RESPONSE, AA |
+ +---------------------------------------------------+
+ Question | QNAME=USC-ISIC.ARPA., QCLASS=IN, QTYPE=A |
+ +---------------------------------------------------+
+ Answer | USC-ISIC.ARPA. 86400 IN CNAME C.ISI.EDU. |
+ | C.ISI.EDU. 86400 IN A 10.0.0.52 |
+ +---------------------------------------------------+
+ Authority | <empty> |
+ +---------------------------------------------------+
+ Additional | <empty> |
+ +---------------------------------------------------+
+
+Note that the AA bit in the header guarantees that the data matching
+QNAME is authoritative, but does not say anything about whether the data
+for C.ISI.EDU is authoritative. This complete reply is possible because
+A.ISI.EDU happens to be authoritative for both the ARPA domain where
+USC-ISIC.ARPA is found and the ISI.EDU domain where C.ISI.EDU data is
+found.
+
+If the same query was sent to C.ISI.EDU, its response might be the same
+as shown above if it had its own address in its cache, but might also
+be:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris [Page 45]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+ +---------------------------------------------------+
+ Header | OPCODE=SQUERY, RESPONSE, AA |
+ +---------------------------------------------------+
+ Question | QNAME=USC-ISIC.ARPA., QCLASS=IN, QTYPE=A |
+ +---------------------------------------------------+
+ Answer | USC-ISIC.ARPA. 86400 IN CNAME C.ISI.EDU. |
+ +---------------------------------------------------+
+ Authority | ISI.EDU. 172800 IN NS VAXA.ISI.EDU. |
+ | NS A.ISI.EDU. |
+ | NS VENERA.ISI.EDU. |
+ +---------------------------------------------------+
+ Additional | VAXA.ISI.EDU. 172800 A 10.2.0.27 |
+ | 172800 A 128.9.0.33 |
+ | VENERA.ISI.EDU. 172800 A 10.1.0.52 |
+ | 172800 A 128.9.0.32 |
+ | A.ISI.EDU. 172800 A 26.3.0.103 |
+ +---------------------------------------------------+
+
+This reply contains an authoritative reply for the alias USC-ISIC.ARPA,
+plus a referral to the name servers for ISI.EDU. This sort of reply
+isn't very likely given that the query is for the host name of the name
+server being asked, but would be common for other aliases.
+
+6.2.8. QNAME=USC-ISIC.ARPA, QTYPE=CNAME
+
+If this query is sent to either A.ISI.EDU or C.ISI.EDU, the reply would
+be:
+
+ +---------------------------------------------------+
+ Header | OPCODE=SQUERY, RESPONSE, AA |
+ +---------------------------------------------------+
+ Question | QNAME=USC-ISIC.ARPA., QCLASS=IN, QTYPE=A |
+ +---------------------------------------------------+
+ Answer | USC-ISIC.ARPA. 86400 IN CNAME C.ISI.EDU. |
+ +---------------------------------------------------+
+ Authority | <empty> |
+ +---------------------------------------------------+
+ Additional | <empty> |
+ +---------------------------------------------------+
+
+Because QTYPE=CNAME, the CNAME RR itself answers the query, and the name
+server doesn't attempt to look up anything for C.ISI.EDU. (Except
+possibly for the additional section.)
+
+6.3. Example resolution
+
+The following examples illustrate the operations a resolver must perform
+for its client. We assume that the resolver is starting without a
+
+
+
+Mockapetris [Page 46]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+cache, as might be the case after system boot. We further assume that
+the system is not one of the hosts in the data and that the host is
+located somewhere on net 26, and that its safety belt (SBELT) data
+structure has the following information:
+
+ Match count = -1
+ SRI-NIC.ARPA. 26.0.0.73 10.0.0.51
+ A.ISI.EDU. 26.3.0.103
+
+This information specifies servers to try, their addresses, and a match
+count of -1, which says that the servers aren't very close to the
+target. Note that the -1 isn't supposed to be an accurate closeness
+measure, just a value so that later stages of the algorithm will work.
+
+The following examples illustrate the use of a cache, so each example
+assumes that previous requests have completed.
+
+6.3.1. Resolve MX for ISI.EDU.
+
+Suppose the first request to the resolver comes from the local mailer,
+which has mail for PVM at ISI.EDU. The mailer might then ask for type MX
+RRs for the domain name ISI.EDU.
+
+The resolver would look in its cache for MX RRs at ISI.EDU, but the
+empty cache wouldn't be helpful. The resolver would recognize that it
+needed to query foreign servers and try to determine the best servers to
+query. This search would look for NS RRs for the domains ISI.EDU, EDU,
+and the root. These searches of the cache would also fail. As a last
+resort, the resolver would use the information from the SBELT, copying
+it into its SLIST structure.
+
+At this point the resolver would need to pick one of the three available
+addresses to try. Given that the resolver is on net 26, it should
+choose either 26.0.0.73 or 26.3.0.103 as its first choice. It would
+then send off a query of the form:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris [Page 47]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+ +---------------------------------------------------+
+ Header | OPCODE=SQUERY |
+ +---------------------------------------------------+
+ Question | QNAME=ISI.EDU., QCLASS=IN, QTYPE=MX |
+ +---------------------------------------------------+
+ Answer | <empty> |
+ +---------------------------------------------------+
+ Authority | <empty> |
+ +---------------------------------------------------+
+ Additional | <empty> |
+ +---------------------------------------------------+
+
+The resolver would then wait for a response to its query or a timeout.
+If the timeout occurs, it would try different servers, then different
+addresses of the same servers, lastly retrying addresses already tried.
+It might eventually receive a reply from SRI-NIC.ARPA:
+
+ +---------------------------------------------------+
+ Header | OPCODE=SQUERY, RESPONSE |
+ +---------------------------------------------------+
+ Question | QNAME=ISI.EDU., QCLASS=IN, QTYPE=MX |
+ +---------------------------------------------------+
+ Answer | <empty> |
+ +---------------------------------------------------+
+ Authority | ISI.EDU. 172800 IN NS VAXA.ISI.EDU. |
+ | NS A.ISI.EDU. |
+ | NS VENERA.ISI.EDU.|
+ +---------------------------------------------------+
+ Additional | VAXA.ISI.EDU. 172800 A 10.2.0.27 |
+ | 172800 A 128.9.0.33 |
+ | VENERA.ISI.EDU. 172800 A 10.1.0.52 |
+ | 172800 A 128.9.0.32 |
+ | A.ISI.EDU. 172800 A 26.3.0.103 |
+ +---------------------------------------------------+
+
+The resolver would notice that the information in the response gave a
+closer delegation to ISI.EDU than its existing SLIST (since it matches
+three labels). The resolver would then cache the information in this
+response and use it to set up a new SLIST:
+
+ Match count = 3
+ A.ISI.EDU. 26.3.0.103
+ VAXA.ISI.EDU. 10.2.0.27 128.9.0.33
+ VENERA.ISI.EDU. 10.1.0.52 128.9.0.32
+
+A.ISI.EDU appears on this list as well as the previous one, but that is
+purely coincidental. The resolver would again start transmitting and
+waiting for responses. Eventually it would get an answer:
+
+
+
+Mockapetris [Page 48]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+ +---------------------------------------------------+
+ Header | OPCODE=SQUERY, RESPONSE, AA |
+ +---------------------------------------------------+
+ Question | QNAME=ISI.EDU., QCLASS=IN, QTYPE=MX |
+ +---------------------------------------------------+
+ Answer | ISI.EDU. MX 10 VENERA.ISI.EDU. |
+ | MX 20 VAXA.ISI.EDU. |
+ +---------------------------------------------------+
+ Authority | <empty> |
+ +---------------------------------------------------+
+ Additional | VAXA.ISI.EDU. 172800 A 10.2.0.27 |
+ | 172800 A 128.9.0.33 |
+ | VENERA.ISI.EDU. 172800 A 10.1.0.52 |
+ | 172800 A 128.9.0.32 |
+ +---------------------------------------------------+
+
+The resolver would add this information to its cache, and return the MX
+RRs to its client.
+
+6.3.2. Get the host name for address 26.6.0.65
+
+The resolver would translate this into a request for PTR RRs for
+65.0.6.26.IN-ADDR.ARPA. This information is not in the cache, so the
+resolver would look for foreign servers to ask. No servers would match,
+so it would use SBELT again. (Note that the servers for the ISI.EDU
+domain are in the cache, but ISI.EDU is not an ancestor of
+65.0.6.26.IN-ADDR.ARPA, so the SBELT is used.)
+
+Since this request is within the authoritative data of both servers in
+SBELT, eventually one would return:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris [Page 49]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+ +---------------------------------------------------+
+ Header | OPCODE=SQUERY, RESPONSE, AA |
+ +---------------------------------------------------+
+ Question | QNAME=65.0.6.26.IN-ADDR.ARPA.,QCLASS=IN,QTYPE=PTR |
+ +---------------------------------------------------+
+ Answer | 65.0.6.26.IN-ADDR.ARPA. PTR ACC.ARPA. |
+ +---------------------------------------------------+
+ Authority | <empty> |
+ +---------------------------------------------------+
+ Additional | <empty> |
+ +---------------------------------------------------+
+
+6.3.3. Get the host address of poneria.ISI.EDU
+
+This request would translate into a type A request for poneria.ISI.EDU.
+The resolver would not find any cached data for this name, but would
+find the NS RRs in the cache for ISI.EDU when it looks for foreign
+servers to ask. Using this data, it would construct a SLIST of the
+form:
+
+ Match count = 3
+
+ A.ISI.EDU. 26.3.0.103
+ VAXA.ISI.EDU. 10.2.0.27 128.9.0.33
+ VENERA.ISI.EDU. 10.1.0.52
+
+A.ISI.EDU is listed first on the assumption that the resolver orders its
+choices by preference, and A.ISI.EDU is on the same network.
+
+One of these servers would answer the query.
+
+7. REFERENCES and BIBLIOGRAPHY
+
+[Dyer 87] Dyer, S., and F. Hsu, "Hesiod", Project Athena
+ Technical Plan - Name Service, April 1987, version 1.9.
+
+ Describes the fundamentals of the Hesiod name service.
+
+[IEN-116] J. Postel, "Internet Name Server", IEN-116,
+ USC/Information Sciences Institute, August 1979.
+
+ A name service obsoleted by the Domain Name System, but
+ still in use.
+
+
+
+
+
+
+
+
+Mockapetris [Page 50]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+[Quarterman 86] Quarterman, J., and J. Hoskins, "Notable Computer
+ Networks",Communications of the ACM, October 1986,
+ volume 29, number 10.
+
+[RFC-742] K. Harrenstien, "NAME/FINGER", RFC-742, Network
+ Information Center, SRI International, December 1977.
+
+[RFC-768] J. Postel, "User Datagram Protocol", RFC-768,
+ USC/Information Sciences Institute, August 1980.
+
+[RFC-793] J. Postel, "Transmission Control Protocol", RFC-793,
+ USC/Information Sciences Institute, September 1981.
+
+[RFC-799] D. Mills, "Internet Name Domains", RFC-799, COMSAT,
+ September 1981.
+
+ Suggests introduction of a hierarchy in place of a flat
+ name space for the Internet.
+
+[RFC-805] J. Postel, "Computer Mail Meeting Notes", RFC-805,
+ USC/Information Sciences Institute, February 1982.
+
+[RFC-810] E. Feinler, K. Harrenstien, Z. Su, and V. White, "DOD
+ Internet Host Table Specification", RFC-810, Network
+ Information Center, SRI International, March 1982.
+
+ Obsolete. See RFC-952.
+
+[RFC-811] K. Harrenstien, V. White, and E. Feinler, "Hostnames
+ Server", RFC-811, Network Information Center, SRI
+ International, March 1982.
+
+ Obsolete. See RFC-953.
+
+[RFC-812] K. Harrenstien, and V. White, "NICNAME/WHOIS", RFC-812,
+ Network Information Center, SRI International, March
+ 1982.
+
+[RFC-819] Z. Su, and J. Postel, "The Domain Naming Convention for
+ Internet User Applications", RFC-819, Network
+ Information Center, SRI International, August 1982.
+
+ Early thoughts on the design of the domain system.
+ Current implementation is completely different.
+
+[RFC-821] J. Postel, "Simple Mail Transfer Protocol", RFC-821,
+ USC/Information Sciences Institute, August 1980.
+
+
+
+
+Mockapetris [Page 51]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+[RFC-830] Z. Su, "A Distributed System for Internet Name Service",
+ RFC-830, Network Information Center, SRI International,
+ October 1982.
+
+ Early thoughts on the design of the domain system.
+ Current implementation is completely different.
+
+[RFC-882] P. Mockapetris, "Domain names - Concepts and
+ Facilities," RFC-882, USC/Information Sciences
+ Institute, November 1983.
+
+ Superceeded by this memo.
+
+[RFC-883] P. Mockapetris, "Domain names - Implementation and
+ Specification," RFC-883, USC/Information Sciences
+ Institute, November 1983.
+
+ Superceeded by this memo.
+
+[RFC-920] J. Postel and J. Reynolds, "Domain Requirements",
+ RFC-920, USC/Information Sciences Institute
+ October 1984.
+
+ Explains the naming scheme for top level domains.
+
+[RFC-952] K. Harrenstien, M. Stahl, E. Feinler, "DoD Internet Host
+ Table Specification", RFC-952, SRI, October 1985.
+
+ Specifies the format of HOSTS.TXT, the host/address
+ table replaced by the DNS.
+
+[RFC-953] K. Harrenstien, M. Stahl, E. Feinler, "HOSTNAME Server",
+ RFC-953, SRI, October 1985.
+
+ This RFC contains the official specification of the
+ hostname server protocol, which is obsoleted by the DNS.
+ This TCP based protocol accesses information stored in
+ the RFC-952 format, and is used to obtain copies of the
+ host table.
+
+[RFC-973] P. Mockapetris, "Domain System Changes and
+ Observations", RFC-973, USC/Information Sciences
+ Institute, January 1986.
+
+ Describes changes to RFC-882 and RFC-883 and reasons for
+ them. Now obsolete.
+
+
+
+
+
+Mockapetris [Page 52]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+[RFC-974] C. Partridge, "Mail routing and the domain system",
+ RFC-974, CSNET CIC BBN Labs, January 1986.
+
+ Describes the transition from HOSTS.TXT based mail
+ addressing to the more powerful MX system used with the
+ domain system.
+
+[RFC-1001] NetBIOS Working Group, "Protocol standard for a NetBIOS
+ service on a TCP/UDP transport: Concepts and Methods",
+ RFC-1001, March 1987.
+
+ This RFC and RFC-1002 are a preliminary design for
+ NETBIOS on top of TCP/IP which proposes to base NetBIOS
+ name service on top of the DNS.
+
+[RFC-1002] NetBIOS Working Group, "Protocol standard for a NetBIOS
+ service on a TCP/UDP transport: Detailed
+ Specifications", RFC-1002, March 1987.
+
+[RFC-1010] J. Reynolds and J. Postel, "Assigned Numbers", RFC-1010,
+ USC/Information Sciences Institute, May 1987
+
+ Contains socket numbers and mnemonics for host names,
+ operating systems, etc.
+
+[RFC-1031] W. Lazear, "MILNET Name Domain Transition", RFC-1031,
+ November 1987.
+
+ Describes a plan for converting the MILNET to the DNS.
+
+[RFC-1032] M. K. Stahl, "Establishing a Domain - Guidelines for
+ Administrators", RFC-1032, November 1987.
+
+ Describes the registration policies used by the NIC to
+ administer the top level domains and delegate subzones.
+
+[RFC-1033] M. K. Lottor, "Domain Administrators Operations Guide",
+ RFC-1033, November 1987.
+
+ A cookbook for domain administrators.
+
+[Solomon 82] M. Solomon, L. Landweber, and D. Neuhengen, "The CSNET
+ Name Server", Computer Networks, vol 6, nr 3, July 1982.
+
+ Describes a name service for CSNET which is independent
+ from the DNS and DNS use in the CSNET.
+
+
+
+
+
+Mockapetris [Page 53]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+Index
+
+ A 12
+ Absolute names 8
+ Aliases 14, 31
+ Authority 6
+ AXFR 17
+
+ Case of characters 7
+ CH 12
+ CNAME 12, 13, 31
+ Completion queries 18
+
+ Domain name 6, 7
+
+ Glue RRs 20
+
+ HINFO 12
+
+ IN 12
+ Inverse queries 16
+ Iterative 4
+
+ Label 7
+
+ Mailbox names 9
+ MX 12
+
+ Name error 27, 36
+ Name servers 5, 17
+ NE 30
+ Negative caching 44
+ NS 12
+
+ Opcode 16
+
+ PTR 12
+
+ QCLASS 16
+ QTYPE 16
+
+ RDATA 13
+ Recursive 4
+ Recursive service 22
+ Relative names 7
+ Resolvers 6
+ RR 12
+
+
+
+
+Mockapetris [Page 54]
+
+RFC 1034 Domain Concepts and Facilities November 1987
+
+
+ Safety belt 33
+ Sections 16
+ SOA 12
+ Standard queries 22
+
+ Status queries 18
+ Stub resolvers 32
+
+ TTL 12, 13
+
+ Wildcards 25
+
+ Zone transfers 28
+ Zones 19
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris [Page 55]
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/rfc1035.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/rfc1035.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,3077 @@
+Network Working Group P. Mockapetris
+Request for Comments: 1035 ISI
+ November 1987
+Obsoletes: RFCs 882, 883, 973
+
+ DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION
+
+
+1. STATUS OF THIS MEMO
+
+This RFC describes the details of the domain system and protocol, and
+assumes that the reader is familiar with the concepts discussed in a
+companion RFC, "Domain Names - Concepts and Facilities" [RFC-1034].
+
+The domain system is a mixture of functions and data types which are an
+official protocol and functions and data types which are still
+experimental. Since the domain system is intentionally extensible, new
+data types and experimental behavior should always be expected in parts
+of the system beyond the official protocol. The official protocol parts
+include standard queries, responses and the Internet class RR data
+formats (e.g., host addresses). Since the previous RFC set, several
+definitions have changed, so some previous definitions are obsolete.
+
+Experimental or obsolete features are clearly marked in these RFCs, and
+such information should be used with caution.
+
+The reader is especially cautioned not to depend on the values which
+appear in examples to be current or complete, since their purpose is
+primarily pedagogical. Distribution of this memo is unlimited.
+
+ Table of Contents
+
+ 1. STATUS OF THIS MEMO 1
+ 2. INTRODUCTION 3
+ 2.1. Overview 3
+ 2.2. Common configurations 4
+ 2.3. Conventions 7
+ 2.3.1. Preferred name syntax 7
+ 2.3.2. Data Transmission Order 8
+ 2.3.3. Character Case 9
+ 2.3.4. Size limits 10
+ 3. DOMAIN NAME SPACE AND RR DEFINITIONS 10
+ 3.1. Name space definitions 10
+ 3.2. RR definitions 11
+ 3.2.1. Format 11
+ 3.2.2. TYPE values 12
+ 3.2.3. QTYPE values 12
+ 3.2.4. CLASS values 13
+
+
+
+Mockapetris [Page 1]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ 3.2.5. QCLASS values 13
+ 3.3. Standard RRs 13
+ 3.3.1. CNAME RDATA format 14
+ 3.3.2. HINFO RDATA format 14
+ 3.3.3. MB RDATA format (EXPERIMENTAL) 14
+ 3.3.4. MD RDATA format (Obsolete) 15
+ 3.3.5. MF RDATA format (Obsolete) 15
+ 3.3.6. MG RDATA format (EXPERIMENTAL) 16
+ 3.3.7. MINFO RDATA format (EXPERIMENTAL) 16
+ 3.3.8. MR RDATA format (EXPERIMENTAL) 17
+ 3.3.9. MX RDATA format 17
+ 3.3.10. NULL RDATA format (EXPERIMENTAL) 17
+ 3.3.11. NS RDATA format 18
+ 3.3.12. PTR RDATA format 18
+ 3.3.13. SOA RDATA format 19
+ 3.3.14. TXT RDATA format 20
+ 3.4. ARPA Internet specific RRs 20
+ 3.4.1. A RDATA format 20
+ 3.4.2. WKS RDATA format 21
+ 3.5. IN-ADDR.ARPA domain 22
+ 3.6. Defining new types, classes, and special namespaces 24
+ 4. MESSAGES 25
+ 4.1. Format 25
+ 4.1.1. Header section format 26
+ 4.1.2. Question section format 28
+ 4.1.3. Resource record format 29
+ 4.1.4. Message compression 30
+ 4.2. Transport 32
+ 4.2.1. UDP usage 32
+ 4.2.2. TCP usage 32
+ 5. MASTER FILES 33
+ 5.1. Format 33
+ 5.2. Use of master files to define zones 35
+ 5.3. Master file example 36
+ 6. NAME SERVER IMPLEMENTATION 37
+ 6.1. Architecture 37
+ 6.1.1. Control 37
+ 6.1.2. Database 37
+ 6.1.3. Time 39
+ 6.2. Standard query processing 39
+ 6.3. Zone refresh and reload processing 39
+ 6.4. Inverse queries (Optional) 40
+ 6.4.1. The contents of inverse queries and responses 40
+ 6.4.2. Inverse query and response example 41
+ 6.4.3. Inverse query processing 42
+
+
+
+
+
+
+Mockapetris [Page 2]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ 6.5. Completion queries and responses 42
+ 7. RESOLVER IMPLEMENTATION 43
+ 7.1. Transforming a user request into a query 43
+ 7.2. Sending the queries 44
+ 7.3. Processing responses 46
+ 7.4. Using the cache 47
+ 8. MAIL SUPPORT 47
+ 8.1. Mail exchange binding 48
+ 8.2. Mailbox binding (Experimental) 48
+ 9. REFERENCES and BIBLIOGRAPHY 50
+ Index 54
+
+2. INTRODUCTION
+
+2.1. Overview
+
+The goal of domain names is to provide a mechanism for naming resources
+in such a way that the names are usable in different hosts, networks,
+protocol families, internets, and administrative organizations.
+
+From the user's point of view, domain names are useful as arguments to a
+local agent, called a resolver, which retrieves information associated
+with the domain name. Thus a user might ask for the host address or
+mail information associated with a particular domain name. To enable
+the user to request a particular type of information, an appropriate
+query type is passed to the resolver with the domain name. To the user,
+the domain tree is a single information space; the resolver is
+responsible for hiding the distribution of data among name servers from
+the user.
+
+From the resolver's point of view, the database that makes up the domain
+space is distributed among various name servers. Different parts of the
+domain space are stored in different name servers, although a particular
+data item will be stored redundantly in two or more name servers. The
+resolver starts with knowledge of at least one name server. When the
+resolver processes a user query it asks a known name server for the
+information; in return, the resolver either receives the desired
+information or a referral to another name server. Using these
+referrals, resolvers learn the identities and contents of other name
+servers. Resolvers are responsible for dealing with the distribution of
+the domain space and dealing with the effects of name server failure by
+consulting redundant databases in other servers.
+
+Name servers manage two kinds of data. The first kind of data held in
+sets called zones; each zone is the complete database for a particular
+"pruned" subtree of the domain space. This data is called
+authoritative. A name server periodically checks to make sure that its
+zones are up to date, and if not, obtains a new copy of updated zones
+
+
+
+Mockapetris [Page 3]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+from master files stored locally or in another name server. The second
+kind of data is cached data which was acquired by a local resolver.
+This data may be incomplete, but improves the performance of the
+retrieval process when non-local data is repeatedly accessed. Cached
+data is eventually discarded by a timeout mechanism.
+
+This functional structure isolates the problems of user interface,
+failure recovery, and distribution in the resolvers and isolates the
+database update and refresh problems in the name servers.
+
+2.2. Common configurations
+
+A host can participate in the domain name system in a number of ways,
+depending on whether the host runs programs that retrieve information
+from the domain system, name servers that answer queries from other
+hosts, or various combinations of both functions. The simplest, and
+perhaps most typical, configuration is shown below:
+
+ Local Host | Foreign
+ |
+ +---------+ +----------+ | +--------+
+ | | user queries | |queries | | |
+ | User |-------------->| |---------|->|Foreign |
+ | Program | | Resolver | | | Name |
+ | |<--------------| |<--------|--| Server |
+ | | user responses| |responses| | |
+ +---------+ +----------+ | +--------+
+ | A |
+ cache additions | | references |
+ V | |
+ +----------+ |
+ | cache | |
+ +----------+ |
+
+User programs interact with the domain name space through resolvers; the
+format of user queries and user responses is specific to the host and
+its operating system. User queries will typically be operating system
+calls, and the resolver and its cache will be part of the host operating
+system. Less capable hosts may choose to implement the resolver as a
+subroutine to be linked in with every program that needs its services.
+Resolvers answer user queries with information they acquire via queries
+to foreign name servers and the local cache.
+
+Note that the resolver may have to make several queries to several
+different foreign name servers to answer a particular user query, and
+hence the resolution of a user query may involve several network
+accesses and an arbitrary amount of time. The queries to foreign name
+servers and the corresponding responses have a standard format described
+
+
+
+Mockapetris [Page 4]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+in this memo, and may be datagrams.
+
+Depending on its capabilities, a name server could be a stand alone
+program on a dedicated machine or a process or processes on a large
+timeshared host. A simple configuration might be:
+
+ Local Host | Foreign
+ |
+ +---------+ |
+ / /| |
+ +---------+ | +----------+ | +--------+
+ | | | | |responses| | |
+ | | | | Name |---------|->|Foreign |
+ | Master |-------------->| Server | | |Resolver|
+ | files | | | |<--------|--| |
+ | |/ | | queries | +--------+
+ +---------+ +----------+ |
+
+Here a primary name server acquires information about one or more zones
+by reading master files from its local file system, and answers queries
+about those zones that arrive from foreign resolvers.
+
+The DNS requires that all zones be redundantly supported by more than
+one name server. Designated secondary servers can acquire zones and
+check for updates from the primary server using the zone transfer
+protocol of the DNS. This configuration is shown below:
+
+ Local Host | Foreign
+ |
+ +---------+ |
+ / /| |
+ +---------+ | +----------+ | +--------+
+ | | | | |responses| | |
+ | | | | Name |---------|->|Foreign |
+ | Master |-------------->| Server | | |Resolver|
+ | files | | | |<--------|--| |
+ | |/ | | queries | +--------+
+ +---------+ +----------+ |
+ A |maintenance | +--------+
+ | +------------|->| |
+ | queries | |Foreign |
+ | | | Name |
+ +------------------|--| Server |
+ maintenance responses | +--------+
+
+In this configuration, the name server periodically establishes a
+virtual circuit to a foreign name server to acquire a copy of a zone or
+to check that an existing copy has not changed. The messages sent for
+
+
+
+Mockapetris [Page 5]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+these maintenance activities follow the same form as queries and
+responses, but the message sequences are somewhat different.
+
+The information flow in a host that supports all aspects of the domain
+name system is shown below:
+
+ Local Host | Foreign
+ |
+ +---------+ +----------+ | +--------+
+ | | user queries | |queries | | |
+ | User |-------------->| |---------|->|Foreign |
+ | Program | | Resolver | | | Name |
+ | |<--------------| |<--------|--| Server |
+ | | user responses| |responses| | |
+ +---------+ +----------+ | +--------+
+ | A |
+ cache additions | | references |
+ V | |
+ +----------+ |
+ | Shared | |
+ | database | |
+ +----------+ |
+ A | |
+ +---------+ refreshes | | references |
+ / /| | V |
+ +---------+ | +----------+ | +--------+
+ | | | | |responses| | |
+ | | | | Name |---------|->|Foreign |
+ | Master |-------------->| Server | | |Resolver|
+ | files | | | |<--------|--| |
+ | |/ | | queries | +--------+
+ +---------+ +----------+ |
+ A |maintenance | +--------+
+ | +------------|->| |
+ | queries | |Foreign |
+ | | | Name |
+ +------------------|--| Server |
+ maintenance responses | +--------+
+
+The shared database holds domain space data for the local name server
+and resolver. The contents of the shared database will typically be a
+mixture of authoritative data maintained by the periodic refresh
+operations of the name server and cached data from previous resolver
+requests. The structure of the domain data and the necessity for
+synchronization between name servers and resolvers imply the general
+characteristics of this database, but the actual format is up to the
+local implementor.
+
+
+
+
+Mockapetris [Page 6]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+Information flow can also be tailored so that a group of hosts act
+together to optimize activities. Sometimes this is done to offload less
+capable hosts so that they do not have to implement a full resolver.
+This can be appropriate for PCs or hosts which want to minimize the
+amount of new network code which is required. This scheme can also
+allow a group of hosts can share a small number of caches rather than
+maintaining a large number of separate caches, on the premise that the
+centralized caches will have a higher hit ratio. In either case,
+resolvers are replaced with stub resolvers which act as front ends to
+resolvers located in a recursive server in one or more name servers
+known to perform that service:
+
+ Local Hosts | Foreign
+ |
+ +---------+ |
+ | | responses |
+ | Stub |<--------------------+ |
+ | Resolver| | |
+ | |----------------+ | |
+ +---------+ recursive | | |
+ queries | | |
+ V | |
+ +---------+ recursive +----------+ | +--------+
+ | | queries | |queries | | |
+ | Stub |-------------->| Recursive|---------|->|Foreign |
+ | Resolver| | Server | | | Name |
+ | |<--------------| |<--------|--| Server |
+ +---------+ responses | |responses| | |
+ +----------+ | +--------+
+ | Central | |
+ | cache | |
+ +----------+ |
+
+In any case, note that domain components are always replicated for
+reliability whenever possible.
+
+2.3. Conventions
+
+The domain system has several conventions dealing with low-level, but
+fundamental, issues. While the implementor is free to violate these
+conventions WITHIN HIS OWN SYSTEM, he must observe these conventions in
+ALL behavior observed from other hosts.
+
+2.3.1. Preferred name syntax
+
+The DNS specifications attempt to be as general as possible in the rules
+for constructing domain names. The idea is that the name of any
+existing object can be expressed as a domain name with minimal changes.
+
+
+
+Mockapetris [Page 7]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+However, when assigning a domain name for an object, the prudent user
+will select a name which satisfies both the rules of the domain system
+and any existing rules for the object, whether these rules are published
+or implied by existing programs.
+
+For example, when naming a mail domain, the user should satisfy both the
+rules of this memo and those in RFC-822. When creating a new host name,
+the old rules for HOSTS.TXT should be followed. This avoids problems
+when old software is converted to use domain names.
+
+The following syntax will result in fewer problems with many
+
+applications that use domain names (e.g., mail, TELNET).
+
+<domain> ::= <subdomain> | " "
+
+<subdomain> ::= <label> | <subdomain> "." <label>
+
+<label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
+
+<ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
+
+<let-dig-hyp> ::= <let-dig> | "-"
+
+<let-dig> ::= <letter> | <digit>
+
+<letter> ::= any one of the 52 alphabetic characters A through Z in
+upper case and a through z in lower case
+
+<digit> ::= any one of the ten digits 0 through 9
+
+Note that while upper and lower case letters are allowed in domain
+names, no significance is attached to the case. That is, two names with
+the same spelling but different case are to be treated as if identical.
+
+The labels must follow the rules for ARPANET host names. They must
+start with a letter, end with a letter or digit, and have as interior
+characters only letters, digits, and hyphen. There are also some
+restrictions on the length. Labels must be 63 characters or less.
+
+For example, the following strings identify hosts in the Internet:
+
+A.ISI.EDU XX.LCS.MIT.EDU SRI-NIC.ARPA
+
+2.3.2. Data Transmission Order
+
+The order of transmission of the header and data described in this
+document is resolved to the octet level. Whenever a diagram shows a
+
+
+
+Mockapetris [Page 8]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+group of octets, the order of transmission of those octets is the normal
+order in which they are read in English. For example, in the following
+diagram, the octets are transmitted in the order they are numbered.
+
+ 0 1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | 1 | 2 |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | 3 | 4 |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | 5 | 6 |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+Whenever an octet represents a numeric quantity, the left most bit in
+the diagram is the high order or most significant bit. That is, the bit
+labeled 0 is the most significant bit. For example, the following
+diagram represents the value 170 (decimal).
+
+ 0 1 2 3 4 5 6 7
+ +-+-+-+-+-+-+-+-+
+ |1 0 1 0 1 0 1 0|
+ +-+-+-+-+-+-+-+-+
+
+Similarly, whenever a multi-octet field represents a numeric quantity
+the left most bit of the whole field is the most significant bit. When
+a multi-octet quantity is transmitted the most significant octet is
+transmitted first.
+
+2.3.3. Character Case
+
+For all parts of the DNS that are part of the official protocol, all
+comparisons between character strings (e.g., labels, domain names, etc.)
+are done in a case-insensitive manner. At present, this rule is in
+force throughout the domain system without exception. However, future
+additions beyond current usage may need to use the full binary octet
+capabilities in names, so attempts to store domain names in 7-bit ASCII
+or use of special bytes to terminate labels, etc., should be avoided.
+
+When data enters the domain system, its original case should be
+preserved whenever possible. In certain circumstances this cannot be
+done. For example, if two RRs are stored in a database, one at x.y and
+one at X.Y, they are actually stored at the same place in the database,
+and hence only one casing would be preserved. The basic rule is that
+case can be discarded only when data is used to define structure in a
+database, and two names are identical when compared in a case
+insensitive manner.
+
+
+
+
+Mockapetris [Page 9]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+Loss of case sensitive data must be minimized. Thus while data for x.y
+and X.Y may both be stored under a single location x.y or X.Y, data for
+a.x and B.X would never be stored under A.x, A.X, b.x, or b.X. In
+general, this preserves the case of the first label of a domain name,
+but forces standardization of interior node labels.
+
+Systems administrators who enter data into the domain database should
+take care to represent the data they supply to the domain system in a
+case-consistent manner if their system is case-sensitive. The data
+distribution system in the domain system will ensure that consistent
+representations are preserved.
+
+2.3.4. Size limits
+
+Various objects and parameters in the DNS have size limits. They are
+listed below. Some could be easily changed, others are more
+fundamental.
+
+labels 63 octets or less
+
+names 255 octets or less
+
+TTL positive values of a signed 32 bit number.
+
+UDP messages 512 octets or less
+
+3. DOMAIN NAME SPACE AND RR DEFINITIONS
+
+3.1. Name space definitions
+
+Domain names in messages are expressed in terms of a sequence of labels.
+Each label is represented as a one octet length field followed by that
+number of octets. Since every domain name ends with the null label of
+the root, a domain name is terminated by a length byte of zero. The
+high order two bits of every length octet must be zero, and the
+remaining six bits of the length field limit the label to 63 octets or
+less.
+
+To simplify implementations, the total length of a domain name (i.e.,
+label octets and label length octets) is restricted to 255 octets or
+less.
+
+Although labels can contain any 8 bit values in octets that make up a
+label, it is strongly recommended that labels follow the preferred
+syntax described elsewhere in this memo, which is compatible with
+existing host naming conventions. Name servers and resolvers must
+compare labels in a case-insensitive manner (i.e., A=a), assuming ASCII
+with zero parity. Non-alphabetic codes must match exactly.
+
+
+
+Mockapetris [Page 10]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+3.2. RR definitions
+
+3.2.1. Format
+
+All RRs have the same top level format shown below:
+
+ 1 1 1 1 1 1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | |
+ / /
+ / NAME /
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | TYPE |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | CLASS |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | TTL |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | RDLENGTH |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
+ / RDATA /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+
+where:
+
+NAME an owner name, i.e., the name of the node to which this
+ resource record pertains.
+
+TYPE two octets containing one of the RR TYPE codes.
+
+CLASS two octets containing one of the RR CLASS codes.
+
+TTL a 32 bit signed integer that specifies the time interval
+ that the resource record may be cached before the source
+ of the information should again be consulted. Zero
+ values are interpreted to mean that the RR can only be
+ used for the transaction in progress, and should not be
+ cached. For example, SOA records are always distributed
+ with a zero TTL to prohibit caching. Zero values can
+ also be used for extremely volatile data.
+
+RDLENGTH an unsigned 16 bit integer that specifies the length in
+ octets of the RDATA field.
+
+
+
+Mockapetris [Page 11]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+RDATA a variable length string of octets that describes the
+ resource. The format of this information varies
+ according to the TYPE and CLASS of the resource record.
+
+3.2.2. TYPE values
+
+TYPE fields are used in resource records. Note that these types are a
+subset of QTYPEs.
+
+TYPE value and meaning
+
+A 1 a host address
+
+NS 2 an authoritative name server
+
+MD 3 a mail destination (Obsolete - use MX)
+
+MF 4 a mail forwarder (Obsolete - use MX)
+
+CNAME 5 the canonical name for an alias
+
+SOA 6 marks the start of a zone of authority
+
+MB 7 a mailbox domain name (EXPERIMENTAL)
+
+MG 8 a mail group member (EXPERIMENTAL)
+
+MR 9 a mail rename domain name (EXPERIMENTAL)
+
+NULL 10 a null RR (EXPERIMENTAL)
+
+WKS 11 a well known service description
+
+PTR 12 a domain name pointer
+
+HINFO 13 host information
+
+MINFO 14 mailbox or mail list information
+
+MX 15 mail exchange
+
+TXT 16 text strings
+
+3.2.3. QTYPE values
+
+QTYPE fields appear in the question part of a query. QTYPES are a
+superset of TYPEs, hence all TYPEs are valid QTYPEs. In addition, the
+following QTYPEs are defined:
+
+
+
+Mockapetris [Page 12]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+AXFR 252 A request for a transfer of an entire zone
+
+MAILB 253 A request for mailbox-related records (MB, MG or MR)
+
+MAILA 254 A request for mail agent RRs (Obsolete - see MX)
+
+* 255 A request for all records
+
+3.2.4. CLASS values
+
+CLASS fields appear in resource records. The following CLASS mnemonics
+and values are defined:
+
+IN 1 the Internet
+
+CS 2 the CSNET class (Obsolete - used only for examples in
+ some obsolete RFCs)
+
+CH 3 the CHAOS class
+
+HS 4 Hesiod [Dyer 87]
+
+3.2.5. QCLASS values
+
+QCLASS fields appear in the question section of a query. QCLASS values
+are a superset of CLASS values; every CLASS is a valid QCLASS. In
+addition to CLASS values, the following QCLASSes are defined:
+
+* 255 any class
+
+3.3. Standard RRs
+
+The following RR definitions are expected to occur, at least
+potentially, in all classes. In particular, NS, SOA, CNAME, and PTR
+will be used in all classes, and have the same format in all classes.
+Because their RDATA format is known, all domain names in the RDATA
+section of these RRs may be compressed.
+
+<domain-name> is a domain name represented as a series of labels, and
+terminated by a label with zero length. <character-string> is a single
+length octet followed by that number of characters. <character-string>
+is treated as binary information, and can be up to 256 characters in
+length (including the length octet).
+
+
+
+
+
+
+
+
+Mockapetris [Page 13]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+3.3.1. CNAME RDATA format
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / CNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+CNAME A <domain-name> which specifies the canonical or primary
+ name for the owner. The owner name is an alias.
+
+CNAME RRs cause no additional section processing, but name servers may
+choose to restart the query at the canonical name in certain cases. See
+the description of name server logic in [RFC-1034] for details.
+
+3.3.2. HINFO RDATA format
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / CPU /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / OS /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+CPU A <character-string> which specifies the CPU type.
+
+OS A <character-string> which specifies the operating
+ system type.
+
+Standard values for CPU and OS can be found in [RFC-1010].
+
+HINFO records are used to acquire general information about a host. The
+main use is for protocols such as FTP that can use special procedures
+when talking between machines or operating systems of the same type.
+
+3.3.3. MB RDATA format (EXPERIMENTAL)
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / MADNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+MADNAME A <domain-name> which specifies a host which has the
+ specified mailbox.
+
+
+
+Mockapetris [Page 14]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+MB records cause additional section processing which looks up an A type
+RRs corresponding to MADNAME.
+
+3.3.4. MD RDATA format (Obsolete)
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / MADNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+MADNAME A <domain-name> which specifies a host which has a mail
+ agent for the domain which should be able to deliver
+ mail for the domain.
+
+MD records cause additional section processing which looks up an A type
+record corresponding to MADNAME.
+
+MD is obsolete. See the definition of MX and [RFC-974] for details of
+the new scheme. The recommended policy for dealing with MD RRs found in
+a master file is to reject them, or to convert them to MX RRs with a
+preference of 0.
+
+3.3.5. MF RDATA format (Obsolete)
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / MADNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+MADNAME A <domain-name> which specifies a host which has a mail
+ agent for the domain which will accept mail for
+ forwarding to the domain.
+
+MF records cause additional section processing which looks up an A type
+record corresponding to MADNAME.
+
+MF is obsolete. See the definition of MX and [RFC-974] for details ofw
+the new scheme. The recommended policy for dealing with MD RRs found in
+a master file is to reject them, or to convert them to MX RRs with a
+preference of 10.
+
+
+
+
+
+
+
+Mockapetris [Page 15]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+3.3.6. MG RDATA format (EXPERIMENTAL)
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / MGMNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+MGMNAME A <domain-name> which specifies a mailbox which is a
+ member of the mail group specified by the domain name.
+
+MG records cause no additional section processing.
+
+3.3.7. MINFO RDATA format (EXPERIMENTAL)
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / RMAILBX /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / EMAILBX /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+RMAILBX A <domain-name> which specifies a mailbox which is
+ responsible for the mailing list or mailbox. If this
+ domain name names the root, the owner of the MINFO RR is
+ responsible for itself. Note that many existing mailing
+ lists use a mailbox X-request for the RMAILBX field of
+ mailing list X, e.g., Msgroup-request for Msgroup. This
+ field provides a more general mechanism.
+
+
+EMAILBX A <domain-name> which specifies a mailbox which is to
+ receive error messages related to the mailing list or
+ mailbox specified by the owner of the MINFO RR (similar
+ to the ERRORS-TO: field which has been proposed). If
+ this domain name names the root, errors should be
+ returned to the sender of the message.
+
+MINFO records cause no additional section processing. Although these
+records can be associated with a simple mailbox, they are usually used
+with a mailing list.
+
+
+
+
+
+
+
+
+Mockapetris [Page 16]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+3.3.8. MR RDATA format (EXPERIMENTAL)
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / NEWNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+NEWNAME A <domain-name> which specifies a mailbox which is the
+ proper rename of the specified mailbox.
+
+MR records cause no additional section processing. The main use for MR
+is as a forwarding entry for a user who has moved to a different
+mailbox.
+
+3.3.9. MX RDATA format
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | PREFERENCE |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / EXCHANGE /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+PREFERENCE A 16 bit integer which specifies the preference given to
+ this RR among others at the same owner. Lower values
+ are preferred.
+
+EXCHANGE A <domain-name> which specifies a host willing to act as
+ a mail exchange for the owner name.
+
+MX records cause type A additional section processing for the host
+specified by EXCHANGE. The use of MX RRs is explained in detail in
+[RFC-974].
+
+3.3.10. NULL RDATA format (EXPERIMENTAL)
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / <anything> /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+Anything at all may be in the RDATA field so long as it is 65535 octets
+or less.
+
+
+
+
+Mockapetris [Page 17]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+NULL records cause no additional section processing. NULL RRs are not
+allowed in master files. NULLs are used as placeholders in some
+experimental extensions of the DNS.
+
+3.3.11. NS RDATA format
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / NSDNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+NSDNAME A <domain-name> which specifies a host which should be
+ authoritative for the specified class and domain.
+
+NS records cause both the usual additional section processing to locate
+a type A record, and, when used in a referral, a special search of the
+zone in which they reside for glue information.
+
+The NS RR states that the named host should be expected to have a zone
+starting at owner name of the specified class. Note that the class may
+not indicate the protocol family which should be used to communicate
+with the host, although it is typically a strong hint. For example,
+hosts which are name servers for either Internet (IN) or Hesiod (HS)
+class information are normally queried using IN class protocols.
+
+3.3.12. PTR RDATA format
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / PTRDNAME /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+PTRDNAME A <domain-name> which points to some location in the
+ domain name space.
+
+PTR records cause no additional section processing. These RRs are used
+in special domains to point to some other location in the domain space.
+These records are simple data, and don't imply any special processing
+similar to that performed by CNAME, which identifies aliases. See the
+description of the IN-ADDR.ARPA domain for an example.
+
+
+
+
+
+
+
+
+Mockapetris [Page 18]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+3.3.13. SOA RDATA format
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / MNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / RNAME /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | SERIAL |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | REFRESH |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | RETRY |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | EXPIRE |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | MINIMUM |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+MNAME The <domain-name> of the name server that was the
+ original or primary source of data for this zone.
+
+RNAME A <domain-name> which specifies the mailbox of the
+ person responsible for this zone.
+
+SERIAL The unsigned 32 bit version number of the original copy
+ of the zone. Zone transfers preserve this value. This
+ value wraps and should be compared using sequence space
+ arithmetic.
+
+REFRESH A 32 bit time interval before the zone should be
+ refreshed.
+
+RETRY A 32 bit time interval that should elapse before a
+ failed refresh should be retried.
+
+EXPIRE A 32 bit time value that specifies the upper limit on
+ the time interval that can elapse before the zone is no
+ longer authoritative.
+
+
+
+
+
+Mockapetris [Page 19]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+MINIMUM The unsigned 32 bit minimum TTL field that should be
+ exported with any RR from this zone.
+
+SOA records cause no additional section processing.
+
+All times are in units of seconds.
+
+Most of these fields are pertinent only for name server maintenance
+operations. However, MINIMUM is used in all query operations that
+retrieve RRs from a zone. Whenever a RR is sent in a response to a
+query, the TTL field is set to the maximum of the TTL field from the RR
+and the MINIMUM field in the appropriate SOA. Thus MINIMUM is a lower
+bound on the TTL field for all RRs in a zone. Note that this use of
+MINIMUM should occur when the RRs are copied into the response and not
+when the zone is loaded from a master file or via a zone transfer. The
+reason for this provison is to allow future dynamic update facilities to
+change the SOA RR with known semantics.
+
+
+3.3.14. TXT RDATA format
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / TXT-DATA /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+TXT-DATA One or more <character-string>s.
+
+TXT RRs are used to hold descriptive text. The semantics of the text
+depends on the domain where it is found.
+
+3.4. Internet specific RRs
+
+3.4.1. A RDATA format
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | ADDRESS |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+ADDRESS A 32 bit Internet address.
+
+Hosts that have multiple Internet addresses will have multiple A
+records.
+
+
+
+
+
+Mockapetris [Page 20]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+A records cause no additional section processing. The RDATA section of
+an A line in a master file is an Internet address expressed as four
+decimal numbers separated by dots without any imbedded spaces (e.g.,
+"10.2.0.52" or "192.0.5.6").
+
+3.4.2. WKS RDATA format
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | ADDRESS |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | PROTOCOL | |
+ +--+--+--+--+--+--+--+--+ |
+ | |
+ / <BIT MAP> /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+ADDRESS An 32 bit Internet address
+
+PROTOCOL An 8 bit IP protocol number
+
+<BIT MAP> A variable length bit map. The bit map must be a
+ multiple of 8 bits long.
+
+The WKS record is used to describe the well known services supported by
+a particular protocol on a particular internet address. The PROTOCOL
+field specifies an IP protocol number, and the bit map has one bit per
+port of the specified protocol. The first bit corresponds to port 0,
+the second to port 1, etc. If the bit map does not include a bit for a
+protocol of interest, that bit is assumed zero. The appropriate values
+and mnemonics for ports and protocols are specified in [RFC-1010].
+
+For example, if PROTOCOL=TCP (6), the 26th bit corresponds to TCP port
+25 (SMTP). If this bit is set, a SMTP server should be listening on TCP
+port 25; if zero, SMTP service is not supported on the specified
+address.
+
+The purpose of WKS RRs is to provide availability information for
+servers for TCP and UDP. If a server supports both TCP and UDP, or has
+multiple Internet addresses, then multiple WKS RRs are used.
+
+WKS RRs cause no additional section processing.
+
+In master files, both ports and protocols are expressed using mnemonics
+or decimal numbers.
+
+
+
+
+Mockapetris [Page 21]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+3.5. IN-ADDR.ARPA domain
+
+The Internet uses a special domain to support gateway location and
+Internet address to host mapping. Other classes may employ a similar
+strategy in other domains. The intent of this domain is to provide a
+guaranteed method to perform host address to host name mapping, and to
+facilitate queries to locate all gateways on a particular network in the
+Internet.
+
+Note that both of these services are similar to functions that could be
+performed by inverse queries; the difference is that this part of the
+domain name space is structured according to address, and hence can
+guarantee that the appropriate data can be located without an exhaustive
+search of the domain space.
+
+The domain begins at IN-ADDR.ARPA and has a substructure which follows
+the Internet addressing structure.
+
+Domain names in the IN-ADDR.ARPA domain are defined to have up to four
+labels in addition to the IN-ADDR.ARPA suffix. Each label represents
+one octet of an Internet address, and is expressed as a character string
+for a decimal value in the range 0-255 (with leading zeros omitted
+except in the case of a zero octet which is represented by a single
+zero).
+
+Host addresses are represented by domain names that have all four labels
+specified. Thus data for Internet address 10.2.0.52 is located at
+domain name 52.0.2.10.IN-ADDR.ARPA. The reversal, though awkward to
+read, allows zones to be delegated which are exactly one network of
+address space. For example, 10.IN-ADDR.ARPA can be a zone containing
+data for the ARPANET, while 26.IN-ADDR.ARPA can be a separate zone for
+MILNET. Address nodes are used to hold pointers to primary host names
+in the normal domain space.
+
+Network numbers correspond to some non-terminal nodes at various depths
+in the IN-ADDR.ARPA domain, since Internet network numbers are either 1,
+2, or 3 octets. Network nodes are used to hold pointers to the primary
+host names of gateways attached to that network. Since a gateway is, by
+definition, on more than one network, it will typically have two or more
+network nodes which point at it. Gateways will also have host level
+pointers at their fully qualified addresses.
+
+Both the gateway pointers at network nodes and the normal host pointers
+at full address nodes use the PTR RR to point back to the primary domain
+names of the corresponding hosts.
+
+For example, the IN-ADDR.ARPA domain will contain information about the
+ISI gateway between net 10 and 26, an MIT gateway from net 10 to MIT's
+
+
+
+Mockapetris [Page 22]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+net 18, and hosts A.ISI.EDU and MULTICS.MIT.EDU. Assuming that ISI
+gateway has addresses 10.2.0.22 and 26.0.0.103, and a name MILNET-
+GW.ISI.EDU, and the MIT gateway has addresses 10.0.0.77 and 18.10.0.4
+and a name GW.LCS.MIT.EDU, the domain database would contain:
+
+ 10.IN-ADDR.ARPA. PTR MILNET-GW.ISI.EDU.
+ 10.IN-ADDR.ARPA. PTR GW.LCS.MIT.EDU.
+ 18.IN-ADDR.ARPA. PTR GW.LCS.MIT.EDU.
+ 26.IN-ADDR.ARPA. PTR MILNET-GW.ISI.EDU.
+ 22.0.2.10.IN-ADDR.ARPA. PTR MILNET-GW.ISI.EDU.
+ 103.0.0.26.IN-ADDR.ARPA. PTR MILNET-GW.ISI.EDU.
+ 77.0.0.10.IN-ADDR.ARPA. PTR GW.LCS.MIT.EDU.
+ 4.0.10.18.IN-ADDR.ARPA. PTR GW.LCS.MIT.EDU.
+ 103.0.3.26.IN-ADDR.ARPA. PTR A.ISI.EDU.
+ 6.0.0.10.IN-ADDR.ARPA. PTR MULTICS.MIT.EDU.
+
+Thus a program which wanted to locate gateways on net 10 would originate
+a query of the form QTYPE=PTR, QCLASS=IN, QNAME=10.IN-ADDR.ARPA. It
+would receive two RRs in response:
+
+ 10.IN-ADDR.ARPA. PTR MILNET-GW.ISI.EDU.
+ 10.IN-ADDR.ARPA. PTR GW.LCS.MIT.EDU.
+
+The program could then originate QTYPE=A, QCLASS=IN queries for MILNET-
+GW.ISI.EDU. and GW.LCS.MIT.EDU. to discover the Internet addresses of
+these gateways.
+
+A resolver which wanted to find the host name corresponding to Internet
+host address 10.0.0.6 would pursue a query of the form QTYPE=PTR,
+QCLASS=IN, QNAME=6.0.0.10.IN-ADDR.ARPA, and would receive:
+
+ 6.0.0.10.IN-ADDR.ARPA. PTR MULTICS.MIT.EDU.
+
+Several cautions apply to the use of these services:
+ - Since the IN-ADDR.ARPA special domain and the normal domain
+ for a particular host or gateway will be in different zones,
+ the possibility exists that that the data may be inconsistent.
+
+ - Gateways will often have two names in separate domains, only
+ one of which can be primary.
+
+ - Systems that use the domain database to initialize their
+ routing tables must start with enough gateway information to
+ guarantee that they can access the appropriate name server.
+
+ - The gateway data only reflects the existence of a gateway in a
+ manner equivalent to the current HOSTS.TXT file. It doesn't
+ replace the dynamic availability information from GGP or EGP.
+
+
+
+Mockapetris [Page 23]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+3.6. Defining new types, classes, and special namespaces
+
+The previously defined types and classes are the ones in use as of the
+date of this memo. New definitions should be expected. This section
+makes some recommendations to designers considering additions to the
+existing facilities. The mailing list NAMEDROPPERS at SRI-NIC.ARPA is the
+forum where general discussion of design issues takes place.
+
+In general, a new type is appropriate when new information is to be
+added to the database about an existing object, or we need new data
+formats for some totally new object. Designers should attempt to define
+types and their RDATA formats that are generally applicable to all
+classes, and which avoid duplication of information. New classes are
+appropriate when the DNS is to be used for a new protocol, etc which
+requires new class-specific data formats, or when a copy of the existing
+name space is desired, but a separate management domain is necessary.
+
+New types and classes need mnemonics for master files; the format of the
+master files requires that the mnemonics for type and class be disjoint.
+
+TYPE and CLASS values must be a proper subset of QTYPEs and QCLASSes
+respectively.
+
+The present system uses multiple RRs to represent multiple values of a
+type rather than storing multiple values in the RDATA section of a
+single RR. This is less efficient for most applications, but does keep
+RRs shorter. The multiple RRs assumption is incorporated in some
+experimental work on dynamic update methods.
+
+The present system attempts to minimize the duplication of data in the
+database in order to insure consistency. Thus, in order to find the
+address of the host for a mail exchange, you map the mail domain name to
+a host name, then the host name to addresses, rather than a direct
+mapping to host address. This approach is preferred because it avoids
+the opportunity for inconsistency.
+
+In defining a new type of data, multiple RR types should not be used to
+create an ordering between entries or express different formats for
+equivalent bindings, instead this information should be carried in the
+body of the RR and a single type used. This policy avoids problems with
+caching multiple types and defining QTYPEs to match multiple types.
+
+For example, the original form of mail exchange binding used two RR
+types one to represent a "closer" exchange (MD) and one to represent a
+"less close" exchange (MF). The difficulty is that the presence of one
+RR type in a cache doesn't convey any information about the other
+because the query which acquired the cached information might have used
+a QTYPE of MF, MD, or MAILA (which matched both). The redesigned
+
+
+
+Mockapetris [Page 24]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+service used a single type (MX) with a "preference" value in the RDATA
+section which can order different RRs. However, if any MX RRs are found
+in the cache, then all should be there.
+
+4. MESSAGES
+
+4.1. Format
+
+All communications inside of the domain protocol are carried in a single
+format called a message. The top level format of message is divided
+into 5 sections (some of which are empty in certain cases) shown below:
+
+ +---------------------+
+ | Header |
+ +---------------------+
+ | Question | the question for the name server
+ +---------------------+
+ | Answer | RRs answering the question
+ +---------------------+
+ | Authority | RRs pointing toward an authority
+ +---------------------+
+ | Additional | RRs holding additional information
+ +---------------------+
+
+The header section is always present. The header includes fields that
+specify which of the remaining sections are present, and also specify
+whether the message is a query or a response, a standard query or some
+other opcode, etc.
+
+The names of the sections after the header are derived from their use in
+standard queries. The question section contains fields that describe a
+question to a name server. These fields are a query type (QTYPE), a
+query class (QCLASS), and a query domain name (QNAME). The last three
+sections have the same format: a possibly empty list of concatenated
+resource records (RRs). The answer section contains RRs that answer the
+question; the authority section contains RRs that point toward an
+authoritative name server; the additional records section contains RRs
+which relate to the query, but are not strictly answers for the
+question.
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris [Page 25]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+4.1.1. Header section format
+
+The header contains the following fields:
+
+ 1 1 1 1 1 1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | ID |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ |QR| Opcode |AA|TC|RD|RA| Z | RCODE |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | QDCOUNT |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | ANCOUNT |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | NSCOUNT |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | ARCOUNT |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+ID A 16 bit identifier assigned by the program that
+ generates any kind of query. This identifier is copied
+ the corresponding reply and can be used by the requester
+ to match up replies to outstanding queries.
+
+QR A one bit field that specifies whether this message is a
+ query (0), or a response (1).
+
+OPCODE A four bit field that specifies kind of query in this
+ message. This value is set by the originator of a query
+ and copied into the response. The values are:
+
+ 0 a standard query (QUERY)
+
+ 1 an inverse query (IQUERY)
+
+ 2 a server status request (STATUS)
+
+ 3-15 reserved for future use
+
+AA Authoritative Answer - this bit is valid in responses,
+ and specifies that the responding name server is an
+ authority for the domain name in question section.
+
+ Note that the contents of the answer section may have
+ multiple owner names because of aliases. The AA bit
+
+
+
+Mockapetris [Page 26]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ corresponds to the name which matches the query name, or
+ the first owner name in the answer section.
+
+TC TrunCation - specifies that this message was truncated
+ due to length greater than that permitted on the
+ transmission channel.
+
+RD Recursion Desired - this bit may be set in a query and
+ is copied into the response. If RD is set, it directs
+ the name server to pursue the query recursively.
+ Recursive query support is optional.
+
+RA Recursion Available - this be is set or cleared in a
+ response, and denotes whether recursive query support is
+ available in the name server.
+
+Z Reserved for future use. Must be zero in all queries
+ and responses.
+
+RCODE Response code - this 4 bit field is set as part of
+ responses. The values have the following
+ interpretation:
+
+ 0 No error condition
+
+ 1 Format error - The name server was
+ unable to interpret the query.
+
+ 2 Server failure - The name server was
+ unable to process this query due to a
+ problem with the name server.
+
+ 3 Name Error - Meaningful only for
+ responses from an authoritative name
+ server, this code signifies that the
+ domain name referenced in the query does
+ not exist.
+
+ 4 Not Implemented - The name server does
+ not support the requested kind of query.
+
+ 5 Refused - The name server refuses to
+ perform the specified operation for
+ policy reasons. For example, a name
+ server may not wish to provide the
+ information to the particular requester,
+ or a name server may not wish to perform
+ a particular operation (e.g., zone
+
+
+
+Mockapetris [Page 27]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ transfer) for particular data.
+
+ 6-15 Reserved for future use.
+
+QDCOUNT an unsigned 16 bit integer specifying the number of
+ entries in the question section.
+
+ANCOUNT an unsigned 16 bit integer specifying the number of
+ resource records in the answer section.
+
+NSCOUNT an unsigned 16 bit integer specifying the number of name
+ server resource records in the authority records
+ section.
+
+ARCOUNT an unsigned 16 bit integer specifying the number of
+ resource records in the additional records section.
+
+4.1.2. Question section format
+
+The question section is used to carry the "question" in most queries,
+i.e., the parameters that define what is being asked. The section
+contains QDCOUNT (usually 1) entries, each of the following format:
+
+ 1 1 1 1 1 1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | |
+ / QNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | QTYPE |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | QCLASS |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+QNAME a domain name represented as a sequence of labels, where
+ each label consists of a length octet followed by that
+ number of octets. The domain name terminates with the
+ zero length octet for the null label of the root. Note
+ that this field may be an odd number of octets; no
+ padding is used.
+
+QTYPE a two octet code which specifies the type of the query.
+ The values for this field include all codes valid for a
+ TYPE field, together with some more general codes which
+ can match more than one type of RR.
+
+
+
+Mockapetris [Page 28]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+QCLASS a two octet code that specifies the class of the query.
+ For example, the QCLASS field is IN for the Internet.
+
+4.1.3. Resource record format
+
+The answer, authority, and additional sections all share the same
+format: a variable number of resource records, where the number of
+records is specified in the corresponding count field in the header.
+Each resource record has the following format:
+ 1 1 1 1 1 1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | |
+ / /
+ / NAME /
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | TYPE |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | CLASS |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | TTL |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | RDLENGTH |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
+ / RDATA /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+NAME a domain name to which this resource record pertains.
+
+TYPE two octets containing one of the RR type codes. This
+ field specifies the meaning of the data in the RDATA
+ field.
+
+CLASS two octets which specify the class of the data in the
+ RDATA field.
+
+TTL a 32 bit unsigned integer that specifies the time
+ interval (in seconds) that the resource record may be
+ cached before it should be discarded. Zero values are
+ interpreted to mean that the RR can only be used for the
+ transaction in progress, and should not be cached.
+
+
+
+
+
+Mockapetris [Page 29]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+RDLENGTH an unsigned 16 bit integer that specifies the length in
+ octets of the RDATA field.
+
+RDATA a variable length string of octets that describes the
+ resource. The format of this information varies
+ according to the TYPE and CLASS of the resource record.
+ For example, the if the TYPE is A and the CLASS is IN,
+ the RDATA field is a 4 octet ARPA Internet address.
+
+4.1.4. Message compression
+
+In order to reduce the size of messages, the domain system utilizes a
+compression scheme which eliminates the repetition of domain names in a
+message. In this scheme, an entire domain name or a list of labels at
+the end of a domain name is replaced with a pointer to a prior occurance
+of the same name.
+
+The pointer takes the form of a two octet sequence:
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | 1 1| OFFSET |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+The first two bits are ones. This allows a pointer to be distinguished
+from a label, since the label must begin with two zero bits because
+labels are restricted to 63 octets or less. (The 10 and 01 combinations
+are reserved for future use.) The OFFSET field specifies an offset from
+the start of the message (i.e., the first octet of the ID field in the
+domain header). A zero offset specifies the first byte of the ID field,
+etc.
+
+The compression scheme allows a domain name in a message to be
+represented as either:
+
+ - a sequence of labels ending in a zero octet
+
+ - a pointer
+
+ - a sequence of labels ending with a pointer
+
+Pointers can only be used for occurances of a domain name where the
+format is not class specific. If this were not the case, a name server
+or resolver would be required to know the format of all RRs it handled.
+As yet, there are no such cases, but they may occur in future RDATA
+formats.
+
+If a domain name is contained in a part of the message subject to a
+length field (such as the RDATA section of an RR), and compression is
+
+
+
+Mockapetris [Page 30]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+used, the length of the compressed name is used in the length
+calculation, rather than the length of the expanded name.
+
+Programs are free to avoid using pointers in messages they generate,
+although this will reduce datagram capacity, and may cause truncation.
+However all programs are required to understand arriving messages that
+contain pointers.
+
+For example, a datagram might need to use the domain names F.ISI.ARPA,
+FOO.F.ISI.ARPA, ARPA, and the root. Ignoring the other fields of the
+message, these domain names might be represented as:
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 20 | 1 | F |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 22 | 3 | I |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 24 | S | I |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 26 | 4 | A |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 28 | R | P |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 30 | A | 0 |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 40 | 3 | F |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 42 | O | O |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 44 | 1 1| 20 |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 64 | 1 1| 26 |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 92 | 0 | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+The domain name for F.ISI.ARPA is shown at offset 20. The domain name
+FOO.F.ISI.ARPA is shown at offset 40; this definition uses a pointer to
+concatenate a label for FOO to the previously defined F.ISI.ARPA. The
+domain name ARPA is defined at offset 64 using a pointer to the ARPA
+component of the name F.ISI.ARPA at 20; note that this pointer relies on
+ARPA being the last label in the string at 20. The root domain name is
+
+
+
+Mockapetris [Page 31]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+defined by a single octet of zeros at 92; the root domain name has no
+labels.
+
+4.2. Transport
+
+The DNS assumes that messages will be transmitted as datagrams or in a
+byte stream carried by a virtual circuit. While virtual circuits can be
+used for any DNS activity, datagrams are preferred for queries due to
+their lower overhead and better performance. Zone refresh activities
+must use virtual circuits because of the need for reliable transfer.
+
+The Internet supports name server access using TCP [RFC-793] on server
+port 53 (decimal) as well as datagram access using UDP [RFC-768] on UDP
+port 53 (decimal).
+
+4.2.1. UDP usage
+
+Messages sent using UDP user server port 53 (decimal).
+
+Messages carried by UDP are restricted to 512 bytes (not counting the IP
+or UDP headers). Longer messages are truncated and the TC bit is set in
+the header.
+
+UDP is not acceptable for zone transfers, but is the recommended method
+for standard queries in the Internet. Queries sent using UDP may be
+lost, and hence a retransmission strategy is required. Queries or their
+responses may be reordered by the network, or by processing in name
+servers, so resolvers should not depend on them being returned in order.
+
+The optimal UDP retransmission policy will vary with performance of the
+Internet and the needs of the client, but the following are recommended:
+
+ - The client should try other servers and server addresses
+ before repeating a query to a specific address of a server.
+
+ - The retransmission interval should be based on prior
+ statistics if possible. Too aggressive retransmission can
+ easily slow responses for the community at large. Depending
+ on how well connected the client is to its expected servers,
+ the minimum retransmission interval should be 2-5 seconds.
+
+More suggestions on server selection and retransmission policy can be
+found in the resolver section of this memo.
+
+4.2.2. TCP usage
+
+Messages sent over TCP connections use server port 53 (decimal). The
+message is prefixed with a two byte length field which gives the message
+
+
+
+Mockapetris [Page 32]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+length, excluding the two byte length field. This length field allows
+the low-level processing to assemble a complete message before beginning
+to parse it.
+
+Several connection management policies are recommended:
+
+ - The server should not block other activities waiting for TCP
+ data.
+
+ - The server should support multiple connections.
+
+ - The server should assume that the client will initiate
+ connection closing, and should delay closing its end of the
+ connection until all outstanding client requests have been
+ satisfied.
+
+ - If the server needs to close a dormant connection to reclaim
+ resources, it should wait until the connection has been idle
+ for a period on the order of two minutes. In particular, the
+ server should allow the SOA and AXFR request sequence (which
+ begins a refresh operation) to be made on a single connection.
+ Since the server would be unable to answer queries anyway, a
+ unilateral close or reset may be used instead of a graceful
+ close.
+
+5. MASTER FILES
+
+Master files are text files that contain RRs in text form. Since the
+contents of a zone can be expressed in the form of a list of RRs a
+master file is most often used to define a zone, though it can be used
+to list a cache's contents. Hence, this section first discusses the
+format of RRs in a master file, and then the special considerations when
+a master file is used to create a zone in some name server.
+
+5.1. Format
+
+The format of these files is a sequence of entries. Entries are
+predominantly line-oriented, though parentheses can be used to continue
+a list of items across a line boundary, and text literals can contain
+CRLF within the text. Any combination of tabs and spaces act as a
+delimiter between the separate items that make up an entry. The end of
+any line in the master file can end with a comment. The comment starts
+with a ";" (semicolon).
+
+The following entries are defined:
+
+ <blank>[<comment>]
+
+
+
+
+Mockapetris [Page 33]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ $ORIGIN <domain-name> [<comment>]
+
+ $INCLUDE <file-name> [<domain-name>] [<comment>]
+
+ <domain-name><rr> [<comment>]
+
+ <blank><rr> [<comment>]
+
+Blank lines, with or without comments, are allowed anywhere in the file.
+
+Two control entries are defined: $ORIGIN and $INCLUDE. $ORIGIN is
+followed by a domain name, and resets the current origin for relative
+domain names to the stated name. $INCLUDE inserts the named file into
+the current file, and may optionally specify a domain name that sets the
+relative domain name origin for the included file. $INCLUDE may also
+have a comment. Note that a $INCLUDE entry never changes the relative
+origin of the parent file, regardless of changes to the relative origin
+made within the included file.
+
+The last two forms represent RRs. If an entry for an RR begins with a
+blank, then the RR is assumed to be owned by the last stated owner. If
+an RR entry begins with a <domain-name>, then the owner name is reset.
+
+<rr> contents take one of the following forms:
+
+ [<TTL>] [<class>] <type> <RDATA>
+
+ [<class>] [<TTL>] <type> <RDATA>
+
+The RR begins with optional TTL and class fields, followed by a type and
+RDATA field appropriate to the type and class. Class and type use the
+standard mnemonics, TTL is a decimal integer. Omitted class and TTL
+values are default to the last explicitly stated values. Since type and
+class mnemonics are disjoint, the parse is unique. (Note that this
+order is different from the order used in examples and the order used in
+the actual RRs; the given order allows easier parsing and defaulting.)
+
+<domain-name>s make up a large share of the data in the master file.
+The labels in the domain name are expressed as character strings and
+separated by dots. Quoting conventions allow arbitrary characters to be
+stored in domain names. Domain names that end in a dot are called
+absolute, and are taken as complete. Domain names which do not end in a
+dot are called relative; the actual domain name is the concatenation of
+the relative part with an origin specified in a $ORIGIN, $INCLUDE, or as
+an argument to the master file loading routine. A relative name is an
+error when no origin is available.
+
+
+
+
+
+Mockapetris [Page 34]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+<character-string> is expressed in one or two ways: as a contiguous set
+of characters without interior spaces, or as a string beginning with a "
+and ending with a ". Inside a " delimited string any character can
+occur, except for a " itself, which must be quoted using \ (back slash).
+
+Because these files are text files several special encodings are
+necessary to allow arbitrary data to be loaded. In particular:
+
+ of the root.
+
+@ A free standing @ is used to denote the current origin.
+
+\X where X is any character other than a digit (0-9), is
+ used to quote that character so that its special meaning
+ does not apply. For example, "\." can be used to place
+ a dot character in a label.
+
+\DDD where each D is a digit is the octet corresponding to
+ the decimal number described by DDD. The resulting
+ octet is assumed to be text and is not checked for
+ special meaning.
+
+( ) Parentheses are used to group data that crosses a line
+ boundary. In effect, line terminations are not
+ recognized within parentheses.
+
+; Semicolon is used to start a comment; the remainder of
+ the line is ignored.
+
+5.2. Use of master files to define zones
+
+When a master file is used to load a zone, the operation should be
+suppressed if any errors are encountered in the master file. The
+rationale for this is that a single error can have widespread
+consequences. For example, suppose that the RRs defining a delegation
+have syntax errors; then the server will return authoritative name
+errors for all names in the subzone (except in the case where the
+subzone is also present on the server).
+
+Several other validity checks that should be performed in addition to
+insuring that the file is syntactically correct:
+
+ 1. All RRs in the file should have the same class.
+
+ 2. Exactly one SOA RR should be present at the top of the zone.
+
+ 3. If delegations are present and glue information is required,
+ it should be present.
+
+
+
+Mockapetris [Page 35]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ 4. Information present outside of the authoritative nodes in the
+ zone should be glue information, rather than the result of an
+ origin or similar error.
+
+5.3. Master file example
+
+The following is an example file which might be used to define the
+ISI.EDU zone.and is loaded with an origin of ISI.EDU:
+
+@ IN SOA VENERA Action\.domains (
+ 20 ; SERIAL
+ 7200 ; REFRESH
+ 600 ; RETRY
+ 3600000; EXPIRE
+ 60) ; MINIMUM
+
+ NS A.ISI.EDU.
+ NS VENERA
+ NS VAXA
+ MX 10 VENERA
+ MX 20 VAXA
+
+A A 26.3.0.103
+
+VENERA A 10.1.0.52
+ A 128.9.0.32
+
+VAXA A 10.2.0.27
+ A 128.9.0.33
+
+
+$INCLUDE <SUBSYS>ISI-MAILBOXES.TXT
+
+Where the file <SUBSYS>ISI-MAILBOXES.TXT is:
+
+ MOE MB A.ISI.EDU.
+ LARRY MB A.ISI.EDU.
+ CURLEY MB A.ISI.EDU.
+ STOOGES MG MOE
+ MG LARRY
+ MG CURLEY
+
+Note the use of the \ character in the SOA RR to specify the responsible
+person mailbox "Action.domains at E.ISI.EDU".
+
+
+
+
+
+
+
+Mockapetris [Page 36]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+6. NAME SERVER IMPLEMENTATION
+
+6.1. Architecture
+
+The optimal structure for the name server will depend on the host
+operating system and whether the name server is integrated with resolver
+operations, either by supporting recursive service, or by sharing its
+database with a resolver. This section discusses implementation
+considerations for a name server which shares a database with a
+resolver, but most of these concerns are present in any name server.
+
+6.1.1. Control
+
+A name server must employ multiple concurrent activities, whether they
+are implemented as separate tasks in the host's OS or multiplexing
+inside a single name server program. It is simply not acceptable for a
+name server to block the service of UDP requests while it waits for TCP
+data for refreshing or query activities. Similarly, a name server
+should not attempt to provide recursive service without processing such
+requests in parallel, though it may choose to serialize requests from a
+single client, or to regard identical requests from the same client as
+duplicates. A name server should not substantially delay requests while
+it reloads a zone from master files or while it incorporates a newly
+refreshed zone into its database.
+
+6.1.2. Database
+
+While name server implementations are free to use any internal data
+structures they choose, the suggested structure consists of three major
+parts:
+
+ - A "catalog" data structure which lists the zones available to
+ this server, and a "pointer" to the zone data structure. The
+ main purpose of this structure is to find the nearest ancestor
+ zone, if any, for arriving standard queries.
+
+ - Separate data structures for each of the zones held by the
+ name server.
+
+ - A data structure for cached data. (or perhaps separate caches
+ for different classes)
+
+All of these data structures can be implemented an identical tree
+structure format, with different data chained off the nodes in different
+parts: in the catalog the data is pointers to zones, while in the zone
+and cache data structures, the data will be RRs. In designing the tree
+framework the designer should recognize that query processing will need
+to traverse the tree using case-insensitive label comparisons; and that
+
+
+
+Mockapetris [Page 37]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+in real data, a few nodes have a very high branching factor (100-1000 or
+more), but the vast majority have a very low branching factor (0-1).
+
+One way to solve the case problem is to store the labels for each node
+in two pieces: a standardized-case representation of the label where all
+ASCII characters are in a single case, together with a bit mask that
+denotes which characters are actually of a different case. The
+branching factor diversity can be handled using a simple linked list for
+a node until the branching factor exceeds some threshold, and
+transitioning to a hash structure after the threshold is exceeded. In
+any case, hash structures used to store tree sections must insure that
+hash functions and procedures preserve the casing conventions of the
+DNS.
+
+The use of separate structures for the different parts of the database
+is motivated by several factors:
+
+ - The catalog structure can be an almost static structure that
+ need change only when the system administrator changes the
+ zones supported by the server. This structure can also be
+ used to store parameters used to control refreshing
+ activities.
+
+ - The individual data structures for zones allow a zone to be
+ replaced simply by changing a pointer in the catalog. Zone
+ refresh operations can build a new structure and, when
+ complete, splice it into the database via a simple pointer
+ replacement. It is very important that when a zone is
+ refreshed, queries should not use old and new data
+ simultaneously.
+
+ - With the proper search procedures, authoritative data in zones
+ will always "hide", and hence take precedence over, cached
+ data.
+
+ - Errors in zone definitions that cause overlapping zones, etc.,
+ may cause erroneous responses to queries, but problem
+ determination is simplified, and the contents of one "bad"
+ zone can't corrupt another.
+
+ - Since the cache is most frequently updated, it is most
+ vulnerable to corruption during system restarts. It can also
+ become full of expired RR data. In either case, it can easily
+ be discarded without disturbing zone data.
+
+A major aspect of database design is selecting a structure which allows
+the name server to deal with crashes of the name server's host. State
+information which a name server should save across system crashes
+
+
+
+Mockapetris [Page 38]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+includes the catalog structure (including the state of refreshing for
+each zone) and the zone data itself.
+
+6.1.3. Time
+
+Both the TTL data for RRs and the timing data for refreshing activities
+depends on 32 bit timers in units of seconds. Inside the database,
+refresh timers and TTLs for cached data conceptually "count down", while
+data in the zone stays with constant TTLs.
+
+A recommended implementation strategy is to store time in two ways: as
+a relative increment and as an absolute time. One way to do this is to
+use positive 32 bit numbers for one type and negative numbers for the
+other. The RRs in zones use relative times; the refresh timers and
+cache data use absolute times. Absolute numbers are taken with respect
+to some known origin and converted to relative values when placed in the
+response to a query. When an absolute TTL is negative after conversion
+to relative, then the data is expired and should be ignored.
+
+6.2. Standard query processing
+
+The major algorithm for standard query processing is presented in
+[RFC-1034].
+
+When processing queries with QCLASS=*, or some other QCLASS which
+matches multiple classes, the response should never be authoritative
+unless the server can guarantee that the response covers all classes.
+
+When composing a response, RRs which are to be inserted in the
+additional section, but duplicate RRs in the answer or authority
+sections, may be omitted from the additional section.
+
+When a response is so long that truncation is required, the truncation
+should start at the end of the response and work forward in the
+datagram. Thus if there is any data for the authority section, the
+answer section is guaranteed to be unique.
+
+The MINIMUM value in the SOA should be used to set a floor on the TTL of
+data distributed from a zone. This floor function should be done when
+the data is copied into a response. This will allow future dynamic
+update protocols to change the SOA MINIMUM field without ambiguous
+semantics.
+
+6.3. Zone refresh and reload processing
+
+In spite of a server's best efforts, it may be unable to load zone data
+from a master file due to syntax errors, etc., or be unable to refresh a
+zone within the its expiration parameter. In this case, the name server
+
+
+
+Mockapetris [Page 39]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+should answer queries as if it were not supposed to possess the zone.
+
+If a master is sending a zone out via AXFR, and a new version is created
+during the transfer, the master should continue to send the old version
+if possible. In any case, it should never send part of one version and
+part of another. If completion is not possible, the master should reset
+the connection on which the zone transfer is taking place.
+
+6.4. Inverse queries (Optional)
+
+Inverse queries are an optional part of the DNS. Name servers are not
+required to support any form of inverse queries. If a name server
+receives an inverse query that it does not support, it returns an error
+response with the "Not Implemented" error set in the header. While
+inverse query support is optional, all name servers must be at least
+able to return the error response.
+
+6.4.1. The contents of inverse queries and responses Inverse
+queries reverse the mappings performed by standard query operations;
+while a standard query maps a domain name to a resource, an inverse
+query maps a resource to a domain name. For example, a standard query
+might bind a domain name to a host address; the corresponding inverse
+query binds the host address to a domain name.
+
+Inverse queries take the form of a single RR in the answer section of
+the message, with an empty question section. The owner name of the
+query RR and its TTL are not significant. The response carries
+questions in the question section which identify all names possessing
+the query RR WHICH THE NAME SERVER KNOWS. Since no name server knows
+about all of the domain name space, the response can never be assumed to
+be complete. Thus inverse queries are primarily useful for database
+management and debugging activities. Inverse queries are NOT an
+acceptable method of mapping host addresses to host names; use the IN-
+ADDR.ARPA domain instead.
+
+Where possible, name servers should provide case-insensitive comparisons
+for inverse queries. Thus an inverse query asking for an MX RR of
+"Venera.isi.edu" should get the same response as a query for
+"VENERA.ISI.EDU"; an inverse query for HINFO RR "IBM-PC UNIX" should
+produce the same result as an inverse query for "IBM-pc unix". However,
+this cannot be guaranteed because name servers may possess RRs that
+contain character strings but the name server does not know that the
+data is character.
+
+When a name server processes an inverse query, it either returns:
+
+ 1. zero, one, or multiple domain names for the specified
+ resource as QNAMEs in the question section
+
+
+
+Mockapetris [Page 40]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ 2. an error code indicating that the name server doesn't support
+ inverse mapping of the specified resource type.
+
+When the response to an inverse query contains one or more QNAMEs, the
+owner name and TTL of the RR in the answer section which defines the
+inverse query is modified to exactly match an RR found at the first
+QNAME.
+
+RRs returned in the inverse queries cannot be cached using the same
+mechanism as is used for the replies to standard queries. One reason
+for this is that a name might have multiple RRs of the same type, and
+only one would appear. For example, an inverse query for a single
+address of a multiply homed host might create the impression that only
+one address existed.
+
+6.4.2. Inverse query and response example The overall structure
+of an inverse query for retrieving the domain name that corresponds to
+Internet address 10.1.0.52 is shown below:
+
+ +-----------------------------------------+
+ Header | OPCODE=IQUERY, ID=997 |
+ +-----------------------------------------+
+ Question | <empty> |
+ +-----------------------------------------+
+ Answer | <anyname> A IN 10.1.0.52 |
+ +-----------------------------------------+
+ Authority | <empty> |
+ +-----------------------------------------+
+ Additional | <empty> |
+ +-----------------------------------------+
+
+This query asks for a question whose answer is the Internet style
+address 10.1.0.52. Since the owner name is not known, any domain name
+can be used as a placeholder (and is ignored). A single octet of zero,
+signifying the root, is usually used because it minimizes the length of
+the message. The TTL of the RR is not significant. The response to
+this query might be:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris [Page 41]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ +-----------------------------------------+
+ Header | OPCODE=RESPONSE, ID=997 |
+ +-----------------------------------------+
+ Question |QTYPE=A, QCLASS=IN, QNAME=VENERA.ISI.EDU |
+ +-----------------------------------------+
+ Answer | VENERA.ISI.EDU A IN 10.1.0.52 |
+ +-----------------------------------------+
+ Authority | <empty> |
+ +-----------------------------------------+
+ Additional | <empty> |
+ +-----------------------------------------+
+
+Note that the QTYPE in a response to an inverse query is the same as the
+TYPE field in the answer section of the inverse query. Responses to
+inverse queries may contain multiple questions when the inverse is not
+unique. If the question section in the response is not empty, then the
+RR in the answer section is modified to correspond to be an exact copy
+of an RR at the first QNAME.
+
+6.4.3. Inverse query processing
+
+Name servers that support inverse queries can support these operations
+through exhaustive searches of their databases, but this becomes
+impractical as the size of the database increases. An alternative
+approach is to invert the database according to the search key.
+
+For name servers that support multiple zones and a large amount of data,
+the recommended approach is separate inversions for each zone. When a
+particular zone is changed during a refresh, only its inversions need to
+be redone.
+
+Support for transfer of this type of inversion may be included in future
+versions of the domain system, but is not supported in this version.
+
+6.5. Completion queries and responses
+
+The optional completion services described in RFC-882 and RFC-883 have
+been deleted. Redesigned services may become available in the future.
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris [Page 42]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+7. RESOLVER IMPLEMENTATION
+
+The top levels of the recommended resolver algorithm are discussed in
+[RFC-1034]. This section discusses implementation details assuming the
+database structure suggested in the name server implementation section
+of this memo.
+
+7.1. Transforming a user request into a query
+
+The first step a resolver takes is to transform the client's request,
+stated in a format suitable to the local OS, into a search specification
+for RRs at a specific name which match a specific QTYPE and QCLASS.
+Where possible, the QTYPE and QCLASS should correspond to a single type
+and a single class, because this makes the use of cached data much
+simpler. The reason for this is that the presence of data of one type
+in a cache doesn't confirm the existence or non-existence of data of
+other types, hence the only way to be sure is to consult an
+authoritative source. If QCLASS=* is used, then authoritative answers
+won't be available.
+
+Since a resolver must be able to multiplex multiple requests if it is to
+perform its function efficiently, each pending request is usually
+represented in some block of state information. This state block will
+typically contain:
+
+ - A timestamp indicating the time the request began.
+ The timestamp is used to decide whether RRs in the database
+ can be used or are out of date. This timestamp uses the
+ absolute time format previously discussed for RR storage in
+ zones and caches. Note that when an RRs TTL indicates a
+ relative time, the RR must be timely, since it is part of a
+ zone. When the RR has an absolute time, it is part of a
+ cache, and the TTL of the RR is compared against the timestamp
+ for the start of the request.
+
+ Note that using the timestamp is superior to using a current
+ time, since it allows RRs with TTLs of zero to be entered in
+ the cache in the usual manner, but still used by the current
+ request, even after intervals of many seconds due to system
+ load, query retransmission timeouts, etc.
+
+ - Some sort of parameters to limit the amount of work which will
+ be performed for this request.
+
+ The amount of work which a resolver will do in response to a
+ client request must be limited to guard against errors in the
+ database, such as circular CNAME references, and operational
+ problems, such as network partition which prevents the
+
+
+
+Mockapetris [Page 43]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ resolver from accessing the name servers it needs. While
+ local limits on the number of times a resolver will retransmit
+ a particular query to a particular name server address are
+ essential, the resolver should have a global per-request
+ counter to limit work on a single request. The counter should
+ be set to some initial value and decremented whenever the
+ resolver performs any action (retransmission timeout,
+ retransmission, etc.) If the counter passes zero, the request
+ is terminated with a temporary error.
+
+ Note that if the resolver structure allows one request to
+ start others in parallel, such as when the need to access a
+ name server for one request causes a parallel resolve for the
+ name server's addresses, the spawned request should be started
+ with a lower counter. This prevents circular references in
+ the database from starting a chain reaction of resolver
+ activity.
+
+ - The SLIST data structure discussed in [RFC-1034].
+
+ This structure keeps track of the state of a request if it
+ must wait for answers from foreign name servers.
+
+7.2. Sending the queries
+
+As described in [RFC-1034], the basic task of the resolver is to
+formulate a query which will answer the client's request and direct that
+query to name servers which can provide the information. The resolver
+will usually only have very strong hints about which servers to ask, in
+the form of NS RRs, and may have to revise the query, in response to
+CNAMEs, or revise the set of name servers the resolver is asking, in
+response to delegation responses which point the resolver to name
+servers closer to the desired information. In addition to the
+information requested by the client, the resolver may have to call upon
+its own services to determine the address of name servers it wishes to
+contact.
+
+In any case, the model used in this memo assumes that the resolver is
+multiplexing attention between multiple requests, some from the client,
+and some internally generated. Each request is represented by some
+state information, and the desired behavior is that the resolver
+transmit queries to name servers in a way that maximizes the probability
+that the request is answered, minimizes the time that the request takes,
+and avoids excessive transmissions. The key algorithm uses the state
+information of the request to select the next name server address to
+query, and also computes a timeout which will cause the next action
+should a response not arrive. The next action will usually be a
+transmission to some other server, but may be a temporary error to the
+
+
+
+Mockapetris [Page 44]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+client.
+
+The resolver always starts with a list of server names to query (SLIST).
+This list will be all NS RRs which correspond to the nearest ancestor
+zone that the resolver knows about. To avoid startup problems, the
+resolver should have a set of default servers which it will ask should
+it have no current NS RRs which are appropriate. The resolver then adds
+to SLIST all of the known addresses for the name servers, and may start
+parallel requests to acquire the addresses of the servers when the
+resolver has the name, but no addresses, for the name servers.
+
+To complete initialization of SLIST, the resolver attaches whatever
+history information it has to the each address in SLIST. This will
+usually consist of some sort of weighted averages for the response time
+of the address, and the batting average of the address (i.e., how often
+the address responded at all to the request). Note that this
+information should be kept on a per address basis, rather than on a per
+name server basis, because the response time and batting average of a
+particular server may vary considerably from address to address. Note
+also that this information is actually specific to a resolver address /
+server address pair, so a resolver with multiple addresses may wish to
+keep separate histories for each of its addresses. Part of this step
+must deal with addresses which have no such history; in this case an
+expected round trip time of 5-10 seconds should be the worst case, with
+lower estimates for the same local network, etc.
+
+Note that whenever a delegation is followed, the resolver algorithm
+reinitializes SLIST.
+
+The information establishes a partial ranking of the available name
+server addresses. Each time an address is chosen and the state should
+be altered to prevent its selection again until all other addresses have
+been tried. The timeout for each transmission should be 50-100% greater
+than the average predicted value to allow for variance in response.
+
+Some fine points:
+
+ - The resolver may encounter a situation where no addresses are
+ available for any of the name servers named in SLIST, and
+ where the servers in the list are precisely those which would
+ normally be used to look up their own addresses. This
+ situation typically occurs when the glue address RRs have a
+ smaller TTL than the NS RRs marking delegation, or when the
+ resolver caches the result of a NS search. The resolver
+ should detect this condition and restart the search at the
+ next ancestor zone, or alternatively at the root.
+
+
+
+
+
+Mockapetris [Page 45]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ - If a resolver gets a server error or other bizarre response
+ from a name server, it should remove it from SLIST, and may
+ wish to schedule an immediate transmission to the next
+ candidate server address.
+
+7.3. Processing responses
+
+The first step in processing arriving response datagrams is to parse the
+response. This procedure should include:
+
+ - Check the header for reasonableness. Discard datagrams which
+ are queries when responses are expected.
+
+ - Parse the sections of the message, and insure that all RRs are
+ correctly formatted.
+
+ - As an optional step, check the TTLs of arriving data looking
+ for RRs with excessively long TTLs. If a RR has an
+ excessively long TTL, say greater than 1 week, either discard
+ the whole response, or limit all TTLs in the response to 1
+ week.
+
+The next step is to match the response to a current resolver request.
+The recommended strategy is to do a preliminary matching using the ID
+field in the domain header, and then to verify that the question section
+corresponds to the information currently desired. This requires that
+the transmission algorithm devote several bits of the domain ID field to
+a request identifier of some sort. This step has several fine points:
+
+ - Some name servers send their responses from different
+ addresses than the one used to receive the query. That is, a
+ resolver cannot rely that a response will come from the same
+ address which it sent the corresponding query to. This name
+ server bug is typically encountered in UNIX systems.
+
+ - If the resolver retransmits a particular request to a name
+ server it should be able to use a response from any of the
+ transmissions. However, if it is using the response to sample
+ the round trip time to access the name server, it must be able
+ to determine which transmission matches the response (and keep
+ transmission times for each outgoing message), or only
+ calculate round trip times based on initial transmissions.
+
+ - A name server will occasionally not have a current copy of a
+ zone which it should have according to some NS RRs. The
+ resolver should simply remove the name server from the current
+ SLIST, and continue.
+
+
+
+
+Mockapetris [Page 46]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+7.4. Using the cache
+
+In general, we expect a resolver to cache all data which it receives in
+responses since it may be useful in answering future client requests.
+However, there are several types of data which should not be cached:
+
+ - When several RRs of the same type are available for a
+ particular owner name, the resolver should either cache them
+ all or none at all. When a response is truncated, and a
+ resolver doesn't know whether it has a complete set, it should
+ not cache a possibly partial set of RRs.
+
+ - Cached data should never be used in preference to
+ authoritative data, so if caching would cause this to happen
+ the data should not be cached.
+
+ - The results of an inverse query should not be cached.
+
+ - The results of standard queries where the QNAME contains "*"
+ labels if the data might be used to construct wildcards. The
+ reason is that the cache does not necessarily contain existing
+ RRs or zone boundary information which is necessary to
+ restrict the application of the wildcard RRs.
+
+ - RR data in responses of dubious reliability. When a resolver
+ receives unsolicited responses or RR data other than that
+ requested, it should discard it without caching it. The basic
+ implication is that all sanity checks on a packet should be
+ performed before any of it is cached.
+
+In a similar vein, when a resolver has a set of RRs for some name in a
+response, and wants to cache the RRs, it should check its cache for
+already existing RRs. Depending on the circumstances, either the data
+in the response or the cache is preferred, but the two should never be
+combined. If the data in the response is from authoritative data in the
+answer section, it is always preferred.
+
+8. MAIL SUPPORT
+
+The domain system defines a standard for mapping mailboxes into domain
+names, and two methods for using the mailbox information to derive mail
+routing information. The first method is called mail exchange binding
+and the other method is mailbox binding. The mailbox encoding standard
+and mail exchange binding are part of the DNS official protocol, and are
+the recommended method for mail routing in the Internet. Mailbox
+binding is an experimental feature which is still under development and
+subject to change.
+
+
+
+
+Mockapetris [Page 47]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+The mailbox encoding standard assumes a mailbox name of the form
+"<local-part>@<mail-domain>". While the syntax allowed in each of these
+sections varies substantially between the various mail internets, the
+preferred syntax for the ARPA Internet is given in [RFC-822].
+
+The DNS encodes the <local-part> as a single label, and encodes the
+<mail-domain> as a domain name. The single label from the <local-part>
+is prefaced to the domain name from <mail-domain> to form the domain
+name corresponding to the mailbox. Thus the mailbox HOSTMASTER at SRI-
+NIC.ARPA is mapped into the domain name HOSTMASTER.SRI-NIC.ARPA. If the
+<local-part> contains dots or other special characters, its
+representation in a master file will require the use of backslash
+quoting to ensure that the domain name is properly encoded. For
+example, the mailbox Action.domains at ISI.EDU would be represented as
+Action\.domains.ISI.EDU.
+
+8.1. Mail exchange binding
+
+Mail exchange binding uses the <mail-domain> part of a mailbox
+specification to determine where mail should be sent. The <local-part>
+is not even consulted. [RFC-974] specifies this method in detail, and
+should be consulted before attempting to use mail exchange support.
+
+One of the advantages of this method is that it decouples mail
+destination naming from the hosts used to support mail service, at the
+cost of another layer of indirection in the lookup function. However,
+the addition layer should eliminate the need for complicated "%", "!",
+etc encodings in <local-part>.
+
+The essence of the method is that the <mail-domain> is used as a domain
+name to locate type MX RRs which list hosts willing to accept mail for
+<mail-domain>, together with preference values which rank the hosts
+according to an order specified by the administrators for <mail-domain>.
+
+In this memo, the <mail-domain> ISI.EDU is used in examples, together
+with the hosts VENERA.ISI.EDU and VAXA.ISI.EDU as mail exchanges for
+ISI.EDU. If a mailer had a message for Mockapetris at ISI.EDU, it would
+route it by looking up MX RRs for ISI.EDU. The MX RRs at ISI.EDU name
+VENERA.ISI.EDU and VAXA.ISI.EDU, and type A queries can find the host
+addresses.
+
+8.2. Mailbox binding (Experimental)
+
+In mailbox binding, the mailer uses the entire mail destination
+specification to construct a domain name. The encoded domain name for
+the mailbox is used as the QNAME field in a QTYPE=MAILB query.
+
+Several outcomes are possible for this query:
+
+
+
+Mockapetris [Page 48]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ 1. The query can return a name error indicating that the mailbox
+ does not exist as a domain name.
+
+ In the long term, this would indicate that the specified
+ mailbox doesn't exist. However, until the use of mailbox
+ binding is universal, this error condition should be
+ interpreted to mean that the organization identified by the
+ global part does not support mailbox binding. The
+ appropriate procedure is to revert to exchange binding at
+ this point.
+
+ 2. The query can return a Mail Rename (MR) RR.
+
+ The MR RR carries new mailbox specification in its RDATA
+ field. The mailer should replace the old mailbox with the
+ new one and retry the operation.
+
+ 3. The query can return a MB RR.
+
+ The MB RR carries a domain name for a host in its RDATA
+ field. The mailer should deliver the message to that host
+ via whatever protocol is applicable, e.g., b,SMTP.
+
+ 4. The query can return one or more Mail Group (MG) RRs.
+
+ This condition means that the mailbox was actually a mailing
+ list or mail group, rather than a single mailbox. Each MG RR
+ has a RDATA field that identifies a mailbox that is a member
+ of the group. The mailer should deliver a copy of the
+ message to each member.
+
+ 5. The query can return a MB RR as well as one or more MG RRs.
+
+ This condition means the the mailbox was actually a mailing
+ list. The mailer can either deliver the message to the host
+ specified by the MB RR, which will in turn do the delivery to
+ all members, or the mailer can use the MG RRs to do the
+ expansion itself.
+
+In any of these cases, the response may include a Mail Information
+(MINFO) RR. This RR is usually associated with a mail group, but is
+legal with a MB. The MINFO RR identifies two mailboxes. One of these
+identifies a responsible person for the original mailbox name. This
+mailbox should be used for requests to be added to a mail group, etc.
+The second mailbox name in the MINFO RR identifies a mailbox that should
+receive error messages for mail failures. This is particularly
+appropriate for mailing lists when errors in member names should be
+reported to a person other than the one who sends a message to the list.
+
+
+
+Mockapetris [Page 49]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+New fields may be added to this RR in the future.
+
+
+9. REFERENCES and BIBLIOGRAPHY
+
+[Dyer 87] S. Dyer, F. Hsu, "Hesiod", Project Athena
+ Technical Plan - Name Service, April 1987, version 1.9.
+
+ Describes the fundamentals of the Hesiod name service.
+
+[IEN-116] J. Postel, "Internet Name Server", IEN-116,
+ USC/Information Sciences Institute, August 1979.
+
+ A name service obsoleted by the Domain Name System, but
+ still in use.
+
+[Quarterman 86] J. Quarterman, and J. Hoskins, "Notable Computer Networks",
+ Communications of the ACM, October 1986, volume 29, number
+ 10.
+
+[RFC-742] K. Harrenstien, "NAME/FINGER", RFC-742, Network
+ Information Center, SRI International, December 1977.
+
+[RFC-768] J. Postel, "User Datagram Protocol", RFC-768,
+ USC/Information Sciences Institute, August 1980.
+
+[RFC-793] J. Postel, "Transmission Control Protocol", RFC-793,
+ USC/Information Sciences Institute, September 1981.
+
+[RFC-799] D. Mills, "Internet Name Domains", RFC-799, COMSAT,
+ September 1981.
+
+ Suggests introduction of a hierarchy in place of a flat
+ name space for the Internet.
+
+[RFC-805] J. Postel, "Computer Mail Meeting Notes", RFC-805,
+ USC/Information Sciences Institute, February 1982.
+
+[RFC-810] E. Feinler, K. Harrenstien, Z. Su, and V. White, "DOD
+ Internet Host Table Specification", RFC-810, Network
+ Information Center, SRI International, March 1982.
+
+ Obsolete. See RFC-952.
+
+[RFC-811] K. Harrenstien, V. White, and E. Feinler, "Hostnames
+ Server", RFC-811, Network Information Center, SRI
+ International, March 1982.
+
+
+
+
+Mockapetris [Page 50]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ Obsolete. See RFC-953.
+
+[RFC-812] K. Harrenstien, and V. White, "NICNAME/WHOIS", RFC-812,
+ Network Information Center, SRI International, March
+ 1982.
+
+[RFC-819] Z. Su, and J. Postel, "The Domain Naming Convention for
+ Internet User Applications", RFC-819, Network
+ Information Center, SRI International, August 1982.
+
+ Early thoughts on the design of the domain system.
+ Current implementation is completely different.
+
+[RFC-821] J. Postel, "Simple Mail Transfer Protocol", RFC-821,
+ USC/Information Sciences Institute, August 1980.
+
+[RFC-830] Z. Su, "A Distributed System for Internet Name Service",
+ RFC-830, Network Information Center, SRI International,
+ October 1982.
+
+ Early thoughts on the design of the domain system.
+ Current implementation is completely different.
+
+[RFC-882] P. Mockapetris, "Domain names - Concepts and
+ Facilities," RFC-882, USC/Information Sciences
+ Institute, November 1983.
+
+ Superceeded by this memo.
+
+[RFC-883] P. Mockapetris, "Domain names - Implementation and
+ Specification," RFC-883, USC/Information Sciences
+ Institute, November 1983.
+
+ Superceeded by this memo.
+
+[RFC-920] J. Postel and J. Reynolds, "Domain Requirements",
+ RFC-920, USC/Information Sciences Institute,
+ October 1984.
+
+ Explains the naming scheme for top level domains.
+
+[RFC-952] K. Harrenstien, M. Stahl, E. Feinler, "DoD Internet Host
+ Table Specification", RFC-952, SRI, October 1985.
+
+ Specifies the format of HOSTS.TXT, the host/address
+ table replaced by the DNS.
+
+
+
+
+
+Mockapetris [Page 51]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+[RFC-953] K. Harrenstien, M. Stahl, E. Feinler, "HOSTNAME Server",
+ RFC-953, SRI, October 1985.
+
+ This RFC contains the official specification of the
+ hostname server protocol, which is obsoleted by the DNS.
+ This TCP based protocol accesses information stored in
+ the RFC-952 format, and is used to obtain copies of the
+ host table.
+
+[RFC-973] P. Mockapetris, "Domain System Changes and
+ Observations", RFC-973, USC/Information Sciences
+ Institute, January 1986.
+
+ Describes changes to RFC-882 and RFC-883 and reasons for
+ them.
+
+[RFC-974] C. Partridge, "Mail routing and the domain system",
+ RFC-974, CSNET CIC BBN Labs, January 1986.
+
+ Describes the transition from HOSTS.TXT based mail
+ addressing to the more powerful MX system used with the
+ domain system.
+
+[RFC-1001] NetBIOS Working Group, "Protocol standard for a NetBIOS
+ service on a TCP/UDP transport: Concepts and Methods",
+ RFC-1001, March 1987.
+
+ This RFC and RFC-1002 are a preliminary design for
+ NETBIOS on top of TCP/IP which proposes to base NetBIOS
+ name service on top of the DNS.
+
+[RFC-1002] NetBIOS Working Group, "Protocol standard for a NetBIOS
+ service on a TCP/UDP transport: Detailed
+ Specifications", RFC-1002, March 1987.
+
+[RFC-1010] J. Reynolds, and J. Postel, "Assigned Numbers", RFC-1010,
+ USC/Information Sciences Institute, May 1987.
+
+ Contains socket numbers and mnemonics for host names,
+ operating systems, etc.
+
+[RFC-1031] W. Lazear, "MILNET Name Domain Transition", RFC-1031,
+ November 1987.
+
+ Describes a plan for converting the MILNET to the DNS.
+
+[RFC-1032] M. Stahl, "Establishing a Domain - Guidelines for
+ Administrators", RFC-1032, November 1987.
+
+
+
+Mockapetris [Page 52]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ Describes the registration policies used by the NIC to
+ administer the top level domains and delegate subzones.
+
+[RFC-1033] M. Lottor, "Domain Administrators Operations Guide",
+ RFC-1033, November 1987.
+
+ A cookbook for domain administrators.
+
+[Solomon 82] M. Solomon, L. Landweber, and D. Neuhengen, "The CSNET
+ Name Server", Computer Networks, vol 6, nr 3, July 1982.
+
+ Describes a name service for CSNET which is independent
+ from the DNS and DNS use in the CSNET.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris [Page 53]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+Index
+
+ * 13
+
+ ; 33, 35
+
+ <character-string> 35
+ <domain-name> 34
+
+ @ 35
+
+ \ 35
+
+ A 12
+
+ Byte order 8
+
+ CH 13
+ Character case 9
+ CLASS 11
+ CNAME 12
+ Completion 42
+ CS 13
+
+ Hesiod 13
+ HINFO 12
+ HS 13
+
+ IN 13
+ IN-ADDR.ARPA domain 22
+ Inverse queries 40
+
+ Mailbox names 47
+ MB 12
+ MD 12
+ MF 12
+ MG 12
+ MINFO 12
+ MINIMUM 20
+ MR 12
+ MX 12
+
+ NS 12
+ NULL 12
+
+ Port numbers 32
+ Primary server 5
+ PTR 12, 18
+
+
+
+Mockapetris [Page 54]
+
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ QCLASS 13
+ QTYPE 12
+
+ RDATA 12
+ RDLENGTH 11
+
+ Secondary server 5
+ SOA 12
+ Stub resolvers 7
+
+ TCP 32
+ TXT 12
+ TYPE 11
+
+ UDP 32
+
+ WKS 12
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris [Page 55]
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/rfc2671.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/rfc2671.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,395 @@
+
+
+
+
+
+
+Network Working Group P. Vixie
+Request for Comments: 2671 ISC
+Category: Standards Track August 1999
+
+
+ Extension Mechanisms for DNS (EDNS0)
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+Abstract
+
+ The Domain Name System's wire protocol includes a number of fixed
+ fields whose range has been or soon will be exhausted and does not
+ allow clients to advertise their capabilities to servers. This
+ document describes backward compatible mechanisms for allowing the
+ protocol to grow.
+
+1 - Rationale and Scope
+
+1.1. DNS (see [RFC1035]) specifies a Message Format and within such
+ messages there are standard formats for encoding options, errors,
+ and name compression. The maximum allowable size of a DNS Message
+ is fixed. Many of DNS's protocol limits are too small for uses
+ which are or which are desired to become common. There is no way
+ for implementations to advertise their capabilities.
+
+1.2. Existing clients will not know how to interpret the protocol
+ extensions detailed here. In practice, these clients will be
+ upgraded when they have need of a new feature, and only new
+ features will make use of the extensions. We must however take
+ account of client behaviour in the face of extra fields, and design
+ a fallback scheme for interoperability with these clients.
+
+
+
+
+
+
+
+
+
+Vixie Standards Track [Page 1]
+
+RFC 2671 Extension Mechanisms for DNS (EDNS0) August 1999
+
+
+2 - Affected Protocol Elements
+
+2.1. The DNS Message Header's (see [RFC1035 4.1.1]) second full 16-bit
+ word is divided into a 4-bit OPCODE, a 4-bit RCODE, and a number of
+ 1-bit flags. The original reserved Z bits have been allocated to
+ various purposes, and most of the RCODE values are now in use.
+ More flags and more possible RCODEs are needed.
+
+2.2. The first two bits of a wire format domain label are used to denote
+ the type of the label. [RFC1035 4.1.4] allocates two of the four
+ possible types and reserves the other two. Proposals for use of
+ the remaining types far outnumber those available. More label
+ types are needed.
+
+2.3. DNS Messages are limited to 512 octets in size when sent over UDP.
+ While the minimum maximum reassembly buffer size still allows a
+ limit of 512 octets of UDP payload, most of the hosts now connected
+ to the Internet are able to reassemble larger datagrams. Some
+ mechanism must be created to allow requestors to advertise larger
+ buffer sizes to responders.
+
+3 - Extended Label Types
+
+3.1. The "0 1" label type will now indicate an extended label type,
+ whose value is encoded in the lower six bits of the first octet of
+ a label. All subsequently developed label types should be encoded
+ using an extended label type.
+
+3.2. The "1 1 1 1 1 1" extended label type will be reserved for future
+ expansion of the extended label type code space.
+
+4 - OPT pseudo-RR
+
+4.1. One OPT pseudo-RR can be added to the additional data section of
+ either a request or a response. An OPT is called a pseudo-RR
+ because it pertains to a particular transport level message and not
+ to any actual DNS data. OPT RRs shall never be cached, forwarded,
+ or stored in or loaded from master files. The quantity of OPT
+ pseudo-RRs per message shall be either zero or one, but not
+ greater.
+
+4.2. An OPT RR has a fixed part and a variable set of options expressed
+ as {attribute, value} pairs. The fixed part holds some DNS meta
+ data and also a small collection of new protocol elements which we
+ expect to be so popular that it would be a waste of wire space to
+ encode them as {attribute, value} pairs.
+
+
+
+
+
+Vixie Standards Track [Page 2]
+
+RFC 2671 Extension Mechanisms for DNS (EDNS0) August 1999
+
+
+4.3. The fixed part of an OPT RR is structured as follows:
+
+ Field Name Field Type Description
+ ------------------------------------------------------
+ NAME domain name empty (root domain)
+ TYPE u_int16_t OPT
+ CLASS u_int16_t sender's UDP payload size
+ TTL u_int32_t extended RCODE and flags
+ RDLEN u_int16_t describes RDATA
+ RDATA octet stream {attribute,value} pairs
+
+4.4. The variable part of an OPT RR is encoded in its RDATA and is
+ structured as zero or more of the following:
+
+ +0 (MSB) +1 (LSB)
+ +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ 0: | OPTION-CODE |
+ +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ 2: | OPTION-LENGTH |
+ +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ 4: | |
+ / OPTION-DATA /
+ / /
+ +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+
+ OPTION-CODE (Assigned by IANA.)
+
+ OPTION-LENGTH Size (in octets) of OPTION-DATA.
+
+ OPTION-DATA Varies per OPTION-CODE.
+
+4.5. The sender's UDP payload size (which OPT stores in the RR CLASS
+ field) is the number of octets of the largest UDP payload that can
+ be reassembled and delivered in the sender's network stack. Note
+ that path MTU, with or without fragmentation, may be smaller than
+ this.
+
+4.5.1. Note that a 512-octet UDP payload requires a 576-octet IP
+ reassembly buffer. Choosing 1280 on an Ethernet connected
+ requestor would be reasonable. The consequence of choosing too
+ large a value may be an ICMP message from an intermediate
+ gateway, or even a silent drop of the response message.
+
+4.5.2. Both requestors and responders are advised to take account of the
+ path's discovered MTU (if already known) when considering message
+ sizes.
+
+
+
+
+
+Vixie Standards Track [Page 3]
+
+RFC 2671 Extension Mechanisms for DNS (EDNS0) August 1999
+
+
+4.5.3. The requestor's maximum payload size can change over time, and
+ should therefore not be cached for use beyond the transaction in
+ which it is advertised.
+
+4.5.4. The responder's maximum payload size can change over time, but
+ can be reasonably expected to remain constant between two
+ sequential transactions; for example, a meaningless QUERY to
+ discover a responder's maximum UDP payload size, followed
+ immediately by an UPDATE which takes advantage of this size.
+ (This is considered preferrable to the outright use of TCP for
+ oversized requests, if there is any reason to suspect that the
+ responder implements EDNS, and if a request will not fit in the
+ default 512 payload size limit.)
+
+4.5.5. Due to transaction overhead, it is unwise to advertise an
+ architectural limit as a maximum UDP payload size. Just because
+ your stack can reassemble 64KB datagrams, don't assume that you
+ want to spend more than about 4KB of state memory per ongoing
+ transaction.
+
+4.6. The extended RCODE and flags (which OPT stores in the RR TTL field)
+ are structured as follows:
+
+ +0 (MSB) +1 (LSB)
+ +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ 0: | EXTENDED-RCODE | VERSION |
+ +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ 2: | Z |
+ +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+
+ EXTENDED-RCODE Forms upper 8 bits of extended 12-bit RCODE. Note
+ that EXTENDED-RCODE value "0" indicates that an
+ unextended RCODE is in use (values "0" through "15").
+
+ VERSION Indicates the implementation level of whoever sets
+ it. Full conformance with this specification is
+ indicated by version "0." Requestors are encouraged
+ to set this to the lowest implemented level capable
+ of expressing a transaction, to minimize the
+ responder and network load of discovering the
+ greatest common implementation level between
+ requestor and responder. A requestor's version
+ numbering strategy should ideally be a run time
+ configuration option.
+
+ If a responder does not implement the VERSION level
+ of the request, then it answers with RCODE=BADVERS.
+ All responses will be limited in format to the
+
+
+
+Vixie Standards Track [Page 4]
+
+RFC 2671 Extension Mechanisms for DNS (EDNS0) August 1999
+
+
+ VERSION level of the request, but the VERSION of each
+ response will be the highest implementation level of
+ the responder. In this way a requestor will learn
+ the implementation level of a responder as a side
+ effect of every response, including error responses,
+ including RCODE=BADVERS.
+
+ Z Set to zero by senders and ignored by receivers,
+ unless modified in a subsequent specification.
+
+5 - Transport Considerations
+
+5.1. The presence of an OPT pseudo-RR in a request should be taken as an
+ indication that the requestor fully implements the given version of
+ EDNS, and can correctly understand any response that conforms to
+ that feature's specification.
+
+5.2. Lack of use of these features in a request must be taken as an
+ indication that the requestor does not implement any part of this
+ specification and that the responder may make no use of any
+ protocol extension described here in its response.
+
+5.3. Responders who do not understand these protocol extensions are
+ expected to send a response with RCODE NOTIMPL, FORMERR, or
+ SERVFAIL. Therefore use of extensions should be "probed" such that
+ a responder who isn't known to support them be allowed a retry with
+ no extensions if it responds with such an RCODE. If a responder's
+ capability level is cached by a requestor, a new probe should be
+ sent periodically to test for changes to responder capability.
+
+6 - Security Considerations
+
+ Requestor-side specification of the maximum buffer size may open a
+ new DNS denial of service attack if responders can be made to send
+ messages which are too large for intermediate gateways to forward,
+ thus leading to potential ICMP storms between gateways and
+ responders.
+
+7 - IANA Considerations
+
+ The IANA has assigned RR type code 41 for OPT.
+
+ It is the recommendation of this document and its working group
+ that IANA create a registry for EDNS Extended Label Types, for EDNS
+ Option Codes, and for EDNS Version Numbers.
+
+ This document assigns label type 0b01xxxxxx as "EDNS Extended Label
+ Type." We request that IANA record this assignment.
+
+
+
+Vixie Standards Track [Page 5]
+
+RFC 2671 Extension Mechanisms for DNS (EDNS0) August 1999
+
+
+ This document assigns extended label type 0bxx111111 as "Reserved
+ for future extended label types." We request that IANA record this
+ assignment.
+
+ This document assigns option code 65535 to "Reserved for future
+ expansion."
+
+ This document expands the RCODE space from 4 bits to 12 bits. This
+ will allow IANA to assign more than the 16 distinct RCODE values
+ allowed in [RFC1035].
+
+ This document assigns EDNS Extended RCODE "16" to "BADVERS".
+
+ IESG approval should be required to create new entries in the EDNS
+ Extended Label Type or EDNS Version Number registries, while any
+ published RFC (including Informational, Experimental, or BCP)
+ should be grounds for allocation of an EDNS Option Code.
+
+8 - Acknowledgements
+
+ Paul Mockapetris, Mark Andrews, Robert Elz, Don Lewis, Bob Halley,
+ Donald Eastlake, Rob Austein, Matt Crawford, Randy Bush, and Thomas
+ Narten were each instrumental in creating and refining this
+ specification.
+
+9 - References
+
+ [RFC1035] Mockapetris, P., "Domain Names - Implementation and
+ Specification", STD 13, RFC 1035, November 1987.
+
+10 - Author's Address
+
+ Paul Vixie
+ Internet Software Consortium
+ 950 Charter Street
+ Redwood City, CA 94063
+
+ Phone: +1 650 779 7001
+ EMail: vixie at isc.org
+
+
+
+
+
+
+
+
+
+
+
+
+Vixie Standards Track [Page 6]
+
+RFC 2671 Extension Mechanisms for DNS (EDNS0) August 1999
+
+
+11 - Full Copyright Statement
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Vixie Standards Track [Page 7]
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/rndc.conf
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/rndc.conf Thu Dec 21 01:30:28 2006
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2000, 2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Sample rndc configuration file.
+ */
+
+options {
+ default-server localhost;
+ default-key "rndckey";
+};
+
+server localhost {
+ key "rndckey";
+};
+
+key "rndckey" {
+ algorithm hmac-md5;
+ secret "ckyTJVIxigdpaEAjOMGNWgIPlYoKInXXqzsKikjSsiVJAWTkWONHwQlARsjY";
+};
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/root.zone
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/root.zone Thu Dec 21 01:30:28 2006
@@ -0,0 +1,14 @@
+; Root zone for testing
+. 3600000 IN SOA ns root (
+ 2002042901 ; SERIAL
+ 7200 ; REFRESH
+ 600 ; RETRY
+ 36000000 ; EXPIRE
+ 60 ; MINIMUM
+ )
+ NS ns.example.com
+ns.example.com A 127.0.0.2
+ AAAA ::2
+ A6 0 ::2
+
+
\ No newline at end of file
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/run_test_sresolv
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/run_test_sresolv Thu Dec 21 01:30:28 2006
@@ -0,0 +1,180 @@
+#! /bin/bash
+#
+# Run sresolv_test using our own name server
+#
+# --------------------------------------------------------------------
+#
+# This file is part of the Sofia-SIP package
+#
+# Copyright (C) 2005 Nokia Corporation.
+#
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+#
+# --------------------------------------------------------------------
+#
+# Author(s): Pekka Pessi <Pekka.Pessi at nokia.com>.
+#
+
+s=${0%/*}
+
+test x$s = x$0 && s=`pwd`
+
+PATH=/usr/sbin:/usr/local/sbin:/sbin:$PATH
+
+# Test for support for IPv6 on Linux. This probably fails on everything else.
+ipv6='sysctl net.ipv6.conf.default.mtu >& /dev/null'
+# Bind not working with IPv6 on RHEL 4:
+# client.c:1325: unexpected error: failed to get request's destination: failure
+#ipv6=false
+
+port=`expr $$ % \( 65536 - 1024 \) + 1024`
+
+# Try to find a free port
+if netstat --ip >/dev/null 2>&1 ; then
+ while netstat --ip -n -a | fgrep -q ":$port "
+ do
+ port=$(($port + 1))
+ if [$port = 65536] ; then
+ port=1024
+ fi
+ done
+fi
+
+# No named, no fun
+type -p named >/dev/null || exit 77
+
+if eval $ipv6
+then
+ # Figure out nice IPv6 address for us
+ ns=$(ip addr ls | awk '
+ /^[0-9]:/ { up = ($3 ~ /UP/) && ($3 !~ /LOOPBACK/); }
+ /inet6 fe80::/ { next; } # no link-local
+ up && $1 ~ /inet6/ { sub(/\/.*$/, "", $2); print $2; exit 0; }')
+
+ # Nothing found, use localnode ::1
+ if test -z "$ns"; then ns=::1 ; fi
+
+ listen6="listen-on-v6 port $port { any; };"
+else
+ ns="127.0.0.1"
+ listen4="listen-on port $port { 127.0.0.1; };"
+fi
+
+#
+# Set up configuration. First, nice tmpdir
+#
+t=${TMPDIR:-/tmp}/sofia-sip-sresolv-$USER-$$
+
+mkdir $t || exit 77
+
+# Main resolv.conf (with primary nameserver not answering)
+cat > $t/resolv.conf <<EOF
+# Zeroconf subnet, reserved range - no-one should answer this
+#nameserver 169.254.0.2
+#...but bind9 listens to it if using IPv6 ... and chokes on it.
+
+# 00:10:c6:e3:da:7f belongs to a Nokia WLAN card tucked safely in my closet
+nameserver fe80::10:c6ff:fee3:da7f
+
+# This is bind we set up
+nameserver $ns
+
+domain example.com
+
+# This is our addition
+port $port
+EOF
+
+# Resolv.conf with bad namserver addresses
+cat > $t/error.conf <<EOF
+nameserver 0.0.0.2
+nameserver 1.1.1.1.1
+search example.com
+port $port
+EOF
+
+cat > $t/named.conf <<EOF
+options {
+ directory "$(cd $s; pwd)";
+ pid-file "$t/named.pid";
+ notify no;
+ $listen4
+ $listen6
+};
+
+zone "example.com" in {
+ type master;
+ file "example.com";
+};
+
+zone "." in {
+ type master;
+ file "root.zone";
+};
+
+zone "188.2.194.in-addr.arpa" in {
+ type master;
+ file "194.2.188";
+};
+
+zone "0.0.127.in-addr.arpa" in {
+ type master;
+ file "127.zone";
+};
+
+zone "0.0.0.c.2.1.0.3.0.0.2.1.e.f.f.3.ip6.int" in {
+ type master;
+ file "3.f.f.e.1.2.0.0.3.0.1.2.c.0.0.0";
+};
+
+zone "0.0.0.c.2.1.0.3.0.0.2.1.e.f.f.3.ip6.arpa" in {
+ type master;
+ file "3.f.f.e.1.2.0.0.3.0.1.2.c.0.0.0.arpa";
+};
+
+EOF
+
+named -f -d 999 -c $t/named.conf &
+
+echo $0: started named pid $!
+for i in 1 2 3 4 5; do
+ test -r $t/named.pid && break
+ sleep 1;
+done
+
+test -r $t/named.pid || {
+ echo $0: cannot start named >&2 ;
+ if fgrep -q -i -e SELINUX=enforcing /etc/selinux/config 2>&/dev/null ; then
+ echo $0: perhaps you have to disable SELinux protection for named
+ fi
+ exit 77
+}
+
+function kill_named
+{
+ kill `cat $t/named.pid`
+ rm $t/named.conf $t/resolv.conf $t/error.conf $t/named.pid
+ rmdir $t
+}
+trap kill_named EXIT
+
+# export SOFIA_DEBUG=9
+
+$VALGRIND ./test_sresolv "$@" - $t/resolv.conf $t/error.conf || exit 1
+
+exit 0
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv/sres.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv/sres.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,267 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SOFIA_RESOLV_SRES_H
+/** Defined when <sofia-resolv/sres.h> has been included. */
+#define SOFIA_RESOLV_SRES_H
+/**
+ * @file sofia-resolv/sres.h Sofia DNS Resolver.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>,
+ * @author Teemu Jalava <Teemu.Jalava at nokia.com>,
+ * @author Mikko Haataja <ext-Mikko.A.Haataja at nokia.com>.
+ *
+ * @par Include Context
+ * @code
+ * #include <sys/types.h>
+ * #include <sys/socket.h>
+ * #include <netinet/in.h>
+ * #include <sofia-resolv/sres.h>
+ * @endcode
+ *
+ */
+
+#include <stdarg.h>
+#include "sofia-resolv/sres_config.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum {
+ /** Resolver timer interval in milliseconds. */
+ SRES_RETRANSMIT_INTERVAL = 500,
+#define SRES_RETRANSMIT_INTERVAL (SRES_RETRANSMIT_INTERVAL)
+
+ /** Initial retry interval in seconds. */
+ SRES_RETRY_INTERVAL = 1,
+#define SRES_RETRY_INTERVAL (SRES_RETRY_INTERVAL)
+
+ /** Maximum number of retries sent. */
+ SRES_MAX_RETRY_COUNT = 6,
+#define SRES_MAX_RETRY_COUNT (SRES_MAX_RETRY_COUNT)
+
+ /** Maximum number of search domains. */
+ SRES_MAX_SEARCH = 6,
+#define SRES_MAX_SEARCH (SRES_MAX_SEARCH)
+
+ /** Maximum number of nameservers. */
+ SRES_MAX_NAMESERVERS = 6,
+#define SRES_MAX_NAMESERVERS (SRES_MAX_NAMESERVERS)
+
+ /** Maximum length of domain name. */
+ SRES_MAXDNAME = 1025,
+#define SRES_MAXDNAME (SRES_MAXDNAME)
+
+ /** Maximum length of sortlist */
+ SRES_MAX_SORTLIST = 10
+#define SRES_MAX_SORTLIST (SRES_MAX_SORTLIST)
+};
+
+#ifndef SRES_RECORD_T
+#define SRES_RECORD_T
+/** Type representing any DNS record. */
+typedef union sres_record sres_record_t;
+#endif
+
+#ifndef SRES_CACHE_T
+#define SRES_CACHE_T
+/** Opaque type of DNS cache object. */
+typedef struct sres_cache sres_cache_t;
+#endif
+
+/** Opaque type of DNS resolver object. */
+typedef struct sres_resolver_s sres_resolver_t;
+
+#ifndef SRES_CONTEXT_T
+#define SRES_CONTEXT_T struct sres_context_s
+#endif
+/** Application-defined type for sres_query_t context. */
+typedef SRES_CONTEXT_T sres_context_t;
+
+/** Opaque type of DNS query object. */
+typedef struct sres_query_s sres_query_t;
+
+struct sockaddr;
+
+/** New resolver object. */
+SRESPUBFUN sres_resolver_t *sres_resolver_new(char const *resolv_conf_path);
+
+/** Copy a resolver. */
+SRESPUBFUN sres_resolver_t *sres_resolver_copy(sres_resolver_t *);
+
+/** New resolver object. */
+SRESPUBFUN
+sres_resolver_t *
+sres_resolver_new_with_cache(char const *conf_file_path,
+ sres_cache_t *cache,
+ char const *options, ...);
+
+/** New resolver object. */
+SRESPUBFUN
+sres_resolver_t *
+sres_resolver_new_with_cache_va(char const *conf_file_path,
+ sres_cache_t *cache,
+ char const *options, va_list va);
+
+/** Increase reference count on a resolver object. */
+SRESPUBFUN sres_resolver_t *sres_resolver_ref(sres_resolver_t *res);
+
+/** Decrease the reference count on a resolver object. */
+SRESPUBFUN void sres_resolver_unref(sres_resolver_t *res);
+
+/** Re-read resolv.conf if needed */
+SRESPUBFUN int sres_resolver_update(sres_resolver_t *res, int always);
+
+/** Set userdata pointer. */
+SRESPUBFUN
+void *sres_resolver_set_userdata(sres_resolver_t *res, void *userdata);
+
+/** Get userdata pointer. */
+SRESPUBFUN
+void *sres_resolver_get_userdata(sres_resolver_t const *res);
+
+/** Prototype for callback function.
+ *
+ * This kind of function is called when a query is completed. The called
+ * function is responsible for freeing the list of answers and it must
+ * (eventually) call sres_free_answers().
+ */
+typedef void sres_answer_f(sres_context_t *context,
+ sres_query_t *query,
+ sres_record_t **answers);
+
+/** Make a DNS query. */
+SRESPUBFUN
+sres_query_t *sres_query(sres_resolver_t *res,
+ sres_answer_f *callback,
+ sres_context_t *context,
+ uint16_t type,
+ char const *domain);
+
+/** Search DNS. */
+SRESPUBFUN
+sres_query_t *sres_search(sres_resolver_t *res,
+ sres_answer_f *callback,
+ sres_context_t *context,
+ uint16_t type,
+ char const *name);
+
+/** Make a reverse DNS query. */
+SRESPUBFUN
+sres_query_t *sres_query_sockaddr(sres_resolver_t *res,
+ sres_answer_f *callback,
+ sres_context_t *context,
+ uint16_t type,
+ struct sockaddr const *addr);
+
+/** Make a DNS query with socket. @deprecated */
+SRESPUBFUN
+sres_query_t *sres_query_make(sres_resolver_t *res,
+ sres_answer_f *callback,
+ sres_context_t *context,
+ int dummy,
+ uint16_t type,
+ char const *domain);
+
+/** Make a reverse DNS query with socket. @deprecated */
+SRESPUBFUN
+sres_query_t *sres_query_make_sockaddr(sres_resolver_t *res,
+ sres_answer_f *callback,
+ sres_context_t *context,
+ int dummy,
+ uint16_t type,
+ struct sockaddr const *addr);
+
+/** Rebind a DNS query. */
+SRESPUBFUN
+void sres_query_bind(sres_query_t *q,
+ sres_answer_f *callback,
+ sres_context_t *context);
+
+/**Get a list of matching (type/domain) records from cache. */
+SRESPUBFUN
+sres_record_t **sres_cached_answers(sres_resolver_t *res,
+ uint16_t type,
+ char const *domain);
+
+/**Search for a list of matching (type/name) records from cache. */
+SRESPUBFUN
+sres_record_t **sres_search_cached_answers(sres_resolver_t *res,
+ uint16_t type,
+ char const *name);
+
+/**Get a list of matching (type/domain) records from cache. */
+SRESPUBFUN
+sres_record_t **sres_cached_answers_sockaddr(sres_resolver_t *res,
+ uint16_t type,
+ struct sockaddr const *addr);
+
+/** Send a query, wait for answer, return results. */
+SRESPUBFUN
+int sres_blocking_query(sres_resolver_t *res,
+ uint16_t type,
+ char const *domain,
+ int ignore_cache,
+ sres_record_t ***return_records);
+
+/** Search DNS, return results. */
+SRESPUBFUN
+int sres_blocking_search(sres_resolver_t *res,
+ uint16_t type,
+ char const *name,
+ int ignore_cache,
+ sres_record_t ***return_records);
+
+/** Send a a reverse DNS query, wait for answer, return results. */
+SRESPUBFUN
+int sres_blocking_query_sockaddr(sres_resolver_t *res,
+ uint16_t type,
+ struct sockaddr const *addr,
+ int ignore_cache,
+ sres_record_t ***return_records);
+
+/** Return true (and set resolver in blocking mode) if resolver can block. */
+SRESPUBFUN int sres_is_blocking(sres_resolver_t *res);
+
+/** Sort the list of records */
+SRESPUBFUN int sres_sort_answers(sres_resolver_t *, sres_record_t **answers);
+
+/** Filter and sort the list of records */
+SRESPUBFUN
+int sres_filter_answers(sres_resolver_t *res,
+ sres_record_t **answers,
+ uint16_t type);
+
+/** Free the list records. */
+SRESPUBFUN void sres_free_answers(sres_resolver_t *, sres_record_t **answers);
+
+/** Free and zero one record. */
+SRESPUBFUN void sres_free_answer(sres_resolver_t *res, sres_record_t *answer);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SOFIA_RESOLV_SRES_H */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv/sres_async.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv/sres_async.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,123 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SOFIA_RESOLV_SRES_ASYNC_H
+/** Defined when <sofia-resolv/sres_async.h> has been included. */
+#define SOFIA_RESOLV_SRES_ASYNC_H
+
+/**
+ * @file sofia-resolv/sres_async.h
+ *
+ * Asynchronous interface for Sofia DNS Resolver.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @par Include Context
+ * @code
+ * #include <sys/types.h>
+ * #include <sys/socket.h>
+ * #include <netinet/in.h>
+ * #include <sofia-resolv/sres.h>
+ * #include <sofia-resolv/sres_async.h>
+ * @endcode
+ *
+ */
+
+#include "sofia-resolv/sres_config.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef SRES_ASYNC_T
+#define SRES_ASYNC_T struct sres_async_s
+#endif
+/** Application-defined type for context used by asynchronous operation. */
+typedef SRES_ASYNC_T sres_async_t;
+
+/** Prototype for update function.
+ *
+ * This kind of function is called when the nameserver configuration has
+ * been updated.
+ *
+ * If the old_socket is not -1, it indicates that old_socket will be closed
+ * and it should be removed from poll() or select() set.
+ *
+ * If the new_socket is not -1, it indicates that resolver has created new
+ * socket that should be added to the poll() or select() set.
+ *
+ * @sa sres_resolver_set_async(), sres_resolver_get_async()
+ */
+typedef int sres_update_f(sres_async_t *async,
+ sres_socket_t new_socket,
+ sres_socket_t old_socket);
+
+/** Set asynchronous operation data. */
+SRESPUBFUN
+sres_async_t *sres_resolver_set_async(sres_resolver_t *res,
+ sres_update_f *update,
+ sres_async_t *async,
+ int update_all);
+
+/** Get async operation data. */
+SRESPUBFUN
+sres_async_t *sres_resolver_get_async(sres_resolver_t const *res,
+ sres_update_f *update);
+
+/** Create sockets for resolver. */
+SRESPUBFUN int sres_resolver_sockets(sres_resolver_t *,
+ sres_socket_t *sockets,
+ int n);
+
+/** Resolver timer function. */
+SRESPUBFUN void sres_resolver_timer(sres_resolver_t *, int dummy);
+
+/** Prototype for scheduler function.
+ *
+ * This function is called when a timer callback is to be scheduled.
+ *
+ * @param async asynchronous object (registered with sres_resolver_set_async())
+ * @param interval interval in milliseconds
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error
+ */
+ typedef int sres_schedule_f(sres_async_t *async, unsigned long interval);
+
+/** Register resolver timer callback. */
+SRESPUBFUN int sres_resolver_set_timer_cb(sres_resolver_t *res,
+ sres_schedule_f *callback,
+ sres_async_t *async);
+
+/** Receive DNS response from socket. */
+SRESPUBFUN int sres_resolver_receive(sres_resolver_t *, int socket);
+
+/** Receive error message from socket. */
+SRESPUBFUN int sres_resolver_error(sres_resolver_t *, int socket);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SOFIA_RESOLV_SRES_ASYNC_H */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv/sres_cache.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv/sres_cache.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,109 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SOFIA_RESOLV_SRES_CACHE_H
+/** Defined when <sofia-resolv/sres_cache.h> has been included. */
+#define SOFIA_RESOLV_SRES_CACHE_H
+/**
+ * @file sofia-resolv/sres_cache.h Sofia DNS Resolver Cache.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>,
+ *
+ * @par Include Context
+ * @code
+ * #include <sys/types.h>
+ * #include <sys/socket.h>
+ * #include <netinet/in.h>
+ * #include <sofia-resolv/sres_cache.h>
+ * @endcode
+ *
+ */
+
+#include "sofia-resolv/sres_config.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef SRES_CACHE_T
+#define SRES_CACHE_T
+/** Opaque type of DNS cache object. */
+typedef struct sres_cache sres_cache_t;
+#endif
+
+#ifndef SRES_RECORD_T
+#define SRES_RECORD_T
+/** Type representing any DNS record. */
+typedef union sres_record sres_record_t;
+#endif
+
+enum {
+ /** Cache cleanup interval in seconds. */
+ SRES_CACHE_TIMER_INTERVAL = 30,
+#define SRES_CACHE_TIMER_INTERVAL (SRES_CACHE_TIMER_INTERVAL)
+};
+
+/** Create a resolver cache object. */
+SRESPUBFUN sres_cache_t *sres_cache_new(int n);
+
+/** Increase reference count on a resolver cache object. */
+SRESPUBFUN sres_cache_t *sres_cache_ref(sres_cache_t *);
+
+/** Decrease the reference count on a resolver cache object. */
+SRESPUBFUN void sres_cache_unref(sres_cache_t *);
+
+/** Get a list of matching records from cache. */
+SRESPUBFUN int sres_cache_get(sres_cache_t *cache,
+ uint16_t type,
+ char const *domain,
+ sres_record_t ***return_cached);
+
+/** Free answers not matching with type */
+SRESPUBFUN int sres_cache_filter(sres_cache_t *cache,
+ sres_record_t **answers,
+ uint16_t type);
+
+/** Free the list records. */
+SRESPUBFUN void sres_cache_free_answers(sres_cache_t *, sres_record_t **);
+
+/** Free and zero one record. */
+SRESPUBFUN void sres_cache_free_one(sres_cache_t *, sres_record_t *answer);
+
+/** Allocate a cache record */
+SRESPUBFUN
+sres_record_t *sres_cache_alloc_record(sres_cache_t *cache,
+ sres_record_t const *template,
+ size_t extra);
+
+/** Free a record that has not been stored. */
+SRESPUBFUN void sres_cache_free_record(sres_cache_t *cache, void *rr);
+
+/** Store a record to cache */
+SRESPUBFUN void sres_cache_store(sres_cache_t *, sres_record_t *, time_t now);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SOFIA_RESOLV_SRES_CACHED_H */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv/sres_config.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv/sres_config.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,66 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SOFIA_RESOLV_SRES_CONFIG_H
+/** Defined when <sofia-resolv/sres_config.h> has been included. */
+#define SOFIA_RESOLV_SRES_CONFIG_H
+
+/**
+ * @file sofia-resolv/sres_config.h
+ *
+ * Configuration for Sofia DNS Resolver.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ */
+
+/* ---------------------------------------------------------------------- */
+/* Macros required by Win32 linkage */
+
+/** SRESPUBFUN declares an exported function */
+#define SRESPUBFUN
+
+#if defined(_WIN32) && !defined(LIBSRES_STATIC) && \
+ (defined(_MSC_VER) || defined(__BORLANDC__) || \
+ defined(__CYGWIN__) || defined(__MINGW32__))
+ /* Windows platform with MS/Borland/Cygwin/MinGW32 compiler */
+ #undef SRESPUBFUN
+ #if defined(IN_LIBSOFIA_SRES)
+ #define SRESPUBFUN __declspec(dllexport)
+ #else
+ #define SRESPUBFUN __declspec(dllimport)
+ #endif
+#endif
+
+/* ---------------------------------------------------------------------- */
+
+/* Types required by Win32/64 */
+
+#if defined(_WIN32)
+typedef SOCKET sres_socket_t;
+#else
+/** Socket descriptor. @since New in @VERSION_1_12_2. */
+typedef int sres_socket_t;
+#endif
+
+#endif /* SOFIA_RESOLV_SRES_CONFIG_H */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv/sres_record.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv/sres_record.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,259 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SOFIA_RESOLV_SRES_RECORD_H
+/** Defined when <sofia-resolv/sres_record.h> has been included. */
+#define SOFIA_RESOLV_SRES_RECORD_H
+/**
+ * @file sofia-resolv/sres_record.h Sofia DNS Resolver Records.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>,
+ *
+ * @par Include Context
+ * @code
+ * #include <sys/types.h>
+ * #include <sys/socket.h>
+ * #include <netinet/in.h>
+ * #include <sofia-resolv/sres_record.h>
+ * @endcode
+ *
+ */
+
+#include "sofia-resolv/sres_config.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Common part of all DNS records. */
+typedef struct sres_common
+{
+ int r_refcount; /**< Number of references to this record */
+ char *r_name; /**< Domain name */
+ uint16_t r_status; /**< Status of query (nonzero upon an error) */
+ uint16_t r_size; /**< Size of this record */
+ uint16_t r_type; /**< Record type (A, CNAME, A6, etc) */
+ uint16_t r_class; /**< Record class (IN) */
+ uint32_t r_ttl; /**< Time-to-live */
+ uint16_t r_rdlen; /**< Length of record data */
+ uint16_t r_parsed; /**< Nonzero if parsed */
+} sres_common_t;
+
+/** Possible values for r_status (RCODE) in #sres_common */
+enum sres_status {
+ SRES_OK = 0, /**< No error condition. */
+ SRES_FORMAT_ERR = 1, /**< Server could not interpret query. */
+ SRES_SERVER_ERR = 2, /**< Server error. */
+ SRES_NAME_ERR = 3, /**< No domain name. */
+ SRES_UNIMPL_ERR = 4, /**< Not implemented. */
+ SRES_AUTH_ERR = 5, /**< Refused */
+
+ /* Errors generated by sresolv */
+ SRES_TIMEOUT_ERR = 32, /**< Timeout occurred */
+ SRES_RECORD_ERR = 33 /**< Name has no given record type */
+};
+
+/** Start of a zone of authority record (@RFC1035). */
+typedef struct sres_soa_record
+{
+ sres_common_t soa_record[1]; /**< Common part of DNS records. */
+ char *soa_mname; /**< Primary name server */
+ char *soa_rname; /**< Person responsible for domain */
+ uint32_t soa_serial; /**< Version number */
+ uint32_t soa_refresh; /**< Refresh intercal */
+ uint32_t soa_retry; /**< Interval between refres retries */
+ uint32_t soa_expire; /**< Upper limit on zone expiration time */
+ uint32_t soa_minimum; /**< Minimum TTL for any record in zone */
+} sres_soa_record_t;
+
+/** Generic DNS record. */
+typedef struct sres_generic
+{
+ sres_common_t g_record[1]; /**< Common part of DNS records. */
+ uint8_t g_data[128]; /**< Record data */
+} sres_generic_t;
+
+/** Address record (@RFC1035). */
+typedef struct sres_a_record
+{
+ sres_common_t a_record[1]; /**< Common part of DNS records. */
+ struct in_addr a_addr; /**< IP4 address */
+} sres_a_record_t;
+
+/** IPv6 address used by sresolv library.
+ *
+ * @sa #sres_aaaa_record, #sres_a6_record
+ */
+typedef struct
+{
+ uint8_t u6_addr[16]; /**< Array of 16 octets. */
+} sres_in6_t;
+
+/** Aggregated address record for IPv6 (@RFC2874, deprecated). */
+typedef struct sres_a6_record
+{
+ sres_common_t a6_record[1]; /**< Common part of DNS records. */
+ uint8_t a6_prelen; /**< Prefix length */
+ uint8_t a6_pad[3]; /**< */
+ sres_in6_t a6_suffix; /**< Address suffix */
+ char *a6_prename; /**< Prefix name */
+} sres_a6_record_t;
+
+/** Address record for IPv6 (@RFC1886). */
+typedef struct sres_aaaa_record
+{
+ sres_common_t aaaa_record[1]; /**< Common part of DNS records. */
+ sres_in6_t aaaa_addr; /**< IP6 address */
+} sres_aaaa_record_t;
+
+/** Canonic name record (@RFC1035). */
+typedef struct sres_cname_record
+{
+ sres_common_t cn_record[1]; /**< Common part of DNS records. */
+ char *cn_cname; /**< */
+} sres_cname_record_t;
+
+/** Pointer record (@RFC1035). */
+typedef struct sres_ptr_record
+{
+ sres_common_t ptr_record[1]; /**< Common part of DNS records. */
+ char *ptr_domain; /**< Domain */
+} sres_ptr_record_t;
+
+/** Service location record (@RFC2782). */
+typedef struct sres_srv_record
+{
+ sres_common_t srv_record[1]; /**< Common part of DNS records. */
+ uint16_t srv_priority; /**< Priority */
+ uint16_t srv_weight; /**< Weight */
+ uint16_t srv_port; /**< Service port on the target host. */
+ uint16_t srv_pad;
+ char *srv_target; /**< Domain name of the target host. */
+} sres_srv_record_t;
+
+/** Naming authority pointer record (@RFC2915). */
+typedef struct sres_naptr_record
+{
+ sres_common_t na_record[1]; /**< Common part of DNS records. */
+ uint16_t na_order; /**< Processing order for NAPTR records. */
+ uint16_t na_prefer; /**< Preference */
+ char *na_flags; /**< Flags for interpretation and rewriting */
+ char *na_services; /**< Services available. */
+ char *na_regexp; /**< Substitution expression. */
+ char *na_replace; /**< Replacement. */
+} sres_naptr_record_t;
+
+
+#ifndef SRES_RECORD_T
+#define SRES_RECORD_T
+/** Type representing any DNS record. */
+typedef union sres_record sres_record_t;
+#endif
+
+/** Union of different DNS records */
+union sres_record
+{
+ sres_common_t sr_record[1]; /**< Common part of all DNS records */
+ sres_generic_t sr_generic[1]; /**< Generic (unparsed) DNS record */
+ sres_soa_record_t sr_soa[1]; /**< SOA (start-of-authority) record */
+ sres_a_record_t sr_a[1]; /**< A (address) record */
+ sres_cname_record_t sr_cname[1]; /**< CNAME (canonic name) record */
+ sres_ptr_record_t sr_ptr[1]; /**< PTR (pointer) record */
+ sres_a6_record_t sr_a6[1]; /**< A6 (IP6 address) record */
+ sres_aaaa_record_t sr_aaaa[1]; /**< AAAA (IP6 address) record */
+ sres_srv_record_t sr_srv[1]; /**< SRV record */
+ sres_naptr_record_t sr_naptr[1]; /**< NAPTR record */
+};
+
+/** Protocol family classes. */
+enum sres_class {
+ sres_class_in = 1, /**< Internet (@b IN) */
+ sres_class_any = 255 /**< Any class */
+};
+
+/** Query types. */
+enum sres_qtypes {
+ sres_type_a = 1, /**< IPv4 address (#sres_a_record). */
+ sres_type_ns = 2, /**< Authoritative server. */
+ sres_type_mf = 4, /**< Mail forwarder. */
+ sres_type_cname = 5, /**< Canonical name (#sres_cname_record). */
+ sres_type_soa = 6, /**< Start of authority zone (#sres_soa_record). */
+ sres_type_mb = 7, /**< Mailbox domain name. */
+ sres_type_mg = 8, /**< Mail group member. */
+ sres_type_mr = 9, /**< Mail rename name. */
+ sres_type_null = 10, /**< Null resource record. */
+ sres_type_wks = 11, /**< Well known service. */
+ sres_type_ptr = 12, /**< Domain name pointer (#sres_ptr_record). */
+ sres_type_hinfo = 13, /**< Host information. */
+ sres_type_minfo = 14, /**< Mailbox information. */
+ sres_type_mx = 15, /**< Mail routing information. */
+ sres_type_txt = 16, /**< Text strings. */
+ sres_type_rp = 17, /**< Responsible person. */
+ sres_type_afsdb = 18, /**< AFS cell database. */
+ sres_type_x25 = 19, /**< X_25 calling address. */
+ sres_type_isdn = 20, /**< ISDN calling address. */
+ sres_type_rt = 21, /**< Router. */
+ sres_type_nsap = 22, /**< NSAP address. */
+ sres_type_nsap_ptr = 23, /**< Reverse NSAP lookup. */
+ sres_type_sig = 24, /**< Security signature. */
+ sres_type_key = 25, /**< Security key. */
+ sres_type_px = 26, /**< X.400 mail mapping. */
+ sres_type_gpos = 27, /**< ICBM record. */
+ sres_type_aaaa = 28, /**< IPv6 Address (#sres_aaaa_record). */
+ sres_type_loc = 29, /**< Location Information. */
+ sres_type_nxt = 30, /**< Next domain. */
+ sres_type_eid = 31, /**< Endpoint identifier. */
+ sres_type_nimloc = 32, /**< Nimrod Locator. */
+ sres_type_srv = 33, /**< Server Selection (@RFC2782,
+ #sres_srv_record). */
+ sres_type_atma = 34, /**< ATM Address */
+ sres_type_naptr = 35, /**< Naming Authority PoinTeR (@RFC2915,
+ #sres_naptr_record) */
+ sres_type_kx = 36, /**< Key Exchange */
+ sres_type_cert = 37, /**< Certification record */
+ sres_type_a6 = 38, /**< IPv6 address (deprecates AAAA) */
+ sres_type_dname = 39, /**< Non-terminal DNAME (for IPv6) */
+ sres_type_sink = 40, /**< Kitchen sink (experimental) */
+ sres_type_opt = 41, /**< EDNS 0 option (@RFC2671) */
+
+ sres_qtype_tsig = 250, /**< Transaction signature. */
+ sres_qtype_ixfr = 251, /**< Incremental zone transfer. */
+ sres_qtype_axfr = 252, /**< Transfer zone of authority. */
+ sres_qtype_mailb = 253, /**< Transfer mailbox records. */
+ sres_qtype_maila = 254, /**< Transfer mail agent records. */
+ sres_qtype_any = 255 /**< Wildcard match. */
+};
+
+/** Convert type to its name. */
+SRESPUBFUN char const *sres_record_type(int type, char buffer[8]);
+
+/** Compare two records. */
+SRESPUBFUN int sres_record_compare(sres_record_t const *,
+ sres_record_t const *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SOFIA_RESOLV_SRES_CACHE_H */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-sip/sresolv.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-sip/sresolv.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,79 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SRESOLV_H
+/** Defined when <sofia-sip/sresolv.h> has been included. */
+#define SRESOLV_H
+
+/**
+ * @file sofia-sip/sresolv.h Easy API for Sofia DNS Resolver.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>,
+ * @author Teemu Jalava <Teemu.Jalava at nokia.com>,
+ * @author Mikko Haataja <ext-Mikko.A.Haataja at nokia.com>.
+ *
+ */
+
+#include <sofia-sip/su.h>
+#include <sofia-sip/su_wait.h>
+#include <sofia-sip/su_tag.h>
+
+#include <sofia-resolv/sres.h>
+#include <sofia-resolv/sres_record.h>
+#include <sofia-resolv/sres_async.h>
+
+SOFIA_BEGIN_DECLS
+
+/* Sofia-specific reactor interface for asynchronous operation */
+
+/** Filter tag matching any sresolv tag. */
+#define SRESOLVTAG_ANY() srestag_any, ((tag_value_t)0)
+SOFIAPUBVAR tag_typedef_t srestag_any;
+
+SOFIAPUBVAR tag_typedef_t srestag_resolv_conf;
+/** Path of resolv.conf file. */
+#define SRESTAG_RESOLV_CONF(x) srestag_resolv_conf, tag_str_v((x))
+SOFIAPUBVAR tag_typedef_t srestag_resolv_conf_ref;
+#define SRESTAG_RESOLV_CONF_REF(x) srestag_resolv_conf_ref, tag_str_vr(&(x))
+
+SOFIAPUBVAR tag_typedef_t srestag_cache;
+/** Pointer to existing #sres_cache_t object. */
+#define SRESTAG_CACHE(x) srestag_cache, tag_ptr_v((x))
+SOFIAPUBVAR tag_typedef_t srestag_cache_ref;
+#define SRESTAG_CACHE_REF(x) srestag_cache_ref, tag_ptr_vr(&(x), (x))
+
+/** Create a resolver object using @a root reactor. */
+SOFIAPUBFUN sres_resolver_t *sres_resolver_create(su_root_t *root,
+ char const *resolv_conf,
+ tag_type_t, tag_value_t,
+ ...);
+/** Destroy a resolver object. */
+SOFIAPUBFUN int sres_resolver_destroy(sres_resolver_t *res);
+
+/* Return socket used by root. @deprecated */
+SOFIAPUBFUN su_socket_t sres_resolver_root_socket(sres_resolver_t *res);
+
+SOFIA_END_DECLS
+
+#endif
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sres.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sres.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,4060 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ * Copyright (C) 2006 Dimitri E. Prado.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE sres.c
+ * @brief Sofia DNS Resolver implementation.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Teemu Jalava <Teemu.Jalava at nokia.com>
+ * @author Mikko Haataja
+ * @author Kai Vehmanen <kai.vehmanen at nokia.com>
+ * (work on the win32 nameserver discovery)
+ * @author Dimitri E. Prado
+ * (initial version of win32 nameserver discovery)
+ *
+ * @todo The resolver should allow handling arbitrary records, too.
+ */
+
+#include "config.h"
+
+#if HAVE_STDINT_H
+#include <stdint.h>
+#elif HAVE_INTTYPES_H
+#include <inttypes.h>
+#else
+#if defined(_WIN32)
+typedef _int8 int8_t;
+typedef unsigned _int8 uint8_t;
+typedef unsigned _int16 uint16_t;
+typedef unsigned _int32 uint32_t;
+#endif
+#endif
+
+#if HAVE_NETINET_IN_H
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#endif
+
+#if HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#if HAVE_WINSOCK2_H
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#ifndef IPPROTO_IPV6 /* socklen_t is used with @RFC2133 API */
+typedef int socklen_t;
+#endif
+#endif
+
+#include <time.h>
+
+#include "sofia-resolv/sres.h"
+#include "sofia-resolv/sres_cache.h"
+#include "sofia-resolv/sres_record.h"
+#include "sofia-resolv/sres_async.h"
+
+#include <sofia-sip/su_alloc.h>
+#include <sofia-sip/su_strlst.h>
+#include <sofia-sip/su_errno.h>
+
+#include "sofia-sip/htable.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include <limits.h>
+
+#include <assert.h>
+
+#if HAVE_WINSOCK2_H
+/* Posix send() */
+static inline
+ssize_t sres_send(sres_socket_t s, void *b, size_t length, int flags)
+{
+ if (length > INT_MAX)
+ length = INT_MAX;
+ return (ssize_t)send(s, b, (int)length, flags);
+}
+
+/* Posix recvfrom() */
+static inline
+ssize_t sres_recvfrom(sres_socket_t s, void *buffer, size_t length, int flags,
+ struct sockaddr *from, socklen_t *fromlen)
+{
+ int retval, ilen;
+
+ if (fromlen)
+ ilen = *fromlen;
+
+ if (length > INT_MAX)
+ length = INT_MAX;
+
+ retval = recvfrom(s, buffer, (int)length, flags,
+ (void *)from, fromlen ? &ilen : NULL);
+
+ if (fromlen)
+ *fromlen = ilen;
+
+ return (ssize_t)retval;
+}
+
+static inline
+int sres_close(sres_socket_t s)
+{
+ return closesocket(s);
+}
+
+#if !defined(IPPROTO_IPV6)
+#if HAVE_SIN6
+#include <tpipv6.h>
+#else
+#if !defined(__MINGW32__)
+struct sockaddr_storage {
+ short ss_family;
+ char ss_pad[126];
+};
+#endif
+#endif
+#endif
+#else
+
+#define sres_send(s,b,len,flags) send((s),(b),(len),(flags))
+#define sres_recvfrom(s,b,len,flags,a,alen) \
+ recvfrom((s),(b),(len),(flags),(a),(alen))
+#define sres_close(s) close((s))
+#define SOCKET_ERROR (-1)
+#define INVALID_SOCKET ((sres_socket_t)-1)
+#endif
+
+
+#if !HAVE_INET_PTON
+int inet_pton(int af, char const *src, void *dst);
+#endif
+#if !HAVE_INET_NTOP
+const char *inet_ntop(int af, void const *src, char *dst, size_t size);
+#endif
+
+#if defined(va_copy)
+#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
+
+/**
+ * How often to recheck nameserver information (seconds).
+ */
+#ifndef _WIN32
+#define SRES_UPDATE_INTERVAL_SECS 5
+#else
+#define SRES_UPDATE_INTERVAL_SECS 180
+#endif
+void sres_cache_clean(sres_cache_t *cache, time_t now);
+
+typedef struct sres_message sres_message_t;
+typedef struct sres_config sres_config_t;
+typedef struct sres_server sres_server_t;
+typedef struct sres_nameserver sres_nameserver_t;
+
+/** Default path to resolv.conf */
+static char const sres_conf_file_path[] = "/etc/resolv.conf";
+
+/** EDNS0 support. @internal */
+enum edns {
+ edns_not_tried = -1,
+ edns_not_supported = 0,
+ edns0_configured = 1,
+ edns0_supported = 2,
+};
+
+struct sres_server {
+ sres_socket_t dns_socket;
+
+ char dns_name[48]; /**< Server name */
+ struct sockaddr_storage dns_addr[1]; /**< Server node address */
+ ssize_t dns_addrlen; /**< Size of address */
+
+ enum edns dns_edns; /**< Server supports edns. */
+
+ /** ICMP/temporary error received, zero when successful. */
+ time_t dns_icmp;
+ /** Persisten error, zero when successful. */
+ time_t dns_error;
+};
+
+HTABLE_DECLARE_WITH(sres_qtable, qt, sres_query_t, unsigned, size_t);
+
+struct sres_resolver_s {
+ su_home_t res_home[1];
+
+ void *res_userdata;
+ sres_cache_t *res_cache;
+
+ time_t res_now;
+ sres_qtable_t res_queries[1]; /**< Table of active queries */
+
+ char const *res_cnffile; /**< Configuration file name */
+ char const **res_options; /**< Option strings */
+
+ sres_config_t const *res_config;
+ time_t res_checked;
+
+ unsigned long res_updated;
+ sres_update_f *res_updcb;
+ sres_async_t *res_async;
+ sres_schedule_f *res_schedulecb;
+ short res_update_all;
+
+ uint16_t res_id;
+ short res_i_server; /**< Current server to try
+ (when doing round-robin) */
+ short res_n_servers; /**< Number of servers */
+ sres_server_t **res_servers;
+};
+
+/* Parsed configuration. @internal */
+struct sres_config {
+ su_home_t c_home[1];
+
+ time_t c_modified;
+ char const *c_filename;
+
+ /* domain and search */
+ char const *c_search[SRES_MAX_SEARCH + 1];
+
+ /* nameserver */
+ struct sres_nameserver {
+ struct sockaddr_storage ns_addr[1];
+ ssize_t ns_addrlen;
+ } *c_nameservers[SRES_MAX_NAMESERVERS + 1];
+
+ /* sortlist */
+ struct sres_sortlist {
+ struct sockaddr_storage addr[1];
+ ssize_t addrlen;
+ char const *name;
+ } *c_sortlist[SRES_MAX_SORTLIST + 1];
+
+ uint16_t c_port; /**< Server port to use */
+
+ /* options */
+ struct sres_options {
+ uint16_t timeout;
+ uint16_t attempts;
+ uint16_t ndots;
+ enum edns edns;
+ unsigned debug:1;
+ unsigned rotate:1;
+ unsigned check_names:1;
+ unsigned inet6:1;
+ unsigned ip6int:1;
+ unsigned ip6bytestring:1;
+ } c_opt;
+};
+
+struct sres_query_s {
+ unsigned q_hash;
+ sres_resolver_t*q_res;
+ sres_answer_f *q_callback;
+ sres_context_t *q_context;
+ char *q_name;
+ time_t q_timestamp;
+ uint16_t q_type;
+ uint16_t q_class;
+ uint16_t q_id; /**< If nonzero, not answered */
+ uint16_t q_retry_count;
+ uint8_t q_n_servers;
+ uint8_t q_i_server;
+ int8_t q_edns;
+ uint8_t q_n_subs;
+ sres_query_t *q_subqueries[1 + SRES_MAX_SEARCH];
+ sres_record_t **q_subanswers[1 + SRES_MAX_SEARCH];
+};
+
+
+struct sres_message {
+ uint16_t m_offset;
+ uint16_t m_size;
+ char const *m_error;
+ union {
+ struct {
+ /* Header defined in RFC 1035 section 4.1.1 (page 26) */
+ uint16_t mh_id; /* Query ID */
+ uint16_t mh_flags; /* Flags */
+ uint16_t mh_qdcount; /* Question record count */
+ uint16_t mh_ancount; /* Answer record count */
+ uint16_t mh_nscount; /* Authority records count */
+ uint16_t mh_arcount; /* Additional records count */
+ } mp_header;
+ uint8_t mp_data[1500 - 40]; /**< IPv6 datagram */
+ } m_packet;
+#define m_id m_packet.mp_header.mh_id
+#define m_flags m_packet.mp_header.mh_flags
+#define m_qdcount m_packet.mp_header.mh_qdcount
+#define m_ancount m_packet.mp_header.mh_ancount
+#define m_nscount m_packet.mp_header.mh_nscount
+#define m_arcount m_packet.mp_header.mh_arcount
+#define m_data m_packet.mp_data
+};
+
+#define sr_refcount sr_record->r_refcount
+#define sr_name sr_record->r_name
+#define sr_status sr_record->r_status
+#define sr_size sr_record->r_size
+#define sr_type sr_record->r_type
+#define sr_class sr_record->r_class
+#define sr_ttl sr_record->r_ttl
+#define sr_rdlen sr_record->r_rdlen
+#define sr_parsed sr_record->r_parsed
+#define sr_rdata sr_generic->g_data
+
+enum {
+ SRES_HDR_QR = (1 << 15),
+ SRES_HDR_QUERY = (0 << 11),
+ SRES_HDR_IQUERY = (1 << 11),
+ SRES_HDR_STATUS = (2 << 11),
+ SRES_HDR_OPCODE = (15 << 11), /* mask */
+ SRES_HDR_AA = (1 << 10),
+ SRES_HDR_TC = (1 << 9),
+ SRES_HDR_RD = (1 << 8),
+ SRES_HDR_RA = (1 << 7),
+ SRES_HDR_RCODE = (15 << 0) /* mask of return code */
+};
+
+HTABLE_PROTOS_WITH(sres_qtable, qt, sres_query_t, unsigned, size_t);
+
+#define CHOME(cache) ((su_home_t *)(cache))
+
+/** Get address from sockaddr storage. */
+#if HAVE_SIN6
+#define SS_ADDR(ss) \
+ ((ss)->ss_family == AF_INET ? \
+ (void *)&((struct sockaddr_in *)ss)->sin_addr : \
+ ((ss)->ss_family == AF_INET6 ? \
+ (void *)&((struct sockaddr_in6 *)ss)->sin6_addr : \
+ (void *)&((struct sockaddr *)ss)->sa_data))
+#else
+#define SS_ADDR(ss) \
+ ((ss)->ss_family == AF_INET ? \
+ (void *)&((struct sockaddr_in *)ss)->sin_addr : \
+ (void *)&((struct sockaddr *)ss)->sa_data)
+#endif
+
+static int sres_config_changed_servers(sres_config_t const *new_c,
+ sres_config_t const *old_c);
+static sres_server_t **sres_servers_new(sres_resolver_t *res,
+ sres_config_t const *c);
+
+/** Generate new 16-bit identifier for DNS query. */
+static uint16_t
+sres_new_id(sres_resolver_t *res)
+{
+ return res->res_id ? res->res_id++ : (res->res_id = 2, 1);
+}
+
+/** Return true if we have a search list or a local domain name. */
+static int
+sres_has_search_domain(sres_resolver_t *res)
+{
+ return res->res_config->c_search[0] != NULL;
+}
+
+static void sres_resolver_destructor(void *);
+
+sres_resolver_t *
+sres_resolver_new_with_cache_va(char const *conf_file_path,
+ sres_cache_t *cache,
+ char const *options,
+ va_list va);
+static
+sres_resolver_t *
+sres_resolver_new_internal(sres_cache_t *cache,
+ sres_config_t const *config,
+ char const *conf_file_path,
+ char const **options);
+
+static void sres_servers_close(sres_resolver_t *res,
+ sres_server_t **servers);
+
+static int sres_servers_count(sres_server_t * const *servers);
+
+static sres_socket_t sres_server_socket(sres_resolver_t *res,
+ sres_server_t *dns);
+
+static sres_query_t * sres_query_alloc(sres_resolver_t *res,
+ sres_answer_f *callback,
+ sres_context_t *context,
+ uint16_t type,
+ char const * domain);
+
+static void sres_free_query(sres_resolver_t *res, sres_query_t *q);
+
+static
+int sres_sockaddr2string(sres_resolver_t *,
+ char name[], size_t namelen,
+ struct sockaddr const *);
+
+static
+sres_config_t *sres_parse_resolv_conf(sres_resolver_t *res,
+ char const **options);
+
+static
+sres_server_t *sres_next_server(sres_resolver_t *res,
+ uint8_t *in_out_i,
+ int timeout);
+
+static
+int sres_send_dns_query(sres_resolver_t *res, sres_query_t *q);
+
+static
+void sres_answer_subquery(sres_context_t *context,
+ sres_query_t *query,
+ sres_record_t **answers);
+
+static
+sres_record_t **
+sres_combine_results(sres_resolver_t *res,
+ sres_record_t **search_results[SRES_MAX_SEARCH + 1]);
+
+static
+void sres_query_report_error(sres_query_t *q,
+ sres_record_t **answers);
+
+static void
+sres_resend_dns_query(sres_resolver_t *res, sres_query_t *q, int timeout);
+
+static
+sres_server_t *sres_server_by_socket(sres_resolver_t const *ts,
+ sres_socket_t socket);
+
+static
+int sres_resolver_report_error(sres_resolver_t *res,
+ sres_socket_t socket,
+ int errcode,
+ struct sockaddr_storage *remote,
+ socklen_t remotelen,
+ char const *info);
+
+static
+void sres_log_response(sres_resolver_t const *res,
+ sres_message_t const *m,
+ struct sockaddr_storage const *from,
+ sres_query_t const *query,
+ sres_record_t * const *reply);
+
+static int sres_decode_msg(sres_resolver_t *res,
+ sres_message_t *m,
+ sres_query_t **,
+ sres_record_t ***aanswers);
+
+static char const *sres_toplevel(char buf[], size_t bsize, char const *domain);
+
+static sres_record_t *sres_create_record(sres_resolver_t *, sres_message_t *m);
+
+static sres_record_t *sres_init_rr_soa(sres_cache_t *cache,
+ sres_soa_record_t *,
+ sres_message_t *m);
+static sres_record_t *sres_init_rr_a(sres_cache_t *cache,
+ sres_a_record_t *,
+ sres_message_t *m);
+static sres_record_t *sres_init_rr_a6(sres_cache_t *cache,
+ sres_a6_record_t *,
+ sres_message_t *m);
+static sres_record_t *sres_init_rr_aaaa(sres_cache_t *cache,
+ sres_aaaa_record_t *,
+ sres_message_t *m);
+static sres_record_t *sres_init_rr_cname(sres_cache_t *cache,
+ sres_cname_record_t *,
+ sres_message_t *m);
+static sres_record_t *sres_init_rr_ptr(sres_cache_t *cache,
+ sres_ptr_record_t *,
+ sres_message_t *m);
+static sres_record_t *sres_init_rr_srv(sres_cache_t *cache,
+ sres_srv_record_t *,
+ sres_message_t *m);
+static sres_record_t *sres_init_rr_naptr(sres_cache_t *cache,
+ sres_naptr_record_t *,
+ sres_message_t *m);
+static sres_record_t *sres_init_rr_unknown(sres_cache_t *cache,
+ sres_common_t *r,
+ sres_message_t *m);
+
+static sres_record_t *sres_create_error_rr(sres_cache_t *cache,
+ sres_query_t const *q,
+ uint16_t errcode);
+
+static void m_put_uint16(sres_message_t *m, uint16_t h);
+static void m_put_uint32(sres_message_t *m, uint32_t w);
+
+static uint16_t m_put_domain(sres_message_t *m,
+ char const *domain,
+ uint16_t top,
+ char const *topdomain);
+
+static uint32_t m_get_uint32(sres_message_t *m);
+static uint16_t m_get_uint16(sres_message_t *m);
+static uint8_t m_get_uint8(sres_message_t *m);
+
+static int m_get_string(char *d, int n, sres_message_t *m, uint16_t offset);
+static int m_get_domain(char *d, int n, sres_message_t *m, uint16_t offset);
+
+/* ---------------------------------------------------------------------- */
+
+#define SU_LOG sresolv_log
+
+#include <sofia-sip/su_debug.h>
+
+#ifdef _WIN32
+#include <winreg.h>
+#endif
+
+/**@var SRESOLV_DEBUG
+ *
+ * Environment variable determining the debug log level for @b sresolv
+ * module.
+ *
+ * The SRESOLV_DEBUG environment variable is used to determine the debug
+ * logging level for @b sresolv module. The default level is 3.
+ *
+ * @sa <su_debug.h>, sresolv_log, SOFIA_DEBUG
+ */
+extern char const SRESOLV_DEBUG[];
+
+/**Debug log for @b sresolv module.
+ *
+ * The sresolv_log is the log object used by @b sresolv module. The level of
+ * #sresolv_log is set using #SRESOLV_DEBUG environment variable.
+ */
+su_log_t sresolv_log[] = { SU_LOG_INIT("sresolv", "SRESOLV_DEBUG", 3) };
+
+/** Internal errors */
+enum {
+ SRES_EDNS0_ERR = 255 /**< Server did not support EDNS. */
+};
+
+/* ---------------------------------------------------------------------- */
+
+/**Create a resolver.
+ *
+ * Allocate and initialize a new sres resolver object. The resolver object
+ * contains the parsed resolv.conf file, a cache object containing past
+ * answers from DNS, and a list of active queries. The default resolv.conf
+ * file can be overriden by giving the name of the configuration file as @a
+ * conf_file_path.
+ *
+ * @param conf_file_path name of the resolv.conf configuration file
+ *
+ * @return A pointer to a newly created sres resolver object, or NULL upon
+ * an error.
+ */
+sres_resolver_t *
+sres_resolver_new(char const *conf_file_path)
+{
+ return sres_resolver_new_internal(NULL, NULL, conf_file_path, NULL);
+}
+
+/** Copy a resolver.
+ *
+ * Make a copy of resolver sharing the configuration and cache with old
+ * resolver.
+ */
+sres_resolver_t *sres_resolver_copy(sres_resolver_t *res)
+{
+ char const *cnffile;
+ sres_config_t *config;
+ sres_cache_t *cache;
+ char const **options;
+
+ if (!res)
+ return NULL;
+
+ cnffile = res->res_cnffile;
+ config = su_home_ref(res->res_config->c_home);
+ cache = res->res_cache;
+ options = res->res_options;
+
+ return sres_resolver_new_internal(cache, config, cnffile, options);
+}
+
+/**New resolver object.
+ *
+ * Allocate and initialize a new sres resolver object. The resolver object
+ * contains the parsed resolv.conf file, a cache object containing past
+ * answers from DNS, and a list of active queries. The default resolv.conf
+ * file can be overriden by giving the name of the configuration file as @a
+ * conf_file_path.
+ *
+ * It is also possible to override the values in the resolv.conf and
+ * RES_OPTIONS by giving the directives in the NULL-terminated list.
+ *
+ * @param conf_file_path name of the resolv.conf configuration file
+ * @param cache optional pointer to a resolver cache (may be NULL)
+ * @param option, ... list of resolv.conf options directives
+ * (overriding options in conf_file)
+ *
+ * @par Environment Variables
+ * - LOCALDOMAIN overrides @c domain or @c search directives
+ * - #RES_OPTIONS overrides values of @a options in resolv.conf
+ * - #SRES_OPTIONS overrides values of @a options in resolv.conf, #RES_OPTIONS,
+ * and @a options, ... list given as argument for this function
+ *
+ * @return A pointer to a newly created sres resolver object, or NULL upon
+ * an error.
+ */
+sres_resolver_t *
+sres_resolver_new_with_cache(char const *conf_file_path,
+ sres_cache_t *cache,
+ char const *option, ...)
+{
+ sres_resolver_t *retval;
+ va_list va;
+ va_start(va, option);
+ retval = sres_resolver_new_with_cache_va(conf_file_path, cache, option, va);
+ va_end(va);
+ return retval;
+}
+
+/**Create a resolver.
+ *
+ * Allocate and initialize a new sres resolver object.
+ *
+ * This is a stdarg version of sres_resolver_new_with_cache().
+ */
+sres_resolver_t *
+sres_resolver_new_with_cache_va(char const *conf_file_path,
+ sres_cache_t *cache,
+ char const *option,
+ va_list va)
+{
+ va_list va0;
+ size_t i;
+ char const *o, *oarray[16], **olist = oarray;
+ sres_resolver_t *res;
+
+ va_copy(va0, va);
+
+ for (i = 0, o = option; o; o = va_arg(va0, char const *)) {
+ if (i < 16)
+ olist[i] = o;
+ i++;
+ }
+
+ if (i >= 16) {
+ olist = malloc((i + 1) * sizeof *olist);
+ if (!olist)
+ return NULL;
+ for (i = 0, o = option; o; o = va_arg(va, char const *)) {
+ olist[i++] = o;
+ i++;
+ }
+ }
+ olist[i] = NULL;
+ res = sres_resolver_new_internal(cache, NULL, conf_file_path, olist);
+ if (olist != oarray)
+ free(olist);
+
+ return res;
+}
+
+sres_resolver_t *
+sres_resolver_new_internal(sres_cache_t *cache,
+ sres_config_t const *config,
+ char const *conf_file_path,
+ char const **options)
+{
+ sres_resolver_t *res;
+ size_t i, n, len;
+ char **array, *o, *end;
+
+ for (n = 0, len = 0; options && options[n]; n++)
+ len += strlen(options[n]) + 1;
+
+ res = su_home_new(sizeof(*res) + (n + 1) * (sizeof *options) + len);
+
+ if (res == NULL)
+ return NULL;
+
+ array = (void *)(res + 1);
+ o = (void *)(array + n + 1);
+ end = o + len;
+
+ for (i = 0; options && options[i]; i++)
+ o = memccpy(array[i] = o, options[i], '\0', len - (end - o));
+ assert(o == end);
+
+ su_home_destructor(res->res_home, sres_resolver_destructor);
+
+ while (res->res_id == 0) {
+#if HAVE_DEV_URANDOM
+ int fd;
+ if ((fd = open("/dev/urandom", O_RDONLY, 0)) != -1) {
+ size_t len = read(fd, &res->res_id, (sizeof res->res_id)); (void)len;
+ close(fd);
+ }
+ else
+#endif
+ res->res_id = time(NULL);
+ }
+
+ time(&res->res_now);
+
+ if (cache)
+ res->res_cache = sres_cache_ref(cache);
+ else
+ res->res_cache = sres_cache_new(0);
+
+ res->res_config = config;
+
+ if (conf_file_path && conf_file_path != sres_conf_file_path)
+ res->res_cnffile = su_strdup(res->res_home, conf_file_path);
+ else
+ res->res_cnffile = conf_file_path = sres_conf_file_path;
+
+ if (!res->res_cache || !res->res_cnffile) {
+ perror("sres: malloc");
+ }
+ else if (sres_qtable_resize(res->res_home, res->res_queries, 0) < 0) {
+ perror("sres: res_qtable_resize");
+ }
+ else if (sres_resolver_update(res, config == NULL) < 0) {
+ perror("sres: sres_resolver_update");
+ }
+ else {
+ return res;
+ }
+
+ sres_resolver_unref(res);
+
+ return NULL;
+}
+
+/** Increase reference count on a resolver object. */
+sres_resolver_t *
+sres_resolver_ref(sres_resolver_t *res)
+{
+ return su_home_ref(res->res_home);
+}
+
+/** Decrease the reference count on a resolver object. */
+void
+sres_resolver_unref(sres_resolver_t *res)
+{
+ su_home_unref(res->res_home);
+}
+
+/** Set userdata pointer.
+ *
+ * @return New userdata pointer.
+ *
+ * @ERRORS
+ * @ERROR EFAULT @a res points outside the address space
+ */
+void *
+sres_resolver_set_userdata(sres_resolver_t *res,
+ void *userdata)
+{
+ void *old;
+
+ if (!res)
+ return su_seterrno(EFAULT), (void *)NULL;
+
+ old = res->res_userdata, res->res_userdata = userdata;
+
+ return old;
+}
+
+/**Get userdata pointer.
+ *
+ * @return Userdata pointer.
+ *
+ * @ERRORS
+ * @ERROR EFAULT @a res points outside the address space
+ */
+void *
+sres_resolver_get_userdata(sres_resolver_t const *res)
+{
+ if (res == NULL)
+ return su_seterrno(EFAULT), (void *)NULL;
+ else
+ return res->res_userdata;
+}
+
+/** Set async object.
+ *
+ * @return Set async object.
+ *
+ * @ERRORS
+ * @ERROR EFAULT @a res points outside the address space
+ * @ERROR EALREADY different async callback already set
+ */
+sres_async_t *
+sres_resolver_set_async(sres_resolver_t *res,
+ sres_update_f *callback,
+ sres_async_t *async,
+ int update_all)
+{
+ if (!res)
+ return su_seterrno(EFAULT), (void *)NULL;
+
+ if (res->res_updcb && res->res_updcb != callback)
+ return su_seterrno(EALREADY), (void *)NULL;
+
+ res->res_async = async;
+ res->res_updcb = callback;
+ res->res_update_all = callback && update_all != 0;
+
+ return async;
+}
+
+/** Get async object */
+sres_async_t *
+sres_resolver_get_async(sres_resolver_t const *res,
+ sres_update_f *callback)
+{
+ if (res == NULL)
+ return su_seterrno(EFAULT), (void *)NULL;
+ else if (callback == NULL)
+ return res->res_async ? (sres_async_t *)-1 : 0;
+ else if (res->res_updcb != callback)
+ return NULL;
+ else
+ return res->res_async;
+}
+
+/** Register resolver timer callback. */
+int sres_resolver_set_timer_cb(sres_resolver_t *res,
+ sres_schedule_f *callback,
+ sres_async_t *async)
+{
+ if (res == NULL)
+ return su_seterrno(EFAULT);
+ if (res->res_async != async)
+ return su_seterrno(EALREADY);
+
+ res->res_schedulecb = callback;
+ return 0;
+}
+
+/**Send a DNS query.
+ *
+ * Sends a DNS query with specified @a type and @a domain to the DNS server.
+ * When an answer is received, the @a callback function is called with
+ * @a context and returned records as arguments.
+ *
+ * The sres resolver takes care of retransmitting the query if a root object
+ * is associate with the resolver or if sres_resolver_timer() is called in
+ * regular intervals. It generates an error record with nonzero status if no
+ * response is received.
+ *
+ * @param res pointer to resolver
+ * @param callback function called when query is answered or times out
+ * @param context pointer given as an extra argument to @a callback function
+ * @param type record type to query (see #sres_qtypes)
+ * @param domain name to query
+ *
+ * Query types also indicate the record type of the result.
+ * Any record can be queried with #sres_qtype_any.
+ * Well-known query types understood and decoded by @b sres include
+ * #sres_type_a,
+ * #sres_type_aaaa,
+ * #sres_type_cname,
+ * #sres_type_ptr
+ * #sres_type_soa,
+ * #sres_type_aaaa,
+ * #sres_type_srv, and
+ * #sres_type_naptr.
+ *
+ * Deprecated query type #sres_type_a6 is also decoded.
+ *
+ * @note The domain name is @b not concatenated with the domains from seach
+ * path or with the local domain. Use sres_search() in order to try domains
+ * in search path.
+ *
+ * @sa sres_search(), sres_blocking_query(), sres_cached_answers(),
+ * sres_query_sockaddr()
+ *
+ * @ERRORS
+ * @ERROR EFAULT @a res or @a domain point outside the address space
+ * @ERROR ENAMETOOLONG @a domain is longer than SRES_MAXDNAME
+ * @ERROR ENETDOWN no DNS servers configured
+ * @ERROR ENOMEM memory exhausted
+ */
+sres_query_t *
+sres_query(sres_resolver_t *res,
+ sres_answer_f *callback,
+ sres_context_t *context,
+ uint16_t type,
+ char const *domain)
+{
+ sres_query_t *query = NULL;
+ size_t dlen;
+
+ char b[8];
+ SU_DEBUG_9(("sres_query(%p, %p, %p, %s, \"%s\") called\n",
+ res, callback, context, sres_record_type(type, b), domain));
+
+ if (res == NULL || domain == NULL)
+ return su_seterrno(EFAULT), (void *)NULL;
+
+ dlen = strlen(domain);
+ if (dlen > SRES_MAXDNAME ||
+ (dlen == SRES_MAXDNAME && domain[dlen - 1] != '.')) {
+ su_seterrno(ENAMETOOLONG);
+ return NULL;
+ }
+
+ /* Reread resolv.conf if needed */
+ sres_resolver_update(res, 0);
+
+ if (res->res_n_servers == 0)
+ return (void)su_seterrno(ENETDOWN), (sres_query_t *)NULL;
+
+ query = sres_query_alloc(res, callback, context, type, domain);
+
+ if (query && sres_send_dns_query(res, query) != 0)
+ sres_free_query(res, query), query = NULL;
+
+ return query;
+}
+
+/**Search DNS.
+ *
+ * Sends DNS queries with specified @a type and @a name to the DNS server.
+ * If the @a name does not contain enought dots, the search domains are
+ * appended to the name and resulting domain name are also queried. When
+ * answer to all the search domains is received, the @a callback function
+ * is called with @a context and combined records from answers as arguments.
+ *
+ * The sres resolver takes care of retransmitting the queries if a root
+ * object is associate with the resolver or if sres_resolver_timer() is
+ * called in regular intervals. It generates an error record with nonzero
+ * status if no response is received.
+ *
+ * @param res pointer to resolver object
+ * @param callback pointer to completion function
+ * @param context argument given to the completion function
+ * @param type record type to search (or sres_qtype_any for any record)
+ * @param name host or domain name to search from DNS
+ *
+ * @ERRORS
+ * @ERROR EFAULT @a res or @a domain point outside the address space
+ * @ERROR ENAMETOOLONG @a domain is longer than SRES_MAXDNAME
+ * @ERROR ENETDOWN no DNS servers configured
+ * @ERROR ENOMEM memory exhausted
+ *
+ * @sa sres_query(), sres_blocking_search(), sres_search_cached_answers().
+ */
+sres_query_t *
+sres_search(sres_resolver_t *res,
+ sres_answer_f *callback,
+ sres_context_t *context,
+ uint16_t type,
+ char const *name)
+{
+ char const *domain = name;
+ sres_query_t *query = NULL;
+ size_t dlen;
+ unsigned dots; char const *dot;
+ char b[8];
+
+ SU_DEBUG_9(("sres_search(%p, %p, %p, %s, \"%s\") called\n",
+ res, callback, context, sres_record_type(type, b), domain));
+
+ if (res == NULL || domain == NULL)
+ return su_seterrno(EFAULT), (void *)NULL;
+
+ dlen = strlen(domain);
+ if (dlen > SRES_MAXDNAME ||
+ (dlen == SRES_MAXDNAME && domain[dlen - 1] != '.')) {
+ su_seterrno(ENAMETOOLONG);
+ return NULL;
+ }
+
+ sres_resolver_update(res, 0);
+
+ if (res->res_n_servers == 0)
+ return (void)su_seterrno(ENETDOWN), (sres_query_t *)NULL;
+
+ if (sres_has_search_domain(res))
+ for (dots = 0, dot = strchr(domain, '.');
+ dots < res->res_config->c_opt.ndots && dot;
+ dots++, dot = strchr(dot + 1, '.'))
+ ;
+ else
+ dots = 0;
+
+ query = sres_query_alloc(res, callback, context, type, domain);
+
+ if (query) {
+ /* Create sub-query for each search domain */
+ if (dots < res->res_config->c_opt.ndots) {
+ sres_query_t *sub;
+ int i, subs;
+ size_t len;
+ char const *const *domains = res->res_config->c_search;
+ char search[SRES_MAXDNAME + 1];
+
+ memcpy(search, domain, dlen);
+ search[dlen++] = '.';
+ search[dlen] = '\0';
+
+ for (i = 0, subs = 0; i <= SRES_MAX_SEARCH; i++) {
+ if (domains[i]) {
+ len = strlen(domains[i]);
+
+ if (dlen + len + 1 > SRES_MAXDNAME)
+ continue;
+
+ memcpy(search + dlen, domains[i], len);
+ search[dlen + len] = '.';
+ search[dlen + len + 1] = '\0';
+ sub = sres_query_alloc(res, sres_answer_subquery, (void *)query,
+ type, search);
+
+ if (sres_send_dns_query(res, sub) == 0) {
+ query->q_subqueries[i] = sub;
+ }
+ else {
+ sres_free_query(res, sub), sub = NULL;
+ }
+ subs += sub != NULL;
+ }
+ }
+
+ query->q_n_subs = subs;
+ }
+
+ if (sres_send_dns_query(res, query) != 0) {
+ if (!query->q_n_subs)
+ sres_free_query(res, query), query = NULL;
+ else
+ query->q_id = 0;
+ }
+ }
+
+ return query;
+}
+
+/** Make a reverse DNS query.
+ *
+ * Send a query to DNS server with specified @a type and domain name formed
+ * from the socket address @a addr. The sres resolver takes care of
+ * retransmitting the query if a root object is associate with the resolver or
+ * if sres_resolver_timer() is called in regular intervals. It generates an
+ * error record with nonzero status if no response is received.
+ *
+ * @param res pointer to resolver
+ * @param callback function called when query is answered or times out
+ * @param context pointer given as an extra argument to @a callback function
+ * @param type record type to query (or sres_qtype_any for any record)
+ * @param addr socket address structure
+ *
+ * The @a type should be #sres_type_ptr. The @a addr should contain either
+ * IPv4 (AF_INET) or IPv6 (AF_INET6) address.
+ *
+ * If the #SRES_OPTIONS environment variable, #RES_OPTIONS environment
+ * variable, or an "options" entry in resolv.conf file contains an option
+ * "ip6-dotint", the IPv6 addresses are resolved using suffix ".ip6.int"
+ * instead of the standard ".ip6.arpa" suffix.
+ *
+ * @ERRORS
+ * @ERROR EAFNOSUPPORT address family specified in @a addr is not supported
+ * @ERROR ENETDOWN no DNS servers configured
+ * @ERROR EFAULT @a res or @a addr point outside the address space
+ * @ERROR ENOMEM memory exhausted
+ *
+ * @sa sres_query(), sres_blocking_query_sockaddr(),
+ * sres_cached_answers_sockaddr()
+ *
+ */
+sres_query_t *
+sres_query_sockaddr(sres_resolver_t *res,
+ sres_answer_f *callback,
+ sres_context_t *context,
+ uint16_t type,
+ struct sockaddr const *addr)
+{
+ char name[80];
+
+ if (!res || !addr)
+ return su_seterrno(EFAULT), (void *)NULL;
+
+ if (!sres_sockaddr2string(res, name, sizeof(name), addr))
+ return NULL;
+
+ return sres_query(res, callback, context, type, name);
+}
+
+
+/** Make a DNS query.
+ *
+ * @deprecated Use sres_query() instead.
+ */
+sres_query_t *
+sres_query_make(sres_resolver_t *res,
+ sres_answer_f *callback,
+ sres_context_t *context,
+ int dummy,
+ uint16_t type,
+ char const *domain)
+{
+ return sres_query(res, callback, context, type, domain);
+}
+
+/** Make a reverse DNS query.
+ *
+ * @deprecated Use sres_query_sockaddr() instead.
+ */
+sres_query_t *
+sres_query_make_sockaddr(sres_resolver_t *res,
+ sres_answer_f *callback,
+ sres_context_t *context,
+ int dummy,
+ uint16_t type,
+ struct sockaddr const *addr)
+{
+ char name[80];
+
+ if (!res || !addr)
+ return su_seterrno(EFAULT), (void *)NULL;
+
+ if (!sres_sockaddr2string(res, name, sizeof(name), addr))
+ return NULL;
+
+ return sres_query_make(res, callback, context, dummy, type, name);
+}
+
+
+/** Bind a query with another callback and context pointer.
+ *
+ * @param query pointer to a query object to bind
+ * @param callback pointer to new callback function (may be NULL)
+ * @param context pointer to callback context (may be NULL)
+*/
+void sres_query_bind(sres_query_t *query,
+ sres_answer_f *callback,
+ sres_context_t *context)
+{
+ if (query) {
+ query->q_callback = callback;
+ query->q_context = context;
+ }
+}
+
+/**Get a list of matching (type/domain) records from cache.
+ *
+ * @return
+ * pointer to an array of pointers to cached records, or
+ * NULL if no entry was found.
+ *
+ * @ERRORS
+ * @ERROR ENAMETOOLONG @a domain is longer than SRES_MAXDNAME
+ * @ERROR ENOENT no cached records were found
+ * @ERROR EFAULT @a res or @a domain point outside the address space
+ * @ERROR ENOMEM memory exhausted
+ */
+sres_record_t **
+sres_cached_answers(sres_resolver_t *res,
+ uint16_t type,
+ char const *domain)
+{
+ sres_record_t **result;
+ char rooted_domain[SRES_MAXDNAME];
+
+ if (!res)
+ return su_seterrno(EFAULT), (void *)NULL;
+
+ domain = sres_toplevel(rooted_domain, sizeof rooted_domain, domain);
+
+ if (!domain)
+ return NULL;
+
+ if (!sres_cache_get(res->res_cache, type, domain, &result))
+ return su_seterrno(ENOENT), (void *)NULL;
+
+ return result;
+}
+
+/**Search for a list of matching (type/name) records from cache.
+ *
+ * @return
+ * pointer to an array of pointers to cached records, or
+ * NULL if no entry was found.
+ *
+ * @ERRORS
+ * @ERROR ENAMETOOLONG @a name or resulting domain is longer than SRES_MAXDNAME
+ * @ERROR ENOENT no cached records were found
+ * @ERROR EFAULT @a res or @a domain point outside the address space
+ * @ERROR ENOMEM memory exhausted
+ *
+ * @sa sres_search(), sres_cached_answers()
+ */
+sres_record_t **
+sres_search_cached_answers(sres_resolver_t *res,
+ uint16_t type,
+ char const *name)
+{
+ char const *domain = name;
+ sres_record_t **search_results[SRES_MAX_SEARCH + 1] = { NULL };
+ char rooted_domain[SRES_MAXDNAME];
+ unsigned dots; char const *dot;
+ size_t found = 0;
+ int i;
+
+ SU_DEBUG_9(("sres_search_cached_answers(%p, %s, \"%s\") called\n",
+ res, sres_record_type(type, rooted_domain), domain));
+
+ if (!res || !name)
+ return su_seterrno(EFAULT), (void *)NULL;
+
+ if (sres_has_search_domain(res))
+ for (dots = 0, dot = strchr(domain, '.');
+ dots < res->res_config->c_opt.ndots && dot;
+ dots++, dot = strchr(dot + 1, '.'))
+ ;
+ else
+ dots = 0;
+
+ domain = sres_toplevel(rooted_domain, sizeof rooted_domain, domain);
+
+ if (!domain)
+ return NULL;
+
+ if (sres_cache_get(res->res_cache, type, domain, &search_results[0]))
+ found = 1;
+
+ if (dots < res->res_config->c_opt.ndots) {
+ char const *const *domains = res->res_config->c_search;
+ size_t dlen = strlen(domain);
+
+ for (i = 0; domains[i] && i < SRES_MAX_SEARCH; i++) {
+ size_t len = strlen(domains[i]);
+ if (dlen + len + 1 >= SRES_MAXDNAME)
+ continue;
+ if (domain != rooted_domain)
+ domain = memcpy(rooted_domain, domain, dlen);
+ memcpy(rooted_domain + dlen, domains[i], len);
+ strcpy(rooted_domain + dlen + len, ".");
+ if (sres_cache_get(res->res_cache, type, domain, search_results + i + 1))
+ found++;
+ }
+ }
+
+ if (found == 0)
+ return su_seterrno(ENOENT), (void *)NULL;
+
+ if (found == 1) {
+ for (i = 0; i <= SRES_MAX_SEARCH; i++)
+ if (search_results[i])
+ return search_results[i];
+ }
+
+ return sres_combine_results(res, search_results);
+}
+
+/**Get a list of matching (type/domain) reverse records from cache.
+ *
+ * @param res pointer to resolver
+ * @param type record type to query (or sres_qtype_any for any record)
+ * @param addr socket address structure
+ *
+ * The @a type should be #sres_type_ptr. The @a addr should contain either
+ * IPv4 (AF_INET) or IPv6 (AF_INET6) address.
+ *
+ * If the #SRES_OPTIONS environment variable, #RES_OPTIONS environment
+ * variable or an "options" entry in resolv.conf file contains an option
+ * "ip6-dotint", the IPv6 addresses are resolved using suffix ".ip6.int"
+ * instead of default ".ip6.arpa".
+ *
+ * @retval
+ * pointer to an array of pointers to cached records, or
+ * NULL if no entry was found.
+ *
+ * @ERRORS
+ * @ERROR EAFNOSUPPORT address family specified in @a addr is not supported
+ * @ERROR ENOENT no cached records were found
+ * @ERROR EFAULT @a res or @a addr point outside the address space
+ * @ERROR ENOMEM memory exhausted
+ */
+sres_record_t **
+sres_cached_answers_sockaddr(sres_resolver_t *res,
+ uint16_t type,
+ struct sockaddr const *addr)
+{
+ sres_record_t **result;
+ char name[80];
+
+ if (!res || !addr)
+ return su_seterrno(EFAULT), (void *)NULL;
+
+ if (!sres_sockaddr2string(res, name, sizeof name, addr))
+ return NULL;
+
+ if (!sres_cache_get(res->res_cache, type, name, &result))
+ su_seterrno(ENOENT), (void *)NULL;
+
+ return result;
+}
+
+/** Sort answers. */
+int
+sres_sort_answers(sres_resolver_t *res, sres_record_t **answers)
+{
+ int i, j;
+
+ if (res == NULL || answers == NULL)
+ return su_seterrno(EFAULT);
+
+ if (answers[0] == NULL || answers[1] == NULL)
+ return 0;
+
+ /* Simple insertion sorting */
+ /*
+ * We do not use qsort because we want later extend this to sort
+ * local A records first etc.
+ */
+ for (i = 1; answers[i]; i++) {
+ for (j = 0; j < i; j++) {
+ if (sres_record_compare(answers[i], answers[j]) < 0)
+ break;
+ }
+ if (j < i) {
+ sres_record_t *r = answers[i];
+ for (; j < i; i--) {
+ answers[i] = answers[i - 1];
+ }
+ answers[j] = r;
+ }
+ }
+
+ return 0;
+}
+
+/** Sort and filter query results */
+int
+sres_filter_answers(sres_resolver_t *res,
+ sres_record_t **answers,
+ uint16_t type)
+{
+ int i, n;
+
+ for (n = 0, i = 0; answers && answers[i]; i++) {
+ if (answers[i]->sr_record->r_status ||
+ answers[i]->sr_record->r_class != sres_class_in ||
+ (type != 0 && answers[i]->sr_record->r_type != type)) {
+ sres_free_answer(res, answers[i]);
+ continue;
+ }
+ answers[n++] = answers[i];
+ }
+ answers[n] = NULL;
+
+ sres_sort_answers(res, answers);
+
+ return n;
+}
+
+
+/** Free and zero one record. */
+void sres_free_answer(sres_resolver_t *res, sres_record_t *answer)
+{
+ if (res && answer)
+ sres_cache_free_one(res->res_cache, answer);
+}
+
+/** Free and zero an array of records.
+ *
+ * The array of records can be returned by sres_cached_answers() or
+ * given by callback function.
+ */
+void
+sres_free_answers(sres_resolver_t *res,
+ sres_record_t **answers)
+{
+ if (res && answers)
+ sres_cache_free_answers(res->res_cache, answers);
+}
+
+/** Convert type to its name. */
+char const *sres_record_type(int type, char buffer[8])
+{
+ switch (type) {
+ case sres_type_a: return "A";
+ case sres_type_ns: return "NS";
+ case sres_type_mf: return "MF";
+ case sres_type_cname: return "CNAME";
+ case sres_type_soa: return "SOA";
+ case sres_type_mb: return "MB";
+ case sres_type_mg: return "MG";
+ case sres_type_mr: return "MR";
+ case sres_type_null: return "NULL";
+ case sres_type_wks: return "WKS";
+ case sres_type_ptr: return "PTR";
+ case sres_type_hinfo: return "HINFO";
+ case sres_type_minfo: return "MINFO";
+ case sres_type_mx: return "MX";
+ case sres_type_txt: return "TXT";
+ case sres_type_rp: return "RP";
+ case sres_type_afsdb: return "AFSDB";
+ case sres_type_x25: return "X25";
+ case sres_type_isdn: return "ISDN";
+ case sres_type_rt: return "RT";
+ case sres_type_nsap: return "NSAP";
+ case sres_type_nsap_ptr: return "NSAP_PTR";
+ case sres_type_sig: return "SIG";
+ case sres_type_key: return "KEY";
+ case sres_type_px: return "PX";
+ case sres_type_gpos: return "GPOS";
+ case sres_type_aaaa: return "AAAA";
+ case sres_type_loc: return "LOC";
+ case sres_type_nxt: return "NXT";
+ case sres_type_eid: return "EID";
+ case sres_type_nimloc: return "NIMLOC";
+ case sres_type_srv: return "SRV";
+ case sres_type_atma: return "ATMA";
+ case sres_type_naptr: return "NAPTR";
+ case sres_type_kx: return "KX";
+ case sres_type_cert: return "CERT";
+ case sres_type_a6: return "A6";
+ case sres_type_dname: return "DNAME";
+ case sres_type_sink: return "SINK";
+ case sres_type_opt: return "OPT";
+
+ case sres_qtype_tsig: return "TSIG";
+ case sres_qtype_ixfr: return "IXFR";
+ case sres_qtype_axfr: return "AXFR";
+ case sres_qtype_mailb: return "MAILB";
+ case sres_qtype_maila: return "MAILA";
+ case sres_qtype_any: return "ANY";
+
+ default:
+ sprintf(buffer, "%u?", type & 65535);
+ return buffer;
+ }
+}
+
+/** Convert class to its name. */
+char const *sres_record_class(int rclass, char buffer[8])
+{
+ switch (rclass) {
+ case 1: return "IN";
+ case 2: return "2?";
+ case 3: return "CHAOS";
+ case 4: return "HS";
+ case 254: return "NONE";
+ case 255: return "ANY";
+
+ default:
+ sprintf(buffer, "%u?", rclass & 65535);
+ return buffer;
+ }
+}
+
+/** Compare two records. */
+int
+sres_record_compare(sres_record_t const *aa, sres_record_t const *bb)
+{
+ int D;
+ sres_common_t const *a = aa->sr_record, *b = bb->sr_record;
+
+ D = a->r_status - b->r_status; if (D) return D;
+ D = a->r_class - b->r_class; if (D) return D;
+ D = a->r_type - b->r_type; if (D) return D;
+
+ if (a->r_status)
+ return 0;
+
+ switch (a->r_type) {
+ case sres_type_soa:
+ {
+ sres_soa_record_t const *A = aa->sr_soa, *B = bb->sr_soa;
+ D = A->soa_serial - B->soa_serial; if (D) return D;
+ D = strcasecmp(A->soa_mname, B->soa_mname); if (D) return D;
+ D = strcasecmp(A->soa_rname, B->soa_rname); if (D) return D;
+ D = A->soa_refresh - B->soa_refresh; if (D) return D;
+ D = A->soa_retry - B->soa_retry; if (D) return D;
+ D = A->soa_expire - B->soa_expire; if (D) return D;
+ D = A->soa_minimum - B->soa_minimum; if (D) return D;
+ return 0;
+ }
+ case sres_type_a:
+ {
+ sres_a_record_t const *A = aa->sr_a, *B = bb->sr_a;
+ return memcmp(&A->a_addr, &B->a_addr, sizeof A->a_addr);
+ }
+ case sres_type_a6:
+ {
+ sres_a6_record_t const *A = aa->sr_a6, *B = bb->sr_a6;
+ D = A->a6_prelen - B->a6_prelen; if (D) return D;
+ D = !A->a6_prename - !B->a6_prename;
+ if (D == 0 && A->a6_prename && B->a6_prename)
+ D = strcasecmp(A->a6_prename, B->a6_prename); if (D) return D;
+ return memcmp(&A->a6_suffix, &B->a6_suffix, sizeof A->a6_suffix);
+ }
+ case sres_type_aaaa:
+ {
+ sres_aaaa_record_t const *A = aa->sr_aaaa, *B = bb->sr_aaaa;
+ return memcmp(&A->aaaa_addr, &B->aaaa_addr, sizeof A->aaaa_addr);
+ }
+ case sres_type_cname:
+ {
+ sres_cname_record_t const *A = aa->sr_cname, *B = bb->sr_cname;
+ return strcmp(A->cn_cname, B->cn_cname);
+ }
+ case sres_type_ptr:
+ {
+ sres_ptr_record_t const *A = aa->sr_ptr, *B = bb->sr_ptr;
+ return strcmp(A->ptr_domain, B->ptr_domain);
+ }
+ case sres_type_srv:
+ {
+ sres_srv_record_t const *A = aa->sr_srv, *B = bb->sr_srv;
+ D = A->srv_priority - B->srv_priority; if (D) return D;
+ /* Record with larger weight first */
+ D = B->srv_weight - A->srv_weight; if (D) return D;
+ D = strcmp(A->srv_target, B->srv_target); if (D) return D;
+ return A->srv_port - B->srv_port;
+ }
+ case sres_type_naptr:
+ {
+ sres_naptr_record_t const *A = aa->sr_naptr, *B = bb->sr_naptr;
+ D = A->na_order - B->na_order; if (D) return D;
+ D = A->na_prefer - B->na_prefer; if (D) return D;
+ D = strcmp(A->na_flags, B->na_flags); if (D) return D;
+ D = strcmp(A->na_services, B->na_services); if (D) return D;
+ D = strcmp(A->na_regexp, B->na_regexp); if (D) return D;
+ return strcmp(A->na_replace, B->na_replace);
+ }
+ default:
+ return 0;
+ }
+}
+
+/* ---------------------------------------------------------------------- */
+/* Private functions */
+
+/** Destruct */
+static
+void
+sres_resolver_destructor(void *arg)
+{
+ sres_resolver_t *res = arg;
+
+ assert(res);
+ sres_cache_unref(res->res_cache);
+ res->res_cache = NULL;
+
+ sres_servers_close(res, res->res_servers);
+
+ if (res->res_config)
+ su_home_unref((su_home_t *)res->res_config->c_home);
+
+ if (res->res_updcb)
+ res->res_updcb(res->res_async, INVALID_SOCKET, INVALID_SOCKET);
+}
+
+/*
+ * 3571 is a prime =>
+ * we hash successive id values to different parts of hash tables
+ */
+#define Q_PRIME 3571
+#define SRES_QUERY_HASH(q) ((q)->q_hash)
+
+HTABLE_BODIES_WITH(sres_qtable, qt, sres_query_t, SRES_QUERY_HASH,
+ unsigned, size_t);
+
+/** Allocate a query structure */
+static
+sres_query_t *
+sres_query_alloc(sres_resolver_t *res,
+ sres_answer_f *callback,
+ sres_context_t *context,
+ uint16_t type,
+ char const *domain)
+{
+ sres_query_t *query;
+ size_t dlen = strlen(domain);
+
+ if (sres_qtable_is_full(res->res_queries))
+ if (sres_qtable_resize(res->res_home, res->res_queries, 0) < 0)
+ return NULL;
+
+ query = su_alloc(res->res_home, sizeof(*query) + dlen + 1);
+
+ if (query) {
+ memset(query, 0, sizeof *query);
+ query->q_res = res;
+ query->q_callback = callback;
+ query->q_context = context;
+ query->q_type = type;
+ query->q_class = sres_class_in;
+ query->q_timestamp = res->res_now;
+ query->q_name = strcpy((char *)(query + 1), domain);
+
+ query->q_id = sres_new_id(res); assert(query->q_id);
+ query->q_i_server = res->res_i_server;
+ query->q_n_servers = res->res_n_servers;
+ query->q_hash = query->q_id * Q_PRIME /* + query->q_i_server */;
+
+ sres_qtable_append(res->res_queries, query);
+
+ if (res->res_schedulecb && res->res_queries->qt_used == 1)
+ res->res_schedulecb(res->res_async, 2 * SRES_RETRANSMIT_INTERVAL);
+ }
+
+ return query;
+}
+
+static inline
+void
+sres_remove_query(sres_resolver_t *res, sres_query_t *q, int all)
+{
+ int i;
+
+ if (q->q_hash) {
+ sres_qtable_remove(res->res_queries, q), q->q_hash = 0;
+
+ if (all)
+ for (i = 0; i <= SRES_MAX_SEARCH; i++) {
+ if (q->q_subqueries[i] && q->q_subqueries[i]->q_hash) {
+ sres_qtable_remove(res->res_queries, q->q_subqueries[i]);
+ q->q_subqueries[i]->q_hash = 0;
+ }
+ }
+ }
+}
+
+/** Remove a query from hash table and free it. */
+static
+void sres_free_query(sres_resolver_t *res, sres_query_t *q)
+{
+ int i;
+
+ if (q == NULL)
+ return;
+
+ if (q->q_hash)
+ sres_qtable_remove(res->res_queries, q), q->q_hash = 0;
+
+ for (i = 0; i <= SRES_MAX_SEARCH; i++) {
+ sres_query_t *sq;
+
+ sq = q->q_subqueries[i];
+ q->q_subqueries[i] = NULL;
+ if (sq)
+ sres_free_query(res, sq);
+ if (q->q_subanswers[i])
+ sres_cache_free_answers(res->res_cache, q->q_subanswers[i]);
+ q->q_subanswers[i] = NULL;
+ }
+
+ su_free(res->res_home, q);
+}
+
+static
+sres_record_t **
+sres_combine_results(sres_resolver_t *res,
+ sres_record_t **search_results[SRES_MAX_SEARCH + 1])
+{
+ sres_record_t **combined_result;
+ int i, j, found;
+
+ /* Combine the results into a single list. */
+ for (i = 0, found = 0; i <= SRES_MAX_SEARCH; i++)
+ if (search_results[i])
+ for (j = 0; search_results[i][j]; j++)
+ found++;
+
+ combined_result = su_alloc((su_home_t *)res->res_cache,
+ (found + 1) * (sizeof combined_result[0]));
+ if (combined_result) {
+ for (i = 0, found = 0; i <= SRES_MAX_SEARCH; i++)
+ if (search_results[i])
+ for (j = 0; search_results[i][j]; j++) {
+ combined_result[found++] = search_results[i][j];
+ search_results[i][j] = NULL;
+ }
+
+ combined_result[found] = NULL;
+ sres_sort_answers(res, combined_result);
+ }
+
+ for (i = 0; i <= SRES_MAX_SEARCH; i++)
+ if (search_results[i])
+ sres_free_answers(res, search_results[i]), search_results[i] = NULL;
+
+ return combined_result;
+}
+
+static
+int
+sres_sockaddr2string(sres_resolver_t *res,
+ char name[],
+ size_t namelen,
+ struct sockaddr const *addr)
+{
+ name[0] = '\0';
+
+ if (addr->sa_family == AF_INET) {
+ struct sockaddr_in const *sin = (struct sockaddr_in *)addr;
+ uint8_t const *in_addr = (uint8_t*)&sin->sin_addr;
+ return snprintf(name, namelen, "%u.%u.%u.%u.in-addr.arpa.",
+ in_addr[3], in_addr[2], in_addr[1], in_addr[0]);
+ }
+#if HAVE_SIN6
+ else if (addr->sa_family == AF_INET6) {
+ struct sockaddr_in6 const *sin6 = (struct sockaddr_in6 *)addr;
+ size_t addrsize = sizeof(sin6->sin6_addr.s6_addr);
+ char *postfix;
+ size_t required;
+ size_t i;
+
+ if (res->res_config->c_opt.ip6int)
+ postfix = "ip6.int.";
+ else
+ postfix = "ip6.arpa.";
+
+ required = addrsize * 4 + strlen(postfix);
+
+ if (namelen <= required)
+ return (int)required;
+
+ for (i = 0; i < addrsize; i++) {
+ uint8_t byte = sin6->sin6_addr.s6_addr[addrsize - i - 1];
+ uint8_t hex;
+
+ hex = byte & 0xf;
+ name[4 * i] = hex > 9 ? hex + 'a' - 10 : hex + '0';
+ name[4 * i + 1] = '.';
+ hex = (byte >> 4) & 0xf;
+ name[4 * i + 2] = hex > 9 ? hex + 'a' - 10 : hex + '0';
+ name[4 * i + 3] = '.';
+ }
+
+ strcpy(name + 4 * i, postfix);
+
+ return (int)required;
+ }
+#endif /* HAVE_SIN6 */
+ else {
+ su_seterrno(EAFNOSUPPORT);
+ SU_DEBUG_3(("%s: %s\n", "sres_sockaddr2string",
+ su_strerror(EAFNOSUPPORT)));
+ return 0;
+ }
+}
+
+/** Make a domain name a top level domain name.
+ *
+ * The function sres_toplevel() returns a copies string @a domain and
+ * terminates it with a dot if it is not already terminated.
+ */
+static
+char const *
+sres_toplevel(char buf[], size_t blen, char const *domain)
+{
+ size_t len;
+ int already;
+
+ if (!domain)
+ return su_seterrno(EFAULT), (void *)NULL;
+
+ len = strlen(domain);
+
+ if (len >= blen)
+ return su_seterrno(ENAMETOOLONG), (void *)NULL;
+
+ already = len > 0 && domain[len - 1] == '.';
+
+ if (already)
+ return domain;
+
+ if (len + 1 >= blen)
+ return su_seterrno(ENAMETOOLONG), (void *)NULL;
+
+ strcpy(buf, domain);
+ buf[len] = '.'; buf[len + 1] = '\0';
+
+ return buf;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int sres_update_config(sres_resolver_t *res, int always, time_t now);
+static int sres_parse_config(sres_config_t *, FILE *);
+static int sres_parse_options(sres_config_t *c, char const *value);
+static int sres_parse_nameserver(sres_config_t *c, char const *server);
+static time_t sres_config_timestamp(sres_config_t const *c);
+
+/** Update configuration
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error
+ */
+int sres_resolver_update(sres_resolver_t *res, int always)
+{
+ sres_server_t **servers, **old_servers;
+ int updated;
+
+ updated = sres_update_config(res, always, time(&res->res_now));
+ if (updated < 0)
+ return -1;
+
+ if (!res->res_servers || always || updated) {
+ servers = sres_servers_new(res, res->res_config);
+ old_servers = res->res_servers;
+
+ res->res_i_server = 0;
+ res->res_n_servers = sres_servers_count(servers);
+ res->res_servers = servers;
+
+ sres_servers_close(res, old_servers);
+ su_free(res->res_home, old_servers);
+
+ if (!servers)
+ return -1;
+ }
+
+ return 0;
+}
+
+/** Update config file.
+ *
+ * @retval 1 if DNS server list is different from old one.
+ * @retval 0 when otherwise successful
+ * @retval -1 upon an error
+ */
+static
+int sres_update_config(sres_resolver_t *res, int always, time_t now)
+{
+ sres_config_t *c = NULL;
+ sres_config_t const *previous;
+ int retval;
+
+ previous = res->res_config;
+
+ if (!always && previous && now < res->res_checked)
+ return 0;
+ /* Try avoid checking for changes too often. */
+ res->res_checked = now + SRES_UPDATE_INTERVAL_SECS;
+
+ if (!always && previous &&
+ sres_config_timestamp(previous) == previous->c_modified)
+ return 0;
+
+ c = sres_parse_resolv_conf(res, res->res_options);
+ if (!c)
+ return -1;
+
+ res->res_config = c;
+
+ retval = sres_config_changed_servers(c, previous);
+
+ su_home_unref((su_home_t *)previous->c_home);
+
+ return retval;
+}
+
+#if _WIN32
+
+/** Number of octets to read from a registry key at a time */
+#define QUERY_DATALEN 1024
+#define MAX_DATALEN 65535
+
+/**
+ * Parses name servers listed in registry key 'key+lpValueName'. The
+ * key is expected to contain a whitespace separate list of
+ * name server IP addresses.
+ *
+ * @return number of server addresses added
+ */
+static int sres_parse_win32_reg_parse_dnsserver(sres_config_t *c, HKEY key, LPCTSTR lpValueName)
+{
+ su_home_t *home = c->c_home;
+ su_strlst_t *reg_dns_list;
+ BYTE *name_servers = su_alloc(home, QUERY_DATALEN);
+ DWORD name_servers_length = QUERY_DATALEN;
+ int ret, servers_added = 0;
+
+ /* get name servers and ... */
+ while((ret = RegQueryValueEx(key,
+ lpValueName,
+ NULL, NULL,
+ name_servers,
+ &name_servers_length)) == ERROR_MORE_DATA) {
+ name_servers_length += QUERY_DATALEN;
+
+ /* sanity check, upper limit for memallocs */
+ if (name_servers_length > MAX_DATALEN) break;
+
+ name_servers = su_realloc(home, name_servers, name_servers_length);
+ }
+
+ /* if reading the key was succesful, continue */
+ if (ret == ERROR_SUCCESS) {
+ if (name_servers[0]){
+ int i;
+
+ /* add to list */
+ reg_dns_list = su_strlst_split(home, (char *)name_servers, " ");
+
+ for(i = 0 ; i < su_strlst_len(reg_dns_list); i++) {
+ const char *item = su_strlst_item(reg_dns_list, i);
+ SU_DEBUG_3(("Adding nameserver: %s (key=%s)\n", item, (char*)lpValueName));
+ sres_parse_nameserver(c, item);
+ ++servers_added;
+ }
+
+ su_strlst_destroy(reg_dns_list);
+
+ }
+ }
+
+ su_free(home, name_servers);
+
+ return servers_added;
+}
+
+/**
+ * Discover system nameservers from Windows registry.
+ *
+ * Refs:
+ * - http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sysinfo/base/regqueryvalueex.asp
+ * - http://support.microsoft.com/default.aspx?scid=kb;en-us;120642
+ * - http://support.microsoft.com/kb/314053/EN-US/
+ * - IP Helper API (possibly better way than current registry-based impl.)
+ * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/iphlp/iphlp/ip_helper_start_page.asp
+ */
+static int sres_parse_win32_reg(sres_config_t *c)
+{
+ int ret = -1;
+
+#define MAX_KEY_LEN 255
+#define MAX_VALUE_NAME_LEN 16383
+
+ su_home_t *home = c->c_home;
+ HKEY key_handle;
+#if 0
+ HKEY interface_key_handle;
+ FILETIME ftime;
+ int index, i;
+#endif
+ int found = 0;
+ char *interface_guid = su_alloc(home, MAX_VALUE_NAME_LEN);
+
+#if 0
+#if __MINGW32__
+ DWORD guid_size = QUERY_DATALEN;
+#else
+ int guid_size = MAX_VALUE_NAME_LEN;
+#endif
+
+ /* step: find interface specific nameservers
+ * - this is currently disabled 2006/Jun (the current check might insert
+ * multiple unnecessary nameservers to the search list)
+ */
+ /* open the 'Interfaces' registry Key */
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces",
+ 0, KEY_READ, &key_handle)) {
+ SU_DEBUG_2(("RegOpenKeyEx failed\n"));
+ } else {
+ index = 0;
+ /* for each interface listed ... */
+ while (RegEnumKeyEx(key_handle, index,
+ interface_guid, &guid_size,
+ NULL,NULL,0,&ftime) == ERROR_SUCCESS){
+ if (RegOpenKeyEx(key_handle, interface_guid,
+ 0, KEY_READ,
+ &interface_key_handle) == ERROR_SUCCESS) {
+
+ /* note: 'NameServer' is preferred over 'DhcpNameServer' */
+ found += sres_parse_win32_reg_parse_dnsserver(c, interface_key_handle, "NameServer");
+ if (found == 0)
+ found += sres_parse_win32_reg_parse_dnsserver(c, interface_key_handle, "DhcpNameServer");
+
+ RegCloseKey(interface_key_handle);
+ } else{
+ SU_DEBUG_2(("interface RegOpenKeyEx failed\n"));
+ }
+ index++;
+ guid_size = 64;
+ }
+ RegCloseKey(key_handle);
+ }
+#endif /* #if 0: interface-specific nameservers */
+
+ /* step: if no interface-specific nameservers are found,
+ * check for system-wide nameservers */
+ if (found == 0) {
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",
+ 0, KEY_READ, &key_handle)) {
+ SU_DEBUG_2(("RegOpenKeyEx failed (2)\n"));
+ } else {
+ found += sres_parse_win32_reg_parse_dnsserver(c, key_handle, "NameServer");
+ if (found == 0)
+ found += sres_parse_win32_reg_parse_dnsserver(c, key_handle, "DhcpNameServer");
+ RegCloseKey(key_handle);
+ }
+ }
+
+ SU_DEBUG_3(("Total of %d name servers found from win32 registry.\n", found));
+
+ /* return success if servers found */
+ if (found) ret = 0;
+
+ su_free(home, interface_guid);
+
+ return ret;
+}
+
+#endif /* _WIN32 */
+
+/** Parse /etc/resolv.conf file.
+ *
+ * @retval #sres_config_t structure when successful
+ * @retval NULL upon an error
+ *
+ * @todo The resolv.conf directives @b sortlist and most of the options
+ * are currently ignored.
+ */
+static
+sres_config_t *sres_parse_resolv_conf(sres_resolver_t *res,
+ char const **options)
+{
+ sres_config_t *c = su_home_new(sizeof *c);
+
+ if (c) {
+ FILE *f;
+ int i;
+
+ f = fopen(c->c_filename = res->res_cnffile, "r");
+
+ sres_parse_config(c, f);
+
+ if (f)
+ fclose(f);
+
+#if _WIN32
+ /* note: no 127.0.0.1 on win32 systems */
+ /* on win32, query the registry for nameservers */
+ if (sres_parse_win32_reg(c) == 0)
+ /* success */;
+ else
+ /* now what? */;
+#else
+ /* Use local nameserver by default */
+ if (c->c_nameservers[0] == NULL)
+ sres_parse_nameserver(c, "127.0.0.1");
+#endif
+
+ for (i = 0; c->c_nameservers[i] && i < SRES_MAX_NAMESERVERS; i++) {
+ struct sockaddr_in *sin = (void *)c->c_nameservers[i]->ns_addr;
+ sin->sin_port = htons(c->c_port);
+ }
+
+ sres_parse_options(c, getenv("RES_OPTIONS"));
+
+ if (options)
+ for (i = 0; options[i]; i++)
+ sres_parse_options(c, options[i]);
+
+ sres_parse_options(c, getenv("SRES_OPTIONS"));
+
+ su_home_threadsafe(c->c_home);
+ }
+
+ return c;
+}
+
+/** Parse config file.
+ *
+ * @return Number of search domains, if successful.
+ * @retval -1 upon an error (never happens).
+ */
+static
+int sres_parse_config(sres_config_t *c, FILE *f)
+{
+ su_home_t *home = c->c_home;
+ int line;
+ char const *localdomain;
+ char *search = NULL, *domain = NULL;
+ char buf[1025];
+ int i = 0;
+
+ localdomain = getenv("LOCALDOMAIN");
+
+ /* Default values */
+ c->c_opt.ndots = 1;
+ c->c_opt.check_names = 1;
+ c->c_opt.timeout = SRES_RETRY_INTERVAL;
+ c->c_opt.attempts = SRES_MAX_RETRY_COUNT;
+ c->c_port = 53;
+
+ if (f != NULL) {
+ for (line = 1; fgets(buf, sizeof(buf), f); line++) {
+ size_t len;
+ char *value, *b;
+
+ /* Skip whitespace at the beginning ...*/
+ b = buf + strspn(buf, " \t");
+
+ /* ... and at the end of line */
+ for (len = strlen(b); len > 0 && strchr(" \t\r\n", b[len - 1]); len--)
+ ;
+
+ if (len == 0 || b[0] == '#') /* Empty line or comment */
+ continue;
+
+ b[len] = '\0';
+
+ len = strcspn(b, " \t");
+ value = b + len; value += strspn(value, " \t");
+
+#define MATCH(token) (len == strlen(token) && strncasecmp(token, b, len) == 0)
+
+ if (MATCH("nameserver")) {
+ if (sres_parse_nameserver(c, value) < 0)
+ return -1;
+ }
+ else if (MATCH("domain")) {
+ if (localdomain) /* LOCALDOMAIN overrides */
+ continue;
+ if (search)
+ su_free(home, search), search = NULL;
+ if (domain)
+ su_free(home, domain), domain = NULL;
+ domain = su_strdup(home, value);
+ if (!domain)
+ return -1;
+ }
+ else if (MATCH("search")) {
+ if (localdomain) /* LOCALDOMAIN overrides */
+ continue;
+ if (search) su_free(home, search), search = NULL;
+ if (domain) su_free(home, domain), domain = NULL;
+ search = su_strdup(home, value);
+ if (!search)
+ return -1;
+ }
+ else if (MATCH("port")) {
+ unsigned long port = strtoul(value, NULL, 10);
+ if (port < 65536)
+ c->c_port = port;
+ }
+ else if (MATCH("options")) {
+ sres_parse_options(c, value);
+ }
+ }
+ }
+
+ if (f)
+ c->c_modified = sres_config_timestamp(c);
+
+ if (localdomain)
+ c->c_search[0] = localdomain;
+ else if (domain)
+ c->c_search[0] = domain;
+ else if (search) {
+ for (i = 0; search[0] && i < SRES_MAX_SEARCH; i++) {
+ c->c_search[i] = search;
+ search += strcspn(search, " \t");
+ if (*search) {
+ *search++ = '\0';
+ search += strspn(search, " \t");
+ }
+ }
+ }
+
+ return i;
+}
+
+/**Environment variable containing options for Sofia resolver. The options
+ * recognized by Sofia resolver are as follows:
+ * - debug turn on debugging (no effect)
+ * - ndots:<i>n</i> when searching, try first to query name as absolute
+ * domain if it contains at least <i>n</i> dots
+ * - timeout:<i>secs</i> timeout in seconds
+ * - attempts:<i>n</i> fail after <i>n</i> retries
+ * - rotate use round robin selection of nameservers
+ * - no-check-names do not check names for invalid characters
+ * - inet6 (no effect)
+ * - ip6-dotint IPv6 addresses are resolved using suffix ".ip6.int"
+ * instead of the standard ".ip6.arpa" suffix
+ * - ip6-bytestring (no effect)
+ * The following option is a Sofia-specific extension:
+ * - no-edns0 do not try to use EDNS0 extension (@RFC2671)
+ *
+ * The same options can be listed in @b options directive in resolv.conf, or
+ * in #RES_OPTIONS environment variable. Note that options given in
+ * #SRES_OPTIONS override those specified in #RES_OPTIONS which in turn
+ * override options specified in the @b options directive of resolve.conf.
+ *
+ * The meaning of an option can be reversed with prefix "no-".
+ *
+ * @sa Manual page for resolv.conf, #RES_OPTIONS.
+ */
+extern char const SRES_OPTIONS[];
+
+/**Environment variable containing resolver options. This environment
+ * variable is also used by standard BIND resolver.
+ *
+ * @sa Manual page for resolv.conf, #SRES_OPTIONS.
+ */
+extern char const RES_OPTIONS[];
+
+
+/* Parse options line or #SRES_OPTIONS or #RES_OPTIONS environment variable. */
+static int
+sres_parse_options(sres_config_t *c, char const *value)
+{
+ if (!value)
+ return -1;
+
+ while (value[0]) {
+ char const *b;
+ size_t len, extra = 0;
+ unsigned long n = 0;
+
+ b = value; len = strcspn(value, " \t:");
+ value += len;
+
+ if (value[0] == ':') {
+ len++;
+ n = strtoul(++value, NULL, 10);
+ value += extra = strcspn(value, " \t");
+ }
+
+ if (*value)
+ value += strspn(value, " \t");
+
+ if (n > 65536) {
+ SU_DEBUG_3(("sres: %s: invalid %*.s\n", c->c_filename,
+ (int)(len + extra), b));
+ continue;
+ }
+
+ /* Documented by BIND9 resolv.conf */
+ if (MATCH("no-debug")) c->c_opt.debug = 0;
+ else if (MATCH("debug")) c->c_opt.debug = 1;
+ else if (MATCH("ndots:")) c->c_opt.ndots = n;
+ else if (MATCH("timeout:")) c->c_opt.timeout = n;
+ else if (MATCH("attempts:")) c->c_opt.attempts = n;
+ else if (MATCH("no-rotate")) c->c_opt.rotate = 0;
+ else if (MATCH("rotate")) c->c_opt.rotate = 1;
+ else if (MATCH("no-check-names")) c->c_opt.check_names = 0;
+ else if (MATCH("check-names")) c->c_opt.check_names = 1;
+ else if (MATCH("no-inet6")) c->c_opt.ip6int = 0;
+ else if (MATCH("inet6")) c->c_opt.inet6 = 1;
+ else if (MATCH("no-ip6-dotint")) c->c_opt.ip6int = 0;
+ else if (MATCH("ip6-dotint")) c->c_opt.ip6int = 1;
+ else if (MATCH("no-ip6-bytestring")) c->c_opt.ip6bytestring = 0;
+ else if (MATCH("ip6-bytestring")) c->c_opt.ip6bytestring = 1;
+ /* Sofia-specific extensions: */
+ else if (MATCH("no-edns0")) c->c_opt.edns = edns_not_supported;
+ else if (MATCH("edns0")) c->c_opt.edns = edns0_configured;
+ else {
+ SU_DEBUG_3(("sres: %s: unknown option %*.s\n",
+ c->c_filename, (int)(len + extra), b));
+ }
+ }
+
+ return 0;
+}
+
+static
+int sres_parse_nameserver(sres_config_t *c, char const *server)
+{
+ sres_nameserver_t *ns;
+ struct sockaddr *sa;
+ int err, i;
+
+ for (i = 0; i < SRES_MAX_NAMESERVERS; i++)
+ if (c->c_nameservers[i] == NULL)
+ break;
+
+ if (i >= SRES_MAX_NAMESERVERS)
+ return 0 /* Silently discard extra nameservers */;
+
+ ns = su_zalloc(c->c_home, (sizeof *ns) + strlen(server) + 1);
+ if (!ns)
+ return -1;
+
+ sa = (void *)ns->ns_addr;
+
+#if HAVE_SIN6
+ if (strchr(server, ':')) {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
+ memset(sa, 0, ns->ns_addrlen = sizeof *sin6);
+ err = inet_pton(sa->sa_family = AF_INET6, server, &sin6->sin6_addr);
+ }
+ else
+#endif
+ {
+ struct sockaddr_in *sin = (struct sockaddr_in *)sa;
+ memset(sa, 0, ns->ns_addrlen = sizeof *sin);
+ err = inet_pton(sa->sa_family = AF_INET, server, &sin->sin_addr);
+ }
+
+ if (err <= 0) {
+ SU_DEBUG_3(("sres: nameserver %s: invalid address\n", server));
+ su_free(c->c_home, ns);
+ return 0;
+ }
+
+#if HAVE_SA_LEN
+ sa->sa_len = ns->ns_addrlen;
+#endif
+
+ c->c_nameservers[i] = ns;
+
+ return 1;
+}
+
+/** Get current timestamp of resolv.conf file */
+static
+time_t sres_config_timestamp(sres_config_t const *c)
+{
+#ifndef _WIN32
+ struct stat st;
+
+ if (stat(c->c_filename, &st) == 0)
+ return st.st_mtime;
+
+ /** @return If the resolv.conf file does not exists, return old timestamp. */
+ return c->c_modified;
+#else
+ /** On WIN32, return always different timestamp */
+ return c->c_modified + SRES_UPDATE_INTERVAL_SECS;
+#endif
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+/** Check if the new configuration has different servers than the old */
+static
+int sres_config_changed_servers(sres_config_t const *new_c,
+ sres_config_t const *old_c)
+{
+ int i;
+ sres_nameserver_t const *new_ns, *old_ns;
+
+ if (old_c == NULL)
+ return 1;
+
+ for (i = 0; i < SRES_MAX_NAMESERVERS; i++) {
+ new_ns = new_c->c_nameservers[i];
+ old_ns = old_c->c_nameservers[i];
+
+ if (!new_ns != !old_ns)
+ return 1;
+ if (!new_ns)
+ return 0;
+ if (new_ns->ns_addrlen != old_ns->ns_addrlen)
+ return 1;
+ if (memcmp(new_ns->ns_addr, old_ns->ns_addr, new_ns->ns_addrlen))
+ return 1;
+ }
+
+ return 0;
+}
+
+/** Allocate new servers structure */
+static
+sres_server_t **sres_servers_new(sres_resolver_t *res,
+ sres_config_t const *c)
+{
+ sres_server_t **servers, *dns;
+ sres_nameserver_t *ns;
+ int N, i;
+ size_t size;
+
+ for (N = 0; c->c_nameservers[N] && N < SRES_MAX_NAMESERVERS; N++)
+ ;
+
+ size = (N + 1) * (sizeof *servers) + N * (sizeof **servers);
+
+ servers = su_zalloc(res->res_home, size); if (!servers) return servers;
+ dns = (void *)(servers + N + 1);
+ for (i = 0; i < N; i++) {
+ dns->dns_socket = INVALID_SOCKET;
+ ns = c->c_nameservers[i];
+ memcpy(dns->dns_addr, ns->ns_addr, dns->dns_addrlen = ns->ns_addrlen);
+ inet_ntop(dns->dns_addr->ss_family, SS_ADDR(dns->dns_addr),
+ dns->dns_name, sizeof dns->dns_name);
+ dns->dns_edns = c->c_opt.edns;
+ servers[i] = dns++;
+ }
+
+ return servers;
+}
+
+static
+void sres_servers_close(sres_resolver_t *res,
+ sres_server_t **servers)
+{
+ int i;
+
+ if (res == NULL || servers == NULL)
+ return;
+
+ for (i = 0; i < SRES_MAX_NAMESERVERS; i++) {
+ if (!servers[i])
+ break;
+
+ if (servers[i]->dns_socket != -1) {
+ if (res->res_updcb)
+ res->res_updcb(res->res_async, INVALID_SOCKET, servers[i]->dns_socket);
+ sres_close(servers[i]->dns_socket);
+ }
+ }
+}
+
+static
+int sres_servers_count(sres_server_t *const *servers)
+{
+ int i;
+
+ if (!servers)
+ return 0;
+
+ for (i = 0; i < SRES_MAX_NAMESERVERS; i++) {
+ if (!servers[i])
+ break;
+ }
+
+ return i;
+}
+
+static
+sres_socket_t sres_server_socket(sres_resolver_t *res, sres_server_t *dns)
+{
+ int family = dns->dns_addr->ss_family;
+ sres_socket_t s;
+
+ if (dns->dns_socket != -1)
+ return dns->dns_socket;
+
+ s = socket(family, SOCK_DGRAM, IPPROTO_UDP);
+ if (s == -1) {
+ SU_DEBUG_1(("%s: %s: %s\n", "sres_server_socket", "socket",
+ su_strerror(su_errno())));
+ dns->dns_error = time(NULL);
+ return s;
+ }
+
+#if HAVE_IP_RECVERR
+ if (family == AF_INET || family == AF_INET6) {
+ int const one = 1;
+ if (setsockopt(s, SOL_IP, IP_RECVERR, &one, sizeof(one)) < 0) {
+ if (family == AF_INET)
+ SU_DEBUG_3(("setsockopt(IPVRECVERR): %s\n", su_strerror(su_errno())));
+ }
+ }
+#endif
+#if HAVE_IPV6_RECVERR
+ if (family == AF_INET6) {
+ int const one = 1;
+ if (setsockopt(s, SOL_IPV6, IPV6_RECVERR, &one, sizeof(one)) < 0)
+ SU_DEBUG_3(("setsockopt(IPV6_RECVERR): %s\n", su_strerror(su_errno())));
+ }
+#endif
+
+ if (connect(s, (void *)dns->dns_addr, dns->dns_addrlen) < 0) {
+ char ipaddr[64];
+ char const *lb = "", *rb = "";
+
+ if (family == AF_INET) {
+ void *addr = &((struct sockaddr_in *)dns->dns_addr)->sin_addr;
+ inet_ntop(family, addr, ipaddr, sizeof ipaddr);
+ }
+#if HAVE_SIN6
+ else if (family == AF_INET6) {
+ void *addr = &((struct sockaddr_in6 *)dns->dns_addr)->sin6_addr;
+ inet_ntop(family, addr, ipaddr, sizeof ipaddr);
+ lb = "[", rb = "]";
+ }
+#endif
+ else
+ snprintf(ipaddr, sizeof ipaddr, "<af=%u>", family);
+
+ SU_DEBUG_1(("%s: %s: %s: %s%s%s:%u\n", "sres_server_socket", "connect",
+ su_strerror(su_errno()), lb, ipaddr, rb,
+ ntohs(((struct sockaddr_in *)dns->dns_addr)->sin_port)));
+ sres_close(s);
+ dns->dns_error = time(NULL);
+ return INVALID_SOCKET;
+ }
+
+ if (res->res_updcb) {
+ if (res->res_updcb(res->res_async, s, INVALID_SOCKET) < 0) {
+ SU_DEBUG_1(("%s: %s: %s\n", "sres_server_socket", "update callback",
+ su_strerror(su_errno())));
+ sres_close(s);
+ dns->dns_error = time(NULL);
+ return INVALID_SOCKET;
+ }
+ }
+
+ dns->dns_socket = s;
+
+ return s;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/** Send a query packet */
+static
+int
+sres_send_dns_query(sres_resolver_t *res,
+ sres_query_t *q)
+{
+ sres_message_t m[1];
+ uint8_t i, i0, N = res->res_n_servers;
+ sres_socket_t s;
+ int transient, error = 0;
+ ssize_t size, no_edns_size, edns_size;
+ uint16_t id = q->q_id;
+ uint16_t type = q->q_type;
+ char const *domain = q->q_name;
+ time_t now = res->res_now;
+ sres_server_t **servers = res->res_servers, *dns;
+ char b[8];
+
+ if (now == 0) time(&now);
+
+ SU_DEBUG_9(("sres_send_dns_query(%p, %p) called\n", res, q));
+
+ if (domain == NULL)
+ return -1;
+ if (servers == NULL)
+ return -1;
+ if (N == 0)
+ return -1;
+
+ memset(m, 0, offsetof(sres_message_t, m_data[sizeof m->m_packet.mp_header]));
+
+ /* Create a DNS message */
+ size = sizeof(m->m_packet.mp_header);
+ m->m_size = (uint16_t)sizeof(m->m_data);
+ m->m_offset = (uint16_t)size;
+
+ m->m_id = id;
+ m->m_flags = htons(SRES_HDR_QUERY | SRES_HDR_RD);
+
+ /* Query record */
+ m->m_qdcount = htons(1);
+ m_put_domain(m, domain, 0, NULL);
+ m_put_uint16(m, type);
+ m_put_uint16(m, sres_class_in);
+
+ no_edns_size = m->m_offset;
+
+ /* EDNS0 record (optional) */
+ m_put_domain(m, ".", 0, NULL);
+ m_put_uint16(m, sres_type_opt);
+ m_put_uint16(m, sizeof(m->m_packet)); /* Class: our UDP payload size */
+ m_put_uint32(m, 0); /* TTL: extended RCODE & flags */
+ m_put_uint16(m, 0);
+
+ edns_size = m->m_offset;
+
+ if (m->m_error) {
+ SU_DEBUG_3(("%s(): encoding: %s\n", "sres_send_dns_query", m->m_error));
+ su_seterrno(EIO);
+ return -1;
+ }
+
+ transient = 0;
+
+ i0 = q->q_i_server; if (i0 > N) i0 = 0; /* Number of DNS servers reduced */
+
+ if (res->res_config->c_opt.rotate ||
+ servers[i0]->dns_error || servers[i0]->dns_icmp)
+ dns = sres_next_server(res, &q->q_i_server, 0), i = q->q_i_server;
+ else
+ dns = servers[i0], i = i0;
+
+ for (; dns; dns = sres_next_server(res, &i, 0)) {
+ /* If server supports EDNS, include EDNS0 record */
+ q->q_edns = dns->dns_edns;
+ /* 0 (no EDNS) or 1 (EDNS supported) additional data records */
+ m->m_arcount = htons(q->q_edns != 0);
+ /* Size with or without EDNS record */
+ size = q->q_edns ? edns_size : no_edns_size;
+
+ s = sres_server_socket(res, dns);
+
+ /* Send the DNS message via the UDP socket */
+ if (s != INVALID_SOCKET && sres_send(s, m->m_data, size, 0) == size)
+ break;
+
+ error = su_errno();
+ dns->dns_icmp = now;
+ /* EINVAL is returned if destination address is bad */
+ if (transient++ < 3 && error != EINVAL && s != -1)
+ continue;
+ transient = 0;
+
+ dns->dns_error = now; /* Mark as a bad destination */
+ }
+
+ if (!dns) {
+ /* All servers have reported errors */
+ SU_DEBUG_5(("%s(): sendto: %s\n", "sres_send_dns_query",
+ su_strerror(error)));
+ return su_seterrno(error);
+ }
+
+ q->q_i_server = i;
+
+ SU_DEBUG_5(("%s(%p, %p) id=%u %s %s (to [%s]:%u)\n",
+ "sres_send_dns_query",
+ res, q, id, sres_record_type(type, b), domain,
+ dns->dns_name,
+ htons(((struct sockaddr_in *)dns->dns_addr)->sin_port)));
+
+ return 0;
+}
+
+
+/** Select next server */
+static
+sres_server_t *sres_next_server(sres_resolver_t *res,
+ uint8_t *in_out_i,
+ int timeout)
+{
+ int i, j, N;
+ sres_server_t **servers;
+
+ assert(res && in_out_i);
+
+ N = res->res_n_servers;
+ servers = res->res_servers;
+ i = *in_out_i;
+
+ assert(res->res_servers && res->res_servers[i]);
+
+ /* Retry using another server? */
+ for (j = (i + 1) % N; (j != i); j = (j + 1) % N) {
+ if (servers[j]->dns_icmp == 0) {
+ return *in_out_i = j, servers[j];
+ }
+ }
+
+ for (j = (i + 1) % N; (j != i); j = (j + 1) % N) {
+ if (servers[j]->dns_error == 0) {
+ return *in_out_i = j, servers[j];
+ }
+ }
+
+ if (timeout)
+ return servers[i];
+
+ return NULL;
+}
+
+/**
+ * Callback function for subqueries
+ */
+static
+void sres_answer_subquery(sres_context_t *context,
+ sres_query_t *query,
+ sres_record_t **answers)
+{
+ sres_resolver_t *res;
+ sres_query_t *top = (sres_query_t *)context;
+ int i;
+ assert(top); assert(top->q_n_subs > 0); assert(query);
+
+ res = query->q_res;
+
+ for (i = 0; i <= SRES_MAX_SEARCH; i++) {
+ if (top->q_subqueries[i] == query)
+ break;
+ }
+ assert(i <= SRES_MAX_SEARCH);
+ if (i > SRES_MAX_SEARCH || top->q_n_subs == 0) {
+ sres_free_answers(res, answers);
+ return;
+ }
+
+ if (answers) {
+ int j, k;
+ for (j = 0, k = 0; answers[j]; j++) {
+ if (answers[j]->sr_status)
+ sres_free_answer(query->q_res, answers[j]);
+ else
+ answers[k++] = answers[j];
+ }
+ answers[k] = NULL;
+ if (!answers[0])
+ sres_free_answers(query->q_res, answers), answers = NULL;
+ }
+
+ top->q_subqueries[i] = NULL;
+ top->q_subanswers[i] = answers;
+ top->q_n_subs--;
+
+ if (answers && top->q_callback) {
+ sres_answer_f *callback = top->q_callback;
+
+ top->q_callback = NULL;
+ sres_remove_query(top->q_res, top, 1);
+ callback(top->q_context, top, answers);
+ }
+ else if (top->q_n_subs == 0 && top->q_id == 0) {
+ sres_query_report_error(top, NULL);
+ };
+}
+
+/** Report sres error */
+static void
+sres_query_report_error(sres_query_t *q,
+ sres_record_t **answers)
+{
+ int i;
+
+ if (q->q_callback) {
+ for (i = 0; i <= SRES_MAX_SEARCH; i++) {
+ if (q->q_subqueries[i]) /* a pending query... */
+ return;
+
+ if (q->q_subanswers[i]) {
+ answers = q->q_subanswers[i];
+ q->q_subanswers[i] = NULL;
+ break;
+ }
+ }
+
+ SU_DEBUG_5(("sres(q=%p): reporting errors for %u %s\n",
+ q, q->q_type, q->q_name));
+
+ sres_remove_query(q->q_res, q, 1);
+ (q->q_callback)(q->q_context, q, answers);
+ }
+
+ sres_free_query(q->q_res, q);
+}
+
+/** Resolver timer function.
+ *
+ * The function sresolver_timer() should be called in regular intervals. We
+ * recommend calling it in 500 ms intervals.
+ *
+ * @param res pointer to resolver object
+ * @param dummy argument for compatibility
+ */
+void sres_resolver_timer(sres_resolver_t *res, int dummy)
+{
+ size_t i;
+ sres_query_t *q;
+ time_t now, retry_time;
+
+ if (res == NULL)
+ return;
+
+ now = time(&res->res_now);
+
+ if (res->res_queries->qt_used) {
+ SU_DEBUG_9(("sres_resolver_timer() called at %lu\n", (long) now));
+
+ /** Every time it is called it goes through all query structures, and
+ * retransmits all the query messages, which have not been answered yet.
+ */
+ for (i = 0; i < res->res_queries->qt_size; i++) {
+ q = res->res_queries->qt_table[i];
+
+ if (!q)
+ continue;
+
+ /* Exponential backoff */
+ retry_time = q->q_timestamp + ((time_t)1 << q->q_retry_count);
+
+ if (now < retry_time)
+ continue;
+
+ sres_resend_dns_query(res, q, 1);
+
+ if (q != res->res_queries->qt_table[i])
+ i--;
+ }
+
+ if (res->res_schedulecb && res->res_queries->qt_used)
+ res->res_schedulecb(res->res_async, SRES_RETRANSMIT_INTERVAL);
+ }
+
+ sres_cache_clean(res->res_cache, res->res_now);
+}
+
+/** Resend DNS query, report error if cannot resend any more. */
+static void
+sres_resend_dns_query(sres_resolver_t *res, sres_query_t *q, int timeout)
+{
+ uint8_t i, N;
+ sres_server_t *dns;
+
+ SU_DEBUG_9(("sres_resend_dns_query(%p, %p, %u) called\n",
+ res, q, timeout));
+
+ N = res->res_n_servers;
+
+ if (N > 0 && q->q_retry_count < SRES_MAX_RETRY_COUNT) {
+ i = q->q_i_server;
+ dns = sres_next_server(res, &i, timeout);
+
+ if (dns) {
+ res->res_i_server = q->q_i_server = i;
+
+ if (q->q_retry_count > res->res_n_servers + 1 &&
+ dns->dns_edns == edns_not_tried)
+ q->q_edns = edns_not_supported;
+
+ sres_send_dns_query(res, q);
+
+ if (timeout)
+ q->q_retry_count++;
+
+ return;
+ }
+ }
+
+ /* report timeout/network error */
+ q->q_id = 0;
+
+ if (q->q_n_subs)
+ return; /* let subqueries also timeout */
+
+ sres_query_report_error(q, NULL);
+}
+
+
+/** Get a server by socket */
+static
+sres_server_t *
+sres_server_by_socket(sres_resolver_t const *res, sres_socket_t socket)
+{
+ int i;
+
+ if (socket == -1)
+ return NULL;
+
+ for (i = 0; i < res->res_n_servers; i++) {
+ if (socket == res->res_servers[i]->dns_socket)
+ return res->res_servers[i];
+ }
+
+ return NULL;
+}
+
+static
+void
+sres_canonize_sockaddr(struct sockaddr_storage *from, socklen_t *fromlen)
+{
+#if HAVE_SIN6
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)from;
+
+ size_t sin6_addrsize =
+ offsetof(struct sockaddr_in6, sin6_addr) +
+ (sizeof sin6->sin6_addr);
+
+ if (from->ss_family == AF_INET6) {
+ struct in6_addr const *ip6 = &sin6->sin6_addr;
+
+ if (IN6_IS_ADDR_V4MAPPED(ip6) || IN6_IS_ADDR_V4COMPAT(ip6)) {
+ /* Convert to a IPv4 address */
+ struct sockaddr_in *sin = (struct sockaddr_in *)from;
+ memcpy(&sin->sin_addr, ip6->s6_addr + 12, sizeof sin->sin_addr);
+ sin->sin_family = AF_INET;
+ *fromlen = sizeof (*sin);
+#if HAVE_SA_LEN
+ sin->sin_len = sizeof (*sin);
+#endif
+ }
+ else if (sin6_addrsize < *fromlen) {
+ /* Zero extra sin6 members like sin6_flowinfo or sin6_scope_id */
+ memset((char *)from + sin6_addrsize, 0, *fromlen - sin6_addrsize);
+ }
+ }
+#endif
+
+ if (from->ss_family == AF_INET) {
+ struct sockaddr_in *sin = (struct sockaddr_in *)from;
+ memset(sin->sin_zero, 0, sizeof (sin->sin_zero));
+ }
+}
+
+#if HAVE_IP_RECVERR || HAVE_IPV6_RECVERR
+#include <linux/types.h>
+#include <linux/errqueue.h>
+#include <sys/uio.h>
+#endif
+
+static
+int sres_no_update(sres_async_t *async,
+ sres_socket_t new_socket,
+ sres_socket_t old_socket)
+{
+ return 0;
+}
+
+/** Create connected sockets for resolver.
+ */
+int sres_resolver_sockets(sres_resolver_t *res,
+ sres_socket_t *return_sockets,
+ int n)
+{
+ sres_socket_t s = INVALID_SOCKET;
+ int i, retval;
+
+ if (!sres_resolver_set_async(res, sres_no_update,
+ (sres_async_t *)-1, 1))
+ return -1;
+
+ retval = res->res_n_servers; assert(retval <= SRES_MAX_NAMESERVERS);
+
+ if (!return_sockets || n == 0)
+ return retval;
+
+ for (i = 0; i < retval && i < n;) {
+ sres_server_t *dns = res->res_servers[i];
+
+ s = sres_server_socket(res, dns);
+
+ return_sockets[i++] = s;
+ }
+
+ return retval;
+}
+
+#if 0
+/** Get a server by socket address */
+static
+sres_server_t *
+sres_server_by_sockaddr(sres_resolver_t const *res,
+ void const *from, socklen_t fromlen)
+{
+ int i;
+
+ for (i = 0; i < res->res_n_servers; i++) {
+ sres_server_t *dns = res->res_servers[i];
+ if (dns->dns_addrlen == fromlen &&
+ memcmp(dns->dns_addr, from, fromlen) == 0)
+ return dns;
+ }
+
+ return NULL;
+}
+#endif
+
+/** Receive error message from socket. */
+#if HAVE_IP_RECVERR || HAVE_IPV6_RECVERR
+int sres_resolver_error(sres_resolver_t *res, int socket)
+{
+ int errcode = 0;
+ struct cmsghdr *c;
+ struct sock_extended_err *ee;
+ struct sockaddr_storage *from;
+ char control[512];
+ char errmsg[64 + 768];
+ struct iovec iov[1];
+ struct msghdr msg[1] = {{ 0 }};
+ struct sockaddr_storage name[1] = {{ 0 }};
+ int n;
+ char info[128] = "";
+
+ SU_DEBUG_9(("%s(%p, %u) called\n", "sres_resolver_error", res, socket));
+
+ msg->msg_name = name, msg->msg_namelen = sizeof(name);
+ msg->msg_iov = iov, msg->msg_iovlen = 1;
+ iov->iov_base = errmsg, iov->iov_len = sizeof(errmsg);
+ msg->msg_control = control, msg->msg_controllen = sizeof(control);
+
+ n = recvmsg(socket, msg, MSG_ERRQUEUE);
+
+ if (n < 0) {
+ int error = su_errno();
+ if (error != EAGAIN && error != EWOULDBLOCK)
+ SU_DEBUG_1(("%s: recvmsg: %s\n", __func__, su_strerror(error)));
+ return n;
+ }
+
+ if ((msg->msg_flags & MSG_ERRQUEUE) != MSG_ERRQUEUE) {
+ SU_DEBUG_1(("%s: recvmsg: no errqueue\n", __func__));
+ return su_seterrno(EIO);
+ }
+
+ if (msg->msg_flags & MSG_CTRUNC) {
+ SU_DEBUG_1(("%s: extended error was truncated\n", __func__));
+ return su_seterrno(EIO);
+ }
+
+ if (msg->msg_flags & MSG_TRUNC) {
+ /* ICMP message may contain original message... */
+ SU_DEBUG_5(("%s: icmp(6) message was truncated (at %d)\n", __func__, n));
+ }
+
+ /* Go through the ancillary data */
+ for (c = CMSG_FIRSTHDR(msg); c; c = CMSG_NXTHDR(msg, c)) {
+ if (0
+#if HAVE_IP_RECVERR
+ || (c->cmsg_level == SOL_IP && c->cmsg_type == IP_RECVERR)
+#endif
+#if HAVE_IPV6_RECVERR
+ || (c->cmsg_level == SOL_IPV6 && c->cmsg_type == IPV6_RECVERR)
+#endif
+ ) {
+ char const *origin;
+
+ ee = (struct sock_extended_err *)CMSG_DATA(c);
+ from = (void *)SO_EE_OFFENDER(ee);
+ info[0] = '\0';
+
+ switch (ee->ee_origin) {
+ case SO_EE_ORIGIN_LOCAL:
+ strcpy(info, origin = "local");
+ break;
+ case SO_EE_ORIGIN_ICMP:
+ snprintf(info, sizeof(info), "%s type=%u code=%u",
+ origin = "icmp", ee->ee_type, ee->ee_code);
+ break;
+ case SO_EE_ORIGIN_ICMP6:
+ snprintf(info, sizeof(info), "%s type=%u code=%u",
+ origin = "icmp6", ee->ee_type, ee->ee_code);
+ break;
+ case SO_EE_ORIGIN_NONE:
+ strcpy(info, origin = "none");
+ break;
+ default:
+ strcpy(info, origin = "unknown");
+ break;
+ }
+
+ if (ee->ee_info)
+ snprintf(info + strlen(info), sizeof(info) - strlen(info),
+ " info=%08x", ee->ee_info);
+ errcode = ee->ee_errno;
+
+ if (from->ss_family != AF_UNSPEC) {
+ socklen_t fromlen = ((char *)c + c->cmsg_len) - (char *)from;
+
+ sres_canonize_sockaddr(from, &fromlen);
+
+ snprintf(info + strlen(info), sizeof(info) - strlen(info),
+ " reported by ");
+ inet_ntop(from->ss_family, SS_ADDR(from),
+ info + strlen(info), sizeof(info) - strlen(info));
+ }
+
+ if (msg->msg_namelen <= 0)
+ break;
+
+ {
+ int error;
+ socklen_t errorlen = sizeof error;
+ /* Get error, if any */
+ getsockopt(socket, SOL_SOCKET, SO_ERROR, (void *)&error, &errorlen);
+ }
+
+ if (sres_resolver_report_error(res, socket, errcode,
+ msg->msg_name, msg->msg_namelen,
+ info))
+ return errcode;
+ break;
+ }
+ }
+
+ if (errcode)
+ sres_resolver_report_error(res, socket, errcode, NULL, 0, info);
+
+ return errcode;
+}
+
+#else
+int sres_resolver_error(sres_resolver_t *res, int socket)
+{
+ int errcode = 0;
+ socklen_t errorlen = sizeof(errcode);
+
+ SU_DEBUG_9(("%s(%p, %u) called\n", "sres_resolver_error", res, socket));
+
+ getsockopt(socket, SOL_SOCKET, SO_ERROR, (void *)&errcode, &errorlen);
+
+ return sres_resolver_report_error(res, socket, errcode, NULL, 0, "");
+}
+#endif
+
+
+/** Report error */
+static
+int
+sres_resolver_report_error(sres_resolver_t *res,
+ sres_socket_t socket,
+ int errcode,
+ struct sockaddr_storage *remote,
+ socklen_t remotelen,
+ char const *info)
+{
+ char buf[80];
+
+ buf[0] = '\0';
+
+ if (remote) {
+ sres_canonize_sockaddr(remote, &remotelen);
+
+ if (remote->ss_family == AF_INET) {
+ struct sockaddr_in const *sin = (struct sockaddr_in *)remote;
+ uint8_t const *in_addr = (uint8_t*)&sin->sin_addr;
+ inet_ntop(AF_INET, in_addr, buf, sizeof(buf));
+ }
+#if HAVE_SIN6
+ else if (remote->ss_family == AF_INET6) {
+ struct sockaddr_in6 const *sin6 = (struct sockaddr_in6 *)remote;
+ uint8_t const *in_addr = (uint8_t*)&sin6->sin6_addr;
+ inet_ntop(AF_INET6, in_addr, buf, sizeof(buf));
+ }
+#endif
+ }
+
+ SU_DEBUG_5(("sres: network error %u (%s)%s%s%s%s\n",
+ errcode, su_strerror(errcode),
+ buf[0] ? " from " : "", buf,
+ info ? " by " : "",
+ info ? info : ""));
+
+ if (res->res_queries->qt_used) {
+ /* Report error to queries */
+ sres_server_t *dns;
+ sres_query_t *q;
+ size_t i;
+
+ dns = sres_server_by_socket(res, socket);
+
+ if (dns) {
+ time(&res->res_now);
+ dns->dns_icmp = res->res_now;
+
+ for (i = 0; i < res->res_queries->qt_size; i++) {
+ q = res->res_queries->qt_table[i];
+
+ if (!q || dns != res->res_servers[q->q_i_server])
+ continue;
+
+ /* Resend query/report error to application */
+ sres_resend_dns_query(res, q, 1);
+
+ if (q != res->res_queries->qt_table[i])
+ i--;
+ }
+ }
+ }
+
+ return 1;
+}
+
+
+/** Receive a response packet from socket. */
+int
+sres_resolver_receive(sres_resolver_t *res, int socket)
+{
+ ssize_t num_bytes;
+ int error;
+ sres_message_t m[1];
+
+ sres_query_t *query = NULL;
+ sres_record_t **reply;
+ sres_server_t *dns;
+
+ struct sockaddr_storage from[1];
+ socklen_t fromlen = sizeof from;
+
+ SU_DEBUG_9(("%s(%p, %u) called\n", "sres_resolver_receive", res, socket));
+
+ memset(m, 0, offsetof(sres_message_t, m_data));
+
+ num_bytes = sres_recvfrom(socket, m->m_data, sizeof (m->m_data), 0,
+ (void *)from, &fromlen);
+
+ if (num_bytes <= 0) {
+ SU_DEBUG_5(("%s: %s\n", "sres_resolver_receive", su_strerror(su_errno())));
+ return 0;
+ }
+
+ if (num_bytes > 65535)
+ num_bytes = 65535;
+
+ dns = sres_server_by_socket(res, socket);
+ if (!dns)
+ return 0;
+
+ m->m_size = (uint16_t)num_bytes;
+
+ /* Decode the received message and get the matching query object */
+ error = sres_decode_msg(res, m, &query, &reply);
+
+ sres_log_response(res, m, from, query, reply);
+
+ if (query == NULL)
+ ;
+ else if (error == SRES_EDNS0_ERR) {
+ dns->dns_edns = edns_not_supported;
+ assert(query->q_id);
+ sres_remove_query(res, query, 0);
+ query->q_id = sres_new_id(res);
+ query->q_hash = query->q_id * Q_PRIME;
+ sres_qtable_append(res->res_queries, query);
+ sres_send_dns_query(res, query);
+ query->q_retry_count++;
+ }
+ else if (!error && reply) {
+ /* Remove the query from the pending list and notify the listener */
+ sres_remove_query(res, query, 1);
+ if (query->q_callback != NULL)
+ (query->q_callback)(query->q_context, query, reply);
+ sres_free_query(res, query);
+ }
+ else {
+ sres_query_report_error(query, reply);
+ }
+
+ return 1;
+}
+
+static
+void sres_log_response(sres_resolver_t const *res,
+ sres_message_t const *m,
+ struct sockaddr_storage const *from,
+ sres_query_t const *query,
+ sres_record_t * const *reply)
+{
+ if (SU_LOG->log_level >= 5) {
+#ifndef ADDRSIZE
+#define ADDRSIZE 48
+#endif
+ char host[ADDRSIZE] = "*";
+
+ if (from == NULL)
+ ;
+ else if (from->ss_family == AF_INET) {
+ struct sockaddr_in const *sin = (void *)from;
+ inet_ntop(AF_INET, &sin->sin_addr, host, sizeof host);
+ }
+#if HAVE_SIN6
+ else if (from->ss_family == AF_INET6) {
+ struct sockaddr_in6 const *sin6 = (void *)from;
+ inet_ntop(AF_INET6, &sin6->sin6_addr, host, sizeof host);
+ }
+#endif
+
+ SU_DEBUG_5(("sres_resolver_receive(%p, %p) id=%u (from [%s]:%u)\n",
+ res, query, m->m_id,
+ host, ntohs(((struct sockaddr_in *)from)->sin_port)));
+ }
+}
+
+/** Decode DNS message.
+ *
+ *
+ * @retval 0 if successful
+ * @retval >0 if message indicated error
+ * @retval -1 if decoding error
+ */
+static
+int
+sres_decode_msg(sres_resolver_t *res,
+ sres_message_t *m,
+ sres_query_t **qq,
+ sres_record_t ***return_answers)
+{
+ sres_record_t *rr = NULL, **answers = NULL, *error = NULL;
+ sres_query_t *query = NULL, **hq;
+ su_home_t *chome = CHOME(res->res_cache);
+ hash_value_t hash;
+ int err;
+ unsigned i, total, errorcount = 0;
+
+ assert(res && m && return_answers);
+
+ time(&res->res_now);
+
+ *qq = NULL;
+ *return_answers = NULL;
+
+ m->m_offset = sizeof(m->m_packet.mp_header);
+
+ if (m->m_size < m->m_offset) {
+ SU_DEBUG_5(("sres_decode_msg: truncated message\n"));
+ return -1;
+ }
+
+ m->m_flags = ntohs(m->m_flags);
+ m->m_qdcount = ntohs(m->m_qdcount);
+ m->m_ancount = ntohs(m->m_ancount);
+ m->m_nscount = ntohs(m->m_nscount);
+ m->m_arcount = ntohs(m->m_arcount);
+
+ hash = Q_PRIME * m->m_id;
+
+ /* Search for query with this ID */
+ for (hq = sres_qtable_hash(res->res_queries, hash);
+ *hq;
+ hq = sres_qtable_next(res->res_queries, hq))
+ if (hash == (*hq)->q_hash)
+ break;
+
+ *qq = query = *hq;
+
+ if (!query) {
+ SU_DEBUG_5(("sres_decode_msg: matching query for id=%u\n", m->m_id));
+ return -1;
+ }
+
+ assert(query && m->m_id == query->q_id);
+
+ if ((m->m_flags & 15) == SRES_FORMAT_ERR && query->q_edns)
+ return SRES_EDNS0_ERR;
+
+ /* Scan question section */
+ for (i = 0; i < m->m_qdcount; i++) {
+ char name[1024];
+ uint16_t qtype, qclass;
+ m_get_domain(name, sizeof(name), m, 0); /* Query domain */
+ qtype = m_get_uint16(m); /* Query type */
+ qclass = m_get_uint16(m); /* Query class */
+ }
+
+ if (m->m_error) {
+ SU_DEBUG_5(("sres_decode_msg: %s\n", m->m_error));
+ return -1;
+ }
+
+ err = m->m_flags & SRES_HDR_RCODE;
+
+ if (m->m_ancount == 0 && err == 0)
+ err = SRES_RECORD_ERR;
+
+ if (err == SRES_RECORD_ERR ||
+ err == SRES_NAME_ERR ||
+ err == SRES_UNIMPL_ERR)
+ errorcount = 1;
+
+ total = errorcount + m->m_ancount + m->m_nscount + m->m_arcount;
+
+ answers = su_zalloc(chome, (total + 1) * sizeof answers[0]);
+ if (!answers)
+ return -1;
+
+ /* Scan resource records */
+ for (i = 0; i < total; i++) {
+ if (i < errorcount)
+ rr = error = sres_create_error_rr(res->res_cache, query, err);
+ else
+ rr = sres_create_record(res, m);
+
+ if (!rr) {
+ SU_DEBUG_5(("sres_create_record: %s\n", m->m_error));
+ break;
+ }
+
+ if (error && rr->sr_type == sres_type_soa) {
+ sres_soa_record_t *soa = (sres_soa_record_t *)rr;
+ if (error->sr_ttl > soa->soa_minimum && soa->soa_minimum > 10)
+ error->sr_ttl = soa->soa_minimum;
+ }
+
+ answers[i] = rr;
+ }
+
+ if (i < total) {
+ for (i = 0; i < total; i++)
+ sres_cache_free_record(res->res_cache, answers[i]);
+ su_free(chome, answers);
+ return -1;
+ }
+
+ for (i = 0; i < total; i++) {
+ rr = answers[i];
+
+ if (i < m->m_ancount + errorcount)
+ /* Increase reference count of entry passed in answers */
+ rr->sr_refcount++;
+ else
+ /* Do not pass extra records to user */
+ answers[i] = NULL;
+
+ sres_cache_store(res->res_cache, rr, res->res_now);
+ }
+
+ *return_answers = answers;
+
+ return err;
+}
+
+static
+sres_record_t *
+sres_create_record(sres_resolver_t *res, sres_message_t *m)
+{
+ sres_cache_t *cache = res->res_cache;
+ sres_record_t *sr, sr0[1];
+
+ uint16_t m_size;
+ char name[1025];
+ int len;
+ char btype[8], bclass[8];
+
+ sr = memset(sr0, 0, sizeof sr0);
+
+ len = m_get_domain(sr->sr_name = name, sizeof(name) - 1, m, 0); /* Name */
+ sr->sr_type = m_get_uint16(m); /* Type */
+ sr->sr_class = m_get_uint16(m); /* Class */
+ sr->sr_ttl = m_get_uint32(m); /* TTL */
+ sr->sr_rdlen = m_get_uint16(m); /* rdlength */
+ sr->sr_parsed = 1;
+ if (m->m_error)
+ goto error;
+
+ name[len] = 0;
+
+ SU_DEBUG_9(("RR received %s %s %s %d rdlen=%d\n", name,
+ sres_record_type(sr->sr_type, btype),
+ sres_record_class(sr->sr_class, bclass),
+ sr->sr_ttl, sr->sr_rdlen));
+
+ if (m->m_offset + sr->sr_rdlen > m->m_size) {
+ m->m_error = "truncated message";
+ goto error;
+ }
+
+ m_size = m->m_size;
+ /* limit m_size to indicated rdlen, check whether record is truncated */
+ m->m_size = m->m_offset + sr->sr_rdlen;
+
+ switch (sr->sr_type) {
+ case sres_type_soa:
+ sr = sres_init_rr_soa(cache, sr->sr_soa, m);
+ break;
+ case sres_type_a:
+ sr = sres_init_rr_a(cache, sr->sr_a, m);
+ break;
+ case sres_type_a6:
+ sr = sres_init_rr_a6(cache, sr->sr_a6, m);
+ break;
+ case sres_type_aaaa:
+ sr = sres_init_rr_aaaa(cache, sr->sr_aaaa, m);
+ break;
+ case sres_type_cname:
+ sr = sres_init_rr_cname(cache, sr->sr_cname, m);
+ break;
+ case sres_type_ptr:
+ sr = sres_init_rr_ptr(cache, sr->sr_ptr, m);
+ break;
+ case sres_type_srv:
+ sr = sres_init_rr_srv(cache, sr->sr_srv, m);
+ break;
+ case sres_type_naptr:
+ sr = sres_init_rr_naptr(cache, sr->sr_naptr, m);
+ break;
+ default:
+ sr = sres_init_rr_unknown(cache, sr->sr_record, m);
+ break;
+ }
+
+ if (m->m_error)
+ goto error;
+
+ if (sr == sr0)
+ sr = sres_cache_alloc_record(cache, sr, 0);
+
+ if (sr == NULL) {
+ m->m_error = "memory exhausted";
+ goto error;
+ }
+
+ /* Fill in the common fields */
+ m->m_size = m_size;
+
+ return sr;
+
+ error:
+ if (sr && sr != sr0)
+ sres_cache_free_record(cache, sr);
+ SU_DEBUG_5(("%s: %s\n", "sres_create_record", m->m_error));
+ return NULL;
+}
+
+/** Decode SOA record */
+static sres_record_t *sres_init_rr_soa(sres_cache_t *cache,
+ sres_soa_record_t *soa,
+ sres_message_t *m)
+{
+ uint16_t moffset, roffset;
+ int mnamelen, rnamelen;
+
+ soa->soa_record->r_size = sizeof *soa;
+
+ moffset = m->m_offset, mnamelen = m_get_domain(NULL, 0, m, 0) + 1;
+ roffset = m->m_offset, rnamelen = m_get_domain(NULL, 0, m, 0) + 1;
+
+ soa->soa_serial = m_get_uint32(m);
+ soa->soa_refresh = m_get_uint32(m);
+ soa->soa_retry = m_get_uint32(m);
+ soa->soa_expire = m_get_uint32(m);
+ soa->soa_minimum = m_get_uint32(m);
+
+ if (m->m_error)
+ return NULL;
+
+ soa = (void *)sres_cache_alloc_record(cache, (void *)soa,
+ mnamelen + rnamelen);
+
+ if (soa) {
+ char *mname, *rname;
+
+ assert(moffset > 0 && roffset > 0 && mnamelen > 1 && rnamelen > 1);
+
+ m_get_domain(mname = (char *)(soa + 1), mnamelen, m, moffset);
+ soa->soa_mname = mname;
+
+ m_get_domain(rname = mname + mnamelen, rnamelen, m, roffset);
+ soa->soa_rname = rname;
+ }
+
+ return (sres_record_t *)soa;
+}
+
+/** Decode A record */
+static sres_record_t *sres_init_rr_a(sres_cache_t *cache,
+ sres_a_record_t *a,
+ sres_message_t *m)
+{
+ a->a_record->r_size = sizeof *a;
+
+ a->a_addr.s_addr = htonl(m_get_uint32(m));
+
+ return (sres_record_t *)a;
+}
+
+/** Decode A6 record. See @RFC2874 */
+static sres_record_t *sres_init_rr_a6(sres_cache_t *cache,
+ sres_a6_record_t *a6,
+ sres_message_t *m)
+{
+
+ int suffixlen = 0, i;
+ int prefixlen = 0;
+ uint16_t offset;
+
+ a6->a6_record->r_size = sizeof *a6;
+
+ a6->a6_prelen = m_get_uint8(m);
+
+ if (a6->a6_prelen > 128) {
+ m->m_error = "Invalid prefix length in A6 record";
+ return NULL;
+ }
+
+ suffixlen = (128 + 7 - a6->a6_prelen) / 8;
+ for (i = 16 - suffixlen; i < 16; i++)
+ a6->a6_suffix.u6_addr[i] = m_get_uint8(m);
+
+ if (a6->a6_prelen > 0) {
+ /* Zero pad bits */
+ a6->a6_suffix.u6_addr[16 - suffixlen] &= 0xff >> (a6->a6_prelen & 7);
+
+ offset = m->m_offset, prefixlen = m_get_domain(NULL, 0, m, 0) + 1;
+
+ if (m->m_error)
+ return NULL;
+
+ a6 = (void *)sres_cache_alloc_record(cache, (void *)a6, prefixlen);
+ if (a6)
+ m_get_domain(a6->a6_prename = (char *)(a6 + 1), prefixlen, m, offset);
+ }
+
+ return (sres_record_t *)a6;
+}
+
+/** Decode AAAA record */
+static sres_record_t *sres_init_rr_aaaa(sres_cache_t *cache,
+ sres_aaaa_record_t *aaaa,
+ sres_message_t *m)
+{
+ aaaa->aaaa_record->r_size = sizeof *aaaa;
+
+ if (m->m_offset + sizeof(aaaa->aaaa_addr) <= m->m_size) {
+ memcpy(&aaaa->aaaa_addr, m->m_data + m->m_offset, sizeof(aaaa->aaaa_addr));
+ m->m_offset += sizeof(aaaa->aaaa_addr);
+ }
+ else
+ m->m_error = "truncated AAAA record";
+
+ return (sres_record_t *)aaaa;
+}
+
+/** Decode CNAME record */
+static sres_record_t *sres_init_rr_cname(sres_cache_t *cache,
+ sres_cname_record_t *cn,
+ sres_message_t *m)
+{
+ uint16_t offset;
+ int dlen;
+
+ cn->cn_record->r_size = sizeof *cn;
+
+ offset = m->m_offset, dlen = m_get_domain(NULL, 0, m, 0) + 1;
+
+ if (m->m_error)
+ return NULL;
+
+ cn = (void *)sres_cache_alloc_record(cache, (void *)cn, dlen);
+ if (cn)
+ m_get_domain(cn->cn_cname = (char *)(cn + 1), dlen, m, offset);
+
+ return (sres_record_t *)cn;
+}
+
+/** Decode PTR record */
+static sres_record_t *sres_init_rr_ptr(sres_cache_t *cache,
+ sres_ptr_record_t *ptr,
+ sres_message_t *m)
+{
+ uint16_t offset;
+ int dlen;
+
+ ptr->ptr_record->r_size = sizeof *ptr;
+
+ offset = m->m_offset, dlen = m_get_domain(NULL, 0, m, 0) + 1;
+
+ if (m->m_error)
+ return NULL;
+
+ ptr = (void *)sres_cache_alloc_record(cache, (void *)ptr, dlen);
+ if (ptr)
+ m_get_domain(ptr->ptr_domain = (char *)(ptr + 1), dlen, m, offset);
+
+ return (sres_record_t *)ptr;
+}
+
+/** Decode SRV record */
+static sres_record_t *sres_init_rr_srv(sres_cache_t *cache,
+ sres_srv_record_t *srv,
+ sres_message_t *m)
+{
+ uint16_t offset;
+ int dlen;
+
+ srv->srv_record->r_size = sizeof *srv;
+
+ srv->srv_priority = m_get_uint16(m);
+ srv->srv_weight = m_get_uint16(m);
+ srv->srv_port = m_get_uint16(m);
+ offset = m->m_offset, dlen = m_get_domain(NULL, 0, m, 0) + 1;
+ if (m->m_error)
+ return NULL;
+
+ srv = (void *)sres_cache_alloc_record(cache, (void *)srv, dlen);
+ if (srv)
+ m_get_domain(srv->srv_target = (char *)(srv + 1), dlen, m, offset);
+
+ return (sres_record_t *)srv;
+}
+
+/** Decode NAPTR record */
+static sres_record_t *sres_init_rr_naptr(sres_cache_t *cache,
+ sres_naptr_record_t *na,
+ sres_message_t *m)
+{
+ uint16_t offset[4];
+ int len[4];
+
+ na->na_record->r_size = sizeof *na;
+
+ na->na_order = m_get_uint16(m);
+ na->na_prefer = m_get_uint16(m);
+
+ offset[0] = m->m_offset, len[0] = m_get_string(NULL, 0, m, 0) + 1;
+ offset[1] = m->m_offset, len[1] = m_get_string(NULL, 0, m, 0) + 1;
+ offset[2] = m->m_offset, len[2] = m_get_string(NULL, 0, m, 0) + 1;
+ offset[3] = m->m_offset, len[3] = m_get_domain(NULL, 0, m, 0) + 1;
+
+ if (m->m_error)
+ return NULL;
+
+ na = (void *)sres_cache_alloc_record(cache, (void *)na,
+ len[0] + len[1] + len[2] + len[3]);
+ if (na) {
+ char *s = (char *)(na + 1);
+ m_get_string(na->na_flags = s, len[0], m, offset[0]), s += len[0];
+ m_get_string(na->na_services = s, len[1], m, offset[1]), s += len[1];
+ m_get_string(na->na_regexp = s, len[2], m, offset[2]), s += len[2];
+ m_get_domain(na->na_replace = s, len[3], m, offset[3]), s += len[3];
+ }
+
+ return (sres_record_t *)na;
+}
+
+/** Decode unknown record */
+static sres_record_t *sres_init_rr_unknown(sres_cache_t *cache,
+ sres_common_t *r,
+ sres_message_t *m)
+{
+ if (m->m_offset + r->r_rdlen > m->m_size)
+ m->m_error = "truncated record";
+
+ if (m->m_error)
+ return NULL;
+
+ r->r_size = sizeof *r;
+
+ r = (void *)sres_cache_alloc_record(cache, (void *)r, r->r_rdlen + 1);
+ if (r) {
+ char *data = (char *)(r + 1);
+
+ r->r_parsed = 0;
+
+ memcpy(data, m->m_data + m->m_offset, r->r_rdlen);
+ m->m_offset += r->r_rdlen;
+ data[r->r_rdlen] = 0;
+ }
+
+ return (sres_record_t *)r;
+}
+
+static
+sres_record_t *sres_create_error_rr(sres_cache_t *cache,
+ sres_query_t const *q,
+ uint16_t errcode)
+{
+ sres_record_t *sr, r[1];
+ char buf[SRES_MAXDNAME];
+
+ sr = memset(r, 0, sizeof *sr);
+
+ sr->sr_name = (char *)sres_toplevel(buf, sizeof buf, q->q_name);
+ sr->sr_size = sizeof *sr;
+ sr->sr_status = errcode;
+ sr->sr_type = q->q_type;
+ sr->sr_class = q->q_class;
+ sr->sr_ttl = 10 * 60;
+
+ return sres_cache_alloc_record(cache, sr, 0);
+}
+
+/* Message processing primitives */
+
+static
+void
+m_put_uint16(sres_message_t *m,
+ uint16_t h)
+{
+ uint8_t *p;
+
+ if (m->m_error)
+ return;
+
+ p = m->m_data + m->m_offset;
+ m->m_offset += sizeof h;
+
+ if (m->m_offset > m->m_size) {
+ m->m_error = "message size overflow";
+ return;
+ }
+
+ p[0] = h >> 8; p[1] = h;
+}
+
+static
+void
+m_put_uint32(sres_message_t *m,
+ uint32_t w)
+{
+ uint8_t *p;
+
+ if (m->m_error)
+ return;
+
+ p = m->m_data + m->m_offset;
+ m->m_offset += sizeof w;
+
+ if (m->m_offset > m->m_size) {
+ m->m_error = "message size overflow";
+ return;
+ }
+
+ p[0] = w >> 24; p[1] = w >> 16; p[2] = w >> 8; p[3] = w;
+}
+
+/*
+ * Put domain into query
+ */
+static
+uint16_t
+m_put_domain(sres_message_t *m,
+ char const *domain,
+ uint16_t top,
+ char const *topdomain)
+{
+ char const *label;
+ size_t llen;
+
+ if (m->m_error)
+ return top;
+
+ /* Copy domain into query label at a time */
+ for (label = domain; label && label[0]; label += llen) {
+ if (label[0] == '.' && label[1] != '\0') {
+ m->m_error = "empty label";
+ return 0;
+ }
+
+ llen = strcspn(label, ".");
+
+ if (llen >= 64) {
+ m->m_error = "too long label";
+ return 0;
+ }
+ if (m->m_offset + llen + 1 > m->m_size) {
+ m->m_error = "message size overflow";
+ return 0;
+ }
+
+ m->m_data[m->m_offset++] = (uint8_t)llen;
+ memcpy(m->m_data + m->m_offset, label, llen);
+ m->m_offset += (uint8_t)llen;
+
+ if (label[llen] == '\0')
+ break;
+ if (llen == 0)
+ return top;
+ if (label[llen + 1])
+ llen++;
+ }
+
+ if (top) {
+ m_put_uint16(m, 0xc000 | top);
+ return top;
+ }
+ else if (topdomain) {
+ uint16_t retval = m->m_offset;
+ m_put_domain(m, topdomain, 0, NULL);
+ return retval;
+ }
+ else if (m->m_offset < m->m_size)
+ m->m_data[m->m_offset++] = '\0';
+ else
+ m->m_error = "message size overflow";
+
+ return 0;
+}
+
+static
+uint32_t
+m_get_uint32(sres_message_t *m)
+{
+ uint8_t const *p = m->m_data + m->m_offset;
+
+ if (m->m_error)
+ return 0;
+
+ m->m_offset += 4;
+
+ if (m->m_offset > m->m_size) {
+ m->m_error = "truncated message";
+ return 0;
+ }
+
+ return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
+}
+
+static
+uint16_t
+m_get_uint16(sres_message_t *m)
+{
+ uint8_t const *p = m->m_data + m->m_offset;
+
+ if (m->m_error)
+ return 0;
+
+ m->m_offset += 2;
+
+ if (m->m_offset > m->m_size) {
+ m->m_error = "truncated message";
+ return 0;
+ }
+
+ return (p[0] << 8) | p[1];
+}
+
+static
+uint8_t
+m_get_uint8(sres_message_t *m)
+{
+ uint8_t const *p = m->m_data + m->m_offset;
+
+ if (m->m_error)
+ return 0;
+
+ m->m_offset += 1;
+
+ if (m->m_offset > m->m_size) {
+ m->m_error = "truncated message";
+ return 0;
+ }
+
+ return p[0];
+}
+
+/**
+ * Get a string.
+ */
+static int m_get_string(char *d,
+ int n,
+ sres_message_t *m,
+ uint16_t offset)
+{
+ uint8_t size;
+ uint8_t *p = m->m_data;
+ int save_offset;
+
+ if (m->m_error)
+ return 0;
+
+ if (offset == 0)
+ offset = m->m_offset, save_offset = 1;
+ else
+ save_offset = 0;
+
+ size = p[offset++];
+
+ if (size + offset >= m->m_size) {
+ m->m_error = "truncated message";
+ return size;
+ }
+
+ offset += size;
+
+ if (save_offset)
+ m->m_offset = offset;
+
+ if (n == 0 || d == NULL)
+ return size; /* Just return the size (without NUL). */
+
+ memcpy(d, p + offset - size, size < n ? size : n);
+
+ if (size < n)
+ d[size] = '\0'; /* NUL terminate */
+
+ return size;
+}
+
+/**
+ * Uncompress a domain.
+ *
+ * @param offset start uncompression from this point in message
+ */
+static int m_get_domain(char *d,
+ int n,
+ sres_message_t *m,
+ uint16_t offset)
+{
+ uint8_t cnt;
+ int i = 0;
+ uint8_t *p = m->m_data;
+ uint16_t new_offset;
+ int save_offset;
+
+ if (m->m_error)
+ return 0;
+
+ if (d == NULL)
+ n = 0;
+
+ if (offset == 0)
+ offset = m->m_offset, save_offset = 1;
+ else
+ save_offset = 0;
+
+ while ((cnt = p[offset++])) {
+ if (cnt >= 0xc0) {
+ if (offset >= m->m_size) {
+ m->m_error = "truncated message";
+ return 0;
+ }
+
+ new_offset = ((cnt & 0x3F) << 8) + p[offset++];
+
+ if (save_offset)
+ m->m_offset = offset;
+
+ if (new_offset <= 0 || new_offset >= m->m_size) {
+ m->m_error = "invalid domain compression";
+ return 0;
+ }
+
+ offset = new_offset;
+ save_offset = 0;
+ }
+ else {
+ if (offset + cnt >= m->m_size) {
+ m->m_error = "truncated message";
+ return 0;
+ }
+ if (i + cnt + 1 < n) {
+ memcpy(d + i, p + offset, cnt);
+ d[i + cnt] = '.';
+ }
+
+ i += cnt + 1;
+ offset += cnt;
+ }
+ }
+
+ if (i == 0) {
+ if (i < n)
+ d[i] = '.';
+ i++;
+ }
+
+ if (i < n)
+ d[i] = '\0';
+
+ if (save_offset)
+ m->m_offset = offset;
+
+ return i;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sres_blocking.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sres_blocking.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,433 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE sres_blocking.c
+ * @brief Blocking interface for Sofia DNS Resolver implementation.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @date Created: Fri Mar 24 15:23:08 EET 2006 ppessi
+ */
+
+#include "config.h"
+
+#if HAVE_STDINT_H
+#include <stdint.h>
+#elif HAVE_INTTYPES_H
+#include <inttypes.h>
+#else
+#if defined(_WIN32)
+typedef _int8 int8_t;
+typedef unsigned _int8 uint8_t;
+typedef unsigned _int16 uint16_t;
+typedef unsigned _int32 uint32_t;
+#endif
+#endif
+
+#if HAVE_NETINET_IN_H
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#endif
+
+#if HAVE_WINSOCK2_H
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#define HAVE_SELECT 1
+#else
+#define SOCKET_ERROR (-1)
+#define INVALID_SOCKET ((sres_socket_t)-1)
+#endif
+
+typedef struct sres_blocking_s sres_blocking_t;
+typedef struct sres_blocking_context_s sres_blocking_context_t;
+
+#define SRES_CONTEXT_T struct sres_blocking_context_s
+#define SRES_ASYNC_T struct sres_blocking_s
+
+#include "sofia-resolv/sres.h"
+#include "sofia-resolv/sres_async.h"
+#include <sofia-sip/su_errno.h>
+
+#if HAVE_POLL
+#include <poll.h>
+#elif HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#include <stdlib.h>
+#include <errno.h>
+
+struct sres_blocking_s
+{
+ int n_sockets;
+#if HAVE_POLL
+ struct pollfd fds[SRES_MAX_NAMESERVERS];
+#elif HAVE_SELECT
+ struct { sres_socket_t fd; } fds[SRES_MAX_NAMESERVERS];
+#else
+#error No wait mechanism!
+#endif
+ sres_record_t ***return_records;
+};
+
+struct sres_blocking_context_s
+{
+ int ready;
+ sres_resolver_t *resolver;
+ sres_blocking_t *block;
+ sres_query_t *query;
+ sres_record_t ***return_records;
+};
+
+static
+int sres_blocking_update(sres_blocking_t *b,
+ sres_socket_t new_socket,
+ sres_socket_t old_socket)
+{
+ int i, N = b->n_sockets;
+
+ if (old_socket == new_socket) {
+ if (old_socket == INVALID_SOCKET) {
+ free(b); /* Destroy us */
+ }
+ return 0;
+ }
+
+ if (old_socket != INVALID_SOCKET) {
+ for (i = 0; i < N; i++) {
+ if (b->fds[i].fd == old_socket)
+ break;
+ }
+ if (i == N)
+ return -1;
+
+ N--;
+ b->fds[i].fd = b->fds[N].fd;
+ b->fds[N].fd = INVALID_SOCKET;
+#if HAVE_POLL
+ b->fds[i].events = b->fds[N].events;
+ b->fds[N].events = 0;
+#endif
+
+ b->n_sockets = N;
+ }
+
+ if (new_socket != INVALID_SOCKET) {
+ if (N == SRES_MAX_NAMESERVERS)
+ return -1;
+ b->fds[N].fd = new_socket;
+#if HAVE_POLL
+ b->fds[N].events = POLLIN;
+#endif
+ b->n_sockets = N + 1;
+ }
+
+ return 0;
+}
+
+static
+int sres_blocking_complete(sres_blocking_context_t *c)
+{
+ while (!c->ready) {
+ int n, i;
+#if HAVE_POLL
+ n = poll(c->block->fds, c->block->n_sockets, 500);
+ if (n < 0) {
+ c->ready = n;
+ }
+ else if (n == 0) {
+ sres_resolver_timer(c->resolver, -1);
+ }
+ else for (i = 0; i < c->block->n_sockets; i++) {
+ if (c->block->fds[i].revents | POLLERR)
+ sres_resolver_error(c->resolver, c->block->fds[i].fd);
+ if (c->block->fds[i].revents | POLLIN)
+ sres_resolver_receive(c->resolver, c->block->fds[i].fd);
+ }
+#elif HAVE_SELECT
+ fd_set readfds[1], errorfds[1];
+ struct timeval timeval[1];
+
+ FD_ZERO(readfds);
+ FD_ZERO(errorfds);
+
+ timeval->tv_sec = 0;
+ timeval->tv_usec = 500000;
+
+ for (i = 0, n = 0; i < c->block->n_sockets; i++) {
+ FD_SET(c->block->fds[i].fd, readfds);
+ FD_SET(c->block->fds[i].fd, errorfds);
+ if (c->block->fds[i].fd >= n)
+ n = c->block->fds[i].fd + 1;
+ }
+
+ n = select(n, readfds, NULL, errorfds, timeval);
+
+ if (n <= 0)
+ sres_resolver_timer(c->resolver, -1);
+ else for (i = 0; n > 0 && i < c->block->n_sockets; i++) {
+ if (FD_ISSET(c->block->fds[i].fd, errorfds))
+ sres_resolver_error(c->resolver, c->block->fds[i].fd);
+ else if (FD_ISSET(c->block->fds[i].fd, readfds))
+ sres_resolver_receive(c->resolver, c->block->fds[i].fd);
+ else
+ continue;
+ n--;
+ }
+#endif
+ }
+
+ return c->ready;
+}
+
+static
+void sres_blocking_callback(sres_blocking_context_t *c,
+ sres_query_t *query,
+ sres_record_t **answers)
+{
+ c->ready = 1;
+ *c->return_records = answers;
+}
+
+static
+sres_blocking_t *sres_set_blocking(sres_resolver_t *res)
+{
+ sres_blocking_t *b;
+ int i;
+
+ b = sres_resolver_get_async(res, sres_blocking_update);
+ if (b)
+ return b;
+
+ /* Check if resolver is already in asynchronous mode */
+ if (sres_resolver_get_async(res, NULL))
+ return NULL;
+
+ /* Create a synchronous (blocking) interface towards resolver */
+ b = calloc(1, sizeof *b);
+
+ for (i = 0; i < SRES_MAX_NAMESERVERS; i++)
+ b->fds[i].fd = INVALID_SOCKET;
+
+ if (!sres_resolver_set_async(res, sres_blocking_update, b, 0)) {
+ free(b), b = NULL;
+ }
+
+ return b;
+}
+
+/** Return true (and set resolver in blocking mode) if resolver can block. */
+int sres_is_blocking(sres_resolver_t *res)
+{
+ if (res == NULL)
+ return 0;
+ return sres_set_blocking(res) != NULL;
+}
+
+/**Send a DNS query, wait for response, return results.
+ *
+ * Sends a DNS query with specified @a type and @a domain to the DNS server,
+ * if @a ignore_cache is not given or no records are found from cache.
+ * Function returns an error record with nonzero status if no response is
+ * received from DNS server.
+ *
+ * @param res pointer to resolver object
+ * @param type record type to search (or sres_qtype_any for any record)
+ * @param domain domain name to query
+ * @param ignore_cache ignore cached answers if nonzero
+ * @param return_records return-value parameter for dns records
+ *
+ * @retval >0 if query was responded
+ * @retval 0 if result was found from cache
+ * @retval -1 upon error
+ *
+ * @ERRORS
+ * @ERROR EFAULT @a res or @a domain point outside the address space
+ * @ERROR ENAMETOOLONG @a domain is longer than SRES_MAXDNAME
+ * @ERROR ENETDOWN no DNS servers configured
+ * @ERROR ENOMEM memory exhausted
+ * @ERROR EOPNOTSUPP resolver @a res is in asynchronous mode
+ *
+ * @sa sres_query(), sres_blocking_search()
+ *
+ * @note A blocking query converts a resolver object permanently into
+ * blocking mode. If you need to make blocking and non-blocking queries, use
+ * sres_resolver_copy() to make a separate resolver object for blocking
+ * queries.
+ */
+int sres_blocking_query(sres_resolver_t *res,
+ uint16_t type,
+ char const *domain,
+ int ignore_cache,
+ sres_record_t ***return_records)
+{
+ sres_blocking_context_t c[1];
+ sres_record_t **cached;
+
+ if (return_records == NULL)
+ return su_seterrno(EFAULT);
+
+ *return_records = NULL;
+
+ c->block = sres_set_blocking(res);
+ if (c->block == NULL)
+ return su_seterrno(EOPNOTSUPP); /* Resolver in asynchronous mode */
+
+ if (!ignore_cache) {
+ cached = sres_cached_answers(res, type, domain);
+ if (cached) {
+ *return_records = cached;
+ return 0;
+ }
+ }
+
+ c->ready = 0;
+ c->resolver = res;
+ c->return_records = return_records;
+ c->query = sres_query(res, sres_blocking_callback, c, type, domain);
+
+ return sres_blocking_complete(c);
+}
+
+/** Search DNS, return results.
+ *
+ * Search for @a name with specified @a type and @a name from the DNS server.
+ * If the @a name does not contain enought dots, the search domains are
+ * appended to the name and resulting domain name are also queried.
+ *
+ * @param res pointer to resolver object
+ * @param type record type to search (or sres_qtype_any for any record)
+ * @param name host or domain name to search from DNS
+ * @param ignore_cache ignore cached answers if nonzero
+ * @param return_records return-value parameter for dns records
+ *
+ * @retval >0 if query was responded
+ * @retval 0 if result was found from cache
+ * @retval -1 upon error
+ *
+ * @ERRORS
+ * @ERROR EFAULT @a res or @a domain point outside the address space
+ * @ERROR ENAMETOOLONG @a domain is longer than SRES_MAXDNAME
+ * @ERROR ENETDOWN no DNS servers configured
+ * @ERROR ENOMEM memory exhausted
+ * @ERROR EOPNOTSUPP resolver @a res is in asynchronous mode
+ *
+ * @sa sres_blocking_query(), sres_search()
+ *
+ * @note A blocking query converts a resolver object permanently into
+ * blocking mode. If you need to make blocking and non-blocking queries, use
+ * sres_resolver_copy() to make a separate resolver object for blocking
+ * queries.
+ */
+int sres_blocking_search(sres_resolver_t *res,
+ uint16_t type,
+ char const *name,
+ int ignore_cache,
+ sres_record_t ***return_records)
+{
+ sres_blocking_context_t c[1];
+ sres_record_t **cached;
+
+ if (return_records == NULL)
+ return su_seterrno(EFAULT);
+
+ *return_records = NULL;
+
+ c->block = sres_set_blocking(res);
+ if (c->block == NULL)
+ return su_seterrno(EOPNOTSUPP); /* Resolver in asynchronous mode */
+
+ if (!ignore_cache) {
+ cached = sres_search_cached_answers(res, type, name);
+ if (cached) {
+ *return_records = cached;
+ return 0;
+ }
+ }
+
+ c->ready = 0;
+ c->resolver = res;
+ c->return_records = return_records;
+ c->query = sres_search(res, sres_blocking_callback, c, type, name);
+
+ return sres_blocking_complete(c);
+}
+
+/** Send a a reverse DNS query, return results.
+ *
+ * Sends a reverse DNS query with specified @a type and @a domain to the DNS
+ * server if @a ignore_cache is not given or no cached records are found from
+ * the cache. Function returns an error record with nonzero status if no
+ * response is received from DNS server.
+ *
+ * @retval >0 if query was responded
+ * @retval 0 if result was found from cache
+ * @retval -1 upon error
+ *
+ * @ERRORS
+ * @ERROR EFAULT @a res or @a addr point outside the address space
+ * @ERROR ENOMEM memory exhausted
+ * @ERROR ENETDOWN no DNS servers configured
+ * @ERROR EOPNOTSUPP resolver @a res is in asynchronous mode
+ *
+ * @sa sres_blocking_query(), sres_query_sockaddr(), sres_cached_answers_sockaddr()
+ *
+ * @note A blocking query converts a resolver object permanently into
+ * blocking mode. If you need to make blocking and non-blocking queries, use
+ * sres_resolver_copy() to make a separate resolver object for blocking
+ * queries.
+ */
+int sres_blocking_query_sockaddr(sres_resolver_t *res,
+ uint16_t type,
+ struct sockaddr const *addr,
+ int ignore_cache,
+ sres_record_t ***return_records)
+{
+ sres_blocking_context_t c[1];
+ sres_record_t **cached;
+
+ if (return_records == NULL)
+ return errno = EFAULT, -1;
+
+ *return_records = NULL;
+
+ c->block = sres_set_blocking(res);
+ if (c->block == NULL)
+ return su_seterrno(EOPNOTSUPP); /* Resolver in asynchronous mode */
+
+ if (!ignore_cache) {
+ cached = sres_cached_answers_sockaddr(res, type, addr);
+ if (cached) {
+ *return_records = cached;
+ return 0;
+ }
+ }
+
+ c->ready = 0;
+ c->resolver = res;
+ c->return_records = return_records;
+ c->query = sres_query_sockaddr(res, sres_blocking_callback, c, type, addr);
+
+ return sres_blocking_complete(c);
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sres_cache.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sres_cache.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,450 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE sres_cache.c
+ * @brief Cache for Sofia DNS Resolver.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Teemu Jalava <Teemu.Jalava at nokia.com>
+ * @author Mikko Haataja
+ *
+ * @todo The resolver should allow handling arbitrary records, too.
+ */
+
+#include "config.h"
+
+#if HAVE_STDINT_H
+#include <stdint.h>
+#elif HAVE_INTTYPES_H
+#include <inttypes.h>
+#else
+#if defined(_WIN32)
+typedef unsigned _int8 uint8_t;
+typedef unsigned _int16 uint16_t;
+typedef unsigned _int32 uint32_t;
+#endif
+#endif
+
+#if HAVE_NETINET_IN_H
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#endif
+
+#if HAVE_WINSOCK2_H
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#endif
+
+#include <time.h>
+
+#include "sofia-resolv/sres_cache.h"
+#include "sofia-resolv/sres_record.h"
+
+#include <sofia-sip/su_alloc.h>
+#include <sofia-sip/su_strlst.h>
+#include <sofia-sip/htable.h>
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <limits.h>
+
+#include <assert.h>
+
+#define SU_LOG sresolv_log
+
+#include <sofia-sip/su_debug.h>
+
+typedef struct sres_rr_hash_entry_s sres_rr_hash_entry_t;
+
+HTABLE_DECLARE_WITH(sres_htable, ht, sres_rr_hash_entry_t, unsigned, size_t);
+
+struct sres_rr_hash_entry_s {
+ unsigned int rr_hash_key;
+ time_t rr_received;
+ sres_record_t *rr;
+};
+
+#define SRES_HENTRY_HASH(e) ((e)->rr_hash_key)
+
+struct sres_cache
+{
+ su_home_t cache_home[1];
+ time_t cache_cleaned;
+ sres_htable_t cache_hash[1];
+};
+
+#define sr_refcount sr_record->r_refcount
+#define sr_name sr_record->r_name
+#define sr_status sr_record->r_status
+#define sr_size sr_record->r_size
+#define sr_type sr_record->r_type
+#define sr_class sr_record->r_class
+#define sr_ttl sr_record->r_ttl
+#define sr_rdlen sr_record->r_rdlen
+#define sr_rdata sr_generic->g_data
+
+/* ---------------------------------------------------------------------- */
+/* Internal prototypes */
+
+#define LOCK(cache) (su_home_mutex_lock((cache)->cache_home) == 0)
+#define UNLOCK(cache) (su_home_mutex_unlock((cache)->cache_home))
+
+static inline
+void _sres_cache_free_one(sres_cache_t *cache, sres_record_t *answer);
+static inline
+void _sres_cache_free_answers(sres_cache_t *cache, sres_record_t **answers);
+
+static unsigned sres_hash_key(const char *string);
+
+HTABLE_PROTOS_WITH(sres_htable, ht, sres_rr_hash_entry_t, unsigned, size_t);
+
+
+/* ---------------------------------------------------------------------- */
+/* Public functions */
+
+/** Create a resolver cache object.
+ *
+ * @param n initial size of cache
+ */
+sres_cache_t *sres_cache_new(int n)
+{
+ sres_cache_t *cache = su_home_new(sizeof *cache);
+
+ if (cache) {
+ su_home_threadsafe(cache->cache_home);
+ if (sres_htable_resize(cache->cache_home, cache->cache_hash, n) < 0)
+ su_home_unref(cache->cache_home), cache = NULL;
+ }
+
+ return cache;
+}
+
+/** Increase reference count on a resolver cache object. */
+sres_cache_t *sres_cache_ref(sres_cache_t *cache)
+{
+ return su_home_ref(cache->cache_home);
+}
+
+/** Decrease the reference count on a resolver cache object. */
+void sres_cache_unref(sres_cache_t *cache)
+{
+ su_home_unref(cache->cache_home);
+}
+
+/** Get a list of matching records from cache. */
+int sres_cache_get(sres_cache_t *cache,
+ uint16_t type,
+ char const *domain,
+ sres_record_t ***return_cached)
+{
+ sres_record_t **result = NULL, *rr = NULL;
+ sres_rr_hash_entry_t **rr_iter, **rr_iter2;
+ int result_size, rr_count = 0;
+ unsigned hash;
+ time_t now;
+ char b[8];
+
+ if (!domain || !return_cached)
+ return -1;
+
+ *return_cached = NULL;
+
+ SU_DEBUG_9(("%s(%p, %s, \"%s\") called\n", "sres_cache_get",
+ cache, sres_record_type(type, b), domain));
+
+ hash = sres_hash_key(domain);
+
+ if (!LOCK(cache))
+ return -1;
+
+ time(&now);
+
+ /* First pass: just count the number of rr:s for array allocation */
+ rr_iter2 = sres_htable_hash(cache->cache_hash, hash);
+
+ /* Find the domain records from the hash table */
+ for (rr_iter = rr_iter2;
+ rr_iter && *rr_iter;
+ rr_iter = sres_htable_next(cache->cache_hash, rr_iter)) {
+ rr = (*rr_iter)->rr;
+
+ if (rr != NULL &&
+ (uint32_t)(now - (*rr_iter)->rr_received) <= rr->sr_ttl &&
+ (type == sres_qtype_any || rr->sr_type == type) &&
+ rr->sr_name != NULL &&
+ strcasecmp(rr->sr_name, domain) == 0)
+ rr_count++;
+ }
+
+ if (rr_count == 0) {
+ UNLOCK(cache);
+ return 0;
+ }
+
+ result_size = (sizeof *result) * (rr_count + 1);
+ result = su_zalloc(cache->cache_home, result_size);
+ if (result == NULL) {
+ UNLOCK(cache);
+ return -1;
+ }
+
+ /* Second pass: add the rr pointers to the allocated array */
+
+ for (rr_iter = rr_iter2, rr_count = 0;
+ rr_iter && *rr_iter;
+ rr_iter = sres_htable_next(cache->cache_hash, rr_iter)) {
+ rr = (*rr_iter)->rr;
+
+ if (rr != NULL &&
+ (uint32_t)(now - (*rr_iter)->rr_received) <= rr->sr_ttl &&
+ (type == sres_qtype_any || rr->sr_type == type) &&
+ rr->sr_name != NULL &&
+ strcasecmp(rr->sr_name, domain) == 0) {
+ SU_DEBUG_9(("rr found in cache: %s %02d\n",
+ rr->sr_name, rr->sr_type));
+
+ result[rr_count++] = rr;
+ rr->sr_refcount++;
+ }
+ }
+
+ result[rr_count] = NULL;
+
+ UNLOCK(cache);
+
+ SU_DEBUG_9(("%s(%p, %s, \"%s\") returned %d entries\n", "sres_cache_get",
+ cache, sres_record_type(type, b), domain, rr_count));
+
+ *return_cached = result;
+
+ return rr_count;
+}
+
+sres_record_t *
+sres_cache_alloc_record(sres_cache_t *cache,
+ sres_record_t const *template,
+ size_t extra)
+{
+ sres_record_t *sr;
+ size_t size, name_length;
+
+ size = template->sr_size;
+
+ assert(size >= sizeof(sres_common_t));
+ assert(template->sr_name != NULL);
+
+ name_length = strlen(template->sr_name);
+
+ sr = su_alloc(cache->cache_home, size + extra + name_length + 1);
+
+ if (sr) {
+ char *s = (char *)sr + size + extra;
+ sr->sr_refcount = 0;
+ sr->sr_name = memcpy(s, template->sr_name, name_length);
+ sr->sr_name[name_length] = '\0';
+ memcpy(&sr->sr_status, &template->sr_status,
+ size - offsetof(sres_common_t, r_status));
+ }
+
+ return sr;
+}
+
+/** Free a record that has not been stored. */
+void sres_cache_free_record(sres_cache_t *cache, void *rr)
+{
+ sres_record_t *sr = rr;
+
+ if (sr) {
+ assert(sr->sr_refcount == 0);
+ su_free(cache->cache_home, rr);
+ }
+}
+
+/** Store record to cache */
+void
+sres_cache_store(sres_cache_t *cache, sres_record_t *rr, time_t now)
+{
+ sres_rr_hash_entry_t **rr_iter, *rr_hash_entry;
+ unsigned hash;
+
+ if (rr == NULL)
+ return;
+
+ hash = sres_hash_key(rr->sr_name);
+
+ if (!LOCK(cache))
+ return;
+
+ if (sres_htable_is_full(cache->cache_hash))
+ sres_htable_resize(cache->cache_home, cache->cache_hash, 0);
+
+ for (rr_iter = sres_htable_hash(cache->cache_hash, hash);
+ (rr_hash_entry = *rr_iter);
+ rr_iter = sres_htable_next(cache->cache_hash, rr_iter)) {
+ sres_record_t *or = rr_hash_entry->rr;
+
+ if (or == NULL)
+ continue;
+ if (rr_hash_entry->rr_hash_key != hash)
+ continue;
+ if (or->sr_type != rr->sr_type)
+ continue;
+ if (!!or->sr_name != !!rr->sr_name)
+ continue;
+ if (or->sr_name != rr->sr_name &&
+ strcasecmp(or->sr_name, rr->sr_name) != 0)
+ continue;
+ if (rr->sr_type != sres_type_soa /* There can be only one */
+ && sres_record_compare(or, rr))
+ continue;
+
+ /* There was an old entry in the cache.. Zap it, replace this with it */
+ rr_hash_entry->rr_received = now;
+ rr_hash_entry->rr = rr;
+ rr->sr_refcount++;
+
+ _sres_cache_free_one(cache, or);
+
+ UNLOCK(cache);
+
+ return;
+ }
+
+ rr_hash_entry = su_zalloc(cache->cache_home, sizeof(*rr_hash_entry));
+ if (rr_hash_entry) {
+ rr_hash_entry->rr_hash_key = hash;
+ rr_hash_entry->rr_received = now;
+ rr_hash_entry->rr = rr;
+ rr->sr_refcount++;
+
+ cache->cache_hash->ht_used++;
+ }
+
+ *rr_iter = rr_hash_entry;
+
+ UNLOCK(cache);
+}
+
+/** Free the list records. */
+void sres_cache_free_answers(sres_cache_t *cache, sres_record_t **answers)
+{
+ if (answers && LOCK(cache)) {
+ _sres_cache_free_answers(cache, answers);
+ UNLOCK(cache);
+ }
+}
+
+/** Free and zero one record. */
+void sres_cache_free_one(sres_cache_t *cache, sres_record_t *answer)
+{
+ if (LOCK(cache)) {
+ _sres_cache_free_one(cache, answer);
+ UNLOCK(cache);
+ }
+}
+
+/* ---------------------------------------------------------------------- */
+/* Private functions */
+
+static inline
+void _sres_cache_free_answers(sres_cache_t *cache, sres_record_t **answers)
+{
+ int i;
+
+ for (i = 0; answers[i] != NULL; i++) {
+ if (answers[i]->sr_refcount <= 1)
+ su_free(cache->cache_home, answers[i]);
+ else
+ answers[i]->sr_refcount--;
+ answers[i] = NULL;
+ }
+
+ su_free(cache->cache_home, answers);
+}
+
+static inline
+void _sres_cache_free_one(sres_cache_t *cache, sres_record_t *answer)
+{
+ if (answer) {
+ if (answer->sr_refcount <= 1)
+ su_free(cache->cache_home, answer);
+ else
+ answer->sr_refcount--;
+ }
+}
+
+/** Calculate a hash key for a string */
+static
+unsigned
+sres_hash_key(const char *string)
+{
+ unsigned int result = 0;
+
+ while (string && *string)
+ result = result * 797 + (unsigned char) * (string++);
+
+ if (result == 0)
+ result--;
+
+ return result;
+}
+
+void sres_cache_clean(sres_cache_t *cache, time_t now)
+{
+ size_t i;
+
+ if (now < cache->cache_cleaned + SRES_CACHE_TIMER_INTERVAL)
+ return;
+
+ if (!LOCK(cache))
+ return;
+
+ /* Clean cache from old entries */
+ cache->cache_cleaned = now;
+
+ for (i = 0; i < cache->cache_hash->ht_size; i++) {
+ sres_rr_hash_entry_t *e;
+
+ while ((e = cache->cache_hash->ht_table[i]) != NULL) {
+ if ((uint32_t)(now - e->rr_received) <= e->rr->sr_ttl)
+ break;
+
+ sres_htable_remove(cache->cache_hash, e);
+
+ _sres_cache_free_one(cache, e->rr);
+ }
+ }
+
+ UNLOCK(cache);
+}
+
+HTABLE_BODIES_WITH(sres_htable, ht, sres_rr_hash_entry_t, SRES_HENTRY_HASH,
+ unsigned, size_t);
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sresolv.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sresolv.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,362 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE sresolv.c
+ * @brief Sofia DNS Resolver interface using su_root_t.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Teemu Jalava <Teemu.Jalava at nokia.com>
+ * @author Mikko Haataja
+ *
+ * @todo The resolver should allow handling arbitrary records, too.
+ */
+
+#include "config.h"
+
+#define SU_TIMER_ARG_T struct sres_sofia_s
+#define SU_WAKEUP_ARG_T struct sres_sofia_register_s
+#define SRES_ASYNC_T struct sres_sofia_s
+
+#include <sofia-sip/sresolv.h>
+
+#define SU_LOG sresolv_log
+#include <sofia-sip/su_debug.h>
+
+#include <string.h>
+#include <assert.h>
+
+/* ====================================================================== */
+/* Glue functions for Sofia root (reactor) */
+
+#define TAG_NAMESPACE "sres"
+
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/su_tagarg.h>
+
+tag_typedef_t srestag_any = NSTAG_TYPEDEF(*);
+tag_typedef_t srestag_resolv_conf = STRTAG_TYPEDEF(resolv_conf);
+tag_typedef_t srestag_resolv_conf_ref = REFTAG_TYPEDEF(srestag_resolv_conf);
+
+tag_typedef_t srestag_cache = PTRTAG_TYPEDEF(cache);
+tag_typedef_t srestag_cache_ref = REFTAG_TYPEDEF(srestag_cache);
+
+typedef struct sres_sofia_s sres_sofia_t;
+typedef struct sres_sofia_register_s sres_sofia_register_t;
+
+struct sres_sofia_register_s {
+ sres_sofia_t *reg_ptr;
+ su_socket_t reg_socket;
+ int reg_index; /**< Registration index */
+};
+
+struct sres_sofia_s {
+ sres_resolver_t *srs_resolver;
+ su_root_t *srs_root;
+ su_timer_t *srs_timer;
+ su_socket_t srs_socket;
+ sres_sofia_register_t srs_reg[SRES_MAX_NAMESERVERS];
+};
+
+static int sres_sofia_update(sres_sofia_t *,
+ su_socket_t new_socket,
+ su_socket_t old_socket);
+
+static void sres_sofia_timer(su_root_magic_t *magic,
+ su_timer_t *t,
+ sres_sofia_t *arg);
+
+static int sres_sofia_set_timer(sres_sofia_t *srs, unsigned long interval);
+
+static int sres_sofia_poll(su_root_magic_t *, su_wait_t *,
+ sres_sofia_register_t *);
+
+/**Create a resolver.
+ *
+ * The function sres_resolver_create() is used to allocate and initialize
+ * the resolver object using the Sofia asynchronous reactor #su_root_t.
+ */
+sres_resolver_t *
+sres_resolver_create(su_root_t *root,
+ char const *conf_file_path,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ sres_resolver_t *res;
+ sres_sofia_t *srs;
+ sres_cache_t *cache = NULL;
+ ta_list ta;
+
+ if (root == NULL)
+ return su_seterrno(EFAULT), (void *)NULL;
+
+ ta_start(ta, tag, value);
+ tl_gets(ta_args(ta),
+ SRESTAG_RESOLV_CONF_REF(conf_file_path),
+ SRESTAG_CACHE_REF(cache),
+ TAG_END());
+ ta_end(ta);
+
+ res = sres_resolver_new_with_cache(conf_file_path, cache, NULL);
+ srs = res ? su_zalloc(0, sizeof *srs) : NULL;
+
+ if (res && srs) {
+ su_timer_t *t;
+
+ srs->srs_resolver = res;
+ srs->srs_root = root;
+ srs->srs_socket = INVALID_SOCKET;
+
+ sres_resolver_set_async(res, sres_sofia_update, srs, 0);
+
+ t = su_timer_create(su_root_task(root), SRES_RETRANSMIT_INTERVAL);
+ srs->srs_timer = t;
+
+ if (!srs->srs_timer)
+ SU_DEBUG_3(("sres: cannot create timer\n"));
+#if nomore
+ else if (su_timer_set_for_ever(t, sres_sofia_timer, srs) < 0)
+ SU_DEBUG_3(("sres: cannot set timer\n"));
+#else
+ else if (sres_resolver_set_timer_cb(res, sres_sofia_set_timer, srs) < 0)
+ SU_DEBUG_3(("sres: cannot set timer cb\n"));
+#endif
+ else
+ return res; /* Success! */
+
+ sres_resolver_destroy(res), res = NULL;
+ }
+
+ return res;
+}
+
+/** Destroy a resolver object. */
+int
+sres_resolver_destroy(sres_resolver_t *res)
+{
+ sres_sofia_t *srs;
+
+ if (res == NULL)
+ return su_seterrno(EFAULT);
+
+ srs = sres_resolver_get_async(res, sres_sofia_update);
+ if (srs == NULL)
+ return su_seterrno(EINVAL);
+
+ /* Remove sockets from too, zap timers. */
+ sres_sofia_update(srs, INVALID_SOCKET, INVALID_SOCKET);
+
+ sres_resolver_unref(res);
+
+ return 0;
+}
+
+/**Update registered socket.
+ *
+ * @retval 0 if success
+ * @retval -1 upon failure
+ */
+static int sres_sofia_update(sres_sofia_t *srs,
+ su_socket_t new_socket,
+ su_socket_t old_socket)
+{
+ char const *what = NULL;
+ su_wait_t wait[1];
+ sres_sofia_register_t *reg = NULL;
+ sres_sofia_register_t *old_reg = NULL;
+ int i, index = -1, error = 0;
+ int N = SRES_MAX_NAMESERVERS;
+
+ SU_DEBUG_9(("sres_sofia_update(%p, %d, %d)\n", srs,
+ (int)new_socket, (int)old_socket));
+
+ if (srs == NULL)
+ return 0;
+
+ if (srs->srs_root == NULL)
+ return -1;
+
+ if (old_socket == new_socket) {
+ if (old_socket == INVALID_SOCKET) {
+ sres_resolver_set_async(srs->srs_resolver, sres_sofia_update, NULL, 0);
+ /* Destroy srs */
+ for (i = 0; i < N; i++) {
+ if (!srs->srs_reg[i].reg_index)
+ continue;
+ su_root_deregister(srs->srs_root, srs->srs_reg[i].reg_index);
+ memset(&srs->srs_reg[i], 0, sizeof(srs->srs_reg[i]));
+ }
+ su_timer_destroy(srs->srs_timer), srs->srs_timer = NULL;
+ su_free(NULL, srs);
+ }
+ return 0;
+ }
+
+ if (old_socket != INVALID_SOCKET)
+ for (i = 0; i < N; i++)
+ if ((srs->srs_reg + i)->reg_socket == old_socket) {
+ old_reg = srs->srs_reg + i;
+ break;
+ }
+
+ if (new_socket != INVALID_SOCKET) {
+ if (old_reg == NULL) {
+ for (i = 0; i < N; i++) {
+ if (!(srs->srs_reg + i)->reg_ptr)
+ break;
+ }
+ if (i > N)
+ return su_seterrno(ENOMEM);
+
+ reg = srs->srs_reg + i;
+ }
+ else
+ reg = old_reg;
+ }
+
+ if (reg) {
+ if (su_wait_create(wait, new_socket, SU_WAIT_IN | SU_WAIT_ERR) == -1) {
+ reg = NULL;
+ what = "su_wait_create";
+ error = su_errno();
+ }
+
+ if (reg)
+ index = su_root_register(srs->srs_root, wait, sres_sofia_poll, reg, 0);
+
+ if (index < 0) {
+ reg = NULL;
+ what = "su_root_register";
+ error = su_errno();
+ su_wait_destroy(wait);
+ }
+ }
+
+ if (old_reg) {
+ if (old_socket == srs->srs_socket)
+ srs->srs_socket = INVALID_SOCKET;
+ su_root_deregister(srs->srs_root, old_reg->reg_index);
+ memset(old_reg, 0, sizeof *old_reg);
+ }
+
+ if (reg) {
+ srs->srs_socket = new_socket;
+
+ reg->reg_ptr = srs;
+ reg->reg_socket = new_socket;
+ reg->reg_index = index;
+ }
+
+ if (!what)
+ return 0; /* success */
+
+ SU_DEBUG_3(("sres: %s: %s\n", what, su_strerror(error)));
+
+ return su_seterrno(error);
+}
+
+
+/** Return a socket registered to su_root_t object.
+ *
+ * @retval sockfd if succesful
+ * @retval INVALID_SOCKET (-1) upon an error
+ *
+ * @ERRORS
+ * @ERROR EFAULT Invalid argument passed.
+ * @ERROR EINVAL Resolver is not using su_root_t.
+ */
+su_socket_t sres_resolver_root_socket(sres_resolver_t *res)
+{
+ sres_sofia_t *srs;
+ int i, N = SRES_MAX_NAMESERVERS;
+
+ if (res == NULL)
+ return (void)su_seterrno(EFAULT), INVALID_SOCKET;
+
+ srs = sres_resolver_get_async(res, sres_sofia_update);
+
+ if (!srs)
+ return su_seterrno(EINVAL);
+
+ if (sres_resolver_set_async(res, sres_sofia_update, srs, 1) < 0)
+ return INVALID_SOCKET;
+
+ if (srs->srs_socket != INVALID_SOCKET)
+ return srs->srs_socket;
+
+ for (i = 0; i < N; i++) {
+ if (!srs->srs_reg[i].reg_ptr)
+ break;
+ }
+
+ if (i < N) {
+ srs->srs_socket = srs->srs_reg[i].reg_socket;
+ }
+ else {
+ su_socket_t socket;
+ if (sres_resolver_sockets(res, &socket, 1) < 0)
+ return INVALID_SOCKET;
+ }
+
+ return srs->srs_socket;
+}
+
+
+/** Sofia timer wrapper. */
+static
+void
+sres_sofia_timer(su_root_magic_t *magic, su_timer_t *t, sres_sofia_t *srs)
+{
+ sres_resolver_timer(srs->srs_resolver, -1);
+}
+
+/** Sofia timer set wrapper. */
+static
+int
+sres_sofia_set_timer(sres_sofia_t *srs, unsigned long interval)
+{
+ if (interval > SU_DURATION_MAX)
+ interval = SU_DURATION_MAX;
+ return su_timer_set_interval(srs->srs_timer, sres_sofia_timer, srs,
+ (su_duration_t)interval);
+}
+
+
+/** Sofia poll/select wrapper, called by su_root_t object */
+static
+int
+sres_sofia_poll(su_root_magic_t *magic,
+ su_wait_t *w,
+ sres_sofia_register_t *reg)
+{
+ sres_sofia_t *srs = reg->reg_ptr;
+ int retval = 0;
+ su_socket_t socket = reg->reg_socket;
+ int events = su_wait_events(w, socket);
+
+ if (events & SU_WAIT_ERR)
+ retval = sres_resolver_error(srs->srs_resolver, socket);
+ if (events & SU_WAIT_IN)
+ retval = sres_resolver_receive(srs->srs_resolver, socket);
+
+ return retval;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sresolv.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/sresolv.docs Thu Dec 21 01:30:28 2006
@@ -0,0 +1,263 @@
+/**@MODULEPAGE "sresolv" - Asynchronous DNS Resolver
+
+ at section sresolv_meta Module Information
+
+The Sofia @b sresolv module consists of an asynchronous DNS resolver with
+EDNS extensions. The interface to library using #su_root_t is declared in
+<sofia-sip/sresolv.h>.
+
+An alternative interface is defined by <sofia-resolv/sres.h>,
+<sofia-resolv/sres_record.h>, <sofia-resolv/sres_async.h>, and
+<sofia-resolv/sres_cache.h>.
+
+ at sa @RFC1034, @RFC1035, @RFC1886, @RFC2671, @RFC2782, @RFC2915
+
+ at CONTACT Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ at STATUS @SofiaSIP Core library
+
+ at LICENSE LGPL
+
+ at todo Caching Policy and Cache Poisoning
+
+The policy for caching non-authoritave entries should be solved.
+
+ at section sresolv_overview Why Sofia Resolver?
+
+The generally available open source DNS libraries are either synchronous,
+that is, they block the thread making the query or they resolve only host
+names. As SIP protocol uses NAPTR and SRV records in addition ot the usual A
+or AAAA records, these DNS libraries are inadequate for a SIP application.
+
+Sofia resolver uses the usual configuration for DNS. In Unix-based systems,
+the DNS configuration is stored in the file /etc/resolv.conf, on Windows, it
+is available through the registry. Sofia resolvers reloads the configuration
+when it detect that it has been changed.
+
+In addition to the configuration files, the environment variables
+#SRES_OPTIONS and #RES_OPTIONS can be used to change the behaviour of the
+resolver.
+
+ at section sresolv_interfaces Using Sofia Resolver
+
+Sofia resolver works usually asynchronously, in other words, it generates a
+a query, sends it to DNS server and returns immediately to the caller. When
+a response is received and the query is completed, sresolv signals
+application through a callback function.
+
+The application can either explicitly poll(2) or select(2) on file
+descriptors used by resolver and call the driver functions, or it can use
+ at ref su_root_t "su root" a pointer to a #su_root_t object. Third option is to
+use resolver synchronously with sres_blocking_query().
+
+There is an internal cache used by sresolv. The query functions add
+records to the cache: using the cache is made similar as if receiving
+entries directly from DNS server.
+
+Please note that you have to create a separate resolver object for each
+thread using Sofia resolver. The resolver objects can share the cache,
+however.
+
+ at section sofia_sip_sresolv_h Interface in <sofia-sip/sresolv.h>
+
+The simple use of Sofia resolver driven from #su_root_t is defined in
+<sofia-sip/sresolv.h>. The resolver object can be created with
+sres_resolver_create(). The provided @ref su_root_t "root object" takes care
+of calling the sres_query() and sres_query_sockaddr() callback functions.
+
+ at code
+#include <sofia-sip/sresolv.h>
+
+sres_resolver_t *sres_resolver_create(su_root_t *root,
+ char const *resolv_conf,
+ tag_type_t, tag_value_t, ...);
+
+int sres_resolver_destroy(sres_resolver_t *res);
+
+ at endcode
+
+ at section sres_query Sending DNS Queries
+
+The second part of interface is used when sending DNS queries:
+
+ at code
+sres_query_t *sres_query(sres_resolver_t *res,
+ sres_answer_f *callback,
+ sres_context_t *context,
+ int socket,
+ uint16_t type,
+ char const *domain);
+
+sres_query_t *sres_query_sockaddr(sres_resolver_t *res,
+ sres_answer_f *callback,
+ sres_context_t *context,
+ int socket,
+ uint16_t type,
+ struct sockaddr const *addr);
+
+void sres_query_bind(sres_query_t *q,
+ sres_answer_f *callback,
+ sres_context_t *context);
+ at endcode
+
+ at section sres_record Handling DNS Records
+
+The third part is used to handle the records which were returned by DNS
+query or stored into the cache:
+
+ at code
+sres_record_t **sres_cached_answers(sres_resolver_t *res,
+ uint16_t type,
+ char const *domain);
+
+sres_record_t **sres_cached_answers_sockaddr(sres_resolver_t *res,
+ uint16_t type,
+ struct sockaddr const *addr);
+
+int sres_sort_answers(sres_resolver_t *res, sres_record_t **answers);
+
+int sres_filter_answers(sres_resolver_t *sres, sres_record_t **answers,
+ uint16_t type);
+
+void sres_free_answers(sres_resolver_t *res, sres_record_t **answers);
+
+void sres_free_answer(sres_resolver_t *res, sres_record_t *answer);
+
+ at endcode
+
+ at section sofia_resolv_sres_h Interface in <sofia-resolv/sres.h>
+
+The generic interface to Sofia resolver is defined in <sofia-resolv/sres.h>.
+The first part of interface consists of functions for handling resolver
+objects:
+
+ at code
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <sofia-resolv/sres.h>
+
+sres_resolver_t *sres_resolver_new(char const *resolv_conf_path);
+
+sres_resolver_t *sres_resolver_new_with_cache(char const *conf_file_path,
+ sres_cache_t *cache,
+ char const *options, ...);
+
+sres_resolver_t *sres_resolver_ref(sres_resolver_t *res);
+void sres_resolver_unref(sres_resolver_t *res);
+
+sres_resolver_t *sres_resolver_copy(sres_resolver_t *);
+
+void *sres_resolver_set_userdata(sres_resolver_t *res, void *userdata);
+void *sres_resolver_get_userdata(sres_resolver_t const *res);
+
+ at endcode
+
+ at subsection sresolv_blocking Using Sofia Resolver Synchronously
+
+The blocking interface defined in <sofia-resolv/sres.h> makes it possible to
+use Sofia resolver synchronously, that is, the function call making the DNS
+query does not return until the query is responded or it times out.
+
+ at code
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <sofia-resolv/sres.h>
+
+int sres_blocking_query(sres_resolver_t *res,
+ uint16_t type,
+ char const *domain,
+ sres_record_t ***return_records);
+
+int sres_blocking_query_sockaddr(sres_resolver_t *res,
+ uint16_t type,
+ struct sockaddr const *addr,
+ sres_record_t ***return_records);
+
+ at endcode
+
+ at subsection sresolv_async Asynchronous Interface in <sofia-resolv/sres_async.h>
+
+It is also possible to use resolver asynchronously without #su_root_t object.
+
+ at code
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <sofia-resolv/sres_async.h>
+
+sres_async_t *sres_resolver_set_async(sres_resolver_t *res,
+ sres_update_f *update,
+ sres_async_t *async,
+ int update_all);
+sres_async_t *sres_resolver_get_async(sres_resolver_t const *res,
+ sres_update_f *update);
+
+int sres_resolver_sockets(sres_resolver_t const *res, int *sockets, int n);
+void sres_resolver_timer(sres_resolver_t *, int socket);
+
+int sres_resolver_receive(sres_resolver_t *res, int socket);
+int sres_resolver_error(sres_resolver_t *res, int socket);
+
+ at endcode
+
+Here is a short code fragment showing how to use resolver driven from
+#su_root_t:
+
+ at code
+
+#define SRES_CONTEXT_T struct context
+
+#include <sofia-sip/sresolv.h>
+
+...
+
+struct context
+{
+ ...
+ su_root_t *root;
+ sres_resolver_t *sres;
+ sres_query_t *query;
+ ...
+} *context;
+
+...
+
+ context->sres = sres_resolver_create(context->root, NULL, TAG_END());
+
+...
+
+ sres_record_t *results;
+
+ results = sres_cached_answers(context->sres, sres_type_naptr, domain);
+ if (results) {
+ process_natpr(context, NULL, results);
+ }
+ else {
+ context->query = sres_query(context->sres,
+ process_natpr, context,
+ sres_type_naptr, domain);
+ if (!context->query)
+ process_naptr(context, NULL, NULL);
+ }
+}
+...
+
+void process_natpr(sres_context_t *context,
+ sres_query_t *q,
+ sres_record_t *answers[])
+{
+ sres_sort_answers(context->sres, answers);
+
+ ...
+
+ sres_free_answers(context->sres, answers);
+}
+ at endcode
+
+*/
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/test_sresolv.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sresolv/test_sresolv.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,2020 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@internal
+ *
+ * @CFILE test_sresolv.c Test module for sresolv
+ *
+ * @author Mikko Haataja
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ */
+
+#include "config.h"
+
+#if HAVE_STDINT_H
+#include <stdint.h>
+#elif HAVE_INTTYPES_H
+#include <inttypes.h>
+#else
+#if defined(_WIN32)
+typedef unsigned _int8 uint8_t;
+typedef unsigned _int16 uint16_t;
+typedef unsigned _int32 uint32_t;
+#endif
+#endif
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#if HAVE_NETINET_IN_H
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#endif
+
+#if HAVE_WINSOCK2_H
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#endif
+
+#include <sofia-resolv/sres.h>
+#include <sofia-resolv/sres_async.h>
+#include <sofia-resolv/sres_record.h>
+
+#include <sofia-sip/su.h>
+#include <sofia-sip/su_alloc.h>
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+#define TSTFLAGS tstflags
+#include <sofia-sip/tstdef.h>
+
+#if HAVE_POLL
+#include <poll.h>
+#elif HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#if HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#if HAVE_ALARM
+#include <unistd.h>
+#include <signal.h>
+#endif
+
+char const name[] = "test_sresolv";
+
+struct sres_context_s
+{
+ su_home_t home[1];
+ sres_resolver_t *resolver;
+ sres_query_t *query;
+ sres_record_t **result;
+
+ int timeout;
+ int sink;
+ int sinkidx;
+ char const *sinkconf;
+
+ int ready;
+ int n_sockets;
+ sres_socket_t sockets[SRES_MAX_NAMESERVERS];
+#if HAVE_POLL
+ struct pollfd fds[SRES_MAX_NAMESERVERS];
+#endif
+};
+
+static void test_answer(sres_context_t *ctx, sres_query_t *query,
+ sres_record_t **answer);
+static void test_answer_multi(sres_context_t *ctx, sres_query_t *query,
+ sres_record_t **answer);
+
+static int tstflags = 0;
+
+#if 1
+
+#if HAVE_POLL && 0
+
+static
+int setblocking(sres_socket_t s, int blocking)
+{
+ unsigned mode = fcntl(s, F_GETFL, 0);
+
+ if (mode < 0)
+ return -1;
+
+ if (blocking)
+ mode &= ~(O_NDELAY | O_NONBLOCK);
+ else
+ mode |= O_NDELAY | O_NONBLOCK;
+
+ return fcntl(s, F_SETFL, mode);
+}
+
+/** Test few assumptions about sockets */
+static
+int test_socket(sres_context_t *ctx)
+{
+ int af;
+ su_sockeet_t s1, s2, s3, s4;
+ struct sockaddr_storage a[1];
+ struct sockaddr_storage a1[1], a2[1], a3[1], a4[1];
+ struct sockaddr_in *sin = (void *)a;
+ struct sockaddr_in *sin3 = (void *)a3, *sin4 = (void *)a4;
+ struct sockaddr *sa = (void *)a;
+ struct sockaddr *sa3 = (void *)a3, *sa4 = (void *)a4;
+ socklen_t alen, a1len, a2len, a3len, a4len;
+ char buf[16];
+
+ BEGIN();
+
+ af = AF_INET;
+
+ for (;;) {
+ TEST_1((s1 = su_socket(af, SOCK_DGRAM, 0)) != INVALID_SOCKET);
+ TEST_1((s2 = su_socket(af, SOCK_DGRAM, 0)) != INVALID_SOCKET);
+ TEST_1((s3 = su_socket(af, SOCK_DGRAM, 0)) != INVALID_SOCKET);
+ TEST_1((s4 = su_socket(af, SOCK_DGRAM, 0)) != INVALID_SOCKET);
+
+ TEST_1(setblocking(s1, 0) == 0);
+ TEST_1(setblocking(s2, 0) == 0);
+ TEST_1(setblocking(s3, 0) == 0);
+ TEST_1(setblocking(s4, 0) == 0);
+
+ memset(a, 0, sizeof a);
+ memset(a1, 0, sizeof a1);
+ memset(a2, 0, sizeof a2);
+ memset(a3, 0, sizeof a3);
+ memset(a4, 0, sizeof a4);
+
+#if HAVE_SA_LEN
+ a1->ss_len = a2->ss_len = a3->ss_len = a4->ss_len = sizeof a1;
+#endif
+ a1->ss_family = a2->ss_family = a3->ss_family = a4->ss_family = af;
+
+ if (af == AF_INET)
+ a1len = a2len = a3len = a4len = sizeof (struct sockaddr_in);
+ else
+ a1len = a2len = a3len = a4len = sizeof (struct sockaddr_in6);
+
+ if (af == AF_INET) {
+ TEST_1(inet_pton(af, "127.0.0.1", &sin3->sin_addr) > 0);
+ TEST_1(inet_pton(af, "127.0.0.1", &sin4->sin_addr) > 0);
+ } else {
+ }
+
+ TEST(bind(s3, (struct sockaddr *)a3, a3len), 0);
+ TEST(bind(s4, (struct sockaddr *)a4, a4len), 0);
+
+ alen = sizeof a;
+ TEST(getsockname(s3, (struct sockaddr *)a, &alen), 0);
+ sin3->sin_port = sin->sin_port;
+ memset(sin->sin_zero, 0, sizeof sin->sin_zero);
+ TEST(alen, a3len); TEST_M(a, a3, a3len);
+
+ alen = sizeof a;
+ TEST(getsockname(s4, (struct sockaddr *)a, &alen), 0);
+ sin4->sin_port = sin->sin_port;
+ memset(sin->sin_zero, 0, sizeof sin->sin_zero);
+ TEST(alen, a4len); TEST_M(a, a4, a4len);
+
+ TEST(connect(s1, sa3, a3len), 0);
+ TEST(getsockname(s1, (struct sockaddr *)a1, &a1len), 0);
+ TEST(connect(s2, sa4, a4len), 0);
+ TEST(getsockname(s2, (struct sockaddr *)a2, &a2len), 0);
+
+ TEST(sendto(s1, "foo", 3, 0, sa4, a4len), 3);
+ TEST(recvfrom(s4, buf, sizeof buf, 0, sa, &alen), 3);
+ TEST(sendto(s4, "bar", 3, 0, sa, alen), 3);
+ TEST(recvfrom(s2, buf, sizeof buf, 0, sa, &alen), -1);
+ TEST(recvfrom(s1, buf, sizeof buf, 0, sa, &alen), 3);
+
+ su_close(s1), su_close(s2), su_close(s3), su_close(s4);
+
+ break;
+ }
+
+ END();
+}
+
+#endif
+
+static unsigned offset;
+
+#define TEST_RUN(ctx) \
+ { sres_free_answers(ctx->resolver, ctx->result); ctx->result = NULL; \
+ ctx->query = NULL; run(ctx); TEST_1(ctx->query); }
+
+
+static
+int poll_sockets(sres_context_t *ctx)
+{
+ int i, n, events;
+
+ n = ctx->n_sockets;
+
+ events = poll(ctx->fds, ctx->n_sockets, ctx->timeout ? 50 : 500);
+
+ if (!events)
+ return events;
+
+ for (i = 0; i < n; i++) {
+ if (ctx->fds[i].revents & POLLERR)
+ sres_resolver_error(ctx->resolver, ctx->fds[i].fd);
+ if (ctx->fds[i].revents & POLLIN)
+ sres_resolver_receive(ctx->resolver, ctx->fds[i].fd);
+ }
+
+ return events;
+}
+
+#define BREAK(ctx) (ctx->ready = 1)
+static void run(sres_context_t *ctx)
+{
+ for (ctx->ready = 0; !ctx->ready; ) {
+ poll_sockets(ctx);
+
+ if (ctx->timeout) {
+ ctx->timeout <<= 1;
+ offset += ctx->timeout;
+ }
+
+ /* No harm is done (except wasted CPU) if timer is called more often */
+ sres_resolver_timer(ctx->resolver, -1);
+ }
+}
+
+int test_soa(sres_context_t *ctx)
+{
+ sres_resolver_t *res = ctx->resolver;
+ sres_record_t **result;
+ const sres_soa_record_t *rr_soa;
+
+ char const *domain = "example.com";
+
+ BEGIN();
+
+ TEST_1(sres_query(res, test_answer, ctx, sres_type_soa, domain));
+ TEST_RUN(ctx);
+
+ TEST_1(sres_query(res, test_answer, ctx, sres_type_soa, domain));
+ TEST_RUN(ctx);
+
+ TEST_1(result = sres_cached_answers(res, sres_type_soa, domain));
+
+ TEST_1(result != NULL);
+ TEST_1(result[0] != NULL);
+
+ rr_soa = result[0]->sr_soa;
+ TEST(rr_soa->soa_record->r_type, sres_type_soa);
+ TEST(rr_soa->soa_record->r_class, sres_class_in);
+
+ TEST_S(rr_soa->soa_mname, "ns.example.com.");
+ TEST_S(rr_soa->soa_rname, "root.example.com.");
+ TEST(rr_soa->soa_serial, 2002042901);
+ TEST(rr_soa->soa_refresh, 7200);
+ TEST(rr_soa->soa_retry, 600);
+ TEST(rr_soa->soa_expire, 36000000);
+ TEST(rr_soa->soa_minimum, 60);
+
+ sres_free_answers(res, result);
+
+ END();
+}
+
+int test_naptr(sres_context_t *ctx)
+{
+ sres_resolver_t *res = ctx->resolver;
+ sres_record_t **result;
+ const sres_naptr_record_t *rr;
+ char const *domain = "example.com";
+ int i;
+
+ BEGIN();
+
+ TEST_1(sres_query(res, test_answer, ctx, sres_type_naptr, domain));
+ TEST_RUN(ctx);
+
+ TEST_1(result = ctx->result);
+ TEST_1(result[0]);
+
+ for (i = 0; result[i] != NULL; i++) {
+ rr = (sres_naptr_record_t *) result[i]->sr_naptr;
+
+ switch(rr->na_order) {
+ case 20:
+ TEST(rr->na_record->r_type, sres_type_naptr);
+ TEST(rr->na_record->r_class, sres_class_in);
+ TEST(rr->na_record->r_ttl, 60);
+ TEST(rr->na_order, 20);
+ TEST(rr->na_prefer, 50);
+ TEST_S(rr->na_flags, "s");
+ TEST_S(rr->na_services, "SIPS+D2T");
+ TEST_S(rr->na_regexp, "");
+ TEST_S(rr->na_replace, "_sips._tcp.example.com.");
+ break;
+
+ case 40:
+ TEST(rr->na_record->r_type, sres_type_naptr);
+ TEST(rr->na_record->r_class, sres_class_in);
+ TEST(rr->na_record->r_ttl, 60);
+ TEST(rr->na_order, 40);
+ TEST(rr->na_prefer, 15);
+ TEST_S(rr->na_flags, "s");
+ TEST_S(rr->na_services, "SIP+D2U");
+ TEST_S(rr->na_regexp, "");
+ TEST_S(rr->na_replace, "_sip._udp.example.com.");
+ break;
+
+ case 50:
+ TEST(rr->na_record->r_type, sres_type_naptr);
+ TEST(rr->na_record->r_class, sres_class_in);
+ TEST(rr->na_record->r_ttl, 60);
+ TEST(rr->na_order, 50);
+ TEST(rr->na_prefer, 15);
+ TEST_S(rr->na_flags, "u");
+ TEST_S(rr->na_services, "TEST+D2U");
+ TEST_S(rr->na_regexp, "/(tst:([^@]+@))?example.com$/\\1operator.com/i");
+ TEST_S(rr->na_replace, ".");
+ break;
+
+ case 80:
+ TEST(rr->na_record->r_type, sres_type_naptr);
+ TEST(rr->na_record->r_class, sres_class_in);
+ TEST(rr->na_record->r_ttl, 60);
+ TEST(rr->na_order, 80);
+ TEST(rr->na_prefer, 25);
+ TEST_S(rr->na_flags, "s");
+ TEST_S(rr->na_services, "SIP+D2T");
+ TEST_S(rr->na_regexp, "");
+ TEST_S(rr->na_replace, "_sip._tcp.example.com.");
+ break;
+
+ default:
+ TEST_1(0);
+ }
+ }
+
+ sres_free_answers(res, ctx->result), ctx->result = NULL;
+
+ END();
+}
+
+char const longname[1026] =
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
+
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
+
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
+
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.";
+
+char name2048[2049] =
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
+ "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
+ "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
+ "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ "gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg"
+ "hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh"
+
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
+ "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
+ "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
+ "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ "gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg"
+ "hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh"
+
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
+ "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
+ "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
+ "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ "gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg"
+ "hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh"
+
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
+ "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
+ "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
+ "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ "gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg"
+ "hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh";
+
+int test_a(sres_context_t *ctx)
+{
+ sres_resolver_t *res = ctx->resolver;
+ sres_query_t *query;
+ sres_record_t **result;
+ const sres_a_record_t *rr_a;
+ char const *domain = "sip00.example.com";
+ char name1025[1026] =
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+
+ ".";
+
+ BEGIN();
+
+ TEST_1(!sres_query(res, test_answer, ctx, sres_type_a, name1025));
+
+ name1025[1024] = '\0';
+
+ TEST_1(!sres_query(res, test_answer, ctx, sres_type_a, name1025));
+
+ name1025[1023] = '\0';
+
+ TEST_1(!sres_query(res, test_answer, ctx, sres_type_a, name1025));
+
+ TEST_1(!sres_query(res, test_answer, ctx, sres_type_a, name2048));
+
+ query = sres_query(res, test_answer, ctx, sres_type_a, longname);
+ TEST_1(query);
+ sres_query_bind(query, NULL, NULL);
+
+ TEST_1(sres_query(res, test_answer, ctx, sres_type_a, domain));
+
+ TEST_RUN(ctx);
+
+ TEST_1(result = ctx->result);
+ TEST_1(result[0]);
+ TEST(result[0]->sr_record->r_status, 0);
+ TEST_1(rr_a = result[0]->sr_a);
+ TEST(rr_a->a_record->r_type, sres_type_a);
+ TEST(rr_a->a_record->r_class, sres_class_in);
+ TEST(rr_a->a_record->r_ttl, 60);
+
+ TEST_S(inet_ntoa(rr_a->a_addr), "194.2.188.133");
+
+ sres_free_answers(res, ctx->result), ctx->result = NULL;
+
+ TEST_1(result = sres_cached_answers(res, sres_type_a, domain));
+ TEST(result[0]->sr_record->r_status, 0);
+ TEST_1(rr_a = result[0]->sr_a);
+ TEST(rr_a->a_record->r_type, sres_type_a);
+ TEST(rr_a->a_record->r_class, sres_class_in);
+ TEST(rr_a->a_record->r_ttl, 60);
+ TEST_S(inet_ntoa(rr_a->a_addr), "194.2.188.133");
+
+ sres_free_answers(res, result);
+
+ /* Try sub-queries */
+ TEST_1(sres_search(res, test_answer, ctx, sres_type_a, "sip00"));
+
+ TEST_RUN(ctx);
+
+ TEST_1(result = ctx->result);
+
+ for (;*result; result++)
+ if (result[0]->sr_a->a_record->r_type == sres_type_a)
+ break;
+
+ TEST(result[0]->sr_record->r_status, 0);
+ TEST_1(rr_a = result[0]->sr_a);
+ TEST(rr_a->a_record->r_type, sres_type_a);
+ TEST(rr_a->a_record->r_class, sres_class_in);
+ TEST(rr_a->a_record->r_ttl, 60);
+ TEST_S(inet_ntoa(rr_a->a_addr), "194.2.188.133");
+
+ sres_free_answers(res, ctx->result), ctx->result = NULL;
+
+ /* Try missing domain */
+ TEST_1(sres_query(res, test_answer, ctx, sres_type_a,
+ "no-sip.example.com"));
+
+ TEST_RUN(ctx);
+
+ TEST_1(result = ctx->result);
+ TEST(result[0]->sr_record->r_status, SRES_NAME_ERR);
+ TEST_1(rr_a = result[0]->sr_a);
+ TEST(rr_a->a_record->r_type, sres_type_a);
+ TEST(rr_a->a_record->r_class, sres_class_in);
+ /* Error gets TTL from example.com SOA record minimum time */
+ TEST(rr_a->a_record->r_ttl, 60);
+
+ sres_free_answers(res, ctx->result), ctx->result = NULL;
+
+ /* Try domain without A record =>
+ we should get a record with SRES_RECORD_ERR */
+ TEST_1(sres_query(res, test_answer, ctx, sres_type_a,
+ "aaaa.example.com"));
+
+ TEST_RUN(ctx);
+
+ TEST_1(result = ctx->result);
+ TEST(result[0]->sr_record->r_status, SRES_RECORD_ERR);
+ TEST_1(rr_a = result[0]->sr_a);
+ TEST(rr_a->a_record->r_type, sres_type_a);
+ TEST(rr_a->a_record->r_class, sres_class_in);
+ /* Error gets TTL from example.com SOA record minimum time */
+ TEST(rr_a->a_record->r_ttl, 60);
+
+ sres_free_answers(res, ctx->result), ctx->result = NULL;
+
+ /* Cached search */
+ TEST_1(result = sres_search_cached_answers(res, sres_type_a, "sip00"));
+ TEST_1(rr_a = result[0]->sr_a);
+ TEST(rr_a->a_record->r_status, 0);
+ TEST_S(rr_a->a_record->r_name, "sip00.example.com.");
+ TEST(rr_a->a_record->r_type, sres_type_a);
+ TEST(rr_a->a_record->r_class, sres_class_in);
+ TEST(rr_a->a_record->r_ttl, 60);
+ TEST_S(inet_ntoa(rr_a->a_addr), "194.2.188.133");
+
+ if (result[1]) {
+ TEST(result[1]->sr_a->a_record->r_type, sres_type_a);
+ }
+
+ sres_free_answers(res, result), result = NULL;
+
+ /* Cached search */
+ TEST_1(result = sres_cached_answers(res, sres_type_a, "no-sip.example.com"));
+ TEST_1(rr_a = result[0]->sr_a);
+ TEST(rr_a->a_record->r_status, SRES_NAME_ERR);
+ TEST(rr_a->a_record->r_type, sres_type_a);
+ TEST(rr_a->a_record->r_class, sres_class_in);
+
+ sres_free_answers(res, result), result = NULL;
+
+ END();
+}
+
+#if HAVE_SIN6
+int test_a6(sres_context_t *ctx)
+{
+ sres_resolver_t *res = ctx->resolver;
+ sres_record_t **result;
+ const sres_a6_record_t *rr_a6;
+ char buf[50] = {0};
+ char const *domain = "oldns.example.com";
+
+ BEGIN();
+
+ TEST_1(sres_query(res, test_answer, ctx, sres_type_a6, domain));
+ TEST_RUN(ctx);
+
+ TEST_1(result = ctx->result);
+ TEST_1(result[0]);
+
+ rr_a6 = result[0]->sr_a6;
+ TEST(rr_a6->a6_record->r_type, sres_type_a6);
+ TEST(rr_a6->a6_record->r_class, sres_class_in);
+ TEST(rr_a6->a6_record->r_ttl, 60);
+ TEST(rr_a6->a6_prelen, 0);
+
+ TEST_S(inet_ntop(AF_INET6, &rr_a6->a6_suffix, buf, sizeof(buf)),
+ "3ffe:1200:3012:c000:210:a4ff:fe8d:6a46");
+
+ TEST_P(rr_a6->a6_prename, NULL);
+
+ sres_free_answers(res, ctx->result), ctx->result = NULL;
+
+ TEST_1(result = sres_cached_answers(res, sres_type_a6, domain));
+ TEST_1(rr_a6 = result[0]->sr_a6);
+ TEST(rr_a6->a6_record->r_type, sres_type_a6);
+ TEST(rr_a6->a6_record->r_class, sres_class_in);
+ TEST(rr_a6->a6_record->r_ttl, 60);
+ TEST(rr_a6->a6_prelen, 0);
+
+ TEST_S(inet_ntop(AF_INET6, &rr_a6->a6_suffix, buf, sizeof(buf)),
+ "3ffe:1200:3012:c000:210:a4ff:fe8d:6a46");
+
+ TEST_P(rr_a6->a6_prename, NULL);
+
+ sres_free_answers(res, result), result = NULL;
+
+ END();
+}
+
+int test_a6_prefix(sres_context_t *ctx)
+{
+ sres_resolver_t *res = ctx->resolver;
+ sres_record_t **result;
+ const sres_a6_record_t *rr_a6;
+ char buf[50] = {0};
+ char const *domain = "a6.example.com";
+
+ BEGIN();
+
+ TEST_1(sres_query(res, test_answer, ctx, sres_type_a6, domain));
+ TEST_RUN(ctx);
+
+ TEST_1(result = ctx->result);
+ TEST_1(rr_a6 = result[0]->sr_a6);
+ TEST(rr_a6->a6_record->r_type, sres_type_a6);
+ TEST(rr_a6->a6_record->r_class, sres_class_in);
+ TEST(rr_a6->a6_record->r_ttl, 60);
+ TEST(rr_a6->a6_prelen, 64);
+
+ TEST_S(inet_ntop(AF_INET6, &rr_a6->a6_suffix, buf, sizeof(buf)),
+ "::a08:20ff:fe7d:e7ac");
+
+ TEST_S(rr_a6->a6_prename, "mynet.example.com.");
+
+ sres_free_answers(res, ctx->result), ctx->result = NULL;
+
+ /* Check parsing of special case: no prefix */
+ TEST_1(sres_query(res, test_answer, ctx, sres_type_a6, "full.example.com"));
+ TEST_RUN(ctx);
+
+ TEST_1(result = ctx->result);
+ TEST_1(rr_a6 = result[0]->sr_a6);
+ TEST(rr_a6->a6_record->r_type, sres_type_a6);
+ TEST(rr_a6->a6_record->r_class, sres_class_in);
+ TEST(rr_a6->a6_record->r_ttl, 60);
+ TEST(rr_a6->a6_prelen, 0);
+ TEST_S(inet_ntop(AF_INET6, &rr_a6->a6_suffix, buf, sizeof(buf)),
+ "3ff0:12:3012:c006:a08:20ff:fe7d:e7ac");
+ TEST_P(rr_a6->a6_prename, NULL);
+
+ sres_free_answers(res, ctx->result), ctx->result = NULL;
+
+ /* Check parsing of special case: no suffix */
+ TEST_1(sres_query(res, test_answer, ctx, sres_type_a6, "alias6.example.com"));
+ TEST_RUN(ctx);
+
+ TEST_1(result = ctx->result);
+ TEST_1(rr_a6 = result[0]->sr_a6);
+ TEST(rr_a6->a6_record->r_type, sres_type_a6);
+ TEST(rr_a6->a6_record->r_class, sres_class_in);
+ TEST(rr_a6->a6_record->r_ttl, 60);
+ TEST(rr_a6->a6_prelen, 128);
+ TEST_S(inet_ntop(AF_INET6, &rr_a6->a6_suffix, buf, sizeof(buf)), "::");
+ TEST_S(rr_a6->a6_prename, "a6.example.com.");
+
+ sres_free_answers(res, ctx->result), ctx->result = NULL;
+
+ TEST_1(result = sres_cached_answers(res, sres_type_a6, domain));
+
+ TEST_1(rr_a6 = result[0]->sr_a6);
+ TEST(rr_a6->a6_record->r_type, sres_type_a6);
+ TEST(rr_a6->a6_record->r_class, sres_class_in);
+ TEST(rr_a6->a6_record->r_ttl, 60);
+ TEST(rr_a6->a6_prelen, 64);
+
+ TEST_S(inet_ntop(AF_INET6, &rr_a6->a6_suffix, buf, sizeof(buf)),
+ "::a08:20ff:fe7d:e7ac");
+
+ TEST_S(rr_a6->a6_prename, "mynet.example.com.");
+
+ sres_free_answers(res, result), result = NULL;
+
+ END();
+}
+
+int test_aaaa(sres_context_t *ctx)
+{
+ sres_resolver_t *res = ctx->resolver;
+ sres_record_t **result;
+ const sres_aaaa_record_t *rr_aaaa;
+ char buf[50] = {0};
+ char const *domain = "sip03.example.com";
+
+ BEGIN();
+
+ TEST_1(sres_query(res, test_answer, ctx, sres_type_aaaa, domain));
+ TEST_RUN(ctx);
+
+ TEST_1(result = ctx->result);
+ TEST_1(rr_aaaa = result[0]->sr_aaaa);
+ TEST(rr_aaaa->aaaa_record->r_type, sres_type_aaaa);
+ TEST(rr_aaaa->aaaa_record->r_class, sres_class_in);
+ TEST(rr_aaaa->aaaa_record->r_ttl, 60);
+
+ TEST_S(inet_ntop(AF_INET6, &rr_aaaa->aaaa_addr, buf, sizeof(buf)),
+ "3ffe:1200:3012:c000:206:5bff:fe55:4630");
+
+ sres_free_answers(res, ctx->result), ctx->result = NULL;
+
+ TEST_1(result = sres_cached_answers(res, sres_type_aaaa, domain));
+
+ TEST_1(rr_aaaa = result[0]->sr_aaaa);
+ TEST(rr_aaaa->aaaa_record->r_type, sres_type_aaaa);
+ TEST(rr_aaaa->aaaa_record->r_class, sres_class_in);
+ TEST(rr_aaaa->aaaa_record->r_ttl, 60);
+
+ TEST_S(inet_ntop(AF_INET6, &rr_aaaa->aaaa_addr, buf, sizeof(buf)),
+ "3ffe:1200:3012:c000:206:5bff:fe55:4630");
+
+ sres_free_answers(res, result), result = NULL;
+
+ END();
+}
+#endif /* HAVE_SIN6 */
+
+int test_srv(sres_context_t *ctx)
+{
+ sres_resolver_t *res = ctx->resolver;
+ sres_record_t **result;
+ const sres_srv_record_t *rr;
+ char const *domain = "_sips._tcp.example.com";
+ int i;
+
+ BEGIN();
+
+ TEST_1(sres_query(res, test_answer, ctx, sres_type_srv, domain));
+ TEST_RUN(ctx);
+
+ TEST_1(result = ctx->result);
+
+ for (i = 0; result[i] != NULL; i++) {
+ TEST_1(rr = (sres_srv_record_t *) result[i]->sr_srv);
+
+ switch(rr->srv_priority) {
+ case 3:
+ TEST(rr->srv_record->r_type, sres_type_srv);
+ TEST(rr->srv_record->r_class, sres_class_in);
+ TEST(rr->srv_record->r_ttl, 60);
+ TEST(rr->srv_weight, 100);
+ TEST(rr->srv_port, 5061);
+ TEST_S(rr->srv_target, "sip00.example.com.");
+ break;
+
+ case 4:
+ TEST(rr->srv_record->r_type, sres_type_srv);
+ TEST(rr->srv_record->r_class, sres_class_in);
+ TEST(rr->srv_record->r_ttl, 60);
+ TEST(rr->srv_weight, 50);
+ TEST(rr->srv_port, 5050);
+ TEST_S(rr->srv_target, "sip02.example.com.");
+ break;
+
+ case 5:
+ TEST(rr->srv_record->r_type, sres_type_srv);
+ TEST(rr->srv_record->r_class, sres_class_in);
+ TEST(rr->srv_record->r_ttl, 60);
+ TEST(rr->srv_weight, 10);
+ TEST(rr->srv_port, 5060);
+ TEST_S(rr->srv_target, "sip01.example.com.");
+ break;
+
+ default:
+ TEST_1(0);
+ }
+ }
+
+ sres_free_answers(res, ctx->result), ctx->result = NULL;
+
+ TEST_1(result = sres_cached_answers(res, sres_type_srv, domain));
+
+ for (i = 0; result[i] != NULL; i++) {
+ TEST_1(rr = (sres_srv_record_t *) result[i]->sr_srv);
+
+ switch(rr->srv_priority) {
+ case 3:
+ TEST(rr->srv_record->r_type, sres_type_srv);
+ TEST(rr->srv_record->r_class, sres_class_in);
+ TEST(rr->srv_record->r_ttl, 60);
+ TEST(rr->srv_weight, 100);
+ TEST(rr->srv_port, 5061);
+ TEST_S(rr->srv_target, "sip00.example.com.");
+ break;
+
+ case 4:
+ TEST(rr->srv_record->r_type, sres_type_srv);
+ TEST(rr->srv_record->r_class, sres_class_in);
+ TEST(rr->srv_record->r_ttl, 60);
+ TEST(rr->srv_weight, 50);
+ TEST(rr->srv_port, 5050);
+ TEST_S(rr->srv_target, "sip02.example.com.");
+ break;
+
+ case 5:
+ TEST(rr->srv_record->r_type, sres_type_srv);
+ TEST(rr->srv_record->r_class, sres_class_in);
+ TEST(rr->srv_record->r_ttl, 60);
+ TEST(rr->srv_weight, 10);
+ TEST(rr->srv_port, 5060);
+ TEST_S(rr->srv_target, "sip01.example.com.");
+ break;
+
+ default:
+ TEST_1(0);
+ }
+ }
+
+ sres_free_answers(res, result), result = NULL;
+
+ END();
+}
+
+int test_cname(sres_context_t *ctx)
+{
+ sres_resolver_t *res = ctx->resolver;
+ sres_record_t **result;
+ const sres_cname_record_t *rr;
+ char const *domain = "sip.example.com";
+
+ BEGIN();
+
+ TEST_1(sres_query(res, test_answer, ctx, sres_type_a, domain));
+ TEST_RUN(ctx);
+
+ TEST_1(result = ctx->result);
+ TEST_1(rr = result[0]->sr_cname);
+ TEST(rr->cn_record->r_class, sres_class_in);
+ TEST(rr->cn_record->r_type, sres_type_cname);
+ TEST(rr->cn_record->r_ttl, 60);
+ TEST_S(rr->cn_cname, "sip00.example.com.");
+
+ sres_free_answers(res, ctx->result), ctx->result = NULL;
+
+ END();
+}
+
+int test_ptr_ipv4(sres_context_t *ctx)
+{
+ sres_resolver_t *res = ctx->resolver;
+ sres_record_t **result;
+ const sres_ptr_record_t *rr;
+ char const *domain = "1.0.0.127.in-addr.arpa";
+
+ BEGIN();
+
+ TEST_1(sres_query(res, test_answer, ctx, sres_type_ptr, domain));
+ TEST_RUN(ctx);
+
+ result = ctx->result;
+ TEST_1(result != NULL);
+ TEST_1(result[0] != NULL);
+
+ rr = result[0]->sr_ptr;
+ TEST_1(rr != NULL);
+ TEST(rr->ptr_record->r_class, sres_class_in);
+ TEST(rr->ptr_record->r_type, sres_type_ptr);
+ TEST_S(rr->ptr_domain, "localhost.");
+
+ END();
+}
+
+int test_ptr_ipv4_sockaddr(sres_context_t *ctx)
+{
+ sres_resolver_t *res = ctx->resolver;
+ sres_record_t **result;
+ sres_query_t *query;
+ const sres_ptr_record_t *rr;
+ struct sockaddr_in sin = {0};
+
+ inet_pton(AF_INET, "127.0.0.1", &sin.sin_addr);
+ sin.sin_family = AF_INET;
+
+ BEGIN();
+
+ query = sres_query_sockaddr(res, test_answer, ctx,
+ sres_qtype_any, (struct sockaddr*)&sin);
+ TEST_1(query != NULL);
+
+ TEST_RUN(ctx);
+
+ result = ctx->result;
+
+ TEST_1(result != NULL);
+ TEST_1(result[0] != NULL);
+
+ rr = result[0]->sr_ptr;
+ TEST_1(rr != NULL);
+ TEST(rr->ptr_record->r_type, sres_type_ptr);
+ TEST(rr->ptr_record->r_class, sres_class_in);
+ TEST_S(rr->ptr_domain, "localhost.");
+
+ END();
+}
+
+#if HAVE_SIN6
+int test_ptr_ipv6(sres_context_t *ctx)
+{
+ sres_resolver_t *res = ctx->resolver;
+ sres_record_t **result;
+ const sres_ptr_record_t *rr;
+ char const *domain =
+ "c.a.7.e.d.7.e.f.f.f.0.2.8.0.a.0.0.0.0.c.2.1.0.3.0.0.2.1.e.f.f.3.ip6.int";
+
+ BEGIN();
+
+ TEST_1(sres_query(res, test_answer, ctx, sres_type_ptr, domain));
+ TEST_RUN(ctx);
+
+ result = ctx->result;
+
+ TEST_1(result != NULL);
+ TEST_1(result[0] != NULL);
+
+ rr = result[0]->sr_ptr;
+ TEST_1(rr != NULL);
+ TEST(rr->ptr_record->r_type, sres_type_ptr);
+ TEST(rr->ptr_record->r_class, sres_class_in);
+ TEST_S(rr->ptr_domain, "sip01.example.com.");
+
+ END();
+}
+
+int test_ptr_ipv6_sockaddr(sres_context_t *ctx)
+{
+ sres_resolver_t *res = ctx->resolver;
+ sres_record_t **result;
+ const sres_ptr_record_t *rr;
+ struct sockaddr_in6 sin6 = {0};
+
+ BEGIN();
+
+ inet_pton(AF_INET6, "3ffe:1200:3012:c000:0a08:20ff:fe7d:e7ac",
+ &sin6.sin6_addr);
+
+ sin6.sin6_family = AF_INET6;
+
+ ctx->query =
+ sres_query_sockaddr(res, test_answer, ctx,
+ sres_type_ptr, (struct sockaddr*)&sin6);
+ TEST_1(ctx->query != NULL);
+
+ TEST_RUN(ctx);
+
+ result = ctx->result;
+
+ TEST_1(result != NULL);
+ TEST_1(result[0] != NULL);
+
+ rr = result[0]->sr_ptr;
+ TEST_1(rr != NULL);
+ TEST(rr->ptr_record->r_type, sres_type_ptr);
+ TEST(rr->ptr_record->r_class, sres_class_in);
+ TEST_S(rr->ptr_domain, "sip01.example.com.");
+
+ END();
+}
+#endif /* HAVE_SIN6 */
+
+/* Test sres_cached_answers(), sres_sort_answers(), sres_free_answers() */
+int test_cache(sres_context_t *ctx)
+{
+ sres_resolver_t *res = ctx->resolver;
+ int ok = 0;
+ sres_record_t *sort_array[3];
+ sres_record_t **result;
+ sres_query_t *query;
+ const sres_record_t *rr = NULL;
+ const sres_a6_record_t *rr_a6;
+ const sres_aaaa_record_t *rr_aaaa;
+ const sres_cname_record_t *rr_cname;
+ const sres_ptr_record_t *rr_ptr;
+#if HAVE_SIN6
+ struct sockaddr_in6 sin6 = {0};
+#endif
+ char const *domain;
+ char buf[50] = {0};
+ int i, j;
+
+ BEGIN();
+
+ sres_query(res, test_answer_multi, ctx,
+ sres_qtype_any, "example.com");
+
+ sres_query(res, test_answer_multi, ctx,
+ sres_qtype_any, "_sips._tcp.example.com");
+
+ sres_query(res, test_answer_multi, ctx,
+ sres_qtype_any, "sip.example.com");
+
+ sres_query(res, test_answer_multi, ctx,
+ sres_qtype_any, "subnet.example.com");
+
+#if HAVE_SIN6
+ sres_query(res, test_answer_multi, ctx,
+ sres_type_aaaa, "mgw02.example.com");
+
+ inet_pton(AF_INET6,
+ "3ffe:1200:3012:c000:0a08:20ff:fe7d:e7ac",
+ &sin6.sin6_addr);
+
+ sin6.sin6_family = AF_INET6;
+
+ query = sres_query_sockaddr(res, test_answer_multi, ctx,
+ sres_qtype_any, (struct sockaddr *)&sin6);
+
+ TEST_1(query != NULL);
+#endif
+
+ TEST_RUN(ctx);
+
+ /* For a chance, a fully qualified domain name with final "." */
+ domain = "example.com.";
+
+ result = sres_cached_answers(res,
+ sres_qtype_any,
+ domain);
+
+ TEST_1(result != NULL);
+
+ for (i = 0; result[i] != NULL; i++) {
+ rr = result[i];
+
+ if (rr->sr_record->r_type == sres_type_naptr) {
+ const sres_naptr_record_t *rr_naptr = rr->sr_naptr;
+ switch(rr_naptr->na_order) {
+ case 20:
+ TEST(rr_naptr->na_record->r_type, sres_type_naptr);
+ TEST(rr_naptr->na_record->r_class, sres_class_in);
+ TEST(rr_naptr->na_record->r_ttl, 60);
+ TEST(rr_naptr->na_order, 20);
+ TEST(rr_naptr->na_prefer, 50);
+ TEST_S(rr_naptr->na_flags, "s");
+ TEST_S(rr_naptr->na_services, "SIPS+D2T");
+ TEST_S(rr_naptr->na_regexp, "");
+ TEST_S(rr_naptr->na_replace, "_sips._tcp.example.com.");
+ ok |= 1;
+ break;
+
+ case 40:
+ TEST(rr_naptr->na_record->r_type, sres_type_naptr);
+ TEST(rr_naptr->na_record->r_class, sres_class_in);
+ TEST(rr_naptr->na_record->r_ttl, 60);
+ TEST(rr_naptr->na_order, 40);
+ TEST(rr_naptr->na_prefer, 15);
+ TEST_S(rr_naptr->na_flags, "s");
+ TEST_S(rr_naptr->na_services, "SIP+D2U");
+ TEST_S(rr_naptr->na_regexp, "");
+ TEST_S(rr_naptr->na_replace, "_sip._udp.example.com.");
+ ok |= 2;
+ break;
+
+ case 50:
+ TEST(rr_naptr->na_record->r_type, sres_type_naptr);
+ TEST(rr_naptr->na_record->r_class, sres_class_in);
+ TEST(rr_naptr->na_record->r_ttl, 60);
+ TEST(rr_naptr->na_order, 50);
+ TEST(rr_naptr->na_prefer, 15);
+ TEST_S(rr_naptr->na_flags, "u");
+ TEST_S(rr_naptr->na_services, "TEST+D2U");
+
+ TEST_S(rr_naptr->na_regexp,
+ "/(tst:([^@]+@))?example.com$/\\1operator.com/i");
+
+ TEST_S(rr_naptr->na_replace, ".");
+ break;
+
+ case 80:
+ TEST(rr_naptr->na_record->r_type, sres_type_naptr);
+ TEST(rr_naptr->na_record->r_class, sres_class_in);
+ TEST(rr_naptr->na_record->r_ttl, 60);
+ TEST(rr_naptr->na_order, 80);
+ TEST(rr_naptr->na_prefer, 25);
+ TEST_S(rr_naptr->na_flags, "s");
+ TEST_S(rr_naptr->na_services, "SIP+D2T");
+ TEST_S(rr_naptr->na_regexp, "");
+ TEST_S(rr_naptr->na_replace, "_sip._tcp.example.com.");
+ ok |= 4;
+ break;
+
+ default:
+ TEST_1(0);
+ }
+ }
+ }
+
+ TEST(ok, 7);
+
+ /* Reverse order before sorting */
+ for (j = 0; j < --i; j++) {
+ sres_record_t *swap = result[j];
+ result[j] = result[i];
+ result[i] = swap;
+ }
+
+ /* Test sorting */
+ sres_sort_answers(res, result);
+
+ /* Sort all records with themselves */
+ for (i = 0; result[i]; i++) {
+ sort_array[0] = result[i], sort_array[1] = result[i], sort_array[2] = NULL;
+ sres_sort_answers(res, sort_array);
+ }
+
+ /* Test free */
+ for (i = 0; result[i]; i++) {
+ sres_free_answer(res, result[i]);
+ result[i] = NULL;
+ }
+
+ /* Test sres_free_answers() */
+ sres_free_answers(res, result);
+
+ result = sres_cached_answers(res,
+ sres_qtype_any,
+ "_sips._tcp.example.com");
+
+ TEST_1(result != NULL);
+
+ ok = 0;
+
+ for (i = 0; result[i] != NULL; i++) {
+ sres_srv_record_t *rr_srv = result[i]->sr_srv;
+
+ TEST(rr_srv->srv_record->r_type, sres_type_srv);
+ switch(rr_srv->srv_priority) {
+ case 3:
+ TEST(rr_srv->srv_record->r_type, sres_type_srv);
+ TEST(rr_srv->srv_record->r_class, sres_class_in);
+ TEST(rr_srv->srv_record->r_ttl, 60);
+ TEST(rr_srv->srv_weight, 100);
+ TEST(rr_srv->srv_port, 5061);
+ TEST_S(rr_srv->srv_target, "sip00.example.com.");
+ ok |= 1;
+ break;
+
+ case 4:
+ TEST(rr_srv->srv_record->r_type, sres_type_srv);
+ TEST(rr_srv->srv_record->r_class, sres_class_in);
+ TEST(rr_srv->srv_record->r_ttl, 60);
+ TEST(rr_srv->srv_weight, 50);
+ TEST(rr_srv->srv_port, 5050);
+ TEST_S(rr_srv->srv_target, "sip02.example.com.");
+ ok |= 2;
+ break;
+
+ case 5:
+ TEST(rr_srv->srv_record->r_type, sres_type_srv);
+ TEST(rr_srv->srv_record->r_class, sres_class_in);
+ TEST(rr_srv->srv_record->r_ttl, 60);
+ TEST(rr_srv->srv_weight, 10);
+ TEST(rr_srv->srv_port, 5060);
+ TEST_S(rr_srv->srv_target, "sip01.example.com.");
+ ok |= 4;
+ break;
+
+ default:
+ TEST_1(0);
+ }
+ }
+
+ TEST(ok, 7);
+
+ /* Reverse order before sorting */
+ for (j = 0; j < --i; j++) {
+ sres_record_t *swap = result[j];
+ result[j] = result[i];
+ result[i] = swap;
+ }
+
+ sres_sort_answers(res, result);
+ sres_free_answers(res, result);
+
+ domain = "sip.example.com";
+ result = sres_cached_answers(res,
+ sres_qtype_any,
+ domain);
+
+ TEST_1(result != NULL);
+ TEST_1(result[0] != NULL);
+
+ rr_cname = result[0]->sr_cname;
+ TEST(rr_cname->cn_record->r_type, sres_type_cname);
+ TEST(rr_cname->cn_record->r_class, sres_class_in);
+ TEST(rr_cname->cn_record->r_ttl, 60);
+ TEST_S(rr_cname->cn_cname, "sip00.example.com.");
+
+ sres_free_answers(res, result);
+
+#if HAVE_SIN6
+ domain = "subnet.example.com";
+ result = sres_cached_answers(res,
+ sres_qtype_any,
+ domain);
+
+ TEST_1(result != NULL);
+ TEST_1(result[0] != NULL);
+
+ rr_a6 = result[0]->sr_a6;
+ TEST(rr_a6->a6_record->r_type, sres_type_a6);
+ TEST(rr_a6->a6_record->r_class, sres_class_in);
+ TEST(rr_a6->a6_record->r_ttl, 60);
+ TEST(rr_a6->a6_prelen, 0);
+
+ TEST_S(inet_ntop(AF_INET6, &rr_a6->a6_suffix, buf, sizeof(buf)), "3ff0::");
+
+ TEST_P(rr_a6->a6_prename, NULL);
+
+ sres_free_answers(res, result);
+
+ domain = "mgw02.example.com";
+ TEST_1(result = sres_cached_answers(res, sres_type_aaaa, domain));
+ TEST_1(rr_aaaa = result[0]->sr_aaaa);
+ TEST(rr_aaaa->aaaa_record->r_type, sres_type_aaaa);
+ TEST(rr_aaaa->aaaa_record->r_class, sres_class_in);
+ TEST(rr_aaaa->aaaa_record->r_ttl, 60);
+ TEST_S(inet_ntop(AF_INET6, &rr_aaaa->aaaa_addr, buf, sizeof(buf)),
+ "3ffe:1200:3012:c000:206:5bff:fe55:462f");
+ sres_free_answers(res, result);
+
+ result = sres_cached_answers_sockaddr(res,
+ sres_type_ptr,
+ (struct sockaddr *)&sin6);
+
+ TEST_1(result != NULL);
+
+ rr_ptr = result[0]->sr_ptr;
+ TEST_1(rr_ptr != NULL);
+
+ TEST(rr_ptr->ptr_record->r_type, sres_type_ptr);
+ TEST(rr_ptr->ptr_record->r_class, sres_class_in);
+ TEST_S(rr_ptr->ptr_domain, "sip01.example.com.");
+
+ sres_free_answers(res, result);
+#endif /* HAVE_SIN6 */
+
+ END();
+}
+
+#if HAVE_SIN6
+int test_query_one_type(sres_context_t *ctx)
+{
+ sres_resolver_t *res = ctx->resolver;
+ sres_record_t **result;
+ const sres_aaaa_record_t *rr_aaaa;
+ char buf[50] = {0};
+
+ BEGIN();
+
+ TEST_1(sres_query(res, test_answer, ctx,
+ sres_type_aaaa, "mgw02.example.com"));
+ TEST_RUN(ctx);
+ TEST_1(result = ctx->result);
+ TEST_1(result[0] != NULL);
+
+ TEST_1(rr_aaaa = result[0]->sr_aaaa);
+ TEST(rr_aaaa->aaaa_record->r_type, sres_type_aaaa);
+ TEST(rr_aaaa->aaaa_record->r_class, sres_class_in);
+ TEST(rr_aaaa->aaaa_record->r_ttl, 60);
+ TEST_S(inet_ntop(AF_INET6, &rr_aaaa->aaaa_addr, buf, sizeof(buf)),
+ "3ffe:1200:3012:c000:206:5bff:fe55:462f");
+
+ TEST_P(result[1], NULL);
+
+ END();
+}
+#endif /* HAVE_SIN6*/
+
+#ifdef _WIN32
+#include <fcntl.h>
+#endif
+
+int sink_make(sres_context_t *ctx)
+{
+ char *tmpdir = getenv("TMPDIR");
+ char *template;
+ int fd, sink;
+ struct sockaddr_in sin[1];
+ socklen_t sinsize = sizeof sin;
+ FILE *f;
+
+ BEGIN();
+
+ sink = socket(AF_INET, SOCK_DGRAM, 0); TEST_1(sink != -1);
+ TEST(getsockname(sink, (struct sockaddr *)sin, &sinsize), 0);
+ sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ TEST(bind(sink, (struct sockaddr *)sin, sinsize), 0);
+ TEST(getsockname(sink, (struct sockaddr *)sin, &sinsize), 0);
+
+ ctx->sink = sink;
+
+ template = su_sprintf(ctx->home, "%s/test_sresolv.XXXXXX",
+ tmpdir ? tmpdir : "/tmp");
+ TEST_1(template);
+
+#ifndef _WIN32
+ fd = mkstemp(template); TEST_1(fd != -1);
+#else
+ fd = open(template, O_WRONLY); TEST_1(fd != -1);
+#endif
+
+ f = fdopen(fd, "w"); TEST_1(f);
+ fprintf(f,
+ "domain example.com\n"
+ "search foo.bar.com\n"
+ "port %u\n",
+ ntohs(sin->sin_port));
+ fclose(f);
+
+ ctx->sinkconf = template;
+
+ END();
+}
+
+#if 0
+int recv_sink(su_root_magic_t *rm, su_wait_t *w, sres_context_t *ctx)
+{
+ union {
+ char bytes[8192];
+ unsigned short shorts[4096];
+ } buffer[1];
+
+ su_wait_events(w, ctx->sink);
+ recv(ctx->sink, buffer->bytes, sizeof buffer, 0);
+
+ return 0;
+}
+
+int sink_init(sres_context_t *ctx)
+{
+ su_wait_t w[1];
+ BEGIN();
+
+ TEST(su_wait_create(w, ctx->sink, SU_WAIT_IN), 0);
+ ctx->sinkidx = su_root_register(ctx->root, w, recv_sink, ctx, 0);
+ TEST_1(ctx->sinkidx != 0);
+
+ END();
+}
+
+int sink_deinit(sres_context_t *ctx)
+{
+ BEGIN();
+
+ if (ctx->sinkidx)
+ su_root_deregister(ctx->root, ctx->sinkidx);
+ ctx->sinkidx = 0;
+ su_close(ctx->sink), ctx->sink = -1;
+
+ END();
+}
+#endif
+
+int test_timeout(sres_context_t *ctx)
+{
+ sres_resolver_t *res = ctx->resolver;
+ sres_record_t **result;
+ /* const sres_soa_record_t *rr_soa; */
+ char const *domain = "test";
+
+ BEGIN();
+
+ sres_query(res, test_answer, ctx, sres_type_a, domain);
+
+ ctx->timeout = 1;
+ TEST_RUN(ctx);
+ ctx->timeout = 0;
+
+ TEST_P(ctx->result, NULL);
+
+ result = sres_cached_answers(res, sres_type_a, domain);
+
+#if 0
+ TEST_1(result); TEST_1(result[0] != NULL);
+
+ rr_soa = result[0]->sr_soa;
+ TEST(rr_soa->soa_record->r_type, sres_type_soa);
+ TEST(rr_soa->soa_record->r_class, sres_class_in);
+ TEST_S(rr_soa->soa_record->r_name, "example.com.");
+ TEST(rr_soa->soa_record->r_status, SRES_TIMEOUT_ERR);
+
+ sres_free_answers(res, result);
+#else
+ /* Currently, we do not create error records */
+ TEST_1(result == NULL);
+#endif
+
+ END();
+}
+
+static void test_answer(sres_context_t *ctx,
+ sres_query_t *q,
+ sres_record_t **answer)
+{
+ ctx->query = q;
+ if (ctx->result)
+ sres_free_answers(ctx->resolver, ctx->result);
+ ctx->result = answer;
+ BREAK(ctx);
+}
+
+static void test_answer_multi(sres_context_t *ctx,
+ sres_query_t *q,
+ sres_record_t **answer)
+{
+ static int count = 0;
+
+ ctx->query = q;
+
+ count++;
+
+ sres_free_answers(ctx->resolver, answer);
+
+ if (count == 6)
+ BREAK(ctx);
+}
+
+#include <sys/time.h>
+
+/* Fake time() implementation, used by sresolv library */
+time_t time(time_t *tp)
+{
+ struct timeval tv[1];
+
+#ifndef _WIN32
+ gettimeofday(tv, NULL);
+#else
+ return 0;
+#endif
+
+ if (tp)
+ *tp = tv->tv_sec + offset;
+
+ return tv->tv_sec + offset;
+}
+
+int test_expiration(sres_context_t *ctx)
+{
+ sres_resolver_t *res = ctx->resolver;
+ sres_record_t **result;
+ char const *domain = "example.com";
+
+ BEGIN();
+
+ offset = 3600; /* Time suddenly proceeds by an hour.. */
+
+ sres_resolver_timer(res, -1);
+
+ result = sres_cached_answers(res, sres_qtype_any, domain);
+
+ TEST_P(result, NULL); /* the cache should be empty after 15 secs */
+
+ END();
+}
+
+#define is_hexdigit(c) ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f'))
+#define hex(c) ((c >= '0' && c <= '9') ? (c - '0') : (c - 'a' + 10))
+
+/* Convert lowercase hex to binary */
+static
+void *hex2bin(char const *test_name,
+ char const *hex1, char const *hex2, unsigned *binsize)
+{
+ char output[2048];
+ char *bin;
+ char const *b;
+ int j;
+
+ if (hex1 == NULL || binsize == NULL)
+ return NULL;
+
+ for (b = hex1, j = 0; b;) {
+ while (b[0]) {
+ if (is_hexdigit(b[0])) {
+ if (!is_hexdigit(b[1])) {
+ fprintf(stderr, "%s: hex2bin: invalid hex '%c'\n", test_name, b[1]);
+ exit(2);
+ }
+
+ output[j++] = (hex(b[0]) << 4) | hex(b[1]);
+ if (j == sizeof(output)) {
+ fprintf(stderr, "%s:%u: hex2bin: buffer too small\n",
+ __FILE__, __LINE__);
+ exit(2);
+ }
+ b++;
+ } else if (b[0] != ' ') {
+ fprintf(stderr, "%s: hex2bin: invalid nonhex '%c'\n", test_name,
+ b[0]);
+ exit(2);
+ }
+ b++;
+ }
+ b = hex2, hex2 = NULL;
+ }
+
+ bin = malloc(j);
+ if (bin == NULL)
+ perror("malloc"), exit(2);
+
+ return memcpy(bin, output, *binsize = j);
+}
+
+static char const hextest[] =
+ " 34 44 85 80 00 01 00 04 "
+ "00 01 00 08 07 65 78 61 6d 70 6c 65 03 63 6f 6d "
+ "00 00 23 00 01 c0 0c 00 23 00 01 00 00 00 3c 00 "
+ "26 00 28 00 0f 01 73 07 53 49 50 2b 44 32 55 00 "
+ "04 5f 73 69 70 04 5f 75 64 70 07 65 78 61 6d 70 "
+ "6c 65 03 63 6f 6d 00 c0 42 00 23 00 01 00 00 00 "
+ "3c 00 3e 00 32 00 0f 01 75 08 54 45 53 54 2b 44 "
+ "32 55 2d 2f 28 74 73 74 3a 28 5b 5e 40 5d 2b 40 "
+ "29 29 3f 65 78 61 6d 70 6c 65 2e 63 6f 6d 24 2f "
+ "5c 31 6f 70 65 72 61 74 6f 72 2e 63 6f 6d 2f 69 "
+ "00 c0 42 00 23 00 01 00 00 00 3c 00 26 00 50 00 "
+ "19 01 73 07 53 49 50 2b 44 32 54 00 04 5f 73 69 "
+ "70 04 5f 74 63 70 07 65 78 61 6d 70 6c 65 03 63 "
+ "6f 6d 00 c0 be 00 23 00 01 00 00 00 3c 00 28 00 "
+ "14 00 32 01 73 08 53 49 50 53 2b 44 32 54 00 05 "
+ "5f 73 69 70 73 04 5f 74 63 70 07 65 78 61 6d 70 "
+ "6c 65 03 63 6f 6d 00 c0 f2 00 02 00 01 00 00 00 "
+ "3c 00 05 02 6e 73 c0 f2 05 73 69 70 30 30 c0 f2 "
+ "00 01 00 01 00 00 00 3c 00 04 c2 02 bc 85 c1 10 "
+ "00 1c 00 01 00 00 00 3c 00 10 3f f0 00 10 30 12 "
+ "c0 00 02 c0 95 ff fe e2 4b 78 05 73 69 70 30 32 "
+ "c0 f2 00 01 00 01 00 00 00 3c 00 04 c2 02 bc 87 "
+ "c1 42 00 1c 00 01 00 00 00 3c 00 10 3f fe 12 00 "
+ "30 12 c0 06 02 06 5b ff fe 55 46 2f 05 73 69 70 "
+ "30 31 c0 f2 00 01 00 01 00 00 00 3c 00 04 c2 02 "
+ "bc 86 c1 74 00 1c 00 01 00 00 00 3c 00 10 3f f0 "
+ "00 12 30 12 c0 06 0a 08 20 ff fe 7d e7 ac c1 0b "
+ "00 01 00 01 00 00 00 3c 00 04 c2 02 bc 85 c1 0b "
+ "00 26 00 01 00 00 00 3c 00 11 00 3f fe 12 00 30 "
+ "12 c0 00 02 10 a4 ff fe 8d 6a 46 ";
+
+int test_net(sres_context_t *ctx)
+{
+ sres_resolver_t *res = ctx->resolver;
+ sres_query_t *q = NULL;
+ int c = ctx->sink;
+ struct sockaddr_storage ss[1];
+ struct sockaddr *sa = (void *)ss;
+ socklen_t salen = sizeof ss, binlen;
+ char *bin;
+ int i, n;
+ char const *domain = "example.com";
+ char query[512];
+
+ BEGIN();
+
+ TEST_1(ctx->sink != -1 && ctx->sink != 0);
+
+ /* Prepare for test_answer() callback */
+ sres_free_answers(ctx->resolver, ctx->result);
+ ctx->result = NULL;
+ ctx->query = NULL;
+
+ /* Get canned response */
+ TEST_1(bin = hex2bin(__func__, hextest, NULL, &binlen));
+
+ /* Send responses with one erroneus byte */
+ for (i = 1; i < (int)binlen; i++) {
+ if (!q) {
+ /* We got an error => make new query */
+ TEST_1(q = sres_query(res, test_answer, ctx, /* Send query */
+ sres_type_naptr, domain));
+ TEST_1((n = recvfrom(c, query, sizeof query, 0, sa, &salen)) != -1);
+ memcpy(bin, query, 2); /* Copy ID */
+ }
+ if (i != 1)
+ bin[i] ^= 0xff;
+ else
+ bin[3] ^= SRES_FORMAT_ERR; /* format error -> EDNS0 failure */
+ n = sendto(c, bin, binlen, 0, sa, salen);
+ if (i != 1)
+ bin[i] ^= 0xff;
+ else
+ bin[3] ^= SRES_FORMAT_ERR;
+ if (n == -1)
+ perror("sendto");
+
+ while (!poll_sockets(ctx))
+ ;
+
+ if (ctx->query)
+ q = NULL;
+ }
+
+ /* Send runt responses */
+ for (i = 1; i <= (int)binlen; i++) {
+ if (!q) {
+ /* We got an error => make new query */
+ TEST_1(q = sres_query(res, test_answer, ctx, /* Send query */
+ sres_type_naptr, domain));
+ TEST_1((n = recvfrom(c, query, sizeof query, 0, sa, &salen)) != -1);
+ memcpy(bin, query, 2); /* Copy ID */
+ }
+ n = sendto(c, bin, i, 0, sa, salen);
+ if (n == -1)
+ perror("sendto");
+ while (!poll_sockets(ctx))
+ ;
+
+ if (ctx->query)
+ q = NULL;
+ }
+
+ free(bin);
+
+ END();
+}
+
+
+/* Test API function argument validation */
+static
+int test_api_errors(sres_context_t *noctx)
+{
+ sres_context_t ctx[1];
+ sres_resolver_t *res;
+ int s, fd;
+ int sockets[20];
+ struct sockaddr sa[1] = {{ 0 }};
+ char *template = NULL;
+ FILE *f;
+
+ BEGIN();
+
+ memset(ctx, 0, sizeof ctx);
+
+ template = su_sprintf(ctx->home, ".test_sresolv_api.conf.XXXXXX");
+ TEST_1(template);
+
+ TEST_1(res = sres_resolver_new(NULL));
+ TEST(su_home_threadsafe((su_home_t *)res), 0);
+ TEST_VOID(sres_resolver_unref(res));
+
+#ifndef _WIN32
+ fd = mkstemp(template); TEST_1(fd != -1);
+#else
+ fd = open(template, O_WRONLY); TEST_1(fd != -1);
+#endif
+
+ f = fdopen(fd, "w"); TEST_1(f);
+ fprintf(f, "domain example.com\n");
+ fclose(f);
+
+ /* Test also LOCALDOMAIN handling */
+ putenv("LOCALDOMAIN=localdomain");
+
+ TEST_1(res = sres_resolver_new(template));
+ TEST(su_home_threadsafe((su_home_t *)res), 0);
+
+ unlink(template);
+
+ s = sockets[0];
+
+ TEST_P(sres_resolver_ref(NULL), NULL);
+ TEST(errno, EFAULT);
+ sres_resolver_unref(NULL);
+
+ TEST_P(sres_resolver_set_userdata(NULL, NULL), NULL);
+ TEST(errno, EFAULT);
+
+ TEST_P(sres_resolver_get_userdata(NULL), NULL);
+
+ TEST_P(sres_resolver_get_userdata(res), NULL);
+ TEST_P(sres_resolver_set_userdata(res, sa), NULL);
+ TEST_P(sres_resolver_get_userdata(res), sa);
+ TEST_P(sres_resolver_set_userdata(res, NULL), sa);
+ TEST_P(sres_resolver_get_userdata(res), NULL);
+
+ errno = 0;
+ TEST_P(sres_query(NULL, test_answer, ctx, sres_type_a, "com"), NULL);
+ TEST(errno, EFAULT); errno = 0;
+ TEST_P(sres_query(res, test_answer, ctx, sres_type_a, NULL), NULL);
+ TEST(errno, EFAULT); errno = 0;
+ TEST_P(sres_query_sockaddr(res, test_answer, ctx,
+ sres_qtype_any, sa), NULL);
+#if defined(EAFNOSUPPORT)
+ TEST(errno, EAFNOSUPPORT); errno = 0;
+#endif
+
+ TEST_P(sres_cached_answers(NULL, sres_qtype_any, "example.com"), NULL);
+ TEST(errno, EFAULT); errno = 0;
+ TEST_P(sres_cached_answers(res, sres_qtype_any, NULL), NULL);
+ TEST(errno, EFAULT); errno = 0;
+ TEST_P(sres_cached_answers(res, sres_qtype_any, name2048), NULL);
+ TEST(errno, ENAMETOOLONG); errno = 0;
+ TEST_P(sres_cached_answers_sockaddr(res, sres_qtype_any, sa), NULL);
+ TEST(errno, EAFNOSUPPORT); errno = 0;
+
+ sres_free_answer(res, NULL);
+ sres_free_answers(res, NULL);
+ sres_sort_answers(res, NULL);
+
+ sres_free_answer(NULL, NULL);
+ sres_free_answers(NULL, NULL);
+ sres_sort_answers(NULL, NULL);
+
+ sres_resolver_unref(res);
+
+ END();
+}
+
+
+static
+int test_init(sres_context_t *ctx, char const *conf_file)
+{
+ BEGIN();
+
+ sres_resolver_t *res;
+ int i, n;
+
+ ctx->query = NULL, ctx->result = NULL;
+
+ TEST_1(ctx->resolver = res = sres_resolver_new(conf_file));
+ TEST(su_home_threadsafe((su_home_t *)ctx->resolver), 0);
+ n = sres_resolver_sockets(res, NULL, 0);
+ ctx->n_sockets = n;
+ TEST_1(n < SRES_MAX_NAMESERVERS);
+ TEST(sres_resolver_sockets(res, ctx->sockets, n), n);
+
+ for (i = 0; i < n; i++) {
+ ctx->fds[i].fd = ctx->sockets[i];
+ ctx->fds[i].events = POLLIN | POLLERR;
+ }
+
+ TEST_P(sres_resolver_ref(ctx->resolver), ctx->resolver);
+ sres_resolver_unref(ctx->resolver);
+
+ END();
+}
+
+static
+int test_deinit(sres_context_t *ctx)
+{
+ offset += 2 * 36000000;
+
+ sres_resolver_timer(ctx->resolver, -1); /* Zap everything */
+
+ sres_free_answers(ctx->resolver, ctx->result); ctx->result = NULL;
+
+ su_free(ctx->home, (void *)ctx->sinkconf); ctx->sinkconf = NULL;
+
+ sres_resolver_unref(ctx->resolver); ctx->resolver = NULL;
+
+ offset = 0;
+ memset(ctx, 0, sizeof ctx);
+ ctx->home->suh_size = sizeof ctx;
+
+ return 0;
+}
+
+static
+int test_conf_errors(sres_context_t *ctx, char const *conf_file)
+{
+ sres_resolver_t *res;
+ sres_socket_t socket;
+ int n;
+
+ BEGIN();
+
+ TEST_1(res = sres_resolver_new(conf_file));
+ n = sres_resolver_sockets(res, NULL, 0);
+ TEST_1(n > 0);
+
+ TEST(sres_resolver_sockets(res, &socket, 1), n);
+
+#if HAVE_SA_LEN
+ /* We fail this test in BSD systems */
+ /* conf_file looks like this:
+--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--
+nameserver 0.0.0.2
+nameserver 1.1.1.1.1
+search example.com
+port $port
+-->8-->8-->8-->8-->8-->8-->8-->8-->8-->8-->8-->8--
+ */
+ printf("%s:%u: %s test should be updated\n",
+ __FILE__, __LINE__, __func__);
+#else
+ TEST_P(sres_query(res, test_answer, ctx, sres_type_a, "example.com"), NULL);
+#endif
+
+ sres_resolver_unref(res);
+
+ END();
+}
+
+void
+fill_stack(void)
+{
+ int i,array[32768];
+
+ for (i = 0; i < 32768; i++)
+ array[i] = i ^ 0xdeadbeef;
+}
+
+#if HAVE_ALARM
+static RETSIGTYPE sig_alarm(int s)
+{
+ fprintf(stderr, "%s: FAIL! test timeout!\n", name);
+ exit(1);
+}
+#endif
+
+void usage(void)
+{
+ fprintf(stderr,
+ "usage: %s [-v] [-l level] [-] [conf-file] [error-conf-file]\n",
+ name);
+}
+
+#include <sofia-sip/su_log.h>
+
+extern su_log_t sresolv_log[];
+
+int main(int argc, char **argv)
+{
+ int i;
+ int error = 0;
+ int o_attach = 0, o_alarm = 1;
+ sres_context_t ctx[1] = {{{SU_HOME_INIT(ctx)}}};
+
+ for (i = 1; argv[i]; i++) {
+ if (argv[i][0] != '-')
+ break;
+ else if (strcmp(argv[i], "-") == 0) {
+ i++; break;
+ }
+ else if (strcmp(argv[i], "-v") == 0)
+ tstflags |= tst_verbatim;
+ else if (strcmp(argv[i], "--no-alarm") == 0) {
+ o_alarm = 0;
+ }
+ else if (strcmp(argv[i], "--attach") == 0) {
+ o_attach = 1;
+ }
+ else if (strncmp(argv[i], "-l", 2) == 0) {
+ int level = 3;
+ char *rest = NULL;
+
+ if (argv[i][2])
+ level = strtol(argv[i] + 2, &rest, 10);
+ else if (argv[i + 1])
+ level = strtol(argv[i + 1], &rest, 10), i++;
+ else
+ level = 3, rest = "";
+
+ if (rest == NULL || *rest)
+ usage();
+
+ su_log_set_level(sresolv_log, level);
+ } else
+ usage();
+ }
+
+ if (o_attach) {
+ char buf[8];
+
+ fprintf(stderr, "test_sresolv: started with pid %u"
+ " (press enter to continue)\n", getpid());
+
+ fgets(buf, sizeof buf, stdin);
+ }
+#if HAVE_ALARM
+ else if (o_alarm) {
+ alarm(60);
+ signal(SIGALRM, sig_alarm);
+ }
+#endif
+
+ if (!(TSTFLAGS & tst_verbatim)) {
+ su_log_soft_set_level(sresolv_log, 0);
+ }
+
+#if 0
+ if (sink_make(ctx) == 0)
+ {
+ error |= test_init(ctx, ctx->sinkconf);
+ error |= sink_init(ctx);
+ error |= test_net(ctx);
+ error |= test_timeout(ctx);
+ error |= sink_deinit(ctx);
+ error |= test_deinit(ctx);
+ }
+#endif
+
+ offset = 0;
+
+ if (argv[i]) {
+ /* These tests are run with (local) nameserver,
+ */
+ int initerror = test_init(ctx, argv[i]);
+ if (!initerror) {
+ error |= test_a(ctx);
+ error |= test_soa(ctx);
+ error |= test_naptr(ctx);
+#if HAVE_SIN6
+ error |= test_a6(ctx);
+ error |= test_a6_prefix(ctx);
+ error |= test_aaaa(ctx);
+#endif
+ error |= test_srv(ctx);
+ error |= test_cname(ctx);
+ error |= test_ptr_ipv4(ctx);
+ error |= test_ptr_ipv4_sockaddr(ctx);
+#if HAVE_SIN6
+ error |= test_ptr_ipv6(ctx);
+ error |= test_ptr_ipv6_sockaddr(ctx);
+#endif
+ error |= test_cache(ctx);
+#if HAVE_SIN6
+ error |= test_query_one_type(ctx);
+#endif
+ error |= test_expiration(ctx);
+ }
+ error |= test_deinit(ctx) | initerror;
+
+ if (argv[i + 1]) {
+ error |= test_conf_errors(ctx, argv[i + 1]);
+ }
+ }
+
+ error |= test_api_errors(ctx);
+
+ return error;
+}
+
+
+#else /* HAVE_POLL */
+
+int main(int argc, char **argv)
+{
+ printf("*** Test not supported without POLL API ***\n");
+ return 0;
+}
+#endif /* HAVE_POLL */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/ChangeLog Thu Dec 21 01:30:28 2006
@@ -0,0 +1,244 @@
+2006-07-11 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * sofia-sip/stun_common.h: New defines for STUN attributes defined
+ in RFC3489bis. Some old defines have been deprecated, but are still
+ supported in the API.
+
+2006-05-22 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * Makefile.am: Install the stunc tool.
+
+2006-05-07 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * sofia-sip/stun.h: Added new NAT types stun_nattype_t. The
+ naming is now compliant with the terms used by IETF BEHAVE
+ documents.
+
+2006-05-06 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * sofia-sip/stun.h (stun_nattype_str): Added a new function to the
+ public API.
+
+ * sofia-sip/stun.h (stun_nattype): Modified the function signature.
+
+ * sofia-sip/stun.h (stun_state_t): Moved all request-specific states
+ to private stun_req_state_t struct in stun.c.
+
+2006-05-05 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * sofia-sip/stun.h, stun.c: Removed various deprecated functions
+ that were already commented out from the code. Closed sf.net
+ bug #1456403.
+
+2006-03-27 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * stun.h: Added stun_server_address().
+
+ * stun.h: Added stun_dns_lookup*() interface.
+
+ * stun.h: Renamed get_nattype to test_nattype and
+ get_lifetime to test_lifetime. Removed deprecated
+ wrappers.
+
+ * stun.h: Deprecated stun_handle_release().
+
+2006-01-26 Martti Mela <martti.mela at nokia.com>
+
+ * STUN: initial keepalive dispatcher
+
+ M ./libsofia-sip-ua/stun/stun.c -28 +149
+ M ./libsofia-sip-ua/stun/stun.h +9
+ M ./libsofia-sip-ua/stun/stun_tag.c +16
+ M ./libsofia-sip-ua/stun/stun_tag.h +6
+ M ./libsofia-sip-ua/stun/stunc.c +6
+
+2006-02-09 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * stun_tag.h: Added STUN_DOMAIN() and STUN_REQUIRE_INTEGRITY().
+ Deprecated STUN_INTEGRITY.
+
+ * stun.c: Mark wait entries as deregistered after
+ su_root_deregister().
+
+2006-01-26 Martti Mela <martti.mela at nokia.com>
+
+ * STUN: initial keepalive dispatcher
+
+ M ./libsofia-sip-ua/stun/stun.c -28 +149
+ M ./libsofia-sip-ua/stun/stun.h +9
+ M ./libsofia-sip-ua/stun/stun_tag.c +16
+ M ./libsofia-sip-ua/stun/stun_tag.h +6
+ M ./libsofia-sip-ua/stun/stunc.c +6
+
+2006-01-19 Martti Mela <martti.mela at nokia.com>
+
+ * stun.c: assign_socket() now takes care of socket registering and
+ binding operations
+
+2006-01-17 Martti Mela <martti.mela at nokia.com>
+
+ * stun.c: tls callback now fails if connect() fails. Random
+ cleanup.
+
+2006-01-15 Martti Mela <martti.mela at nokia.com>
+
+ * stun.c: bug fixes in get NAT type.
+
+ * stun.h: changed request_get_localinfo() to
+ discovery_get_address()
+
+ * stunc.c: debugging info cleanup
+
+ * stun_common.c, stun_common.h: cleanup + SU_DEBUG is now
+ determined from stun_internal.h
+
+ * stun_internal.h: included stun_common.h
+
+ * torture_stun.c: updated get_localinfo() to get_address()
+
+2006-01-13 Martti Mela <martti.mela at nokia.com>
+
+ * stun.c: actions are now very separate from each other. Bug fixes.
+
+ * stun.h: added some new error states
+
+ * stunc.c: passing STUN_SOCKET() for each of the actions.
+
+2006-01-11 Martti Mela <martti.mela at nokia.com>
+
+ * stun.c: Fixed bug in timing problem in get_lifetime. Added
+ stun_message_length() and stun_handle_process_message() for
+ glueing into TPORT.
+
+ * stunc.c: Removed unnecessary su_root_break()s.
+
+2006-01-10 Martti Mela <martti.mela at nokia.com>
+
+ * stun.c: First working version of get_lifetime functionality. All
+ stun_requests are now destroyed automatically by their timers if
+ the request's state is marked as "stun_dispose_me".
+
+ * stun.h: Updated stun_lifetime() API, moved discovery type enums
+ here from stun.c.
+
+2006-01-05 Martti Mela <martti.mela at nokia.com>
+
+ * stun.c: Finished get_nattype functionality. Might
+ work. Different stun actions are now kept in stun_discovery_t struct.
+
+ * stun.h: Updated event to support nattype discovery; get_nattype
+ definition, too.
+
+ * stunc.c: Support for discovery events
+
+ * torture_stun.c: stun_states_t -> stun_state_t
+
+2006-01-04 Martti Mela <martti.mela at nokia.com>
+
+ * stun.c: Functionality changed to support transactions; initial
+ support for NAT type discovery
+
+ * stun.h: API changed to support transactions
+
+ * stun_internal.h: API changed to support transactions
+
+ * stun_tag.[ch]: added tag STUNTAG_ACTION for different actions
+ (lifetime, NAT type, bind, keepalive)
+
+ * stunc.c: enabled get_nattype
+
+ * torture_stun.c: changed to support new API
+
+ *stun_common.h: removed NAT type strings to stun.c.
+
+2005-12-19 Martti Mela <martti.mela at nokia.com>
+
+ * stun.c: fixed TLS and bind timers.
+
+ * stun_common.c: changed every SU_DEBUG to contain __func__.
+
+2005-12-19 Martti Mela <martti.mela at nokia.com>
+
+ * stun.c: TLS connection works now.
+
+ * stun.h: removed stun_socket_t references, replaced by
+ stun_handle functionality.
+
+ * stunc.c, torture_stun.c: modified in accordance to stun.h.
+
+2005-12-16 Martti Mela <martti.mela at nokia.com>
+
+ * stun.h: changed stun_engine_t to stun_handle_t.
+
+ * stun.c: STUN handle is now created independently of
+ stun_connect_start(). Callback events have now string
+ representation, too.
+
+ * stunc.c, torture_stun.c: behave now in conformance to stun.h
+
+2005-12-15 Martti Mela <martti.mela at nokia.com>
+
+ * STUN updated to work asynchronously.
+
+ * stun.c: added timeout timer for connect() (defaults to 8 seconds).
+
+ * stun_internal.h: added.
+
+ * stun.h: Does not contain functions that are interal. Cleaned the API. Specified
+ more states for stun_states_t.
+
+2005-11-19 Kai Vehmanen <kaiv at .devtag.AUTHORS>
+
+ * stun.h (stun_set_uname_pwd): Changed from unsigned to signed
+ char pointers for passing username and password.
+
+2005-11-18 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * stun.c: Print the error state code if discovery
+ process fails.
+ * stunc.c (stun_bind_test): The fd_set was not
+ properly reseted between calls to select().
+
+2005-10-27 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Always building stun tags.
+
+ M ./libsofia-sip-ua/stun/Makefile.am -3 +3
+
+2005-10-24 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * stun.c: Fixed stun_bind() behaviour when STUN
+ discovery fails. Added enum for tracking client
+ state.
+
+2005-10-18 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Checking that we have got valid server address as parameter.
+
+ M ./libsofia-sip-ua/stun/stun.c -6 +14
+
+ * Added stun_is_requested().
+
+ M ./libsofia-sip-ua/stun/stun.c +22
+ M ./libsofia-sip-ua/stun/stun.h +2
+
+ * Added tagged call stun_engine_tcreate().
+
+ M ./libsofia-sip-ua/stun/Makefile.am -10 +7
+ M ./libsofia-sip-ua/stun/stun.c -7 +44
+ M ./libsofia-sip-ua/stun/stun.h +7
+ A ./libsofia-sip-ua/stun/stun_tag.c
+ A ./libsofia-sip-ua/stun/stun_tag.h
+
+2005-10-13 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * stun_common.h, stun.h: Updated inline docs to use
+ the doxygen syntax.
+
+ * stun_common.c: Fixed memory leaks.
+
+ * stun.c (stun_engine_create): Add hostname resolving.
+
+2005-07-18 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * Initial import of the module to Sofia-SIP tree.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/Doxyfile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/Doxyfile Thu Dec 21 01:30:28 2006
@@ -0,0 +1,10 @@
+PROJECT_NAME = "stun"
+OUTPUT_DIRECTORY = ../docs/html/stun
+
+INPUT = stun.docs sofia-sip .
+
+ at INCLUDE = ../docs/Doxyfile.conf
+
+TAGFILES += ../docs/su.doxytags=../su
+
+GENERATE_TAGFILE = ../docs/stun.doxytags
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/Makefile.am Thu Dec 21 01:30:28 2006
@@ -0,0 +1,63 @@
+#
+# Makefile.am @template@ for stun module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# General options
+
+AUTOMAKE_OPTIONS = foreign
+
+# ----------------------------------------------------------------------
+# Header paths
+
+INCLUDES = $(INTERNAL_INCLUDES)
+
+# ----------------------------------------------------------------------
+# Build targets
+
+stun_lib_sources = stun.c stun_common.c stun_dns.c stun_mini.c
+
+noinst_LTLIBRARIES = libstun.la
+
+bin_PROGRAMS = stunc
+check_PROGRAMS = lookup_stun_server
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+
+nobase_include_sofia_HEADERS = \
+ sofia-sip/stun.h sofia-sip/stun_common.h \
+ sofia-sip/stun_tag.h
+libstun_la_SOURCES = $(stun_lib_sources) \
+ stun_tag.c stun_tag_ref.c stun_internal.h
+
+BUILT_SOURCES = stun_tag_ref.c
+
+COVERAGE_INPUT = $(libstun_la_SOURCES) $(include_sofia_HEADERS)
+
+LDADD = \
+ libstun.la
+ ../sresolv/libsresolv.la \
+ ../su/libsu.la
+
+stunc_LDADD = libstun.la ../sresolv/libsresolv.la ../su/libsu.la
+
+lookup_stun_server_LDADD = libstun.la ../sresolv/libsresolv.la ../su/libsu.la
+
+# ----------------------------------------------------------------------
+# tests
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+
+EXTRA_DIST = Doxyfile stun.docs cert.pem key.pem
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+
+include ../sofia.am
+
+TAG_DLL_FLAGS = LIST=stun_tag_list
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/Makefile.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1,679 @@
+# 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.
+
+ at SET_MAKE@
+
+#
+# Makefile.am @template@ for stun module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# General options
+
+# common Makefile targets for libsofia-sip-ua modules
+# ---------------------------------------------------
+
+
+
+SOURCES = $(libstun_la_SOURCES) lookup_stun_server.c stunc.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@
+bin_PROGRAMS = stunc$(EXEEXT)
+check_PROGRAMS = lookup_stun_server$(EXEEXT)
+DIST_COMMON = $(nobase_include_sofia_HEADERS) $(srcdir)/../sofia.am \
+ $(srcdir)/Makefile.am $(srcdir)/Makefile.in ChangeLog
+subdir = libsofia-sip-ua/stun
+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 =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libstun_la_LIBADD =
+am__objects_1 = stun.lo stun_common.lo stun_dns.lo stun_mini.lo
+am_libstun_la_OBJECTS = $(am__objects_1) stun_tag.lo stun_tag_ref.lo
+libstun_la_OBJECTS = $(am_libstun_la_OBJECTS)
+am__installdirs = "$(DESTDIR)$(bindir)" \
+ "$(DESTDIR)$(include_sofiadir)"
+binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+PROGRAMS = $(bin_PROGRAMS)
+lookup_stun_server_SOURCES = lookup_stun_server.c
+lookup_stun_server_OBJECTS = lookup_stun_server.$(OBJEXT)
+lookup_stun_server_DEPENDENCIES = libstun.la ../sresolv/libsresolv.la \
+ ../su/libsu.la
+stunc_SOURCES = stunc.c
+stunc_OBJECTS = stunc.$(OBJEXT)
+stunc_DEPENDENCIES = libstun.la ../sresolv/libsresolv.la \
+ ../su/libsu.la
+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 = $(libstun_la_SOURCES) lookup_stun_server.c stunc.c
+DIST_SOURCES = $(libstun_la_SOURCES) lookup_stun_server.c stunc.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@
+AUTOMAKE_OPTIONS = foreign
+
+# ----------------------------------------------------------------------
+# Header paths
+INCLUDES = $(INTERNAL_INCLUDES)
+
+# ----------------------------------------------------------------------
+# Build targets
+stun_lib_sources = stun.c stun_common.c stun_dns.c stun_mini.c
+noinst_LTLIBRARIES = libstun.la
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+nobase_include_sofia_HEADERS = \
+ sofia-sip/stun.h sofia-sip/stun_common.h \
+ sofia-sip/stun_tag.h
+
+libstun_la_SOURCES = $(stun_lib_sources) \
+ stun_tag.c stun_tag_ref.c stun_internal.h
+
+BUILT_SOURCES = stun_tag_ref.c
+COVERAGE_INPUT = $(libstun_la_SOURCES) $(include_sofia_HEADERS)
+LDADD = \
+ libstun.la
+
+stunc_LDADD = libstun.la ../sresolv/libsresolv.la ../su/libsu.la
+lookup_stun_server_LDADD = libstun.la ../sresolv/libsresolv.la ../su/libsu.la
+
+# ----------------------------------------------------------------------
+# tests
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+EXTRA_DIST = Doxyfile stun.docs cert.pem key.pem
+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
+TAG_DLL_FLAGS = LIST=stun_tag_list
+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) --foreign libsofia-sip-ua/stun/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --foreign libsofia-sip-ua/stun/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-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
+libstun.la: $(libstun_la_OBJECTS) $(libstun_la_DEPENDENCIES)
+ $(LINK) $(libstun_la_LDFLAGS) $(libstun_la_OBJECTS) $(libstun_la_LIBADD) $(LIBS)
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)"
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ if test -f $$p \
+ || test -f $$p1 \
+ ; then \
+ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \
+ else :; fi; \
+ done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \
+ rm -f "$(DESTDIR)$(bindir)/$$f"; \
+ done
+
+clean-binPROGRAMS:
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f $$p $$f"; \
+ rm -f $$p $$f ; \
+ done
+
+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
+lookup_stun_server$(EXEEXT): $(lookup_stun_server_OBJECTS) $(lookup_stun_server_DEPENDENCIES)
+ @rm -f lookup_stun_server$(EXEEXT)
+ $(LINK) $(lookup_stun_server_LDFLAGS) $(lookup_stun_server_OBJECTS) $(lookup_stun_server_LDADD) $(LIBS)
+stunc$(EXEEXT): $(stunc_OBJECTS) $(stunc_DEPENDENCIES)
+ @rm -f stunc$(EXEEXT)
+ $(LINK) $(stunc_LDFLAGS) $(stunc_OBJECTS) $(stunc_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/lookup_stun_server.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/stun.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/stun_common.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/stun_dns.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/stun_mini.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/stun_tag.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/stun_tag_ref.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/stunc.Po at am__quote@
+
+.c.o:
+ at am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+ at am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ at am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at 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
+
+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)
+check: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(bindir)" "$(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-binPROGRAMS clean-checkPROGRAMS clean-generic \
+ clean-libtool 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-nobase_include_sofiaHEADERS
+
+install-exec-am: install-binPROGRAMS
+
+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-binPROGRAMS uninstall-info-am \
+ uninstall-nobase_include_sofiaHEADERS
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \
+ clean-checkPROGRAMS clean-generic clean-libtool \
+ 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-binPROGRAMS install-data install-data-am 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-binPROGRAMS \
+ uninstall-info-am uninstall-nobase_include_sofiaHEADERS
+
+ ../sresolv/libsresolv.la \
+ ../su/libsu.la
+
+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) $<
+
+ at ENABLE_COVERAGE_TRUE@coverage:
+ at 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)
+# 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:
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/cert.pem
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/cert.pem Thu Dec 21 01:30:28 2006
@@ -0,0 +1,14 @@
+-----BEGIN CERTIFICATE-----
+MIICLDCCAdYCAQAwDQYJKoZIhvcNAQEEBQAwgaAxCzAJBgNVBAYTAlBUMRMwEQYD
+VQQIEwpRdWVlbnNsYW5kMQ8wDQYDVQQHEwZMaXNib2ExFzAVBgNVBAoTDk5ldXJv
+bmlvLCBMZGEuMRgwFgYDVQQLEw9EZXNlbnZvbHZpbWVudG8xGzAZBgNVBAMTEmJy
+dXR1cy5uZXVyb25pby5wdDEbMBkGCSqGSIb3DQEJARYMc2FtcG9AaWtpLmZpMB4X
+DTk2MDkwNTAzNDI0M1oXDTk2MTAwNTAzNDI0M1owgaAxCzAJBgNVBAYTAlBUMRMw
+EQYDVQQIEwpRdWVlbnNsYW5kMQ8wDQYDVQQHEwZMaXNib2ExFzAVBgNVBAoTDk5l
+dXJvbmlvLCBMZGEuMRgwFgYDVQQLEw9EZXNlbnZvbHZpbWVudG8xGzAZBgNVBAMT
+EmJydXR1cy5uZXVyb25pby5wdDEbMBkGCSqGSIb3DQEJARYMc2FtcG9AaWtpLmZp
+MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL7+aty3S1iBA/+yxjxv4q1MUTd1kjNw
+L4lYKbpzzlmC5beaQXeQ2RmGMTXU+mDvuqItjVHOK3DvPK7lTcSGftUCAwEAATAN
+BgkqhkiG9w0BAQQFAANBAFqPEKFjk6T6CKTHvaQeEAsX0/8YHPHqH/9AnhSjrwuX
+9EBc0n6bVGhN7XaXd6sJ7dym9sbsWxb+pJdurnkxjx4=
+-----END CERTIFICATE-----
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/key.pem
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/key.pem Thu Dec 21 01:30:28 2006
@@ -0,0 +1,9 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIBPAIBAAJBAL7+aty3S1iBA/+yxjxv4q1MUTd1kjNwL4lYKbpzzlmC5beaQXeQ
+2RmGMTXU+mDvuqItjVHOK3DvPK7lTcSGftUCAwEAAQJBALjkK+jc2+iihI98riEF
+oudmkNziSRTYjnwjx8mCoAjPWviB3c742eO3FG4/soi1jD9A5alihEOXfUzloenr
+8IECIQD3B5+0l+68BA/6d76iUNqAAV8djGTzvxnCxycnxPQydQIhAMXt4trUI3nc
+a+U8YL2HPFA3gmhBsSICbq2OptOCnM7hAiEA6Xi3JIQECob8YwkRj29DU3/4WYD7
+WLPgsQpwo1GuSpECICGsnWH5oaeD9t9jbFoSfhJvv0IZmxdcLpRcpslpeWBBAiEA
+6/5B8J0GHdJq89FHwEG/H2eVVUYu5y/aD6sgcm+0Avg=
+-----END RSA PRIVATE KEY-----
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/lookup_stun_server.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/lookup_stun_server.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,106 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**
+ * @file lookup_stun_server.c
+ * @brief Test app for STUN DNS-SRV lookups.
+ *
+ * @author Kai Vehmanen <Kai.Vehmanen at nokia.com>
+ *
+ * @todo TODO
+ * - picks one UDP and TLS target:port
+ * - does not pick up A/AAAA records that might be delivered
+ * in 'Additional Data' section as defined in RFC2782
+ */
+
+#include <stdio.h>
+
+#include <sofia-sip/su.h>
+#include <sofia-sip/su_alloc.h>
+#include <sofia-sip/su_wait.h>
+#define STUN_MAGIC_T su_root_t
+#include <sofia-sip/stun.h>
+
+static char* g_domain = NULL;
+
+static void lookup_cb(stun_dns_lookup_t *self,
+ su_root_t *root)
+{
+# define RESULT(x) (x == 0 ? "OK" : "ERRORS")
+
+ const char *tcp_target = NULL, *udp_target = NULL, *stp_target = NULL;
+ uint16_t tcp_port = 0, udp_port = 0, stp_port = 0;
+ int res = 0;
+
+ printf("STUN DNS-SRV lookup results:\n");
+
+ res = stun_dns_lookup_udp_addr(self, &udp_target, &udp_port);
+ printf(" _stun._udp.%s: %s:%u (%s).\n", g_domain, udp_target, udp_port, RESULT(res));
+
+ res = stun_dns_lookup_tcp_addr(self, &tcp_target, &tcp_port);
+ printf(" _stun._tcp.%s: %s:%u (%s).\n", g_domain, tcp_target, tcp_port, RESULT(res));
+
+ res = stun_dns_lookup_stp_addr(self, &stp_target, &stp_port);
+ printf(" _stun-tls._tcp.%s: %s:%u (%s).\n", g_domain, stp_target, stp_port, RESULT(res));
+
+ su_root_break(root);
+}
+
+int main(int argc, char *argv[])
+{
+ su_root_t *root;
+ stun_dns_lookup_t *lookup;
+
+ if (argc < 2) {
+ printf("usage: ./lookup_stun_server <domain>\n");
+ return -1;
+ }
+
+ g_domain = argv[1];
+
+ /* step: initialize sofia su OS abstraction layer */
+ su_init();
+
+ /* step: create a su event loop and connect it to glib */
+ root = su_root_create(NULL);
+
+ /* step: initiate the DNS-SRV lookup */
+ lookup = stun_dns_lookup(root, root, lookup_cb, g_domain);
+
+ if (lookup) {
+ /* step: enter the main loop (break fro lookup_cb()) */
+ su_root_run(root);
+
+ /* step: free any allocated resources */
+ stun_dns_lookup_destroy(lookup);
+ }
+ else {
+ printf("ERROR: failed to create lookup object.\n");
+ }
+
+ su_root_destroy(root);
+ su_deinit();
+
+ return 0;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/rfc3489.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/rfc3489.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,2635 @@
+
+
+
+
+
+
+Network Working Group J. Rosenberg
+Request for Comments: 3489 J. Weinberger
+Category: Standards Track dynamicsoft
+ C. Huitema
+ Microsoft
+ R. Mahy
+ Cisco
+ March 2003
+
+
+ STUN - Simple Traversal of User Datagram Protocol (UDP)
+ Through Network Address Translators (NATs)
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2003). All Rights Reserved.
+
+Abstract
+
+ Simple Traversal of User Datagram Protocol (UDP) Through Network
+ Address Translators (NATs) (STUN) is a lightweight protocol that
+ allows applications to discover the presence and types of NATs and
+ firewalls between them and the public Internet. It also provides the
+ ability for applications to determine the public Internet Protocol
+ (IP) addresses allocated to them by the NAT. STUN works with many
+ existing NATs, and does not require any special behavior from them.
+ As a result, it allows a wide variety of applications to work through
+ existing NAT infrastructure.
+
+Table of Contents
+
+ 1. Applicability Statement ................................... 3
+ 2. Introduction .............................................. 3
+ 3. Terminology ............................................... 4
+ 4. Definitions ............................................... 5
+ 5. NAT Variations ............................................ 5
+ 6. Overview of Operation ..................................... 6
+ 7. Message Overview .......................................... 8
+ 8. Server Behavior ........................................... 10
+ 8.1 Binding Requests .................................... 10
+
+
+
+Rosenberg, et al. Standards Track [Page 1]
+
+RFC 3489 STUN March 2003
+
+
+ 8.2 Shared Secret Requests .............................. 13
+ 9. Client Behavior ........................................... 14
+ 9.1 Discovery ........................................... 15
+ 9.2 Obtaining a Shared Secret ........................... 15
+ 9.3 Formulating the Binding Request ..................... 17
+ 9.4 Processing Binding Responses ........................ 17
+ 10. Use Cases ................................................. 19
+ 10.1 Discovery Process ................................... 19
+ 10.2 Binding Lifetime Discovery .......................... 21
+ 10.3 Binding Acquisition ................................. 23
+ 11. Protocol Details .......................................... 24
+ 11.1 Message Header ...................................... 25
+ 11.2 Message Attributes .................................. 26
+ 11.2.1 MAPPED-ADDRESS .............................. 27
+ 11.2.2 RESPONSE-ADDRESS ............................ 27
+ 11.2.3 CHANGED-ADDRESS ............................. 28
+ 11.2.4 CHANGE-REQUEST .............................. 28
+ 11.2.5 SOURCE-ADDRESS .............................. 28
+ 11.2.6 USERNAME .................................... 28
+ 11.2.7 PASSWORD .................................... 29
+ 11.2.8 MESSAGE-INTEGRITY ........................... 29
+ 11.2.9 ERROR-CODE .................................. 29
+ 11.2.10 UNKNOWN-ATTRIBUTES .......................... 31
+ 11.2.11 REFLECTED-FROM .............................. 31
+ 12. Security Considerations ................................... 31
+ 12.1 Attacks on STUN ..................................... 31
+ 12.1.1 Attack I: DDOS Against a Target ............. 32
+ 12.1.2 Attack II: Silencing a Client ............... 32
+ 12.1.3 Attack III: Assuming the Identity of a Client 32
+ 12.1.4 Attack IV: Eavesdropping .................... 33
+ 12.2 Launching the Attacks ............................... 33
+ 12.2.1 Approach I: Compromise a Legitimate
+ STUN Server ................................. 33
+ 12.2.2 Approach II: DNS Attacks .................... 34
+ 12.2.3 Approach III: Rogue Router or NAT ........... 34
+ 12.2.4 Approach IV: MITM ........................... 35
+ 12.2.5 Approach V: Response Injection Plus DoS ..... 35
+ 12.2.6 Approach VI: Duplication .................... 35
+ 12.3 Countermeasures ..................................... 36
+ 12.4 Residual Threats .................................... 37
+ 13. IANA Considerations ....................................... 38
+ 14. IAB Considerations ........................................ 38
+ 14.1 Problem Definition .................................. 38
+ 14.2 Exit Strategy ....................................... 39
+ 14.3 Brittleness Introduced by STUN ...................... 40
+ 14.4 Requirements for a Long Term Solution ............... 42
+ 14.5 Issues with Existing NAPT Boxes ..................... 43
+ 14.6 In Closing .......................................... 43
+
+
+
+Rosenberg, et al. Standards Track [Page 2]
+
+RFC 3489 STUN March 2003
+
+
+ 15. Acknowledgments ........................................... 44
+ 16. Normative References ...................................... 44
+ 17. Informative References .................................... 44
+ 18. Authors' Addresses ........................................ 46
+ 19. Full Copyright Statement................................... 47
+
+1. Applicability Statement
+
+ This protocol is not a cure-all for the problems associated with NAT.
+ It does not enable incoming TCP connections through NAT. It allows
+ incoming UDP packets through NAT, but only through a subset of
+ existing NAT types. In particular, STUN does not enable incoming UDP
+ packets through symmetric NATs (defined below), which are common in
+ large enterprises. STUN's discovery procedures are based on
+ assumptions on NAT treatment of UDP; such assumptions may prove
+ invalid down the road as new NAT devices are deployed. STUN does not
+ work when it is used to obtain an address to communicate with a peer
+ which happens to be behind the same NAT. STUN does not work when the
+ STUN server is not in a common shared address realm. For a more
+ complete discussion of the limitations of STUN, see Section 14.
+
+2. Introduction
+
+ Network Address Translators (NATs), while providing many benefits,
+ also come with many drawbacks. The most troublesome of those
+ drawbacks is the fact that they break many existing IP applications,
+ and make it difficult to deploy new ones. Guidelines have been
+ developed [8] that describe how to build "NAT friendly" protocols,
+ but many protocols simply cannot be constructed according to those
+ guidelines. Examples of such protocols include almost all peer-to-
+ peer protocols, such as multimedia communications, file sharing and
+ games.
+
+ To combat this problem, Application Layer Gateways (ALGs) have been
+ embedded in NATs. ALGs perform the application layer functions
+ required for a particular protocol to traverse a NAT. Typically,
+ this involves rewriting application layer messages to contain
+ translated addresses, rather than the ones inserted by the sender of
+ the message. ALGs have serious limitations, including scalability,
+ reliability, and speed of deploying new applications. To resolve
+ these problems, the Middlebox Communications (MIDCOM) protocol is
+ being developed [9]. MIDCOM allows an application entity, such as an
+ end client or network server of some sort (like a Session Initiation
+ Protocol (SIP) proxy [10]) to control a NAT (or firewall), in order
+ to obtain NAT bindings and open or close pinholes. In this way, NATs
+ and applications can be separated once more, eliminating the need for
+ embedding ALGs in NATs, and resolving the limitations imposed by
+ current architectures.
+
+
+
+Rosenberg, et al. Standards Track [Page 3]
+
+RFC 3489 STUN March 2003
+
+
+ Unfortunately, MIDCOM requires upgrades to existing NAT and
+ firewalls, in addition to application components. Complete upgrades
+ of these NAT and firewall products will take a long time, potentially
+ years. This is due, in part, to the fact that the deployers of NAT
+ and firewalls are not the same people who are deploying and using
+ applications. As a result, the incentive to upgrade these devices
+ will be low in many cases. Consider, for example, an airport
+ Internet lounge that provides access with a NAT. A user connecting
+ to the NATed network may wish to use a peer-to-peer service, but
+ cannot, because the NAT doesn't support it. Since the administrators
+ of the lounge are not the ones providing the service, they are not
+ motivated to upgrade their NAT equipment to support it, using either
+ an ALG, or MIDCOM.
+
+ Another problem is that the MIDCOM protocol requires that the agent
+ controlling the middleboxes know the identity of those middleboxes,
+ and have a relationship with them which permits control. In many
+ configurations, this will not be possible. For example, many cable
+ access providers use NAT in front of their entire access network.
+ This NAT could be in addition to a residential NAT purchased and
+ operated by the end user. The end user will probably not have a
+ control relationship with the NAT in the cable access network, and
+ may not even know of its existence.
+
+ Many existing proprietary protocols, such as those for online games
+ (such as the games described in RFC 3027 [11]) and Voice over IP,
+ have developed tricks that allow them to operate through NATs without
+ changing those NATs. This document is an attempt to take some of
+ those ideas, and codify them into an interoperable protocol that can
+ meet the needs of many applications.
+
+ The protocol described here, Simple Traversal of UDP Through NAT
+ (STUN), allows entities behind a NAT to first discover the presence
+ of a NAT and the type of NAT, and then to learn the addresses
+ bindings allocated by the NAT. STUN requires no changes to NATs, and
+ works with an arbitrary number of NATs in tandem between the
+ application entity and the public Internet.
+
+3. Terminology
+
+ In this document, the key words "MUST", "MUST NOT", "REQUIRED",
+ "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY",
+ and "OPTIONAL" are to be interpreted as described in BCP 14, RFC 2119
+ [1] and indicate requirement levels for compliant STUN
+ implementations.
+
+
+
+
+
+
+Rosenberg, et al. Standards Track [Page 4]
+
+RFC 3489 STUN March 2003
+
+
+4. Definitions
+
+ STUN Client: A STUN client (also just referred to as a client)
+ is an entity that generates STUN requests. A STUN client can
+ execute on an end system, such as a user's PC, or can run in a
+ network element, such as a conferencing server.
+
+ STUN Server: A STUN Server (also just referred to as a server)
+ is an entity that receives STUN requests, and sends STUN
+ responses. STUN servers are generally attached to the public
+ Internet.
+
+5. NAT Variations
+
+ It is assumed that the reader is familiar with NATs. It has been
+ observed that NAT treatment of UDP varies among implementations. The
+ four treatments observed in implementations are:
+
+ Full Cone: A full cone NAT is one where all requests from the
+ same internal IP address and port are mapped to the same external
+ IP address and port. Furthermore, any external host can send a
+ packet to the internal host, by sending a packet to the mapped
+ external address.
+
+ Restricted Cone: A restricted cone NAT is one where all requests
+ from the same internal IP address and port are mapped to the same
+ external IP address and port. Unlike a full cone NAT, an external
+ host (with IP address X) can send a packet to the internal host
+ only if the internal host had previously sent a packet to IP
+ address X.
+
+ Port Restricted Cone: A port restricted cone NAT is like a
+ restricted cone NAT, but the restriction includes port numbers.
+ Specifically, an external host can send a packet, with source IP
+ address X and source port P, to the internal host only if the
+ internal host had previously sent a packet to IP address X and
+ port P.
+
+ Symmetric: A symmetric NAT is one where all requests from the
+ same internal IP address and port, to a specific destination IP
+ address and port, are mapped to the same external IP address and
+ port. If the same host sends a packet with the same source
+ address and port, but to a different destination, a different
+ mapping is used. Furthermore, only the external host that
+ receives a packet can send a UDP packet back to the internal host.
+
+
+
+
+
+
+Rosenberg, et al. Standards Track [Page 5]
+
+RFC 3489 STUN March 2003
+
+
+ Determining the type of NAT is important in many cases. Depending on
+ what the application wants to do, it may need to take the particular
+ behavior into account.
+
+6. Overview of Operation
+
+ This section is descriptive only. Normative behavior is described in
+ Sections 8 and 9.
+
+ /-----\
+ // STUN \\
+ | Server |
+ \\ //
+ \-----/
+
+
+ +--------------+ Public Internet
+ ................| NAT 2 |.......................
+ +--------------+
+
+
+ +--------------+ Private NET 2
+ ................| NAT 1 |.......................
+ +--------------+
+
+ /-----\
+ // STUN \\
+ | Client |
+ \\ // Private NET 1
+ \-----/
+
+ Figure 1: STUN Configuration
+
+ The typical STUN configuration is shown in Figure 1. A STUN client
+ is connected to private network 1. This network connects to private
+ network 2 through NAT 1. Private network 2 connects to the public
+ Internet through NAT 2. The STUN server resides on the public
+ Internet.
+
+ STUN is a simple client-server protocol. A client sends a request to
+ a server, and the server returns a response. There are two types of
+ requests - Binding Requests, sent over UDP, and Shared Secret
+ Requests, sent over TLS [2] over TCP. Shared Secret Requests ask the
+ server to return a temporary username and password. This username
+ and password are used in a subsequent Binding Request and Binding
+ Response, for the purposes of authentication and message integrity.
+
+
+
+
+
+Rosenberg, et al. Standards Track [Page 6]
+
+RFC 3489 STUN March 2003
+
+
+ Binding requests are used to determine the bindings allocated by
+ NATs. The client sends a Binding Request to the server, over UDP.
+ The server examines the source IP address and port of the request,
+ and copies them into a response that is sent back to the client.
+ There are some parameters in the request that allow the client to ask
+ that the response be sent elsewhere, or that the server send the
+ response from a different address and port. There are attributes for
+ providing message integrity and authentication.
+
+ The trick is using STUN to discover the presence of NAT, and to learn
+ and use the bindings they allocate.
+
+ The STUN client is typically embedded in an application which needs
+ to obtain a public IP address and port that can be used to receive
+ data. For example, it might need to obtain an IP address and port to
+ receive Real Time Transport Protocol (RTP) [12] traffic. When the
+ application starts, the STUN client within the application sends a
+ STUN Shared Secret Request to its server, obtains a username and
+ password, and then sends it a Binding Request. STUN servers can be
+ discovered through DNS SRV records [3], and it is generally assumed
+ that the client is configured with the domain to use to find the STUN
+ server. Generally, this will be the domain of the provider of the
+ service the application is using (such a provider is incented to
+ deploy STUN servers in order to allow its customers to use its
+ application through NAT). Of course, a client can determine the
+ address or domain name of a STUN server through other means. A STUN
+ server can even be embedded within an end system.
+
+ The STUN Binding Request is used to discover the presence of a NAT,
+ and to discover the public IP address and port mappings generated by
+ the NAT. Binding Requests are sent to the STUN server using UDP.
+ When a Binding Request arrives at the STUN server, it may have passed
+ through one or more NATs between the STUN client and the STUN server.
+ As a result, the source address of the request received by the server
+ will be the mapped address created by the NAT closest to the server.
+ The STUN server copies that source IP address and port into a STUN
+ Binding Response, and sends it back to the source IP address and port
+ of the STUN request. For all of the NAT types above, this response
+ will arrive at the STUN client.
+
+ When the STUN client receives the STUN Binding Response, it compares
+ the IP address and port in the packet with the local IP address and
+ port it bound to when the request was sent. If these do not match,
+ the STUN client is behind one or more NATs. In the case of a full-
+ cone NAT, the IP address and port in the body of the STUN response
+ are public, and can be used by any host on the public Internet to
+ send packets to the application that sent the STUN request. An
+ application need only listen on the IP address and port from which
+
+
+
+Rosenberg, et al. Standards Track [Page 7]
+
+RFC 3489 STUN March 2003
+
+
+ the STUN request was sent. Any packets sent by a host on the public
+ Internet to the public address and port learned by STUN will be
+ received by the application.
+
+ Of course, the host may not be behind a full-cone NAT. Indeed, it
+ doesn't yet know what type of NAT it is behind. To determine that,
+ the client uses additional STUN Binding Requests. The exact
+ procedure is flexible, but would generally work as follows. The
+ client would send a second STUN Binding Request, this time to a
+ different IP address, but from the same source IP address and port.
+ If the IP address and port in the response are different from those
+ in the first response, the client knows it is behind a symmetric NAT.
+ To determine if it's behind a full-cone NAT, the client can send a
+ STUN Binding Request with flags that tell the STUN server to send a
+ response from a different IP address and port than the request was
+ received on. In other words, if the client sent a Binding Request to
+ IP address/port A/B using a source IP address/port of X/Y, the STUN
+ server would send the Binding Response to X/Y using source IP
+ address/port C/D. If the client receives this response, it knows it
+ is behind a full cone NAT.
+
+ STUN also allows the client to ask the server to send the Binding
+ Response from the same IP address the request was received on, but
+ with a different port. This can be used to detect whether the client
+ is behind a port restricted cone NAT or just a restricted cone NAT.
+
+ It should be noted that the configuration in Figure 1 is not the only
+ permissible configuration. The STUN server can be located anywhere,
+ including within another client. The only requirement is that the
+ STUN server is reachable by the client, and if the client is trying
+ to obtain a publicly routable address, that the server reside on the
+ public Internet.
+
+7. Message Overview
+
+ STUN messages are TLV (type-length-value) encoded using big endian
+ (network ordered) binary. All STUN messages start with a STUN
+ header, followed by a STUN payload. The payload is a series of STUN
+ attributes, the set of which depends on the message type. The STUN
+ header contains a STUN message type, transaction ID, and length. The
+ message type can be Binding Request, Binding Response, Binding Error
+ Response, Shared Secret Request, Shared Secret Response, or Shared
+ Secret Error Response. The transaction ID is used to correlate
+ requests and responses. The length indicates the total length of the
+ STUN payload, not including the header. This allows STUN to run over
+ TCP. Shared Secret Requests are always sent over TCP (indeed, using
+ TLS over TCP).
+
+
+
+
+Rosenberg, et al. Standards Track [Page 8]
+
+RFC 3489 STUN March 2003
+
+
+ Several STUN attributes are defined. The first is a MAPPED-ADDRESS
+ attribute, which is an IP address and port. It is always placed in
+ the Binding Response, and it indicates the source IP address and port
+ the server saw in the Binding Request. There is also a RESPONSE-
+ ADDRESS attribute, which contains an IP address and port. The
+ RESPONSE-ADDRESS attribute can be present in the Binding Request, and
+ indicates where the Binding Response is to be sent. It's optional,
+ and when not present, the Binding Response is sent to the source IP
+ address and port of the Binding Request.
+
+ The third attribute is the CHANGE-REQUEST attribute, and it contains
+ two flags to control the IP address and port used to send the
+ response. These flags are called "change IP" and "change port"
+ flags. The CHANGE-REQUEST attribute is allowed only in the Binding
+ Request. The "change IP" and "change port" flags are useful for
+ determining whether the client is behind a restricted cone NAT or
+ restricted port cone NAT. They instruct the server to send the
+ Binding Responses from a different source IP address and port. The
+ CHANGE-REQUEST attribute is optional in the Binding Request.
+
+ The fourth attribute is the CHANGED-ADDRESS attribute. It is present
+ in Binding Responses. It informs the client of the source IP address
+ and port that would be used if the client requested the "change IP"
+ and "change port" behavior.
+
+ The fifth attribute is the SOURCE-ADDRESS attribute. It is only
+ present in Binding Responses. It indicates the source IP address and
+ port where the response was sent from. It is useful for detecting
+ twice NAT configurations.
+
+ The sixth attribute is the USERNAME attribute. It is present in a
+ Shared Secret Response, which provides the client with a temporary
+ username and password (encoded in the PASSWORD attribute). The
+ USERNAME is also present in Binding Requests, serving as an index to
+ the shared secret used for the integrity protection of the Binding
+ Request. The seventh attribute, PASSWORD, is only found in Shared
+ Secret Response messages. The eight attribute is the MESSAGE-
+ INTEGRITY attribute, which contains a message integrity check over
+ the Binding Request or Binding Response.
+
+ The ninth attribute is the ERROR-CODE attribute. This is present in
+ the Binding Error Response and Shared Secret Error Response. It
+ indicates the error that has occurred. The tenth attribute is the
+ UNKNOWN-ATTRIBUTES attribute, which is present in either the Binding
+ Error Response or Shared Secret Error Response. It indicates the
+ mandatory attributes from the request which were unknown. The
+ eleventh attribute is the REFLECTED-FROM attribute, which is present
+ in Binding Responses. It indicates the IP address and port of the
+
+
+
+Rosenberg, et al. Standards Track [Page 9]
+
+RFC 3489 STUN March 2003
+
+
+ sender of a Binding Request, used for traceability purposes to
+ prevent certain denial-of-service attacks.
+
+8. Server Behavior
+
+ The server behavior depends on whether the request is a Binding
+ Request or a Shared Secret Request.
+
+8.1 Binding Requests
+
+ A STUN server MUST be prepared to receive Binding Requests on four
+ address/port combinations - (A1, P1), (A2, P1), (A1, P2), and (A2,
+ P2). (A1, P1) represent the primary address and port, and these are
+ the ones obtained through the client discovery procedures below.
+ Typically, P1 will be port 3478, the default STUN port. A2 and P2
+ are arbitrary. A2 and P2 are advertised by the server through the
+ CHANGED-ADDRESS attribute, as described below.
+
+ It is RECOMMENDED that the server check the Binding Request for a
+ MESSAGE-INTEGRITY attribute. If not present, and the server requires
+ integrity checks on the request, it generates a Binding Error
+ Response with an ERROR-CODE attribute with response code 401. If the
+ MESSAGE-INTEGRITY attribute was present, the server computes the HMAC
+ over the request as described in Section 11.2.8. The key to use
+ depends on the shared secret mechanism. If the STUN Shared Secret
+ Request was used, the key MUST be the one associated with the
+ USERNAME attribute present in the request. If the USERNAME attribute
+ was not present, the server MUST generate a Binding Error Response.
+ The Binding Error Response MUST include an ERROR-CODE attribute with
+ response code 432. If the USERNAME is present, but the server
+ doesn't remember the shared secret for that USERNAME (because it
+ timed out, for example), the server MUST generate a Binding Error
+ Response. The Binding Error Response MUST include an ERROR-CODE
+ attribute with response code 430. If the server does know the shared
+ secret, but the computed HMAC differs from the one in the request,
+ the server MUST generate a Binding Error Response with an ERROR-CODE
+ attribute with response code 431. The Binding Error Response is sent
+ to the IP address and port the Binding Request came from, and sent
+ from the IP address and port the Binding Request was sent to.
+
+ Assuming the message integrity check passed, processing continues.
+ The server MUST check for any attributes in the request with values
+ less than or equal to 0x7fff which it does not understand. If it
+ encounters any, the server MUST generate a Binding Error Response,
+ and it MUST include an ERROR-CODE attribute with a 420 response code.
+
+
+
+
+
+
+Rosenberg, et al. Standards Track [Page 10]
+
+RFC 3489 STUN March 2003
+
+
+ That response MUST contain an UNKNOWN-ATTRIBUTES attribute listing
+ the attributes with values less than or equal to 0x7fff which were
+ not understood. The Binding Error Response is sent to the IP address
+ and port the Binding Request came from, and sent from the IP address
+ and port the Binding Request was sent to.
+
+ Assuming the request was correctly formed, the server MUST generate a
+ single Binding Response. The Binding Response MUST contain the same
+ transaction ID contained in the Binding Request. The length in the
+ message header MUST contain the total length of the message in bytes,
+ excluding the header. The Binding Response MUST have a message type
+ of "Binding Response".
+
+ The server MUST add a MAPPED-ADDRESS attribute to the Binding
+ Response. The IP address component of this attribute MUST be set to
+ the source IP address observed in the Binding Request. The port
+ component of this attribute MUST be set to the source port observed
+ in the Binding Request.
+
+ If the RESPONSE-ADDRESS attribute was absent from the Binding
+ Request, the destination address and port of the Binding Response
+ MUST be the same as the source address and port of the Binding
+ Request. Otherwise, the destination address and port of the Binding
+ Response MUST be the value of the IP address and port in the
+ RESPONSE-ADDRESS attribute.
+
+ The source address and port of the Binding Response depend on the
+ value of the CHANGE-REQUEST attribute and on the address and port the
+ Binding Request was received on, and are summarized in Table 1.
+
+ Let Da represent the destination IP address of the Binding Request
+ (which will be either A1 or A2), and Dp represent the destination
+ port of the Binding Request (which will be either P1 or P2). Let Ca
+ represent the other address, so that if Da is A1, Ca is A2. If Da is
+ A2, Ca is A1. Similarly, let Cp represent the other port, so that if
+ Dp is P1, Cp is P2. If Dp is P2, Cp is P1. If the "change port"
+ flag was set in CHANGE-REQUEST attribute of the Binding Request, and
+ the "change IP" flag was not set, the source IP address of the
+ Binding Response MUST be Da and the source port of the Binding
+ Response MUST be Cp. If the "change IP" flag was set in the Binding
+ Request, and the "change port" flag was not set, the source IP
+ address of the Binding Response MUST be Ca and the source port of the
+ Binding Response MUST be Dp. When both flags are set, the source IP
+ address of the Binding Response MUST be Ca and the source port of the
+ Binding Response MUST be Cp. If neither flag is set, or if the
+ CHANGE-REQUEST attribute is absent entirely, the source IP address of
+ the Binding Response MUST be Da and the source port of the Binding
+ Response MUST be Dp.
+
+
+
+Rosenberg, et al. Standards Track [Page 11]
+
+RFC 3489 STUN March 2003
+
+
+ Flags Source Address Source Port CHANGED-ADDRESS
+ none Da Dp Ca:Cp
+ Change IP Ca Dp Ca:Cp
+ Change port Da Cp Ca:Cp
+ Change IP and
+ Change port Ca Cp Ca:Cp
+
+ Table 1: Impact of Flags on Packet Source and CHANGED-ADDRESS
+
+ The server MUST add a SOURCE-ADDRESS attribute to the Binding
+ Response, containing the source address and port used to send the
+ Binding Response.
+
+ The server MUST add a CHANGED-ADDRESS attribute to the Binding
+ Response. This contains the source IP address and port that would be
+ used if the client had set the "change IP" and "change port" flags in
+ the Binding Request. As summarized in Table 1, these are Ca and Cp,
+ respectively, regardless of the value of the CHANGE-REQUEST flags.
+
+ If the Binding Request contained both the USERNAME and MESSAGE-
+ INTEGRITY attributes, the server MUST add a MESSAGE-INTEGRITY
+ attribute to the Binding Response. The attribute contains an HMAC
+ [13] over the response, as described in Section 11.2.8. The key to
+ use depends on the shared secret mechanism. If the STUN Shared
+ Secret Request was used, the key MUST be the one associated with the
+ USERNAME attribute present in the Binding Request.
+
+ If the Binding Request contained a RESPONSE-ADDRESS attribute, the
+ server MUST add a REFLECTED-FROM attribute to the response. If the
+ Binding Request was authenticated using a username obtained from a
+ Shared Secret Request, the REFLECTED-FROM attribute MUST contain the
+ source IP address and port where that Shared Secret Request came
+ from. If the username present in the request was not allocated using
+ a Shared Secret Request, the REFLECTED-FROM attribute MUST contain
+ the source address and port of the entity which obtained the
+ username, as best can be verified with the mechanism used to allocate
+ the username. If the username was not present in the request, and
+ the server was willing to process the request, the REFLECTED-FROM
+ attribute SHOULD contain the source IP address and port where the
+ request came from.
+
+ The server SHOULD NOT retransmit the response. Reliability is
+ achieved by having the client periodically resend the request, each
+ of which triggers a response from the server.
+
+
+
+
+
+
+
+Rosenberg, et al. Standards Track [Page 12]
+
+RFC 3489 STUN March 2003
+
+
+8.2 Shared Secret Requests
+
+ Shared Secret Requests are always received on TLS connections. When
+ the server receives a request from the client to establish a TLS
+ connection, it MUST proceed with TLS, and SHOULD present a site
+ certificate. The TLS ciphersuite TLS_RSA_WITH_AES_128_CBC_SHA [4]
+ SHOULD be used. Client TLS authentication MUST NOT be done, since
+ the server is not allocating any resources to clients, and the
+ computational burden can be a source of attacks.
+
+ If the server receives a Shared Secret Request, it MUST verify that
+ the request arrived on a TLS connection. If it did not receive the
+ request over TLS, it MUST generate a Shared Secret Error Response,
+ and it MUST include an ERROR-CODE attribute with a 433 response code.
+ The destination for the error response depends on the transport on
+ which the request was received. If the Shared Secret Request was
+ received over TCP, the Shared Secret Error Response is sent over the
+ same connection the request was received on. If the Shared Secret
+ Request was receive over UDP, the Shared Secret Error Response is
+ sent to the source IP address and port that the request came from.
+
+ The server MUST check for any attributes in the request with values
+ less than or equal to 0x7fff which it does not understand. If it
+ encounters any, the server MUST generate a Shared Secret Error
+ Response, and it MUST include an ERROR-CODE attribute with a 420
+ response code. That response MUST contain an UNKNOWN-ATTRIBUTES
+ attribute listing the attributes with values less than or equal to
+ 0x7fff which were not understood. The Shared Secret Error Response
+ is sent over the TLS connection.
+
+ All Shared Secret Error Responses MUST contain the same transaction
+ ID contained in the Shared Secret Request. The length in the message
+ header MUST contain the total length of the message in bytes,
+ excluding the header. The Shared Secret Error Response MUST have a
+ message type of "Shared Secret Error Response" (0x0112).
+
+ Assuming the request was properly constructed, the server creates a
+ Shared Secret Response. The Shared Secret Response MUST contain the
+ same transaction ID contained in the Shared Secret Request. The
+ length in the message header MUST contain the total length of the
+ message in bytes, excluding the header. The Shared Secret Response
+ MUST have a message type of "Shared Secret Response". The Shared
+ Secret Response MUST contain a USERNAME attribute and a PASSWORD
+ attribute. The USERNAME attribute serves as an index to the
+ password, which is contained in the PASSWORD attribute. The server
+ can use any mechanism it chooses to generate the username. However,
+ the username MUST be valid for a period of at least 10 minutes.
+ Validity means that the server can compute the password for that
+
+
+
+Rosenberg, et al. Standards Track [Page 13]
+
+RFC 3489 STUN March 2003
+
+
+ username. There MUST be a single password for each username. In
+ other words, the server cannot, 10 minutes later, assign a different
+ password to the same username. The server MUST hand out a different
+ username for each distinct Shared Secret Request. Distinct, in this
+ case, implies a different transaction ID. It is RECOMMENDED that the
+ server explicitly invalidate the username after ten minutes. It MUST
+ invalidate the username after 30 minutes. The PASSWORD contains the
+ password bound to that username. The password MUST have at least 128
+ bits. The likelihood that the server assigns the same password for
+ two different usernames MUST be vanishingly small, and the passwords
+ MUST be unguessable. In other words, they MUST be a
+ cryptographically random function of the username.
+
+ These requirements can still be met using a stateless server, by
+ intelligently computing the USERNAME and PASSWORD. One approach is
+ to construct the USERNAME as:
+
+ USERNAME = <prefix,rounded-time,clientIP,hmac>
+
+ Where prefix is some random text string (different for each shared
+ secret request), rounded-time is the current time modulo 20 minutes,
+ clientIP is the source IP address where the Shared Secret Request
+ came from, and hmac is an HMAC [13] over the prefix, rounded-time,
+ and client IP, using a server private key.
+
+ The password is then computed as:
+
+ password = <hmac(USERNAME,anotherprivatekey)>
+
+ With this structure, the username itself, which will be present in
+ the Binding Request, contains the source IP address where the Shared
+ Secret Request came from. That allows the server to meet the
+ requirements specified in Section 8.1 for constructing the
+ REFLECTED-FROM attribute. The server can verify that the username
+ was not tampered with, using the hmac present in the username.
+
+ The Shared Secret Response is sent over the same TLS connection the
+ request was received on. The server SHOULD keep the connection open,
+ and let the client close it.
+
+9. Client Behavior
+
+ The behavior of the client is very straightforward. Its task is to
+ discover the STUN server, obtain a shared secret, formulate the
+ Binding Request, handle request reliability, and process the Binding
+ Responses.
+
+
+
+
+
+Rosenberg, et al. Standards Track [Page 14]
+
+RFC 3489 STUN March 2003
+
+
+9.1 Discovery
+
+ Generally, the client will be configured with a domain name of the
+ provider of the STUN servers. This domain name is resolved to an IP
+ address and port using the SRV procedures specified in RFC 2782 [3].
+
+ Specifically, the service name is "stun". The protocol is "udp" for
+ sending Binding Requests, or "tcp" for sending Shared Secret
+ Requests. The procedures of RFC 2782 are followed to determine the
+ server to contact. RFC 2782 spells out the details of how a set of
+ SRV records are sorted and then tried. However, it only states that
+ the client should "try to connect to the (protocol, address,
+ service)" without giving any details on what happens in the event of
+ failure. Those details are described here for STUN.
+
+ For STUN requests, failure occurs if there is a transport failure of
+ some sort (generally, due to fatal ICMP errors in UDP or connection
+ failures in TCP). Failure also occurs if the transaction fails due
+ to timeout. This occurs 9.5 seconds after the first request is sent,
+ for both Shared Secret Requests and Binding Requests. See Section
+ 9.3 for details on transaction timeouts for Binding Requests. If a
+ failure occurs, the client SHOULD create a new request, which is
+ identical to the previous, but has a different transaction ID and
+ MESSAGE INTEGRITY attribute (the HMAC will change because the
+ transaction ID has changed). That request is sent to the next
+ element in the list as specified by RFC 2782.
+
+ The default port for STUN requests is 3478, for both TCP and UDP.
+ Administrators SHOULD use this port in their SRV records, but MAY use
+ others.
+
+ If no SRV records were found, the client performs an A record lookup
+ of the domain name. The result will be a list of IP addresses, each
+ of which can be contacted at the default port.
+
+ This would allow a firewall admin to open the STUN port, so hosts
+ within the enterprise could access new applications. Whether they
+ will or won't do this is a good question.
+
+9.2 Obtaining a Shared Secret
+
+ As discussed in Section 12, there are several attacks possible on
+ STUN systems. Many of these are prevented through integrity of
+ requests and responses. To provide that integrity, STUN makes use of
+ a shared secret between client and server, used as the keying
+ material for an HMAC used in both the Binding Request and Binding
+ Response. STUN allows for the shared secret to be obtained in any
+ way (for example, Kerberos [14]). However, it MUST have at least 128
+
+
+
+Rosenberg, et al. Standards Track [Page 15]
+
+RFC 3489 STUN March 2003
+
+
+ bits of randomness. In order to ensure interoperability, this
+ specification describes a TLS-based mechanism. This mechanism,
+ described in this section, MUST be implemented by clients and
+ servers.
+
+ First, the client determines the IP address and port that it will
+ open a TCP connection to. This is done using the discovery
+ procedures in Section 9.1. The client opens up the connection to
+ that address and port, and immediately begins TLS negotiation [2].
+ The client MUST verify the identity of the server. To do that, it
+ follows the identification procedures defined in Section 3.1 of RFC
+ 2818 [5]. Those procedures assume the client is dereferencing a URI.
+ For purposes of usage with this specification, the client treats the
+ domain name or IP address used in Section 9.1 as the host portion of
+ the URI that has been dereferenced.
+
+ Once the connection is opened, the client sends a Shared Secret
+ request. This request has no attributes, just the header. The
+ transaction ID in the header MUST meet the requirements outlined for
+ the transaction ID in a binding request, described in Section 9.3
+ below. The server generates a response, which can either be a Shared
+ Secret Response or a Shared Secret Error Response.
+
+ If the response was a Shared Secret Error Response, the client checks
+ the response code in the ERROR-CODE attribute. Interpretation of
+ those response codes is identical to the processing of Section 9.4
+ for the Binding Error Response.
+
+ If a client receives a Shared Secret Response with an attribute whose
+ type is greater than 0x7fff, the attribute MUST be ignored. If the
+ client receives a Shared Secret Response with an attribute whose type
+ is less than or equal to 0x7fff, the response is ignored.
+
+ If the response was a Shared Secret Response, it will contain a short
+ lived username and password, encoded in the USERNAME and PASSWORD
+ attributes, respectively.
+
+ The client MAY generate multiple Shared Secret Requests on the
+ connection, and it MAY do so before receiving Shared Secret Responses
+ to previous Shared Secret Requests. The client SHOULD close the
+ connection as soon as it has finished obtaining usernames and
+ passwords.
+
+ Section 9.3 describes how these passwords are used to provide
+ integrity protection over Binding Requests, and Section 8.1 describes
+ how it is used in Binding Responses.
+
+
+
+
+
+Rosenberg, et al. Standards Track [Page 16]
+
+RFC 3489 STUN March 2003
+
+
+9.3 Formulating the Binding Request
+
+ A Binding Request formulated by the client follows the syntax rules
+ defined in Section 11. Any two requests that are not bit-wise
+ identical, and not sent to the same server from the same IP address
+ and port, MUST carry different transaction IDs. The transaction ID
+ MUST be uniformly and randomly distributed between 0 and 2**128 - 1.
+ The large range is needed because the transaction ID serves as a form
+ of randomization, helping to prevent replays of previously signed
+ responses from the server. The message type of the request MUST be
+ "Binding Request".
+
+ The RESPONSE-ADDRESS attribute is optional in the Binding Request.
+ It is used if the client wishes the response to be sent to a
+ different IP address and port than the one the request was sent from.
+ This is useful for determining whether the client is behind a
+ firewall, and for applications that have separated control and data
+ components. See Section 10.3 for more details. The CHANGE-REQUEST
+ attribute is also optional. Whether it is present depends on what
+ the application is trying to accomplish. See Section 10 for some
+ example uses.
+
+ The client SHOULD add a MESSAGE-INTEGRITY and USERNAME attribute to
+ the Binding Request. This MESSAGE-INTEGRITY attribute contains an
+ HMAC [13]. The value of the username, and the key to use in the
+ MESSAGE-INTEGRITY attribute depend on the shared secret mechanism.
+ If the STUN Shared Secret Request was used, the USERNAME must be a
+ valid username obtained from a Shared Secret Response within the last
+ nine minutes. The shared secret for the HMAC is the value of the
+ PASSWORD attribute obtained from the same Shared Secret Response.
+
+ Once formulated, the client sends the Binding Request. Reliability
+ is accomplished through client retransmissions. Clients SHOULD
+ retransmit the request starting with an interval of 100ms, doubling
+ every retransmit until the interval reaches 1.6s. Retransmissions
+ continue with intervals of 1.6s until a response is received, or a
+ total of 9 requests have been sent. If no response is received by 1.6
+ seconds after the last request has been sent, the client SHOULD
+ consider the transaction to have failed. In other words, requests
+ would be sent at times 0ms, 100ms, 300ms, 700ms, 1500ms, 3100ms,
+ 4700ms, 6300ms, and 7900ms. At 9500ms, the client considers the
+ transaction to have failed if no response has been received.
+
+9.4 Processing Binding Responses
+
+ The response can either be a Binding Response or Binding Error
+ Response. Binding Error Responses are always received on the source
+ address and port the request was sent from. A Binding Response will
+
+
+
+Rosenberg, et al. Standards Track [Page 17]
+
+RFC 3489 STUN March 2003
+
+
+ be received on the address and port placed in the RESPONSE-ADDRESS
+ attribute of the request. If none was present, the Binding Responses
+ will be received on the source address and port the request was sent
+ from.
+
+ If the response is a Binding Error Response, the client checks the
+ response code from the ERROR-CODE attribute of the response. For a
+ 400 response code, the client SHOULD display the reason phrase to the
+ user. For a 420 response code, the client SHOULD retry the request,
+ this time omitting any attributes listed in the UNKNOWN-ATTRIBUTES
+ attribute of the response. For a 430 response code, the client
+ SHOULD obtain a new shared secret, and retry the Binding Request with
+ a new transaction. For 401 and 432 response codes, if the client had
+ omitted the USERNAME or MESSAGE-INTEGRITY attribute as indicated by
+ the error, it SHOULD try again with those attributes. For a 431
+ response code, the client SHOULD alert the user, and MAY try the
+ request again after obtaining a new username and password. For a 500
+ response code, the client MAY wait several seconds and then retry the
+ request. For a 600 response code, the client MUST NOT retry the
+ request, and SHOULD display the reason phrase to the user. Unknown
+ attributes between 400 and 499 are treated like a 400, unknown
+ attributes between 500 and 599 are treated like a 500, and unknown
+ attributes between 600 and 699 are treated like a 600. Any response
+ between 100 and 399 MUST result in the cessation of request
+ retransmissions, but otherwise is discarded.
+
+ If a client receives a response with an attribute whose type is
+ greater than 0x7fff, the attribute MUST be ignored. If the client
+ receives a response with an attribute whose type is less than or
+ equal to 0x7fff, request retransmissions MUST cease, but the entire
+ response is otherwise ignored.
+
+ If the response is a Binding Response, the client SHOULD check the
+ response for a MESSAGE-INTEGRITY attribute. If not present, and the
+ client placed a MESSAGE-INTEGRITY attribute into the request, it MUST
+ discard the response. If present, the client computes the HMAC over
+ the response as described in Section 11.2.8. The key to use depends
+ on the shared secret mechanism. If the STUN Shared Secret Request
+ was used, the key MUST be same as used to compute the MESSAGE-
+ INTEGRITY attribute in the request. If the computed HMAC differs
+ from the one in the response, the client MUST discard the response,
+ and SHOULD alert the user about a possible attack. If the computed
+ HMAC matches the one from the response, processing continues.
+
+ Reception of a response (either Binding Error Response or Binding
+ Response) to a Binding Request will terminate retransmissions of that
+ request. However, clients MUST continue to listen for responses to a
+ Binding Request for 10 seconds after the first response. If it
+
+
+
+Rosenberg, et al. Standards Track [Page 18]
+
+RFC 3489 STUN March 2003
+
+
+ receives any responses in this interval with different message types
+ (Binding Responses and Binding Error Responses, for example) or
+ different MAPPED-ADDRESSes, it is an indication of a possible attack.
+ The client MUST NOT use the MAPPED-ADDRESS from any of the responses
+ it received (either the first or the additional ones), and SHOULD
+ alert the user.
+
+ Furthermore, if a client receives more than twice as many Binding
+ Responses as the number of Binding Requests it sent, it MUST NOT use
+ the MAPPED-ADDRESS from any of those responses, and SHOULD alert the
+ user about a potential attack.
+
+ If the Binding Response is authenticated, and the MAPPED-ADDRESS was
+ not discarded because of a potential attack, the CLIENT MAY use the
+ MAPPED-ADDRESS and SOURCE-ADDRESS attributes.
+
+10. Use Cases
+
+ The rules of Sections 8 and 9 describe exactly how a client and
+ server interact to send requests and get responses. However, they do
+ not dictate how the STUN protocol is used to accomplish useful tasks.
+ That is at the discretion of the client. Here, we provide some
+ useful scenarios for applying STUN.
+
+10.1 Discovery Process
+
+ In this scenario, a user is running a multimedia application which
+ needs to determine which of the following scenarios applies to it:
+
+ o On the open Internet
+
+ o Firewall that blocks UDP
+
+ o Firewall that allows UDP out, and responses have to come back to
+ the source of the request (like a symmetric NAT, but no
+ translation. We call this a symmetric UDP Firewall)
+
+ o Full-cone NAT
+
+ o Symmetric NAT
+
+ o Restricted cone or restricted port cone NAT
+
+ Which of the six scenarios applies can be determined through the flow
+ chart described in Figure 2. The chart refers only to the sequence
+ of Binding Requests; Shared Secret Requests will, of course, be
+ needed to authenticate each Binding Request used in the sequence.
+
+
+
+
+Rosenberg, et al. Standards Track [Page 19]
+
+RFC 3489 STUN March 2003
+
+
+ The flow makes use of three tests. In test I, the client sends a
+ STUN Binding Request to a server, without any flags set in the
+ CHANGE-REQUEST attribute, and without the RESPONSE-ADDRESS attribute.
+ This causes the server to send the response back to the address and
+ port that the request came from. In test II, the client sends a
+ Binding Request with both the "change IP" and "change port" flags
+ from the CHANGE-REQUEST attribute set. In test III, the client sends
+ a Binding Request with only the "change port" flag set.
+
+ The client begins by initiating test I. If this test yields no
+ response, the client knows right away that it is not capable of UDP
+ connectivity. If the test produces a response, the client examines
+ the MAPPED-ADDRESS attribute. If this address and port are the same
+ as the local IP address and port of the socket used to send the
+ request, the client knows that it is not natted. It executes test
+ II.
+
+ If a response is received, the client knows that it has open access
+ to the Internet (or, at least, its behind a firewall that behaves
+ like a full-cone NAT, but without the translation). If no response
+ is received, the client knows its behind a symmetric UDP firewall.
+
+ In the event that the IP address and port of the socket did not match
+ the MAPPED-ADDRESS attribute in the response to test I, the client
+ knows that it is behind a NAT. It performs test II. If a response
+ is received, the client knows that it is behind a full-cone NAT. If
+ no response is received, it performs test I again, but this time,
+ does so to the address and port from the CHANGED-ADDRESS attribute
+ from the response to test I. If the IP address and port returned in
+ the MAPPED-ADDRESS attribute are not the same as the ones from the
+ first test I, the client knows its behind a symmetric NAT. If the
+ address and port are the same, the client is either behind a
+ restricted or port restricted NAT. To make a determination about
+ which one it is behind, the client initiates test III. If a response
+ is received, its behind a restricted NAT, and if no response is
+ received, its behind a port restricted NAT.
+
+ This procedure yields substantial information about the operating
+ condition of the client application. In the event of multiple NATs
+ between the client and the Internet, the type that is discovered will
+ be the type of the most restrictive NAT between the client and the
+ Internet. The types of NAT, in order of restrictiveness, from most
+ to least, are symmetric, port restricted cone, restricted cone, and
+ full cone.
+
+ Typically, a client will re-do this discovery process periodically to
+ detect changes, or look for inconsistent results. It is important to
+ note that when the discovery process is redone, it should not
+
+
+
+Rosenberg, et al. Standards Track [Page 20]
+
+RFC 3489 STUN March 2003
+
+
+ generally be done from the same local address and port used in the
+ previous discovery process. If the same local address and port are
+ reused, bindings from the previous test may still be in existence,
+ and these will invalidate the results of the test. Using a different
+ local address and port for subsequent tests resolves this problem.
+ An alternative is to wait sufficiently long to be confident that the
+ old bindings have expired (half an hour should more than suffice).
+
+10.2 Binding Lifetime Discovery
+
+ STUN can also be used to discover the lifetimes of the bindings
+ created by the NAT. In many cases, the client will need to refresh
+ the binding, either through a new STUN request, or an application
+ packet, in order for the application to continue to use the binding.
+ By discovering the binding lifetime, the client can determine how
+ frequently it needs to refresh.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Rosenberg, et al. Standards Track [Page 21]
+
+RFC 3489 STUN March 2003
+
+
+ +--------+
+ | Test |
+ | I |
+ +--------+
+ |
+ |
+ V
+ /\ /\
+ N / \ Y / \ Y +--------+
+ UDP <-------/Resp\--------->/ IP \------------->| Test |
+ Blocked \ ? / \Same/ | II |
+ \ / \? / +--------+
+ \/ \/ |
+ | N |
+ | V
+ V /\
+ +--------+ Sym. N / \
+ | Test | UDP <---/Resp\
+ | II | Firewall \ ? /
+ +--------+ \ /
+ | \/
+ V |Y
+ /\ /\ |
+ Symmetric N / \ +--------+ N / \ V
+ NAT <--- / IP \<-----| Test |<--- /Resp\ Open
+ \Same/ | I | \ ? / Internet
+ \? / +--------+ \ /
+ \/ \/
+ | |Y
+ | |
+ | V
+ | Full
+ | Cone
+ V /\
+ +--------+ / \ Y
+ | Test |------>/Resp\---->Restricted
+ | III | \ ? /
+ +--------+ \ /
+ \/
+ |N
+ | Port
+ +------>Restricted
+
+ Figure 2: Flow for type discovery process
+
+
+
+
+
+
+
+Rosenberg, et al. Standards Track [Page 22]
+
+RFC 3489 STUN March 2003
+
+
+ To determine the binding lifetime, the client first sends a Binding
+ Request to the server from a particular socket, X. This creates a
+ binding in the NAT. The response from the server contains a MAPPED-
+ ADDRESS attribute, providing the public address and port on the NAT.
+ Call this Pa and Pp, respectively. The client then starts a timer
+ with a value of T seconds. When this timer fires, the client sends
+ another Binding Request to the server, using the same destination
+ address and port, but from a different socket, Y. This request
+ contains a RESPONSE-ADDRESS address attribute, set to (Pa,Pp). This
+ will create a new binding on the NAT, and cause the STUN server to
+ send a Binding Response that would match the old binding, if it still
+ exists. If the client receives the Binding Response on socket X, it
+ knows that the binding has not expired. If the client receives the
+ Binding Response on socket Y (which is possible if the old binding
+ expired, and the NAT allocated the same public address and port to
+ the new binding), or receives no response at all, it knows that the
+ binding has expired.
+
+ The client can find the value of the binding lifetime by doing a
+ binary search through T, arriving eventually at the value where the
+ response is not received for any timer greater than T, but is
+ received for any timer less than T.
+
+ This discovery process takes quite a bit of time, and is something
+ that will typically be run in the background on a device once it
+ boots.
+
+ It is possible that the client can get inconsistent results each time
+ this process is run. For example, if the NAT should reboot, or be
+ reset for some reason, the process may discover a lifetime than is
+ shorter than the actual one. For this reason, implementations are
+ encouraged to run the test numerous times, and be prepared to get
+ inconsistent results.
+
+10.3 Binding Acquisition
+
+ Consider once more the case of a VoIP phone. It used the discovery
+ process above when it started up, to discover its environment. Now,
+ it wants to make a call. As part of the discovery process, it
+ determined that it was behind a full-cone NAT.
+
+ Consider further that this phone consists of two logically separated
+ components - a control component that handles signaling, and a media
+ component that handles the audio, video, and RTP [12]. Both are
+ behind the same NAT. Because of this separation of control and
+ media, we wish to minimize the communication required between them.
+ In fact, they may not even run on the same host.
+
+
+
+
+Rosenberg, et al. Standards Track [Page 23]
+
+RFC 3489 STUN March 2003
+
+
+ In order to make a voice call, the phone needs to obtain an IP
+ address and port that it can place in the call setup message as the
+ destination for receiving audio.
+
+ To obtain an address, the control component sends a Shared Secret
+ Request to the server, obtains a shared secret, and then sends a
+ Binding Request to the server. No CHANGE-REQUEST attribute is
+ present in the Binding Request, and neither is the RESPONSE-ADDRESS
+ attribute. The Binding Response contains a mapped address. The
+ control component then formulates a second Binding Request. This
+ request contains a RESPONSE-ADDRESS, which is set to the mapped
+ address learned from the previous Binding Response. This Binding
+ Request is passed to the media component, along with the IP address
+ and port of the STUN server. The media component sends the Binding
+ Request. The request goes to the STUN server, which sends the
+ Binding Response back to the control component. The control
+ component receives this, and now has learned an IP address and port
+ that will be routed back to the media component that sent the
+ request.
+
+ The client will be able to receive media from anywhere on this mapped
+ address.
+
+ In the case of silence suppression, there may be periods where the
+ client receives no media. In this case, the UDP bindings could
+ timeout (UDP bindings in NATs are typically short; 30 seconds is
+ common). To deal with this, the application can periodically
+ retransmit the query in order to keep the binding fresh.
+
+ It is possible that both participants in the multimedia session are
+ behind the same NAT. In that case, both will repeat this procedure
+ above, and both will obtain public address bindings. When one sends
+ media to the other, the media is routed to the NAT, and then turns
+ right back around to come back into the enterprise, where it is
+ translated to the private address of the recipient. This is not
+ particularly efficient, and unfortunately, does not work in many
+ commercial NATs. In such cases, the clients may need to retry using
+ private addresses.
+
+11. Protocol Details
+
+ This section presents the detailed encoding of a STUN message.
+
+ STUN is a request-response protocol. Clients send a request, and the
+ server sends a response. There are two requests, Binding Request,
+ and Shared Secret Request. The response to a Binding Request can
+
+
+
+
+
+Rosenberg, et al. Standards Track [Page 24]
+
+RFC 3489 STUN March 2003
+
+
+ either be the Binding Response or Binding Error Response. The
+ response to a Shared Secret Request can either be a Shared Secret
+ Response or a Shared Secret Error Response.
+
+ STUN messages are encoded using binary fields. All integer fields
+ are carried in network byte order, that is, most significant byte
+ (octet) first. This byte order is commonly known as big-endian. The
+ transmission order is described in detail in Appendix B of RFC 791
+ [6]. Unless otherwise noted, numeric constants are in decimal (base
+ 10).
+
+11.1 Message Header
+
+ All STUN messages consist of a 20 byte header:
+
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | STUN Message Type | Message Length |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ Transaction ID
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ The Message Types can take on the following values:
+
+ 0x0001 : Binding Request
+ 0x0101 : Binding Response
+ 0x0111 : Binding Error Response
+ 0x0002 : Shared Secret Request
+ 0x0102 : Shared Secret Response
+ 0x0112 : Shared Secret Error Response
+
+ The message length is the count, in bytes, of the size of the
+ message, not including the 20 byte header.
+
+ The transaction ID is a 128 bit identifier. It also serves as salt
+ to randomize the request and the response. All responses carry the
+ same identifier as the request they correspond to.
+
+
+
+
+
+
+
+Rosenberg, et al. Standards Track [Page 25]
+
+RFC 3489 STUN March 2003
+
+
+11.2 Message Attributes
+
+ After the header are 0 or more attributes. Each attribute is TLV
+ encoded, with a 16 bit type, 16 bit length, and variable value:
+
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Type | Length |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Value ....
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ The following types are defined:
+
+ 0x0001: MAPPED-ADDRESS
+ 0x0002: RESPONSE-ADDRESS
+ 0x0003: CHANGE-REQUEST
+ 0x0004: SOURCE-ADDRESS
+ 0x0005: CHANGED-ADDRESS
+ 0x0006: USERNAME
+ 0x0007: PASSWORD
+ 0x0008: MESSAGE-INTEGRITY
+ 0x0009: ERROR-CODE
+ 0x000a: UNKNOWN-ATTRIBUTES
+ 0x000b: REFLECTED-FROM
+
+ To allow future revisions of this specification to add new attributes
+ if needed, the attribute space is divided into optional and mandatory
+ ones. Attributes with values greater than 0x7fff are optional, which
+ means that the message can be processed by the client or server even
+ though the attribute is not understood. Attributes with values less
+ than or equal to 0x7fff are mandatory to understand, which means that
+ the client or server cannot process the message unless it understands
+ the attribute.
+
+ The MESSAGE-INTEGRITY attribute MUST be the last attribute within a
+ message. Any attributes that are known, but are not supposed to be
+ present in a message (MAPPED-ADDRESS in a request, for example) MUST
+ be ignored.
+
+ Table 2 indicates which attributes are present in which messages. An
+ M indicates that inclusion of the attribute in the message is
+ mandatory, O means its optional, C means it's conditional based on
+ some other aspect of the message, and N/A means that the attribute is
+ not applicable to that message type.
+
+
+
+
+
+Rosenberg, et al. Standards Track [Page 26]
+
+RFC 3489 STUN March 2003
+
+
+ Binding Shared Shared Shared
+ Binding Binding Error Secret Secret Secret
+ Att. Req. Resp. Resp. Req. Resp. Error
+ Resp.
+ _____________________________________________________________________
+ MAPPED-ADDRESS N/A M N/A N/A N/A N/A
+ RESPONSE-ADDRESS O N/A N/A N/A N/A N/A
+ CHANGE-REQUEST O N/A N/A N/A N/A N/A
+ SOURCE-ADDRESS N/A M N/A N/A N/A N/A
+ CHANGED-ADDRESS N/A M N/A N/A N/A N/A
+ USERNAME O N/A N/A N/A M N/A
+ PASSWORD N/A N/A N/A N/A M N/A
+ MESSAGE-INTEGRITY O O N/A N/A N/A N/A
+ ERROR-CODE N/A N/A M N/A N/A M
+ UNKNOWN-ATTRIBUTES N/A N/A C N/A N/A C
+ REFLECTED-FROM N/A C N/A N/A N/A N/A
+
+ Table 2: Summary of Attributes
+
+ The length refers to the length of the value element, expressed as an
+ unsigned integral number of bytes.
+
+11.2.1 MAPPED-ADDRESS
+
+ The MAPPED-ADDRESS attribute indicates the mapped IP address and
+ port. It consists of an eight bit address family, and a sixteen bit
+ port, followed by a fixed length value representing the IP address.
+
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ |x x x x x x x x| Family | Port |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Address |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ The port is a network byte ordered representation of the mapped port.
+ The address family is always 0x01, corresponding to IPv4. The first
+ 8 bits of the MAPPED-ADDRESS are ignored, for the purposes of
+ aligning parameters on natural boundaries. The IPv4 address is 32
+ bits.
+
+11.2.2 RESPONSE-ADDRESS
+
+ The RESPONSE-ADDRESS attribute indicates where the response to a
+ Binding Request should be sent. Its syntax is identical to MAPPED-
+ ADDRESS.
+
+
+
+
+Rosenberg, et al. Standards Track [Page 27]
+
+RFC 3489 STUN March 2003
+
+
+11.2.3 CHANGED-ADDRESS
+
+ The CHANGED-ADDRESS attribute indicates the IP address and port where
+ responses would have been sent from if the "change IP" and "change
+ port" flags had been set in the CHANGE-REQUEST attribute of the
+ Binding Request. The attribute is always present in a Binding
+ Response, independent of the value of the flags. Its syntax is
+ identical to MAPPED-ADDRESS.
+
+11.2.4 CHANGE-REQUEST
+
+ The CHANGE-REQUEST attribute is used by the client to request that
+ the server use a different address and/or port when sending the
+ response. The attribute is 32 bits long, although only two bits (A
+ and B) are used:
+
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 A B 0|
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ The meaning of the flags is:
+
+ A: This is the "change IP" flag. If true, it requests the server
+ to send the Binding Response with a different IP address than the
+ one the Binding Request was received on.
+
+ B: This is the "change port" flag. If true, it requests the
+ server to send the Binding Response with a different port than the
+ one the Binding Request was received on.
+
+11.2.5 SOURCE-ADDRESS
+
+ The SOURCE-ADDRESS attribute is present in Binding Responses. It
+ indicates the source IP address and port that the server is sending
+ the response from. Its syntax is identical to that of MAPPED-
+ ADDRESS.
+
+11.2.6 USERNAME
+
+ The USERNAME attribute is used for message integrity. It serves as a
+ means to identify the shared secret used in the message integrity
+ check. The USERNAME is always present in a Shared Secret Response,
+ along with the PASSWORD. It is optionally present in a Binding
+ Request when message integrity is used.
+
+
+
+
+
+Rosenberg, et al. Standards Track [Page 28]
+
+RFC 3489 STUN March 2003
+
+
+ The value of USERNAME is a variable length opaque value. Its length
+ MUST be a multiple of 4 (measured in bytes) in order to guarantee
+ alignment of attributes on word boundaries.
+
+11.2.7 PASSWORD
+
+ The PASSWORD attribute is used in Shared Secret Responses. It is
+ always present in a Shared Secret Response, along with the USERNAME.
+
+ The value of PASSWORD is a variable length value that is to be used
+ as a shared secret. Its length MUST be a multiple of 4 (measured in
+ bytes) in order to guarantee alignment of attributes on word
+ boundaries.
+
+11.2.8 MESSAGE-INTEGRITY
+
+ The MESSAGE-INTEGRITY attribute contains an HMAC-SHA1 [13] of the
+ STUN message. It can be present in Binding Requests or Binding
+ Responses. Since it uses the SHA1 hash, the HMAC will be 20 bytes.
+ The text used as input to HMAC is the STUN message, including the
+ header, up to and including the attribute preceding the MESSAGE-
+ INTEGRITY attribute. That text is then padded with zeroes so as to be
+ a multiple of 64 bytes. As a result, the MESSAGE-INTEGRITY attribute
+ MUST be the last attribute in any STUN message. The key used as
+ input to HMAC depends on the context.
+
+11.2.9 ERROR-CODE
+
+ The ERROR-CODE attribute is present in the Binding Error Response and
+ Shared Secret Error Response. It is a numeric value in the range of
+ 100 to 699 plus a textual reason phrase encoded in UTF-8, and is
+ consistent in its code assignments and semantics with SIP [10] and
+ HTTP [15]. The reason phrase is meant for user consumption, and can
+ be anything appropriate for the response code. The lengths of the
+ reason phrases MUST be a multiple of 4 (measured in bytes). This can
+ be accomplished by added spaces to the end of the text, if necessary.
+ Recommended reason phrases for the defined response codes are
+ presented below.
+
+ To facilitate processing, the class of the error code (the hundreds
+ digit) is encoded separately from the rest of the code.
+
+
+
+
+
+
+
+
+
+
+Rosenberg, et al. Standards Track [Page 29]
+
+RFC 3489 STUN March 2003
+
+
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | 0 |Class| Number |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Reason Phrase (variable) ..
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ The class represents the hundreds digit of the response code. The
+ value MUST be between 1 and 6. The number represents the response
+ code modulo 100, and its value MUST be between 0 and 99.
+
+ The following response codes, along with their recommended reason
+ phrases (in brackets) are defined at this time:
+
+ 400 (Bad Request): The request was malformed. The client should not
+ retry the request without modification from the previous
+ attempt.
+
+ 401 (Unauthorized): The Binding Request did not contain a MESSAGE-
+ INTEGRITY attribute.
+
+ 420 (Unknown Attribute): The server did not understand a mandatory
+ attribute in the request.
+
+ 430 (Stale Credentials): The Binding Request did contain a MESSAGE-
+ INTEGRITY attribute, but it used a shared secret that has
+ expired. The client should obtain a new shared secret and try
+ again.
+
+ 431 (Integrity Check Failure): The Binding Request contained a
+ MESSAGE-INTEGRITY attribute, but the HMAC failed verification.
+ This could be a sign of a potential attack, or client
+ implementation error.
+
+ 432 (Missing Username): The Binding Request contained a MESSAGE-
+ INTEGRITY attribute, but not a USERNAME attribute. Both must be
+ present for integrity checks.
+
+ 433 (Use TLS): The Shared Secret request has to be sent over TLS, but
+ was not received over TLS.
+
+ 500 (Server Error): The server has suffered a temporary error. The
+ client should try again.
+
+ 600 (Global Failure:) The server is refusing to fulfill the request.
+ The client should not retry.
+
+
+
+
+Rosenberg, et al. Standards Track [Page 30]
+
+RFC 3489 STUN March 2003
+
+
+11.2.10 UNKNOWN-ATTRIBUTES
+
+ The UNKNOWN-ATTRIBUTES attribute is present only in a Binding Error
+ Response or Shared Secret Error Response when the response code in
+ the ERROR-CODE attribute is 420.
+
+ The attribute contains a list of 16 bit values, each of which
+ represents an attribute type that was not understood by the server.
+ If the number of unknown attributes is an odd number, one of the
+ attributes MUST be repeated in the list, so that the total length of
+ the list is a multiple of 4 bytes.
+
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Attribute 1 Type | Attribute 2 Type |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Attribute 3 Type | Attribute 4 Type ...
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+11.2.11 REFLECTED-FROM
+
+ The REFLECTED-FROM attribute is present only in Binding Responses,
+ when the Binding Request contained a RESPONSE-ADDRESS attribute. The
+ attribute contains the identity (in terms of IP address) of the
+ source where the request came from. Its purpose is to provide
+ traceability, so that a STUN server cannot be used as a reflector for
+ denial-of-service attacks.
+
+ Its syntax is identical to the MAPPED-ADDRESS attribute.
+
+12. Security Considerations
+
+12.1 Attacks on STUN
+
+ Generally speaking, attacks on STUN can be classified into denial of
+ service attacks and eavesdropping attacks. Denial of service attacks
+ can be launched against a STUN server itself, or against other
+ elements using the STUN protocol.
+
+ STUN servers create state through the Shared Secret Request
+ mechanism. To prevent being swamped with traffic, a STUN server
+ SHOULD limit the number of simultaneous TLS connections it will hold
+ open by dropping an existing connection when a new connection request
+ arrives (based on an Least Recently Used (LRU) policy, for example).
+ Similarly, it SHOULD limit the number of shared secrets it will
+ store, in the event that the server is storing the shared secrets.
+
+
+
+
+Rosenberg, et al. Standards Track [Page 31]
+
+RFC 3489 STUN March 2003
+
+
+ The attacks of greater interest are those in which the STUN server
+ and client are used to launch DOS attacks against other entities,
+ including the client itself.
+
+ Many of the attacks require the attacker to generate a response to a
+ legitimate STUN request, in order to provide the client with a faked
+ MAPPED-ADDRESS. The attacks that can be launched using such a
+ technique include:
+
+12.1.1 Attack I: DDOS Against a Target
+
+ In this case, the attacker provides a large number of clients with
+ the same faked MAPPED-ADDRESS that points to the intended target.
+ This will trick all the STUN clients into thinking that their
+ addresses are equal to that of the target. The clients then hand out
+ that address in order to receive traffic on it (for example, in SIP
+ or H.323 messages). However, all of that traffic becomes focused at
+ the intended target. The attack can provide substantial
+ amplification, especially when used with clients that are using STUN
+ to enable multimedia applications.
+
+12.1.2 Attack II: Silencing a Client
+
+ In this attack, the attacker seeks to deny a client access to
+ services enabled by STUN (for example, a client using STUN to enable
+ SIP-based multimedia traffic). To do that, the attacker provides
+ that client with a faked MAPPED-ADDRESS. The MAPPED-ADDRESS it
+ provides is an IP address that routes to nowhere. As a result, the
+ client won't receive any of the packets it expects to receive when it
+ hands out the MAPPED-ADDRESS.
+
+ This exploitation is not very interesting for the attacker. It
+ impacts a single client, which is frequently not the desired target.
+ Moreover, any attacker that can mount the attack could also deny
+ service to the client by other means, such as preventing the client
+ from receiving any response from the STUN server, or even a DHCP
+ server.
+
+12.1.3 Attack III: Assuming the Identity of a Client
+
+ This attack is similar to attack II. However, the faked MAPPED-
+ ADDRESS points to the attacker themself. This allows the attacker to
+ receive traffic which was destined for the client.
+
+
+
+
+
+
+
+
+Rosenberg, et al. Standards Track [Page 32]
+
+RFC 3489 STUN March 2003
+
+
+12.1.4 Attack IV: Eavesdropping
+
+ In this attack, the attacker forces the client to use a MAPPED-
+ ADDRESS that routes to itself. It then forwards any packets it
+ receives to the client. This attack would allow the attacker to
+ observe all packets sent to the client. However, in order to launch
+ the attack, the attacker must have already been able to observe
+ packets from the client to the STUN server. In most cases (such as
+ when the attack is launched from an access network), this means that
+ the attacker could already observe packets sent to the client. This
+ attack is, as a result, only useful for observing traffic by
+ attackers on the path from the client to the STUN server, but not
+ generally on the path of packets being routed towards the client.
+
+12.2 Launching the Attacks
+
+ It is important to note that attacks of this nature (injecting
+ responses with fake MAPPED-ADDRESSes) require that the attacker be
+ capable of eavesdropping requests sent from the client to the server
+ (or to act as a MITM for such attacks). This is because STUN
+ requests contain a transaction identifier, selected by the client,
+ which is random with 128 bits of entropy. The server echoes this
+ value in the response, and the client ignores any responses that
+ don't have a matching transaction ID. Therefore, in order for an
+ attacker to provide a faked response that is accepted by the client,
+ the attacker needs to know what the transaction ID in the request
+ was. The large amount of randomness, combined with the need to know
+ when the client sends a request, precludes attacks that involve
+ guessing the transaction ID.
+
+ Since all of the above attacks rely on this one primitive - injecting
+ a response with a faked MAPPED-ADDRESS - preventing the attacks is
+ accomplished by preventing this one operation. To prevent it, we
+ need to consider the various ways in which it can be accomplished.
+ There are several:
+
+12.2.1 Approach I: Compromise a Legitimate STUN Server
+
+ In this attack, the attacker compromises a legitimate STUN server
+ through a virus or Trojan horse. Presumably, this would allow the
+ attacker to take over the STUN server, and control the types of
+ responses it generates.
+
+ Compromise of a STUN server can also lead to discovery of open ports.
+ Knowledge of an open port creates an opportunity for DoS attacks on
+ those ports (or DDoS attacks if the traversed NAT is a full cone
+ NAT). Discovering open ports is already fairly trivial using port
+ probing, so this does not represent a major threat.
+
+
+
+Rosenberg, et al. Standards Track [Page 33]
+
+RFC 3489 STUN March 2003
+
+
+12.2.2 Approach II: DNS Attacks
+
+ STUN servers are discovered using DNS SRV records. If an attacker
+ can compromise the DNS, it can inject fake records which map a domain
+ name to the IP address of a STUN server run by the attacker. This
+ will allow it to inject fake responses to launch any of the attacks
+ above.
+
+12.2.3 Approach III: Rogue Router or NAT
+
+ Rather than compromise the STUN server, an attacker can cause a STUN
+ server to generate responses with the wrong MAPPED-ADDRESS by
+ compromising a router or NAT on the path from the client to the STUN
+ server. When the STUN request passes through the rogue router or
+ NAT, it rewrites the source address of the packet to be that of the
+ desired MAPPED-ADDRESS. This address cannot be arbitrary. If the
+ attacker is on the public Internet (that is, there are no NATs
+ between it and the STUN server), and the attacker doesn't modify the
+ STUN request, the address has to have the property that packets sent
+ from the STUN server to that address would route through the
+ compromised router. This is because the STUN server will send the
+ responses back to the source address of the request. With a modified
+ source address, the only way they can reach the client is if the
+ compromised router directs them there. If the attacker is on the
+ public Internet, but they can modify the STUN request, they can
+ insert a RESPONSE-ADDRESS attribute into the request, containing the
+ actual source address of the STUN request. This will cause the
+ server to send the response to the client, independent of the source
+ address the STUN server sees. This gives the attacker the ability to
+ forge an arbitrary source address when it forwards the STUN request.
+
+ If the attacker is on a private network (that is, there are NATs
+ between it and the STUN server), the attacker will not be able to
+ force the server to generate arbitrary MAPPED-ADRESSes in responses.
+ They will only be able force the STUN server to generate MAPPED-
+ ADDRESSes which route to the private network. This is because the
+ NAT between the attacker and the STUN server will rewrite the source
+ address of the STUN request, mapping it to a public address that
+ routes to the private network. Because of this, the attacker can
+ only force the server to generate faked mapped addresses that route
+ to the private network. Unfortunately, it is possible that a low
+ quality NAT would be willing to map an allocated public address to
+ another public address (as opposed to an internal private address),
+ in which case the attacker could forge the source address in a STUN
+ request to be an arbitrary public address. This kind of behavior
+ from NATs does appear to be rare.
+
+
+
+
+
+Rosenberg, et al. Standards Track [Page 34]
+
+RFC 3489 STUN March 2003
+
+
+12.2.4 Approach IV: MITM
+
+ As an alternative to approach III, if the attacker can place an
+ element on the path from the client to the server, the element can
+ act as a man-in-the-middle. In that case, it can intercept a STUN
+ request, and generate a STUN response directly with any desired value
+ of the MAPPED-ADDRESS field. Alternatively, it can forward the STUN
+ request to the server (after potential modification), receive the
+ response, and forward it to the client. When forwarding the request
+ and response, this attack is subject to the same limitations on the
+ MAPPED-ADDRESS described in Section 12.2.3.
+
+12.2.5 Approach V: Response Injection Plus DoS
+
+ In this approach, the attacker does not need to be a MITM (as in
+ approaches III and IV). Rather, it only needs to be able to
+ eavesdrop onto a network segment that carries STUN requests. This is
+ easily done in multiple access networks such as ethernet or
+ unprotected 802.11. To inject the fake response, the attacker
+ listens on the network for a STUN request. When it sees one, it
+ simultaneously launches a DoS attack on the STUN server, and
+ generates its own STUN response with the desired MAPPED-ADDRESS
+ value. The STUN response generated by the attacker will reach the
+ client, and the DoS attack against the server is aimed at preventing
+ the legitimate response from the server from reaching the client.
+ Arguably, the attacker can do without the DoS attack on the server,
+ so long as the faked response beats the real response back to the
+ client, and the client uses the first response, and ignores the
+ second (even though it's different).
+
+12.2.6 Approach VI: Duplication
+
+ This approach is similar to approach V. The attacker listens on the
+ network for a STUN request. When it sees it, it generates its own
+ STUN request towards the server. This STUN request is identical to
+ the one it saw, but with a spoofed source IP address. The spoofed
+ address is equal to the one that the attacker desires to have placed
+ in the MAPPED-ADDRESS of the STUN response. In fact, the attacker
+ generates a flood of such packets. The STUN server will receive the
+ one original request, plus a flood of duplicate fake ones. It
+ generates responses to all of them. If the flood is sufficiently
+ large for the responses to congest routers or some other equipment,
+ there is a reasonable probability that the one real response is lost
+ (along with many of the faked ones), but the net result is that only
+ the faked responses are received by the STUN client. These responses
+ are all identical and all contain the MAPPED-ADDRESS that the
+ attacker wanted the client to use.
+
+
+
+
+Rosenberg, et al. Standards Track [Page 35]
+
+RFC 3489 STUN March 2003
+
+
+ The flood of duplicate packets is not needed (that is, only one faked
+ request is sent), so long as the faked response beats the real
+ response back to the client, and the client uses the first response,
+ and ignores the second (even though it's different).
+
+ Note that, in this approach, launching a DoS attack against the STUN
+ server or the IP network, to prevent the valid response from being
+ sent or received, is problematic. The attacker needs the STUN server
+ to be available to handle its own request. Due to the periodic
+ retransmissions of the request from the client, this leaves a very
+ tiny window of opportunity. The attacker must start the DoS attack
+ immediately after the actual request from the client, causing the
+ correct response to be discarded, and then cease the DoS attack in
+ order to send its own request, all before the next retransmission
+ from the client. Due to the close spacing of the retransmits (100ms
+ to a few seconds), this is very difficult to do.
+
+ Besides DoS attacks, there may be other ways to prevent the actual
+ request from the client from reaching the server. Layer 2
+ manipulations, for example, might be able to accomplish it.
+
+ Fortunately, Approach IV is subject to the same limitations
+ documented in Section 12.2.3, which limit the range of MAPPED-
+ ADDRESSes the attacker can cause the STUN server to generate.
+
+12.3 Countermeasures
+
+ STUN provides mechanisms to counter the approaches described above,
+ and additional, non-STUN techniques can be used as well.
+
+ First off, it is RECOMMENDED that networks with STUN clients
+ implement ingress source filtering (RFC 2827 [7]). This is
+ particularly important for the NATs themselves. As Section 12.2.3
+ explains, NATs which do not perform this check can be used as
+ "reflectors" in DDoS attacks. Most NATs do perform this check as a
+ default mode of operation. We strongly advise people that purchase
+ NATs to ensure that this capability is present and enabled.
+
+ Secondly, it is RECOMMENDED that STUN servers be run on hosts
+ dedicated to STUN, with all UDP and TCP ports disabled except for the
+ STUN ports. This is to prevent viruses and Trojan horses from
+ infecting STUN servers, in order to prevent their compromise. This
+ helps mitigate Approach I (Section 12.2.1).
+
+ Thirdly, to prevent the DNS attack of Section 12.2.2, Section 9.2
+ recommends that the client verify the credentials provided by the
+ server with the name used in the DNS lookup.
+
+
+
+
+Rosenberg, et al. Standards Track [Page 36]
+
+RFC 3489 STUN March 2003
+
+
+ Finally, all of the attacks above rely on the client taking the
+ mapped address it learned from STUN, and using it in application
+ layer protocols. If encryption and message integrity are provided
+ within those protocols, the eavesdropping and identity assumption
+ attacks can be prevented. As such, applications that make use of
+ STUN addresses in application protocols SHOULD use integrity and
+ encryption, even if a SHOULD level strength is not specified for that
+ protocol. For example, multimedia applications using STUN addresses
+ to receive RTP traffic would use secure RTP [16].
+
+ The above three techniques are non-STUN mechanisms. STUN itself
+ provides several countermeasures.
+
+ Approaches IV (Section 12.2.4), when generating the response locally,
+ and V (Section 12.2.5) require an attacker to generate a faked
+ response. This attack is prevented using the message integrity
+ mechanism provided in STUN, described in Section 8.1.
+
+ Approaches III (Section 12.2.3) IV (Section 12.2.4), when using the
+ relaying technique, and VI (12.2.6), however, are not preventable
+ through server signatures. Both approaches are most potent when the
+ attacker can modify the request, inserting a RESPONSE-ADDRESS that
+ routes to the client. Fortunately, such modifications are
+ preventable using the message integrity techniques described in
+ Section 9.3. However, these three approaches are still functional
+ when the attacker modifies nothing but the source address of the STUN
+ request. Sadly, this is the one thing that cannot be protected
+ through cryptographic means, as this is the change that STUN itself
+ is seeking to detect and report. It is therefore an inherent
+ weakness in NAT, and not fixable in STUN. To help mitigate these
+ attacks, Section 9.4 provides several heuristics for the client to
+ follow. The client looks for inconsistent or extra responses, both
+ of which are signs of the attacks described above. However, these
+ heuristics are just that - heuristics, and cannot be guaranteed to
+ prevent attacks. The heuristics appear to prevent the attacks as we
+ know how to launch them today. Implementors should stay posted for
+ information on new heuristics that might be required in the future.
+ Such information will be distributed on the IETF MIDCOM mailing list,
+ midcom at ietf.org.
+
+12.4 Residual Threats
+
+ None of the countermeasures listed above can prevent the attacks
+ described in Section 12.2.3 if the attacker is in the appropriate
+ network paths. Specifically, consider the case in which the attacker
+ wishes to convince client C that it has address V. The attacker
+ needs to have a network element on the path between A and the server
+ (in order to modify the request) and on the path between the server
+
+
+
+Rosenberg, et al. Standards Track [Page 37]
+
+RFC 3489 STUN March 2003
+
+
+ and V so that it can forward the response to C. Furthermore, if
+ there is a NAT between the attacker and the server, V must also be
+ behind the same NAT. In such a situation, the attacker can either
+ gain access to all the application-layer traffic or mount the DDOS
+ attack described in Section 12.1.1. Note that any host which exists
+ in the correct topological relationship can be DDOSed. It need not
+ be using STUN.
+
+13. IANA Considerations
+
+ STUN cannot be extended. Changes to the protocol are made through a
+ standards track revision of this specification. As a result, no IANA
+ registries are needed. Any future extensions will establish any
+ needed registries.
+
+14. IAB Considerations
+
+ The IAB has studied the problem of "Unilateral Self Address Fixing",
+ which is the general process by which a client attempts to determine
+ its address in another realm on the other side of a NAT through a
+ collaborative protocol reflection mechanism (RFC 3424 [17]). STUN is
+ an example of a protocol that performs this type of function. The
+ IAB has mandated that any protocols developed for this purpose
+ document a specific set of considerations. This section meets those
+ requirements.
+
+14.1 Problem Definition
+
+ From RFC 3424 [17], any UNSAF proposal must provide:
+
+ Precise definition of a specific, limited-scope problem that is to
+ be solved with the UNSAF proposal. A short term fix should not be
+ generalized to solve other problems; this is why "short term fixes
+ usually aren't".
+
+ The specific problems being solved by STUN are:
+
+ o Provide a means for a client to detect the presence of one or more
+ NATs between it and a server run by a service provider on the
+ public Internet. The purpose of such detection is to determine
+ additional steps that might be necessary in order to receive
+ service from that particular provider.
+
+ o Provide a means for a client to detect the presence of one or more
+ NATs between it and another client, where the second client is
+ reachable from the first, but it is not known whether the second
+ client resides on the public Internet.
+
+
+
+
+Rosenberg, et al. Standards Track [Page 38]
+
+RFC 3489 STUN March 2003
+
+
+ o Provide a means for a client to obtain an address on the public
+ Internet from a non-symmetric NAT, for the express purpose of
+ receiving incoming UDP traffic from another host, targeted to that
+ address.
+
+ STUN does not address TCP, either incoming or outgoing, and does not
+ address outgoing UDP communications.
+
+14.2 Exit Strategy
+
+ From [17], any UNSAF proposal must provide:
+
+ Description of an exit strategy/transition plan. The better short
+ term fixes are the ones that will naturally see less and less use
+ as the appropriate technology is deployed.
+
+ STUN comes with its own built in exit strategy. This strategy is the
+ detection operation that is performed as a precursor to the actual
+ UNSAF address-fixing operation. This discovery operation, documented
+ in Section 10.1, attempts to discover the existence of, and type of,
+ any NATS between the client and the service provider network. Whilst
+ the detection of the specific type of NAT may be brittle, the
+ discovery of the existence of NAT is itself quite robust. As NATs
+ are phased out through the deployment of IPv6, the discovery
+ operation will return immediately with the result that there is no
+ NAT, and no further operations are required. Indeed, the discovery
+ operation itself can be used to help motivate deployment of IPv6; if
+ a user detects a NAT between themselves and the public Internet, they
+ can call up their access provider and complain about it.
+
+ STUN can also help facilitate the introduction of midcom. As
+ midcom-capable NATs are deployed, applications will, instead of using
+ STUN (which also resides at the application layer), first allocate an
+ address binding using midcom. However, it is a well-known limitation
+ of midcom that it only works when the agent knows the middleboxes
+ through which its traffic will flow. Once bindings have been
+ allocated from those middleboxes, a STUN detection procedure can
+ validate that there are no additional middleboxes on the path from
+ the public Internet to the client. If this is the case, the
+ application can continue operation using the address bindings
+ allocated from midcom. If it is not the case, STUN provides a
+ mechanism for self-address fixing through the remaining midcom-
+ unaware middleboxes. Thus, STUN provides a way to help transition to
+ full midcom-aware networks.
+
+
+
+
+
+
+
+Rosenberg, et al. Standards Track [Page 39]
+
+RFC 3489 STUN March 2003
+
+
+14.3 Brittleness Introduced by STUN
+
+ From [17], any UNSAF proposal must provide:
+
+ Discussion of specific issues that may render systems more
+ "brittle". For example, approaches that involve using data at
+ multiple network layers create more dependencies, increase
+ debugging challenges, and make it harder to transition.
+
+ STUN introduces brittleness into the system in several ways:
+
+ o The discovery process assumes a certain classification of devices
+ based on their treatment of UDP. There could be other types of
+ NATs that are deployed that would not fit into one of these molds.
+ Therefore, future NATs may not be properly detected by STUN. STUN
+ clients (but not servers) would need to change to accommodate
+ that.
+
+ o The binding acquisition usage of STUN does not work for all NAT
+ types. It will work for any application for full cone NATs only.
+ For restricted cone and port restricted cone NAT, it will work for
+ some applications depending on the application. Application
+ specific processing will generally be needed. For symmetric NATs,
+ the binding acquisition will not yield a usable address. The
+ tight dependency on the specific type of NAT makes the protocol
+ brittle.
+
+ o STUN assumes that the server exists on the public Internet. If
+ the server is located in another private address realm, the user
+ may or may not be able to use its discovered address to
+ communicate with other users. There is no way to detect such a
+ condition.
+
+ o The bindings allocated from the NAT need to be continuously
+ refreshed. Since the timeouts for these bindings is very
+ implementation specific, the refresh interval cannot easily be
+ determined. When the binding is not being actively used to
+ receive traffic, but to wait for an incoming message, the binding
+ refresh will needlessly consume network bandwidth.
+
+ o The use of the STUN server as an additional network element
+ introduces another point of potential security attack. These
+ attacks are largely prevented by the security measures provided by
+ STUN, but not entirely.
+
+
+
+
+
+
+
+Rosenberg, et al. Standards Track [Page 40]
+
+RFC 3489 STUN March 2003
+
+
+ o The use of the STUN server as an additional network element
+ introduces another point of failure. If the client cannot locate
+ a STUN server, or if the server should be unavailable due to
+ failure, the application cannot function.
+
+ o The use of STUN to discover address bindings will result in an
+ increase in latency for applications. For example, a Voice over
+ IP application will see an increase of call setup delays equal to
+ at least one RTT to the STUN server.
+
+ o The discovery of binding lifetimes is prone to error. It assumes
+ that the same lifetime will exist for all bindings. This may not
+ be true if the NAT uses dynamic binding lifetimes to handle
+ overload, or if the NAT itself reboots during the discovery
+ process.
+
+ o STUN imposes some restrictions on the network topologies for
+ proper operation. If client A obtains an address from STUN server
+ X, and sends it to client B, B may not be able to send to A using
+ that IP address. The address will not work if any of the
+ following is true:
+
+ - The STUN server is not in an address realm that is a common
+ ancestor (topologically) of both clients A and B. For example,
+ consider client A and B, both of which have residential NAT
+ devices. Both devices connect them to their cable operators,
+ but both clients have different providers. Each provider has a
+ NAT in front of their entire network, connecting it to the
+ public Internet. If the STUN server used by A is in A's cable
+ operator's network, an address obtained by it will not be
+ usable by B. The STUN server must be in the network which is a
+ common ancestor to both - in this case, the public Internet.
+
+ - The STUN server is in an address realm that is a common
+ ancestor to both clients, but both clients are behind the same
+ NAT connecting to that address realm. For example, if the two
+ clients in the previous example had the same cable operator,
+ that cable operator had a single NAT connecting their network
+ to the public Internet, and the STUN server was on the public
+ Internet, the address obtained by A would not be usable by B.
+ That is because some NATs will not accept an internal packet
+ sent to a public IP address which is mapped back to an internal
+ address. To deal with this, additional protocol mechanisms or
+ configuration parameters need to be introduced which detect
+ this case.
+
+
+
+
+
+
+Rosenberg, et al. Standards Track [Page 41]
+
+RFC 3489 STUN March 2003
+
+
+ o Most significantly, STUN introduces potential security threats
+ which cannot be eliminated. This specification describes
+ heuristics that can be used to mitigate the problem, but it is
+ provably unsolvable given what STUN is trying to accomplish.
+ These security problems are described fully in Section 12.
+
+14.4 Requirements for a Long Term Solution
+
+ From [17], any UNSAF proposal must provide:
+
+ Identify requirements for longer term, sound technical solutions
+ -- contribute to the process of finding the right longer term
+ solution.
+
+ Our experience with STUN has led to the following requirements for a
+ long term solution to the NAT problem:
+
+ Requests for bindings and control of other resources in a NAT
+ need to be explicit. Much of the brittleness in STUN derives from
+ its guessing at the parameters of the NAT, rather than telling the
+ NAT what parameters to use.
+
+ Control needs to be "in-band". There are far too many scenarios
+ in which the client will not know about the location of
+ middleboxes ahead of time. Instead, control of such boxes needs
+ to occur in-band, traveling along the same path as the data will
+ itself travel. This guarantees that the right set of middleboxes
+ are controlled. This is only true for first-party controls;
+ third-party controls are best handled using the midcom framework.
+
+ Control needs to be limited. Users will need to communicate
+ through NATs which are outside of their administrative control.
+ In order for providers to be willing to deploy NATs which can be
+ controlled by users in different domains, the scope of such
+ controls needs to be extremely limited - typically, allocating a
+ binding to reach the address where the control packets are coming
+ from.
+
+ Simplicity is Paramount. The control protocol will need to be
+ implement in very simple clients. The servers will need to
+ support extremely high loads. The protocol will need to be
+ extremely robust, being the precursor to a host of application
+ protocols. As such, simplicity is key.
+
+
+
+
+
+
+
+
+Rosenberg, et al. Standards Track [Page 42]
+
+RFC 3489 STUN March 2003
+
+
+14.5 Issues with Existing NAPT Boxes
+
+ From [17], any UNSAF proposal must provide:
+
+ Discussion of the impact of the noted practical issues with
+ existing, deployed NA[P]Ts and experience reports.
+
+ Several of the practical issues with STUN involve future proofing -
+ breaking the protocol when new NAT types get deployed. Fortunately,
+ this is not an issue at the current time, since most of the deployed
+ NATs are of the types assumed by STUN. The primary usage STUN has
+ found is in the area of VoIP, to facilitate allocation of addresses
+ for receiving RTP [12] traffic. In that application, the periodic
+ keepalives are provided by the RTP traffic itself. However, several
+ practical problems arise for RTP. First, RTP assumes that RTCP
+ traffic is on a port one higher than the RTP traffic. This pairing
+ property cannot be guaranteed through NATs that are not directly
+ controllable. As a result, RTCP traffic may not be properly
+ received. Protocol extensions to SDP have been proposed which
+ mitigate this by allowing the client to signal a different port for
+ RTCP [18]. However, there will be interoperability problems for some
+ time.
+
+ For VoIP, silence suppression can cause a gap in the transmission of
+ RTP packets. This could result in the loss of a binding in the
+ middle of a call, if that silence period exceeds the binding timeout.
+ This can be mitigated by sending occasional silence packets to keep
+ the binding alive. However, the result is additional brittleness;
+ proper operation depends on the silence suppression algorithm in use,
+ the usage of a comfort noise codec, the duration of the silence
+ period, and the binding lifetime in the NAT.
+
+14.6 In Closing
+
+ The problems with STUN are not design flaws in STUN. The problems in
+ STUN have to do with the lack of standardized behaviors and controls
+ in NATs. The result of this lack of standardization has been a
+ proliferation of devices whose behavior is highly unpredictable,
+ extremely variable, and uncontrollable. STUN does the best it can in
+ such a hostile environment. Ultimately, the solution is to make the
+ environment less hostile, and to introduce controls and standardized
+ behaviors into NAT. However, until such time as that happens, STUN
+ provides a good short term solution given the terrible conditions
+ under which it is forced to operate.
+
+
+
+
+
+
+
+Rosenberg, et al. Standards Track [Page 43]
+
+RFC 3489 STUN March 2003
+
+
+15. Acknowledgments
+
+ The authors would like to thank Cedric Aoun, Pete Cordell, Cullen
+ Jennings, Bob Penfield and Chris Sullivan for their comments, and
+ Baruch Sterman and Alan Hawrylyshen for initial implementations.
+ Thanks for Leslie Daigle, Allison Mankin, Eric Rescorla, and Henning
+ Schulzrinne for IESG and IAB input on this work.
+
+16. Normative References
+
+ [1] Bradner, S., "Key words for use in RFCs to indicate requirement
+ levels", BCP 14, RFC 2119, March 1997.
+
+ [2] Dierks, T. and C. Allen, "The TLS protocol Version 1.0", RFC
+ 2246, January 1999.
+
+ [3] Gulbrandsen, A., Vixie, P. and L. Esibov, "A DNS RR for
+ specifying the location of services (DNS SRV)", RFC 2782,
+ February 2000.
+
+ [4] Chown, P., "Advanced Encryption Standard (AES) Ciphersuites for
+ Transport Layer Security (TLS)", RFC 3268, June 2002.
+
+ [5] Rescorla, E., "HTTP over TLS", RFC 2818, May 2000.
+
+ [6] Postel, J., "Internet Protocol", STD 5, RFC 791, September 1981.
+
+ [7] Ferguson, P. and D. Senie, "Network Ingress Filtering: Defeating
+ Denial of Service Attacks which employ IP Source Address
+ Spoofing", BCP 38, RFC 2827, May 2000.
+
+17. Informative References
+
+ [8] Senie, D., "Network Address Translator (NAT)-Friendly
+ Application Design Guidelines", RFC 3235, January 2002.
+
+ [9] Srisuresh, P., Kuthan, J., Rosenberg, J., Molitor, A. and A.
+ Rayhan, "Middlebox Communication Architecture and Framework",
+ RFC 3303, August 2002.
+
+ [10] Rosenberg, J., Schulzrinne, H., Camarillo, G., Johnston, A.,
+ Peterson, J., Sparks, R., Handley, M. and E. Schooler, "SIP:
+ Session Initiation Protocol", RFC 3261, June 2002.
+
+ [11] Holdrege, M. and P. Srisuresh, "Protocol Complications with the
+ IP Network Address Translator", RFC 3027, January 2001.
+
+
+
+
+
+Rosenberg, et al. Standards Track [Page 44]
+
+RFC 3489 STUN March 2003
+
+
+ [12] Schulzrinne, H., Casner, S., Frederick, R. and V. Jacobson,
+ "RTP: A Transport Protocol for Real-Time Applications", RFC
+ 1889, January 1996.
+
+ [13] Krawczyk, H., Bellare, M. and R. Canetti, "HMAC: Keyed-Hashing
+ for Message Authentication", RFC 2104, February 1997.
+
+ [14] Kohl, J. and C. Neuman, "The kerberos Network Authentication
+ Service (V5)", RFC 1510, September 1993.
+
+ [15] Fielding, R., Gettys, J., Mogul, J., Frystyk, H., Masinter, L.,
+ Leach, P. and T. Berners-Lee, "Hypertext Transfer Protocol --
+ HTTP/1.1", RFC 2616, June 1999.
+
+ [16] Baugher M., et al., "The secure real-time transport protocol",
+ Work in Progress.
+
+ [17] Daigle, L., Editor, "IAB Considerations for UNilateral Self-
+ Address Fixing (UNSAF) Across Network Address Translation", RFC
+ 3424, November 2002.
+
+ [18] Huitema, C., "RTCP attribute in SDP", Work in Progress.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Rosenberg, et al. Standards Track [Page 45]
+
+RFC 3489 STUN March 2003
+
+
+18. Authors' Addresses
+
+ Jonathan Rosenberg
+ dynamicsoft
+ 72 Eagle Rock Avenue
+ First Floor
+ East Hanover, NJ 07936
+
+ EMail: jdrosen at dynamicsoft.com
+
+
+ Joel Weinberger
+ dynamicsoft
+ 72 Eagle Rock Avenue
+ First Floor
+ East Hanover, NJ 07936
+
+ EMail: jweinberger at dynamicsoft.com
+
+
+ Christian Huitema
+ Microsoft Corporation
+ One Microsoft Way
+ Redmond, WA 98052-6399
+
+ EMail: huitema at microsoft.com
+
+
+ Rohan Mahy
+ Cisco Systems
+ 101 Cooper St
+ Santa Cruz, CA 95060
+
+ EMail: rohan at cisco.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Rosenberg, et al. Standards Track [Page 46]
+
+RFC 3489 STUN March 2003
+
+
+19. Full Copyright Statement
+
+ Copyright (C) The Internet Society (2003). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Rosenberg, et al. Standards Track [Page 47]
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/sofia-sip/stun.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/sofia-sip/stun.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,305 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005-2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef STUN_H
+/** Defined when <sofia-sip/stun.h> has been included. */
+#define STUN_H
+
+/**@file sofia-sip/stun.h STUN module public interface
+ *
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ * @author Tat Chan <Tat.Chan at nokia.com>
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Kai Vehmanen <kai.vehmanen at nokia.com>
+ */
+
+#ifndef SU_WAIT_H
+#include <sofia-sip/su_wait.h>
+#endif
+#ifndef SU_TAG_H
+#include <sofia-sip/su_tag.h>
+#endif
+#include "sofia-sip/stun_common.h"
+
+#include <sofia-sip/su_localinfo.h>
+
+SOFIA_BEGIN_DECLS
+
+typedef struct stun_handle_s stun_handle_t;
+typedef struct stun_request_s stun_request_t;
+typedef struct stun_discovery_s stun_discovery_t;
+typedef struct stun_dns_lookup_s stun_dns_lookup_t;
+
+typedef struct stun_mini_s stun_mini_t;
+
+#ifndef STUN_MAGIC_T
+#define STUN_MAGIC_T struct stun_magic_t
+#endif
+/** STUN server context */
+typedef STUN_MAGIC_T stun_magic_t;
+
+#ifndef STUN_DISCOVERY_MAGIC_T
+#define STUN_DISCOVERY_MAGIC_T struct stun_discovery_magic_t
+#endif
+/** STUN discovery_ context */
+typedef STUN_DISCOVERY_MAGIC_T stun_discovery_magic_t;
+
+/** Name and version of STUN software */
+SOFIAPUBVAR char const stun_version[];
+
+/**
+ * STUN Action types. These define the current discovery process.
+ * Defined as a bitmap.
+ */
+typedef enum stun_action_s {
+ stun_action_no_action = 1,
+ stun_action_tls_query = 2,
+ stun_action_binding_request = 4,
+ stun_action_keepalive = 8,
+ stun_action_test_nattype = 16,
+ stun_action_test_lifetime = 32,
+} stun_action_t;
+
+/**
+ * NAT types
+ *
+ * XXX: should be extended to distinguish between filtering and
+ * mapping allocation behaviour (see IETF BEHAVE documents)
+ *
+ * Note: the NAT type detection algorithm can fail in
+ * case where the NAT behaves in a nondeterministic
+ * fashion.
+ **/
+typedef enum stun_nattype_e {
+ stun_nat_unknown = 0,
+
+ /* no NAT between client and STUN server */
+ stun_open_internet,
+
+ /* UDP communication blocked by FW */
+ stun_udp_blocked,
+
+ /* No NAT, but a FW element is performing address and port
+ * restricted filtering. */
+ stun_sym_udp_fw,
+
+ /* Endpoint independent filtering (endpoint independent mapping)
+ * RFC3489 full cone NAT. */
+ stun_nat_full_cone,
+
+ /* Address restricted filtering (endpoint independent mapping),
+ * RFC3489 restricted cone NAT. */
+ stun_nat_res_cone,
+
+ /* Address and port restricted filtering (endpoint
+ * independent mapping), RFC3489 port restricted cone */
+ stun_nat_port_res_cone,
+
+ /* Endpoint independent filtering, endpoint dependent mapping. */
+ stun_nat_ei_filt_ad_map,
+
+ /* Address dependent filtering, endpoint dependent mapping. */
+ stun_nat_ad_filt_ad_map,
+
+ /* Address and port dependent filtering, endpoint dependent mapping
+ * RFC3489 symmetric NAT). */
+ stun_nat_adp_filt_ad_map,
+
+} stun_nattype_t;
+
+/**
+ * States of the STUN client->server query process.
+ *
+ * @see stun_bind()
+ * @see stun_obtain_shared_secret()
+ * @see stun_test_nattype()
+ * @see stun_test_lifetime()
+ */
+typedef enum stun_state_e {
+
+ stun_no_assigned_event,
+
+ /* TLS events; see stun_obtain_shared_request() */
+ stun_tls_connecting, /**< Connecting to TLS port */
+ stun_tls_ssl_connecting, /**< Started the TLS/SSL handshake */
+ stun_tls_writing, /**< Next step: send request */
+ stun_tls_closing, /**< Closing TLS connection */
+ stun_tls_reading, /**< Request send, waiting for response */
+ stun_tls_done, /**< Shared-secret acquired */
+
+ /* STUN discovery events */
+ stun_discovery_done, /**< Discovery process done */
+
+ /* STUN errors */
+ /* Do not change the order! Errors need to be after stun_error */
+
+ stun_error, /**< Generic error in discovery process */
+ stun_tls_connection_timeout, /**< No response to connect attempt */
+ stun_tls_connection_failed, /**< No response from TLS/SSL server */
+ stun_tls_ssl_connect_failed, /**< TLS/SSL handshake failed */
+
+ stun_discovery_error, /**< Error in discovery process */
+ stun_discovery_timeout, /**< No response to discovery request */
+
+} stun_state_t;
+
+/* -------------------------------------------------------------------
+ * Calback function prototypes (signals emitted by the stack) */
+
+/* Per discovery */
+typedef void (*stun_discovery_f)(stun_discovery_magic_t *magic,
+ stun_handle_t *sh,
+ stun_discovery_t *sd,
+ stun_action_t action,
+ stun_state_t event);
+
+/** Callback invoked by stun handle when it has a message to send. */
+typedef int (*stun_send_callback)(stun_magic_t *magic,
+ stun_handle_t *sh,
+ int socket,
+ void *data,
+ unsigned len,
+ int only_a_keepalive);
+
+/** Callback for delivering DNS lookup results */
+typedef void (*stun_dns_lookup_f)(stun_dns_lookup_t *self,
+ stun_magic_t *magic);
+
+/* -------------------------------------------------------------------
+ * Functions for managing STUN handles. */
+
+SOFIAPUBFUN stun_handle_t *stun_handle_init(su_root_t *root,
+ tag_type_t, tag_value_t, ...);
+
+SOFIAPUBFUN void stun_handle_destroy(stun_handle_t *sh);
+
+SOFIAPUBFUN su_root_t *stun_root(stun_handle_t *sh);
+SOFIAPUBFUN int stun_is_requested(tag_type_t tag, tag_value_t value, ...);
+SOFIAPUBFUN char const *stun_str_state(stun_state_t state);
+SOFIAPUBFUN su_addrinfo_t const *stun_server_address(stun_handle_t *sh);
+
+SOFIAPUBFUN
+int stun_process_message(stun_handle_t *sh, su_socket_t s,
+ su_sockaddr_t *sa, socklen_t salen,
+ void *data, isize_t len);
+SOFIAPUBFUN
+int stun_process_request(su_socket_t s, stun_msg_t *req,
+ int sid, su_sockaddr_t *from_addr,
+ socklen_t from_len);
+
+/* -------------------------------------------------------------------
+ * Functions for 'Binding Discovery' usage (RFC3489/3489bis) */
+
+SOFIAPUBFUN
+int stun_obtain_shared_secret(stun_handle_t *sh, stun_discovery_f,
+ stun_discovery_magic_t *magic,
+ tag_type_t tag, tag_value_t value, ...);
+
+SOFIAPUBFUN
+int stun_bind(stun_handle_t *sh,
+ stun_discovery_f, stun_discovery_magic_t *magic,
+ tag_type_t tag, tag_value_t value, ...);
+
+SOFIAPUBFUN
+int stun_discovery_get_address(stun_discovery_t *sd,
+ void *addr,
+ socklen_t *return_addrlen);
+SOFIAPUBFUN su_socket_t stun_discovery_get_socket(stun_discovery_t *sd);
+SOFIAPUBFUN int stun_discovery_release_socket(stun_discovery_t *sd);
+
+SOFIAPUBFUN
+int stun_test_nattype(stun_handle_t *sh,
+ stun_discovery_f, stun_discovery_magic_t *magic,
+ tag_type_t tag, tag_value_t value, ...);
+SOFIAPUBFUN char const *stun_nattype_str(stun_discovery_t *sd);
+SOFIAPUBFUN stun_nattype_t stun_nattype(stun_discovery_t *sd);
+
+SOFIAPUBFUN
+int stun_test_lifetime(stun_handle_t *sh,
+ stun_discovery_f, stun_discovery_magic_t *magic,
+ tag_type_t tag, tag_value_t value, ...);
+SOFIAPUBFUN int stun_lifetime(stun_discovery_t *sd);
+
+/* -------------------------------------------------------------------
+ * Functions for 'Connectivity Check' and 'NAT Keepalives' usages (RFC3489bis) */
+
+SOFIAPUBFUN
+int stun_set_uname_pwd(stun_handle_t *sh,
+ const char *uname,
+ isize_t len_uname,
+ const char *pwd,
+ isize_t len_pwd);
+
+SOFIAPUBFUN int stun_msg_is_keepalive(uint16_t data);
+SOFIAPUBFUN int stun_message_length(void *data, isize_t len, int end_of_message);
+
+/* Create a keepalive dispatcher for bound SIP sockets */
+
+SOFIAPUBFUN
+int stun_keepalive(stun_handle_t *sh,
+ su_sockaddr_t *sa,
+ tag_type_t tag, tag_value_t value,
+ ...);
+SOFIAPUBFUN int stun_keepalive_destroy(stun_handle_t *sh, su_socket_t s);
+
+/* -------------------------------------------------------------------
+ * Functions for 'Short-Term password' usage (RFC3489bis) */
+
+/* (not implemented, see stun_request_shared_secret()) */
+
+/* -------------------------------------------------------------------
+ * Functions for STUN server discovery using DNS (RFC3489/3489bis) */
+
+SOFIAPUBFUN
+stun_dns_lookup_t *stun_dns_lookup(stun_magic_t *magic,
+ su_root_t *root,
+ stun_dns_lookup_f func,
+ const char *domain);
+SOFIAPUBFUN void stun_dns_lookup_destroy(stun_dns_lookup_t *self);
+
+SOFIAPUBFUN int stun_dns_lookup_udp_addr(stun_dns_lookup_t *,
+ const char **target, uint16_t *port);
+SOFIAPUBFUN int stun_dns_lookup_tcp_addr(stun_dns_lookup_t *self,
+ const char **target, uint16_t *port);
+SOFIAPUBFUN int stun_dns_lookup_stp_addr(stun_dns_lookup_t *self,
+ const char **target, uint16_t *port);
+
+/* -------------------------------------------------------------------
+ * Functions for minimal STUN server */
+
+SOFIAPUBFUN stun_mini_t *stun_mini_create(void);
+SOFIAPUBFUN void stun_mini_destroy(stun_mini_t *);
+
+SOFIAPUBFUN int stun_mini_add_socket(stun_mini_t *server,
+ su_socket_t socket);
+SOFIAPUBFUN int stun_mini_remove_socket(stun_mini_t *server,
+ su_socket_t socket);
+
+SOFIAPUBFUN void stun_mini_request(stun_mini_t *server, su_socket_t socket,
+ void *msg, ssize_t msglen,
+ void *addr, socklen_t addrlen);
+
+SOFIA_END_DECLS
+
+#endif /* !defined(STUN_H) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/sofia-sip/stun_common.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/sofia-sip/stun_common.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,253 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef STUN_COMMON_H
+/** Defined when <sofia-sip/stun_common.h> has been included. */
+#define STUN_COMMON_H
+
+/**
+ * @file sofia-sip/stun_common.h
+ * @brief
+ *
+ * @author Tat Chan <Tat.Chan at nokia.com>
+ *
+ * @date Created: Fri Oct 3 13:39:55 2003 ppessi
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+
+#ifdef WIN32
+#include <winsock.h>
+#else
+#include <sys/socket.h>
+#include <netinet/tcp.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+
+#include <sofia-sip/su.h>
+#include <sofia-sip/su_localinfo.h>
+
+SOFIA_BEGIN_DECLS
+
+/* Define Message Types */
+#define BINDING_REQUEST 0x0001
+#define BINDING_RESPONSE 0x0101
+#define BINDING_ERROR_RESPONSE 0x0111
+#define SHARED_SECRET_REQUEST 0x0002
+#define SHARED_SECRET_RESPONSE 0x0102
+#define SHARED_SECRET_ERROR_RESPONSE 0x0112
+
+/* Define Attribute Types */
+#define MAPPED_ADDRESS 0x0001
+#define RESPONSE_ADDRESS 0x0002
+#define CHANGE_REQUEST 0x0003
+#define SOURCE_ADDRESS 0x0004
+#define CHANGED_ADDRESS 0x0005
+#define USERNAME 0x0006
+#define PASSWORD 0x0007
+#define MESSAGE_INTEGRITY 0x0008
+#define ERROR_CODE 0x0009
+#define UNKNOWN_ATTRIBUTES 0x000a
+#define REFLECTED_FROM 0x000b
+#define STUN_A_REALM 0x0014 /* XXX: check value in 3489bis-05+ */
+#define STUN_A_NONCE 0x0015 /* XXX: check value in 3489bis-05+ */
+#define STUN_A_XOR_MAPPED_ADDRESS 0x0020
+#define STUN_A_FINGERPRINT 0x0023
+#define STUN_A_SERVER 0x8022
+#define STUN_A_ALTERNATE_SERVER 0x8023
+#define STUN_A_REFRESH_INTERVAL 0x8024
+
+/* Defines for mandatory and optional attributes */
+#define STUN_A_LAST_MANDATORY 0x0023 /**< largest attribute in the current
+ spec (see above for exceptions
+ for buggy servers) */
+#define STUN_A_OPTIONAL 0x7fff
+
+/* Compability attribute types */
+#define STUN_A_ALTERNATE_SERVER_DEP 0x000e /**< historic from early fc3489bis drafts */
+#define STUN_A_BUGGYSERVER_XORONLY 0x0021 /**< workaround for stund-0.94 and older */
+#define STUN_A_BUGGYSERVER_SERVER 0x0022 /**< workaround for stund-0.94 and older */
+#define LARGEST_ATTRIBUTE STUN_A_LAST_MANDATORY /**< deprecated API */
+#define OPTIONAL_ATTRIBUTE STUN_A_OPTIONAL /**< deprecated API */
+
+/* Stun response codes */
+#define STUN_400_BAD_REQUEST 400
+#define STUN_401_UNAUTHORIZED 401
+#define STUN_420_UNKNOWN_ATTRIBUTE 420
+#define STUN_430_STALE_CREDENTIALS 430
+#define STUN_431_INTEGRITY_CHECK_FAILURE 431
+#define STUN_432_MISSING_USERNAME 432
+#define STUN_433_USE_TLS 433
+#define STUN_500_SERVER_ERROR 500
+#define STUN_600_GLOBAL_FAILURE 600
+
+/* flags for CHANGE_REQUEST */
+#define STUN_CR_CHANGE_IP 0x0004
+#define STUN_CR_CHANGE_PORT 0x0002
+
+/* mask for ERROR_CODE */
+#define STUN_EC_CLASS 0x0070
+#define STUN_EC_NUM 0x000F
+
+#define RAND_MAX_16 65535
+
+#define STUN_TID_BYTES 16
+
+/* other protocol specific parameters */
+#define STUN_MAX_RETRX 5 /* should be 8? */
+#define STUN_MAX_RETRX_INT 1600 /**< max retrx interval in
+ millisec */
+#define STUN_DEFAULT_PORT 3478 /**< from RFC3489 */
+
+/*
+ * STUN header format
+ */
+ /*
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | message type | message length |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ | Transaction ID |
+ | |
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct stun_buffer_s {
+ unsigned char *data; /**< Pointer to data */
+ unsigned size; /**< Size of buffer */
+};
+
+typedef struct stun_buffer_s stun_buffer_t;
+
+typedef struct {
+ uint16_t msg_type; /**< message type */
+ uint16_t msg_len; /**< message length */
+ uint8_t tran_id[16]; /**< transaction id, 128 bits */
+} stun_hdr_t;
+
+typedef struct stun_attr_s {
+ uint16_t attr_type; /**< attribute type */
+ void *pattr; /**< pointer to corresponding attribute */
+ stun_buffer_t enc_buf; /**< encoded attribue */
+ struct stun_attr_s *next; /**< next attribute */
+} stun_attr_t;
+
+typedef struct {
+ stun_hdr_t stun_hdr;
+ stun_attr_t *stun_attr;
+ stun_buffer_t enc_buf; /**< to store already encoded stun msg */
+} stun_msg_t;
+
+/* stun attribute definition */
+/* stun_sockaddr_t is used for:
+ MAPPED_ADDRESS
+ RESPONSE_ADDRESS
+ SOURCE_ADDRESS
+ CHANGED_ADDRESS
+ REFLECTED_FROM
+*/
+typedef struct sockaddr_in stun_attr_sockaddr_t;
+
+/* CHANGE_REQUEST attribute */
+typedef struct stun_attr_uint32_s {
+ uint32_t value;
+} stun_attr_uint32_t;
+
+typedef stun_attr_uint32_t stun_attr_changerequest_t;
+
+/* ERROR_CODE attribute */
+typedef struct {
+ int code;
+ char *phrase;
+} stun_attr_errorcode_t;
+
+/* USERNAME attribute */
+/* typedef struct {
+ stun_buffer_t *uname;
+} stun_attr_username_t;
+*/
+typedef stun_buffer_t stun_attr_username_t;
+
+/* PASSWORD attribute */
+typedef stun_buffer_t stun_attr_password_t;
+
+/* UNKNOWN_ATTRIBUTES attribute */
+typedef struct stun_attr_unknownattributes_s{
+ uint16_t attr_type[2];
+ struct stun_attr_unknownattributes_s *next;
+} stun_attr_unknownattributes_t;
+
+/* Common functions */
+int stun_parse_message(stun_msg_t *msg);
+int stun_parse_attribute(stun_msg_t *msg, unsigned char *p);
+int stun_parse_attr_address(stun_attr_t *attr, const unsigned char *p, unsigned len);
+int stun_parse_attr_error_code(stun_attr_t *attr, const unsigned char *p, unsigned len);
+int stun_parse_attr_unknown_attributes(stun_attr_t *attr, const unsigned char *p, unsigned len);
+int stun_parse_attr_uint32(stun_attr_t *attr, const unsigned char *p, unsigned len);
+int stun_parse_attr_buffer(stun_attr_t *attr, const unsigned char *p, unsigned len);
+
+stun_attr_t *stun_get_attr(stun_attr_t *attr, uint16_t attr_type);
+
+int stun_encode_address(stun_attr_t *attr);
+int stun_encode_uint32(stun_attr_t *attr);
+int stun_encode_buffer(stun_attr_t *attr);
+int stun_encode_error_code(stun_attr_t *attr);
+int stun_encode_message_integrity(stun_attr_t *attr, unsigned char *buf, int len, stun_buffer_t *pwd);
+int stun_encode_type_len(stun_attr_t *attr, uint16_t len);
+int stun_encode_response_address(stun_attr_t *attr);
+
+int stun_validate_message_integrity(stun_msg_t *msg, stun_buffer_t *pwd);
+
+int stun_copy_buffer(stun_buffer_t *p, stun_buffer_t *p2);
+void stun_init_buffer(stun_buffer_t *p);
+int stun_free_buffer(stun_buffer_t *p);
+int stun_free_message(stun_msg_t *msg);
+
+int stun_init_message(stun_msg_t *msg);
+/* int stun_send_message(int sockfd, struct sockaddr_in *to_addr, stun_msg_t *msg, stun_buffer_t *pwd); */
+int stun_encode_message(stun_msg_t *msg, stun_buffer_t *pwd);
+
+char const *stun_response_phrase(int status);
+void debug_print(stun_buffer_t *buf);
+char const *stun_attr_phrase(uint16_t type);
+
+/**Determines and returns local IP address
+ *
+ * Address is determined using su_getlocalinfo() function.
+ *
+ * @param family network address family in use
+ * @return local ip address
+ */
+char *stun_determine_ip_address(int family);
+
+SOFIA_END_DECLS
+
+#endif /* !defined STUN_COMMON_H */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/sofia-sip/stun_tag.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/sofia-sip/stun_tag.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,105 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005-2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef STUN_TAG_H
+#define STUN_TAG_H
+/**@file sofia-sip/stun_tag.h Tags for STUN.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ * @author Kai Vehmanen <Kai.Vehmanen at nokia.com>
+ *
+ * @date Created: Tue Oct 18 20:13:50 EEST 2005 ppessi
+ */
+
+#ifndef SU_TAG_H
+#include <sofia-sip/su_tag.h>
+#endif
+#ifndef SU_TAG_IO_H
+#include <sofia-sip/su_tag_io.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/*****************************************
+ * Note: see documentation in stun_tag.c *
+ *****************************************/
+
+#define STUNTAG_ANY() stuntag_any, ((tag_value_t)0)
+SOFIAPUBVAR tag_typedef_t stuntag_any;
+
+#define STUNTAG_DOMAIN(x) stuntag_domain, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t stuntag_domain;
+#define STUNTAG_DOMAIN_REF(x) stuntag_domain_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t stuntag_domain_ref;
+
+#define STUNTAG_SERVER(x) stuntag_server, tag_str_v(x)
+SOFIAPUBVAR tag_typedef_t stuntag_server;
+#define STUNTAG_SERVER_REF(x) stuntag_server_ref, tag_str_vr(&(x))
+SOFIAPUBVAR tag_typedef_t stuntag_server_ref;
+
+#define STUNTAG_REQUIRE_INTEGRITY(x) stuntag_require_integrity, tag_int_v(x)
+SOFIAPUBVAR tag_typedef_t stuntag_require_integrity;
+#define STUNTAG_REQUIRE_INTEGRITY_REF(x) stuntag_require_integrity_ref, tag_int_vr(&(x))
+SOFIAPUBVAR tag_typedef_t stuntag_require_integrity_ref;
+
+#define STUNTAG_INTEGRITY(x) stuntag_integrity, tag_int_v(x)
+SOFIAPUBVAR tag_typedef_t stuntag_integrity;
+#define STUNTAG_INTEGRITY_REF(x) stuntag_integrity_ref, tag_int_vr(&(x))
+SOFIAPUBVAR tag_typedef_t stuntag_integrity_ref;
+
+#define STUNTAG_SOCKET(x) stuntag_socket, tag_socket_v(x)
+SOFIAPUBVAR tag_typedef_t stuntag_socket;
+#define STUNTAG_SOCKET_REF(x) stuntag_socket_ref, tag_socket_vr(&(x))
+SOFIAPUBVAR tag_typedef_t stuntag_socket_ref;
+
+#define STUNTAG_REGISTER_EVENTS(x) stuntag_register_events, tag_int_v(x)
+SOFIAPUBVAR tag_typedef_t stuntag_register_events;
+#define STUNTAG_REGISTER_EVENTS_REF(x) stuntag_register_events_ref, tag_int_vr(&(x))
+SOFIAPUBVAR tag_typedef_t stuntag_register_events_ref;
+
+#define STUNTAG_ACTION(x) stuntag_action, tag_int_v(x)
+SOFIAPUBVAR tag_typedef_t stuntag_action;
+#define STUNTAG_ACTION_REF(x) stuntag_action_ref, tag_int_vr(&(x))
+SOFIAPUBVAR tag_typedef_t stuntag_action_ref;
+
+#define STUNTAG_CHANGE_IP(x) stuntag_change_ip, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t stuntag_change_ip;
+#define STUNTAG_CHANGE_IP_REF(x) stuntag_change_ip_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t stuntag_change_ip_ref;
+
+#define STUNTAG_CHANGE_PORT(x) stuntag_change_port, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t stuntag_change_port;
+#define STUNTAG_CHANGE_PORT_REF(x) stuntag_change_port_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t stuntag_change_port_ref;
+
+#define STUNTAG_TIMEOUT(x) stuntag_timeout, tag_uint_v((x))
+SOFIAPUBVAR tag_typedef_t stuntag_timeout;
+#define STUNTAG_TIMEOUT_REF(x) stuntag_timeout_ref, tag_uint_vr(&(x))
+SOFIAPUBVAR tag_typedef_t stuntag_timeout_ref;
+
+
+SOFIA_END_DECLS
+
+#endif /* STUN_TAG_H */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stun.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stun.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,3138 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005-2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**
+ * @file stun.c STUN client module
+ *
+ * See RFC 3489/3489bis for further information.
+ *
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ * @author Tat Chan <Tat.Chan at nokia.com>
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Kai Vehmanen <Kai.Vehmanen at nokia.com>
+ *
+ * @date Created: Thu Jul 24 17:21:00 2003 ppessi
+ */
+
+#include "config.h"
+
+#include <assert.h>
+#include <string.h>
+
+#define SU_ROOT_MAGIC_T struct stun_magic_t
+
+#include "sofia-sip/stun.h"
+#include "stun_internal.h"
+#include "sofia-sip/stun_tag.h"
+
+#include <sofia-sip/su_alloc.h>
+#include <sofia-sip/su_tagarg.h>
+#include <sofia-sip/su_log.h>
+#include <sofia-sip/su.h>
+#include <sofia-sip/su_localinfo.h>
+
+#if HAVE_WINSOCK2_H
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#endif
+
+#if defined(HAVE_OPENSSL)
+#include <openssl/opensslv.h>
+#endif
+
+#if !defined(ETIMEDOUT) && defined(_WIN32)
+#define ETIMEDOUT WSAETIMEDOUT
+#endif
+
+/* Missing socket symbols */
+#ifndef SOL_TCP
+#define SOL_TCP IPPROTO_TCP
+#endif
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+static char const __func__[] = "stun";
+#endif
+
+/** STUN log. */
+su_log_t stun_log[] = { SU_LOG_INIT("stun", "STUN_DEBUG", 3) };
+
+/**@var STUN_DEBUG
+ *
+ * Environment variable determining the debug log level for @b stun module.
+ *
+ * The STUN_DEBUG environment variable is used to determine the debug logging
+ * level for @b stun module. The default level is 3.
+ *
+ * @sa <sofia-sip/su_debug.h>, stun_log, SOFIA_DEBUG
+ */
+extern char const STUN__DEBUG[];
+
+enum {
+ STUN_SENDTO_TIMEOUT = 1000,
+ STUN_TLS_CONNECT_TIMEOUT = 8000,
+};
+
+/**
+ * States of STUN requests. See stun_state_e for states
+ * discovery processes.
+ */
+typedef enum stun_req_state_e {
+ stun_req_no_assigned_event,
+ stun_req_dispose_me, /**< request can be disposed */
+ stun_req_discovery_init,
+ stun_req_discovery_processing,
+
+ stun_req_error,
+ stun_req_timeout
+} stun_req_state_t;
+
+#define CHG_IP 0x001
+#define CHG_PORT 0x004
+
+#define x_insert(l, n, x) \
+ ((l) ? (l)->x##_prev = &(n)->x##_next : 0, \
+ (n)->x##_next = (l), (n)->x##_prev = &(l), (l) = (n))
+
+#define x_remove(n, x) \
+ ((*(n)->x##_prev = (n)->x##_next) ? \
+ (n)->x##_next->x##_prev = (n)->x##_prev : 0)
+
+#define x_is_inserted(n, x) ((n)->x##_prev != NULL)
+
+struct stun_discovery_s {
+ stun_discovery_t *sd_next, **sd_prev; /**< Linked list */
+
+ stun_handle_t *sd_handle;
+ stun_discovery_f sd_callback;
+ stun_discovery_magic_t *sd_magic;
+
+ tagi_t *sd_tags; /** stored tags for the discovery */
+
+
+ su_addrinfo_t sd_pri_info; /**< server primary info */
+ su_sockaddr_t sd_pri_addr[1]; /**< server primary address */
+
+ su_addrinfo_t sd_sec_info; /**< server secondary info */
+ su_sockaddr_t sd_sec_addr[1]; /**< server secondary address */
+
+ stun_action_t sd_action; /**< My action */
+ stun_state_t sd_state; /**< Progress states */
+
+ su_socket_t sd_socket; /**< target socket */
+ su_sockaddr_t sd_bind_addr[1]; /**< local address */
+
+ su_socket_t sd_socket2; /**< Alternative socket */
+
+ int sd_index; /**< root_register index */
+
+ /* Binding discovery */
+ su_sockaddr_t sd_addr_seen_outside[1]; /**< local address */
+
+ /* NAT type related */
+ stun_nattype_t sd_nattype; /**< Determined NAT type */
+ int sd_mapped_addr_match; /** Mapped addresses match? */
+ int sd_first; /**< These are the requests */
+ int sd_second;
+ int sd_third;
+ int sd_fourth;
+
+ /* Life time related */
+ int sd_lt_cur;
+ int sd_lt;
+ int sd_lt_max;
+
+ /* Keepalive timeout */
+ unsigned int sd_timeout;
+ su_timer_t *sd_timer;
+};
+
+struct stun_request_s {
+ su_timer_t *sr_timer;
+ stun_request_t *sr_next, **sr_prev; /**< Linked list */
+ stun_msg_t *sr_msg; /**< STUN message pointer */
+ stun_handle_t *sr_handle; /**< backpointer, STUN object */
+
+ su_socket_t sr_socket; /**< Alternative socket */
+ su_localinfo_t sr_localinfo; /**< local addrinfo */
+ su_sockaddr_t sr_local_addr[1]; /**< local address */
+ su_sockaddr_t sr_destination[1];
+
+ stun_state_t sr_state; /**< Progress states */
+ int sr_retry_count; /**< current retry number */
+ long sr_timeout; /**< timeout for next sendto() */
+
+ int sr_from_y;
+ int sr_request_mask; /**< Mask consisting of chg_ip and chg_port */
+ stun_discovery_t *sr_discovery;
+};
+
+struct stun_handle_s
+{
+ su_home_t sh_home[1];
+ su_root_t *sh_root; /**< event loop */
+ int sh_root_index; /**< object index of su_root_register() */
+
+ stun_request_t *sh_requests; /**< outgoing requests list */
+ stun_discovery_t *sh_discoveries; /**< Actions list */
+
+ int sh_max_retries; /**< max resend for sendto() */
+
+ su_addrinfo_t sh_pri_info; /**< server primary info */
+ su_sockaddr_t sh_pri_addr[1]; /**< server primary address */
+
+ su_addrinfo_t sh_sec_info; /**< server secondary info */
+ su_sockaddr_t sh_sec_addr[1]; /**< server secondary address */
+
+ su_localinfo_t sh_localinfo; /**< local addrinfo */
+ su_sockaddr_t sh_local_addr[1]; /**< local address */
+
+ char *sh_domain; /**< domain address for DNS-SRV lookups */
+
+ stun_dns_lookup_t *sh_dns_lookup;
+ stun_action_t sh_dns_pend_action;
+ stun_discovery_f sh_dns_pend_cb;
+ stun_discovery_magic_t *sh_dns_pend_ctx;
+ tagi_t *sh_dns_pend_tags;
+
+#if defined(HAVE_OPENSSL)
+ SSL_CTX *sh_ctx; /**< SSL context for TLS */
+ SSL *sh_ssl; /**< SSL handle for TLS */
+#else
+ void *sh_ctx; /**< SSL context for TLS */
+ void *sh_ssl; /**< SSL handle for TLS */
+#endif
+
+ stun_msg_t sh_tls_request;
+ stun_msg_t sh_tls_response;
+ int sh_nattype; /**< NAT-type, see stun_common.h */
+
+ stun_buffer_t sh_username;
+ stun_buffer_t sh_passwd;
+
+ int sh_use_msgint; /**< try message integrity (TLS) */
+ int sh_req_msgint; /**< require use of msg-int (TLS) */
+};
+
+
+#define STUN_STATE_STR(x) case x: return #x
+
+char const *stun_str_state(stun_state_t state)
+{
+ switch (state) {
+ STUN_STATE_STR(stun_no_assigned_event);
+ /* STUN_STATE_STR(stun_req_dispose_me); */
+ STUN_STATE_STR(stun_tls_connecting);
+ STUN_STATE_STR(stun_tls_writing);
+ STUN_STATE_STR(stun_tls_closing);
+ STUN_STATE_STR(stun_tls_reading);
+ STUN_STATE_STR(stun_tls_done);
+ /* STUN_STATE_STR(stun_req_discovery_init); */
+ /* STUN_STATE_STR(stun_req_discovery_processing); */
+ STUN_STATE_STR(stun_discovery_done);
+ STUN_STATE_STR(stun_tls_connection_timeout);
+ STUN_STATE_STR(stun_tls_connection_failed);
+ STUN_STATE_STR(stun_tls_ssl_connect_failed);
+ STUN_STATE_STR(stun_discovery_timeout);
+ /* STUN_STATE_STR(stun_req_timeout); */
+
+ case stun_error:
+ default: return "stun_error";
+ }
+}
+
+/**
+ * Returns the NAT type attached to STUN discovery handle.
+ *
+ * @see stun_nattype_str().
+ * @see stun_test_nattype().
+ */
+char const *stun_nattype_str(stun_discovery_t *sd)
+{
+ char const *stun_nattype_str[] = {
+ "NAT type undetermined",
+ "Open Internet",
+ "UDP traffic is blocked or server unreachable",
+ "Symmetric UDP Firewall",
+ "Full-Cone NAT (endpoint independent filtering and mapping)",
+ "Restricted Cone NAT (endpoint independent mapping)",
+ "Port Restricted Cone NAT (endpoint independent mapping)",
+ "Endpoint independent filtering, endpoint dependent mapping",
+ "Address dependent filtering, endpoint dependent mapping",
+ "Symmetric NAT (address and port dependent filtering, endpoint dependent mapping)",
+ };
+
+ if (sd)
+ return stun_nattype_str[sd->sd_nattype];
+ else
+ return stun_nattype_str[stun_nat_unknown];
+}
+
+/**
+ * Returns the detected NAT type.
+ *
+ * @see stun_nattype_str().
+ * @see stun_test_nattype().
+ */
+stun_nattype_t stun_nattype(stun_discovery_t *sd)
+{
+ if (!sd)
+ return stun_nat_unknown;
+
+ return sd->sd_nattype;
+}
+
+su_addrinfo_t const *stun_server_address(stun_handle_t *sh)
+{
+ return &sh->sh_pri_info;
+}
+
+int stun_lifetime(stun_discovery_t *sd)
+{
+ return sd ? sd->sd_lt_cur : -1;
+}
+
+
+#if defined(HAVE_OPENSSL)
+char const stun_version[] =
+ "sofia-sip-stun using " OPENSSL_VERSION_TEXT;
+#else
+char const stun_version[] =
+ "sofia-sip-stun";
+#endif
+
+static int do_action(stun_handle_t *sh, stun_msg_t *binding_response);
+static int stun_tls_callback(su_root_magic_t *m, su_wait_t *w, su_wakeup_arg_t *arg);
+static int process_binding_request(stun_request_t *req, stun_msg_t *binding_response);
+static stun_discovery_t *stun_discovery_create(stun_handle_t *sh,
+ stun_action_t action,
+ stun_discovery_f sdf,
+ stun_discovery_magic_t *magic);
+static int stun_discovery_destroy(stun_discovery_t *sd);
+static int action_bind(stun_request_t *req, stun_msg_t *binding_response);
+static int action_determine_nattype(stun_request_t *req, stun_msg_t *binding_response);
+static int process_test_lifetime(stun_request_t *req, stun_msg_t *binding_response);
+
+static stun_request_t *stun_request_create(stun_discovery_t *sd);
+static int stun_send_binding_request(stun_request_t *req,
+ su_sockaddr_t *srvr_addr);
+static int stun_bind_callback(stun_magic_t *m, su_wait_t *w, su_wakeup_arg_t *arg);
+
+#if defined (__CYGWIN__)
+static int get_localinfo(int family, su_sockaddr_t *su, socklen_t *return_len);
+#endif
+
+/* timers */
+static void stun_sendto_timer_cb(su_root_magic_t *magic,
+ su_timer_t *t,
+ su_timer_arg_t *arg);
+static void stun_tls_connect_timer_cb(su_root_magic_t *magic,
+ su_timer_t *t,
+ su_timer_arg_t *arg);
+static void stun_test_lifetime_timer_cb(su_root_magic_t *magic,
+ su_timer_t *t,
+ su_timer_arg_t *arg);
+static void stun_keepalive_timer_cb(su_root_magic_t *magic,
+ su_timer_t *t,
+ su_timer_arg_t *arg);
+
+
+static int priv_stun_bind_send(stun_handle_t *sh, stun_request_t *req, stun_discovery_t *sd);
+static int priv_dns_queue_action(stun_handle_t *sh,
+ stun_action_t action,
+ stun_discovery_f sdf,
+ stun_discovery_magic_t *magic,
+ tag_type_t tag, tag_value_t value, ...);
+
+/**
+ * Return su_root_t assigned to stun_handle_t.
+ *
+ * @param self stun_handle_t object
+ * @return su_root_t object, NULL if self not given.
+ */
+su_root_t *stun_root(stun_handle_t *self)
+{
+ return self ? self->sh_root : NULL;
+}
+
+
+/**
+ * Check if a STUN handle should be created.
+ *
+ * Return true if STUNTAG_SERVER() or STUNTAG_DOMAIN() tags have
+ * been specified, or otherwise if STUN_SERVER environment variable
+ * is set.
+ *
+ * @TAGS
+ * @TAG STUNTAG_DOMAIN() domain to use in DNS-SRV based STUN server
+ * @TAG STUNTAG_SERVER() stun server hostname or dotted IPv4 address
+ *
+ * @param tag,value,... tag-value list
+ */
+int stun_is_requested(tag_type_t tag, tag_value_t value, ...)
+{
+ ta_list ta;
+ tagi_t const *t, *t2;
+ char const *stun_server;
+
+ enter;
+
+ ta_start(ta, tag, value);
+ t = tl_find(ta_args(ta), stuntag_server);
+ t2 = tl_find(ta_args(ta), stuntag_domain);
+ if (t && t->t_value)
+ stun_server = (char *)t->t_value;
+ else if (t2 && t2->t_value)
+ stun_server = (char *)t2->t_value;
+ else
+ stun_server = getenv("STUN_SERVER");
+ ta_end(ta);
+
+ return stun_server != NULL;
+}
+
+
+/**
+ * Creates a STUN handle.
+ *
+ * The created handles can be used for STUN binding discovery,
+ * keepalives, and other STUN usages.
+ *
+ * @param root eventloop to used by the stun state machine
+ * @param tag,value,... tag-value list
+ *
+ * @TAGS
+ * @TAG STUNTAG_DOMAIN() domain to use in DNS-SRV based STUN server
+ * @TAG STUNTAG_SERVER() stun server hostname or dotted IPv4 address
+ * @TAG STUNTAG_REQUIRE_INTEGRITY() true if msg integrity should be
+ * used enforced
+ *
+ */
+stun_handle_t *stun_handle_init(su_root_t *root,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ stun_handle_t *stun = NULL;
+ char const *server = NULL, *domain = NULL;
+ int req_msg_integrity = 1;
+ int err;
+ ta_list ta;
+
+ enter;
+
+ ta_start(ta, tag, value);
+
+ tl_gets(ta_args(ta),
+ STUNTAG_SERVER_REF(server),
+ STUNTAG_DOMAIN_REF(domain),
+ STUNTAG_REQUIRE_INTEGRITY_REF(req_msg_integrity),
+ TAG_END());
+
+ ta_end(ta);
+
+ stun = su_home_clone(NULL, sizeof(*stun));
+
+ if (!stun) {
+ SU_DEBUG_3(("%s: %s failed\n", __func__, "su_home_clone()"));
+ return NULL;
+ }
+
+ /* Enviroment overrides */
+ if (getenv("STUN_SERVER")) {
+ server = getenv("STUN_SERVER");
+ SU_DEBUG_5(("%s: using STUN_SERVER=%s\n", __func__, server));
+ }
+
+ SU_DEBUG_5(("%s(\"%s\"): called\n",
+ __func__, server));
+
+ /* fail, if no server or a domain for a DNS-SRV lookup is specified */
+ if (!server && !domain) {
+ errno = ENOENT;
+ return NULL;
+ }
+
+ stun->sh_pri_info.ai_addrlen = 16;
+ stun->sh_pri_info.ai_addr = &stun->sh_pri_addr->su_sa;
+
+ stun->sh_sec_info.ai_addrlen = 16;
+ stun->sh_sec_info.ai_addr = &stun->sh_sec_addr->su_sa;
+
+ stun->sh_localinfo.li_addrlen = 16;
+ stun->sh_localinfo.li_addr = stun->sh_local_addr;
+
+ stun->sh_domain = su_strdup(stun->sh_home, domain);
+ stun->sh_dns_lookup = NULL;
+
+ if (server) {
+ err = stun_atoaddr(stun->sh_home, AF_INET, &stun->sh_pri_info, server);
+ if (err < 0) {
+ errno = ENOENT;
+ return NULL;
+ }
+ }
+
+ stun->sh_nattype = stun_nat_unknown;
+
+ stun->sh_root = root;
+ /* always try TLS: */
+ stun->sh_use_msgint = 1;
+ /* whether use of shared-secret msgint is required */
+ stun->sh_req_msgint = req_msg_integrity;
+
+ stun->sh_max_retries = STUN_MAX_RETRX;
+
+ /* initialize username and password */
+ stun_init_buffer(&stun->sh_username);
+ stun_init_buffer(&stun->sh_passwd);
+
+ stun->sh_nattype = stun_nat_unknown;
+
+ /* initialize random number generator */
+ srand(time(NULL));
+
+ return stun;
+}
+
+/**
+ * Performs shared secret request/response processing.
+ * Result will be trigged in STUN handle callback (state
+ * one of stun_tls_*).
+ **/
+int stun_obtain_shared_secret(stun_handle_t *sh,
+ stun_discovery_f sdf,
+ stun_discovery_magic_t *magic,
+ tag_type_t tag, tag_value_t value, ...)
+{
+#if defined(HAVE_OPENSSL)
+ int events = -1;
+ int one, err = -1;
+ su_wait_t wait[1] = { SU_WAIT_INIT };
+ su_socket_t s = INVALID_SOCKET;
+ int family;
+ su_addrinfo_t *ai = NULL;
+ stun_discovery_t *sd;
+ /* stun_request_t *req; */
+
+ ta_list ta;
+
+ assert(sh);
+
+ enter;
+
+ if (!sh->sh_pri_addr[0].su_port) {
+ /* no STUN server address, perform a DNS-SRV lookup */
+
+ ta_list ta;
+ ta_start(ta, tag, value);
+ SU_DEBUG_5(("Delaying STUN shared-secret req. for DNS-SRV query.\n"));
+ err = priv_dns_queue_action(sh, stun_action_tls_query, sdf, magic, ta_tags(ta));
+ ta_end(ta);
+
+ return err;
+ }
+
+ ai = &sh->sh_pri_info;
+
+ if (sh->sh_use_msgint == 1) {
+ SU_DEBUG_3(("%s: Obtaining shared secret.\n", __func__));
+ }
+ else {
+ SU_DEBUG_3(("No message integrity enabled.\n"));
+ return errno = EFAULT, -1;
+ }
+
+ /* open tcp connection to server */
+ s = su_socket(family = AF_INET, SOCK_STREAM, 0);
+
+ if (s == INVALID_SOCKET) {
+ return STUN_ERROR(errno, socket);
+ }
+
+ /* asynchronous connect() */
+ if (su_setblocking(s, 0) < 0) {
+ return STUN_ERROR(errno, su_setblocking);
+ }
+
+ if (setsockopt(s, SOL_TCP, TCP_NODELAY,
+ (void *)&one, sizeof one) == -1) {
+ return STUN_ERROR(errno, setsockopt);
+ }
+
+ /* Do an asynchronous connect(). Three error codes are ok,
+ * others cause return -1. */
+ if (connect(s, (struct sockaddr *) &sh->sh_pri_addr,
+ ai->ai_addrlen) == SOCKET_ERROR) {
+ err = su_errno();
+ if (err != EINPROGRESS && err != EAGAIN && err != EWOULDBLOCK) {
+ return STUN_ERROR(err, connect);
+ }
+ }
+
+ SU_DEBUG_9(("%s: %s: %s\n", __func__, "connect",
+ su_strerror(err)));
+
+ sd = stun_discovery_create(sh, stun_action_tls_query, sdf, magic);
+ sd->sd_socket = s;
+ /* req = stun_request_create(sd); */
+
+ events = SU_WAIT_CONNECT | SU_WAIT_ERR;
+ if (su_wait_create(wait, s, events) == -1)
+ return STUN_ERROR(errno, su_wait_create);
+
+ /* su_root_eventmask(sh->sh_root, sh->sh_root_index, s, events); */
+
+ if ((sd->sd_index =
+ su_root_register(sh->sh_root, wait, stun_tls_callback, (su_wakeup_arg_t *) sd, 0)) == -1) {
+ return STUN_ERROR(errno, su_root_register);
+ }
+
+ ta_start(ta, tag, value);
+ sd->sd_tags = tl_adup(sh->sh_home, ta_args(ta));
+ ta_end(ta);
+
+ sd->sd_state = stun_tls_connecting;
+
+ /* Create and start timer for connect() timeout */
+ SU_DEBUG_3(("%s: creating timeout timer for connect()\n", __func__));
+
+ sd->sd_timer = su_timer_create(su_root_task(sh->sh_root),
+ STUN_TLS_CONNECT_TIMEOUT);
+
+ su_timer_set(sd->sd_timer, stun_tls_connect_timer_cb, (su_wakeup_arg_t *) sd);
+
+ return 0;
+#else /* !HAVE_OPENSSL */
+ return -1;
+#endif
+}
+
+static stun_request_t *stun_request_create(stun_discovery_t *sd)
+{
+ stun_handle_t *sh = sd->sd_handle;
+ stun_request_t *req = NULL;
+
+ enter;
+
+ req = calloc(sizeof(stun_request_t), 1);
+ if (!req)
+ return NULL;
+
+ req->sr_handle = sh;
+ req->sr_discovery = sd;
+
+ /* This is the default */
+ req->sr_socket = sd->sd_socket;
+
+ req->sr_localinfo.li_addrlen = sizeof(su_sockaddr_t);
+ req->sr_localinfo.li_addr = req->sr_local_addr;
+
+ /* default timeout for next sendto() */
+ req->sr_timeout = STUN_SENDTO_TIMEOUT;
+ req->sr_retry_count = 0;
+ /* req->sr_action = action; */
+ req->sr_request_mask = 0;
+
+ req->sr_msg = calloc(sizeof(stun_msg_t), 1);
+
+ req->sr_state = stun_req_discovery_init;
+ memcpy(req->sr_local_addr, sd->sd_bind_addr, sizeof(su_sockaddr_t));
+
+ /* Insert this request to the request queue */
+ x_insert(sh->sh_requests, req, sr);
+
+ return req;
+}
+
+void stun_request_destroy(stun_request_t *req)
+{
+ stun_handle_t *sh;
+ assert(req);
+
+ enter;
+
+ sh = req->sr_handle;
+
+ if (x_is_inserted(req, sr))
+ x_remove(req, sr);
+
+ req->sr_handle = NULL;
+ req->sr_discovery = NULL;
+ /* memset(req->sr_destination, 0, sizeof(su_sockaddr_t)); */
+
+ if (req->sr_timer) {
+ su_timer_destroy(req->sr_timer);
+ req->sr_timer = NULL;
+ SU_DEBUG_7(("%s: timer destroyed.\n", __func__));
+ }
+
+ if (req->sr_msg) {
+ free(req->sr_msg);
+ req->sr_msg = NULL;
+ }
+
+ free(req);
+
+ SU_DEBUG_9(("%s: request destroyed.\n", __func__));
+
+ return;
+}
+
+
+/** Destroy a STUN client */
+void stun_handle_destroy(stun_handle_t *sh)
+{
+ stun_discovery_t *sd = NULL, *kill = NULL;
+ stun_request_t *a, *b;
+
+ enter;
+
+ if (sh->sh_dns_lookup)
+ stun_dns_lookup_destroy(sh->sh_dns_lookup);
+
+ if (sh->sh_dns_pend_tags)
+ su_free(sh->sh_home, sh->sh_dns_pend_tags);
+
+ for (a = sh->sh_requests; a; ) {
+ b = a->sr_next;
+ stun_request_destroy(a);
+ a = b;
+ }
+
+
+ /* There can be several discoveries using the same socket. It is
+ still enough to deregister the socket in first of them */
+ for (sd = sh->sh_discoveries; sd; ) {
+ kill = sd;
+ sd = sd->sd_next;
+
+ /* Index has same value as sockfd, right? ... or not? */
+ if (kill->sd_index != -1)
+ su_root_deregister(sh->sh_root, kill->sd_index);
+ if (kill->sd_action == stun_action_tls_query)
+ su_close(kill->sd_socket);
+
+ stun_discovery_destroy(kill);
+ }
+
+ stun_free_message(&sh->sh_tls_request);
+ stun_free_message(&sh->sh_tls_response);
+ stun_free_buffer(&sh->sh_username);
+ stun_free_buffer(&sh->sh_passwd);
+
+ su_home_zap(sh->sh_home);
+}
+
+
+/** Create wait object and register it to the handle callback */
+static
+int assign_socket(stun_discovery_t *sd, su_socket_t s, int register_socket)
+{
+ stun_handle_t *sh = sd->sd_handle;
+ int events;
+ stun_discovery_t *tmp;
+ /* su_localinfo_t clientinfo[1]; */
+ su_sockaddr_t su[1];
+ socklen_t sulen;
+ char addr[SU_ADDRSIZE];
+ int err;
+
+ su_wait_t wait[1] = { SU_WAIT_INIT };
+
+ enter;
+
+ if (s == INVALID_SOCKET) {
+ SU_DEBUG_3(("%s: invalid socket\n", __func__));
+ return errno = EINVAL, -1;
+ }
+
+ for (tmp = sh->sh_discoveries; tmp; tmp = tmp->sd_next) {
+ if (tmp->sd_socket == s) {
+ sd->sd_socket = s;
+ sd->sd_index = tmp->sd_index;
+ memcpy(sd->sd_bind_addr, tmp->sd_bind_addr, sizeof(su_sockaddr_t));
+ return 0;
+ }
+ }
+ sd->sd_socket = s;
+
+ if (!register_socket)
+ return 0;
+
+ /* set socket asynchronous */
+ if (su_setblocking(s, 0) < 0) {
+ return STUN_ERROR(errno, su_setblocking);
+ }
+
+ /* xxx -- check if socket is already assigned to this root */
+
+ memset(su, 0, sulen = sizeof su);
+
+ /* Try to bind it if not already bound */
+ if (getsockname(s, &su->su_sa, &sulen) == -1 || su->su_port == 0) {
+
+ sulen = su->su_len = sizeof su->su_sin;
+ su->su_family = AF_INET;
+
+#if defined (__CYGWIN__)
+ get_localinfo(AF_INET, su, &sulen);
+#endif
+
+ if ((err = bind(s, &su->su_sa, sulen)) < 0) {
+ SU_DEBUG_3(("%s: bind(%s:%u): %s\n", __func__,
+ inet_ntop(su->su_family, SU_ADDR(su), addr, sizeof(addr)),
+ (unsigned) ntohs(su->su_port),
+ su_strerror(su_errno())));
+ return -1;
+ }
+
+ if (getsockname(s, &su->su_sa, &sulen) == -1) {
+ return STUN_ERROR(errno, getsockname);
+ }
+ }
+
+ memcpy(&sd->sd_bind_addr, su, sulen);
+
+ SU_DEBUG_3(("%s: local socket is bound to %s:%u\n", __func__,
+ inet_ntop(su->su_family, SU_ADDR(su), addr, sizeof(addr)),
+ (unsigned) ntohs(su->su_port)));
+
+ events = SU_WAIT_IN | SU_WAIT_ERR;
+
+ if (su_wait_create(wait, s, events) == -1) {
+ return STUN_ERROR(su_errno(), su_wait_create);
+ }
+
+ /* Register receiving function with events specified above */
+ if ((sd->sd_index = su_root_register(sh->sh_root,
+ wait, stun_bind_callback,
+ (su_wakeup_arg_t *) sd, 0)) < 0) {
+ return STUN_ERROR(errno, su_root_register);
+ }
+
+ SU_DEBUG_7(("%s: socket registered.\n", __func__));
+
+ return 0;
+}
+
+
+/**
+ * Helper function needed by Cygwin builds.
+ */
+#if defined (__CYGWIN__)
+static int get_localinfo(int family, su_sockaddr_t *su, socklen_t *return_len)
+{
+ su_localinfo_t hints[1] = {{ LI_CANONNAME | LI_NUMERIC }}, *li, *res = NULL;
+ int i, error;
+ char addr[SU_ADDRSIZE];
+
+ hints->li_family = family;
+
+ if ((error = su_getlocalinfo(hints, &res)) == 0) {
+ /* try to bind to the first available address */
+ for (i = 0, li = res; li; li = li->li_next) {
+ if (li->li_family != family)
+ continue;
+ if (li->li_scope == LI_SCOPE_HOST)
+ continue;
+
+ assert(*return_len >= li->li_addrlen);
+
+ memcpy(su, li->li_addr, *return_len = li->li_addrlen);
+
+ SU_DEBUG_3(("%s: using local address %s\n", __func__,
+ inet_ntop(family, SU_ADDR(su), addr, sizeof(addr))));
+ break;
+ }
+
+ su_freelocalinfo(res);
+
+ if (!li) { /* Not found */
+ return STUN_ERROR(error, su_getlocalinfo);
+ }
+
+ return 0;
+ }
+ else {
+ return STUN_ERROR(error, su_getlocalinfo);
+ }
+}
+#endif
+
+static void priv_lookup_cb(stun_dns_lookup_t *self,
+ stun_magic_t *magic)
+{
+ const char *udp_target = NULL;
+ uint16_t udp_port = 0;
+ int res;
+ stun_handle_t *sh = (stun_handle_t *)magic;
+
+ res = stun_dns_lookup_udp_addr(self, &udp_target, &udp_port);
+ if (res == 0 && udp_target) {
+ /* XXX: assumption that same host and port used for UDP/TLS */
+ stun_atoaddr(sh->sh_home, AF_INET, &sh->sh_pri_info, udp_target);
+
+ if (udp_port)
+ sh->sh_pri_addr[0].su_port = htons(udp_port);
+ else
+ sh->sh_pri_addr[0].su_port = htons(STUN_DEFAULT_PORT);
+
+ /* step: now that server address is known, continue
+ * the pending action */
+
+ SU_DEBUG_5(("STUN server address found, running queue actions (%d).\n",
+ sh->sh_dns_pend_action));
+
+ switch(sh->sh_dns_pend_action) {
+ case stun_action_tls_query:
+ stun_obtain_shared_secret(sh, sh->sh_dns_pend_cb, sh->sh_dns_pend_ctx, TAG_NEXT(sh->sh_dns_pend_tags));
+ break;
+
+ case stun_action_binding_request:
+ stun_bind(sh, sh->sh_dns_pend_cb, sh->sh_dns_pend_ctx, TAG_NEXT(sh->sh_dns_pend_tags));
+ break;
+
+ case stun_action_test_lifetime:
+ stun_test_lifetime(sh, sh->sh_dns_pend_cb, sh->sh_dns_pend_ctx, TAG_NEXT(sh->sh_dns_pend_tags));
+ break;
+
+ case stun_action_test_nattype:
+ stun_test_nattype(sh, sh->sh_dns_pend_cb, sh->sh_dns_pend_ctx, TAG_NEXT(sh->sh_dns_pend_tags));
+ break;
+
+ default:
+ SU_DEBUG_5(("Warning: unknown pending STUN DNS-SRV action.\n"));
+ }
+ }
+ else {
+ /* DNS lookup failed */
+ SU_DEBUG_5(("Warning: STUN DNS-SRV lookup failed.\n"));
+ if (sh->sh_dns_pend_cb) {
+ sh->sh_dns_pend_cb(sh->sh_dns_pend_ctx, sh, NULL,
+ sh->sh_dns_pend_action, stun_error);
+ }
+ }
+
+ su_free(sh->sh_home, sh->sh_dns_pend_tags), sh->sh_dns_pend_tags = NULL;
+ sh->sh_dns_pend_action = 0;
+ sh->sh_dns_pend_cb = NULL;
+ sh->sh_dns_pend_ctx = NULL;
+}
+
+/**
+ * Queus a discovery process for later execution when DNS-SRV lookup
+ * has been completed.
+ */
+static int priv_dns_queue_action(stun_handle_t *sh,
+ stun_action_t action,
+ stun_discovery_f sdf,
+ stun_discovery_magic_t *magic,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ ta_list ta;
+
+ if (!sh->sh_dns_pend_action) {
+ if (!sh->sh_dns_lookup) {
+ sh->sh_dns_lookup = stun_dns_lookup((stun_magic_t*)sh, sh->sh_root, priv_lookup_cb, sh->sh_domain);
+ ta_start(ta, tag, value);
+ assert(sh->sh_dns_pend_tags == NULL);
+ sh->sh_dns_pend_tags = tl_tlist(sh->sh_home,
+ ta_tags(ta));
+ ta_end(ta);
+ sh->sh_dns_pend_cb = sdf;
+ sh->sh_dns_pend_ctx = magic;
+
+ }
+ sh->sh_dns_pend_action |= action;
+
+ return 0;
+ }
+
+ return -1;
+}
+
+static int priv_stun_bind_send(stun_handle_t *sh, stun_request_t *req, stun_discovery_t *sd)
+{
+ int res = stun_send_binding_request(req, sh->sh_pri_addr);
+ if (res < 0) {
+ stun_free_message(req->sr_msg);
+ stun_discovery_destroy(sd);
+ }
+ return res;
+}
+
+/**
+ * Performs a STUN Binding Discovery (see RFC3489/3489bis) process
+ *
+ * To integrity protect the discovery process, first call
+ * stun_request_shared_secret() on the handle 'sh'.
+ *
+ * If STUNTAG_REGISTER_SOCKET() is omitted, or set to false, the
+ * client is responsible for socket i/o. Other stun module will
+ * perform the whole discovery process and return the results
+ * via callback 'sdf'.
+ *
+ * @param sh pointer to valid stun handle
+ * @param sdf callback to signal process progress
+ * @param magic context pointer attached to 'sdf'
+ * @param tag, value, ... list of tagged parameters.
+ *
+ * @TAGS
+ * @TAG STUNTAG_SOCKET() Bind socket handle to STUN (socket handle).
+ * @TAG STUNTAG_REGISTER_SOCKET() Register socket for eventloop owned by STUN (boolean)
+ *
+ * @return
+ * On success, zero is returned. Upon error, -1 is returned, and @e errno is
+ * set appropriately.
+ *
+ * @ERRORS
+ * @ERROR EFAULT An invalid address is given as argument
+ * @ERROR EPROTONOSUPPORT Not a UDP socket.
+ * @ERROR EINVAL The socket is already bound to an address.
+ * @ERROR EACCESS The address is protected, and the user is not
+ * the super-user.
+ * @ERROR ENOTSOCK Argument is a descriptor for a file, not a socket.
+ * @ERROR EAGAIN Operation in progress. Application should call
+ * stun_bind() again when there is data available on
+ * the socket.
+ */
+int stun_bind(stun_handle_t *sh,
+ stun_discovery_f sdf,
+ stun_discovery_magic_t *magic,
+ tag_type_t tag, tag_value_t value,
+ ...)
+{
+ su_socket_t s = INVALID_SOCKET;
+ stun_request_t *req = NULL;
+ stun_discovery_t *sd = NULL;
+ ta_list ta;
+ int s_reg = 0;
+
+ enter;
+
+ if (sh == NULL)
+ return errno = EFAULT, -1;
+
+ if (!sh->sh_pri_addr[0].su_port) {
+ /* no STUN server address, perform a DNS-SRV lookup */
+ int err;
+ ta_list ta;
+ ta_start(ta, tag, value);
+ SU_DEBUG_5(("Delaying STUN bind for DNS-SRV query.\n"));
+ err = priv_dns_queue_action(sh, stun_action_binding_request, sdf, magic, ta_tags(ta));
+ ta_end(ta);
+ return err;
+ }
+
+ ta_start(ta, tag, value);
+
+ tl_gets(ta_args(ta),
+ STUNTAG_SOCKET_REF(s),
+ STUNTAG_REGISTER_EVENTS_REF(s_reg),
+ TAG_END());
+
+ ta_end(ta);
+
+ sd = stun_discovery_create(sh, stun_action_binding_request, sdf, magic);
+ if (assign_socket(sd, s, s_reg) < 0)
+ return -1;
+
+ req = stun_request_create(sd);
+
+ if (stun_make_binding_req(sh, req, req->sr_msg, 0, 0) < 0) {
+ stun_discovery_destroy(sd);
+ stun_free_message(req->sr_msg);
+ return -1;
+ }
+
+ /* note: we always report success if bind() succeeds */
+ return priv_stun_bind_send(sh, req, sd);
+}
+
+
+/**
+ * Returns the address of the public binding allocated by the NAT.
+ *
+ * In case of multiple on path NATs, the binding allocated by
+ * the outermost NAT is returned.
+ *
+ * This function returns the local address seen from outside.
+ * Note that the address is not valid until the event stun_clien_done is launched.
+ */
+int stun_discovery_get_address(stun_discovery_t *sd,
+ void *addr,
+ socklen_t *return_addrlen)
+{
+ socklen_t siz;
+
+ enter;
+
+ assert(sd && addr);
+
+ siz = SU_SOCKADDR_SIZE(sd->sd_addr_seen_outside);
+
+ /* Check if enough memory provided */
+ if (siz > *return_addrlen)
+ return errno = EFAULT, -1;
+ else
+ *return_addrlen = siz;
+
+ memcpy(addr, sd->sd_addr_seen_outside, siz);
+
+ return 0;
+}
+
+static stun_discovery_t *stun_discovery_create(stun_handle_t *sh,
+ stun_action_t action,
+ stun_discovery_f sdf,
+ stun_discovery_magic_t *magic)
+{
+ stun_discovery_t *sd = NULL;
+
+ enter;
+
+ sd = calloc(1, sizeof(stun_discovery_t));
+
+ sd->sd_action = action;
+ sd->sd_handle = sh;
+ sd->sd_callback = sdf;
+ sd->sd_magic = magic;
+
+ sd->sd_lt_cur = 0;
+ sd->sd_lt = STUN_LIFETIME_EST;
+ sd->sd_lt_max = STUN_LIFETIME_MAX;
+
+ sd->sd_pri_info.ai_addrlen = sizeof sd->sd_pri_addr->su_sin;
+ sd->sd_pri_info.ai_addr = &sd->sd_pri_addr->su_sa;
+
+ /* Insert this action to the discovery queue */
+ x_insert(sh->sh_discoveries, sd, sd);
+
+ return sd;
+}
+
+static int stun_discovery_destroy(stun_discovery_t *sd)
+{
+ stun_handle_t *sh;
+
+ enter;
+
+ if (!sd)
+ return errno = EFAULT, -1;
+
+ sh = sd->sd_handle;
+
+ if (sd->sd_timer)
+ su_timer_destroy(sd->sd_timer), sd->sd_timer = NULL;
+
+ /* if we are in the queue*/
+ if (x_is_inserted(sd, sd))
+ x_remove(sd, sd);
+
+ sd->sd_next = NULL;
+
+ free(sd);
+ return 0;
+}
+
+/**
+ * Initiates STUN discovery process to find out NAT
+ * characteristics.
+ *
+ * Process partly follows the algorithm defined in RFC3489 section
+ * 10.1. Due the known limitations of RFC3489, some of the tests
+ * are done.
+ *
+ * Note: does not support STUNTAG_DOMAIN() even if specified to
+ * stun_handle_init().
+ *
+ * @TAGS
+ * @TAG STUNTAG_SOCKET Bind socket for STUN
+ * @TAG STUNTAG_REGISTER_SOCKET Register socket for eventloop owned by STUN
+ * @TAG STUNTAG_SERVER() stun server hostname or dotted IPv4 address
+ *
+ * @return 0 on success, non-zero on error
+ */
+int stun_test_nattype(stun_handle_t *sh,
+ stun_discovery_f sdf,
+ stun_discovery_magic_t *magic,
+ tag_type_t tag, tag_value_t value,
+ ...)
+{
+ int err = 0, index = 0, s_reg = 0;
+ ta_list ta;
+ char const *server = NULL;
+ stun_request_t *req = NULL;
+ stun_discovery_t *sd = NULL;
+ su_socket_t s = INVALID_SOCKET;
+ su_sockaddr_t *destination = NULL;
+
+ enter;
+
+ if (!sh->sh_pri_addr[0].su_port) {
+ /* no STUN server address, perform a DNS-SRV lookup */
+
+ ta_list ta;
+ ta_start(ta, tag, value);
+ SU_DEBUG_5(("Delaying STUN get-nat-type req. for DNS-SRV query.\n"));
+ err = priv_dns_queue_action(sh, stun_action_test_nattype, sdf, magic, ta_tags(ta));
+ ta_end(ta);
+
+ return err;
+ }
+
+ ta_start(ta, tag, value);
+ tl_gets(ta_args(ta),
+ STUNTAG_SOCKET_REF(s),
+ STUNTAG_REGISTER_EVENTS_REF(s_reg),
+ STUNTAG_SERVER_REF(server),
+ TAG_END());
+
+ ta_end(ta);
+
+ if (s < 0)
+ return errno = EFAULT, -1;
+
+ sd = stun_discovery_create(sh, stun_action_test_nattype, sdf, magic);
+ sd->sd_mapped_addr_match = -1;
+
+ if ((index = assign_socket(sd, s, s_reg)) < 0)
+ return errno = EFAULT, -1;
+
+ /* If no server given, use default address from stun_handle_init() */
+ if (!server) {
+ /* memcpy(&sd->sd_pri_info, &sh->sh_pri_info, sizeof(su_addrinfo_t)); */
+ memcpy(sd->sd_pri_addr, sh->sh_pri_addr, sizeof(su_sockaddr_t));
+ }
+ else {
+ err = stun_atoaddr(sh->sh_home, AF_INET, &sd->sd_pri_info, server);
+ memcpy(sd->sd_pri_addr, &sd->sd_pri_info.ai_addr, sizeof(su_sockaddr_t));
+ }
+ destination = (su_sockaddr_t *) sd->sd_pri_addr;
+
+ req = stun_request_create(sd);
+ if (stun_make_binding_req(sh, req, req->sr_msg,
+ STUNTAG_CHANGE_IP(0),
+ STUNTAG_CHANGE_PORT(0),
+ TAG_END()) < 0)
+ return -1;
+
+ err = stun_send_binding_request(req, destination);
+ if (err < 0) {
+ stun_free_message(req->sr_msg);
+ return -1;
+ }
+
+ /* Same Public IP and port, Test III, server ip 0 or 1 should be
+ the same */
+ req = stun_request_create(sd);
+ if (stun_make_binding_req(sh, req, req->sr_msg,
+ STUNTAG_CHANGE_IP(0),
+ STUNTAG_CHANGE_PORT(1),
+ TAG_END()) < 0)
+ return -1;
+
+ err = stun_send_binding_request(req, destination);
+ if (err < 0) {
+ stun_free_message(req->sr_msg);
+ return -1;
+ }
+ req = NULL;
+
+ req = stun_request_create(sd);
+ if (stun_make_binding_req(sh, req, req->sr_msg,
+ STUNTAG_CHANGE_IP(1),
+ STUNTAG_CHANGE_PORT(1),
+ TAG_END()) < 0)
+ return -1;
+
+ err = stun_send_binding_request(req, destination);
+ if (err < 0) {
+ stun_free_message(req->sr_msg);
+ }
+
+ return err;
+}
+
+/********************************************************************
+ * Internal functions
+ *******************************************************************/
+
+#if defined(HAVE_OPENSSL)
+static int stun_tls_callback(su_root_magic_t *m, su_wait_t *w, su_wakeup_arg_t *arg)
+{
+ stun_discovery_t *sd = arg;
+ stun_handle_t *self = sd->sd_handle;
+ stun_msg_t *msg_req, *resp;
+ int z, err = -1;
+ SSL_CTX* ctx;
+ SSL *ssl;
+ X509* server_cert;
+ unsigned char buf[512];
+ stun_attr_t *password, *username;
+ int state;
+ int events = su_wait_events(w, sd->sd_socket), one = 0;
+ unsigned int onelen;
+
+ enter;
+
+ SU_DEBUG_7(("%s(%p): events%s%s%s%s\n", __func__, self,
+ events & SU_WAIT_CONNECT ? " CONNECTED" : "",
+ events & SU_WAIT_ERR ? " ERR" : "",
+ events & SU_WAIT_IN ? " IN" : "",
+ events & SU_WAIT_OUT ? " OUT" : ""));
+
+ getsockopt(sd->sd_socket, SOL_SOCKET, SO_ERROR,
+ (void *)&one, &onelen);
+ if (one != 0) {
+ STUN_ERROR(one, SO_ERROR);
+ }
+
+ if (one || events & SU_WAIT_ERR) {
+ su_wait_destroy(w);
+ su_root_deregister(self->sh_root, sd->sd_index);
+ sd->sd_index = -1; /* mark index as deregistered */
+
+ su_timer_reset(sd->sd_timer);
+
+ SU_DEBUG_3(("%s: shared secret not obtained from server. " \
+ "Proceed without username/password.\n", __func__));
+
+ sd->sd_state = stun_tls_connection_failed;
+
+ if (sd->sd_callback)
+ sd->sd_callback(sd->sd_magic, self, sd, sd->sd_action, sd->sd_state);
+
+ return 0;
+ }
+
+ /* Can be NULL, too */
+ ssl = self->sh_ssl;
+ msg_req = &self->sh_tls_request;
+ resp = &self->sh_tls_response;
+
+ state = sd->sd_state;
+ switch (state) {
+ case stun_tls_connecting:
+
+ /* compose shared secret request */
+ if (stun_make_sharedsecret_req(msg_req) != 0) {
+ STUN_ERROR(errno, stun_make_sharedsecret_req);
+ stun_free_buffer(&msg_req->enc_buf);
+ return -1;
+ }
+
+ /* openssl initiation */
+ SSLeay_add_ssl_algorithms();
+ SSL_load_error_strings();
+ ctx = SSL_CTX_new(TLSv1_client_method());
+ self->sh_ctx = ctx;
+
+ if (ctx == NULL) {
+ STUN_ERROR(errno, SSL_CTX_new);
+ stun_free_buffer(&msg_req->enc_buf);
+ return -1;
+ }
+
+ if (SSL_CTX_set_cipher_list(ctx, "AES128-SHA") == 0) {
+ STUN_ERROR(errno, SSL_CTX_set_cipher_list);
+ stun_free_buffer(&msg_req->enc_buf);
+ return -1;
+ }
+
+ /* Start TLS negotiation */
+ ssl = SSL_new(ctx);
+ self->sh_ssl = ssl;
+
+ if (SSL_set_fd(ssl, sd->sd_socket) == 0) {
+ STUN_ERROR(err, connect);
+ stun_free_buffer(&msg_req->enc_buf);
+ return -1;
+ }
+
+ /* No break here! Continue to SSL_connect. If SSL_continue returns
+ * less than 1 because of nonblocking, have a different state
+ * (ssl_connecting) for it */
+
+ case stun_tls_ssl_connecting:
+ events = SU_WAIT_ERR | SU_WAIT_IN;
+ su_root_eventmask(self->sh_root, sd->sd_index,
+ sd->sd_socket, events);
+
+ z = SSL_connect(ssl);
+ err = SSL_get_error(ssl, z);
+ if (z < 1 && (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE)) {
+ sd->sd_state = stun_tls_ssl_connecting;
+ return 0;
+ }
+ else if (z < 1) {
+ su_wait_destroy(w);
+ su_root_deregister(self->sh_root, sd->sd_index);
+ sd->sd_index = -1; /* mark index as deregistered */
+
+ stun_free_buffer(&msg_req->enc_buf);
+ sd->sd_state = stun_tls_connection_failed;
+
+ if (sd->sd_callback)
+ sd->sd_callback(sd->sd_magic, self, sd, sd->sd_action, sd->sd_state);
+
+ return -1;
+ }
+
+ /* Inform application about the progress */
+ sd->sd_state = stun_tls_writing;
+ /* self->sh_callback(self->sh_context, self, self->sh_state); */
+
+ events = SU_WAIT_ERR | SU_WAIT_OUT;
+ su_root_eventmask(self->sh_root, sd->sd_index,
+ sd->sd_socket, events);
+
+ break;
+
+ case stun_tls_writing:
+
+ events = SU_WAIT_ERR | SU_WAIT_IN;
+ su_root_eventmask(self->sh_root, sd->sd_index,
+ sd->sd_socket, events);
+
+ SU_DEBUG_3(("TLS connection using %s\n", SSL_get_cipher(ssl)));
+
+ server_cert = SSL_get_peer_certificate(ssl);
+ if(server_cert) {
+ SU_DEBUG_3(("\t subject: %s\n", X509_NAME_oneline(X509_get_subject_name(server_cert), 0, 0)));
+ SU_DEBUG_3(("\t issuer: %s\n", X509_NAME_oneline(X509_get_issuer_name(server_cert), 0, 0)));
+ }
+ X509_free(server_cert);
+
+ z = SSL_write(ssl, msg_req->enc_buf.data, msg_req->enc_buf.size);
+
+ if (z < 0) {
+ err = SSL_get_error(ssl, z);
+ if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE)
+ return 0;
+ else {
+ STUN_ERROR(errno, SSL_write);
+ stun_free_buffer(&msg_req->enc_buf);
+ return -1;
+ }
+ }
+ sd->sd_state = stun_tls_reading;
+
+ break;
+
+ case stun_tls_reading:
+ events = SU_WAIT_ERR | SU_WAIT_OUT;
+ su_root_eventmask(self->sh_root, sd->sd_index,
+ sd->sd_socket, events);
+
+ SU_DEBUG_5(("Shared Secret Request sent to server:\n"));
+ debug_print(&msg_req->enc_buf);
+
+ z = SSL_read(ssl, buf, sizeof(buf));
+ if (z <= 0) {
+ err = SSL_get_error(ssl, z);
+ if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE)
+ return 0;
+ else {
+ stun_free_buffer(&msg_req->enc_buf);
+ return -1;
+ }
+ }
+
+ /* We end up here after there's something to read from the
+ * socket */
+ resp->enc_buf.size = z;
+ resp->enc_buf.data = malloc(z);
+ memcpy(resp->enc_buf.data, buf, z);
+ SU_DEBUG_5(("Shared Secret Response received from server:\n"));
+ debug_print(&resp->enc_buf);
+
+ /* closed TLS connection */
+ SSL_shutdown(ssl);
+
+ su_close(sd->sd_socket), sd->sd_socket = INVALID_SOCKET;
+
+ SSL_free(self->sh_ssl), ssl = NULL;
+ SSL_CTX_free(self->sh_ctx), ctx = NULL;
+
+ stun_free_buffer(&msg_req->enc_buf);
+
+ /* process response */
+ if (stun_parse_message(resp) < 0) {
+ perror("stun_parse_message");
+ stun_free_buffer(&resp->enc_buf);
+ return -1;
+ }
+
+ switch(resp->stun_hdr.msg_type) {
+ case SHARED_SECRET_RESPONSE:
+ username = stun_get_attr(resp->stun_attr, USERNAME);
+ password = stun_get_attr(resp->stun_attr, PASSWORD);
+ if (username != NULL && password != NULL) {
+ /* move result to se */
+ stun_copy_buffer(&self->sh_username, username->pattr);
+ stun_copy_buffer(&self->sh_passwd, password->pattr);
+ }
+ break;
+
+ case SHARED_SECRET_ERROR_RESPONSE:
+ if (stun_process_error_response(resp) < 0) {
+ SU_DEBUG_5(("Error in Shared Secret Error Response.\n"));
+ }
+ stun_free_buffer(&resp->enc_buf);
+ return -1;
+
+ break;
+
+ default:
+ break;
+ }
+
+ su_wait_destroy(w);
+ su_root_deregister(self->sh_root, sd->sd_index);
+ sd->sd_index = -1; /* mark index as deregistered */
+
+ self->sh_use_msgint = 1;
+ sd->sd_state = stun_tls_done;
+
+ if (sd->sd_callback)
+ sd->sd_callback(sd->sd_magic, self, sd, sd->sd_action, sd->sd_state);
+
+ break;
+
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+#else
+static int stun_tls_callback(su_root_magic_t *m, su_wait_t *w, su_wakeup_arg_t *arg)
+{
+ return 0;
+}
+#endif /* HAVE_OPENSSL */
+
+
+#if defined(HAVE_OPENSSL)
+static void stun_tls_connect_timer_cb(su_root_magic_t *magic,
+ su_timer_t *t,
+ su_timer_arg_t *arg)
+{
+ stun_discovery_t *sd = arg;
+ stun_handle_t *sh = sd->sd_handle;
+
+ enter;
+
+ su_timer_destroy(t);
+ if (t == sd->sd_timer) {
+ sd->sd_timer = NULL;
+ }
+
+ SU_DEBUG_7(("%s: timer destroyed.\n", __func__));
+
+ if (sd->sd_state != stun_tls_connecting)
+ return;
+
+ SU_DEBUG_7(("%s: connect() timeout.\n", __func__));
+
+ su_root_deregister(sh->sh_root, sd->sd_index);
+ sd->sd_index = -1; /* mark index as deregistered */
+
+ sd->sd_state = stun_tls_connection_timeout;
+ sd->sd_callback(sd->sd_magic, sh, sd, sd->sd_action, sd->sd_state);
+
+ return;
+}
+#else
+static void stun_tls_connect_timer_cb(su_root_magic_t *magic,
+ su_timer_t *t,
+ su_timer_arg_t *arg)
+{
+}
+#endif /* HAVE_OPENSSL */
+
+/** Compose a STUN message of the format defined by stun_msg_t
+ * result encoded in enc_buf ready for sending as well.
+ */
+int stun_make_sharedsecret_req(stun_msg_t *msg)
+{
+
+ int i, len;
+ uint16_t tmp;
+
+ /* compose header */
+ msg->stun_hdr.msg_type = SHARED_SECRET_REQUEST;
+ msg->stun_hdr.msg_len = 0; /* actual len computed by
+ stun_send_message */
+ for (i = 0; i < STUN_TID_BYTES; i++) {
+ msg->stun_hdr.tran_id[i] = (1 + rand() % RAND_MAX_16);
+ }
+
+ /* no buffer assigned yet */
+ stun_init_buffer(&msg->enc_buf);
+
+ msg->enc_buf.data = malloc(20);
+ msg->enc_buf.size = 20;
+
+ tmp = htons(msg->stun_hdr.msg_type);
+ len = 0;
+
+ memcpy(msg->enc_buf.data, &tmp, sizeof(tmp));
+ len+=sizeof(tmp);
+
+ tmp = htons(msg->stun_hdr.msg_len);
+ memcpy(msg->enc_buf.data+len, &tmp, sizeof(tmp));
+ len+=sizeof(tmp);
+
+ memcpy(msg->enc_buf.data+len, msg->stun_hdr.tran_id, STUN_TID_BYTES);
+ len+=STUN_TID_BYTES;
+
+ return 0;
+}
+
+
+/* Return action of the request. If no request, return default value */
+static inline
+stun_action_t get_action(stun_request_t *req)
+{
+ stun_discovery_t *sd = NULL;
+
+ /* XXX -- if no sr_handle something is leaking... */
+ if (!req || !req->sr_discovery || !req->sr_handle)
+ return stun_action_no_action;
+
+ sd = req->sr_discovery;
+ return sd->sd_action;
+}
+
+
+/* Find request from the request queue, based on TID */
+static inline
+stun_request_t *find_request(stun_handle_t *self, void *id)
+{
+ void *match;
+ stun_request_t *req = NULL;
+ int len = STUN_TID_BYTES;
+
+ for (req = self->sh_requests; req; req = req->sr_next) {
+ match = req->sr_msg->stun_hdr.tran_id;
+ if (memcmp(match, id, len) == 0) {
+ return req;
+ }
+ }
+
+ return NULL;
+}
+
+/** Process socket event */
+static int stun_bind_callback(stun_magic_t *m, su_wait_t *w, su_wakeup_arg_t *arg)
+{
+ stun_discovery_t *sd = arg;
+ stun_handle_t *self = sd->sd_handle;
+
+ int retval = -1, err = -1, dgram_len;
+ char addr[SU_ADDRSIZE];
+ stun_msg_t binding_response, *msg;
+ unsigned char dgram[512] = { 0 };
+ su_sockaddr_t recv;
+ socklen_t recv_len;
+ su_socket_t s = sd->sd_socket;
+ int events = su_wait_events(w, s);
+
+ enter;
+
+ SU_DEBUG_7(("%s(%p): events%s%s%s\n", __func__, self,
+ events & SU_WAIT_IN ? " IN" : "",
+ events & SU_WAIT_OUT ? " OUT" : "",
+ events & SU_WAIT_ERR ? " ERR" : ""));
+
+ if (!(events & SU_WAIT_IN || events & SU_WAIT_OUT)) {
+ /* su_wait_destroy(w); */
+ /* su_root_deregister(self->sh_root, self->ss_root_index); */
+ /* self->sh_state = stun_bind_error; */
+ return 0;
+ }
+
+ /* receive response */
+ recv_len = sizeof(recv);
+ dgram_len = su_recvfrom(s, dgram, sizeof(dgram), 0, &recv, &recv_len);
+ err = errno;
+ if ((dgram_len < 0) && (err != EAGAIN)) {
+ /* su_wait_destroy(w); */
+ /* su_root_deregister(self->sh_root, self->ss_root_index); */
+ STUN_ERROR(err, recvfrom);
+ /* stun_free_message(binding_request); */
+ return err;
+ }
+ else if (dgram_len <= 0) {
+ STUN_ERROR(err, recvfrom);
+ /* No data available yet, wait for the event. */
+ return 0;
+ }
+
+ /* Message received. */
+ binding_response.enc_buf.data = (unsigned char *) malloc(dgram_len);
+ binding_response.enc_buf.size = dgram_len;
+ memcpy(binding_response.enc_buf.data, dgram, dgram_len);
+
+
+ SU_DEBUG_5(("%s: response from server %s:%u\n", __func__,
+ inet_ntop(recv.su_family, SU_ADDR(&recv), addr, sizeof(addr)),
+ ntohs(recv.su_port)));
+
+ debug_print(&binding_response.enc_buf);
+
+ /* Parse here the incoming message. */
+ if (stun_parse_message(&binding_response) < 0) {
+ stun_free_message(&binding_response);
+ SU_DEBUG_5(("%s: Error parsing response.\n", __func__));
+ return retval;
+ }
+
+ /* Based on the decoded payload, find the corresponding request
+ * (based on TID). */
+
+ do_action(self, &binding_response);
+
+ if (binding_response.enc_buf.size)
+ free(binding_response.enc_buf.data);
+
+ {
+ stun_attr_t **a, *b;
+
+ msg = &binding_response;
+ for (a = &msg->stun_attr; *a;) {
+
+ if ((*a)->pattr)
+ free((*a)->pattr);
+
+ if ((*a)->enc_buf.data)
+ free((*a)->enc_buf.data);
+
+ b = *a;
+ b = b->next;
+ free(*a);
+ *a = NULL;
+ *a = b;
+ }
+ }
+
+ return 0;
+}
+
+/** Choose the right state machine */
+static int do_action(stun_handle_t *sh, stun_msg_t *msg)
+{
+ stun_request_t *req = NULL;
+ stun_action_t action = stun_action_no_action;
+ void *id;
+
+ enter;
+
+ if (!sh)
+ return errno = EFAULT, -1;
+
+ id = msg->stun_hdr.tran_id;
+ req = find_request(sh, id);
+ if (!req) {
+ SU_DEBUG_7(("warning: unable to find matching TID for response\n"));
+ return 0;
+ }
+
+ action = get_action(req);
+
+ /* Based on the action, use different state machines */
+ switch (action) {
+ case stun_action_binding_request:
+ action_bind(req, msg);
+ break;
+
+ case stun_action_test_nattype:
+ action_determine_nattype(req, msg);
+ break;
+
+ case stun_action_test_lifetime:
+ process_test_lifetime(req, msg);
+ break;
+
+ case stun_action_keepalive:
+ SU_DEBUG_3(("%s: Response to keepalive received.\n", __func__));
+ req->sr_state = stun_req_dispose_me;
+ break;
+
+ case stun_action_no_action:
+ SU_DEBUG_3(("%s: Unknown response. No matching request found.\n", __func__));
+ req->sr_state = stun_req_dispose_me;
+ break;
+
+ default:
+ SU_DEBUG_3(("%s: bad action.\n", __func__));
+ req->sr_state = stun_req_error;
+
+ req->sr_state = stun_req_dispose_me;
+ break;
+ }
+
+ return 0;
+}
+
+static int process_binding_request(stun_request_t *req, stun_msg_t *binding_response)
+{
+ int retval = -1, clnt_addr_len;
+ stun_attr_t *mapped_addr, *chg_addr;
+ stun_handle_t *self = req->sr_handle;
+ su_localinfo_t *clnt_info = &req->sr_localinfo;
+ su_sockaddr_t *clnt_addr = clnt_info->li_addr;
+ stun_msg_t *binding_request;
+ stun_discovery_t *sd = req->sr_discovery;
+
+ enter;
+
+ binding_request = req->sr_msg;
+
+ switch (binding_response->stun_hdr.msg_type) {
+ case BINDING_RESPONSE:
+ if (stun_validate_message_integrity(binding_response, &self->sh_passwd) < 0) {
+ stun_free_message(binding_request);
+ stun_free_message(binding_response);
+ return retval;
+ }
+
+ memset(clnt_addr, 0, sizeof(su_sockaddr_t));
+ clnt_addr_len = sizeof(su_sockaddr_t);
+ mapped_addr = stun_get_attr(binding_response->stun_attr, MAPPED_ADDRESS);
+
+ if (mapped_addr != NULL) {
+ memcpy(clnt_addr, mapped_addr->pattr, clnt_addr_len);
+ retval = 0;
+ }
+
+ /* update alternative server address */
+ if (sd->sd_sec_addr->su_family == 0) {
+ /* alternative server address not present */
+ chg_addr = stun_get_attr(binding_response->stun_attr, CHANGED_ADDRESS);
+
+ if (chg_addr != NULL)
+ memcpy(sd->sd_sec_addr, chg_addr->pattr, sizeof(struct sockaddr_in));
+ }
+
+ break;
+
+ case BINDING_ERROR_RESPONSE:
+ default:
+ if (stun_process_error_response(binding_response) < 0) {
+ SU_DEBUG_3(("%s: Error in Binding Error Response.\n", __func__));
+ }
+ req->sr_state = stun_discovery_error;
+
+ break;
+ }
+
+ return retval;
+
+}
+
+static void stun_test_lifetime_timer_cb(su_root_magic_t *magic,
+ su_timer_t *t,
+ su_timer_arg_t *arg)
+{
+ stun_request_t *req = arg;
+ stun_discovery_t *sd = req->sr_discovery;
+ su_sockaddr_t *destination;
+
+ int err;
+
+ enter;
+
+ su_timer_destroy(t);
+
+ destination = (su_sockaddr_t *) sd->sd_pri_addr;
+ err = stun_send_binding_request(req, destination);
+ if (err < 0) {
+ stun_free_message(req->sr_msg);
+ return;
+ }
+
+
+ return;
+
+}
+
+static int process_test_lifetime(stun_request_t *req, stun_msg_t *binding_response)
+{
+ stun_discovery_t *sd = req->sr_discovery;
+ stun_request_t *new;
+ stun_handle_t *sh = req->sr_handle;
+ su_localinfo_t *li;
+ su_sockaddr_t *sa;
+ su_timer_t *sockfdy_timer = NULL;
+ su_socket_t sockfdy = sd->sd_socket2;
+ int err;
+ stun_action_t action = get_action(req);
+ su_sockaddr_t *destination;
+
+ /* Even the first message could not be delivered */
+ if ((req->sr_state == stun_req_timeout) && (req->sr_from_y == -1)) {
+ SU_DEBUG_0(("%s: lifetime determination failed.\n", __func__));
+ sd->sd_state = stun_discovery_timeout;
+
+ /* Use per discovery specific callback */
+ if (sd->sd_callback)
+ sd->sd_callback(sd->sd_magic, sh, sd, action, sd->sd_state);
+
+ req->sr_state = stun_req_dispose_me;
+ return 0;
+ }
+
+ if (abs(sd->sd_lt_cur - sd->sd_lt) <= STUN_LIFETIME_CI) {
+ sd->sd_state = stun_discovery_done;
+
+ /* Use per discovery specific callback */
+ if (sd->sd_callback)
+ sd->sd_callback(sd->sd_magic, sh, sd, action, sd->sd_state);
+
+ req->sr_state = stun_req_dispose_me;
+ return 0;
+ }
+
+ /* We come here as a response to a request send from the sockfdy */
+ if (req->sr_from_y == 1) {
+ req->sr_state = stun_req_dispose_me, req = NULL;
+
+ new = stun_request_create(sd);
+ new->sr_from_y = 0;
+ if (stun_make_binding_req(sh, new, new->sr_msg, 0, 0) < 0)
+ return -1;
+
+ destination = (su_sockaddr_t *) sd->sd_pri_addr;
+ err = stun_send_binding_request(new, destination);
+ if (err < 0) {
+ stun_free_message(new->sr_msg);
+ return -1;
+ }
+ return 0;
+ }
+ else if (req->sr_from_y == 0) {
+ if (req->sr_state != stun_discovery_timeout) {
+ /* mapping with X still valid */
+ sd->sd_lt_cur = sd->sd_lt;
+ sd->sd_lt = (int) (sd->sd_lt + sd->sd_lt_max) / 2;
+
+ SU_DEBUG_1(("%s: Response received from socket X, " \
+ "lifetime at least %d sec, next trial: %d sec\n",
+ __func__, sd->sd_lt_cur, sd->sd_lt));
+ }
+ else {
+ sd->sd_lt_max = sd->sd_lt;
+ sd->sd_lt = (int) (sd->sd_lt + sd->sd_lt_cur) / 2;
+ SU_DEBUG_1(("%s: No response received from socket X, " \
+ "lifetime at most %d sec, next trial: %d sec\n",
+ __func__, sd->sd_lt_max, sd->sd_lt));
+ }
+ }
+
+ /* Rock, we come from sockfdx */
+ process_binding_request(req, binding_response);
+
+ li = &req->sr_localinfo;
+ sa = req->sr_local_addr;
+ stun_free_message(binding_response);
+
+ /* Destroy me with the bad mofo timer */
+ req->sr_state = stun_req_dispose_me, req = NULL;
+
+ new = stun_request_create(sd);
+ /* Use sockfdy */
+ new->sr_socket = sockfdy;
+ new->sr_from_y = 1;
+
+ if (stun_make_binding_req(sh, new, new->sr_msg, 0, 0) < 0)
+ return -1;
+
+ stun_add_response_address(new->sr_msg, (struct sockaddr_in *) sa);
+
+ /* Create and start timer */
+ sockfdy_timer = su_timer_create(su_root_task(sh->sh_root), sd->sd_lt);
+ su_timer_set(sockfdy_timer, stun_test_lifetime_timer_cb, (su_wakeup_arg_t *) new);
+
+ return 0;
+}
+
+
+static int action_bind(stun_request_t *req, stun_msg_t *binding_response)
+{
+ su_localinfo_t *li = NULL;
+ su_sockaddr_t *sa = NULL;
+ stun_discovery_t *sd = req->sr_discovery;
+ stun_handle_t *sh = req->sr_handle;
+ stun_action_t action;
+
+ enter;
+ action = get_action(req);
+
+ process_binding_request(req, binding_response);
+
+ li = &req->sr_localinfo;
+ sa = req->sr_local_addr;
+
+ memcpy(sd->sd_addr_seen_outside, sa, sizeof(su_sockaddr_t));
+
+ sd->sd_state = stun_discovery_done;
+
+ if (sd->sd_callback)
+ sd->sd_callback(sd->sd_magic, sh, sd, action, sd->sd_state);
+
+ req->sr_state = stun_req_dispose_me;
+
+ return 0;
+}
+
+/**
+ * Returns a non-zero value if some local interface address
+ * matches address in su.
+ */
+static int priv_find_matching_localadress(su_sockaddr_t *su)
+{
+ su_localinfo_t hints[1] = {{ LI_CANONNAME | LI_NUMERIC }}, *li, *res = NULL;
+ int af;
+ char addr[SU_ADDRSIZE];
+
+ SU_DEBUG_5(("%s: checking if %s is a local address.\n", __func__,
+ inet_ntop(AF_INET, SU_ADDR(su), addr, sizeof(addr))));
+
+ hints->li_family = af = su->su_family;
+
+ if (su_getlocalinfo(hints, &res) != 0)
+ return 0;
+
+ /* check if any of the address match 'sockaddr' */
+ for (li = res; li; li = li->li_next) {
+ if (li->li_family != af)
+ continue;
+
+ if (memcmp(SU_ADDR(su), SU_ADDR(li->li_addr), SU_ADDRLEN(su)) == 0) {
+ SU_DEBUG_5(("%s: found matching local address\n", __func__));
+ break;
+ }
+
+ SU_DEBUG_9(("%s: skipping local address %s.\n", __func__,
+ inet_ntop(af, SU_ADDR(li->li_addr), addr, sizeof(addr))));
+ }
+
+ su_freelocalinfo(res);
+
+ return li != NULL;
+}
+
+/**
+ * Helper function for action_determine_nattype().
+ */
+static void priv_mark_discovery_done(stun_discovery_t *sd,
+ stun_handle_t *sh,
+ stun_action_t action,
+ stun_request_t *req)
+{
+ sd->sd_state = stun_discovery_done;
+ if (sd->sd_callback)
+ sd->sd_callback(sd->sd_magic, sh, sd, action, sd->sd_state);
+ req->sr_state = stun_req_dispose_me;
+}
+
+/**
+ * Handles responses related to the NAT type discovery process.
+ *
+ * The requests for Tests I-III are sent in parallel, so the
+ * callback has to keep track of which requests have been received
+ * and postpone decisions until enough responses have been processed.
+ *
+ * @see stun_test_nattype().
+ */
+static int action_determine_nattype(stun_request_t *req, stun_msg_t *binding_response)
+{
+ stun_handle_t *sh = req->sr_handle;
+ su_localinfo_t *li = NULL;
+ stun_discovery_t *sd = req->sr_discovery;
+ stun_action_t action;
+ int err;
+ /* test status: 0 not received, -1 timeout, 1 response received */
+ int reply_res;
+
+ enter;
+
+ action = get_action(req);
+
+ /* if the NAT type is already detected, ignore this request */
+ if (!sd || (sd->sd_nattype != stun_nat_unknown)) {
+ req->sr_state = stun_req_dispose_me;
+ /* stun_request_destroy(req); */
+ return 0;
+ }
+
+ /* parse first the response payload */
+ if (binding_response)
+ process_binding_request(req, binding_response);
+
+ /* get pointer to MAPPED-ADDRESS of req */
+ li = &req->sr_localinfo;
+
+ /* check whether the response timed out or not */
+ if (req->sr_state == stun_req_timeout)
+ reply_res = -1;
+ else
+ reply_res = 1;
+
+ /* note: Test I completed - reply from the destination address
+ * where we sent our packet */
+ if (req->sr_request_mask == 0 && sd->sd_first == 0) {
+ sd->sd_first = reply_res;
+ if (reply_res)
+ memcpy(sd->sd_addr_seen_outside, li->li_addr, sizeof(su_sockaddr_t));
+ }
+
+ /* note: Test II completed - reply from another address and port */
+ else if ((req->sr_request_mask & CHG_IP) &&
+ (req->sr_request_mask & CHG_PORT))
+ sd->sd_second = reply_res;
+
+ /* note: Test III completed - reply from another port */
+ else if (req->sr_request_mask & CHG_PORT)
+ sd->sd_third = reply_res;
+
+ /* note: Test IV completed - request and reply to another port */
+ else if (req->sr_request_mask == 0 && sd->sd_fourth == 2) {
+ sd->sd_fourth = reply_res;
+
+ /* SU_DEBUG_5(("Comparing reported MAPPED ADDRESSES %s:%u vs %s:%u.\n",
+ inet_ntoa(sd->sd_addr_seen_outside[0].su_sin.sin_addr),
+ sd->sd_addr_seen_outside[0].su_port,
+ inet_ntoa(li->li_addr->su_sin.sin_addr),
+ li->li_addr->su_port)); */
+
+ /* note: check whether MAPPED-ADDRESS address has changed (when
+ * sending to a different IP:port -> NAT mapping behaviour) */
+ if (su_cmp_sockaddr(sd->sd_addr_seen_outside, li->li_addr) != 0) {
+ sd->sd_mapped_addr_match = 0;
+ }
+ else {
+ sd->sd_mapped_addr_match = 1;
+ }
+ }
+
+ SU_DEBUG_9(("stun natcheck status: 1st=%d, 2nd=%d, 3rd=%d, 4th=%d, mask=%d, sr_state=%d (timeout=%d, done=%d)..\n",
+ sd->sd_first, sd->sd_second, sd->sd_third, sd->sd_fourth, req->sr_request_mask, req->sr_state, stun_req_timeout, stun_discovery_done));
+
+ /* case 1: no response to Test-I (symmetric response)
+ * a FW must be blocking us */
+ if (sd->sd_first < 0) {
+ sd->sd_nattype = stun_udp_blocked;
+ priv_mark_discovery_done(sd, sh, action, req);
+ }
+ /* case 2: mapped address matches our local address
+ * not behind a NAT, result of test two determinces
+ * whether we are behind a symmetric FW or not */
+ else if (sd->sd_first > 0 &&
+ sd->sd_second &&
+ priv_find_matching_localadress(sd->sd_addr_seen_outside)) {
+ if (sd->sd_second > 0)
+ sd->sd_nattype = stun_open_internet;
+ else
+ sd->sd_nattype = stun_sym_udp_fw;
+ priv_mark_discovery_done(sd, sh, action, req);
+ }
+ /* case 3: response ok to Test-II, and behind a NAT
+ * do not make conclusions until Test-IV has been scheduled */
+ else if (sd->sd_first > 0 &&
+ sd->sd_second > 0 &&
+ sd->sd_fourth) {
+ if (sd->sd_mapped_addr_match == 1)
+ sd->sd_nattype = stun_nat_full_cone;
+ else
+ sd->sd_nattype = stun_nat_ei_filt_ad_map;
+ priv_mark_discovery_done(sd, sh, action, req);
+ }
+ /* case 4: tests I-III done, perform IV
+ * see notes below */
+ else if (sd->sd_first > 0 &&
+ sd->sd_second &&
+ sd->sd_third &&
+ sd->sd_fourth == 0) {
+
+ /*
+ * No response received, so we now perform Test IV using the address
+ * learnt from response to Test-I.
+ *
+ * Unfortunately running this test will potentially affect
+ * results of a subsequent Test-II (depends on NAT binding timeout
+ * values). To get around this, the STUN server would ideally have
+ * a dedicated IP:port for Test-IV. But within the currents specs,
+ * we need to reuse one of the IP:port addresses already used in
+ * Test-II by the STUN server to send us packets.
+ */
+
+ SU_DEBUG_7(("Sending STUN NAT type Test-IV request to %s.\n",
+ inet_ntoa(sd->sd_sec_addr[0].su_sin.sin_addr)));
+
+ sd->sd_fourth = 2; /* request, -1, 0, 1 reserved for results */
+ req->sr_state = stun_req_dispose_me;
+ req = stun_request_create(sd);
+ err = stun_make_binding_req(sh, req, req->sr_msg,
+ STUNTAG_CHANGE_IP(0),
+ STUNTAG_CHANGE_PORT(0),
+ TAG_END());
+
+ if (err == 0) {
+ err = stun_send_binding_request(req, sd->sd_sec_addr);
+ }
+
+ if (err < 0) {
+ SU_DEBUG_0(("WARNING: Failure in performing STUN Test-IV check. "
+ "The results related to mapping characteristics may be incorrect."));
+ stun_free_message(req->sr_msg);
+ sd->sd_fourth = -1;
+ /* call function again, sd_fourth stops the recursion */
+ action_determine_nattype(req, binding_response);
+ return -1;
+ }
+
+ return 0; /* we don't want to dispose this req */
+ }
+ /* case 5: no response Test-II, and success with III
+ * the NAT is filtering packets from different IP
+ * do not make conclusions until Test-IV has been scheduled */
+ else if (sd->sd_first > 0 &&
+ sd->sd_second < 0 &&
+ sd->sd_third > 0 &&
+ sd->sd_fourth) {
+ if (sd->sd_mapped_addr_match == 1)
+ sd->sd_nattype = stun_nat_res_cone;
+ else
+ sd->sd_nattype = stun_nat_ad_filt_ad_map;
+ priv_mark_discovery_done(sd, sh, action, req);
+ }
+ /* case 6: no response to Test-II nor III
+ * the NAT is filtering packets from different port
+ * do not make conclusions until Test-IV has been scheduled */
+ else if (sd->sd_first > 0 &&
+ sd->sd_second < 0 &&
+ sd->sd_third < 0 &&
+ sd->sd_fourth) {
+ if (sd->sd_mapped_addr_match == 1)
+ sd->sd_nattype = stun_nat_port_res_cone;
+ else
+ sd->sd_nattype = stun_nat_adp_filt_ad_map;
+ priv_mark_discovery_done(sd, sh, action, req);
+ }
+
+ /* this request of the discovery process can be disposed */
+ req->sr_state = stun_req_dispose_me;
+
+ return 0;
+}
+
+
+static void stun_sendto_timer_cb(su_root_magic_t *magic,
+ su_timer_t *t,
+ su_timer_arg_t *arg)
+{
+ stun_request_t *req = arg;
+ stun_handle_t *sh = req->sr_handle;
+ stun_discovery_t *sd = req->sr_discovery;
+ stun_action_t action = get_action(req);
+ long timeout = 0;
+
+ enter;
+
+ if (req->sr_state == stun_req_dispose_me) {
+ stun_request_destroy(req);
+ SU_DEBUG_7(("%s: timer destroyed.\n", __func__));
+ return;
+ }
+
+ ++req->sr_retry_count;
+
+ /* check if max retry count has been exceeded; or if
+ * action type is NAT type check (XXX: the request attributes
+ * are not passed correctly to resend function) */
+ if (req->sr_retry_count >= sh->sh_max_retries ||
+ action == stun_action_test_nattype) {
+ errno = ETIMEDOUT;
+ STUN_ERROR(errno, stun_sendto_timer_cb);
+
+ stun_free_message(req->sr_msg);
+ free(req->sr_msg), req->sr_msg = NULL;
+
+ /* Either the server was dead, address wrong or STUN_UDP_BLOCKED */
+ /* sd->sd_nattype = stun_udp_blocked; */
+ req->sr_state = stun_req_timeout;
+
+ /* If the action is binding request, we are done. If action was
+ NAT type determination, process with the state machine. */
+ switch (action) {
+ case stun_action_binding_request:
+ sd->sd_state = stun_discovery_timeout;
+
+ /* Use per discovery specific callback */
+ if (sd->sd_callback)
+ sd->sd_callback(sd->sd_magic, sh, sd, action, sd->sd_state);
+
+ req->sr_state = stun_req_dispose_me;
+ break;
+
+ case stun_action_test_nattype:
+ action_determine_nattype(req, NULL);
+ break;
+
+ case stun_action_test_lifetime:
+ process_test_lifetime(req, NULL);
+ break;
+
+ case stun_action_keepalive:
+ sd->sd_state = stun_discovery_timeout;
+
+ /* Use per discovery specific callback */
+ if (sd->sd_callback)
+ sd->sd_callback(sd->sd_magic, sh, sd, action, sd->sd_state);
+
+ stun_keepalive_destroy(sh, sd->sd_socket);
+
+ break;
+
+ default:
+ break;
+
+ return;
+ }
+
+ /* Destroy me immediately */
+ req->sr_state = stun_req_dispose_me;
+ timeout = 0;
+ }
+ else {
+ SU_DEBUG_3(("%s: Timeout no. %d, retransmitting.\n",
+ __func__, req->sr_retry_count));
+
+ /* Use pre-defined destination address for re-sends */
+ if (stun_send_message(req->sr_socket, req->sr_destination,
+ req->sr_msg, &(sh->sh_passwd)) < 0) {
+ stun_free_message(req->sr_msg);
+ free(req->sr_msg), req->sr_msg = NULL;
+ return;
+ }
+ timeout = req->sr_timeout *= 2;
+
+ }
+
+ su_timer_set_at(t, stun_sendto_timer_cb, (su_wakeup_arg_t *) req,
+ su_time_add(su_now(), timeout));
+
+ return;
+}
+
+
+/** This function sends a binding request to the address at serv (ip,
+ * port). which could be the original or alternative socket addresses
+ * of the STUN server. Local address is provided in cli, and
+ * resulting mapped address is also saved in cli.
+ * Return 0 if successful, -1 if failed
+ *
+ * @return
+ * On success, zero is returned. Upon error, -1 is returned, and @e errno is
+ * set appropriately.
+ *
+ * @ERRORS
+ * @ERROR EBADF @a sockfd is not a valid deseriptor.
+ * @ERROR EPROTONOSUPPORT @a sockfd is not an UDP socket.
+ * @ERROR EINVAL The socket is already bound to an address.
+ * @ERROR EACCESS The address is protected, and the user is not
+ * the super-user.
+ * @ERROR ENOTSOCK Argument is a descriptor for a file, not a socket.
+ * @ERROR EAGAIN Operation in progress. Application should call
+ * stun_bind() again when there is data available on
+ * the socket.
+ * @ERROR ETIMEDOUT Request timed out.
+ *
+ */
+static int stun_send_binding_request(stun_request_t *req,
+ su_sockaddr_t *srvr_addr)
+{
+ su_timer_t *sendto_timer = NULL;
+ su_socket_t s;
+ stun_handle_t *sh = req->sr_handle;
+ stun_msg_t *msg = req->sr_msg;
+
+ assert (sh && srvr_addr);
+
+ enter;
+
+ s = req->sr_socket;
+ memcpy(req->sr_destination, srvr_addr, sizeof(su_sockaddr_t));
+
+ if (stun_send_message(s, srvr_addr, msg, &(sh->sh_passwd)) < 0) {
+ return -1;
+ }
+
+ /* Create and start timer */
+ sendto_timer = su_timer_create(su_root_task(sh->sh_root), STUN_SENDTO_TIMEOUT);
+ su_timer_set(sendto_timer, stun_sendto_timer_cb, (su_wakeup_arg_t *) req);
+
+ req->sr_timer = sendto_timer;
+ req->sr_state = stun_req_discovery_processing;
+
+ return 0;
+}
+
+
+/** Compose a STUN message of the format defined by stun_msg_t */
+int stun_make_binding_req(stun_handle_t *sh,
+ stun_request_t *req,
+ stun_msg_t *msg,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ int i;
+ stun_attr_t *tmp, **p;
+ int bits = 0;
+ int chg_ip = 0, chg_port = 0;
+
+ ta_list ta;
+
+ enter;
+
+ ta_start(ta, tag, value);
+
+ tl_gets(ta_args(ta),
+ STUNTAG_CHANGE_IP_REF(chg_ip),
+ STUNTAG_CHANGE_PORT_REF(chg_port),
+ TAG_END());
+
+ ta_end(ta);
+
+ if (chg_ip)
+ bits |= CHG_IP;
+ if (chg_port)
+ bits |= CHG_PORT;
+
+ if (req)
+ req->sr_request_mask = bits;
+
+ /* compose header */
+ msg->stun_hdr.msg_type = BINDING_REQUEST;
+ msg->stun_hdr.msg_len = 0; /* actual len computed by
+ stun_send_message */
+ for (i = 0; i < STUN_TID_BYTES; i++) {
+ msg->stun_hdr.tran_id[i] = (1 + rand() % RAND_MAX_16);
+ }
+
+ /* optional attributes:
+ * - Response Address
+ * - Change Request X
+ * - Username
+ * - Message-Integrity */
+ msg->stun_attr = NULL;
+ /* CHANGE_REQUEST */
+ p = &(msg->stun_attr);
+
+ if (chg_ip || chg_port) {
+ stun_attr_changerequest_t *attr_cr;
+ tmp = (stun_attr_t *) malloc(sizeof(stun_attr_t));
+ tmp->attr_type = CHANGE_REQUEST;
+ attr_cr = (stun_attr_changerequest_t *) malloc(sizeof(stun_attr_changerequest_t));
+ attr_cr->value =
+ (chg_ip ? STUN_CR_CHANGE_IP : 0) | (chg_port ? STUN_CR_CHANGE_PORT : 0);
+
+ tmp->pattr = attr_cr;
+ tmp->next = NULL;
+ *p = tmp; p = &(tmp->next);
+ }
+
+ /* USERNAME */
+ if (sh->sh_use_msgint &&
+ sh->sh_username.data &&
+ sh->sh_passwd.data) {
+ stun_buffer_t *a_pattr = (stun_buffer_t*)malloc(sizeof(stun_buffer_t));
+ tmp = (stun_attr_t *) malloc(sizeof(stun_attr_t));
+ tmp->attr_type = USERNAME;
+
+ /* copy USERNAME from STUN handle */
+ a_pattr->data = (void*)malloc(sh->sh_username.size);
+ memcpy(a_pattr->data, sh->sh_username.data, sh->sh_username.size);
+ a_pattr->size = sh->sh_username.size;
+ tmp->pattr = a_pattr;
+
+ tmp->next = NULL;
+ *p = tmp; p = &(tmp->next);
+
+ /* dummy MESSAGE_INTEGRITY attribute, computed later */
+ tmp = (stun_attr_t *) malloc(sizeof(stun_attr_t));
+ tmp->attr_type = MESSAGE_INTEGRITY;
+ tmp->pattr = NULL;
+ tmp->next = NULL;
+ *p = tmp; p = &(tmp->next);
+ }
+
+ /* no buffer assigned yet */
+ msg->enc_buf.data = NULL;
+ msg->enc_buf.size = 0;
+
+ return 0;
+}
+
+int stun_process_response(stun_msg_t *msg)
+{
+
+ enter;
+
+ /* parse msg first */
+ if (stun_parse_message(msg) < 0) {
+ SU_DEBUG_3(("%s: Error parsing response.\n", __func__));
+ return -1;
+ }
+
+ /* check message digest if exists */
+ switch (msg->stun_hdr.msg_type) {
+ case BINDING_RESPONSE:
+ if (stun_process_binding_response(msg) < 0)
+ return -1;
+ break;
+ case BINDING_ERROR_RESPONSE:
+ if (stun_process_error_response(msg) < 0)
+ return -1;
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/** process binding response */
+int stun_process_binding_response(stun_msg_t *msg) {
+ /* currently not needed. */
+ return 0;
+}
+
+
+/** process binding error response
+ * Report error and return
+ */
+int stun_process_error_response(stun_msg_t *msg)
+{
+ stun_attr_t *attr;
+ stun_attr_errorcode_t *ec;
+
+ enter;
+
+ attr = stun_get_attr(msg->stun_attr, ERROR_CODE);
+ if (attr == NULL) {
+ perror("stun_process_error_response");
+ return -1;
+ }
+
+ ec = (stun_attr_errorcode_t *)attr->pattr;
+
+ SU_DEBUG_5(("%s: Received Binding Error Response:\n", __func__));
+ SU_DEBUG_5(("%s: Error: %d %s\n", __func__, ec->code, ec->phrase));
+
+ return 0;
+}
+
+/**
+ * Sets values for USERNAME and PASSWORD stun fields
+ * for the handle.
+ */
+int stun_set_uname_pwd(stun_handle_t *sh,
+ const char *uname,
+ isize_t len_uname,
+ const char *pwd,
+ isize_t len_pwd)
+{
+ enter;
+
+ sh->sh_username.data = malloc(len_uname);
+ if (sh->sh_username.data) {
+ memcpy(sh->sh_username.data, uname, len_uname);
+ sh->sh_username.size = (unsigned)len_uname;
+ }
+ else
+ return -1;
+
+ sh->sh_passwd.data = malloc(len_pwd);
+ if (sh->sh_passwd.data) {
+ memcpy(sh->sh_passwd.data, pwd, len_pwd);
+ sh->sh_passwd.size = (unsigned)len_pwd;
+ }
+ else
+ return -1;
+
+ sh->sh_use_msgint = 1; /* turn on message integrity ussage */
+
+ return 0;
+}
+
+
+/**
+ * Converts character address format to sockaddr_in
+ */
+int stun_atoaddr(su_home_t *home,
+ int ai_family,
+ su_addrinfo_t *info,
+ char const *in)
+{
+ su_addrinfo_t *res = NULL, *ai, hints[1] = {{ 0 }};
+ char const *host;
+ char *port = NULL, tmp[SU_ADDRSIZE];
+ int err;
+ su_sockaddr_t *dstaddr;
+
+ assert(info && in);
+
+ enter;
+
+ dstaddr = (su_sockaddr_t *) info->ai_addr;
+
+ /* note: works only for IPv4 */
+ if (ai_family != AF_INET)
+ return -1;
+
+ hints->ai_family = ai_family;
+
+ port = strstr(in, ":");
+ if (port == NULL) {
+ host = in;
+ }
+ else {
+ assert((size_t)(port - in) < strlen(in) + 1);
+ memcpy(tmp, in, port - in);
+ tmp[port - in] = 0;
+ host = tmp;
+ ++port;
+ }
+
+ err = su_getaddrinfo(host, NULL, hints, &res);
+ if (err == 0) {
+ for (ai = res; ai; ai = ai->ai_next) {
+ if (ai->ai_family != AF_INET)
+ continue;
+
+ info->ai_flags = ai->ai_flags;
+ info->ai_family = ai->ai_family;
+ info->ai_socktype = ai->ai_socktype;
+ info->ai_protocol = ai->ai_protocol;
+ info->ai_addrlen = ai->ai_addrlen;
+ info->ai_canonname = su_strdup(home, host);
+
+ memcpy(&dstaddr->su_sa, res->ai_addr, sizeof(struct sockaddr));
+ break;
+ }
+
+ if (port)
+ dstaddr->su_port = htons(atoi(port));
+ else
+ dstaddr->su_port = htons(STUN_DEFAULT_PORT);
+ }
+ else {
+ SU_DEBUG_5(("stun_atoaddr: %s(%s): %s\n", "su_getaddrinfo", in,
+ su_gai_strerror(err)));
+ }
+
+ if (res)
+ su_freeaddrinfo(res);
+
+ return err;
+}
+
+/**
+ * Initiates STUN discovery process to find out NAT
+ * binding life-time settings.
+ *
+ * @TAGS
+ * @TAG STUNTAG_SOCKET Bind socket for STUN
+ * @TAG STUNTAG_REGISTER_EVENTS Register socket for eventloop owned by STUN
+ * @TAG STUNTAG_SERVER() stun server hostname or dotted IPv4 address
+ *
+ * @return 0 on success, non-zero on error
+ */
+int stun_test_lifetime(stun_handle_t *sh,
+ stun_discovery_f sdf,
+ stun_discovery_magic_t *magic,
+ tag_type_t tag, tag_value_t value,
+ ...)
+{
+ stun_request_t *req = NULL;
+ stun_discovery_t *sd = NULL;
+ ta_list ta;
+ su_socket_t s = INVALID_SOCKET;
+ int err, index = 0, s_reg = 0;
+ char addr[SU_ADDRSIZE];
+ char const *server = NULL;
+ su_socket_t sockfdy;
+ socklen_t y_len;
+ su_sockaddr_t y_addr;
+ su_sockaddr_t *destination;
+
+ assert(sh);
+
+ enter;
+
+ if (!sh->sh_pri_addr[0].su_port) {
+ /* no STUN server address, perform a DNS-SRV lookup */
+
+ ta_list ta;
+ ta_start(ta, tag, value);
+ SU_DEBUG_5(("Delaying STUN get-lifetime req. for DNS-SRV query.\n"));
+ err = priv_dns_queue_action(sh, stun_action_test_lifetime, sdf, magic, ta_tags(ta));
+ ta_end(ta);
+
+ return err;
+ }
+
+ ta_start(ta, tag, value);
+
+ tl_gets(ta_args(ta),
+ STUNTAG_SOCKET_REF(s),
+ STUNTAG_REGISTER_EVENTS_REF(s_reg),
+ STUNTAG_SERVER_REF(server),
+ TAG_END());
+
+ sd = stun_discovery_create(sh, stun_action_test_lifetime, sdf, magic);
+ if ((index = assign_socket(sd, s, s_reg)) < 0)
+ return errno = EFAULT, -1;
+
+ /* If no server given, use default address from stun_handle_init() */
+ if (!server) {
+ /* memcpy(&sd->sd_pri_info, &sh->sh_pri_info, sizeof(su_addrinfo_t)); */
+ memcpy(sd->sd_pri_addr, sh->sh_pri_addr, sizeof(su_sockaddr_t));
+ }
+ else {
+ err = stun_atoaddr(sh->sh_home, AF_INET, &sd->sd_pri_info, server);
+ memcpy(sd->sd_pri_addr, &sd->sd_pri_info.ai_addr, sizeof(su_sockaddr_t));
+ }
+ destination = (su_sockaddr_t *) sd->sd_pri_addr;
+
+ req = stun_request_create(sd);
+
+ /* ci = &req->sr_localinfo; */
+
+ /* get local ip address */
+ /* get_localinfo(); */
+
+ /* initialize socket y */
+ sockfdy = su_socket(AF_INET, SOCK_DGRAM, 0);
+
+ /* set socket asynchronous */
+ if (su_setblocking(sockfdy, 0) < 0) {
+ STUN_ERROR(errno, su_setblocking);
+
+ su_close(sockfdy);
+ return errno = EFAULT, -1;
+ }
+
+ sd->sd_socket2 = sockfdy;
+
+ memset(&y_addr, 0, sizeof(y_addr));
+ memcpy(&y_addr, sd->sd_bind_addr, sizeof(y_addr));
+ y_addr.su_port = 0;
+
+ y_len = sizeof(y_addr);
+ if (bind(sockfdy, (struct sockaddr *) &y_addr, y_len) < 0) {
+ return -1;
+ }
+
+ if (getsockname(sockfdy, (struct sockaddr *) &y_addr, &y_len) < 0) {
+ STUN_ERROR(errno, getsockname);
+ return -1;
+ }
+
+ SU_DEBUG_3(("%s: socket y bound to %s:%u\n", __func__,
+ inet_ntop(y_addr.su_family, SU_ADDR(&y_addr), addr, sizeof(addr)),
+ (unsigned) ntohs(y_addr.su_port)));
+
+ req->sr_from_y = -1;
+
+ SU_DEBUG_1(("%s: determining binding life time, this may take a while.\n", __func__));
+
+ if (stun_make_binding_req(sh, req, req->sr_msg, 0, 0) < 0)
+ return -1;
+
+ err = stun_send_binding_request(req, destination);
+ if (err < 0) {
+ stun_free_message(req->sr_msg);
+ return -1;
+ }
+
+ ta_end(ta);
+
+ return 0;
+}
+
+int stun_add_response_address(stun_msg_t *req, struct sockaddr_in *mapped_addr)
+{
+ stun_attr_sockaddr_t *addr;
+ stun_attr_t *tmp;
+
+ enter;
+
+ tmp = malloc(sizeof(stun_attr_t));
+ tmp->attr_type = RESPONSE_ADDRESS;
+ addr = malloc(sizeof(stun_attr_sockaddr_t));
+ memcpy(addr, mapped_addr, sizeof(stun_attr_sockaddr_t));
+ tmp->pattr = addr;
+
+ if (req->stun_attr == NULL) {
+ tmp->next = NULL;
+ }
+ else {
+ tmp->next = req->stun_attr;
+ }
+ req->stun_attr = tmp;
+
+ return 0;
+}
+
+
+/**
+ * Determines if the message is STUN message (-1 if not stun).
+ */
+int stun_msg_is_keepalive(uint16_t data)
+{
+ uint16_t msg_type;
+ /* parse header */
+ msg_type = ntohs(data);
+
+ if (msg_type == BINDING_REQUEST ||
+ msg_type == BINDING_RESPONSE ||
+ msg_type == BINDING_ERROR_RESPONSE) {
+ return 0;
+ }
+
+ return -1;
+}
+
+/**
+ * Determines length of STUN message (0 (-1?) if not stun).
+ */
+int stun_message_length(void *data, isize_t len, int end_of_message)
+{
+ unsigned char *p;
+ uint16_t msg_type;
+
+ if (len < 4)
+ return -1;
+
+ /* parse header first */
+ p = data;
+ msg_type = (p[0] << 8) | p[1];
+
+ if (msg_type == BINDING_REQUEST ||
+ msg_type == BINDING_RESPONSE ||
+ msg_type == BINDING_ERROR_RESPONSE) {
+ /* return message length */
+ return (p[0] << 8) | p[1];
+ }
+ else
+ return -1;
+}
+
+/** Process incoming message */
+int stun_process_message(stun_handle_t *sh, su_socket_t s,
+ su_sockaddr_t *sa, socklen_t salen,
+ void *data, isize_t len)
+{
+ int retval = -1;
+ stun_msg_t msg;
+
+ enter;
+
+ if (len >= 65536)
+ len = 65536;
+
+ /* Message received. */
+ msg.enc_buf.data = data;
+ msg.enc_buf.size = (unsigned)len;
+
+ debug_print(&msg.enc_buf);
+
+ /* Parse here the incoming message. */
+ if (stun_parse_message(&msg) < 0) {
+ stun_free_message(&msg);
+ SU_DEBUG_5(("%s: Error parsing response.\n", __func__));
+ return retval;
+ }
+
+ if (msg.stun_hdr.msg_type == BINDING_REQUEST) {
+ return stun_process_request(s, &msg, 0, sa, salen);
+ }
+ else if (msg.stun_hdr.msg_type == BINDING_RESPONSE) {
+ /* Based on the decoded payload, find the corresponding request
+ * (based on TID). */
+ return do_action(sh, &msg);
+ }
+
+ return -1;
+}
+
+
+int stun_discovery_release_socket(stun_discovery_t *sd)
+{
+ stun_handle_t *sh = sd->sd_handle;
+
+ if (su_root_deregister(sh->sh_root, sd->sd_index) >= 0) {
+ SU_DEBUG_3(("%s: socket deregistered from STUN \n", __func__));
+ sd->sd_index = -1; /* mark index as deregistered */
+
+ return 0;
+ }
+
+ return -1;
+}
+
+
+/**
+ * Creates a keepalive dispatcher for bound SIP sockets
+ */
+int stun_keepalive(stun_handle_t *sh,
+ su_sockaddr_t *sa,
+ tag_type_t tag, tag_value_t value,
+ ...)
+{
+ su_socket_t s = INVALID_SOCKET;
+ unsigned int timeout = 0;
+ ta_list ta;
+ stun_discovery_t *sd;
+ stun_request_t *req;
+ stun_action_t action = stun_action_keepalive;
+ char addr[SU_ADDRSIZE];
+
+ enter;
+
+ ta_start(ta, tag, value);
+
+ tl_gets(ta_args(ta),
+ STUNTAG_SOCKET_REF(s),
+ STUNTAG_TIMEOUT_REF(timeout),
+ TAG_END());
+
+ ta_end(ta);
+
+ if (s < 1 || !sa || timeout == 0)
+ return errno = EFAULT, -1;
+
+ /* If there already is keepalive associated with the given socket,
+ * destroy it. */
+ stun_keepalive_destroy(sh, s);
+
+ sd = stun_discovery_create(sh, action, NULL, NULL); /* XXX --
+ specify last
+ params if
+ necessary */
+ sd->sd_socket = s;
+ sd->sd_timeout = timeout;
+ memcpy(sd->sd_pri_addr, sa, sizeof(*sa));
+
+ req = stun_request_create(sd);
+
+ SU_DEBUG_3(("%s: Starting to send STUN keepalives to %s:%u\n", __func__,
+ inet_ntop(sa->su_family, SU_ADDR(sa), addr, sizeof(addr)),
+ (unsigned) ntohs(sa->su_port)));
+
+ if (stun_make_binding_req(sh, req, req->sr_msg, 0, 0) < 0 ||
+ stun_send_binding_request(req, sa) < 0) {
+ stun_request_destroy(req);
+ stun_discovery_destroy(sd);
+ return -1;
+ }
+
+ sd->sd_timer = su_timer_create(su_root_task(sh->sh_root), timeout);
+ su_timer_set(sd->sd_timer, stun_keepalive_timer_cb, (su_wakeup_arg_t *) sd);
+
+ return 0;
+}
+
+/** Send SIP keepalives */
+static void stun_keepalive_timer_cb(su_root_magic_t *magic,
+ su_timer_t *t,
+ su_timer_arg_t *arg)
+{
+ stun_discovery_t *sd = arg;
+ stun_handle_t *sh = sd->sd_handle;
+ int timeout = sd->sd_timeout;
+ su_sockaddr_t *destination = sd->sd_pri_addr;
+ stun_request_t *req;
+
+ enter;
+
+ su_timer_destroy(t);
+
+ if (sd->sd_state == stun_discovery_timeout)
+ return;
+
+ req = stun_request_create(sd);
+
+ if (stun_make_binding_req(sh, req, req->sr_msg, 0, 0) < 0 ||
+ stun_send_binding_request(req, destination) < 0) {
+ stun_request_destroy(req);
+ stun_discovery_destroy(sd);
+ return;
+ }
+
+ sd->sd_timer = su_timer_create(su_root_task(sh->sh_root), timeout);
+ su_timer_set(sd->sd_timer, stun_keepalive_timer_cb, (su_wakeup_arg_t *) sd);
+
+ return;
+}
+
+/**
+ * Destroys the keepalive dispatcher without touching the socket
+ */
+int stun_keepalive_destroy(stun_handle_t *sh, su_socket_t s)
+{
+ stun_discovery_t *sd = NULL;
+ stun_request_t *req;
+ stun_action_t action = stun_action_keepalive;
+
+ if (sh == NULL)
+ return 1;
+
+ /* Go through the request queue and destroy keepalive requests
+ * associated with the given socket. */
+ for (req = sh->sh_requests; req; req = req->sr_next) {
+ if (req->sr_socket == s && req->sr_discovery->sd_action == action) {
+ req->sr_state = stun_req_dispose_me;
+ if (!sd)
+ sd = req->sr_discovery;
+ }
+ }
+
+ /* No keepalive found */
+ if (!sd)
+ return 1;
+
+ su_timer_destroy(sd->sd_timer), sd->sd_timer = NULL;
+ stun_discovery_destroy(sd);
+
+ return 0;
+}
+
+
+int stun_process_request(su_socket_t s, stun_msg_t *req,
+ int sid, su_sockaddr_t *from_addr,
+ socklen_t from_len)
+{
+ stun_msg_t resp;
+ su_sockaddr_t mod_addr[1] = {{ 0 }}, src_addr[1] = {{ 0 }}, chg_addr[1] = {{ 0 }};
+ stun_attr_t *tmp, m_attr[1], s_attr[1], c_attr[1], **p;
+ su_sockaddr_t to_addr;
+ int c, i;
+
+ tmp = stun_get_attr(req->stun_attr, RESPONSE_ADDRESS);
+
+ if (tmp) {
+ memcpy(&to_addr, tmp->pattr, sizeof(to_addr));
+ }
+ else {
+ memcpy(&to_addr, from_addr, sizeof(to_addr));
+ }
+
+ /* compose header */
+ stun_init_message(&resp);
+ resp.stun_hdr.msg_type = BINDING_RESPONSE;
+ resp.stun_hdr.msg_len = 0; /* actual len computed later */
+
+ for (i = 0; i < STUN_TID_BYTES; i++) {
+ resp.stun_hdr.tran_id[i] = req->stun_hdr.tran_id[i];
+ }
+ p = &(resp.stun_attr);
+
+ /* MAPPED-ADDRESS */
+ tmp = m_attr;
+ tmp->attr_type = MAPPED_ADDRESS;
+ memcpy(mod_addr, from_addr, sizeof(*mod_addr));
+ tmp->pattr = mod_addr;
+ tmp->next = NULL;
+ *p = tmp; p = &(tmp->next);
+
+ /* SOURCE-ADDRESS depends on CHANGE_REQUEST */
+ tmp = stun_get_attr(req->stun_attr, CHANGE_REQUEST);
+ if (!tmp) {
+ c = 0;
+ }
+ else {
+ switch (((stun_attr_changerequest_t *) tmp->pattr)->value) {
+ case STUN_CR_CHANGE_IP:
+ c = 1;
+ break;
+
+ case STUN_CR_CHANGE_PORT:
+ c = 2;
+ break;
+
+ case STUN_CR_CHANGE_IP | STUN_CR_CHANGE_PORT: /* bitwise or */
+ c = 3;
+ break;
+
+ default:
+ return -1;
+ }
+ }
+
+ tmp = s_attr;
+ tmp->attr_type = SOURCE_ADDRESS;
+
+ /* memcpy(src_addr, &stun_change_map[c][sid], sizeof(*src_addr)); */
+ tmp->pattr = src_addr;
+ tmp->next = NULL;
+ *p = tmp; p = &(tmp->next);
+
+ /* CHANGED-ADDRESS */ /* depends on sid */
+ tmp = c_attr;
+ tmp->attr_type = CHANGED_ADDRESS;
+ /* memcpy(chg_addr, &stun_change_map[3][sid], sizeof(*chg_addr)); */
+ tmp->pattr = chg_addr;
+ tmp->next = NULL;
+ *p = tmp; p = &(tmp->next);
+
+
+ /* no buffer assigned yet */
+ resp.enc_buf.data = NULL;
+ resp.enc_buf.size = 0;
+
+ stun_send_message(s, &to_addr, &resp, NULL);
+ return 0;
+}
+
+/**
+ * Returns socket attached to the discovery object
+ */
+su_socket_t stun_discovery_get_socket(stun_discovery_t *sd)
+{
+ assert(sd);
+ return sd->sd_socket;
+}
+
+/* -------------------------------------------------------------------
+ * DEPRECATED functions
+ * -------------------------------------------------------------------
+ */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stun.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stun.docs Thu Dec 21 01:30:28 2006
@@ -0,0 +1,29 @@
+/**@MODULEPAGE "stun" - STUN Client and Server Module
+
+ at section stun_meta Module Meta Information
+
+The Sofia @b stun module contains macros and functions for STUN server and
+client library.
+
+ at CONTACT Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ at STATUS @SofiaSIP Core library
+
+ at LICENSE LGPL
+
+ at section stun_contents Contents of stun Module
+
+The stun module contains the public header files as follows:
+- <stun.h> the public API of the module
+- <stun_common.h> low-level functions for parsing and encoding STUN messages
+- <stun_tag.h> defines the su tags used by stun
+
+ at section stun_usage Using Sofia STUN Library
+
+To be written. See torture_stun.c and tport/tport.c.
+
+ at section todo Todo
+
+- none at the moment
+
+*/
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stun_common.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stun_common.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,826 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**
+ * @file stun_common.c
+ * @brief
+ *
+ * @author Tat Chan <Tat.Chan at nokia.com>
+ * @author Kai Vehmanen <kai.vehmanen at nokia.com>
+ *
+ * @date Created: Fri Oct 3 13:40:41 2003 ppessi
+ *
+ */
+
+#include "config.h"
+
+#ifdef USE_TURN
+#include "../turn/turn_common.h"
+#undef STUN_A_LAST_MANDATORY
+#define STUN_A_LAST_MANDATORY TURN_LARGEST_ATTRIBUTE
+#endif
+
+#include "stun_internal.h"
+
+#include <assert.h>
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+#define __func__ "stun_common"
+#endif
+
+const char stun_400_Bad_request[] = "Bad Request",
+ stun_401_Unauthorized[] = "Unauthorized",
+ stun_420_Unknown_attribute[] = "Unknown Attribute",
+ stun_430_Stale_credentials[] = "Stale Credentials",
+ stun_431_Integrity_check_failure[] = "Integrity Check Failure",
+ stun_432_Missing_username[] = "Missing Username",
+ stun_433_Use_tls[] = "Use TLS",
+#ifdef USE_TURN
+ turn_434_Missing_realm[] = "Missing Realm",
+ turn_435_Missing_nonce[] = "Missing Nonce",
+ turn_436_Unknown_username[] = "Unknown Username",
+ turn_437_No_binding[] = "No Binding",
+ turn_439_Illegal_port[] = "Illegal Port",
+#endif
+ stun_500_Server_error[] = "Server Error",
+ stun_600_Global_failure[] = "Global Failure";
+
+#define set16(b, offset, value) \
+ (((b)[(offset) + 0] = ((value) >> 8) & 255), \
+ ((b)[(offset) + 1] = (value) & 255))
+
+#define get16(b, offset) \
+ (((b)[(offset) + 0] << 8) | \
+ ((b)[(offset) + 1] << 0))
+
+int stun_parse_message(stun_msg_t *msg)
+{
+ unsigned len;
+ int i;
+ unsigned char *p;
+
+ /* parse header first */
+ p = msg->enc_buf.data;
+ msg->stun_hdr.msg_type = get16(p, 0);
+ msg->stun_hdr.msg_len = get16(p, 2);
+ memcpy(msg->stun_hdr.tran_id, p + 4, STUN_TID_BYTES);
+
+ SU_DEBUG_5(("%s: Parse STUN message: Length = %d\n", __func__,
+ msg->stun_hdr.msg_len));
+
+ /* parse attributes */
+ len = msg->stun_hdr.msg_len;
+ p = msg->enc_buf.data + 20;
+ msg->stun_attr = NULL;
+ while (len > 0) {
+ i = stun_parse_attribute(msg, p);
+ if (i <= 0) {
+ SU_DEBUG_3(("%s: Error parsing attribute.\n", __func__));
+ return -1;
+ }
+ p += i;
+ len -= i;
+ }
+
+ return 0;
+}
+
+int stun_parse_attribute(stun_msg_t *msg, unsigned char *p)
+{
+ int len;
+ uint16_t attr_type;
+ stun_attr_t *attr, *next;
+
+ attr_type = get16(p, 0);
+ len = get16(p, 2);
+
+ SU_DEBUG_5(("%s: received attribute: Type %02X, Length %d - %s\n",
+ __func__, attr_type, len, stun_attr_phrase(attr_type)));
+
+ if (attr_type > STUN_A_LAST_MANDATORY && attr_type < STUN_A_OPTIONAL) {
+ return -1;
+ }
+
+ attr = (stun_attr_t *)calloc(1, sizeof(stun_attr_t));
+ if (!attr)
+ return -1;
+ attr->next = NULL;
+ attr->attr_type = attr_type;
+ p += 4;
+
+ switch (attr->attr_type) {
+ case MAPPED_ADDRESS:
+ case RESPONSE_ADDRESS:
+ case SOURCE_ADDRESS:
+ case CHANGED_ADDRESS:
+ case REFLECTED_FROM:
+#ifdef USE_TURN
+ case TURN_ALTERNATE_SERVER:
+ case TURN_DESTINATION_ADDRESS:
+ case TURN_SOURCE_ADDRESS:
+#endif
+ if (stun_parse_attr_address(attr, p, len) < 0) {
+ free(attr);
+ return -1;
+ }
+ break;
+ case ERROR_CODE:
+ if (stun_parse_attr_error_code(attr, p, len) <0) { free(attr); return -1; }
+ break;
+ case UNKNOWN_ATTRIBUTES:
+ if(stun_parse_attr_unknown_attributes(attr, p, len) <0) { free(attr); return -1; }
+ break;
+ case CHANGE_REQUEST:
+#ifdef USE_TURN
+ case TURN_LIFETIME:
+ case TURN_MAGIC_COOKIE:
+ case TURN_BANDWIDTH:
+#endif
+ if (stun_parse_attr_uint32(attr, p, len) <0) { free(attr); return -1; }
+ break;
+ case USERNAME:
+ case PASSWORD:
+ case STUN_A_REALM:
+ case STUN_A_NONCE:
+#ifdef USE_TURN
+ case TURN_DATA:
+ case TURN_NONCE:
+#endif
+ if (stun_parse_attr_buffer(attr, p, len) <0) { free(attr); return -1; }
+ break;
+ default:
+ /* just copy as is */
+ attr->pattr = NULL;
+ attr->enc_buf.size = len;
+ attr->enc_buf.data = (unsigned char *) malloc(len);
+ memcpy(attr->enc_buf.data, p, len);
+ break;
+ }
+
+ /* skip to end of list */
+ if(msg->stun_attr==NULL) {
+ msg->stun_attr = attr;
+ }
+ else {
+ next = msg->stun_attr;
+ while(next->next!=NULL) {
+ next = next->next;
+ }
+ next->next = attr;
+ }
+ return len+4;
+}
+
+int stun_parse_attr_address(stun_attr_t *attr,
+ const unsigned char *p,
+ unsigned len)
+{
+ su_sockaddr_t *addr;
+ int addrlen;
+ char ipaddr[SU_ADDRSIZE + 2];
+
+ if (len != 8) {
+ return -1;
+ }
+
+ addrlen = sizeof(su_sockaddr_t);
+ addr = (su_sockaddr_t *) malloc(addrlen);
+
+ if (*(p+1) == 1) { /* expected value for IPv4 */
+ addr->su_sin.sin_family = AF_INET;
+ }
+ else {
+ free(addr);
+ return -1;
+ }
+ memcpy(&addr->su_sin.sin_port, p + 2, 2);
+ memcpy(&addr->su_sin.sin_addr.s_addr, p + 4, 4);
+
+ SU_DEBUG_5(("%s: address attribute: %s:%d\n", __func__,
+ inet_ntop(addr->su_family, SU_ADDR(addr), ipaddr, sizeof(ipaddr)),
+ (unsigned) ntohs(addr->su_sin.sin_port)));
+
+ attr->pattr = addr;
+ stun_init_buffer(&attr->enc_buf);
+
+ return 0;
+}
+
+int stun_parse_attr_error_code(stun_attr_t *attr, const unsigned char *p, unsigned len) {
+
+ uint32_t tmp;
+ stun_attr_errorcode_t *error;
+
+ memcpy(&tmp, p, sizeof(uint32_t));
+ tmp = ntohl(tmp);
+ error = (stun_attr_errorcode_t *) malloc(sizeof(*error));
+
+ error->code = (tmp & STUN_EC_CLASS)*100 + (tmp & STUN_EC_NUM);
+
+ error->phrase = (char *) malloc(len-3);
+
+ strncpy(error->phrase, (char*)p+4, len-4);
+ error->phrase[len - 4] = '\0';
+
+ attr->pattr = error;
+ stun_init_buffer(&attr->enc_buf);
+
+ return 0;
+}
+
+int stun_parse_attr_uint32(stun_attr_t *attr, const unsigned char *p, unsigned len)
+{
+ uint32_t tmp;
+ stun_attr_changerequest_t *cr;
+ cr = (stun_attr_changerequest_t *) malloc(sizeof(*cr));
+ memcpy(&tmp, p, sizeof(uint32_t));
+ cr->value = ntohl(tmp);
+ attr->pattr = cr;
+ stun_init_buffer(&attr->enc_buf);
+
+ return 0;
+}
+
+int stun_parse_attr_buffer(stun_attr_t *attr, const unsigned char *p, unsigned len)
+{
+ stun_buffer_t *buf;
+ buf = (stun_buffer_t *) malloc(sizeof(stun_buffer_t));
+ buf->size = len;
+ buf->data = (unsigned char *) malloc(len);
+ memcpy(buf->data, p, len);
+ attr->pattr = buf;
+ stun_init_buffer(&attr->enc_buf);
+
+ return 0;
+}
+
+int stun_parse_attr_unknown_attributes(stun_attr_t *attr,
+ const unsigned char *p,
+ unsigned len)
+{
+ return 0;
+}
+
+/** scan thru attribute list and return the next requested attr */
+stun_attr_t *stun_get_attr(stun_attr_t *attr, uint16_t attr_type) {
+ stun_attr_t *p;
+
+ for (p = attr; p != NULL; p = p->next) {
+ if (p->attr_type == attr_type)
+ break;
+ }
+
+ return p;
+}
+
+void stun_init_buffer(stun_buffer_t *p) {
+ p->data = NULL;
+ p->size = 0;
+}
+
+int stun_free_buffer(stun_buffer_t *p) {
+ if (p->data)
+ free(p->data), p->data = NULL;
+ p->size = 0;
+ return 0;
+}
+
+int stun_copy_buffer(stun_buffer_t *p, stun_buffer_t *p2) {
+ stun_free_buffer(p); /* clean up existing data */
+ p->size = p2->size;
+ p->data = (unsigned char *) malloc(p->size);
+ memcpy(p->data, p2->data, p->size);
+ return p->size;
+}
+
+const char *stun_response_phrase(int status) {
+ if (status <100 || status >600)
+ return NULL;
+
+ switch (status) {
+ case STUN_400_BAD_REQUEST: return stun_400_Bad_request;
+ case STUN_401_UNAUTHORIZED: return stun_401_Unauthorized;
+ case STUN_420_UNKNOWN_ATTRIBUTE: return stun_420_Unknown_attribute;
+ case STUN_430_STALE_CREDENTIALS: return stun_430_Stale_credentials;
+ case STUN_431_INTEGRITY_CHECK_FAILURE: return stun_431_Integrity_check_failure;
+ case STUN_432_MISSING_USERNAME: return stun_432_Missing_username;
+ case STUN_433_USE_TLS: return stun_433_Use_tls;
+#ifdef USE_TURN
+ case TURN_MISSING_REALM: return turn_434_Missing_realm;
+ case TURN_MISSING_NONCE: return turn_435_Missing_nonce;
+ case TURN_UNKNOWN_USERNAME: return turn_436_Unknown_username;
+ case TURN_NO_BINDING: return turn_437_No_binding;
+ case TURN_ILLEGAL_PORT: return turn_439_Illegal_port;
+#endif
+ case STUN_500_SERVER_ERROR: return stun_500_Server_error;
+ case STUN_600_GLOBAL_FAILURE: return stun_600_Global_failure;
+ }
+ return "Response";
+}
+
+/** The set of functions encodes the corresponding attribute to
+ * network format, and save the result to the enc_buf. Return the
+ * size of the buffer.
+ */
+
+
+/* This function is used to encode any attribute of the form ADDRESS
+ */
+int stun_encode_address(stun_attr_t *attr) {
+ stun_attr_sockaddr_t *a;
+ uint16_t tmp;
+
+ a = (stun_attr_sockaddr_t *)attr->pattr;
+
+ if (stun_encode_type_len(attr, 8) < 0) {
+ return -1;
+ }
+
+ tmp = htons(0x01); /* FAMILY = 0x01 */
+ memcpy(attr->enc_buf.data+4, &tmp, sizeof(tmp));
+ memcpy(attr->enc_buf.data+6, &a->sin_port, 2);
+ memcpy(attr->enc_buf.data+8, &a->sin_addr.s_addr, 4);
+
+ return attr->enc_buf.size;
+}
+
+int stun_encode_uint32(stun_attr_t *attr) {
+ uint32_t tmp;
+
+ if (stun_encode_type_len(attr, 4) < 0) {
+ return -1;
+ }
+
+ tmp = htonl(((stun_attr_changerequest_t *) attr->pattr)->value);
+ memcpy(attr->enc_buf.data+4, &tmp, 4);
+ return attr->enc_buf.size;
+}
+
+int stun_encode_error_code(stun_attr_t *attr) {
+ short int class, num;
+ size_t phrase_len, padded;
+ stun_attr_errorcode_t *error;
+
+ error = (stun_attr_errorcode_t *) attr->pattr;
+ class = error->code / 100;
+ num = error->code % 100;
+
+ phrase_len = strlen(error->phrase);
+ if (phrase_len + 8 > 65536)
+ phrase_len = 65536 - 8;
+
+ /* note: align the phrase len (see RFC3489:11.2.9) */
+ padded = phrase_len + (phrase_len % 4 == 0 ? 0 : 4 - (phrase_len % 4));
+
+ /* note: error-code has four octets of headers plus the
+ * reason field -> len+4 octets */
+ if (stun_encode_type_len(attr, (uint16_t)(padded + 4)) < 0) {
+ return -1;
+ }
+ else {
+ assert(attr->enc_buf.size == padded + 8);
+ memset(attr->enc_buf.data+4, 0, 2);
+ attr->enc_buf.data[6] = class;
+ attr->enc_buf.data[7] = num;
+ /* note: 4 octets of TLV header and 4 octets of error-code header */
+ memcpy(attr->enc_buf.data+8, error->phrase,
+ phrase_len);
+ memset(attr->enc_buf.data + 8 + phrase_len, 0, padded - phrase_len);
+ }
+
+ return attr->enc_buf.size;
+}
+
+int stun_encode_buffer(stun_attr_t *attr) {
+ stun_buffer_t *a;
+
+ a = (stun_buffer_t *)attr->pattr;
+ assert(a->size < 65536);
+ if (stun_encode_type_len(attr, (uint16_t)a->size) < 0) {
+ return -1;
+ }
+
+ memcpy(attr->enc_buf.data+4, a->data, a->size);
+ return attr->enc_buf.size;
+}
+
+#if defined(HAVE_OPENSSL)
+int stun_encode_message_integrity(stun_attr_t *attr,
+ unsigned char *buf,
+ int len,
+ stun_buffer_t *pwd) {
+ int padded_len;
+ unsigned int dig_len;
+ unsigned char *padded_text = NULL;
+ void *sha1_hmac;
+
+ if (stun_encode_type_len(attr, 20) < 0) {
+ return -1;
+ }
+
+ /* zero padding */
+ if (len % 64 != 0) {
+
+ padded_len = len + (64 - (len % 64));
+ padded_text = (unsigned char *) malloc(padded_len);
+ memcpy(padded_text, buf, len);
+ memset(padded_text + len, 0, padded_len - len);
+
+ sha1_hmac = HMAC(EVP_sha1(), pwd->data, pwd->size, padded_text, padded_len, NULL, &dig_len);
+ }
+ else {
+ sha1_hmac = HMAC(EVP_sha1(), pwd->data, pwd->size, buf, len, NULL, &dig_len);
+ }
+
+ assert(dig_len == 20);
+
+ memcpy(attr->enc_buf.data + 4, sha1_hmac, 20);
+ free(padded_text);
+ return attr->enc_buf.size;
+}
+#else
+int stun_encode_message_integrity(stun_attr_t *attr,
+ unsigned char *buf,
+ int len,
+ stun_buffer_t *pwd) {
+
+ return 0;
+}
+#endif /* HAVE_OPENSSL */
+
+/** this function allocates the enc_buf, fills in type, length */
+int stun_encode_type_len(stun_attr_t *attr, uint16_t len) {
+ uint16_t tmp;
+
+ attr->enc_buf.data = (unsigned char *) malloc(len + 4);
+ memset(attr->enc_buf.data, 0, len + 4);
+
+ tmp = htons(attr->attr_type);
+ memcpy(attr->enc_buf.data, &tmp, 2);
+
+ tmp = htons(len);
+ memcpy(attr->enc_buf.data + 2, &tmp, 2);
+ attr->enc_buf.size = len + 4;
+
+ return 0;
+}
+
+/**
+ * Validate the message integrity based on given
+ * STUN password 'pwd'. The received content should be
+ * in msg->enc_buf.
+ */
+int stun_validate_message_integrity(stun_msg_t *msg, stun_buffer_t *pwd)
+{
+
+#if defined(HAVE_OPENSSL)
+ int padded_len, len;
+ unsigned int dig_len;
+ unsigned char dig[20]; /* received sha1 digest */
+ unsigned char *padded_text;
+#endif
+
+ /* password NULL so shared-secret not established and
+ messege integrity checks can be skipped */
+ if (pwd->data == NULL)
+ return 0;
+
+ /* otherwise the check must match */
+
+#if defined(HAVE_OPENSSL)
+
+ /* message integrity not received */
+ if (stun_get_attr(msg->stun_attr, MESSAGE_INTEGRITY) == NULL) {
+ SU_DEBUG_5(("%s: error: message integrity missing.\n", __func__));
+ return -1;
+ }
+
+ /* zero padding */
+ len = msg->enc_buf.size - 24;
+ padded_len = len + (len % 64 == 0 ? 0 : 64 - (len % 64));
+ padded_text = (unsigned char *) malloc(padded_len);
+ memset(padded_text, 0, padded_len);
+ memcpy(padded_text, msg->enc_buf.data, len);
+
+ memcpy(dig, HMAC(EVP_sha1(), pwd->data, pwd->size, padded_text, padded_len, NULL, &dig_len), 20);
+
+ if (memcmp(dig, msg->enc_buf.data + msg->enc_buf.size - 20, 20) != 0) {
+ /* does not match, but try the test server's password */
+ if (memcmp(msg->enc_buf.data+msg->enc_buf.size-20, "hmac-not-implemented", 20) != 0) {
+ SU_DEBUG_5(("%s: error: message digest problem.\n", __func__));
+ return -1;
+ }
+ }
+ else {
+ SU_DEBUG_5(("%s: message integrity validated.\n", __func__));
+ }
+
+ free(padded_text);
+
+ return 0;
+#else /* HAVE_OPENSSL */
+ return -1;
+#endif
+}
+
+void debug_print(stun_buffer_t *buf) {
+ unsigned i;
+ for(i = 0; i < buf->size/4; i++) {
+ SU_DEBUG_9(("%02x %02x %02x %02x\n",
+ *(buf->data + i*4),
+ *(buf->data + i*4 +1),
+ *(buf->data + i*4 +2),
+ *(buf->data + i*4 +3)));
+ if (i == 4)
+ SU_DEBUG_9(("---------------------\n"));
+ }
+ SU_DEBUG_9(("\n"));
+}
+
+int stun_init_message(stun_msg_t *msg) {
+ msg->stun_hdr.msg_type = 0;
+ msg->stun_hdr.msg_len = 0;
+ msg->stun_attr = NULL;
+ stun_init_buffer(&msg->enc_buf);
+ return 0;
+}
+
+int stun_free_message(stun_msg_t *msg) {
+
+ stun_attr_t *p, *p2;
+
+ /* clearing header */
+ memset(&msg->stun_hdr, 0, sizeof msg->stun_hdr);
+
+ /* clearing attr */
+ p = msg->stun_attr;
+ while(p) {
+ if(p->pattr) {
+ switch(p->attr_type) {
+ case USERNAME:
+ case PASSWORD:
+#ifdef USE_TURN
+ case TURN_DATA:
+ case TURN_NONCE:
+#endif
+ stun_free_buffer(p->pattr);
+ break;
+ default:
+ free(p->pattr);
+ }
+ }
+ stun_free_buffer(&p->enc_buf);
+ p2 = p->next;
+ free(p);
+ p = p2;
+ }
+ msg->stun_attr = NULL;
+
+ /* clearing buffer */
+ stun_free_buffer(&msg->enc_buf);
+
+ return 0;
+}
+
+
+int stun_send_message(su_socket_t s, su_sockaddr_t *to_addr,
+ stun_msg_t *msg, stun_buffer_t *pwd)
+{
+ int err;
+ char ipaddr[SU_ADDRSIZE + 2];
+ stun_attr_t **a, *b;
+
+ stun_encode_message(msg, pwd);
+
+ err = su_sendto(s, msg->enc_buf.data, msg->enc_buf.size, 0,
+ to_addr, SU_SOCKADDR_SIZE(to_addr));
+
+ free(msg->enc_buf.data), msg->enc_buf.data = NULL;
+ msg->enc_buf.size = 0;
+
+ for (a = &msg->stun_attr; *a;) {
+
+ if ((*a)->pattr)
+ free((*a)->pattr), (*a)->pattr = NULL;
+
+ if ((*a)->enc_buf.data)
+ free((*a)->enc_buf.data), (*a)->enc_buf.data = NULL;
+
+ b = *a;
+ b = b->next;
+ free(*a);
+ *a = NULL;
+ *a = b;
+ }
+
+ if (err > 0) {
+ inet_ntop(to_addr->su_family, SU_ADDR(to_addr), ipaddr, sizeof(ipaddr));
+ SU_DEBUG_5(("%s: message sent to %s:%u\n", __func__,
+ ipaddr, ntohs(to_addr->su_port)));
+
+ debug_print(&msg->enc_buf);
+ }
+ else
+ STUN_ERROR(errno, sendto);
+
+ return err;
+}
+
+
+/** Send a STUN message.
+ * This will convert the stun_msg_t to the binary format based on the
+ * spec
+ */
+int stun_encode_message(stun_msg_t *msg, stun_buffer_t *pwd) {
+
+ int z = -1, len, buf_len = 0;
+ unsigned char *buf;
+ stun_attr_t *attr, *msg_int=NULL;
+
+ if (msg->enc_buf.data == NULL) {
+ /* convert msg to binary format */
+ /* convert attributes to binary format for transmission */
+ len = 0;
+ for (attr = msg->stun_attr; attr ; attr = attr->next) {
+ switch(attr->attr_type) {
+ case RESPONSE_ADDRESS:
+ case MAPPED_ADDRESS:
+ case SOURCE_ADDRESS:
+ case CHANGED_ADDRESS:
+ case REFLECTED_FROM:
+#ifdef USE_TURN
+ case TURN_ALTERNATE_SERVER:
+ case TURN_DESTINATION_ADDRESS:
+ case TURN_SOURCE_ADDRESS:
+#endif
+ z = stun_encode_address(attr);
+ break;
+ case CHANGE_REQUEST:
+#ifdef USE_TURN
+ case TURN_LIFETIME:
+ case TURN_MAGIC_COOKIE:
+ case TURN_BANDWIDTH:
+#endif
+ z = stun_encode_uint32(attr);
+ break;
+
+ case USERNAME:
+ case PASSWORD:
+#ifdef USE_TURN
+ case TURN_REALM:
+ case TURN_NONCE:
+ case TURN_DATA:
+#endif
+ z = stun_encode_buffer(attr);
+ break;
+ case MESSAGE_INTEGRITY:
+ msg_int = attr;
+ z = 24;
+ break;
+ case ERROR_CODE:
+ z = stun_encode_error_code(attr);
+ default:
+ break;
+ }
+
+ if(z < 0) return z;
+
+ len += z;
+ }
+
+ msg->stun_hdr.msg_len = len;
+ buf_len = 20 + msg->stun_hdr.msg_len;
+ buf = (unsigned char *) malloc(buf_len);
+
+ /* convert to binary format for transmission */
+ set16(buf, 0, msg->stun_hdr.msg_type);
+ set16(buf, 2, msg->stun_hdr.msg_len);
+ memcpy(buf + 4, msg->stun_hdr.tran_id, STUN_TID_BYTES);
+
+ len = 20;
+
+ /* attaching encoded attributes */
+ attr = msg->stun_attr;
+ while(attr) {
+ /* attach only if enc_buf is not null */
+ if(attr->enc_buf.data && attr->attr_type != MESSAGE_INTEGRITY) {
+ memcpy(buf+len, (void *)attr->enc_buf.data, attr->enc_buf.size);
+ len += attr->enc_buf.size;
+ }
+ attr = attr->next;
+ }
+
+ if (msg_int) {
+ /* compute message integrity */
+ if(stun_encode_message_integrity(msg_int, buf, len, pwd)!=24) {
+ free(buf);
+ return -1;
+ }
+ memcpy(buf+len, (void *)msg_int->enc_buf.data,
+ msg_int->enc_buf.size);
+ }
+
+ /* save binary buffer for future reference */
+ if (msg->enc_buf.data)
+ free(msg->enc_buf.data);
+
+ msg->enc_buf.data = buf; msg->enc_buf.size = buf_len;
+ }
+
+ return 0;
+}
+
+#include <sofia-sip/su.h>
+#include <sofia-sip/su_debug.h>
+#include <sofia-sip/su_localinfo.h>
+
+char *stun_determine_ip_address(int family)
+{
+
+ char *local_ip_address;
+ su_localinfo_t *li = NULL, hints[1] = {{ LI_CANONNAME|LI_NUMERIC }};
+ int error;
+ size_t address_size;
+ struct sockaddr_in *sa = NULL;
+ su_sockaddr_t *temp;
+
+ hints->li_family = family;
+ hints->li_canonname = getenv("HOSTADDRESS");
+ if ((error = su_getlocalinfo(hints, &li)) < 0) {
+ SU_DEBUG_5(("%s: stun_determine_ip_address, su_getlocalinfo: %s\n",
+ __func__, su_gli_strerror(error)));
+ return NULL;
+ }
+
+ temp = li->li_addr;
+ sa = &temp->su_sin;
+
+ address_size = strlen(inet_ntoa(sa->sin_addr));
+
+ local_ip_address = malloc(address_size + 1);
+ strcpy(local_ip_address, (char *) inet_ntoa(sa->sin_addr)); /* otherwise? */
+
+ su_freelocalinfo(li);
+
+ return local_ip_address;
+
+}
+
+const char *stun_attr_phrase(uint16_t type)
+{
+ switch(type) {
+ case MAPPED_ADDRESS: return "MAPPED-ADDRESS";
+ case RESPONSE_ADDRESS: return "RESPONSE-ADDRESS";
+ case CHANGE_REQUEST: return "CHANGE-REQUEST";
+ case SOURCE_ADDRESS: return "SOURCE-ADDRESS";
+ case CHANGED_ADDRESS: return "CHANGED-ADDRESS";
+ case USERNAME: return "USERNAME";
+ case PASSWORD: return "PASSWORD";
+ case MESSAGE_INTEGRITY: return "MESSAGE-INTEGRITY";
+ case ERROR_CODE: return "ERROR-CODE";
+ case UNKNOWN_ATTRIBUTES: return "UNKNOWN-ATTRIBUTES";
+ case REFLECTED_FROM: return "REFLECTED-FROM";
+ case STUN_A_ALTERNATE_SERVER:
+ case STUN_A_ALTERNATE_SERVER_DEP:
+ return "ALTERNATE-SERVER";
+ case STUN_A_REALM: return "REALM";
+ case STUN_A_NONCE: return "NONCE";
+ case STUN_A_XOR_MAPPED_ADDRESS: return "XOR-MAPPED-ADDRESS";
+#ifdef USE_TURN
+ case TURN_REALM: return "REALM";
+ case TURN_LIFETIME: return "LIFETIME";
+ case TURN_ALTERNATE_SERVER: return "ALTERNATE_SERVER";
+ case TURN_MAGIC_COOKIE: return "MAGIC_COOKIE";
+ case TURN_BANDWIDTH: return "BANDWIDTH";
+ case TURN_DESTINATION_ADDRESS: return "DESTINATION_ADDRESS";
+ case TURN_SOURCE_ADDRESS: return "SOURCE_ADDRESS";
+ case TURN_DATA: return "DATA";
+ case TURN_NONCE: return "NONCE";
+#endif
+ default: return "Attribute undefined";
+ }
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stun_dns.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stun_dns.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,246 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**
+ * @file stun_dns.c
+ * @brief Functins to discover STUN server address using DNS-SRV.
+ *
+ * Refs:
+ * - RFC3489/3489bis
+ * - RFC2782
+ *
+ * @author Kai Vehmanen <kai.vehmanen at nokia.com>
+ */
+
+#include "config.h"
+
+#define STUN_SRV_SERVICE_TCP "_stun._tcp"
+#define STUN_SRV_SERVICE_UDP "_stun._udp"
+
+#include <sofia-sip/stun.h>
+#include <sofia-sip/su.h>
+#include <sofia-sip/su_alloc.h>
+#include <sofia-sip/su_wait.h>
+#define SRES_CONTEXT_T stun_dns_lookup_t
+#include <sofia-sip/sresolv.h>
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+static char const __func__[] = "stun_dns";
+#endif
+
+#include "stun_internal.h"
+
+struct stun_dns_lookup_s {
+ su_home_t stun_home[1];
+ su_root_t *stun_root;
+ stun_magic_t *stun_magic;
+ sres_resolver_t *stun_sres;
+ su_socket_t stun_socket;
+ stun_dns_lookup_f stun_cb;
+ char *stun_tcp_target;
+ char *stun_udp_target;
+ uint16_t stun_tcp_port;
+ uint16_t stun_udp_port;
+ unsigned stun_state:2; /**< bit0:udp, bit1:tcp */
+};
+
+enum stun_dns_state {
+ stun_dns_udp = 1,
+ stun_dns_tls = 2,
+ stun_dns_done = stun_dns_udp | stun_dns_tls
+};
+
+/**
+ * Internal callback used for gathering DNS replies.
+ */
+static void priv_sres_cb(stun_dns_lookup_t *self,
+ sres_query_t *q,
+ sres_record_t **answer)
+{
+ int i;
+
+ sres_sort_answers(self->stun_sres, answer);
+
+ /* note: picks the first ones (sort puts records with most
+ * weight at start */
+
+ for (i = 0; answer && answer[i] != NULL; i++) {
+ sres_srv_record_t *rr = (sres_srv_record_t *) answer[i]->sr_srv;
+ if (rr && rr->srv_record && rr->srv_record->r_type == sres_type_srv) {
+ const char *tcp_name = STUN_SRV_SERVICE_TCP;
+ const char *udp_name = STUN_SRV_SERVICE_UDP;
+ if ((self->stun_state & stun_dns_tls) == 0 &&
+ strncmp(rr->srv_record->r_name, tcp_name, strlen(tcp_name)) == 0) {
+ self->stun_tcp_target = su_strdup(self->stun_home, rr->srv_target);
+ self->stun_tcp_port = rr->srv_port;
+ self->stun_state |= stun_dns_tls;
+ SU_DEBUG_5(("%s: stun (tcp) for domain %s is at %s:%u.\n",
+ __func__, rr->srv_record->r_name, self->stun_tcp_target, self->stun_tcp_port));
+ }
+ else if ((self->stun_state & stun_dns_udp) == 0 &&
+ strncmp(rr->srv_record->r_name, udp_name, strlen(udp_name)) == 0) {
+ self->stun_udp_target = su_strdup(self->stun_home, rr->srv_target);
+ self->stun_udp_port = rr->srv_port;
+ self->stun_state |= stun_dns_udp;
+ SU_DEBUG_5(("%s: stun (udp) for domain %s is at %s:%u.\n",
+ __func__, rr->srv_record->r_name, self->stun_udp_target, self->stun_udp_port));
+ }
+ }
+ }
+
+ if (self->stun_state == stun_dns_done) {
+ self->stun_cb(self, self->stun_magic);
+
+ sres_resolver_timer(self->stun_sres, -1);
+ }
+
+ sres_free_answers(self->stun_sres, answer);
+}
+
+/**
+ * Performs a DNS-SRV check for STUN 'stun' (tcp) and
+ * 'stun' (udp) services for 'domain'.
+ *
+ * The result will be delivered asynchronously in the
+ * 'func' callback. 'root' will be used as the event loop.
+ */
+stun_dns_lookup_t *stun_dns_lookup(stun_magic_t *magic,
+ su_root_t *root,
+ stun_dns_lookup_f func,
+ const char *domain)
+{
+ stun_dns_lookup_t *self;
+ sres_query_t *query;
+
+ if (!domain ||
+ strlen(domain) + strlen(STUN_SRV_SERVICE_UDP ".") + 1>= SRES_MAXDNAME)
+ return NULL;
+
+ self = su_home_new(sizeof(stun_dns_lookup_t));
+
+ /* see nta.c:outgoing_answer_srv() */
+ self->stun_magic = magic;
+ self->stun_cb = func;
+ self->stun_root = root;
+ self->stun_sres = sres_resolver_create(root, NULL, TAG_END());
+ if (self->stun_sres) {
+ char srvname[SRES_MAXDNAME + 1];
+
+ snprintf(srvname, sizeof srvname, "%s.%s", STUN_SRV_SERVICE_UDP, domain);
+
+ query = sres_query(self->stun_sres, priv_sres_cb, self,
+ sres_type_srv,
+ srvname);
+
+ snprintf(srvname, sizeof srvname, "%s.%s", STUN_SRV_SERVICE_TCP, domain);
+
+ query = sres_query(self->stun_sres, priv_sres_cb, self,
+ sres_type_srv,
+ srvname);
+ }
+ else {
+ su_free(NULL, self), self = NULL;
+ }
+
+ return self;
+}
+
+/**
+ * Destroys the 'self' object created by stun_dns_lookup_destroy().
+ */
+void stun_dns_lookup_destroy(stun_dns_lookup_t *self)
+{
+ if (self->stun_sres)
+ sres_resolver_destroy(self->stun_sres);
+
+ su_home_unref(self->stun_home);
+}
+
+/**
+ * Fetches the results of a completed STUN DNS-SRV lookup
+ * for "_stun._udp" service (RFC3489/3489bis).
+ *
+ * @param self context pointer
+ * @param target location where to stored the 'target'
+ * SRV field for stun service
+ * @param port location where to store port number
+ *
+ * @return 0 on success, non-zero otherwise
+ */
+int stun_dns_lookup_udp_addr(stun_dns_lookup_t *self, const char **target, uint16_t *port)
+{
+ int result = -1;
+ if (self->stun_state == stun_dns_done) {
+ if (target) *target = self->stun_udp_target;
+ if (port) *port = self->stun_udp_port;
+ result = 0;
+ }
+
+ return result;
+}
+
+/**
+ * Fetches the results of a completed STUN DNS-SRV lookup
+ * for "_stun._tcp" service (RFC3489).
+ *
+ * @param self context pointer
+ * @param target location where to stored the 'target'
+ * SRV field for stun service
+ * @param port location where to store port number
+ *
+ * @return 0 on success, non-zero otherwise
+ */
+int stun_dns_lookup_tcp_addr(stun_dns_lookup_t *self, const char **target, uint16_t *port)
+{
+ int result = -1;
+ if (self->stun_state == stun_dns_done) {
+ if (target) *target = self->stun_tcp_target;
+ if (port) *port = self->stun_tcp_port;
+ result = 0;
+ }
+
+ return result;
+}
+
+/**
+ * Fetches the results of a completed STUN DNS-SRV lookup
+ * for "_stun._udp" service (3489bis, "Short-Term Password").
+ *
+ * @param self context pointer
+ * @param target location where to stored the 'target'
+ * SRV field for stun service
+ * @param port location where to store port number
+ *
+ * @return 0 on success, non-zero otherwise
+ */
+int stun_dns_lookup_stp_addr(stun_dns_lookup_t *self, const char **target, uint16_t *port)
+{
+ /* XXX: not implemented */
+ return -1;
+}
+
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stun_internal.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stun_internal.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,112 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef STUN_INTERNAL_H
+/** Defined when <stun_internal.h> has been included. */
+#define STUN_INTERNAL_H
+/**@file stun_internal.h STUN client interface
+ *
+ * @author Martti Mela <martti.mela at nokia.com>
+ * @author Tat Chan <Tat.Chan at nokia.com>
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Kai Vehmanen <kai.vehmanen at nokia.com>
+ */
+
+#ifndef SU_DEBUG
+#define SU_DEBUG 0
+#endif
+
+#ifndef SU_WAIT_H
+#include <sofia-sip/su_wait.h>
+#endif
+
+#ifndef SU_TAG_H
+#include <sofia-sip/su_tag.h>
+#endif
+
+#ifndef STUN_H
+#include "sofia-sip/stun.h"
+#endif
+
+#if defined(HAVE_OPENSSL)
+/* avoid krb5-related build failures */
+#define OPENSSL_NO_KRB5
+#include <openssl/sha.h>
+#include <openssl/hmac.h>
+#include <openssl/ssl.h>
+#include <openssl/x509.h>
+#endif
+
+#ifndef STUN_COMMON_H
+#include "sofia-sip/stun_common.h"
+#endif
+
+
+
+#define SU_LOG (stun_log)
+#include <sofia-sip/su_debug.h>
+
+#define enter (void)SU_DEBUG_9(("%s: entering.\n", __func__))
+
+SOFIA_BEGIN_DECLS
+
+extern char const STUN_DEBUG[]; /* dummy declaration for Doxygen */
+
+/* XXX -- mela: note that this are 100 times too small */
+#if 1
+#define STUN_LIFETIME_EST 3500 /**< 6 min? */
+#define STUN_LIFETIME_MAX 18000 /**< 30 min? */
+#define STUN_LIFETIME_CI 50 /**< 5 sec confidence interval */
+#else
+#define STUN_LIFETIME_EST 350 /**< 6 min? */
+#define STUN_LIFETIME_MAX 1800 /**< 30 min? */
+#define STUN_LIFETIME_CI 5 /**< 5 sec confidence interval */
+#endif
+
+#define STUN_ERROR(err, what) \
+ SU_DEBUG_5(("%s: %s: %s\n", __func__, #what, su_strerror(err))), \
+ -1 \
+
+int stun_is_requested(tag_type_t tag, tag_value_t value, ...);
+
+/* internal functions declaration */
+int stun_make_sharedsecret_req(stun_msg_t *msg);
+
+int stun_send_message(su_socket_t s, su_sockaddr_t *srvr,
+ stun_msg_t *msg, stun_buffer_t *pwd);
+
+int stun_make_binding_req(stun_handle_t *se, stun_request_t *req,
+ stun_msg_t *msg,
+ tag_type_t, tag_value_t, ...);
+int stun_process_response(stun_msg_t *msg);
+
+int stun_process_binding_response(stun_msg_t *msg);
+int stun_process_error_response(stun_msg_t *msg);
+
+int stun_atoaddr(su_home_t *home, int ai_family, su_addrinfo_t *info, char const *in);
+int stun_add_response_address(stun_msg_t *req, struct sockaddr_in *mapped_addr);
+
+SOFIA_END_DECLS
+
+#endif /* !defined(STUN_INTERNAL_H) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stun_mini.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stun_mini.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,388 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**
+ * @file stun_mini.c
+ * @brief Minimal stun server
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Tat Chan <Tat.Chan at nokia.com>
+ * @author Kai Vehmanen <kai.vehmanen at nokia.com>
+ *
+ * @date Created: Fri Oct 3 13:40:41 2003 ppessi
+ *
+ */
+
+#include "config.h"
+
+#include "stun_internal.h"
+
+#include <assert.h>
+
+typedef struct stun_bound_s stun_bound_t;
+
+struct stun_bound_s
+{
+ stun_bound_t *ss_next;
+ su_socket_t ss_socket;
+ int ss_scope; /* LI_SCOPE */
+ socklen_t ss_addrlen;
+ union {
+ struct sockaddr_in sin[1];
+ struct sockaddr_storage storage[1];
+ char array[sizeof (struct sockaddr_storage)];
+ } ss_addr;
+};
+
+struct stun_mini_s
+{
+ stun_bound_t *sockets;
+};
+
+static int process_3489_request(stun_mini_t *mini,
+ stun_msg_t *request, stun_msg_t *response,
+ su_socket_t socket, void *, socklen_t);
+
+static int process_bis_request(stun_mini_t *mini,
+ stun_msg_t *request, stun_msg_t *response,
+ su_socket_t socket, void *, socklen_t);
+
+int send_stun_error(stun_msg_t *response,
+ int error,
+ int socket,
+ void *transaction_id,
+ void *from,
+ socklen_t fromlen);
+
+/** Create a stun miniserver */
+stun_mini_t *stun_mini_create(void)
+{
+ return calloc(1, sizeof (stun_mini_t));
+}
+
+/** Destroy a stun miniserver */
+void stun_mini_destroy(stun_mini_t *mini)
+{
+ if (mini) {
+ stun_bound_t *ss, **next;
+ for (next = &mini->sockets; *next; ) {
+ ss = *next;
+ *next = ss->ss_next;
+ free(ss);
+ }
+ free(mini);
+ }
+}
+
+/** Add a socket to stun miniserver. */
+int stun_mini_add_socket(stun_mini_t *mini, su_socket_t socket)
+{
+ stun_bound_t *ss, **next;
+ struct sockaddr_storage addr[1];
+ socklen_t addrlen = sizeof addr;
+
+ if (mini == NULL)
+ return su_seterrno(EFAULT);
+
+ for (next = &mini->sockets; *next; next = &(*next)->ss_next)
+ if (socket == (*next)->ss_socket)
+ return su_seterrno(EEXIST);
+
+ if (getsockname(socket, (void *)addr, &addrlen) < 0)
+ return -1;
+
+ if (addr->ss_family != AF_INET)
+ return su_seterrno(EAFNOSUPPORT);
+
+ ss = calloc(1, offsetof(stun_bound_t, ss_addr.array[addrlen]));
+
+ ss->ss_socket = socket;
+ ss->ss_scope = su_sockaddr_scope((void *)addr, addrlen);
+
+ memcpy(ss->ss_addr.array, addr, ss->ss_addrlen = addrlen);
+
+ *next = ss;
+
+ return 0;
+}
+
+/** Remove socket from stun miniserver */
+int stun_mini_remove_socket(stun_mini_t *mini, su_socket_t socket)
+{
+ stun_bound_t *ss, **next;
+
+ if (mini == NULL)
+ return errno = EFAULT, -1;
+
+ for (next = &mini->sockets; *next; next = &(*next)->ss_next)
+ if (socket == (*next)->ss_socket) {
+ ss = *next;
+ *next = ss->ss_next;
+ free(ss);
+ return 0;
+ }
+
+ return errno = ENOENT, -1;
+}
+
+void stun_mini_request(stun_mini_t *mini,
+ su_socket_t socket,
+ void *msg, ssize_t msglen,
+ void *from, socklen_t fromlen)
+{
+ int error;
+ struct {
+ stun_msg_t in[1];
+ stun_msg_t out[1];
+ stun_msg_t error[1];
+ } m;
+ char const *verdict = NULL;
+ uint8_t *data = msg;
+ char buffer[80];
+ uint8_t const magic_cookie[4] = { 0x21, 0x12, 0xA4, 0x42 };
+
+ memset(&m, 0, sizeof m);
+
+ if (mini == NULL || msg == NULL || from == NULL)
+ return;
+
+ if (msglen < 20)
+ verdict = "runt";
+ else if (data[0] == 1)
+ verdict = "response";
+ else if (data[0] != 0)
+ verdict = "garbage";
+ else if (data[1] == 2)
+ verdict = "shared secret request";
+ else if (data[1] != 1)
+ verdict = "garbage";
+
+ {
+ struct sockaddr_in const *sin = from;
+
+ if (sin->sin_family == AF_INET)
+ inet_ntop(sin->sin_family, &sin->sin_addr, buffer, sizeof buffer);
+ else
+ sprintf(buffer, "<af=%u>", (unsigned)sin->sin_family);
+
+ fprintf(stderr, "stun %s from %s:%u\n",
+ verdict ? verdict : "request", buffer, ntohs(sin->sin_port));
+
+ if (verdict)
+ return;
+ }
+
+ m.in->enc_buf.data = msg;
+ m.in->enc_buf.size = msglen;
+
+ if (memcmp(data + 4, magic_cookie, sizeof magic_cookie) == 0)
+ error = process_3489_request(mini, m.in, m.out, socket, from, fromlen);
+ else
+ error = process_bis_request(mini, m.in, m.out, socket, from, fromlen);
+
+ if (error)
+ send_stun_error(m.error, error, socket, data + 4, from, fromlen);
+
+ m.in->enc_buf.data = NULL;
+
+ stun_free_message(m.in);
+ stun_free_message(m.out);
+ stun_free_message(m.error);
+}
+
+static
+int process_3489_request(stun_mini_t *mini,
+ stun_msg_t *request,
+ stun_msg_t *response,
+ su_socket_t socket,
+ void *from,
+ socklen_t fromlen)
+{
+ stun_bound_t *ss, *changed = NULL, ss0[1];
+ stun_attr_t *a, **next;
+ stun_attr_sockaddr_t *addr;
+ int change_address = 0;
+
+ if (stun_parse_message(request) < 0) {
+ fprintf(stderr, "stun: error parsing request\n");
+ return STUN_400_BAD_REQUEST;
+ }
+
+ if (request->stun_hdr.msg_type != BINDING_REQUEST) {
+ fprintf(stderr, "stun: not binding request\n");
+ return 0;
+ }
+
+ a = stun_get_attr(request->stun_attr, RESPONSE_ADDRESS);
+ if (a)
+ return STUN_600_GLOBAL_FAILURE;
+
+ /* compose header */
+ response->stun_hdr.msg_type = BINDING_RESPONSE;
+ memcpy(response->stun_hdr.tran_id, request->stun_hdr.tran_id,
+ sizeof response->stun_hdr.tran_id);
+
+ next = &response->stun_attr;
+
+ /* MAPPED-ADDRESS */
+ a = malloc(sizeof *a); if (!a) return STUN_500_SERVER_ERROR;
+ a->attr_type = MAPPED_ADDRESS;
+ addr = malloc(sizeof *addr); if (!addr) return STUN_500_SERVER_ERROR;
+ memcpy(addr, from, sizeof *addr);
+ a->pattr = addr;
+ a->next = NULL;
+ *next = a; next = &a->next;
+
+ /* SOURCE-ADDRESS */ /* depends on CHANGE_REQUEST */
+ a = stun_get_attr(request->stun_attr, CHANGE_REQUEST);
+ if (a)
+ change_address = ((stun_attr_changerequest_t *)a->pattr)->value;
+
+ if (change_address) {
+ struct sockaddr_in const *sin, *sin2;
+ int scope = su_sockaddr_scope(from, fromlen);
+ stun_bound_t *changed_ip = NULL, *same_scope = NULL;
+
+ sin = from;
+
+ for (changed = mini->sockets; changed; changed = changed->ss_next) {
+ sin2 = changed->ss_addr.sin;
+
+ if (scope != LI_SCOPE_HOST && changed->ss_scope == LI_SCOPE_HOST)
+ continue;
+
+ if (scope != LI_SCOPE_SITE && changed->ss_scope == LI_SCOPE_SITE)
+ continue;
+
+ if (same_scope == NULL)
+ same_scope = changed;
+
+ if (change_address & STUN_CR_CHANGE_IP)
+ if (!memcmp(&sin->sin_addr, &sin2->sin_addr, sizeof sin->sin_addr))
+ continue;
+
+ if (changed_ip == NULL)
+ changed_ip = changed;
+
+ if (change_address & STUN_CR_CHANGE_PORT)
+ if (sin->sin_port == sin2->sin_port)
+ continue;
+ }
+
+ if (changed == NULL && (change_address & STUN_CR_CHANGE_IP))
+ /* We don't have socekt with both changed port and ip */
+ changed = changed_ip;
+
+ if (changed == NULL)
+ changed = same_scope;
+ }
+
+ for (ss = mini->sockets; ss; ss = ss->ss_next)
+ if (socket == ss->ss_socket)
+ break;
+
+ if (ss == NULL) {
+ memset(ss = ss0, 0, sizeof ss0);
+ ss->ss_socket = socket;
+ ss->ss_addrlen = sizeof ss->ss_addr;
+ if (getsockname(socket, (void *)ss->ss_addr.array, &ss->ss_addrlen) < 0)
+ return STUN_500_SERVER_ERROR;
+ }
+
+ a = malloc(sizeof *a); if (!a) return STUN_500_SERVER_ERROR;
+ a->attr_type = SOURCE_ADDRESS;
+ addr = malloc(sizeof *addr); if (!addr) return STUN_500_SERVER_ERROR;
+ memcpy(addr, ss->ss_addr.array, sizeof *addr);
+ a->pattr = addr;
+ a->next = NULL;
+ *next = a; next = &(a->next);
+
+ if (changed) {
+ socket = changed->ss_socket;
+
+ /* CHANGED-ADDRESS */
+ a = malloc(sizeof *a); if (!a) return STUN_500_SERVER_ERROR;
+ a->attr_type = CHANGED_ADDRESS;
+ addr = malloc(sizeof *addr); if (!addr) return STUN_500_SERVER_ERROR;
+ memcpy(addr, changed->ss_addr.array, sizeof *addr);
+
+ a->pattr = addr;
+ a->next = NULL;
+ *next = a; next = &(a->next);
+ }
+
+ stun_send_message(socket, (void *)from, response, NULL);
+
+ return 0;
+}
+
+static int process_bis_request(stun_mini_t *mini,
+ stun_msg_t *request, stun_msg_t *response,
+ su_socket_t socket,
+ void *from, socklen_t fromlen)
+{
+ return process_3489_request(mini, request, response, socket, from, fromlen);
+}
+
+int send_stun_error(stun_msg_t *response,
+ int error,
+ int socket,
+ void *transaction_id,
+ void *from,
+ socklen_t fromlen)
+{
+ stun_attr_t *attr;
+ stun_attr_errorcode_t *errorcode;
+ char const *phrase = stun_response_phrase(error);
+
+ if (!phrase)
+ error = STUN_500_SERVER_ERROR, phrase = "Internal Server Error";
+
+ stun_init_message(response);
+
+ response->stun_hdr.msg_type = BINDING_ERROR_RESPONSE;
+ response->stun_hdr.msg_len = 0; /* actual len computed later */
+
+ memcpy(response->stun_hdr.tran_id, transaction_id, 16);
+
+ /* ERROR-CODE */
+ attr = malloc(sizeof *attr); if (!attr) return -1;
+ response->stun_attr = attr;
+ attr->attr_type = ERROR_CODE;
+
+ errorcode = malloc(sizeof(*errorcode));
+ if (!errorcode)
+ return -1;
+ errorcode->code = error;
+ errorcode->phrase = malloc(strlen(phrase) + 1);
+ if (!errorcode->phrase)
+ return -1;
+ strcpy(errorcode->phrase, phrase);
+ attr->pattr = errorcode;
+
+ stun_send_message(socket, from, response, NULL);
+
+ return 0;
+}
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stun_tag.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stun_tag.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,212 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005-2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE stun_tag.c Tags and tag lists for Offer/Answer Engine
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ * @author Kai Vehmanen <Kai.Vehmanen at nokia.com>
+ *
+ * @date Created: Wed Aug 3 20:28:17 EEST 2005
+ */
+
+#include "config.h"
+
+#define TAG_NAMESPACE "stun"
+
+#include <sofia-sip/su_tag_class.h>
+
+/**@def STUNTAG_ANY()
+ *
+ * Filter tag matching any STUNTAG_*().
+ */
+tag_typedef_t stuntag_any = NSTAG_TYPEDEF(*);
+
+/**@def STUNTAG_DOMAIN(x)
+ *
+ * The domain to use in DNS-SRV based STUN server discovery.
+ * Note: this is commonly the domain part of a public SIP
+ * address (AOR). See sect 9.1 of RFC3489.
+ *
+ * @par Used with
+ * nua_set_params() \n
+ * nua_get_params() \n
+ * nua_invite() \n
+ * nua_respond()
+ *
+ * @par Parameter type
+ * char const *
+
+ */
+tag_typedef_t stuntag_domain = STRTAG_TYPEDEF(domain);
+
+/**@def STUNTAG_SERVER(x)
+ *
+ * Fully qualified host name, or dotted IP address of the STUN server
+ * address. If defined, the DNS-SRV based discovery (@see STUNTAG_DOMAIN())
+ * will be skipped.
+ *
+ * @par Used with
+ * nua_set_params() \n
+ * nua_get_params() \n
+ * nua_invite() \n
+ * nua_respond()
+ *
+ * @par Parameter type
+ * char const *
+ *
+ * @par Values
+ * NULL terminated character string containing a domain name,
+ * IPv4 address, or IPv6 address.
+ *
+ * Corresponding tag taking reference parameter is STUNTAG_SERVER_REF()
+*/
+tag_typedef_t stuntag_server = STRTAG_TYPEDEF(server);
+
+/**@def STUNTAG_REQUIRE_INTEGRITY(x)
+ *
+ * Whether to require support for shared-secret based packet
+ * authentication and integrity checks (see sect 9.2 of RFC3489).
+ * If false, integrity checks are performed only when server supports it.
+ *
+ * @par Used with
+ * nua_create() \n
+ *
+ * @par Parameter type
+ * int (boolean)
+ *
+ * @par Values
+ * @c !=0 enable
+ * @c 0 disable
+ *
+ * Corresponding tag taking reference parameter is STUNTAG_INTEGRITY_REF()
+ */
+tag_typedef_t stuntag_require_integrity = BOOLTAG_TYPEDEF(require_integrity);
+
+/**@def STUNTAG_INTEGRITY(x)
+ *
+ * XXX: should this tag be deprecated in favor of just supporting
+ * STUNTAG_REQURIE_INTEGRITY() instead...?
+ */
+tag_typedef_t stuntag_integrity = BOOLTAG_TYPEDEF(integrity);
+
+/**@def STUNTAG_SOCKET(x)
+ *
+ * Bind socket for STUN.
+ *
+ * @par Used with
+ * stun_handle_bind() \n
+ *
+ * @par Parameter type
+ * int (su_socket_t)
+ *
+ * @par Values
+ * IPv4 (AF_INET) socket
+ *
+ * Corresponding tag taking reference parameter is STUNTAG_SOCKET_REF()
+ */
+tag_typedef_t stuntag_socket = SOCKETTAG_TYPEDEF(socket);
+
+/**@def STUNTAG_REGISTER_EVENTS(x)
+ *
+ * Register socket events for eventloop owned by STUN.
+ *
+ * @par Used with
+ * stun_bind() \n
+ * stun_get_lifetime() \n
+ * stun_get_nattype() \n
+ * stun_keepalive() \n
+ *
+ * @par Parameter type
+ * bool
+ *
+ * @par Values
+ * false (0) or true (nonzero)
+ *
+ * Corresponding tag taking reference parameter is STUNTAG_REGISTER_EVENTS_REF()
+ */
+tag_typedef_t stuntag_register_events = BOOLTAG_TYPEDEF(register_events);
+
+/**@def STUNTAG_ACTION(x)
+ *
+ * Command action for STUN request.
+ *
+ * @par Used with
+ * stun_handle_bind() \n
+ *
+ * @par Parameter type
+ * int (stun_action_t)
+ *
+ * @par Values
+ * See types for stun_action_t in stun.h
+ *
+ * Corresponding tag taking reference parameter is STUNTAG_ACTION_REF()
+ */
+tag_typedef_t stuntag_action = INTTAG_TYPEDEF(action);
+
+/* ---------------------------------------------------------------------- */
+
+/**@def STUNTAG_CHANGE_IP(x)
+ *
+ * Add CHANGE-REQUEST attribute with "change IP" flag to the request.
+ *
+ * @par Used with
+ * stun_make_binding_req() \n
+ *
+ * @par Parameter type
+ * bool
+ *
+ * Corresponding tag taking reference parameter is STUNTAG_CHANGE_IP_REF()
+ */
+tag_typedef_t stuntag_change_ip = BOOLTAG_TYPEDEF(change_ip);
+
+/**@def STUNTAG_CHANGE_PORT(x)
+ *
+ * Add CHANGE-REQUEST attribute with "change port" flag to the request.
+ *
+ * @par Used with
+ * stun_make_binding_req() \n
+ *
+ * @par Parameter type
+ * bool
+ *
+ * Corresponding tag taking reference parameter is STUNTAG_CHANGE_PORT_REF()
+ */
+tag_typedef_t stuntag_change_port = BOOLTAG_TYPEDEF(change_port);
+
+/* ---------------------------------------------------------------------- */
+
+/**@def STUNTAG_TIMEOUT(x)
+ *
+ * Timeout controls the launching of the STUN keepalive timer.
+ *
+ * @par Used with
+ * stun_keepalive() \n
+ *
+ * @par Parameter type
+ * int
+ *
+ * Corresponding tag taking reference parameter is STUNTAG_TIMEOUT_REF()
+ */
+tag_typedef_t stuntag_timeout = INTTAG_TYPEDEF(timeout);
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stunc.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/stun/stunc.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,493 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005,2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**
+ * STUN test client
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ * @author Kai Vehmanen <Kai.Vehmanen at nokia.com>
+ *
+ * @date Created: Thu Jul 24 17:21:00 2003 ppessi
+ */
+
+/**@page stunc STUN test client.
+ *
+ * @section stunc_synopsis Synopsis
+ * <tt>stunc [OPTIONS] \<stun-server-address\></tt>
+ *
+ * @section stunc_description Description
+ * The @em stunc utility can be used to gather information about possible
+ * NAT devices that are located between the client and STUN server.
+ *
+ * @em stunc can provide the following information: the IP address and
+ * port as seen by the STUN server, detecting presence of NATs, and
+ * hints on the type of address translation done. It should be noted
+ * that the results of NAT type and life-time detection should be
+ * considered as hints. There is no guarantee that NAT(s) will handle
+ * future packets in the same way.
+ *
+ * @section stunc_options Command Line Options
+ * The @em stunc utility accepts following command line options:
+ *
+ * <dl>
+ *
+ * <dt>-b</dt>
+ * <dd>Perform a STUN binding discovery. @em stunc will report the
+ * client transport address (IP:port) as seen by the STUN server. In
+ * the presence of NATs, this address is allocated by the NAT closest
+ * to the STUN server.
+ * </dd>
+ *
+ * <dt>-l</dt>
+ * <dd>Perform a STUN binding life-time check.
+ * </dd>
+ *
+ * <dt>-n</dt>
+ * <dd>Perform a STUN binding type check. Notice that the results
+ * are only hints. Nondeterministic behaviour, resource exhaustion,
+ * or reboots of network elements can cause changes in NAT behaviour
+ * between successive runs of stunc.
+ * </dd>
+ *
+ * <dt>-r</dt>
+ * <dd>Randomize the local port. Otherwise @em stunc let's the
+ * operating system select a free port.
+ * </dd>
+ *
+ * <dt>-s</dt>
+ * <dd>Request a shared-secret over TLS. Tests whether the STUN server
+ * supports the shared-secret mechanism (needed to protect message
+ * integrity). Can be combined with @em -b, @em -l and @em -n.
+ * </dd>
+ *
+ * </dl>
+ *
+ * @section stunc_return Return Codes
+ * <table>
+ * <tr><td>0</td><td>when successful</td></tr>
+ * <tr><td>1</td><td>when any errors detected</td></tr>
+ * </table>
+ *
+ * @section stunc_examples Examples
+ *
+ * Discover the NAT binding, use a random local port:
+ * @code
+ * $ stunc stunserver.org -b -r
+ * @endcode
+ *
+ * @section stunc_environment Environment
+ * #STUN_DEBUG
+ *
+ * @section stunc_bugs Reporting Bugs
+ * Report bugs to <sofia-sip-devel at lists.sourceforge.net>.
+ *
+ * @section stunc_author Authors
+ * - Pekka Pessi <pekka -dot pessi -at- nokia -dot- com>
+ * - Martti Mela <martti -dot mela -at- nokia -dot- com>
+ * - Kai Vehmanen <kai -dot vehmanen -at- nokia -dot- com>
+ *
+ * @section stunc_copyright Copyright
+ * Copyright (C) 2005,2006 Nokia Corporation.
+ *
+ * This program is free software; see the source for copying conditions.
+ * There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+
+typedef struct stunc_s stunc_t;
+#define SU_ROOT_MAGIC stunc_t
+#define STUN_MAGIC_T stunc_t
+#define STUN_DISCOVERY_MAGIC_T stunc_t
+
+#include "sofia-sip/stun.h"
+#include "sofia-sip/stun_tag.h"
+#include "sofia-sip/sofia_features.h"
+#include <sofia-sip/su.h>
+
+enum {
+ do_secret = 1,
+ do_bind = 2,
+ do_nat_check = 4,
+ do_life_check = 8,
+ do_randomize_port = 16
+};
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+static char const __func__[] = "stunc";
+#endif
+
+#ifndef SU_DEBUG
+#define SU_DEBUG 0
+#endif
+#define SU_LOG (stun_log)
+#include <sofia-sip/su_debug.h>
+
+void usage(char *name)
+{
+ fprintf(stderr,
+ "stunc (%s)\n"
+ "usage: %s <server> [-b] [-n] [-l] [-r] [-s]\n"
+ " -b\tmake a binding request\n"
+ " -l\tperform NAT lifetime check\n"
+ " -n\tperform NAT type check\n"
+ " -r\trandomize the local port\n",
+ " -s\trequest shared-secret over TLS (combined with -[bln])\n"
+ SOFIA_SIP_NAME_VERSION, name);
+ exit(1);
+}
+
+struct stunc_s {
+ su_socket_t sc_socket;
+ int sc_flags;
+};
+
+
+static
+void stunc_lifetime_cb(stunc_t *stunc,
+ stun_handle_t *sh,
+ stun_discovery_t *sd,
+ stun_action_t action,
+ stun_state_t event);
+
+static
+void stunc_nattype_cb(stunc_t *stunc,
+ stun_handle_t *sh,
+ stun_discovery_t *sd,
+ stun_action_t action,
+ stun_state_t event);
+
+static
+void stunc_bind_cb(stunc_t *stunc,
+ stun_handle_t *sh,
+ stun_discovery_t *sd,
+ stun_action_t action,
+ stun_state_t event);
+
+static
+void stunc_ss_cb(stunc_t *stunc,
+ stun_handle_t *sh,
+ stun_discovery_t *sd,
+ stun_action_t action,
+ stun_state_t event)
+{
+ int err;
+ SU_DEBUG_3(("%s: %s\n", __func__, stun_str_state(event)));
+
+ stunc->sc_flags &= ~do_secret;
+ if (!stunc->sc_flags)
+ su_root_break(stun_root(sh));
+
+ switch (event) {
+ case stun_tls_done:
+ if (stunc->sc_flags & do_bind) {
+ err = stun_bind(sh, stunc_bind_cb, stunc,
+ STUNTAG_SOCKET(stunc->sc_socket),
+ STUNTAG_REGISTER_EVENTS(1),
+ TAG_NULL());
+
+ if (err < 0) {
+ SU_DEBUG_0(("%s: %s failed\n", __func__, "stun_handle_bind()"));
+ su_root_break(stun_root(sh));
+ }
+ }
+ break;
+
+ case stun_tls_connection_failed:
+ SU_DEBUG_0(("%s: Obtaining shared secret failed.\n",
+ __func__));
+ stunc->sc_flags &= ~do_bind;
+ if (!stunc->sc_flags)
+ su_root_break(stun_root(sh));
+
+ break;
+
+ case stun_tls_connection_timeout:
+ SU_DEBUG_0(("%s: Timeout when obtaining shared secret.\n",
+ __func__));
+ stunc->sc_flags &= ~do_bind;
+ break;
+
+ default:
+ break;
+ }
+
+ return;
+}
+
+
+static
+void stunc_bind_cb(stunc_t *stunc,
+ stun_handle_t *sh,
+ stun_discovery_t *sd,
+ stun_action_t action,
+ stun_state_t event)
+{
+ su_sockaddr_t sa[1];
+ char ipaddr[48];
+ socklen_t addrlen;
+
+ SU_DEBUG_3(("%s: %s\n", __func__, stun_str_state(event)));
+
+ stunc->sc_flags &= ~do_bind;
+
+ if (!stunc->sc_flags)
+ su_root_break(stun_root(sh));
+
+ switch (event) {
+ case stun_discovery_done:
+ addrlen = sizeof(*sa);
+ memset(sa, 0, addrlen);
+
+ if (stun_discovery_get_address(sd, sa, &addrlen) < 0) {
+ SU_DEBUG_0(("%s: stun_discovery_get_address() failed", __func__));
+ return;
+ }
+
+ SU_DEBUG_0(("%s: local address NATed as %s:%u\n", __func__,
+ inet_ntop(sa->su_family, SU_ADDR(sa),
+ ipaddr, sizeof(ipaddr)),
+ (unsigned) ntohs(sa->su_port)));
+
+ break;
+
+ case stun_discovery_timeout:
+ case stun_discovery_error:
+ case stun_error:
+ default:
+ break;
+ }
+
+ return;
+}
+
+
+static
+void stunc_nattype_cb(stunc_t *stunc,
+ stun_handle_t *sh,
+ stun_discovery_t *sd,
+ stun_action_t action,
+ stun_state_t event)
+{
+ SU_DEBUG_3(("%s: %s\n", __func__, stun_str_state(event)));
+
+ stunc->sc_flags &= ~do_nat_check;
+
+ if (!stunc->sc_flags)
+ su_root_break(stun_root(sh));
+
+ switch (event) {
+ case stun_discovery_timeout:
+ SU_DEBUG_3(("%s: NAT type determination timeout.\n", __func__));
+ break;
+
+ case stun_discovery_done:
+ SU_DEBUG_3(("%s: NAT type determined to be '%s' (%d).\n",
+ __func__, stun_nattype_str(sd), (int)stun_nattype(sd)));
+ break;
+
+ case stun_error:
+ default:
+ break;
+ }
+
+ return;
+}
+
+
+static
+void stunc_lifetime_cb(stunc_t *stunc,
+ stun_handle_t *sh,
+ stun_discovery_t *sd,
+ stun_action_t action,
+ stun_state_t event)
+{
+ SU_DEBUG_3(("%s: %s\n", __func__, stun_str_state(event)));
+
+ stunc->sc_flags &= ~do_life_check;
+
+ if (!stunc->sc_flags)
+ su_root_break(stun_root(sh));
+
+ switch (event) {
+ case stun_discovery_timeout:
+ SU_DEBUG_3(("%s: Lifetime determination timeout.\n", __func__));
+ break;
+
+ case stun_discovery_done:
+ SU_DEBUG_3(("%s: Lifetime determined to be %d.\n", __func__, stun_lifetime(sd)));
+ break;
+
+ case stun_error:
+ default:
+ break;
+ }
+
+ return;
+}
+
+
+int main(int argc, char *argv[])
+{
+ int err = 0, i, sflags = 0;
+ stunc_t stunc[1];
+ su_root_t *root;
+ stun_handle_t *sh;
+ su_socket_t s;
+
+ if (su_init() != 0)
+ return -1;
+
+ root = su_root_create(stunc);
+
+ if (argc < 3)
+ usage(argv[0]);
+
+ for (i = 2; argv[i]; i++) {
+ if (strcmp(argv[i], "-s") == 0)
+ sflags |= do_secret;
+ else if (strcmp(argv[i], "-b") == 0)
+ sflags |= do_bind;
+ else if (strcmp(argv[i], "-n") == 0)
+ sflags |= do_nat_check;
+ else if (strcmp(argv[i], "-l") == 0)
+ sflags |= do_life_check;
+ else if (strcmp(argv[i], "-r") == 0)
+ sflags |= do_randomize_port;
+ else {
+ fprintf(stderr, "Unable to parse option %s.\n", argv[i]);
+ usage(argv[0]);
+ }
+ }
+
+ /* Running this test requires a local STUN server on default port */
+ sh = stun_handle_init(root,
+ STUNTAG_SERVER(argv[1]),
+ STUNTAG_REQUIRE_INTEGRITY(sflags & do_secret),
+ TAG_NULL());
+
+ if (!sh) {
+ SU_DEBUG_0(("%s: %s failed\n", __func__, "stun_handle_init()"));
+ return -1;
+ }
+
+ s = su_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (s == -1) {
+ SU_DEBUG_0(("%s: %s failed: %s\n", __func__,
+ "su_socket()", su_gli_strerror(errno)));
+ return -1;
+ }
+
+ stunc->sc_socket = s;
+ stunc->sc_flags = sflags;
+
+ if (sflags & do_randomize_port) {
+ su_sockaddr_t sockaddr;
+ char ipaddr[SU_ADDRSIZE + 2] = { 0 };
+ socklen_t socklen = sizeof(sockaddr);
+
+ srand((unsigned int)time((time_t *)NULL));
+
+ memset(&sockaddr, 0, sizeof(su_sockaddr_t));
+ sockaddr.su_port = htons((rand() % (65536 - 1024)) + 1024);
+ sockaddr.su_family = AF_INET;
+
+ SU_DEBUG_3(("stunc: Binding to local port %u.\n", ntohs(sockaddr.su_port)));
+
+ err = bind(s, (struct sockaddr *)&sockaddr, socklen);
+ if (err < 0) {
+ SU_DEBUG_1(("%s: Error %d binding to %s:%u\n", __func__, err,
+ inet_ntop(sockaddr.su_family, SU_ADDR(&sockaddr),
+ ipaddr, sizeof(ipaddr)),
+ (unsigned) ntohs(sockaddr.su_port)));
+ return -1;
+ }
+
+ stunc->sc_flags &= ~do_randomize_port;
+ }
+
+ if (sflags & do_secret) {
+ if (stun_obtain_shared_secret(sh, stunc_ss_cb, stunc, TAG_NULL()) < 0) {
+ SU_DEBUG_3(("%s: %s failed\n", __func__,
+ "stun_handle_request_shared_secret()"));
+ return -1;
+ }
+ }
+
+
+ /* If we want to bind and no integrity required */
+ if ((sflags & do_bind) && !(sflags & do_secret)) {
+ err = stun_bind(sh, stunc_bind_cb, stunc,
+ STUNTAG_SOCKET(s),
+ STUNTAG_REGISTER_EVENTS(1),
+ TAG_NULL());
+
+ if (err < 0) {
+ SU_DEBUG_0(("%s: %s failed\n", __func__, "stun_bind()"));
+ return -1;
+ }
+ }
+
+ if (sflags & do_nat_check) {
+ err = stun_test_nattype(sh, stunc_nattype_cb, stunc,
+ STUNTAG_REGISTER_EVENTS(1),
+ STUNTAG_SOCKET(stunc->sc_socket),
+ TAG_NULL());
+
+ if (err < 0) {
+ SU_DEBUG_0(("%s: %s failed\n", __func__, "stun_test_nattype()"));
+ su_root_break(stun_root(sh));
+ }
+ }
+
+ if (sflags & do_life_check) {
+ err = stun_test_lifetime(sh, stunc_lifetime_cb, stunc,
+ STUNTAG_REGISTER_EVENTS(1),
+ STUNTAG_SOCKET(stunc->sc_socket),
+ TAG_NULL());
+
+ if (err < 0) {
+ SU_DEBUG_0(("%s: %s failed\n", __func__, "stun_test_lifetime()"));
+ su_root_break(stun_root(sh));
+ }
+ }
+
+ if (err == 0)
+ su_root_run(root);
+
+ stun_handle_destroy(sh);
+ su_root_destroy(root);
+
+ return 0;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/ChangeLog Thu Dec 21 01:30:28 2006
@@ -0,0 +1,102 @@
+2006-05-03 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * poll_test.c: Renamed call s/su_create_wait/su_wait_create/.
+
+2006-01-17 Martti Mela <martti.mela at nokia.com>
+
+ * su_localinfo.c: su_getlocalinfo() works now on OS X
+
+ * su_memmem.c: malloc fetched from different header file in OS X
+
+ * su_config.h: reference to su_configure_win32.h removed.
+
+ M ./libsofia-sip-ua/su/su_localinfo.c -8 +97
+
+
+2006-01-13 Martti Mela <martti.mela at nokia.com>
+
+ * su_wait.h: Added su_wait_socket(). (it returns associated fd)
+
+2005-10-12 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Added tl_llist(), tl_vllist(). Better semantics for tl_next().
+
+ M ./libsofia-sip-ua/su/su_tag.h -1 +3
+ M ./libsofia-sip-ua/su/su_tag_test.c -5 +26
+ M ./libsofia-sip-ua/su/su_taglist.c -7 +102
+
+ * su_home_auto() now accepts unaligned pointer.
+
+ M ./libsofia-sip-ua/su/su_alloc.c -4 +11
+
+2005-10-11 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Fixed superfluous assertion failure here.
+
+ M ./libsofia-sip-ua/su/su_root.c -3 +1
+
+2005-10-10 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Using glib in the clone test, too.
+
+ M ./libsofia-sip-ua/su/run_su_test -4 +26
+ M ./libsofia-sip-ua/su/su_test.c -22 +51
+
+ * Fixed su_home_new() documentation.
+
+ M ./libsofia-sip-ua/su/su_alloc.c -4 +2
+
+ * Remove su_home_incref()/su_home_decref() - they were never implemented.
+
+ M ./libsofia-sip-ua/su/su_alloc.h -4
+
+ * Added more debugging information from SU_PORT_DECREF().
+
+ M ./libsofia-sip-ua/su/su_port.c -3 +5
+
+ * Added su_clone_start()/su_clone_wait() tests.
+
+ M ./libsofia-sip-ua/su/su_root_test.c -42 +104
+
+ * Fixed warning about getenv().
+
+ M ./libsofia-sip-ua/su/su_torture.c +1
+
+2005-10-03 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Fixed bug in stack allocation.
+
+ M ./libsofia-sip-ua/su/su_memmem.c -1 +1
+
+ * Improved test coverage. Fixed bug in allocating arrays from stack.
+
+ M ./libsofia-sip-ua/su/su_memmem.c -11 +10
+ M ./libsofia-sip-ua/su/torture_su_memmem.c +119
+
+ * Added constant reference type su_msg_cr[].
+
+ M ./libsofia-sip-ua/su/su_root.c -2 +2
+ M ./libsofia-sip-ua/su/su_wait.h -14 +17
+
+2005-09-28 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Added tl_filtered_tlist().
+
+ M ./libsofia-sip-ua/su/su_tag.h +3
+ M ./libsofia-sip-ua/su/su_taglist.c +16
+
+ * Added su_home_auto().
+
+ M ./libsofia-sip-ua/su/su_alloc.c -10 +55
+ M ./libsofia-sip-ua/su/su_alloc.h +4
+ M ./libsofia-sip-ua/su/su_alloc_test.c +33
+
+2005-08-17 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Added su_strlst_dup() and su_strlst_copy().
+
+ * Added { to BEGIN() and } to END() in <tstdef.h>
+
+2005-07-18 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * Initial import of the module to Sofia-SIP tree.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/Doxyfile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/Doxyfile Thu Dec 21 01:30:28 2006
@@ -0,0 +1,24 @@
+PROJECT_NAME = "su"
+OUTPUT_DIRECTORY = ../docs/html/su
+
+INPUT = su.docs sofia-sip .
+
+ at INCLUDE = ../docs/Doxyfile.conf
+
+TAGFILES += ../docs/msg.doxytags=../msg
+TAGFILES += ../docs/sip.doxytags=../sip
+TAGFILES += ../docs/docs.doxytags=..
+
+GENERATE_TAGFILE = ../docs/su.doxytags
+
+ALIASES += "SU_TAG=@ingroup su_tag\n"
+
+PREDEFINED += \
+ TSTFLAGS=1 \
+ SU_HAVE_BSDSOCK=0 \
+ su_root_s=su_root_t \
+ _su_task_r=su_task_r
+
+EXCLUDE_PATTERNS += localinfo.c addrinfo.c
+
+ at INCLUDE = ../sip/sip.doxyaliases
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/Makefile.am Thu Dec 21 01:30:28 2006
@@ -0,0 +1,119 @@
+#
+# Makefile.am @template@ for su module
+#
+# Copyright (C) 2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+#
+
+# ----------------------------------------------------------------------
+# Headers
+
+# ----------------------------------------------------------------------
+# Build targets
+
+noinst_LTLIBRARIES = libsu.la
+
+bin_PROGRAMS = addrinfo localinfo
+
+if COREFOUNDATION
+OSXSOURCES = \
+ su_osx_runloop.c
+OSXHEADERS = \
+ sofia-sip/su_osx_runloop.h
+OSXPROGS = \
+ torture_su_root_osx test_su_osx
+OSXTESTS = \
+ torture_su_root_osx run_test_su_osx
+else
+OSXSOURCES =
+OSXHEADERS =
+endif
+
+check_PROGRAMS = torture_su torture_su_port \
+ torture_su_alloc torture_su_time torture_su_tag \
+ test_htable torture_rbtree \
+ test_memmem torture_su_bm \
+ torture_su_root torture_su_timer \
+ test_su su_proxy test_poll $(OSXPROGS)
+
+# ----------------------------------------------------------------------
+# Tests
+
+TESTS = torture_su torture_su_port \
+ torture_su_alloc torture_su_time torture_su_tag \
+ test_htable torture_rbtree \
+ test_memmem torture_su_bm \
+ torture_su_root torture_su_timer \
+ run_addrinfo run_localinfo run_test_su \
+ $(OSXTESTS)
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+
+BUILT_SOURCES = su_tag_ref.c
+
+nobase_include_sofia_HEADERS = \
+ sofia-sip/su_types.h sofia-sip/su.h \
+ sofia-sip/su_errno.h sofia-sip/su_addrinfo.h \
+ sofia-sip/su_localinfo.h sofia-sip/su_wait.h \
+ sofia-sip/su_alloc.h sofia-sip/su_alloc_stat.h \
+ sofia-sip/su_strlst.h sofia-sip/su_vector.h \
+ sofia-sip/su_time.h sofia-sip/su_tag.h \
+ sofia-sip/su_tag_class.h sofia-sip/su_tagarg.h \
+ sofia-sip/su_tag_io.h sofia-sip/su_tag_inline.h \
+ sofia-sip/htable.h sofia-sip/htable2.h \
+ sofia-sip/rbtree.h sofia-sip/su_debug.h \
+ sofia-sip/su_log.h \
+ sofia-sip/su_config.h sofia-sip/su_md5.h \
+ sofia-sip/su_uniqueid.h sofia-sip/su_bm.h \
+ sofia-sip/tstdef.h sofia-sip/su_os_nw.h \
+ $(OSXHEADERS)
+
+nobase_nodist_include_sofia_HEADERS = sofia-sip/su_configure.h
+
+libsu_la_SOURCES = \
+ su.c su_errno.c su_addrinfo.c \
+ su_alloc.c su_alloc_lock.c su_strdup.c su_sprintf.c \
+ su_strlst.c su_vector.c \
+ su_time.c su_time0.c \
+ su_wait.c su_root.c su_timer.c su_port.c su_port.h \
+ su_localinfo.c \
+ su_os_nw.c \
+ su_taglist.c su_tag.c su_tag_io.c \
+ su_log.c su_global_log.c su_default_log.c su_module_debug.h \
+ su_md5.c su_uniqueid.c su_bm.c $(OSXSOURCES)
+
+
+EXTRA_libsu_la_SOURCES = \
+ memmem.c strtoull.c strcasestr.c \
+ memspn.c memcspn.c memccpy.c \
+ inet_ntop.c inet_pton.c getopt.c \
+ su_tag_ref.c
+
+libsu_la_LIBADD = $(REPLACE_LIBADD)
+libsu_la_DEPENDENCIES = $(REPLACE_LIBADD)
+
+COVERAGE_INPUT = $(libsu_la_SOURCES) $(include_sofia_HEADERS)
+
+LDADD = libsu.la
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+
+EXTRA_DIST = Doxyfile su.docs \
+ run_addrinfo run_localinfo run_test_su
+
+dist_pkgdata_SCRIPTS = tag_dll.awk
+
+sofia-sip/su_configure.h: sofia-sip/su_configure.h.in
+
+# ----------------------------------------------------------------------
+# Automake options
+
+AUTOMAKE_OPTIONS = foreign
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+
+include ../sofia.am
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/Makefile.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1058 @@
+# 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.
+
+ at SET_MAKE@
+
+#
+# Makefile.am @template@ for su module
+#
+# Copyright (C) 2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+#
+
+# ----------------------------------------------------------------------
+# Headers
+
+# ----------------------------------------------------------------------
+# Build targets
+
+# common Makefile targets for libsofia-sip-ua modules
+# ---------------------------------------------------
+
+
+
+
+SOURCES = $(libsu_la_SOURCES) $(EXTRA_libsu_la_SOURCES) addrinfo.c localinfo.c su_proxy.c test_htable.c test_memmem.c test_poll.c test_su.c test_su_osx.c torture_rbtree.c torture_su.c torture_su_alloc.c torture_su_bm.c torture_su_port.c torture_su_root.c torture_su_root_osx.c torture_su_tag.c torture_su_time.c torture_su_timer.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@
+bin_PROGRAMS = addrinfo$(EXEEXT) localinfo$(EXEEXT)
+check_PROGRAMS = torture_su$(EXEEXT) torture_su_port$(EXEEXT) \
+ torture_su_alloc$(EXEEXT) torture_su_time$(EXEEXT) \
+ torture_su_tag$(EXEEXT) test_htable$(EXEEXT) \
+ torture_rbtree$(EXEEXT) test_memmem$(EXEEXT) \
+ torture_su_bm$(EXEEXT) torture_su_root$(EXEEXT) \
+ torture_su_timer$(EXEEXT) test_su$(EXEEXT) su_proxy$(EXEEXT) \
+ test_poll$(EXEEXT) $(am__EXEEXT_1)
+DIST_COMMON = $(am__nobase_include_sofia_HEADERS_DIST) \
+ $(dist_pkgdata_SCRIPTS) $(srcdir)/../sofia.am \
+ $(srcdir)/Makefile.am $(srcdir)/Makefile.in ChangeLog
+subdir = libsofia-sip-ua/su
+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 =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+am__libsu_la_SOURCES_DIST = su.c su_errno.c su_addrinfo.c su_alloc.c \
+ su_alloc_lock.c su_strdup.c su_sprintf.c su_strlst.c \
+ su_vector.c su_time.c su_time0.c su_wait.c su_root.c \
+ su_timer.c su_port.c su_port.h su_localinfo.c su_os_nw.c \
+ su_taglist.c su_tag.c su_tag_io.c su_log.c su_global_log.c \
+ su_default_log.c su_module_debug.h su_md5.c su_uniqueid.c \
+ su_bm.c su_osx_runloop.c
+ at COREFOUNDATION_TRUE@am__objects_1 = su_osx_runloop.lo
+am_libsu_la_OBJECTS = su.lo su_errno.lo su_addrinfo.lo su_alloc.lo \
+ su_alloc_lock.lo su_strdup.lo su_sprintf.lo su_strlst.lo \
+ su_vector.lo su_time.lo su_time0.lo su_wait.lo su_root.lo \
+ su_timer.lo su_port.lo su_localinfo.lo su_os_nw.lo \
+ su_taglist.lo su_tag.lo su_tag_io.lo su_log.lo \
+ su_global_log.lo su_default_log.lo su_md5.lo su_uniqueid.lo \
+ su_bm.lo $(am__objects_1)
+libsu_la_OBJECTS = $(am_libsu_la_OBJECTS)
+am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgdatadir)" \
+ "$(DESTDIR)$(include_sofiadir)" \
+ "$(DESTDIR)$(include_sofiadir)"
+binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+ at COREFOUNDATION_TRUE@am__EXEEXT_1 = torture_su_root_osx$(EXEEXT) \
+ at COREFOUNDATION_TRUE@ test_su_osx$(EXEEXT)
+PROGRAMS = $(bin_PROGRAMS)
+addrinfo_SOURCES = addrinfo.c
+addrinfo_OBJECTS = addrinfo.$(OBJEXT)
+addrinfo_LDADD = $(LDADD)
+addrinfo_DEPENDENCIES = libsu.la
+localinfo_SOURCES = localinfo.c
+localinfo_OBJECTS = localinfo.$(OBJEXT)
+localinfo_LDADD = $(LDADD)
+localinfo_DEPENDENCIES = libsu.la
+su_proxy_SOURCES = su_proxy.c
+su_proxy_OBJECTS = su_proxy.$(OBJEXT)
+su_proxy_LDADD = $(LDADD)
+su_proxy_DEPENDENCIES = libsu.la
+test_htable_SOURCES = test_htable.c
+test_htable_OBJECTS = test_htable.$(OBJEXT)
+test_htable_LDADD = $(LDADD)
+test_htable_DEPENDENCIES = libsu.la
+test_memmem_SOURCES = test_memmem.c
+test_memmem_OBJECTS = test_memmem.$(OBJEXT)
+test_memmem_LDADD = $(LDADD)
+test_memmem_DEPENDENCIES = libsu.la
+test_poll_SOURCES = test_poll.c
+test_poll_OBJECTS = test_poll.$(OBJEXT)
+test_poll_LDADD = $(LDADD)
+test_poll_DEPENDENCIES = libsu.la
+test_su_SOURCES = test_su.c
+test_su_OBJECTS = test_su.$(OBJEXT)
+test_su_LDADD = $(LDADD)
+test_su_DEPENDENCIES = libsu.la
+test_su_osx_SOURCES = test_su_osx.c
+test_su_osx_OBJECTS = test_su_osx.$(OBJEXT)
+test_su_osx_LDADD = $(LDADD)
+test_su_osx_DEPENDENCIES = libsu.la
+torture_rbtree_SOURCES = torture_rbtree.c
+torture_rbtree_OBJECTS = torture_rbtree.$(OBJEXT)
+torture_rbtree_LDADD = $(LDADD)
+torture_rbtree_DEPENDENCIES = libsu.la
+torture_su_SOURCES = torture_su.c
+torture_su_OBJECTS = torture_su.$(OBJEXT)
+torture_su_LDADD = $(LDADD)
+torture_su_DEPENDENCIES = libsu.la
+torture_su_alloc_SOURCES = torture_su_alloc.c
+torture_su_alloc_OBJECTS = torture_su_alloc.$(OBJEXT)
+torture_su_alloc_LDADD = $(LDADD)
+torture_su_alloc_DEPENDENCIES = libsu.la
+torture_su_bm_SOURCES = torture_su_bm.c
+torture_su_bm_OBJECTS = torture_su_bm.$(OBJEXT)
+torture_su_bm_LDADD = $(LDADD)
+torture_su_bm_DEPENDENCIES = libsu.la
+torture_su_port_SOURCES = torture_su_port.c
+torture_su_port_OBJECTS = torture_su_port.$(OBJEXT)
+torture_su_port_LDADD = $(LDADD)
+torture_su_port_DEPENDENCIES = libsu.la
+torture_su_root_SOURCES = torture_su_root.c
+torture_su_root_OBJECTS = torture_su_root.$(OBJEXT)
+torture_su_root_LDADD = $(LDADD)
+torture_su_root_DEPENDENCIES = libsu.la
+torture_su_root_osx_SOURCES = torture_su_root_osx.c
+torture_su_root_osx_OBJECTS = torture_su_root_osx.$(OBJEXT)
+torture_su_root_osx_LDADD = $(LDADD)
+torture_su_root_osx_DEPENDENCIES = libsu.la
+torture_su_tag_SOURCES = torture_su_tag.c
+torture_su_tag_OBJECTS = torture_su_tag.$(OBJEXT)
+torture_su_tag_LDADD = $(LDADD)
+torture_su_tag_DEPENDENCIES = libsu.la
+torture_su_time_SOURCES = torture_su_time.c
+torture_su_time_OBJECTS = torture_su_time.$(OBJEXT)
+torture_su_time_LDADD = $(LDADD)
+torture_su_time_DEPENDENCIES = libsu.la
+torture_su_timer_SOURCES = torture_su_timer.c
+torture_su_timer_OBJECTS = torture_su_timer.$(OBJEXT)
+torture_su_timer_LDADD = $(LDADD)
+torture_su_timer_DEPENDENCIES = libsu.la
+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 = $(libsu_la_SOURCES) $(EXTRA_libsu_la_SOURCES) addrinfo.c \
+ localinfo.c su_proxy.c test_htable.c test_memmem.c test_poll.c \
+ test_su.c test_su_osx.c torture_rbtree.c torture_su.c \
+ torture_su_alloc.c torture_su_bm.c torture_su_port.c \
+ torture_su_root.c torture_su_root_osx.c torture_su_tag.c \
+ torture_su_time.c torture_su_timer.c
+DIST_SOURCES = $(am__libsu_la_SOURCES_DIST) $(EXTRA_libsu_la_SOURCES) \
+ addrinfo.c localinfo.c su_proxy.c test_htable.c test_memmem.c \
+ test_poll.c test_su.c test_su_osx.c torture_rbtree.c \
+ torture_su.c torture_su_alloc.c torture_su_bm.c \
+ torture_su_port.c torture_su_root.c torture_su_root_osx.c \
+ torture_su_tag.c torture_su_time.c torture_su_timer.c
+am__nobase_include_sofia_HEADERS_DIST = sofia-sip/su_types.h \
+ sofia-sip/su.h sofia-sip/su_errno.h sofia-sip/su_addrinfo.h \
+ sofia-sip/su_localinfo.h sofia-sip/su_wait.h \
+ sofia-sip/su_alloc.h sofia-sip/su_alloc_stat.h \
+ sofia-sip/su_strlst.h sofia-sip/su_vector.h \
+ sofia-sip/su_time.h sofia-sip/su_tag.h \
+ sofia-sip/su_tag_class.h sofia-sip/su_tagarg.h \
+ sofia-sip/su_tag_io.h sofia-sip/su_tag_inline.h \
+ sofia-sip/htable.h sofia-sip/htable2.h sofia-sip/rbtree.h \
+ sofia-sip/su_debug.h sofia-sip/su_log.h sofia-sip/su_config.h \
+ sofia-sip/su_md5.h sofia-sip/su_uniqueid.h sofia-sip/su_bm.h \
+ sofia-sip/tstdef.h sofia-sip/su_os_nw.h \
+ sofia-sip/su_osx_runloop.h
+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)
+nobase_nodist_include_sofiaHEADERS_INSTALL = $(install_sh_DATA)
+HEADERS = $(nobase_include_sofia_HEADERS) \
+ $(nobase_nodist_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@
+noinst_LTLIBRARIES = libsu.la
+ at COREFOUNDATION_FALSE@OSXSOURCES =
+ at COREFOUNDATION_TRUE@OSXSOURCES = \
+ at COREFOUNDATION_TRUE@ su_osx_runloop.c
+
+ at COREFOUNDATION_FALSE@OSXHEADERS =
+ at COREFOUNDATION_TRUE@OSXHEADERS = \
+ at COREFOUNDATION_TRUE@ sofia-sip/su_osx_runloop.h
+
+ at COREFOUNDATION_TRUE@OSXPROGS = \
+ at COREFOUNDATION_TRUE@ torture_su_root_osx test_su_osx
+
+ at COREFOUNDATION_TRUE@OSXTESTS = \
+ at COREFOUNDATION_TRUE@ torture_su_root_osx run_test_su_osx
+
+
+# ----------------------------------------------------------------------
+# Tests
+TESTS = torture_su torture_su_port \
+ torture_su_alloc torture_su_time torture_su_tag \
+ test_htable torture_rbtree \
+ test_memmem torture_su_bm \
+ torture_su_root torture_su_timer \
+ run_addrinfo run_localinfo run_test_su \
+ $(OSXTESTS)
+
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+BUILT_SOURCES = su_tag_ref.c
+nobase_include_sofia_HEADERS = \
+ sofia-sip/su_types.h sofia-sip/su.h \
+ sofia-sip/su_errno.h sofia-sip/su_addrinfo.h \
+ sofia-sip/su_localinfo.h sofia-sip/su_wait.h \
+ sofia-sip/su_alloc.h sofia-sip/su_alloc_stat.h \
+ sofia-sip/su_strlst.h sofia-sip/su_vector.h \
+ sofia-sip/su_time.h sofia-sip/su_tag.h \
+ sofia-sip/su_tag_class.h sofia-sip/su_tagarg.h \
+ sofia-sip/su_tag_io.h sofia-sip/su_tag_inline.h \
+ sofia-sip/htable.h sofia-sip/htable2.h \
+ sofia-sip/rbtree.h sofia-sip/su_debug.h \
+ sofia-sip/su_log.h \
+ sofia-sip/su_config.h sofia-sip/su_md5.h \
+ sofia-sip/su_uniqueid.h sofia-sip/su_bm.h \
+ sofia-sip/tstdef.h sofia-sip/su_os_nw.h \
+ $(OSXHEADERS)
+
+nobase_nodist_include_sofia_HEADERS = sofia-sip/su_configure.h
+libsu_la_SOURCES = \
+ su.c su_errno.c su_addrinfo.c \
+ su_alloc.c su_alloc_lock.c su_strdup.c su_sprintf.c \
+ su_strlst.c su_vector.c \
+ su_time.c su_time0.c \
+ su_wait.c su_root.c su_timer.c su_port.c su_port.h \
+ su_localinfo.c \
+ su_os_nw.c \
+ su_taglist.c su_tag.c su_tag_io.c \
+ su_log.c su_global_log.c su_default_log.c su_module_debug.h \
+ su_md5.c su_uniqueid.c su_bm.c $(OSXSOURCES)
+
+EXTRA_libsu_la_SOURCES = \
+ memmem.c strtoull.c strcasestr.c \
+ memspn.c memcspn.c memccpy.c \
+ inet_ntop.c inet_pton.c getopt.c \
+ su_tag_ref.c
+
+libsu_la_LIBADD = $(REPLACE_LIBADD)
+libsu_la_DEPENDENCIES = $(REPLACE_LIBADD)
+COVERAGE_INPUT = $(libsu_la_SOURCES) $(include_sofia_HEADERS)
+LDADD = libsu.la
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+EXTRA_DIST = Doxyfile su.docs \
+ run_addrinfo run_localinfo run_test_su
+
+dist_pkgdata_SCRIPTS = tag_dll.awk
+
+# ----------------------------------------------------------------------
+# Automake options
+AUTOMAKE_OPTIONS = foreign
+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
+
+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) --foreign libsofia-sip-ua/su/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --foreign libsofia-sip-ua/su/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-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
+libsu.la: $(libsu_la_OBJECTS) $(libsu_la_DEPENDENCIES)
+ $(LINK) $(libsu_la_LDFLAGS) $(libsu_la_OBJECTS) $(libsu_la_LIBADD) $(LIBS)
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)"
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ if test -f $$p \
+ || test -f $$p1 \
+ ; then \
+ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \
+ else :; fi; \
+ done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \
+ rm -f "$(DESTDIR)$(bindir)/$$f"; \
+ done
+
+clean-binPROGRAMS:
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f $$p $$f"; \
+ rm -f $$p $$f ; \
+ done
+
+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
+addrinfo$(EXEEXT): $(addrinfo_OBJECTS) $(addrinfo_DEPENDENCIES)
+ @rm -f addrinfo$(EXEEXT)
+ $(LINK) $(addrinfo_LDFLAGS) $(addrinfo_OBJECTS) $(addrinfo_LDADD) $(LIBS)
+localinfo$(EXEEXT): $(localinfo_OBJECTS) $(localinfo_DEPENDENCIES)
+ @rm -f localinfo$(EXEEXT)
+ $(LINK) $(localinfo_LDFLAGS) $(localinfo_OBJECTS) $(localinfo_LDADD) $(LIBS)
+su_proxy$(EXEEXT): $(su_proxy_OBJECTS) $(su_proxy_DEPENDENCIES)
+ @rm -f su_proxy$(EXEEXT)
+ $(LINK) $(su_proxy_LDFLAGS) $(su_proxy_OBJECTS) $(su_proxy_LDADD) $(LIBS)
+test_htable$(EXEEXT): $(test_htable_OBJECTS) $(test_htable_DEPENDENCIES)
+ @rm -f test_htable$(EXEEXT)
+ $(LINK) $(test_htable_LDFLAGS) $(test_htable_OBJECTS) $(test_htable_LDADD) $(LIBS)
+test_memmem$(EXEEXT): $(test_memmem_OBJECTS) $(test_memmem_DEPENDENCIES)
+ @rm -f test_memmem$(EXEEXT)
+ $(LINK) $(test_memmem_LDFLAGS) $(test_memmem_OBJECTS) $(test_memmem_LDADD) $(LIBS)
+test_poll$(EXEEXT): $(test_poll_OBJECTS) $(test_poll_DEPENDENCIES)
+ @rm -f test_poll$(EXEEXT)
+ $(LINK) $(test_poll_LDFLAGS) $(test_poll_OBJECTS) $(test_poll_LDADD) $(LIBS)
+test_su$(EXEEXT): $(test_su_OBJECTS) $(test_su_DEPENDENCIES)
+ @rm -f test_su$(EXEEXT)
+ $(LINK) $(test_su_LDFLAGS) $(test_su_OBJECTS) $(test_su_LDADD) $(LIBS)
+test_su_osx$(EXEEXT): $(test_su_osx_OBJECTS) $(test_su_osx_DEPENDENCIES)
+ @rm -f test_su_osx$(EXEEXT)
+ $(LINK) $(test_su_osx_LDFLAGS) $(test_su_osx_OBJECTS) $(test_su_osx_LDADD) $(LIBS)
+torture_rbtree$(EXEEXT): $(torture_rbtree_OBJECTS) $(torture_rbtree_DEPENDENCIES)
+ @rm -f torture_rbtree$(EXEEXT)
+ $(LINK) $(torture_rbtree_LDFLAGS) $(torture_rbtree_OBJECTS) $(torture_rbtree_LDADD) $(LIBS)
+torture_su$(EXEEXT): $(torture_su_OBJECTS) $(torture_su_DEPENDENCIES)
+ @rm -f torture_su$(EXEEXT)
+ $(LINK) $(torture_su_LDFLAGS) $(torture_su_OBJECTS) $(torture_su_LDADD) $(LIBS)
+torture_su_alloc$(EXEEXT): $(torture_su_alloc_OBJECTS) $(torture_su_alloc_DEPENDENCIES)
+ @rm -f torture_su_alloc$(EXEEXT)
+ $(LINK) $(torture_su_alloc_LDFLAGS) $(torture_su_alloc_OBJECTS) $(torture_su_alloc_LDADD) $(LIBS)
+torture_su_bm$(EXEEXT): $(torture_su_bm_OBJECTS) $(torture_su_bm_DEPENDENCIES)
+ @rm -f torture_su_bm$(EXEEXT)
+ $(LINK) $(torture_su_bm_LDFLAGS) $(torture_su_bm_OBJECTS) $(torture_su_bm_LDADD) $(LIBS)
+torture_su_port$(EXEEXT): $(torture_su_port_OBJECTS) $(torture_su_port_DEPENDENCIES)
+ @rm -f torture_su_port$(EXEEXT)
+ $(LINK) $(torture_su_port_LDFLAGS) $(torture_su_port_OBJECTS) $(torture_su_port_LDADD) $(LIBS)
+torture_su_root$(EXEEXT): $(torture_su_root_OBJECTS) $(torture_su_root_DEPENDENCIES)
+ @rm -f torture_su_root$(EXEEXT)
+ $(LINK) $(torture_su_root_LDFLAGS) $(torture_su_root_OBJECTS) $(torture_su_root_LDADD) $(LIBS)
+torture_su_root_osx$(EXEEXT): $(torture_su_root_osx_OBJECTS) $(torture_su_root_osx_DEPENDENCIES)
+ @rm -f torture_su_root_osx$(EXEEXT)
+ $(LINK) $(torture_su_root_osx_LDFLAGS) $(torture_su_root_osx_OBJECTS) $(torture_su_root_osx_LDADD) $(LIBS)
+torture_su_tag$(EXEEXT): $(torture_su_tag_OBJECTS) $(torture_su_tag_DEPENDENCIES)
+ @rm -f torture_su_tag$(EXEEXT)
+ $(LINK) $(torture_su_tag_LDFLAGS) $(torture_su_tag_OBJECTS) $(torture_su_tag_LDADD) $(LIBS)
+torture_su_time$(EXEEXT): $(torture_su_time_OBJECTS) $(torture_su_time_DEPENDENCIES)
+ @rm -f torture_su_time$(EXEEXT)
+ $(LINK) $(torture_su_time_LDFLAGS) $(torture_su_time_OBJECTS) $(torture_su_time_LDADD) $(LIBS)
+torture_su_timer$(EXEEXT): $(torture_su_timer_OBJECTS) $(torture_su_timer_DEPENDENCIES)
+ @rm -f torture_su_timer$(EXEEXT)
+ $(LINK) $(torture_su_timer_LDFLAGS) $(torture_su_timer_OBJECTS) $(torture_su_timer_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
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/addrinfo.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/getopt.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/inet_ntop.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/inet_pton.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/localinfo.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/memccpy.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/memcspn.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/memmem.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/memspn.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/strcasestr.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/strtoull.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_addrinfo.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_alloc.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_alloc_lock.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_bm.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_default_log.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_errno.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_global_log.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_localinfo.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_log.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_md5.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_os_nw.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_osx_runloop.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_port.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_proxy.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_root.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_sprintf.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_strdup.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_strlst.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_tag.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_tag_io.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_tag_ref.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_taglist.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_time.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_time0.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_timer.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_uniqueid.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_vector.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/su_wait.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_htable.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_memmem.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_poll.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_su.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_su_osx.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/torture_rbtree.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/torture_su.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/torture_su_alloc.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/torture_su_bm.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/torture_su_port.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/torture_su_root.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/torture_su_root_osx.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/torture_su_tag.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/torture_su_time.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/torture_su_timer.Po at am__quote@
+
+.c.o:
+ at am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+ at am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ at am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at 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
+install-nobase_nodist_include_sofiaHEADERS: $(nobase_nodist_include_sofia_HEADERS)
+ @$(NORMAL_INSTALL)
+ test -z "$(include_sofiadir)" || $(mkdir_p) "$(DESTDIR)$(include_sofiadir)"
+ @$(am__vpath_adj_setup) \
+ list='$(nobase_nodist_include_sofia_HEADERS)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ $(am__vpath_adj) \
+ echo " $(nobase_nodist_include_sofiaHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(include_sofiadir)/$$f'"; \
+ $(nobase_nodist_include_sofiaHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(include_sofiadir)/$$f"; \
+ done
+
+uninstall-nobase_nodist_include_sofiaHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @$(am__vpath_adj_setup) \
+ list='$(nobase_nodist_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 $(LTLIBRARIES) $(PROGRAMS) $(SCRIPTS) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgdatadir)" "$(DESTDIR)$(include_sofiadir)" "$(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-binPROGRAMS clean-checkPROGRAMS clean-generic \
+ clean-libtool 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-nobase_nodist_include_sofiaHEADERS
+
+install-exec-am: install-binPROGRAMS
+
+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-binPROGRAMS uninstall-dist_pkgdataSCRIPTS \
+ uninstall-info-am uninstall-nobase_include_sofiaHEADERS \
+ uninstall-nobase_nodist_include_sofiaHEADERS
+
+.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \
+ clean-binPROGRAMS clean-checkPROGRAMS clean-generic \
+ clean-libtool 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-binPROGRAMS 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-nobase_nodist_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-binPROGRAMS \
+ uninstall-dist_pkgdataSCRIPTS uninstall-info-am \
+ uninstall-nobase_include_sofiaHEADERS \
+ uninstall-nobase_nodist_include_sofiaHEADERS
+
+
+sofia-sip/su_configure.h: sofia-sip/su_configure.h.in
+
+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) $<
+
+ at ENABLE_COVERAGE_TRUE@coverage:
+ at 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)
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+# 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:
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/addrinfo.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/addrinfo.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,163 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@page addrinfo Resolve network services
+ *
+ * @section synopsis Synopsis
+ *
+ * <tt>addrinfo [-pcn46] host service</tt>
+ *
+ * @section description Description
+ *
+ * The @em addrinfo utility will use su_getaddrinfo() to resolve the network
+ * services and print resolved names.
+ *
+ * @section options Options
+ *
+ * The @e addrinfo utility accepts following ccommand line options:
+ * <dl>
+ * <dt>-p</dt>
+ * <dd>use passive open.</dd>
+ * <dt>-c</dt>
+ * <dd>get canonic name.</dd>
+ * <dt>-n</dt>
+ * <dd>use numeric host names.</dd>
+ * <dt>-4</dt>
+ * <dd>IPv4 only.</dd>
+ * <dt>-6</dt>
+ * <dd>IPv6 only (but including mapped IPv4 addresses).</dd>
+ * </dl>
+ *
+ * @section bugs Reporting Bugs
+ * Report bugs to <sofia-sip-devel at lists.sourceforge.net>.
+ *
+ * @section author Author
+ * Written by Pekka Pessi <pekka -dot pessi -at- nokia -dot- com>
+ *
+ * @section copyright Copyright
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * This program is free software; see the source for copying conditions.
+ * There is @b NO warranty; not even for @b MERCHANTABILITY or <b>FITNESS
+ * FOR A PARTICULAR PURPOSE</b>.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "sofia-sip/su.h"
+
+char const help[] =
+"usage: addrinfo [-pnc46] [domainname]\n"
+"\t-p query for passive open\n"
+"\t-n use numeric host names\n"
+"\t-c ask for canonic names\n"
+"\t-4 IPv4 only\n"
+"\t-6 IPv6 only (but including mapped IPv4 addresses)\n"
+;
+
+int getopt(int argc, char * const argv[], char const *opstring);
+extern int optind;
+
+void usage(void)
+{
+ fputs(help, stderr);
+ exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+#if SU_HAVE_IN6
+ char buffer[INET6_ADDRSTRLEN];
+#else
+ char buffer[20];
+#endif
+ su_addrinfo_t hints[1] = {{ 0 }};
+ su_addrinfo_t *ai, *res = NULL;
+ char const *host, *service;
+ int error;
+
+ for (;;) {
+ switch(getopt(argc, argv, "ndp4c")) {
+ case '4': hints->ai_family = AF_INET; break;
+#if SU_HAVE_IN6
+ case '6': hints->ai_family = AF_INET6; break;
+#endif
+ case 'p': hints->ai_flags |= AI_PASSIVE; break;
+ case 'n': hints->ai_flags |= AI_NUMERICHOST; break;
+ case 'c': hints->ai_flags |= AI_CANONNAME; break;
+
+ case -1:
+ goto main;
+
+ default:
+ usage();
+ }
+ }
+
+ main:
+ if (optind + 1 >= argc)
+ usage();
+
+ service = argv[optind++];
+ host = argv[optind++];
+
+ su_init();
+
+ if ((error = su_getaddrinfo(host, service, hints, &res)) == 0) {
+ for (ai = res; ai; ai = ai->ai_next) {
+ su_sockaddr_t const *su = (su_sockaddr_t const *)ai->ai_addr;
+ unsigned port;
+
+#if SU_HAVE_IN6
+ if (su->su_family != AF_INET6 && su->su_family != AF_INET)
+ continue;
+#else
+ if (su->su_family != AF_INET)
+ continue;
+#endif
+
+ port = ntohs(su->su_port);
+ inet_ntop(ai->ai_family, SU_ADDR(su), buffer, sizeof(buffer));
+ printf("%d@[%s]:%u", ai->ai_protocol, buffer, port);
+
+ if (ai->ai_flags & AI_CANONNAME)
+ printf(" canon=%s", ai->ai_canonname);
+
+ puts("");
+ }
+ su_freeaddrinfo(res);
+ }
+ else {
+ fprintf(stderr, "addrinfo: %s\n", su_gai_strerror(error));
+ error = 1;
+ }
+
+ su_deinit();
+
+ return error;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/getopt.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/getopt.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,177 @@
+/*****************************************************************************
+ *
+ * MODULE NAME : GETOPT.C
+ *
+ * COPYRIGHTS:
+ * This module contains code made available by IBM
+ * Corporation on an AS IS basis. Any one receiving the
+ * module is considered to be licensed under IBM copyrights
+ * to use the IBM-provided source code in any way he or she
+ * deems fit, including copying it, compiling it, modifying
+ * it, and redistributing it, with or without
+ * modifications. No license under any IBM patents or
+ * patent applications is to be implied from this copyright
+ * license.
+ *
+ * A user of the module should understand that IBM cannot
+ * provide technical support for the module and will not be
+ * responsible for any consequences of use of the program.
+ *
+ * Any notices, including this one, are not to be removed
+ * from the module without the prior written consent of
+ * IBM.
+ *
+ * AUTHOR: Original author:
+ * G. R. Blair (BOBBLAIR at AUSVM1)
+ * Internet: bobblair at bobblair.austin.ibm.com
+ *
+ * Extensively revised by:
+ * John Q. Walker II, Ph.D. (JOHHQ at RALVM6)
+ * Internet: johnq at ralvm6.vnet.ibm.com
+ *
+ *****************************************************************************/
+
+/******************************************************************************
+ * getopt()
+ *
+ * The getopt() function is a command line parser. It returns the next
+ * option character in argv that matches an option character in opstring.
+ *
+ * The argv argument points to an array of argc+1 elements containing argc
+ * pointers to character strings followed by a null pointer.
+ *
+ * The opstring argument points to a string of option characters; if an
+ * option character is followed by a colon, the option is expected to have
+ * an argument that may or may not be separated from it by white space.
+ * The external variable optarg is set to point to the start of the option
+ * argument on return from getopt().
+ *
+ * The getopt() function places in optind the argv index of the next argument
+ * to be processed. The system initializes the external variable optind to
+ * 1 before the first call to getopt().
+ *
+ * When all options have been processed (that is, up to the first nonoption
+ * argument), getopt() returns EOF. The special option "--" may be used to
+ * delimit the end of the options; EOF will be returned, and "--" will be
+ * skipped.
+ *
+ * The getopt() function returns a question mark (?) when it encounters an
+ * option character not included in opstring. This error message can be
+ * disabled by setting opterr to zero. Otherwise, it returns the option
+ * character that was detected.
+ *
+ * If the special option "--" is detected, or all options have been
+ * processed, EOF is returned.
+ *
+ * Options are marked by either a minus sign (-) or a slash (/).
+ *
+ * No errors are defined.
+ *****************************************************************************/
+
+#include <stdio.h> /* for EOF */
+#include <string.h> /* for strchr() */
+
+
+/* static (global) variables that are specified as exported by getopt() */
+char *optarg = NULL; /* pointer to the start of the option argument */
+int optind = 1; /* number of the next argv[] to be evaluated */
+int opterr = 1; /* non-zero if a question mark should be returned
+ when a non-valid option character is detected */
+
+/* handle possible future character set concerns by putting this in a macro */
+#define _next_char(string) (char)(*(string+1))
+
+int getopt(int argc, char *argv[], char *opstring)
+{
+ static char *pIndexPosition = NULL; /* place inside current argv string */
+ char *pArgString = NULL; /* where to start from next */
+ char *pOptString; /* the string in our program */
+
+
+ if (pIndexPosition != NULL) {
+ /* we last left off inside an argv string */
+ if (*(++pIndexPosition)) {
+ /* there is more to come in the most recent argv */
+ pArgString = pIndexPosition;
+ }
+ }
+
+ if (pArgString == NULL) {
+ /* we didn't leave off in the middle of an argv string */
+ if (optind >= argc) {
+ /* more command-line arguments than the argument count */
+ pIndexPosition = NULL; /* not in the middle of anything */
+ return EOF; /* used up all command-line arguments */
+ }
+
+ /*---------------------------------------------------------------------
+ * If the next argv[] is not an option, there can be no more options.
+ *-------------------------------------------------------------------*/
+ pArgString = argv[optind++]; /* set this to the next argument ptr */
+
+ if (('/' != *pArgString) && /* doesn't start with a slash or a dash? */
+ ('-' != *pArgString)) {
+ --optind; /* point to current arg once we're done */
+ optarg = NULL; /* no argument follows the option */
+ pIndexPosition = NULL; /* not in the middle of anything */
+ return EOF; /* used up all the command-line flags */
+ }
+
+ /* check for special end-of-flags markers */
+ if ((strcmp(pArgString, "-") == 0) ||
+ (strcmp(pArgString, "--") == 0)) {
+ optarg = NULL; /* no argument follows the option */
+ pIndexPosition = NULL; /* not in the middle of anything */
+ return EOF; /* encountered the special flag */
+ }
+
+ pArgString++; /* look past the / or - */
+ }
+
+ if (':' == *pArgString) { /* is it a colon? */
+ /*---------------------------------------------------------------------
+ * Rare case: if opterr is non-zero, return a question mark;
+ * otherwise, just return the colon we're on.
+ *-------------------------------------------------------------------*/
+ return (opterr ? (int)'?' : (int)':');
+ }
+ else if ((pOptString = strchr(opstring, *pArgString)) == 0) {
+ /*---------------------------------------------------------------------
+ * The letter on the command-line wasn't any good.
+ *-------------------------------------------------------------------*/
+ optarg = NULL; /* no argument follows the option */
+ pIndexPosition = NULL; /* not in the middle of anything */
+ return (opterr ? (int)'?' : (int)*pArgString);
+ }
+ else {
+ /*---------------------------------------------------------------------
+ * The letter on the command-line matches one we expect to see
+ *-------------------------------------------------------------------*/
+ if (':' == _next_char(pOptString)) { /* is the next letter a colon? */
+ /* It is a colon. Look for an argument string. */
+ if ('\0' != _next_char(pArgString)) { /* argument in this argv? */
+ optarg = &pArgString[1]; /* Yes, it is */
+ }
+ else {
+ /*-------------------------------------------------------------
+ * The argument string must be in the next argv.
+ * But, what if there is none (bad input from the user)?
+ * In that case, return the letter, and optarg as NULL.
+ *-----------------------------------------------------------*/
+ if (optind < argc)
+ optarg = argv[optind++];
+ else {
+ optarg = NULL;
+ return (opterr ? (int)'?' : (int)*pArgString);
+ }
+ }
+ pIndexPosition = NULL; /* not in the middle of anything */
+ }
+ else {
+ /* it's not a colon, so just return the letter */
+ optarg = NULL; /* no argument follows the option */
+ pIndexPosition = pArgString; /* point to the letter we're on */
+ }
+ return (int)*pArgString; /* return the letter that matched */
+ }
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/inet_ntop.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/inet_ntop.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,183 @@
+/* Copyright (c) 1996 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <sys/types.h>
+
+#include "sofia-sip/su.h"
+
+/*
+ * WARNING: Don't even consider trying to compile this on a system where
+ * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
+ */
+
+static const char *inet_ntop4(const unsigned char *src, char *dst, size_t size);
+#if HAVE_SIN6
+static const char *inet_ntop6(const unsigned char *src, char *dst, size_t size);
+#endif
+
+/* char *
+ * inet_ntop(af, src, dst, size)
+ * convert a network format address to presentation format.
+ * return:
+ * pointer to presentation format address (`dst'), or NULL (see errno).
+ * author:
+ * Paul Vixie, 1996.
+ */
+const char *
+inet_ntop(int af, void const *src, char *dst, size_t size)
+{
+
+ switch (af) {
+ case AF_INET:
+ return inet_ntop4(src, dst, size);
+#if HAVE_SIN6
+ case AF_INET6:
+ return inet_ntop6(src, dst, size);
+#endif
+ default:
+ su_seterrno(EAFNOSUPPORT);
+ return NULL;
+ }
+ /* NOTREACHED */
+}
+
+/* const char *
+ * inet_ntop4(src, dst, size)
+ * format an IPv4 address, more or less like inet_ntoa()
+ * return:
+ * `dst' (as a const)
+ * notes:
+ * (1) uses no statics
+ * (2) takes a unsigned char* not an in_addr as input
+ * author:
+ * Paul Vixie, 1996.
+ */
+static const char *
+inet_ntop4(const unsigned char *src, char *dst, size_t size)
+{
+ static const char fmt[] = "%u.%u.%u.%u";
+ char tmp[sizeof "255.255.255.255"];
+
+ if (snprintf(tmp, sizeof tmp, fmt,
+ src[0], src[1], src[2], src[3]) >= size) {
+ su_seterrno(ENOSPC);
+ return NULL;
+ }
+
+ return strcpy(dst, tmp);
+}
+
+#if HAVE_SIN6
+/* const char *
+ * inet_ntop6(src, dst, size)
+ * convert IPv6 binary address into presentation (printable) format
+ * author:
+ * Paul Vixie, 1996.
+ */
+static const char *
+inet_ntop6(unsigned char const *src, char *dst, size_t size)
+{
+ /*
+ * Note that int32_t and int16_t need only be "at least" large enough
+ * to contain a value of the specified size. On some systems, like
+ * Crays, there is no such thing as an integer variable with 16 bits.
+ * Keep this in mind if you think this function should have been coded
+ * to use pointer overlays. All the world's not a VAX.
+ */
+ char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
+ struct { int base, len; } best = { -1 , 0 }, cur = { -1, 0 };
+ unsigned int words[8];
+ int i;
+
+ /*
+ * Preprocess:
+ * Copy the input (bytewise) array into a wordwise array.
+ * Find the longest run of 0x00's in src[] for :: shorthanding.
+ */
+ for (i = 0; i < 16; i += 2)
+ words[i / 2] = (src[i] << 8) | (src[i + 1]);
+ best.base = -1;
+ cur.base = -1;
+ for (i = 0; i < 8; i++) {
+ if (words[i] == 0) {
+ if (cur.base == -1)
+ cur.base = i, cur.len = 1;
+ else
+ cur.len++;
+ } else {
+ if (cur.base != -1) {
+ if (best.base == -1 || cur.len > best.len)
+ best = cur;
+ cur.base = -1;
+ }
+ }
+ }
+ if (cur.base != -1) {
+ if (best.base == -1 || cur.len > best.len)
+ best = cur;
+ }
+ if (best.base != -1 && best.len < 2)
+ best.base = -1;
+
+ /*
+ * Format the result.
+ */
+ tp = tmp;
+ for (i = 0; i < 8; i++) {
+ /* Are we inside the best run of 0x00's? */
+ if (best.base != -1 && i >= best.base &&
+ i < (best.base + best.len)) {
+ if (i == best.base)
+ *tp++ = ':';
+ continue;
+ }
+ /* Are we following an initial run of 0x00s or any real hex? */
+ if (i != 0)
+ *tp++ = ':';
+ /* Is this address an encapsulated IPv4? */
+ if (i == 6 && best.base == 0 &&
+ (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
+ if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp)))
+ return (NULL);
+ tp += strlen(tp);
+ break;
+ }
+ tp += sprintf(tp, "%x", words[i]);
+ }
+ /* Was it a trailing run of 0x00's? */
+ if (best.base != -1 && (best.base + best.len) == 8)
+ *tp++ = ':';
+ *tp++ = '\0';
+
+ /*
+ * Check for overflow, copy, and we're done.
+ */
+ if ((size_t)(tp - tmp) >= size) {
+ su_seterrno(ENOSPC);
+ return NULL;
+ }
+
+ return strcpy(dst, tmp);
+}
+#endif
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/inet_pton.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/inet_pton.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <string.h>
+#include <errno.h>
+
+#include "sofia-sip/su.h"
+
+/*
+ * WARNING: Don't even consider trying to compile this on a system where
+ * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
+ */
+
+static int inet_pton4(const char *src, unsigned char *dst);
+#if HAVE_SIN6
+static int inet_pton6(const char *src, unsigned char *dst);
+#endif
+
+/* int
+ * inet_pton(af, src, dst)
+ * convert from presentation format (which usually means ASCII printable)
+ * to network format (which is usually some kind of binary format).
+ * return:
+ * 1 if the address was valid for the specified address family
+ * 0 if the address wasn't valid (`dst' is untouched in this case)
+ * -1 if some other error occurred (`dst' is untouched in this case, too)
+ * author:
+ * Paul Vixie, 1996.
+ */
+int
+inet_pton(int af, const char * src, void * dst)
+{
+ switch (af) {
+ case AF_INET:
+ return (inet_pton4(src, dst));
+#if HAVE_SIN6
+ case AF_INET6:
+ return (inet_pton6(src, dst));
+#endif
+ default:
+ su_seterrno(EAFNOSUPPORT);
+ return (-1);
+ }
+ /* NOTREACHED */
+}
+
+/* int
+ * inet_pton4(src, dst)
+ * like inet_aton() but without all the hexadecimal and shorthand.
+ * return:
+ * 1 if `src' is a valid dotted quad, else 0.
+ * notice:
+ * does not touch `dst' unless it's returning 1.
+ * author:
+ * Paul Vixie, 1996.
+ */
+static int
+inet_pton4(const char *src, unsigned char *dst)
+{
+ int saw_digit, octets, ch;
+ unsigned char tmp[4], *tp;
+
+ saw_digit = 0;
+ octets = 0;
+ *(tp = tmp) = 0;
+ while ((ch = *src++) != '\0') {
+ if ('0' <= ch && ch <= '9') {
+ unsigned octet = *tp * 10 + ch - '0';
+
+ if (saw_digit && *tp == 0)
+ return (0);
+ if (octet > 255)
+ return (0);
+ *tp = octet;
+ if (!saw_digit) {
+ if (++octets > 4)
+ return (0);
+ saw_digit = 1;
+ }
+ } else if (ch == '.' && saw_digit) {
+ if (octets == 4)
+ return (0);
+ *++tp = 0;
+ saw_digit = 0;
+ } else
+ return (0);
+ }
+ if (octets < 4)
+ return (0);
+ memcpy(dst, tmp, 4);
+ return (1);
+}
+
+#if HAVE_SIN6
+
+/* int
+ * inet_pton6(src, dst)
+ * convert presentation level address to network order binary form.
+ * return:
+ * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
+ * notice:
+ * (1) does not touch `dst' unless it's returning 1.
+ * (2) :: in a full address is silently ignored.
+ * credit:
+ * inspired by Mark Andrews.
+ * author:
+ * Paul Vixie, 1996.
+ */
+static int
+inet_pton6(const char *src, unsigned char *dst)
+{
+ uint8_t tmp[16], *tp, *endp, *colonp;
+ const char *curtok;
+ int ch, saw_xdigit;
+ unsigned val;
+
+ memset((tp = tmp), '\0', sizeof tmp);
+ endp = tp + sizeof tmp;
+ colonp = NULL;
+ /* Leading :: requires some special handling. */
+ if (*src == ':')
+ if (*++src != ':')
+ return (0);
+ curtok = src;
+ saw_xdigit = 0;
+ val = 0;
+ while ((ch = *src++) != '\0') {
+ if (ch == ':') {
+ curtok = src;
+ if (!saw_xdigit) {
+ if (colonp)
+ return (0);
+ colonp = tp;
+ continue;
+ } else if (*src == '\0') {
+ return (0);
+ }
+ if (tp + 2 > endp)
+ return (0);
+ *tp++ = (unsigned char) (val >> 8) & 0xff;
+ *tp++ = (unsigned char) val & 0xff;
+ saw_xdigit = 0;
+ val = 0;
+ continue;
+ }
+ if (ch == '.' && ((tp + 4) <= endp) &&
+ inet_pton4(curtok, tp) > 0) {
+ tp += 4;
+ saw_xdigit = 0;
+ break; /* '\0' was seen by inet_pton4(). */
+ }
+
+ if ('0' <= ch && ch <= '9')
+ ch = ch - '0';
+ else if ('A' <= ch && ch <= 'F')
+ ch = ch - 'A' + 10;
+ else if ('a' <= ch && ch <= 'f')
+ ch = ch - 'a' + 10;
+ else
+ return (0);
+ val <<= 4;
+ val |= ch;
+ if (val > 0xffff)
+ return (0);
+ saw_xdigit = 1;
+ }
+ if (saw_xdigit) {
+ if (tp + 2 > endp)
+ return (0);
+ *tp++ = (unsigned char) (val >> 8) & 0xff;
+ *tp++ = (unsigned char) val & 0xff;
+ }
+ if (colonp != NULL) {
+ /*
+ * Since some memmove()'s erroneously fail to handle
+ * overlapping regions, we'll do the shift by hand.
+ */
+ const int n = tp - colonp;
+ int i;
+
+ if (tp == endp)
+ return (0);
+ for (i = 1; i <= n; i++) {
+ endp[- i] = colonp[n - i];
+ colonp[n - i] = 0;
+ }
+ tp = endp;
+ }
+ if (tp != endp)
+ return 0;
+ memcpy(dst, tmp, sizeof tmp);
+ return 1;
+}
+
+#endif
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/localinfo.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/localinfo.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,200 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@page localinfo list local network addresses
+ *
+ * @section synopsis Synopsis
+ *
+ * <tt>localinfo [-imdn46gslh] [domainname]</tt>
+ *
+ * @section description Description
+ *
+ * The @em localinfo utility will obtain the local network addresses
+ * and print them.
+ *
+ * @section options Options
+ *
+ * The @e localinfo utility accepts following command line options:
+ * <dl>
+ * <dt>-i</dt>
+ * <dd>include interface name.</dd>
+ * <dt>-m</dt>
+ * <dd>map IPv4 addresses.</dd>
+ * <dt>-d</dt>
+ * <dd>require a reverse DNS entry.</dd>
+ * <dt>-n</dt>
+ * <dd>use numeric host names.</dd>
+ * <dt>-4</dt>
+ * <dd>IPv4 only.</dd>
+ * <dt>-6</dt>
+ * <dd>IPv6 only (but including mapped IPv4 addresses).</dd>
+ * <dt>-g</dt>
+ * <dd>Global addresses.</dd>
+ * <dt>-s</dt>
+ * <dd>Site-level addresses.</dd>
+ * <dt>-l</dt>
+ * <dd>Link-level addresses.</dd>
+ * <dt>-h</dt>
+ * <dd>Host-internal addresses.</dd>
+ * </dl>
+ *
+ * @section examples Examples
+ *
+ * You want to find out local IPv6 addresses:
+ * @code
+ * $ localinfo -6
+ * @endcode
+ * You want to find out to link-local addresses
+ * @code
+ * $ localinfo -l -n
+ * @endcode
+ *
+ * @section bugs Reporting Bugs
+ * Report bugs to <sofia-sip-devel at lists.sourceforge.net>.
+ *
+ * @section author Author
+ * Written by Pekka Pessi <pekka -dot pessi -at- nokia -dot- com>
+ *
+ * @section copyright Copyright
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * This program is free software; see the source for copying conditions.
+ * There is @b NO warranty; not even for @b MERCHANTABILITY or <b>FITNESS
+ * FOR A PARTICULAR PURPOSE</b>.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "sofia-sip/su.h"
+#include "sofia-sip/su_localinfo.h"
+#include "su_module_debug.h"
+
+char const help[] =
+"usage: localinfo [-imdn46gslh] [domainname]\n"
+"\t-i include interface name\n"
+"\t-m map IPv4 addresses\n"
+"\t-d require DNS entry\n"
+"\t-n use numeric host names\n"
+"\t-4 IPv4 only\n"
+"\t-6 IPv6 only (but including mapped IPv4 addresses)\n"
+"\t-g Global addresses\n"
+"\t-s Site-level addresses\n"
+"\t-l Link-level addresses\n"
+"\t-h Host-internal addresses\n";
+
+int getopt(int argc, char * const argv[], char const *opstring);
+extern int optind;
+
+void usage(int returncode)
+{
+ fputs(help, stderr);
+ exit(returncode);
+}
+
+int main(int argc, char *argv[])
+{
+ char buffer[SU_ADDRSIZE];
+ su_localinfo_t hints[1] = {{ LI_CANONNAME }};
+ su_localinfo_t *li, *res = NULL;
+ int error;
+ int ifindex = 0;
+
+ if (argv[1] && strcmp(argv[1], "--help") == 0)
+ usage(0);
+
+ for (;;) {
+ switch(getopt(argc, argv, "iImdn46gslh")) {
+
+ case 'I': ifindex = 1; break;
+ case 'i': hints->li_flags |= LI_IFNAME; ifindex = 1; break;
+ case 'm': hints->li_flags |= LI_V4MAPPED; break;
+ case '4': hints->li_family = AF_INET; break;
+#if SU_HAVE_IN6
+ case '6': hints->li_family = AF_INET6; break;
+#endif
+ case 'd': hints->li_flags |= LI_NAMEREQD; break;
+ case 'n': hints->li_flags |= LI_NUMERIC; break;
+ case 'g': hints->li_scope |= LI_SCOPE_GLOBAL; break;
+ case 's': hints->li_scope |= LI_SCOPE_SITE; break;
+ case 'l': hints->li_scope |= LI_SCOPE_LINK; break;
+ case 'h': hints->li_scope |= LI_SCOPE_HOST; break;
+
+ case -1:
+ goto main;
+
+ default:
+ usage(1);
+ }
+ }
+
+ main:
+ if (optind < argc)
+ hints->li_canonname = argv[optind++];
+
+ if (optind < argc)
+ usage(1);
+
+ su_init();
+
+ if ((error = su_getlocalinfo(hints, &res)) == 0) {
+ for (li = res; li; li = li->li_next) {
+ if (li->li_flags & LI_NUMERIC) {
+ fputs(li->li_canonname, stdout);
+ }
+ else {
+ inet_ntop(li->li_family, SU_ADDR(li->li_addr),
+ buffer, sizeof(buffer));
+ printf("%s maddr=[%s]", li->li_canonname, buffer);
+ }
+ if (li->li_scope & LI_SCOPE_GLOBAL)
+ fputs(" scope=global", stdout);
+ else if (li->li_scope & LI_SCOPE_SITE)
+ fputs(" scope=site", stdout);
+ else if (li->li_scope & LI_SCOPE_LINK)
+ fputs(" scope=link", stdout);
+ else if (li->li_scope & LI_SCOPE_HOST)
+ fputs(" scope=host", stdout);
+ if (ifindex) {
+ if (li->li_ifname)
+ printf(" if[%d]=%s", li->li_index, li->li_ifname);
+ else
+ printf(" if[%d]", li->li_index);
+ }
+ puts("");
+ }
+ su_freelocalinfo(res);
+ }
+ else {
+ fprintf(stderr, "localinfo: %s\n", su_gli_strerror(error));
+ error = 1;
+ }
+
+ su_deinit();
+
+ return error;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/memccpy.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/memccpy.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,67 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@file memccpy.c
+ * @brief The memccpy() replacement function.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Nov 17 17:45:51 EET 2005 ppessi
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <limits.h>
+
+/**Copy memory until @a c is found.
+ *
+ * Copies no more than @a n bytes from memory area @a src to memory area @a
+ * dest, stopping after the character @a c is copied and found.
+ *
+ * @param dest pointer to destination area
+ * @param src pointer to source area
+ * @param c terminating byte
+ * @param n size of destination area
+ *
+ * @return
+ * Returns a pointer to the next character in @a dest after @a c,
+ * or NULL if @a c was not found in the first @a n characters of @a src.
+ */
+void *memccpy(void *dest, const void *src, int c, size_t n)
+{
+ char *d;
+ char const *s;
+
+ if (!src || !dest)
+ return dest;
+
+ for (d = dest, s = src; n-- > 0;) {
+ if (c == (*d++ = *s++))
+ return d;
+ }
+
+ return NULL;
+}
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/memcspn.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/memcspn.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,81 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@file memcspn.c
+ * @brief The memcspn() replacement function.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Nov 17 17:45:51 EET 2005 ppessi
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <limits.h>
+
+/**Search memory for bytes not in a given set.
+ *
+ * The memcspn() function calculates the length of the memory area @a mem
+ * which consists entirely of bytes not in @a reject.
+ *
+ * @param mem pointer to memory area
+ * @param memlen size of @a mem in bytes
+ * @param reject pointer to table containing bytes to reject
+ * @param rejectlen size of @a reject table
+ *
+ * @return
+ * The memspn() function returns the number of bytes in the memory area @a
+ * which consists entirely of bytes not in @a reject.
+ * @par
+ * If @a rejectlen is 0, or @a reject is NULL, it returns @a memlen, size of
+ * the memory area.
+ */
+size_t memcspn(const void *mem, size_t memlen,
+ const void *reject, size_t rejectlen)
+{
+ size_t i;
+
+ unsigned char const *m = mem, *r = reject;
+
+ char rejected[UCHAR_MAX + 1];
+
+ if (rejectlen == 0 || reject == 0)
+ return memlen;
+
+ if (mem == NULL || memlen == 0)
+ return 0;
+
+ memset(rejected, 0, sizeof rejected);
+
+ for (i = 0; i < rejectlen; i++)
+ rejected[r[i]] = 1;
+
+ for (i = 0; i < memlen; i++)
+ if (rejected[m[i]])
+ break;
+
+ return i;
+}
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/memmem.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/memmem.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,57 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@file memmem.c
+ * @brief Backup implementation of memmem()
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Sat Apr 12 19:32:33 2003 ppessi
+ *
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+/* Naive implementation of memmem() */
+void *memmem(const void *haystack, size_t haystacklen,
+ const void *needle, size_t needlelen)
+{
+ size_t i;
+ char const *hs = haystack;
+
+ if (needlelen == 0)
+ return (void *)haystack;
+
+ if (needlelen > haystacklen || haystack == NULL || needle == NULL)
+ return NULL;
+
+ for (i = 0; i <= haystacklen - needlelen; i++) {
+ if (memcmp(hs + i, needle, needlelen) == 0)
+ return (void *)(hs + i);
+ }
+
+ return NULL;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/memspn.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/memspn.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,75 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@file memspn.c
+ * The memspn() replacement function.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Sat Apr 12 19:32:33 2003 ppessi
+ *
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <limits.h>
+
+/**Scan memory for a set of bytes.
+ *
+ * The memspn() function calculates the length of the memory area @a mem
+ * which consists entirely of bytes in @a accept.
+ *
+ * @param mem pointer to memory area
+ * @param memlen size of @a mem in bytes
+ * @param accept pointer to table containing bytes to accept
+ * @param acceptlen size of @a accept table
+ *
+ * @return
+ * The memspn() function returns the number of bbytes in the memory area @a
+ * which consists entirely of bytes in @a accept.
+ */
+size_t memspn(const void *mem, size_t memlen,
+ const void *accept, size_t acceptlen)
+{
+ size_t i;
+
+ unsigned char const *m = mem, *a = accept;
+
+ char accepted[UCHAR_MAX + 1];
+
+ if (mem == NULL || memlen == 0 || acceptlen == 0 || accept == NULL)
+ return 0;
+
+ memset(accepted, 0, sizeof accepted);
+
+ for (i = 0; i < acceptlen; i++)
+ accepted[a[i]] = 1;
+
+ for (i = 0; i < memlen; i++)
+ if (!accepted[m[i]])
+ break;
+
+ return i;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/run_addrinfo
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/run_addrinfo Thu Dec 21 01:30:28 2006
@@ -0,0 +1,3 @@
+#! /bin/sh
+# Test addrinfo with -n and echo port on 127.0.0.1
+./addrinfo -n echo 127.0.0.1
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/run_localinfo
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/run_localinfo Thu Dec 21 01:30:28 2006
@@ -0,0 +1,3 @@
+#! /bin/sh
+# Test localinfo with -n flag
+./localinfo -n | sed 's:^: :'
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/run_test_su
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/run_test_su Thu Dec 21 01:30:28 2006
@@ -0,0 +1,19 @@
+#! /bin/bash
+
+rc=0
+
+if $VALGRIND ./test_su ; then
+ echo PASS: multithread test_su
+else
+ echo FAIL: multithread test_su failed
+ rc=1
+fi
+
+if $VALGRIND ./test_su -s ; then
+ echo PASS: singlethread test_su
+else
+ echo FAIL: singlethread test_su failed
+ rc=1
+fi
+
+exit $rc
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/htable.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/htable.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,258 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef HTABLE_H
+/** Defined when <sofia-sip/htable.h> has been included. */
+#define HTABLE_H
+
+/**@ingroup su_htable
+ * @file sofia-sip/htable.h
+ *
+ * Hash tables templates.
+ *
+ * This file contain a hash table template for C. The hash tables are
+ * resizeable, and they usually contain pointers to entries. The
+ * declaration for template datatypes is instantiated with macro
+ * HTABLE_DECLARE(). The prototypes for hashing functions are instantiated
+ * with macro HTABLE_PROTOS(). The implementation is instantiated with
+ * macro HTABLE_BODIES().
+ *
+ * The hash table template is most efficient when the hash value is
+ * precalculated and stored in each entry. The hash "function" given to the
+ * HTABLE_BODIES() would then be something like macro
+ * @code
+ * #define HTABLE_ENTRY_HASH(e) ((e)->e_hash_value)
+ * @endcode
+ *
+ * When a entry with new identical hash key is added to the table, it can be
+ * either @e inserted (before any other entry with same key value) or
+ * @e appended.
+ *
+ * Example code can be found from <htable_test.c>.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Sep 25 17:42:40 2001 ppessi
+ */
+
+typedef unsigned long hash_value_t;
+
+/** Minimum size of hash table */
+#define HTABLE_MIN_SIZE 31
+
+/** Declare hash table structure type.
+ *
+ * The macro HTABLE_DECLARE() expands to a declaration for hash table
+ * structure. The its typedef will be <em>prefix</em><code>_t</code>, the
+ * field names start withb @a pr. The entry type is @a entry_t.
+ *
+ * @param prefix hash table type and function prefix
+ * @param pr hash table field prefix
+ * @param entry_t entry type
+ */
+#define HTABLE_DECLARE(prefix, pr, entry_t) \
+ HTABLE_DECLARE_WITH(prefix, pr, entry_t, unsigned, hash_value_t)
+
+#define HTABLE_DECLARE_WITH(prefix, pr, entry_t, size_t, hash_value_t) \
+ typedef struct prefix##_s { \
+ size_t pr##_size; \
+ size_t pr##_used; \
+ entry_t**pr##_table; /**< Hash table itself */ \
+ } prefix##_t
+
+#ifndef HTABLE_SCOPE
+/** Default scope for hash table functions. */
+#define HTABLE_SCOPE static inline
+#endif
+
+/** Prototypes for hash table
+ *
+ * The macro HTABLE_PROTOS() expands to the prototypes of hash table
+ * functions. The function and type names start with @a prefix, the field
+ * names start with @a pr. The entry type is @a entry_t.
+ *
+ * @param prefix hash table type and function prefix
+ * @param pr hash table field prefix
+ * @param entry_t entry type
+ */
+#define HTABLE_PROTOS(prefix, pr, entry_t) \
+ HTABLE_PROTOS_WITH(prefix, pr, entry_t, unsigned, hash_value_t)
+
+#define HTABLE_PROTOS_WITH(prefix, pr, entry_t, size_t, hash_value_t) \
+HTABLE_SCOPE int prefix##_resize(su_home_t *, prefix##_t pr[1], size_t); \
+HTABLE_SCOPE int prefix##_is_full(prefix##_t const *); \
+HTABLE_SCOPE entry_t **prefix##_hash(prefix##_t const *, hash_value_t hv); \
+HTABLE_SCOPE entry_t **prefix##_next(prefix##_t const *, entry_t * const *ee); \
+HTABLE_SCOPE void prefix##_append(prefix##_t *pr, entry_t const *e); \
+HTABLE_SCOPE void prefix##_insert(prefix##_t *pr, entry_t const *e); \
+HTABLE_SCOPE void prefix##_remove(prefix##_t *, entry_t const *e)
+
+/** Hash table implementation.
+ *
+ * The macro HTABLE_BODIES() expands the hash table functions. The function
+ * and type names start with @a prefix, the field names start with @a pr.
+ * The entry type is @a entry_t. The function (or macro) name returning
+ * hash value of each entry is given as @a hfun.
+ *
+ * @param prefix hash table type and function prefix
+ * @param pr hash table field prefix
+ * @param entry_t entry type
+ * @param hfun function or macro returning hash value of entry
+ */
+#define HTABLE_BODIES(prefix, pr, entry_t, hfun) \
+ HTABLE_BODIES_WITH(prefix, pr, entry_t, hfun, unsigned, hash_value_t)
+
+#define HTABLE_BODIES_WITH(prefix, pr, entry_t, hfun, size_t, hash_value_t) \
+/** Reallocate new hash table */ \
+HTABLE_SCOPE \
+int prefix##_resize(su_home_t *home, \
+ prefix##_t pr[], \
+ size_t new_size) \
+{ \
+ entry_t **new_hash; \
+ entry_t **old_hash = pr->pr##_table; \
+ size_t old_size; \
+ size_t i, j, i0; \
+ unsigned again = 0; \
+ size_t used = 0, collisions = 0; \
+\
+ if (new_size == 0) \
+ new_size = 2 * pr->pr##_size + 1; \
+ if (new_size < HTABLE_MIN_SIZE) \
+ new_size = HTABLE_MIN_SIZE; \
+\
+ if (!(new_hash = su_zalloc(home, sizeof(*new_hash) * new_size))) \
+ return -1; \
+\
+ old_size = pr->pr##_size; \
+\
+ do for (j = 0; j < old_size; j++) { \
+ if (!old_hash[j]) \
+ continue; \
+\
+ if (again < 2 && hfun(old_hash[j]) % old_size > j) { \
+ /* Wrapped, leave entry for second pass */ \
+ again = 1; continue; \
+ } \
+\
+ i0 = hfun(old_hash[j]) % new_size; \
+\
+ for (i = i0; new_hash[i]; i = (i + 1) % new_size, assert(i != i0)) \
+ collisions++; \
+\
+ new_hash[i] = old_hash[j], old_hash[j] = NULL; \
+ used++; \
+ } \
+ while (again++ == 1); \
+\
+ pr->pr##_table = new_hash, pr->pr##_size = new_size; \
+\
+ assert(pr->pr##_used == used); \
+\
+ return 0; \
+} \
+\
+HTABLE_SCOPE \
+int prefix##_is_full(prefix##_t const *pr) \
+{ \
+ return pr->pr##_table == NULL || 3 * pr->pr##_used > 2 * pr->pr##_size; \
+} \
+\
+HTABLE_SCOPE \
+entry_t **prefix##_hash(prefix##_t const *pr, hash_value_t hv) \
+{ \
+ return pr->pr##_table + hv % pr->pr##_size; \
+} \
+\
+HTABLE_SCOPE \
+entry_t **prefix##_next(prefix##_t const *pr, entry_t * const *ee) \
+{ \
+ if (++ee < pr->pr##_table + pr->pr##_size && ee >= pr->pr##_table) \
+ return (entry_t **)ee; \
+ else \
+ return pr->pr##_table; \
+} \
+\
+HTABLE_SCOPE \
+void prefix##_append(prefix##_t *pr, entry_t const *e) \
+{ \
+ entry_t **ee; \
+\
+ pr->pr##_used++; \
+ for (ee = prefix##_hash(pr, hfun(e)); *ee; ee = prefix##_next(pr, ee)) \
+ ; \
+ *ee = (entry_t *)e; \
+} \
+\
+HTABLE_SCOPE \
+void prefix##_insert(prefix##_t *pr, entry_t const *e) \
+{ \
+ entry_t *e0, **ee; \
+\
+ pr->pr##_used++; \
+ /* Insert entry into hash table (before other entries with same hash) */ \
+ for (ee = prefix##_hash(pr, hfun(e)); \
+ (e0 = *ee); \
+ ee = prefix##_next(pr, ee)) \
+ *ee = (entry_t *)e, e = e0; \
+ *ee = (entry_t *)e; \
+} \
+\
+HTABLE_SCOPE \
+void prefix##_remove(prefix##_t *pr, entry_t const *e) \
+{ \
+ size_t i, j, k; \
+ size_t size = pr->pr##_size; \
+ entry_t **htable = pr->pr##_table; \
+\
+ if (!e) return; \
+\
+ /* Search for entry */ \
+ for (i = hfun(e) % size; htable[i]; i = (i + 1) % size) \
+ if (e == htable[i]) \
+ break; \
+\
+ /* Entry is not in table? */ \
+ assert(htable[i]); if (!e) return; \
+\
+ /* Move table entries towards their primary place */ \
+ for (j = (i + 1) % size; htable[j]; j = (j + 1) % size) { \
+ /* k is primary place for entry */ \
+ k = hfun(htable[j]) % size; \
+ if (k == j) /* entry is in its primary place? */ \
+ continue; \
+ /* primary place is between i and j - do not move this to i */ \
+ if (j > i ? (i < k && k < j) : (i < k || k < j)) \
+ continue; \
+\
+ htable[i] = htable[j], i = j; \
+ } \
+\
+ pr->pr##_used--; \
+\
+ htable[i] = NULL; \
+} \
+extern int prefix##_dummy
+
+#endif /** !defined(HTABLE_H) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/htable2.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/htable2.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,266 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef HTABLE2_H
+/** Defined when <sofia-sip/htable2.h> has been included. */
+#define HTABLE2_H
+
+/**@file sofia-sip/htable2.h
+ *
+ * Hash tables templates, take 2.
+ *
+ * Note: this version can handle structures as entries, and it can be used
+ * without <su_alloc.h>.
+ *
+ * This file contain a hash table template for C. The hash tables are
+ * resizeable, and they usually contain pointers to entries. The
+ * declaration for template datatypes is instantiated with macro
+ * HTABLE2_DECLARE(). The prototypes for hashing functions are instantiated
+ * with macro HTABLE2_PROTOS(). The implementation is instantiated with
+ * macro HTABLE2_BODIES().
+ *
+ * The hash table template is most efficient when the hash value is
+ * precalculated and stored in each entry. The hash "function" given to the
+ * HTABLE2_BODIES() would then be something like macro
+ * @code
+ * #define HTABLE2_ENTRY_HASH(e) ((e).e_hash_value)
+ * @endcode
+ *
+ * When a entry with new identical hash key is added to the table, it can be
+ * either @e inserted (before any other entry with same key value) or
+ * @e appended.
+ *
+ * Example code can be found from <htable_test.c>.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Tue Sep 25 17:42:40 2001 ppessi
+ *
+ */
+
+typedef unsigned long hash_value_t;
+
+/** Minimum size of hash table */
+#define HTABLE2_MIN_SIZE 31
+
+/** Declare hash table structure type.
+ *
+ * The macro HTABLE2_DECLARE() expands to a declaration for hash table
+ * structure. The its typedef will be <em>prefix</em><code>_t</code>, the
+ * field names start with @a pr. The entry type is @a entrytype.
+ *
+ * @param sname name of struct
+ * @param prefix hash table type and function prefix
+ * @param pr hash table field prefix
+ * @param entrytype entry type
+ */
+#define HTABLE2_DECLARE(sname, prefix, pr, entrytype) \
+struct sname { \
+ unsigned pr##size; \
+ unsigned pr##used; \
+ entrytype *pr##table; /**< Hash table itself */ \
+}
+
+#ifndef HTABLE2_SCOPE
+/** Default scope for hash table functions. */
+#define HTABLE2_SCOPE static inline
+#endif
+
+/** Prototypes for hash table
+ *
+ * The macro HTABLE2_PROTOS() expands to the prototypes of hash table
+ * functions. The function and type names start with @a prefix, the field
+ * names start with @a pr. The entry type is @a entrytype.
+
+ * @param type hash table typedef
+ * @param prefix function prefix
+ * @param pr hash table field prefix
+ * @param entrytype entry type
+ */
+#define HTABLE2_PROTOS(type, prefix, pr, entrytype) \
+HTABLE2_SCOPE int prefix##_resize(void *a, type pr[1], unsigned); \
+HTABLE2_SCOPE int prefix##_is_full(type const *); \
+HTABLE2_SCOPE entrytype *prefix##_hash(type const *, hash_value_t hv); \
+HTABLE2_SCOPE entrytype *prefix##_next(type const *, entrytype *ee); \
+HTABLE2_SCOPE void prefix##_append(type *pr, entrytype e); \
+HTABLE2_SCOPE void prefix##_insert(type *pr, entrytype e); \
+HTABLE2_SCOPE int prefix##_remove(type *, entrytype const e)
+
+/** Hash table implementation.
+ *
+ * The macro HTABLE2_BODIES() expands the hash table functions. The function
+ * and type names start with @a prefix, the field names start with @a pr.
+ * The entry type is @a entrytype. The function (or macro) name returning
+ * hash value of each entry is given as @a hfun.
+ *
+ * @param type hash table type
+ * @param prefix function prefix for hash table
+ * @param pr field prefix for hash table
+ * @param entrytype type of entry element
+ * @param hfun function or macro returning hash value of entry
+ * @param is_used function or macro returning true if entry is occupied
+ * @param reclaim function or macro zeroing entry
+ * @param is_equal equality test
+ * @param halloc function allocating or freeing memory
+ */
+#define HTABLE2_BODIES(type, prefix, pr, entrytype, \
+ hfun, is_used, reclaim, is_equal, halloc) \
+/** Reallocate new hash table */ \
+HTABLE2_SCOPE \
+int prefix##_resize(void *realloc_arg, \
+ type pr[1], \
+ unsigned new_size) \
+{ \
+ entrytype *new_hash; \
+ entrytype *old_hash = pr->pr##table; \
+ unsigned old_size; \
+ unsigned i, j, i0; \
+ unsigned again = 0, used = 0, collisions = 0; \
+\
+ (void)realloc_arg; \
+\
+ if (new_size == 0) \
+ new_size = 2 * pr->pr##size + 1; \
+ if (new_size < HTABLE2_MIN_SIZE) \
+ new_size = HTABLE2_MIN_SIZE; \
+\
+ if (!(new_hash = halloc(realloc_arg, NULL, sizeof(*new_hash) * new_size))) \
+ return -1; \
+\
+ memset(new_hash, 0, sizeof(*new_hash) * new_size); \
+ old_size = pr->pr##size; \
+\
+ do for (j = 0; j < old_size; j++) { \
+ if (!is_used(old_hash[j])) \
+ continue; \
+\
+ if (again < 2 && hfun(old_hash[j]) % old_size > j) { \
+ /* Wrapped, leave entry for second pass */ \
+ again = 1; continue; \
+ } \
+\
+ i0 = hfun(old_hash[j]) % new_size; \
+\
+ for (i = i0; is_used(new_hash[i]); \
+ i = (i + 1) % new_size, assert(i != i0)) \
+ collisions++; \
+\
+ new_hash[i] = old_hash[j]; reclaim(&old_hash[j]); \
+ used++; \
+ } \
+ while (again++ == 1); \
+\
+ pr->pr##table = new_hash, pr->pr##size = new_size; \
+\
+ if (old_hash) old_hash = halloc(realloc_arg, old_hash, 0); \
+\
+ assert(pr->pr##used == used);\
+\
+ return 0; \
+} \
+\
+HTABLE2_SCOPE \
+int prefix##_is_full(type const *pr) \
+{ \
+ return pr->pr##table == NULL || 3 * pr->pr##used > 2 * pr->pr##size; \
+} \
+\
+HTABLE2_SCOPE \
+entrytype *prefix##_hash(type const *pr, hash_value_t hv) \
+{ \
+ return pr->pr##table + hv % pr->pr##size; \
+} \
+\
+HTABLE2_SCOPE \
+entrytype *prefix##_next(type const *pr, entrytype *ee) \
+{ \
+ if (++ee < pr->pr##table + pr->pr##size && ee >= pr->pr##table) \
+ return ee; \
+ else \
+ return pr->pr##table; \
+} \
+\
+HTABLE2_SCOPE \
+void prefix##_append(type *pr, entrytype e) \
+{ \
+ entrytype *ee; \
+\
+ pr->pr##used++; \
+ for (ee = prefix##_hash(pr, hfun(e)); \
+ is_used(*ee); \
+ ee = prefix##_next(pr, ee)) \
+ ; \
+ *ee = e; \
+} \
+\
+HTABLE2_SCOPE \
+void prefix##_insert(type *pr, entrytype e) \
+{ \
+ entrytype e0; \
+ entrytype *ee; \
+\
+ pr->pr##used++; \
+ /* Insert entry into hash table (before other entries with same hash) */ \
+ for (ee = prefix##_hash(pr, hfun(e)); \
+ is_used((*ee)); \
+ ee = prefix##_next(pr, ee)) \
+ *ee = e, e = e0; \
+ *ee = e; \
+} \
+\
+HTABLE2_SCOPE \
+int prefix##_remove(type *pr, entrytype const e) \
+{ \
+ unsigned i, j, k, size = pr->pr##size; \
+ entrytype *htable = pr->pr##table; \
+\
+ /* Search for entry */ \
+ for (i = hfun(e) % size; is_used(htable[i]); i = (i + 1) % size) \
+ if (is_equal(e, htable[i])) \
+ break; \
+\
+ assert(is_used(htable[i])); if (!is_used(htable[i])) return -1; \
+\
+ /* Move table entries towards their primary place */ \
+ for (j = (i + 1) % size; is_used(htable[j]); j = (j + 1) % size) { \
+ /* k is primary place for entry */ \
+ k = hfun(htable[j]) % size; \
+ if (k == j) /* entry is in its primary place? */ \
+ continue; \
+ /* primary place is between i and j - do not move this to i */ \
+ if (j > i ? (i < k && k < j) : (i < k || k < j)) \
+ continue; \
+\
+ htable[i] = htable[j], i = j; \
+ } \
+\
+ pr->pr##used--; \
+\
+ reclaim(&htable[i]); \
+\
+ return 0; \
+} \
+extern int const prefix##_dummy
+
+#endif /** !defined(HTABLE2_H) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/rbtree.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/rbtree.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,673 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef RBTREE_H
+/** Defined when <sofia-sip/rbtree.h> has been included. */
+#define RBTREE_H
+
+/**@file sofia-sip/rbtree.h
+ *
+ * Red-black tree.
+ *
+ * This file contain a red-black-tree template for C. The red-black-tree is
+ * a balanced binary tree containing structures as nodes.
+ *
+ * The prototypes for red-black-tree functions are declared with macro
+ * RBTREE_PROTOS(). The implementation is instantiated with macro
+ * RBTREE_BODIES().
+ *
+ * When a entry with new identical key is added to the tree, it can be
+ * either @e inserted (replacing other node with same key value) or @e
+ * appended.
+ *
+ * Example code can be found from <rbtree_test.c>.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Tue Sep 7 19:45:11 EEST 2004 ppessi
+ *
+ */
+
+#if DOCUMENTATION_ONLY
+/** Type used for rbtree nodes. */
+typedef struct node Type;
+#endif
+
+ /* x c
+ * / \ / \
+ * Convert a c into x d
+ * / \ / \
+ * b d a b
+ */
+
+#define RBTREE_LEFT_ROTATE(prefix, Type, left, right, parent) \
+static inline \
+void prefix ## _left_rotate(Type **top, Type *x) \
+{ \
+ Type *c = right(x), *dad = parent(x); assert(c); \
+ \
+ if ((right(x) = left(c))) \
+ parent(right(x)) = x; \
+ \
+ if (!(parent(c) = dad)) \
+ *top = c; \
+ else if (left(dad) == x) \
+ left(dad) = c; \
+ else \
+ assert(right(dad) == x), right(dad) = c; \
+ \
+ left(c) = x; \
+ parent(x) = c; \
+} \
+extern int const prefix##_dummy
+
+ /* x c
+ * / \ / \
+ * Convert c f into a x
+ * / \ / \
+ * a d d f
+ */
+
+#define RBTREE_RIGHT_ROTATE(prefix, Type, left, right, parent) \
+static inline \
+void prefix ## _right_rotate(Type **top, Type *x) \
+{ \
+ Type *c = left(x), *dad = parent(x); assert(c); \
+ \
+ if ((left(x) = right(c))) \
+ parent(left(x)) = x; \
+ \
+ if (!(parent(c) = dad)) \
+ *top = c; \
+ else if (right(dad) == x) \
+ right(dad) = c; \
+ else \
+ assert(left(dad) == x), left(dad) = c; \
+ \
+ right(c) = x; \
+ parent(x) = c; \
+} \
+extern int const prefix##_dummy
+
+#define RBTREE_BALANCE_INSERT1(prefix, Type, left, right, parent, IS_RED, SET_RED, IS_BLACK, SET_BLACK) \
+static inline \
+void prefix ## _balance_insert(Type **top, Type *node) \
+{ \
+ Type *dad, *uncle, *granddad; \
+} \
+extern int const prefix##_dummy
+
+
+/* Balance Red-Black binary tree after inserting node @a n.
+ *
+ * The function red_black_balance_insert() balances a red-black tree after
+ * insertion.
+ *
+ * RED(node) - set node as red
+ */
+#define RBTREE_BALANCE_INSERT(prefix, Type, left, right, parent, IS_RED, SET_RED, IS_BLACK, SET_BLACK) \
+static inline \
+void prefix ## _balance_insert(Type **top, Type *node) \
+{ \
+ Type *dad, *uncle, *granddad; \
+ \
+ SET_RED(node); \
+ \
+ for (dad = parent(node); node != *top && IS_RED(dad); dad = parent(node)) { \
+ /* Repeat until we are parent or we have a black dad */ \
+ granddad = parent(dad); assert(granddad); \
+ if (dad == left(granddad)) { \
+ uncle = right(granddad); \
+ if (IS_RED(uncle)) { \
+ SET_BLACK(dad); SET_BLACK(uncle); SET_RED(granddad); \
+ node = granddad; \
+ } else { \
+ if (node == right(dad)) { \
+ prefix##_left_rotate(top, node = dad); \
+ dad = parent(node); assert(dad); \
+ granddad = parent(dad); assert(granddad); \
+ } \
+ SET_BLACK(dad); \
+ SET_RED(granddad); \
+ prefix##_right_rotate(top, granddad); \
+ } \
+ } else { assert(dad == right(granddad)); \
+ uncle = left(granddad); \
+ if (IS_RED(uncle)) { \
+ SET_BLACK(dad); SET_BLACK(uncle); SET_RED(granddad); \
+ node = granddad; \
+ } else { \
+ if (node == left(dad)) { \
+ prefix##_right_rotate(top, node = dad); \
+ dad = parent(node); assert(dad); \
+ granddad = parent(dad); assert(granddad); \
+ } \
+ SET_BLACK(dad); \
+ SET_RED(granddad); \
+ prefix##_left_rotate(top, granddad); \
+ } \
+ } \
+ } \
+ \
+ assert(*top); \
+ \
+ SET_BLACK((*top)); \
+} \
+extern int const prefix##_dummy
+
+#define RBTREE_BALANCE_DELETE(prefix, Type, left, right, parent, \
+ IS_RED, SET_RED, IS_BLACK, SET_BLACK, \
+ COPY_COLOR) \
+static inline \
+void prefix##_balance_delete(Type **top, Type *node) \
+{ \
+ Type *dad, *brother; \
+ \
+ for (dad = parent(node); node != *top && IS_RED(dad); dad = parent(node)) { \
+ if (node == left(dad)) { \
+ brother = right(dad); \
+ \
+ if (!brother) { \
+ node = dad; \
+ continue; \
+ } \
+ \
+ assert(IS_BLACK(brother)); \
+ \
+ if (IS_BLACK(left(brother)) && IS_BLACK(right(brother))) { \
+ SET_RED(brother); \
+ node = dad; \
+ continue; \
+ } \
+ \
+ if (IS_BLACK(right(brother))) { \
+ SET_RED(brother); \
+ SET_BLACK(left(brother)); \
+ prefix##_right_rotate(top, brother); \
+ brother = right(dad); \
+ } \
+ \
+ COPY_COLOR(brother, dad); \
+ SET_BLACK(dad); \
+ if (right(brother)) \
+ SET_BLACK(right(brother)); \
+ prefix##_left_rotate(top, dad); \
+ node = *top; \
+ break; \
+ } else { \
+ assert(node == right(dad)); \
+ \
+ brother = left(dad); \
+ \
+ if (!brother) { \
+ node = dad; \
+ continue; \
+ } \
+ \
+ assert(IS_BLACK(brother)); \
+ \
+ if (IS_BLACK(left(brother)) && IS_BLACK(right(brother))) { \
+ SET_RED(brother); \
+ node = dad; \
+ continue; \
+ } \
+ \
+ if (IS_BLACK(left(brother))) { \
+ SET_BLACK(right(brother)); \
+ SET_RED(brother); \
+ prefix##_left_rotate(top, brother); \
+ brother = left(dad); \
+ } \
+ \
+ COPY_COLOR(brother, parent(node)); \
+ SET_BLACK(parent(node)); \
+ if (left(brother)) \
+ SET_BLACK(left(brother)); \
+ prefix##_right_rotate(top, dad); \
+ node = *top; \
+ break; \
+ } \
+ } \
+ \
+ SET_BLACK(node); \
+} \
+extern int const prefix##_dummy
+
+#if DOCUMENTATION_ONLY
+/**Insert a @a node into the @a tree.
+ *
+ * @param tree pointer to the root of the tree
+ * @param node pointer to node to be inserted
+ * @param return_old return value parameter for matching node
+ * already in the @a tree
+ *
+ * @retval 0 if node was inserted
+ * @retval -1 if there already was an matching node
+ * and return_old is NULL.
+ */
+int rbtree_insert(Type **tree, Type *node, Type **return_old);
+#endif
+
+/* Insert node into tree. */
+#define RBTREE_INSERT(SCOPE, prefix, Type, left, right, parent, \
+ IS_RED, SET_RED, IS_BLACK, SET_BLACK, COPY_COLOR, \
+ CMP, REMOVE, INSERT) \
+SCOPE \
+int prefix ## _insert(Type **const tree, \
+ Type * const node, \
+ Type **return_old) \
+{ \
+ Type *old, *dad, **slot; \
+ \
+ if (tree == NULL || node == NULL) return -1; \
+ \
+ for (slot = tree, old = *slot, dad = NULL; old; old = *slot) { \
+ int result = CMP(node, old); \
+ if (result < 0) \
+ dad = old, slot = &(left(old)); \
+ else if (result > 0) \
+ dad = old, slot = &(right(old)); \
+ else \
+ break; \
+ } \
+ \
+ if (old == node) \
+ old = NULL; \
+ else if (old) { \
+ if (!return_old) return -1; \
+ \
+ if ((left(node) = left(old))) \
+ parent(left(node)) = node; \
+ if ((right(node) = right(old))) \
+ parent(right(node)) = node; \
+ \
+ if (!(parent(node) = parent(old))) \
+ *tree = node; \
+ else if (left(parent(node)) == old) \
+ left(parent(node)) = node; \
+ else assert(right(parent(node)) == old), \
+ right(parent(node)) = node; \
+ \
+ COPY_COLOR(node, old); \
+ \
+ REMOVE(old); \
+ \
+ } else { \
+ *slot = node; \
+ parent(node) = dad; \
+ \
+ if (tree != slot) { \
+ prefix##_balance_insert(tree, node); \
+ } else { \
+ SET_BLACK(node); \
+ } \
+ } \
+ \
+ INSERT(node); \
+ \
+ if (return_old) \
+ *return_old = old; \
+ \
+ return 0; \
+} \
+extern int const prefix##_dummy
+
+#if DOCUMENTATION_ONLY
+/** Append @a a node into the @a tree.
+ *
+ * @param tree pointer to the root of the tree
+ * @param node pointer to node to be appended
+ *
+ * @retval 0 when successful (always)
+ */
+int rbtree_append(Type ** tree,
+ Type * node);
+#endif
+
+/* Define function appending a node into the tree */
+#define RBTREE_APPEND(SCOPE, prefix, Type, left, right, parent, \
+ IS_RED, SET_RED, IS_BLACK, SET_BLACK, COPY_COLOR, \
+ CMP, REMOVE, INSERT) \
+SCOPE \
+int prefix ## _append(Type **const tree, \
+ Type * const node) \
+{ \
+ Type *old, *dad, **slot; \
+ \
+ if (tree == NULL || node == NULL) return -1; \
+ \
+ for (slot = tree, old = *slot, dad = NULL; old; old = *slot) { \
+ if (old == node) \
+ return 0; \
+ if (CMP(node, old) < 0) \
+ dad = old, slot = &(left(old)); \
+ else \
+ dad = old, slot = &(right(old)); \
+ } \
+ \
+ *slot = node; \
+ parent(node) = dad; \
+ \
+ if (tree != slot) { \
+ prefix##_balance_insert(tree, node); \
+ } else { \
+ SET_BLACK(node); \
+ } \
+ \
+ INSERT(node); \
+ \
+ return 0; \
+} \
+extern int const prefix##_dummy
+
+#if DOCUMENTATION_ONLY
+/** Remove a @a node from the @a tree.
+ *
+ * @param tree pointer to the root of the tree
+ * @param node pointer to node to be appended
+ */
+void rbtree_remove(Type **tree, Type *node);
+#endif
+
+#define RBTREE_REMOVE(SCOPE, prefix, Type, left, right, parent, \
+ IS_RED, SET_RED, IS_BLACK, SET_BLACK, COPY_COLOR, \
+ REMOVE, INSERT) \
+SCOPE \
+void prefix##_remove(Type **top, Type *node) \
+{ \
+ Type *kid, *dad; \
+ int need_to_balance; \
+ \
+ if (top == NULL || node == NULL) \
+ return; \
+ \
+ /* Make sure that node is in tree */ \
+ for (dad = node; dad; dad = parent(dad)) \
+ if (dad == *top) \
+ break; \
+ \
+ if (!dad) return; \
+ \
+ /* Find a successor node with a free branch */ \
+ if (!left(node) || !right(node)) \
+ dad = node; \
+ else for (dad = right(node); left(dad); dad = left(dad)) \
+ ; \
+ /* Dad has a free branch => kid is dad's only child */ \
+ kid = left(dad) ? left(dad) : right(dad); \
+ \
+ /* Remove dad from tree */ \
+ if (!(parent(dad))) \
+ *top = kid; \
+ else if (left(parent(dad)) == dad) \
+ left(parent(dad)) = kid; \
+ else assert(right(parent(dad)) == dad), \
+ right(parent(dad)) = kid; \
+ if (kid) \
+ parent(kid) = parent(dad); \
+ \
+ need_to_balance = kid && IS_BLACK(dad); \
+ \
+ /* Put dad in place of node */ \
+ if (node != dad) { \
+ if (!(parent(dad) = parent(node))) \
+ *top = dad; \
+ else if (left(parent(dad)) == node) \
+ left(parent(dad)) = dad; \
+ else assert(right(parent(dad)) == node), \
+ right(parent(dad)) = dad; \
+ \
+ COPY_COLOR(dad, node); \
+ \
+ if ((left(dad) = left(node))) \
+ parent(left(dad)) = dad; \
+ \
+ if ((right(dad) = right(node))) \
+ parent(right(dad)) = dad; \
+ } \
+ \
+ REMOVE(node); \
+ SET_RED(node); \
+ \
+ if (need_to_balance) \
+ prefix##_balance_delete(top, kid); \
+} \
+extern int const prefix##_dummy
+
+#if DOCUMENTATION_ONLY
+/** Return inorder successor of node @a node.
+ *
+ * @param node pointer to node
+ *
+ * @return Pointer to successor, or NULL if @a node was last.
+ */
+Type *rbtree_succ(Type const *node);
+#endif
+
+/* Define function returning inorder successor of node @a node. */
+#define RBTREE_SUCC(SCOPE, prefix, Type, left, right, parent) \
+SCOPE Type *prefix##_succ(Type const *node) \
+{ \
+ Type const *dad; \
+ \
+ if (right(node)) { \
+ for (node = right(node); left(node); node = left(node)) \
+ ; \
+ return (Type *)node; \
+ } \
+ \
+ for (dad = parent(node); dad && node == right(dad); dad = parent(node)) \
+ node = dad; \
+ \
+ return (Type *)dad; \
+} \
+extern int const prefix##_dummy
+
+#if DOCUMENTATION_ONLY
+/** Return inorder precedessor of node @a node.
+ *
+ * @param node pointer to node
+ *
+ * @return Pointer to precedessor, or NULL if @a node was first.
+ */
+Type *rbtree_prec(Type const *node);
+#endif
+
+/* Define function returning inorder precedessor of node @a node. */
+#define RBTREE_PREC(SCOPE, prefix, Type, left, right, parent) \
+ SCOPE Type *prefix##_prec(Type const *node) \
+{ \
+ Type const *dad; \
+ \
+ if (left(node)) { \
+ for (node = left(node); right(node); node = right(node)) \
+ ; \
+ return (Type *)node; \
+ } \
+ \
+ for (dad = parent(node); dad && node == left(dad); dad = parent(node)) \
+ node = dad; \
+ \
+ return (Type *)dad; \
+} \
+extern int const prefix##_dummy
+
+#if DOCUMENTATION_ONLY
+/** Return first node in the tree to which @a node belongs to.
+ *
+ * @param node pointer to node
+ *
+ * @return Pointer to first node.
+ */
+Type *rbtree_first(Type const *node);
+#endif
+
+/* Define function returning first node in tree @a node. */
+#define RBTREE_FIRST(SCOPE, prefix, Type, left, right, parent) \
+SCOPE Type *prefix##_first(Type const *node) \
+{ \
+ while (node && left(node)) \
+ node = left(node); \
+ \
+ return (Type *)node; \
+} \
+extern int const prefix##_dummy
+
+#if DOCUMENTATION_ONLY
+/** Return last node in the tree to which @a node belongs to.
+ *
+ * @param node pointer to node
+ *
+ * @return Pointer to last node.
+ */
+Type *rbtree_last(Type const *node);
+#endif
+
+/* Define function returning last node in tree @a node. */
+#define RBTREE_LAST(SCOPE, prefix, Type, left, right, parent) \
+SCOPE Type *prefix##_last(Type const *node) \
+{ \
+ while (node && right(node)) \
+ node = right(node); \
+ \
+ return (Type *)node; \
+} \
+extern int const prefix##_dummy
+
+#if DOCUMENTATION_ONLY
+/** Return height of the tree below @a node.
+ *
+ * @param node pointer to node
+ *
+ * @return Height of the tree.
+ */
+int rbtree_height(Type const *node);
+#endif
+
+/* Define function returning height of the tree from the @a node. */
+#define RBTREE_HEIGHT(SCOPE, prefix, Type, getleft, getright, getparent) \
+SCOPE int prefix##_height(Type const *node) \
+{ \
+ int left, right; \
+ \
+ if (!node) \
+ return 0; \
+ \
+ left = getleft(node) ? prefix##_height(getleft(node)) : 0; \
+ right = getright(node) ? prefix##_height(getright(node)) : 0; \
+ \
+ if (left > right) \
+ return left + 1; \
+ else \
+ return right + 1; \
+} \
+extern int const prefix##_dummy
+
+/** Define prototypes for red-black tree functions. @HIDE
+ *
+ * @param SCOPE function scope (e.g., static inline)
+ * @param prefix function prefix (e.g., rbtree)
+ * @param Type node type
+ *
+ * @par Example
+ * @code
+ * RBTREE_PROTOS(static inline, rbtree, struct node);
+ * @endcode
+ */
+#define RBTREE_PROTOS(SCOPE, prefix, Type) \
+ SCOPE int prefix ## _insert(Type **, Type *, Type **return_old); \
+ SCOPE int prefix ## _append(Type **, Type *); \
+ SCOPE void prefix ## _remove(Type **, Type *); \
+ SCOPE Type *prefix ## _succ(Type const *); \
+ SCOPE Type *prefix ## _prec(Type const *); \
+ SCOPE Type *prefix ## _first(Type const *); \
+ SCOPE Type *prefix ## _last(Type const *); \
+ SCOPE int prefix ## _height(Type const *)
+
+/** Define bodies for red-black tree functions. @HIDE
+ *
+ * @param SCOPE function scope (e.g., static inline)
+ * @param prefix function prefix (e.g., rbtree)
+ * @param Type node type
+ * @param left accessor of left node
+ * @param right accessor of right node
+ * @param parent accessor of parent node
+ * @param IS_RED predicate testing if node is red
+ * @param SET_RED setter marking node as red
+ * @param IS_BLACK predicate testing if node is black
+ * @param SET_BLACK setter marking node as black
+ * @param COPY_COLOR method copying color from node to another
+ * @param CMP method comparing two nodes
+ * @param INSERT setter marking node as inserted to the tree
+ * @param REMOVE method marking node as removed and possibly deleting node
+ *
+ * @par Example
+ *
+ * @code
+ * #define LEFT(node) ((node)->left)
+ * #define RIGHT(node) ((node)->right)
+ * #define PARENT(node) ((node)->parent)
+ * #define SET_RED(node) ((node)->black = 0)
+ * #define SET_BLACK(node) ((node)->black = 1)
+ * #define CMP(a, b) ((a)->value - (b)->value)
+ * #define IS_RED(node) ((node) && (node)->black == 0)
+ * #define IS_BLACK(node) (!(node) || (node)->black == 1)
+ * #define COPY_COLOR(dst, src) ((dst)->black = (src)->black)
+ * #define INSERT(node) ((node)->inserted = 1)
+ * #define REMOVE(node) ((node)->left = (node)->right = (node)->parent = NULL, \
+ * (node)->inserted = 0)
+ *
+ * RBTREE_BODIES(static inline, rbtree, struct node,
+ * LEFT, RIGHT, PARENT,
+ * IS_RED, SET_RED, IS_BLACK, SET_BLACK, COPY_COLOR,
+ * CMP, INSERT, REMOVE);
+ * @endcode
+ */
+#define RBTREE_BODIES(SCOPE, prefix, Type, \
+ left, right, parent, \
+ IS_RED, SET_RED, IS_BLACK, SET_BLACK, COPY_COLOR, \
+ CMP, INSERT, REMOVE) \
+ RBTREE_LEFT_ROTATE(prefix, Type, left, right, parent); \
+ RBTREE_RIGHT_ROTATE(prefix, Type, left, right, parent); \
+ RBTREE_BALANCE_INSERT(prefix, Type, left, right, parent, \
+ IS_RED, SET_RED, IS_BLACK, SET_BLACK); \
+ RBTREE_BALANCE_DELETE(prefix, Type, left, right, parent, \
+ IS_RED, SET_RED, IS_BLACK, SET_BLACK, \
+ COPY_COLOR); \
+ RBTREE_INSERT(SCOPE, prefix, Type, left, right, parent, \
+ IS_RED, SET_RED, IS_BLACK, SET_BLACK, COPY_COLOR, \
+ CMP, REMOVE, INSERT); \
+ RBTREE_APPEND(SCOPE, prefix, Type, left, right, parent, \
+ IS_RED, SET_RED, IS_BLACK, SET_BLACK, COPY_COLOR, \
+ CMP, REMOVE, INSERT); \
+ RBTREE_REMOVE(SCOPE, prefix, Type, left, right, parent, \
+ IS_RED, SET_RED, IS_BLACK, SET_BLACK, COPY_COLOR, \
+ REMOVE, INSERT); \
+ RBTREE_SUCC(SCOPE, prefix, Type, left, right, parent); \
+ RBTREE_PREC(SCOPE, prefix, Type, left, right, parent); \
+ RBTREE_FIRST(SCOPE, prefix, Type, left, right, parent); \
+ RBTREE_LAST(SCOPE, prefix, Type, left, right, parent); \
+ RBTREE_HEIGHT(SCOPE, prefix, Type, left, right, parent)
+
+#endif /* !define(RBTREE_H) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,476 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_H
+/** Defined when <sofia-sip/su.h> has been included. */
+#define SU_H
+/**@ingroup su_socket
+ * @file sofia-sip/su.h Socket and network address interface
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Mar 18 19:40:51 1999 pessi
+ */
+
+/* ---------------------------------------------------------------------- */
+/* Includes */
+
+#ifndef SU_CONFIG_H
+#include "sofia-sip/su_config.h"
+#endif
+#ifndef SU_TYPES_H
+#include "sofia-sip/su_types.h"
+#endif
+#ifndef SU_ERRNO_H
+#include <sofia-sip/su_errno.h>
+#endif
+
+#include <stdio.h>
+#include <limits.h>
+
+#if SU_HAVE_BSDSOCK /* Unix-compatible includes */
+#include <errno.h>
+#include <unistd.h>
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#endif
+
+#if SU_HAVE_WINSOCK /* Windows includes */
+# include <winsock2.h>
+# include <ws2tcpip.h>
+
+# if defined(IPPROTO_IPV6)
+/* IPv6 defined in ws2tcpip.h */
+# elif SU_HAVE_IN6
+# include <tpipv6.h> /* From "IPv6 Tech Preview" */
+# else
+# error Winsock with IPv6 support required
+# endif
+
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/* ---------------------------------------------------------------------- */
+/* Constant definitions */
+
+#if SU_HAVE_BSDSOCK || DOCUMENTATION_ONLY
+enum {
+ /** Invalid socket descriptor, error from socket() or accept() */
+ INVALID_SOCKET = -1,
+#define INVALID_SOCKET ((su_socket_t)INVALID_SOCKET)
+ /** Error from other socket calls */
+ SOCKET_ERROR = -1,
+#define SOCKET_ERROR SOCKET_ERROR
+ /** Return code for a successful call */
+ su_success = 0,
+ /** Return code for an unsuccessful call */
+ su_failure = -1
+};
+#elif SU_HAVE_WINSOCK
+enum {
+ su_success = 0,
+ su_failure = 0xffffffffUL
+};
+
+#define MSG_NOSIGNAL (0)
+
+#endif
+
+/**@HI Maximum size of host name. */
+#define SU_MAXHOST (1025)
+/**@HI Maximum size of service name. */
+#define SU_MAXSERV (25)
+
+/**@HI Maximum size of address in text format. */
+#define SU_ADDRSIZE (48)
+/**@HI Maximum size of port number in text format. */
+#define SU_SERVSIZE (16)
+
+#define SU_SUCCESS su_success
+#define SU_FAILURE su_failure
+
+/* ---------------------------------------------------------------------- */
+/* Type definitions */
+
+/** Socket descriptor type. */
+#if SU_HAVE_BSDSOCK || DOCUMENTATION_ONLY
+typedef int su_socket_t;
+#elif SU_HAVE_WINSOCK
+typedef SOCKET su_socket_t;
+#endif
+
+#if !SU_HAVE_SOCKADDR_STORAGE
+/*
+ * RFC 2553: protocol-independent placeholder for socket addresses
+ */
+#define _SS_MAXSIZE 128
+#define _SS_ALIGNSIZE (sizeof(int64_t))
+#define _SS_PAD1SIZE (_SS_ALIGNSIZE - sizeof(u_char) * 2)
+#define _SS_PAD2SIZE (_SS_MAXSIZE - sizeof(u_char) * 2 - \
+ _SS_PAD1SIZE - _SS_ALIGNSIZE)
+
+struct sockaddr_storage {
+#if SU_HAVE_SOCKADDR_SA_LEN
+ unsigned char ss_len; /* address length */
+ unsigned char ss_family; /* address family */
+#else
+ unsigned short ss_family; /* address family */
+#endif
+ char __ss_pad1[_SS_PAD1SIZE];
+ int64_t __ss_align; /* force desired structure storage alignment */
+ char __ss_pad2[_SS_PAD2SIZE];
+};
+#endif
+
+/** Common socket address structure. */
+union su_sockaddr_u {
+#ifdef DOCUMENTATION_ONLY
+ uint8_t su_len; /**< Length of structure */
+ uint8_t su_family; /**< Address family. */
+ uint16_t su_port; /**< Port number. */
+#else
+ short su_dummy; /**< Dummy member to initialize */
+#if SU_HAVE_SOCKADDR_SA_LEN
+#define su_len su_sa.sa_len
+#define su_family su_sa.sa_family
+#else
+#define su_len su_array[0]
+ short su_family;
+#endif
+#define su_port su_sin.sin_port
+#endif
+
+ char su_array[32]; /**< Presented as chars */
+ uint16_t su_array16[16]; /**< Presented as 16-bit ints */
+ uint32_t su_array32[8]; /**< Presented as 32-bit ints */
+ struct sockaddr su_sa; /**< Address in struct sockaddr format */
+ struct sockaddr_in su_sin; /**< Address in IPv4 format */
+#if SU_HAVE_IN6
+ struct sockaddr_in6 su_sin6; /**< Address in IPv6 format */
+#endif
+#ifdef DOCUMENTATION_ONLY
+ uint32_t su_scope_id; /**< Scope ID. */
+#else
+#define su_scope_id su_array32[6]
+#endif
+};
+
+typedef union su_sockaddr_u su_sockaddr_t;
+
+#if SU_HAVE_BSDSOCK || DOCUMENTATION_ONLY
+/**Type of @a siv_len field in #su_iovec_t.
+ *
+ * The @a siv_len field in #su_iovec_t has different types in with POSIX
+ * (size_t) and WINSOCK2 (u_long). Truncate the iovec element size to
+ * #SU_IOVECLEN_MAX, if needed, and cast using #su_ioveclen_t.
+ *
+ * @sa #su_iovec_t, #SU_IOVECLEN_MAX
+ *
+ * @since New in @VERSION_1_12_2.
+ */
+typedef size_t su_ioveclen_t;
+
+/** I/O vector for scatter-gather I/O.
+ *
+ * This is the I/O vector element used with su_vsend() and su_vrecv(). It is
+ * defined like struct iovec with POSIX sockets:
+ * @code
+ * struct iovec {
+ * void *iov_base; // Pointer to data.
+ * size_t iov_len; // Length of data.
+ * };
+ * @endcode
+ *
+ * When using WINSOCK sockets it is defined as
+ * <a href="http://msdn.microsoft.com/library/en-us/winsock/winsock/wsabuf_2.asp">
+ * WSABUF</a>:
+ * @code
+ * typedef struct __WSABUF {
+ * u_long len;
+ * char FAR* buf;
+ * } WSABUF, *LPWSABUF;
+ * @endcode
+ *
+ * @note Ordering of the fields is reversed on Windows. Do not initialize this
+ * structure with static initializer, but assign both fields separately.
+ *
+ * For historical reasons, the structure is known as #msg_iovec_t in @msg
+ * module.
+ *
+ * @sa #su_iovec_t, #su_ioveclen_t, SU_IOVECLEN_MAX, su_vsend(), su_vrecv(),
+ * #msg_iovec_t, msg_iovec(), msg_recv_iovec(),
+ * @c struct @c iovec defined in <sys/uio.h>, writev(2), readv(2),
+ * sendmsg(), recvmsg(),
+ * <a href="http://msdn.microsoft.com/library/en-us/winsock/winsock/wsabuf_2.asp">
+ * WSABUF of WinSock2</a>
+ */
+typedef struct su_iovec_s {
+ void *siv_base; /**< Pointer to buffer. */
+ su_ioveclen_t siv_len; /**< Size of buffer. */
+} su_iovec_t;
+
+/** Maximum size of buffer in a single su_iovec_t element.
+ * @sa #su_ioveclen_t, #su_iovec_t
+ *
+ * @since New in @VERSION_1_12_2.
+ * @HIDE
+ */
+#define SU_IOVECLEN_MAX SIZE_MAX
+#endif
+
+#if SU_HAVE_WINSOCK
+typedef u_long su_ioveclen_t;
+
+/* This is same as WSABUF */
+typedef struct su_iovec_s {
+ su_ioveclen_t siv_len;
+ void *siv_base;
+} su_iovec_t;
+
+#define SU_IOVECLEN_MAX ULONG_MAX
+#endif
+
+/* ---------------------------------------------------------------------- */
+/* Socket compatibility functions */
+
+SOFIAPUBFUN int su_init(void);
+SOFIAPUBFUN void su_deinit(void);
+
+/** Create an endpoint for communication. */
+SOFIAPUBFUN su_socket_t su_socket(int af, int sock, int proto);
+/** Close an socket descriptor. */
+SOFIAPUBFUN int su_close(su_socket_t s);
+/** Control socket. */
+SOFIAPUBFUN int su_ioctl(su_socket_t s, int request, ...);
+
+/** Checks if the @a errcode indicates that the socket call failed because
+ * it would have blocked.
+ *
+ * Defined as macro with POSIX sockets.
+ *
+ * @since New in @VERSION_1_12_2.
+ */
+SOFIAPUBFUN int su_is_blocking(int errcode);
+
+/** Set/reset blocking option. */
+SOFIAPUBFUN int su_setblocking(su_socket_t s, int blocking);
+/** Set/reset address reusing option. */
+SOFIAPUBFUN int su_setreuseaddr(su_socket_t s, int reuse);
+/** Get the error code associated with the socket. */
+SOFIAPUBFUN int su_soerror(su_socket_t s);
+/** Get size of message available in socket. */
+SOFIAPUBFUN issize_t su_getmsgsize(su_socket_t s);
+
+/** Scatter-gather send. */
+SOFIAPUBFUN
+issize_t su_vsend(su_socket_t, su_iovec_t const iov[], isize_t len, int flags,
+ su_sockaddr_t const *su, socklen_t sulen);
+/** Scatter-gather receive. */
+SOFIAPUBFUN
+issize_t su_vrecv(su_socket_t, su_iovec_t iov[], isize_t len, int flags,
+ su_sockaddr_t *su, socklen_t *sulen);
+/** Return local IP address */
+SOFIAPUBFUN int su_getlocalip(su_sockaddr_t *sin);
+
+#if SU_HAVE_BSDSOCK
+#define su_ioctl ioctl
+/*
+ * Note: before 1.12.2, there was su_isblocking() which did not take argument
+ * and which was missing from WINSOCK
+ */
+#define su_is_blocking(e) \
+ ((e) == EINPROGRESS || (e) == EAGAIN || (e) == EWOULDBLOCK)
+#endif
+
+#if SU_HAVE_WINSOCK
+SOFIAPUBFUN int inet_pton(int af, char const *src, void *dst);
+SOFIAPUBFUN const char *inet_ntop(int af, void const *src,
+ char *dst, size_t size);
+SOFIAPUBFUN ssize_t
+ su_send(su_socket_t s, void *buffer, size_t length, int flags),
+ su_sendto(su_socket_t s, void *buffer, size_t length, int flags,
+ su_sockaddr_t const *to, socklen_t tolen),
+ su_recv(su_socket_t s, void *buffer, size_t length, int flags),
+ su_recvfrom(su_socket_t s, void *buffer, size_t length, int flags,
+ su_sockaddr_t *from, socklen_t *fromlen);
+
+static __inline
+uint16_t su_ntohs(uint16_t s)
+{
+ return (uint16_t)(((s & 255) << 8) | ((s & 0xff00) >> 8));
+}
+
+static __inline
+uint32_t su_ntohl(uint32_t l)
+{
+ return ((l & 0xff) << 24) | ((l & 0xff00) << 8)
+ | ((l & 0xff0000) >> 8) | ((l & 0xff000000U) >> 24);
+}
+
+#define ntohs su_ntohs
+#define htons su_ntohs
+#define ntohl su_ntohl
+#define htonl su_ntohl
+
+#else
+#define su_send(s,b,l,f) send((s),(b),(l),(f))
+#define su_sendto(s,b,l,f,a,L) sendto((s),(b),(l),(f),(void const*)(a),(L))
+#define su_recv(s,b,l,f) recv((s),(b),(l),(f))
+#define su_recvfrom(s,b,l,f,a,L) recvfrom((s),(b),(l),(f),(void *)(a),(L))
+#endif
+
+/* ---------------------------------------------------------------------- */
+/* Other compatibility stuff */
+
+#if SU_HAVE_WINSOCK
+#define getuid() (0x505)
+#endif
+
+#ifndef IPPROTO_SCTP
+#define IPPROTO_SCTP (132)
+#endif
+
+/* ---------------------------------------------------------------------- */
+/* Address manipulation macros */
+
+/**@HI Get pointer to address field.
+ *
+ * The macro SU_ADDR() returns pointer to the address field (sin_data,
+ * sin_addr or sin_addr6, depending on the address family).
+ */
+#if SU_HAVE_IN6
+#define SU_ADDR(su) \
+ ((su)->su_family == AF_INET ? (void *)&(su)->su_sin.sin_addr : \
+ ((su)->su_family == AF_INET6 ? (void *)&(su)->su_sin6.sin6_addr : \
+ (void *)&(su)->su_sa.sa_data))
+#else
+#define SU_ADDR(su) \
+ ((su)->su_family == AF_INET ? (void *)&(su)->su_sin.sin_addr : \
+ (void *)&(su)->su_sa.sa_data)
+#endif
+
+/**@HI Get length of address field.
+ *
+ * The macro SU_ADDRLEN() returns length of the address field (sin_data,
+ * sin_addr or sin_addr6, depending on the address family).
+ */
+#if SU_HAVE_IN6
+#define SU_ADDRLEN(su) \
+ ((su)->su_family == AF_INET \
+ ? (socklen_t)sizeof((su)->su_sin.sin_addr) : \
+ ((su)->su_family == AF_INET6 \
+ ? (socklen_t)sizeof((su)->su_sin6.sin6_addr) \
+ : (socklen_t)sizeof((su)->su_sa.sa_data)))
+#else
+#define SU_ADDRLEN(su) \
+ ((su)->su_family == AF_INET \
+ ? (socklen_t)sizeof((su)->su_sin.sin_addr) \
+ : (socklen_t)sizeof((su)->su_sa.sa_data))
+#endif
+
+/**@HI Test if su_sockaddr_t is INADDR_ANY or IN6ADDR_ANY. */
+#if SU_HAVE_IN6
+#define SU_HAS_INADDR_ANY(su) \
+ ((su)->su_family == AF_INET \
+ ? ((su)->su_sin.sin_addr.s_addr == INADDR_ANY) \
+ : ((su)->su_family == AF_INET6 \
+ ? (memcmp(&(su)->su_sin6.sin6_addr, su_in6addr_any(), \
+ sizeof(*su_in6addr_any())) == 0) : 0))
+#else
+#define SU_HAS_INADDR_ANY(su) \
+ ((su)->su_family == AF_INET \
+ ? ((su)->su_sin.sin_addr.s_addr == INADDR_ANY) : 0)
+#endif
+
+#define SU_SOCKADDR_INADDR_ANY(su) SU_HAS_INADDR_ANY(su)
+
+/**@HI Calculate correct size of su_sockaddr_t structure. */
+#if SU_HAVE_IN6
+#define SU_SOCKADDR_SIZE(su) \
+ ((socklen_t)((su)->su_family == AF_INET ? sizeof((su)->su_sin) \
+ : ((su)->su_family == AF_INET6 ? sizeof((su)->su_sin6) \
+ : sizeof(*su))))
+#else
+#define SU_SOCKADDR_SIZE(su) \
+ ((socklen_t)((su)->su_family == AF_INET ? sizeof((su)->su_sin) \
+ : sizeof(*su)))
+#endif
+#define su_sockaddr_size SU_SOCKADDR_SIZE
+
+#if SU_HAVE_IN6
+#if SU_HAVE_BSDSOCK
+#define su_in6addr_any() (&in6addr_any)
+#define su_in6addr_loopback() (&in6addr_loopback)
+#define SU_IN6ADDR_ANY_INIT IN6ADDR_ANY_INIT
+#define SU_IN6ADDR_LOOPBACK_INIT IN6ADDR_LOOPBACK_INIT
+#endif
+#if SU_HAVE_WINSOCK || DOCUMENTATION_ONLY
+SOFIAPUBVAR const struct in_addr6 *su_in6addr_any(void);
+SOFIAPUBVAR const struct in_addr6 *su_in6addr_loopback(void);
+#define SU_IN6ADDR_ANY_INIT { 0 }
+#define SU_IN6ADDR_LOOPBACK_INIT { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1 }
+#endif
+#endif /* SU_HAVE_IN6 */
+
+#define SU_IN6_IS_ADDR_V4MAPPED(a) \
+ (((uint32_t const *) (a))[0] == 0 && \
+ ((uint32_t const *) (a))[1] == 0 && \
+ ((uint32_t const *) (a))[2] == htonl(0xffff))
+
+#define SU_IN6_IS_ADDR_V4COMPAT(a) \
+ (((uint32_t const *)(a))[0] == 0 && \
+ ((uint32_t const *)(a))[1] == 0 && \
+ ((uint32_t const *)(a))[2] == 0 && \
+ ((uint32_t const *)(a))[3] != htonl(1) && \
+ ((uint32_t const *)(a))[3] != htonl(0))
+
+SOFIAPUBFUN int su_cmp_sockaddr(su_sockaddr_t const *a,
+ su_sockaddr_t const *b);
+SOFIAPUBFUN int su_match_sockaddr(su_sockaddr_t const *a,
+ su_sockaddr_t const *b);
+SOFIAPUBFUN void su_canonize_sockaddr(su_sockaddr_t *su);
+
+#if SU_HAVE_IN6
+#define SU_CANONIZE_SOCKADDR(su) \
+ ((su)->su_family == AF_INET6 ? su_canonize_sockaddr(su) : (void)0)
+#else
+#define SU_CANONIZE_SOCKADDR(su) \
+ ((void)0)
+#endif
+
+SOFIA_END_DECLS
+
+#ifndef SU_ADDRINFO_H
+#include <sofia-sip/su_addrinfo.h>
+#endif
+
+#endif /* !defined(SU_H) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_addrinfo.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_addrinfo.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef SU_ADDRINFO_H
+/* Defined when <sofia-sip/su_addrinfo.h> has been included */
+#define SU_ADDRINFO_H
+/**@ingroup su_socket
+ *
+ * @file sofia-sip/su_addrinfo.h Network address and service translation.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Nov 30 17:07:04 EET 2005 ppessi
+ */
+
+#ifndef SU_TYPES_H
+#include <sofia-sip/su_types.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+#if !SU_HAVE_ADDRINFO
+/*
+ * Error return codes from getaddrinfo()
+ */
+#ifndef EAI_ADDRFAMILY
+#define EAI_ADDRFAMILY 1 /* address family for hostname not supported */
+#define EAI_AGAIN 2 /* temporary failure in name resolution */
+#define EAI_BADFLAGS 3 /* invalid value for ai_flags */
+#define EAI_FAIL 4 /* non-recoverable failure in name resolution */
+#define EAI_FAMILY 5 /* ai_family not supported */
+#define EAI_MEMORY 6 /* memory allocation failure */
+#define EAI_NODATA 7 /* no address associated with hostname */
+#define EAI_NONAME 8 /* hostname nor servname provided, or not known */
+#define EAI_SERVICE 9 /* servname not supported for ai_socktype */
+#define EAI_SOCKTYPE 10 /* ai_socktype not supported */
+#define EAI_SYSTEM 11 /* system error returned in errno */
+#define EAI_BADHINTS 12
+#define EAI_PROTOCOL 13
+#define EAI_MAX 14
+#endif
+
+/*
+ * Flag values for getaddrinfo()
+ */
+#ifndef AI_PASSIVE
+#define AI_PASSIVE 0x00000001 /* get address to use bind() */
+#define AI_CANONNAME 0x00000002 /* fill ai_canonname */
+#define AI_NUMERICHOST 0x00000004 /* prevent name resolution */
+/* valid flags for addrinfo */
+#define AI_MASK (AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST)
+
+#define AI_ALL 0x00000100 /* IPv6 and IPv4-mapped (with AI_V4MAPPED) */
+#define AI_V4MAPPED_CFG 0x00000200 /* accept IPv4-mapped if kernel supports */
+#define AI_ADDRCONFIG 0x00000400 /* only if any address is assigned */
+#define AI_V4MAPPED 0x00000800 /* accept IPv4-mapped IPv6 address */
+/* special recommended flags for getipnodebyname */
+#define AI_DEFAULT (AI_V4MAPPED_CFG | AI_ADDRCONFIG)
+#endif
+
+/*
+ * Constants for getnameinfo()
+ */
+#ifndef NI_MAXHOST
+#define NI_MAXHOST 1025
+#define NI_MAXSERV 32
+#endif
+
+/*
+ * Flag values for getnameinfo()
+ */
+#ifndef NI_NOFQDN
+#define NI_NOFQDN 0x00000001
+#define NI_NUMERICHOST 0x00000002
+#define NI_NAMEREQD 0x00000004
+#define NI_NUMERICSERV 0x00000008
+#define NI_DGRAM 0x00000010
+#endif
+
+struct addrinfo {
+ int ai_flags; /* AI_PASSIVE, AI_CANONNAME */
+ int ai_family; /* PF_xxx */
+ int ai_socktype; /* SOCK_xxx */
+ int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
+ size_t ai_addrlen; /* length of ai_addr */
+ char *ai_canonname; /* canonical name for hostname */
+ struct sockaddr *ai_addr; /* binary address */
+ struct addrinfo *ai_next; /* next structure in linked list */
+};
+#endif /* SU_WITH_GETADDRINFO */
+
+#ifndef EAI_BADHINTS
+#define EAI_BADHINTS 10012
+#endif
+#ifndef EAI_PROTOCOL
+#define EAI_PROTOCOL 10013
+#endif
+
+#ifndef AI_MASK
+#define AI_MASK (AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST)
+#endif
+
+/** RFC 1576 address info structure. */
+typedef struct addrinfo su_addrinfo_t;
+
+/** Translate address and service. */
+SOFIAPUBFUN
+int su_getaddrinfo(char const *node, char const *service,
+ su_addrinfo_t const *hints,
+ su_addrinfo_t **res);
+/** Free su_addrinfo_t structure allocated by su_getaddrinfo(). */
+SOFIAPUBFUN void su_freeaddrinfo(su_addrinfo_t *res);
+
+/** Return string describing address translation error. */
+SOFIAPUBFUN char const *su_gai_strerror(int errcode);
+
+union su_sockaddr_u;
+
+SOFIAPUBFUN
+int su_getnameinfo(const union su_sockaddr_u *su, size_t sulen,
+ char *host, size_t hostlen,
+ char *serv, size_t servlen,
+ int flags);
+
+SOFIA_END_DECLS
+
+#endif /* !defined(SU_ADDRINFO_H) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_alloc.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_alloc.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,153 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_ALLOC_H /** Defined when <sofia-sip/su_alloc.h> has been included. */
+#define SU_ALLOC_H
+
+/**@ingroup su_alloc
+ *
+ * @file sofia-sip/su_alloc.h Home-based memory management interface
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Aug 19 01:12:25 1999 ppessi
+ */
+
+#ifndef SU_TYPES_H
+#include <sofia-sip/su_types.h>
+#endif
+
+#include <stdarg.h>
+
+SOFIA_BEGIN_DECLS
+
+#ifndef SU_HOME_T
+#define SU_HOME_T struct su_home_s
+#endif
+
+/** Memory home type. */
+typedef SU_HOME_T su_home_t;
+typedef struct su_block_s su_block_t;
+
+/** Thread-locking function. @internal */
+typedef struct su_alock su_alock_t;
+
+/** Memory home structure */
+struct su_home_s {
+ int suh_size;
+ su_block_t *suh_blocks;
+ su_alock_t *suh_lock;
+};
+
+#define SU_HOME_INIT(obj) { 0, NULL, NULL }
+
+SU_DLL void *su_home_new(isize_t size)
+ __attribute__((__malloc__));
+SU_DLL void *su_home_ref(su_home_t const *);
+SU_DLL int su_home_unref(su_home_t *);
+
+SU_DLL size_t su_home_refcount(su_home_t *home);
+
+SU_DLL int su_home_destructor(su_home_t *, void (*)(void *));
+
+SU_DLL int su_home_desctructor(su_home_t *, void (*)(void *));
+#ifndef su_home_desctructor
+/* This has typo in before 1.12.4 */
+#define su_home_desctructor(home, destructor) \
+ su_home_destructor((home), (destructor))
+#endif
+
+SU_DLL void *su_home_clone(su_home_t *parent, isize_t size)
+ __attribute__((__malloc__));
+
+SU_DLL int su_home_init(su_home_t *h);
+
+SU_DLL void su_home_deinit(su_home_t *h);
+
+SU_DLL void su_home_preload(su_home_t *h, isize_t n, isize_t size);
+
+SU_DLL su_home_t *su_home_auto(void *area, isize_t size);
+
+#define SU_HOME_AUTO_SIZE(n) \
+ (((n) + ((sizeof(su_home_t) + 7) & (size_t)~8) + \
+ ((3 * sizeof (void *) + 4 * sizeof(unsigned) + \
+ 7 * (sizeof (long) + sizeof(void *)) + 7) & (size_t)~8)) \
+ / sizeof(su_home_t))
+
+SU_DLL int su_home_move(su_home_t *dst, su_home_t *src);
+
+SU_DLL int su_home_threadsafe(su_home_t *home);
+
+SU_DLL int su_home_has_parent(su_home_t const *home);
+
+SU_DLL void su_home_check(su_home_t const *home);
+
+SU_DLL int su_home_mutex_lock(su_home_t *home);
+
+SU_DLL int su_home_mutex_unlock(su_home_t *home);
+
+SU_DLL void *su_alloc(su_home_t *h, isize_t size)
+ __attribute__((__malloc__));
+SU_DLL void *su_zalloc(su_home_t *h, isize_t size)
+ __attribute__((__malloc__));
+SU_DLL void *su_salloc(su_home_t *h, isize_t size)
+ __attribute__((__malloc__));
+SU_DLL void *su_realloc(su_home_t *h, void *data, isize_t size)
+ __attribute__((__malloc__));
+SU_DLL int su_in_home(su_home_t *h, void const *data);
+
+SU_DLL char *su_strdup(su_home_t *home, char const *s)
+ __attribute__((__malloc__));
+SU_DLL char *su_strcat(su_home_t *home, char const *s1, char const *s2)
+ __attribute__((__malloc__));
+SU_DLL char *su_strndup(su_home_t *home, char const *s, isize_t n)
+ __attribute__((__malloc__));
+
+SU_DLL char *su_strcat_all(su_home_t *home, ...)
+ __attribute__((__malloc__));
+
+SU_DLL char *su_sprintf(su_home_t *home, char const *fmt, ...)
+ __attribute__ ((__malloc__, __format__ (printf, 2, 3)));
+
+SU_DLL char *su_vsprintf(su_home_t *home, char const *fmt, va_list ap)
+ __attribute__((__malloc__));
+
+/* free an independent block */
+SU_DLL void su_free(su_home_t *h, void *);
+
+/** Check if a memory home is threadsafe */
+SU_DLL int su_home_is_threadsafe(su_home_t const *home);
+
+/* ---------------------------------------------------------------------- */
+/* Deprecated */
+
+SU_DLL su_home_t *su_home_create(void)
+ __attribute__((__malloc__));
+SU_DLL void su_home_destroy(su_home_t *h);
+
+#define su_home_zap(h) su_home_unref((h))
+
+SOFIA_END_DECLS
+
+#endif /* ! defined(SU_ALLOC_H) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_alloc_stat.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_alloc_stat.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,93 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_ALLOC_STAT_H
+/** Defined when <sofia-sip/su_alloc_stat.h> has been included. */
+#define SU_ALLOC_STAT_H
+
+/**@ingroup su_alloc
+ *
+ * @file sofia-sip/su_alloc_stat.h Home-based memory management statistics
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Apr 9 10:24:05 2002 ppessi
+ */
+
+#ifndef SU_ALLOC_H
+#include <sofia-sip/su_alloc.h>
+#endif
+
+#ifndef SU_TYPES_H
+#include <sofia-sip/su_types.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+typedef struct su_home_stat_t su_home_stat_t;
+
+SU_DLL void su_home_init_stats(su_home_t *h);
+SU_DLL void su_home_get_stats(su_home_t *, int include_clones,
+ su_home_stat_t *stats, isize_t statssize);
+
+SU_DLL void su_home_stat_add(su_home_stat_t *total,
+ su_home_stat_t const *hs);
+
+struct su_home_stat_t
+{
+ int hs_size;
+ usize_t hs_clones; /**< Number of clones */
+ usize_t hs_rehash; /**< Number of (re)allocations of hash table. */
+ usize_t hs_blocksize; /**< Current size of hash table */
+
+ struct {
+ unsigned hsp_size; /**< Size of preload area */
+ unsigned hsp_used; /**< Number of bytes used from preload */
+ } hs_preload;
+
+ struct {
+ uint64_t hsa_number;
+ uint64_t hsa_bytes;
+ uint64_t hsa_rbytes;
+ uint64_t hsa_maxrbytes;
+ uint64_t hsa_preload; /**< Number of allocations from preload area */
+ } hs_allocs;
+
+ struct {
+ uint64_t hsf_number;
+ uint64_t hsf_bytes;
+ uint64_t hsf_rbytes;
+ uint64_t hsf_preload; /**< Number of free()s from preload area */
+ } hs_frees;
+
+ struct {
+ uint64_t hsb_number;
+ uint64_t hsb_bytes;
+ uint64_t hsb_rbytes;
+ } hs_blocks;
+};
+
+SOFIA_END_DECLS
+
+#endif /* ! defined(SU_ALLOC_H) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_bm.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_bm.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,60 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_BM_H
+/** Defined when <sofia-sip/su_bm.h> has been included. */
+#define SU_BM_H
+
+/**
+ * @file sofia-sip/su_bm.h
+ * @brief Boyer-Moore search algorithm
+ *
+ * @author Pekka.Pessi at nokia.com
+ *
+ * @date Created: Mon Apr 11 17:03:13 2005 ppessi
+ */
+
+#ifndef SU_TYPES_H
+#include <sofia-sip/su_types.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+typedef struct bw_fwd_table bm_fwd_table_t;
+
+SOFIAPUBFUN bm_fwd_table_t *bm_memmem_study(char const *needle, size_t nlen);
+
+SOFIAPUBFUN char const* bm_memmem(char const *haystack, size_t hlen,
+ char const *needle, size_t nlen,
+ bm_fwd_table_t *fwd);
+
+SOFIAPUBFUN bm_fwd_table_t *bm_memcasemem_study(char const *needle, size_t);
+
+SOFIAPUBFUN char const* bm_memcasemem(char const *haystack, size_t hlen,
+ char const *needle, size_t nlen,
+ bm_fwd_table_t *fwd);
+
+SOFIA_END_DECLS
+
+#endif /* !defined SU_MEMMEM_H */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_config.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_config.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,113 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_CONFIG_H
+/** Defined when <sofia-sip/su_config.h> has been included. */
+#define SU_CONFIG_H
+/**@file sofia-sip/su_config.h
+ *
+ * @b su library configuration
+ *
+ * This file includes an appropriate <su_configure*.h> include file.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Mar 18 19:40:51 1999 pessi
+ */
+
+#include <sofia-sip/su_configure.h>
+
+#if defined(__GNUC__)
+/* Special attributes for GNU C */
+#if __GNUC__ < 3 && (!defined(__GNUC_MINOR__) || __GNUC_MINOR__ < 96)
+#define __malloc__ /* avoid spurious warnigns */
+#endif
+#elif !defined(__attribute__)
+# define __attribute__(x)
+#endif
+
+/* C++ linkage needs to know that types and declarations are C, not C++. */
+#if defined(__cplusplus)
+/** Begin declarations in Sofia header files */
+# define SOFIA_BEGIN_DECLS extern "C" {
+/** End declarations in Sofia header files */
+# define SOFIA_END_DECLS }
+#else
+# define SOFIA_BEGIN_DECLS
+# define SOFIA_END_DECLS
+#endif
+
+/* ---------------------------------------------------------------------- */
+/* Macros required by Win32 linkage */
+
+/** SOFIAPUBFUN declares an exported function */
+#define SOFIAPUBFUN
+/** SOFIAPUBVAR declares an exported variable */
+#define SOFIAPUBVAR extern
+/** SOFIACALL declares the calling convention for exported functions */
+#define SOFIACALL
+
+/* Win32 linkage */
+
+/* Windows platform with MS/Borland/Cygwin/MinGW32 compiler */
+#if defined(_WIN32) && \
+ (defined(_MSC_VER) || defined(__BORLANDC__) || \
+ defined(__CYGWIN__) || defined(__MINGW32__))
+ #undef SOFIACALL
+ #define SOFIACALL __cdecl
+
+ #if defined(LIBSOFIA_SIP_UA_STATIC)
+ #else
+ #undef SOFIAPUBFUN
+ #undef SOFIAPUBVAR
+ #if defined(IN_LIBSOFIA_SIP_UA)
+ #define SOFIAPUBFUN __declspec(dllexport)
+ #define SOFIAPUBVAR __declspec(dllexport)
+ #else
+ #define SOFIAPUBFUN __declspec(dllimport)
+ #define SOFIAPUBVAR __declspec(dllimport) extern
+ #endif
+ #endif
+
+ #if !defined _REENTRANT
+ #define _REENTRANT
+ #endif
+#endif
+
+#define BNF_DLL SOFIAPUBFUN
+#define HTTP_DLL SOFIAPUBFUN
+#define IPT_DLL SOFIAPUBFUN
+#define AUTH_DLL SOFIAPUBFUN
+#define MSG_DLL SOFIAPUBFUN
+#define NEA_DLL SOFIAPUBFUN
+#define NTA_DLL SOFIAPUBFUN
+#define NTH_DLL SOFIAPUBFUN
+#define SDP_DLL SOFIAPUBFUN
+#define SIP_DLL SOFIAPUBFUN
+#define SU_DLL SOFIAPUBFUN
+#define TPORT_DLL SOFIAPUBFUN
+#define URL_DLL SOFIAPUBFUN
+#define MSG_TEST_DLL SOFIAPUBFUN
+
+#endif /* SU_CONFIG_H */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_configure.h.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_configure.h.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1,131 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_CONFIGURE_H
+/** Defined when <sofia-sip/su_configure.h> has been included. */
+#define SU_CONFIGURE_H
+
+/**@file sofia-sip/su_configure.h
+ *
+ * Autoconf configuration for SU library.
+ *
+ * The file <su_configure.h> is automatically generated by autoconf.
+ *
+ * The file <su_configure.h> contains configuration information for
+ * programs using @b su library. The configuration for su library itself is
+ * in "config.h".
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Mon Aug 21 20:32:25 2000 ppessi
+ */
+
+/** Define as 1 if you have <stdint.h> */
+#undef SU_HAVE_STDINT
+/** Define as 1 if you have <inttypes.h> */
+#undef SU_HAVE_INTTYPES
+/** Define as 1 if you have <sys/types.h> */
+#undef SU_HAVE_SYS_TYPES
+
+/** Define as 1 if you have BSD socket interface */
+#undef SU_HAVE_BSDSOCK
+/** Define as 1 if you have pthreads library */
+#undef SU_HAVE_PTHREADS
+/** Define as 1 if you have poll() */
+#undef SU_HAVE_POLL
+/** Define as 1 if you have IPv6 structures, macros and constants */
+#undef SU_HAVE_IN6
+
+/** Define as 1 if you have sa_len field in struct sockaddr */
+#undef SU_HAVE_SOCKADDR_SA_LEN
+
+/** Define as 1 if you have struct sockaddr_storage */
+#undef SU_HAVE_SOCKADDR_STORAGE
+
+/** Define as 1 if you have struct addrinfo. */
+#undef SU_HAVE_ADDRINFO
+
+/** Define as 1 if you have Winsock interface */
+#undef SU_HAVE_WINSOCK
+
+/** Define as 1 if you have Winsock2 interface */
+#undef SU_HAVE_WINSOCK2
+
+/** Define as 1 if you have OSX CoreFoundation interface */
+#undef SU_HAVE_OSX_CF_API
+
+/** Define as 1 if you have inline functions */
+#undef SU_HAVE_INLINE
+/** Define as suitable declarator inline functions */
+#undef SU_INLINE
+/** Define as suitable declarator static inline functions */
+#undef su_inline
+
+/** Define this as 1 if we can use tags directly from stack. */
+#undef SU_HAVE_TAGSTACK
+
+/* These are valid only for GCC */
+
+#define SU_S64_C(i) (SU_S64_T)(i ## LL)
+#define SU_U64_C(i) (SU_U64_T)(i ## ULL)
+#define SU_S32_C(i) (SU_S32_T)(i ## L)
+#define SU_U32_C(i) (SU_U32_T)(i ## UL)
+#define SU_S16_C(i) (SU_S16_T)(i)
+#define SU_U16_C(i) (SU_U16_T)(i ## U)
+#define SU_S8_C(i) (SU_S8_T)(i)
+#define SU_U8_C(i) (SU_U8_T)(i ## U)
+
+/** Define this as ssize_t. */
+#undef SOFIA_SSIZE_T
+
+/** Define this as size_t
+ (int when compatible with sofia-sip-ua 1.12.0 binaries). */
+#undef SOFIA_ISIZE_T
+
+/** Maximum value of isize_t */
+#undef ISIZE_MAX
+
+/** Define this as ssize_t
+ (int when compatible with sofia-sip-ua 1.12.0 binaries). */
+#undef SOFIA_ISSIZE_T
+
+/** Maximum value of issize_t */
+#undef ISSIZE_MAX
+
+/** Define this as size_t
+ (unsigned int when compatible with sofia-sip-ua 1.12.0 binaries). */
+#undef SOFIA_USIZE_T
+
+/** Maximum value of usize_t */
+#undef USIZE_MAX
+
+/**On Solaris define this in order to get POSIX extensions. */
+#undef __EXTENSIONS__
+
+/** Define this in order to get GNU extensions. */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#endif /* SU_CONFIGURE_H */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_debug.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_debug.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,209 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_DEBUG_H
+/** Defined when <sofia-sip/su_debug.h> has been included */
+#define SU_DEBUG_H
+
+/**@ingroup su_log
+ * @file sofia-sip/su_debug.h
+ * @brief SU debugging macros
+ *
+ * The logging levels and macros to use are defined as follows:
+ * - SU_DEBUG_0() fatal errors, panic
+ * - SU_DEBUG_1() critical errors, minimal progress at subsystem level
+ * - SU_DEBUG_2() non-critical errors
+ * - SU_DEBUG_3() warnings, progress messages
+ * - SU_DEBUG_5() signaling protocol actions (incoming packets, etc.)
+ * - SU_DEBUG_7() media protocol actions (incoming packets, etc.)
+ * - SU_DEBUG_9() entering/exiting functions, very verbatim progress
+ *
+ * These macros are used to log with module-specific levels. The SU_LOG
+ * macro is redefined with a pointer to a module-specific #su_log_t
+ * structure, e.g., "iptsec_debug.h".
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Feb 8 10:06:33 2000 ppessi
+ *
+ * @sa @ref debug_logs, su_llog(), su_vllog(), #su_log_t,
+ */
+
+#ifndef SU_LOG_H
+#include <sofia-sip/su_log.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+#ifndef SU_DEBUG_MAX
+/** The maximum debugging level. */
+#define SU_DEBUG_MAX 9
+#endif
+
+#define SU_LOG_LEVEL \
+((SU_LOG != NULL && SU_LOG->log_init) == 0 ? 9 : \
+((SU_LOG != NULL && SU_LOG->log_init > 1) ? \
+ SU_LOG->log_level : su_log_default->log_level))
+
+#if SU_DEBUG_MAX >= 0
+#ifndef SU_LOG
+#define SU_LOG (su_log_default)
+#else
+SOFIAPUBVAR su_log_t SU_LOG[];
+#endif
+
+#define SU_DEBUG_DEF(level) \
+ static SU_INLINE void su_debug_##level(char const *fmt, ...) \
+ __attribute__ ((__format__ (printf, 1, 2))); \
+ void su_debug_##level(char const *fmt, ...) \
+ { va_list ap; va_start(ap, fmt); su_vllog(SU_LOG, level, fmt, ap); va_end(ap); }
+
+SU_DEBUG_DEF(0)
+/** Log messages at level 0.
+ *
+ * Fatal errors and panic messages should be logged at level 0.
+ *
+ * @sa su_llog(), su_vllog(), #su_log_t, @ref debug_logs
+ */
+#define SU_DEBUG_0(x) (SU_LOG_LEVEL >= 0 ? (su_debug_0 x) : (void)0)
+
+/** Log C library errors. */
+#define SU_LERROR(s) (su_llog(SU_LOG, 1, "%s: %s\n", (s), strerror(errno)))
+/** Log socket errors. */
+#define SU_LSERROR(s) \
+ (su_llog(SU_LOG, 1, "%s: %s\n", (s), su_strerror(su_errno())))
+#else
+#define SU_DEBUG_0(x) ((void)0)
+#define SU_LERROR(s) ((void)0)
+#define SU_LSERROR(s) ((void)0)
+#endif
+
+#if SU_DEBUG_MAX >= 1
+SU_DEBUG_DEF(1)
+/**Log messages at level 1.
+ *
+ * Critical errors and minimal progress at subsystem level should be logged
+ * at level 1.
+ *
+ * @sa su_llog(), su_vllog(), #su_log_t, @ref debug_logs
+ */
+#define SU_DEBUG_1(x) (SU_LOG_LEVEL >= 1 ? (su_debug_1 x) : (void)0)
+#else
+#define SU_DEBUG_1(x) (void)1
+#endif
+
+#if SU_DEBUG_MAX >= 2
+SU_DEBUG_DEF(2)
+/**Log messages at level 2.
+ *
+ * Non-critical errors should be logged at level 2.
+ *
+ * @sa su_llog(), su_vllog(), #su_log_t, @ref debug_logs
+ */
+#define SU_DEBUG_2(x) (SU_LOG_LEVEL >= 2 ? (su_debug_2 x) : (void)0)
+#else
+#define SU_DEBUG_2(x) (void)2
+#endif
+
+#if SU_DEBUG_MAX >= 3
+SU_DEBUG_DEF(3)
+/** Log messages at level 3.
+ *
+ * Warnings and progress messages should be logged at level 3.
+ *
+ * @sa su_llog(), su_vllog(), #su_log_t, @ref debug_logs
+ */
+#define SU_DEBUG_3(x) (SU_LOG_LEVEL >= 3 ? (su_debug_3 x) : (void)0)
+#else
+#define SU_DEBUG_3(x) (void)3
+#endif
+
+#if SU_DEBUG_MAX >= 4
+SU_DEBUG_DEF(4)
+/** Log messages at level 4. */
+#define SU_DEBUG_4(x) (SU_LOG_LEVEL >= 4 ? (su_debug_4 x) : (void)0)
+#else
+#define SU_DEBUG_4(x) (void)4
+#endif
+
+#if SU_DEBUG_MAX >= 5
+SU_DEBUG_DEF(5)
+/** Log messages at level 5.
+ *
+ * Signaling protocol actions (incoming packets, etc.) should be logged
+ * at level 5.
+ *
+ * @sa su_llog(), su_vllog(), #su_log_t, @ref debug_logs
+ */
+#define SU_DEBUG_5(x) (SU_LOG_LEVEL >= 5 ? (su_debug_5 x) : (void)0)
+#else
+#define SU_DEBUG_5(x) (void)5
+#endif
+
+#if SU_DEBUG_MAX >= 6
+SU_DEBUG_DEF(6)
+/** Log messages at level 6. */
+#define SU_DEBUG_6(x) (SU_LOG_LEVEL >= 6 ? (su_debug_6 x) : (void)0)
+#else
+#define SU_DEBUG_6(x) (void)6
+#endif
+
+#if SU_DEBUG_MAX >= 7
+SU_DEBUG_DEF(7)
+/** Log messages at level 7.
+ *
+ * Media protocol actions (incoming packets, etc) should be logged at level 7.
+ *
+ * @sa su_llog(), su_vllog(), #su_log_t, @ref debug_logs
+ */
+#define SU_DEBUG_7(x) (SU_LOG_LEVEL >= 7 ? (su_debug_7 x) : (void)0)
+#else
+#define SU_DEBUG_7(x) (void)7
+#endif
+
+#if SU_DEBUG_MAX >= 8
+SU_DEBUG_DEF(8)
+/** Log messages at level 8. */
+#define SU_DEBUG_8(x) (SU_LOG_LEVEL >= 8 ? (su_debug_8 x) : (void)0)
+#else
+#define SU_DEBUG_8(x) (void)8
+#endif
+
+#if SU_DEBUG_MAX >= 9
+SU_DEBUG_DEF(9)
+/** Log messages at level 9.
+ *
+ * Entering/exiting functions, very verbatim progress should be logged at
+ * level 9.
+ *
+ * @sa su_llog(), su_vllog(), #su_log_t, @ref debug_logs
+ */
+#define SU_DEBUG_9(x) (SU_LOG_LEVEL >= 9 ? (su_debug_9 x) : (void)0)
+#else
+#define SU_DEBUG_9(x) (void)9
+#endif
+
+SOFIA_END_DECLS
+
+#endif /* SU_DEBUG_H */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_errno.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_errno.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,243 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_ERRNO_H
+/** Defined when <sofia-sip/su_errno.h> has been included. */
+#define SU_ERRNO_H
+
+/**@file sofia-sip/su_errno.h Errno handling
+ *
+ * Source-code compatibility with Windows (having separate errno for
+ * socket library and C libraries).
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Dec 22 18:16:06 EET 2005 pessi
+ */
+
+#ifndef SU_CONFIG_H
+#include "sofia-sip/su_config.h"
+#endif
+
+#include <errno.h>
+
+SOFIA_BEGIN_DECLS
+
+/** Return string describing su error code. */
+SOFIAPUBFUN char const *su_strerror(int e);
+
+/** The latest su error. */
+SOFIAPUBFUN int su_errno(void);
+
+/** Set the su error. */
+SOFIAPUBFUN int su_seterrno(int);
+
+#if !SU_HAVE_WINSOCK
+#define su_errno() (errno)
+#define su_seterrno(n) ((errno = (n)), -1)
+#endif
+
+#if defined(__APPLE_CC__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__)
+#ifndef EBADMSG
+#define EBADMSG EFAULT
+#endif
+#ifndef EPROTO
+#define EPROTO EPROTOTYPE
+#endif
+#ifndef EBADMSG
+#define EBADMSG EFAULT
+#endif
+#endif
+
+#if defined(_WIN32)
+
+#ifndef EWOULDBLOCK
+#define EWOULDBLOCK (10035) /* WSAEWOULDBLOCK */
+#endif
+
+#ifndef EINPROGRESS
+#define EINPROGRESS (10036) /* WSAEINPROGRESS */
+#endif
+
+#ifndef EALREADY
+#define EALREADY (10037) /* WSAEALREADY */
+#endif
+
+#ifndef ENOTSOCK
+#define ENOTSOCK (10038) /* WSAENOTSOCK */
+#endif
+
+#ifndef EDESTADDRREQ
+#define EDESTADDRREQ (10039) /* WSAEDESTADDRREQ */
+#endif
+
+#ifndef EMSGSIZE
+#define EMSGSIZE (10040) /* WSAEMSGSIZE */
+#endif
+
+#ifndef EPROTOTYPE
+#define EPROTOTYPE (10041) /* WSAEPROTOTYPE */
+#endif
+
+#ifndef ENOPROTOOPT
+#define ENOPROTOOPT (10042) /* WSAENOPROTOOPT */
+#endif
+
+#ifndef EPROTONOSUPPORT
+#define EPROTONOSUPPORT (10043) /* WSAEPROTONOSUPPORT */
+#endif
+
+#ifndef ESOCKTNOSUPPORT
+#define ESOCKTNOSUPPORT (10044) /* WSAESOCKTNOSUPPORT */
+#endif
+
+#ifndef EOPNOTSUPP
+#define EOPNOTSUPP (10045) /* WSAEOPNOTSUPP */
+#endif
+
+#ifndef EPFNOSUPPORT
+#define EPFNOSUPPORT (10046) /* WSAEPFNOSUPPORT */
+#endif
+
+#ifndef EAFNOSUPPORT
+#define EAFNOSUPPORT (10047) /* WSAEAFNOSUPPORT */
+#endif
+
+#ifndef EADDRINUSE
+#define EADDRINUSE (10048) /* WSAEADDRINUSE */
+#endif
+
+#ifndef EADDRNOTAVAIL
+#define EADDRNOTAVAIL (10049) /* WSAEADDRNOTAVAIL */
+#endif
+
+#ifndef ENETDOWN
+#define ENETDOWN (10050) /* WSAENETDOWN */
+#endif
+
+#ifndef ENETUNREACH
+#define ENETUNREACH (10051) /* WSAENETUNREACH */
+#endif
+
+#ifndef ENETRESET
+#define ENETRESET (10052) /* WSAENETRESET */
+#endif
+
+#ifndef ECONNABORTED
+#define ECONNABORTED (10053) /* WSAECONNABORTED */
+#endif
+
+#ifndef ECONNRESET
+#define ECONNRESET (10054) /* WSAECONNRESET */
+#endif
+
+#ifndef ENOBUFS
+#define ENOBUFS (10055) /* WSAENOBUFS */
+#endif
+
+#ifndef EISCONN
+#define EISCONN (10056) /* WSAEISCONN */
+#endif
+
+#ifndef ENOTCONN
+#define ENOTCONN (10057) /* WSAENOTCONN */
+#endif
+
+#ifndef ESHUTDOWN
+#define ESHUTDOWN (10058) /* WSAESHUTDOWN */
+#endif
+
+#ifndef ETOOMANYREFS
+#define ETOOMANYREFS (10059) /* WSAETOOMANYREFS */
+#endif
+
+#ifndef ETIMEDOUT
+#define ETIMEDOUT (10060) /* WSAETIMEDOUT */
+#endif
+
+#ifndef ECONNREFUSED
+#define ECONNREFUSED (10061) /* WSAECONNREFUSED */
+#endif
+
+#ifndef ELOOP
+#define ELOOP (10062) /* WSAELOOP */
+#endif
+
+#ifndef ENAMETOOLONG
+#define ENAMETOOLONG (10063) /* WSAENAMETOOLONG */
+#endif
+
+#ifndef EHOSTDOWN
+#define EHOSTDOWN (10064) /* WSAEHOSTDOWN */
+#endif
+
+#ifndef EHOSTUNREACH
+#define EHOSTUNREACH (10065) /* WSAEHOSTUNREACH */
+#endif
+
+#ifndef ENOTEMPTY
+#define ENOTEMPTY (10066) /* WSAENOTEMPTY */
+#endif
+
+#ifndef EPROCLIM
+#define EPROCLIM (10067) /* WSAEPROCLIM */
+#endif
+
+#ifndef EUSERS
+#define EUSERS (10068) /* WSAEUSERS */
+#endif
+
+#ifndef EDQUOT
+#define EDQUOT (10069) /* WSAEDQUOT */
+#endif
+
+#ifndef ESTALE
+#define ESTALE (10070) /* WSAESTALE */
+#endif
+
+#ifndef EREMOTE
+#define EREMOTE (10071) /* WSAEREMOTE */
+#endif
+
+#ifndef EBADMSG
+# if defined(WSABADMSG)
+# define EBADMSG (WSAEBADMSG)
+# else
+# define EBADMSG (20005)
+# endif
+#endif
+
+#ifndef EPROTO
+# if defined(WSAEPROTO)
+# define EPROTO WSAEPROTO
+# else
+# define EPROTO (20006)
+# endif
+#endif
+
+#endif
+
+SOFIA_END_DECLS
+
+#endif
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_localinfo.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_localinfo.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,113 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_LOCALINFO_H
+/** Defined when <sofia-sip/su_localinfo.h> has been included. */
+#define SU_LOCALINFO_H
+
+
+/**@ingroup su_socket
+ * @file sofia-sip/su_localinfo.h Interface for obtaining local addresses.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Aug 10 18:58:01 2000 ppessi
+ */
+
+#ifndef SU_H
+#include <sofia-sip/su.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** Local address info structure. */
+typedef struct su_localinfo_s su_localinfo_t;
+
+/** Local address info structure. */
+struct su_localinfo_s {
+ /**Bitwise or of flags:
+ * #LI_V4MAPPED, #LI_CANONNAME, #LI_NAMEREQD,
+ * #LI_NUMERIC, #LI_DOWN, #LI_IFNAME */
+ int li_flags;
+ int li_family; /**< Address family. */
+ int li_index; /**< Network interface index. */
+ int li_scope; /**< Address scope. */
+ socklen_t li_addrlen; /**< Length of li_addr. */
+ su_sockaddr_t *li_addr; /**< Binary address. */
+ char *li_canonname; /**< Canonical name for address. */
+ su_localinfo_t *li_next; /**< Next structure in linked list. */
+ char *li_ifname; /**< Network interface name. */
+};
+
+/** Flags for su_getlocalinfo() - li_flags */
+enum {
+ /** IPv4 addresses will be mapped as IPv6 */
+ LI_V4MAPPED = 1,
+ /** Get domain name corresponding to the local address */
+ LI_CANONNAME = 2,
+ /** Do not return addresses not in DNS. Implies LI_CANONNAME. */
+ LI_NAMEREQD = 6,
+ /** Instead of domain name, use numeric form */
+ LI_NUMERIC = 8,
+ /** Include interfaces even if they are down (new in @VERSION_1_12_2). */
+ LI_DOWN = 16,
+ /** Get interface name */
+ LI_IFNAME = 256
+};
+
+/** Localinfo scope - li_scope */
+enum {
+ LI_SCOPE_HOST = 0x10, /**< Host-local address, valid within host. */
+ LI_SCOPE_LINK = 0x20, /**< Link-local address. */
+ LI_SCOPE_SITE = 0x40, /**< Site-local address. */
+ LI_SCOPE_GLOBAL = 0x80 /**< Global address. */
+};
+
+/** Localinfo error codes. */
+enum {
+ ELI_NOADDRESS = -1, /**< No matching address. */
+ ELI_MEMORY = -2, /**< Memory allocation error. */
+ ELI_FAMILY = -3, /**< Unknown address family. */
+ ELI_RESOLVER = -4, /**< Error when resolving address. */
+ ELI_SYSTEM = -5, /**< System error. */
+ ELI_BADHINTS = -6, /**< Invalid value for hints. */
+ ELI_NOERROR = 0 /**< No error. */
+};
+
+/** Request local address information */
+SOFIAPUBFUN int su_getlocalinfo(su_localinfo_t const *hints,
+ su_localinfo_t **res);
+/** Free local address information */
+SOFIAPUBFUN void su_freelocalinfo(su_localinfo_t *);
+/** Describe su_localinfo errors. */
+SOFIAPUBFUN char const *su_gli_strerror(int error);
+/** Copy a localinfo structure */
+SOFIAPUBFUN su_localinfo_t *su_copylocalinfo(su_localinfo_t const *li0);
+
+/** Return the scope of address in the sockaddr structure */
+SOFIAPUBFUN int su_sockaddr_scope(su_sockaddr_t const *su, socklen_t sulen);
+
+SOFIA_END_DECLS
+
+#endif /* !defined(SU_LOCALINFO_H) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_log.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_log.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,102 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_log
+ * @file sofia-sip/su_log.h SU logging interface
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Thu Feb 22 18:09:02 2001 ppessi
+ *
+ */
+
+#ifndef SU_LOG_T
+/** Defined when the type #su_log_t has been defined. */
+#define SU_LOG_T
+/** Type of log structure. */
+typedef struct su_log_s su_log_t;
+#endif
+
+#ifndef SU_LOG_H_NEED_SU_LOG_T
+
+#ifndef SU_LOG_H
+/** Defined when <sofia-sip/su_log.h> has been included. */
+#define SU_LOG_H
+
+#include <stdarg.h>
+
+#ifndef SU_CONFIG_H
+#include <sofia-sip/su_config.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** Prototype for logging function */
+typedef void (su_logger_f)(void *stream, char const *fmt, va_list ap);
+
+/** Log object. */
+struct su_log_s {
+ int log_size;
+ char const *log_name;
+ char const *log_env;
+ unsigned log_default;
+ unsigned log_level;
+ int log_init;
+
+ su_logger_f *log_logger;
+ void *log_stream;
+};
+
+enum { SU_LOG_MAX = 9 };
+
+/** Initialize a su_log_t structure */
+#define SU_LOG_INIT(name, env, level) \
+ { sizeof(su_log_t), name, env, level, SU_LOG_MAX, 0, NULL, NULL, }
+
+SOFIAPUBFUN void su_log(char const *fmt, ...)
+ __attribute__ ((__format__ (printf, 1, 2)));
+
+SOFIAPUBFUN void su_llog(su_log_t *log, unsigned level, char const *fmt, ...)
+ __attribute__ ((__format__ (printf, 3, 4)));
+SOFIAPUBFUN void su_vllog(su_log_t *log, unsigned level,
+ char const *fmt, va_list ap);
+SOFIAPUBFUN void su_log_redirect(su_log_t *log, su_logger_f *f, void *stream);
+SOFIAPUBFUN void su_log_set_level(su_log_t *log, unsigned level);
+SOFIAPUBFUN void su_log_soft_set_level(su_log_t *log, unsigned level);
+SOFIAPUBFUN void su_log_init(su_log_t *log);
+
+SOFIAPUBVAR su_log_t su_log_default[];
+SOFIAPUBVAR su_log_t su_log_global[];
+
+/** Log the latest su error message */
+SOFIAPUBFUN void su_perror(char const *s);
+
+/** Log the su error message. */
+SOFIAPUBFUN void su_perror2(char const *s, int errcode);
+
+SOFIA_END_DECLS
+
+#endif
+
+#endif /* !defined(SU_LOG_H_NEED_SU_LOG_T) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_md5.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_md5.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,88 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_MD5_H /** Defined when su_md5.h has been included. */
+#define SU_MD5_H
+
+/**@defgroup su_md5 MD5 Digest
+ *
+ * The MD5 message digest algorithm is described in RFC 1321 by R. Rivest,
+ * 1992. The algorithm takes as input a octet string of arbitrary length
+ * and generates a 128-bit hash value, "message digest" from the message
+ * contents.
+ *
+ * While some message collisions (different messages with same MD5 digest)
+ * has been generated, using collisions in an actual attack is much harder
+ * and MD5 can be considered as cryptographically strong.
+ */
+
+/** @file sofia-sip/su_md5.h MD5 digest interface.
+ *
+ * @author <Pekka.Pessi at nokia.com>
+ */
+
+#ifndef SU_TYPES_H
+#include "sofia-sip/su_types.h"
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** MD5 context. */
+typedef struct su_md5_t {
+ uint32_t buf[4];
+ uint32_t bits[2];
+ uint8_t in[64];
+} su_md5_t;
+
+#define SU_MD5_DIGEST_SIZE 16
+
+SOFIAPUBFUN void su_md5_init(su_md5_t *context);
+SOFIAPUBFUN void su_md5_deinit(su_md5_t *context);
+SOFIAPUBFUN void su_md5_update(su_md5_t *context,
+ void const *buf, usize_t len);
+SOFIAPUBFUN void su_md5_strupdate(su_md5_t *ctx, char const *s);
+SOFIAPUBFUN void su_md5_str0update(su_md5_t *ctx, char const *s);
+
+SOFIAPUBFUN void su_md5_iupdate(su_md5_t *context,
+ void const *buf, usize_t len);
+SOFIAPUBFUN void su_md5_striupdate(su_md5_t *ctx, char const *s);
+SOFIAPUBFUN void su_md5_stri0update(su_md5_t *ctx, char const *s);
+
+SOFIAPUBFUN void su_md5_digest(su_md5_t const *ctx,
+ uint8_t digest[SU_MD5_DIGEST_SIZE]);
+SOFIAPUBFUN void su_md5_hexdigest(su_md5_t const *ctx,
+ char digest[2 * SU_MD5_DIGEST_SIZE + 1]);
+
+#define SU_MD5_STRUPDATE(ctx, s) \
+ ((s) ? su_md5_update(ctx, (s), strlen(s)) : (void)0)
+#define SU_MD5_STR0UPDATE(ctx, s) \
+ su_md5_update(ctx, (s) ? (s) : "", (s) ? strlen(s) + 1 : 1)
+#define SU_MD5_STRIUPDATE(ctx, s) \
+ ((s) ? su_md5_iupdate(ctx, (s), strlen(s)) : (void)0)
+#define SU_MD5_STRI0UPDATE(ctx, s) \
+ su_md5_iupdate(ctx, (s) ? (s) : "", (s) ? strlen(s) : 1)
+
+SOFIA_END_DECLS
+
+#endif /* !defined(MD5_H) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_os_nw.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_os_nw.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,122 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_OS_NW_H
+/** Defined when <sofia-sip/su_os_nw.h> has been included. */
+#define SU_OS_NW_H
+
+/**@ingroup su_os_nw
+ * @file sofia-sip/su_os_nw.h Network change events.
+ *
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Aug 15 09:05:18 EEST 2006 martti.mela at nokia.com
+ *
+ * @since Experimental in @VERSION_1_12_2.
+ * Note that this is expected to change in future releases.
+ */
+
+/* ---------------------------------------------------------------------- */
+/* Includes */
+
+#ifndef SU_H
+#include "sofia-sip/su.h"
+#endif
+
+#ifndef SU_TIME_H
+#include "sofia-sip/su_time.h"
+#endif
+
+#ifndef SU_ALLOC_H
+#include "sofia-sip/su_alloc.h"
+#endif
+
+#ifndef SU_WAIT_H
+#include "sofia-sip/su_wait.h"
+#endif
+
+#if SU_HAVE_POLL
+#include <sys/poll.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/* ---------------------------------------------------------------------- */
+/* network-changed callback */
+
+#ifndef SU_NETWORK_CHANGED_MAGIC_T
+/**Default type of application context for network_changed function.
+ *
+ * Application may define the typedef ::su_network_changed_magic_t to appropriate type
+ * by defining macro #SU_NETWORK_CHANGED_MAGIC_T before including <su_os_nw.h>, for
+ * example,
+ * @code
+ * #define SU_NETWORK_CHANGED_MAGIC_T struct context
+ * #include <su_os_nw.h>
+ * @endcode
+ *
+ * @since New in @VERSION_1_12_2.
+ */
+#define SU_NETWORK_CHANGED_MAGIC_T void
+#endif
+
+/** <a href="#su_root_t">Root context</a> pointer type.
+ *
+ * Application may define the typedef ::su_network_changed_magic_t to appropriate type
+ * by defining macro #SU_NETWORK_CHANGED_MAGIC_T before including <su_os_nw.h>, for
+ * example,
+ * @code
+ * #define SU_NETWORK_CHANGED_MAGIC_T struct context
+ * #include <su_os_nw.h>
+ * @endcode
+ *
+ * @since New in @VERSION_1_12_2.
+ */
+typedef SU_NETWORK_CHANGED_MAGIC_T su_network_changed_magic_t;
+
+typedef struct su_network_changed_s su_network_changed_t;
+
+/** Function prototype for network-changed callback .
+ *
+ *
+ * @since New in @VERSION_1_12_2.
+ */
+typedef void (su_network_changed_f)(su_network_changed_magic_t *, su_root_t *);
+
+
+/* ---------------------------------------------------------------------- */
+/* Functions */
+
+/* Network-changed */
+SOFIAPUBFUN su_network_changed_t *
+su_root_add_network_changed(su_home_t *home,
+ su_root_t *root,
+ su_network_changed_f *,
+ su_network_changed_magic_t *);
+SOFIAPUBFUN int su_root_remove_network_changed(su_network_changed_t *);
+
+SOFIA_END_DECLS
+
+#endif /* SU_OS_NW_H */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_osx_runloop.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_osx_runloop.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,53 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_OSX_RUNLOOP_H
+/** Defined when <sofia-sip/su_osx_runloop.h> has been included. */
+#define SU_OSX_RUNLOOP_H
+
+/**
+ * @file sofia-sip/su_osx_runloop.h
+ * @brief OSX Run Loop integration.
+ *
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ *
+ * @date Created: Fri Sep 22 16:49:51 EEST 2006 mela
+ *
+ * @NEW_1_12_4.
+ */
+
+#ifndef SU_WAIT_H
+#include <sofia-sip/su_wait.h>
+#endif
+
+#include <CoreFoundation/CoreFoundation.h>
+
+SOFIA_BEGIN_DECLS
+
+su_root_t *su_root_osx_runloop_create(su_root_magic_t *) __attribute__((__malloc__));
+void su_root_osx_prepare_run(su_root_t *);
+
+SOFIA_END_DECLS
+
+#endif /* !defined SU_OSX_RUNLOOP_H */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_strlst.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_strlst.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,129 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_STRLST_H /** Defined when <sofia-sip/su_strlst.h> has been included. */
+#define SU_STRLST_H
+/**@ingroup su_strlst
+ * @file sofia-sip/su_strlst.h String lists
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Fri May 3 09:13:22 2002 ppessi
+ */
+
+#ifndef SU_ALLOC_H
+#include <sofia-sip/su_alloc.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+typedef struct su_strlst_s su_strlst_t;
+
+/** Create a string list. */
+SU_DLL su_strlst_t *su_strlst_create(su_home_t *home)
+ __attribute__((__malloc__));
+/** Destroy a string list. */
+SU_DLL void su_strlst_destroy(su_strlst_t *);
+
+SU_DLL su_strlst_t *su_strlst_create_with(su_home_t *, char const *, ...)
+ __attribute__((__malloc__));
+
+SU_DLL su_strlst_t *su_strlst_create_with_dup(su_home_t *, char const *, ...)
+ __attribute__((__malloc__));
+
+SU_DLL su_strlst_t *su_strlst_vcreate_with(su_home_t *,
+ char const *,
+ va_list va)
+ __attribute__((__malloc__));
+
+SU_DLL su_strlst_t *su_strlst_vcreate_with_dup(su_home_t *,
+ char const *,
+ va_list va)
+ __attribute__((__malloc__));
+
+/** Shallow copy a string list. */
+SU_DLL su_strlst_t *su_strlst_copy(su_home_t *home, su_strlst_t const *orig);
+
+/** Deep copy a string list. */
+SU_DLL su_strlst_t *su_strlst_dup(su_home_t *home, su_strlst_t const *orig);
+
+/** Duplicate and append a string to list. */
+SU_DLL char *su_strlst_dup_append(su_strlst_t *, char const *str);
+
+/** Append a string to list. */
+SU_DLL char const *su_strlst_append(su_strlst_t *, char const *str);
+
+/** Append a formatted string to the list. */
+SU_DLL char const *su_slprintf(su_strlst_t *self, char const *fmt, ...);
+
+/** Append a formatted string to the list. */
+SU_DLL char const *su_slvprintf(su_strlst_t *self, char const *fmt, va_list ap);
+
+/** Get a numbered item from list. */
+SU_DLL char const *su_strlst_item(su_strlst_t const *, usize_t i);
+
+/** Set a numbered item to list */
+SU_DLL char const *su_strlst_set_item(su_strlst_t *self, usize_t i,
+ char const *s);
+
+/** Remove a numbered item from list. */
+SU_DLL char const *su_strlst_remove(su_strlst_t *, usize_t i);
+
+/** Concatenate list of strings to one string. */
+SU_DLL char *su_strlst_join(su_strlst_t *s, su_home_t *home,
+ char const *sep)
+ __attribute__((__malloc__));
+
+/** Split a string. */
+SU_DLL su_strlst_t *su_strlst_split(su_home_t *, char *s, char const *sep)
+ __attribute__((__malloc__));
+
+/** Duplicate and split a string. */
+SU_DLL su_strlst_t *su_strlst_dup_split(su_home_t *, char const *s,
+ char const *sep)
+ __attribute__((__malloc__));
+
+/** Get number of items in list. */
+SU_DLL usize_t su_strlst_len(su_strlst_t const *l);
+
+#if SU_HAVE_INLINE
+static inline
+su_home_t *su_strlst_home(su_strlst_t *s)
+{
+ return (su_home_t *)s;
+}
+#else
+#define su_strlst_home(s) ((su_home_t *)(s))
+#endif
+
+/** Get a string array from list. */
+SU_DLL char const **su_strlst_get_array(su_strlst_t *self)
+ __attribute__((__malloc__));
+
+/** Free a string array */
+SU_DLL void su_strlst_free_array(su_strlst_t *self, char const * array[]);
+
+SOFIA_END_DECLS
+
+#endif /* ! defined(SU_STRLST_H) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tag.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tag.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,224 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_TAG_H
+/** Defined when <sofia-sip/su_tag.h> has been included. */
+#define SU_TAG_H
+
+/**@SU_TAG
+ * @file sofia-sip/su_tag.h Object-oriented tags and tag list interface.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Feb 20 19:48:18 2001 ppessi
+ */
+
+#ifndef SU_CONFIG_H
+#include <sofia-sip/su_config.h>
+#endif
+
+#ifndef SU_TYPES_H
+#include <sofia-sip/su_types.h>
+#endif
+
+#ifndef SU_ALLOC_H
+#include <sofia-sip/su_alloc.h>
+#endif
+
+#include <stdarg.h>
+#include <stddef.h> /* ANSI C: size_t */
+
+SOFIA_BEGIN_DECLS
+
+/** Tag item type */
+typedef struct tag_type_s const *tag_type_t;
+/** Tag item value */
+typedef intptr_t tag_value_t;
+
+/** Tag list signature */
+#define TAG_LIST tag_type_t tag, tag_value_t value, ...
+
+/** Tag item. */
+typedef struct {
+ tag_type_t t_tag; /**< Tag */
+ tag_value_t t_value; /**< Value */
+} tagi_t;
+
+/** Tag type class */
+typedef struct tag_class_s const tag_class_t;
+
+struct tag_type_s {
+ char const *tt_ns;
+ char const *tt_name;
+ tag_class_t *tt_class;
+ tag_value_t tt_magic;
+};
+
+/** Definition of tag type. */
+typedef struct tag_type_s const tag_typedef_t[1];
+
+/** End of tag list */
+SOFIAPUBVAR tag_typedef_t tag_null;
+
+/** Ignore tag item. */
+SOFIAPUBVAR tag_typedef_t tag_skip;
+
+/** Jump to another tag list */
+SOFIAPUBVAR tag_typedef_t tag_next;
+
+/** Any tag accepted when filtering. */
+SOFIAPUBVAR tag_typedef_t tag_any;
+
+/** Filter tag using function as argument.
+ * @since New in @VERSION_1_12_2.
+ */
+SOFIAPUBVAR tag_typedef_t tag_filter;
+
+/** Prototype for filtering function used with TAG_FILTER().
+ * @since New in @VERSION_1_12_2.
+ */
+typedef int tag_filter_f(tagi_t const *filter, tagi_t const *dest);
+
+/** @HI Initialize a tag item marking the end of list. Equivalent to TAG_END(). */
+#define TAG_NULL() (tag_type_t)0, (tag_value_t)0
+
+/** @HI Initialize a tag item marking the end of list. Equivalent to TAG_NULL(). */
+#define TAG_END() (tag_type_t)0, (tag_value_t)0
+
+/** @HI Initialize an empty tag item. */
+#define TAG_SKIP(x) tag_skip, (tag_value_t)(x)
+
+/** @HI Initialize a tag item pointing to another tag list at @a next. */
+#define TAG_NEXT(next) tag_next, (tag_value_t)(next)
+
+/** @HI Initialize a filter tag item accepting any item. */
+#define TAG_ANY() tag_any, (tag_value_t)0
+
+/** @HI Initialize a @a item if condition is true;
+ * otherwise, initialize an empty tag item. */
+#define TAG_IF(condition, item) !(condition) ? tag_skip : item
+
+/** @HI Initialize a filter tag item accepting any item.
+ * @since New in @VERSION_1_12_2.
+ */
+#define TAG_FILTER(function) tag_filter, tag_filter_v(function)
+
+/** Convert tag item to a string */
+SOFIAPUBFUN int t_snprintf(tagi_t const *t, char b[], size_t size);
+
+/** Convert string to a tag value */
+SOFIAPUBFUN int t_scan(tag_type_t tt, su_home_t *home, char const *s,
+ tag_value_t *return_value);
+
+/* Tagarg functions */
+SOFIAPUBFUN tagi_t *tl_tlist(su_home_t *, tag_type_t, tag_value_t, ...);
+SOFIAPUBFUN size_t tl_tmove(tagi_t *dst, size_t, tag_type_t, tag_value_t, ...);
+SOFIAPUBFUN int tl_gets(tagi_t const lst[], tag_type_t, tag_value_t, ...);
+SOFIAPUBFUN int tl_tgets(tagi_t lst[], tag_type_t, tag_value_t, ...);
+SOFIAPUBFUN tagi_t *tl_tfilter(su_home_t *, tagi_t const lst[],
+ tag_type_t, tag_value_t, ...);
+SOFIAPUBFUN int tl_tremove(tagi_t lst[], tag_type_t, tag_value_t, ...);
+
+/* Low-level taglist manipulation functions */
+SOFIAPUBFUN size_t tl_len(tagi_t const lst[]);
+SOFIAPUBFUN size_t tl_xtra(tagi_t const lst[], size_t offset);
+SOFIAPUBFUN tagi_t *tl_next(tagi_t const *lst);
+SOFIAPUBFUN tagi_t *tl_move(tagi_t *dst, tagi_t const src[]);
+SOFIAPUBFUN tagi_t *tl_dup(tagi_t dst[], tagi_t const lst[], void **bb);
+SOFIAPUBFUN tagi_t *tl_adup(su_home_t *, tagi_t const lst[]);
+SOFIAPUBFUN void tl_free(tagi_t list[]);
+
+SOFIAPUBFUN tagi_t *tl_find(tagi_t const lst[], tag_type_t tt);
+SOFIAPUBFUN tagi_t *tl_find_last(tagi_t const lst[], tag_type_t tt);
+SOFIAPUBFUN tagi_t *tl_filter(tagi_t *, tagi_t const filter[],
+ tagi_t const lst[], void **b);
+SOFIAPUBFUN tagi_t *tl_afilter(su_home_t *, tagi_t const filter[],
+ tagi_t const lst[]);
+
+SOFIAPUBFUN tagi_t *tl_filtered_tlist(su_home_t *home, tagi_t const filter[],
+ tag_type_t, tag_value_t, ...);
+
+SOFIAPUBFUN size_t tl_vlen(va_list ap);
+SOFIAPUBFUN tagi_t *tl_list(tag_type_t tag, tag_value_t value, ...);
+SOFIAPUBFUN tagi_t *tl_vlist2(tag_type_t tag, tag_value_t value, va_list ap);
+SOFIAPUBFUN tagi_t *tl_vlist(va_list ap);
+SOFIAPUBFUN tagi_t *tl_llist(tag_type_t tag, tag_value_t value, ...);
+SOFIAPUBFUN tagi_t *tl_vllist(tag_type_t tag, tag_value_t value, va_list ap);
+SOFIAPUBFUN void tl_vfree(tagi_t *t);
+
+/** Align to pointer size */
+#define SU_ALIGN(x) \
+((sizeof(void *) - ((intptr_t)(x) & (sizeof(void *) - 1))) & (sizeof(void *) - 1))
+
+#if SU_HAVE_INLINE
+su_inline tag_value_t tag_int_v(int v) { return (tag_value_t)v; }
+su_inline tag_value_t tag_int_vr(int *vp) { return (tag_value_t)vp; }
+su_inline tag_value_t tag_uint_v(unsigned v) { return (tag_value_t)v; }
+su_inline tag_value_t tag_uint_vr(unsigned *vp) { return (tag_value_t)vp; }
+su_inline tag_value_t tag_usize_v(usize_t v) { return (tag_value_t)v; }
+su_inline tag_value_t tag_usize_vr(usize_t *vp) { return (tag_value_t)vp; }
+su_inline tag_value_t tag_size_v(size_t v) { return (tag_value_t)v; }
+su_inline tag_value_t tag_size_vr(size_t *vp) { return (tag_value_t)vp; }
+su_inline tag_value_t tag_bool_v(int v) { return v != 0; }
+su_inline tag_value_t tag_bool_vr(int *vp) { return (tag_value_t)vp; }
+su_inline tag_value_t tag_ptr_v(void *v) { return (tag_value_t)v; }
+su_inline tag_value_t tag_ptr_vr(void *vp, void *v)
+ { (void)v; return(tag_value_t)vp; }
+su_inline tag_value_t tag_cptr_v(void const *v) { return (tag_value_t)v; }
+su_inline tag_value_t tag_cptr_vr(void *vp, void const *v)
+ { (void)v; return(tag_value_t)vp; }
+su_inline tag_value_t tag_cstr_v(char const *v) { return (tag_value_t)v; }
+su_inline tag_value_t tag_cstr_vr(char const**vp) {return(tag_value_t)vp;}
+su_inline tag_value_t tag_str_v(char const *v) { return (tag_value_t)v; }
+su_inline tag_value_t tag_str_vr(char const **vp) {return(tag_value_t)vp;}
+#if __cplusplus
+extern "C++" {
+ static inline tag_value_t tag_ptr_v(void const *v)
+ { return (tag_value_t)v; }
+ static inline tag_value_t tag_ptr_vr(void *vp, void const *p)
+ { return(tag_value_t)vp; }
+ static inline tag_value_t tag_str_v(char *v) { return (tag_value_t)v; }
+ static inline tag_value_t tag_str_vr(char **vp) {return(tag_value_t)vp;}
+}
+#endif
+su_inline tag_value_t tag_filter_v(tag_filter_f *v) {return(tag_value_t)v;}
+#else
+#define tag_int_v(v) (tag_value_t)(v)
+#define tag_int_vr(v) (tag_value_t)(v)
+#define tag_uint_v(v) (tag_value_t)(v)
+#define tag_uint_vr(v) (tag_value_t)(v)
+#define tag_bool_v(v) (tag_value_t)(v != 0)
+#define tag_bool_vr(v) (tag_value_t)(v)
+#define tag_ptr_v(v) (tag_value_t)(v)
+#define tag_ptr_vr(v,x) (tag_value_t)(v)
+#define tag_cstr_v(v) (tag_value_t)(v)
+#define tag_cstr_vr(v) (tag_value_t)(v)
+#define tag_str_v(v) (tag_value_t)(v)
+#define tag_str_vr(v) (tag_value_t)(v)
+#define tag_filter_v(v) (tag_value_t)(v)
+#endif
+
+SOFIA_END_DECLS
+
+#endif /** !defined(SU_TAG_H) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tag_class.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tag_class.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,128 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_TAG_CLASS_H
+/** Defined when <sofia-sip/su_tag_class.h> has been included. */
+#define SU_TAG_CLASS_H
+
+/**@SU_TAG
+ * @file su_tag_class.h
+ * @brief Tag class interface for object-oriented tags
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Feb 21 00:49:41 2001 ppessi
+ */
+
+#ifndef SU_TAG_H
+#include <sofia-sip/su_tag.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/* Macros for defining tag classes */
+
+#ifndef TAG_NAMESPACE
+/** Default namespace for tags */
+#define TAG_NAMESPACE ""
+#endif
+
+#define TAG_TYPEDEF(t, type) \
+ {{ TAG_NAMESPACE, #t, type ## _tag_class }}
+
+#define INTTAG_TYPEDEF(t) TAG_TYPEDEF(t, int)
+#define UINTTAG_TYPEDEF(t) TAG_TYPEDEF(t, uint)
+#define USIZETAG_TYPEDEF(t) TAG_TYPEDEF(t, usize)
+#define SIZETAG_TYPEDEF(t) TAG_TYPEDEF(t, size)
+#define BOOLTAG_TYPEDEF(t) TAG_TYPEDEF(t, bool)
+#define PTRTAG_TYPEDEF(t) TAG_TYPEDEF(t, ptr)
+#define SOCKETTAG_TYPEDEF(t) TAG_TYPEDEF(t, socket)
+#define CSTRTAG_TYPEDEF(t) TAG_TYPEDEF(t, cstr)
+#define STRTAG_TYPEDEF(t) TAG_TYPEDEF(t, str)
+#define NSTAG_TYPEDEF(t) TAG_TYPEDEF(t, ns)
+
+struct tag_class_s {
+ int tc_size;
+ tagi_t const *(*tc_next)(tagi_t const *t);
+ size_t (*tc_len)(tagi_t const *t);
+ tagi_t *(*tc_move)(tagi_t *dst, tagi_t const *src);
+ size_t (*tc_xtra)(tagi_t const *t, size_t offset);
+ tagi_t *(*tc_dup)(tagi_t *dst, tagi_t const *src, void **b);
+ tagi_t *(*tc_free)(tagi_t *t);
+ tagi_t const *(*tc_find)(tag_type_t t, tagi_t const lst[]);
+ int (*tc_snprintf)(tagi_t const *t, char b[], size_t size);
+ tagi_t *(*tc_filter)(tagi_t *dst, tagi_t const f[], tagi_t const *src,
+ void **bb);
+ int (*tc_ref_set)(tag_type_t tt, void *ref, tagi_t const value[]);
+ int (*tc_scan)(tag_type_t tt, su_home_t *home,
+ char const *str,
+ tag_value_t *return_value);
+};
+
+SOFIAPUBVAR tag_class_t end_tag_class[];
+SOFIAPUBVAR tag_class_t int_tag_class[];
+SOFIAPUBVAR tag_class_t uint_tag_class[];
+SOFIAPUBVAR tag_class_t usize_tag_class[];
+SOFIAPUBVAR tag_class_t size_tag_class[];
+SOFIAPUBVAR tag_class_t bool_tag_class[];
+SOFIAPUBVAR tag_class_t ptr_tag_class[];
+SOFIAPUBVAR tag_class_t socket_tag_class[];
+SOFIAPUBVAR tag_class_t cstr_tag_class[];
+SOFIAPUBVAR tag_class_t str_tag_class[];
+SOFIAPUBVAR tag_class_t ns_tag_class[];
+
+#define REFTAG_TYPEDEF(tag) \
+ {{ TAG_NAMESPACE, #tag "_ref", ref_tag_class, (tag_value_t)tag }}
+
+SOFIAPUBVAR tag_class_t ref_tag_class[];
+
+SOFIAPUBFUN int t_ptr_snprintf(tagi_t const *t, char b[], size_t size);
+SOFIAPUBFUN int t_ptr_ref_set(tag_type_t tt, void *ref, tagi_t const value[]);
+SOFIAPUBFUN int t_ptr_scan(tag_type_t, su_home_t *, char const *,
+ tag_value_t *return_value);
+
+SOFIAPUBFUN int t_bool_snprintf(tagi_t const *t, char b[], size_t size);
+SOFIAPUBFUN int t_bool_ref_set(tag_type_t tt, void *ref, tagi_t const value[]);
+SOFIAPUBFUN int t_bool_scan(tag_type_t, su_home_t *, char const *,
+ tag_value_t *return_value);
+
+SOFIAPUBFUN int t_int_snprintf(tagi_t const *t, char b[], size_t size);
+SOFIAPUBFUN int t_int_ref_set(tag_type_t tt, void *ref, tagi_t const value[]);
+SOFIAPUBFUN int t_int_scan(tag_type_t, su_home_t *, char const *,
+ tag_value_t *return_value);
+
+SOFIAPUBFUN int t_uint_snprintf(tagi_t const *t, char b[], size_t size);
+SOFIAPUBFUN int t_uint_ref_set(tag_type_t tt, void *ref, tagi_t const value[]);
+SOFIAPUBFUN int t_uint_scan(tag_type_t, su_home_t *, char const *,
+ tag_value_t *return_value);
+
+SOFIAPUBFUN tagi_t *t_str_dup(tagi_t *dst, tagi_t const *src, void **b);
+SOFIAPUBFUN size_t t_str_xtra(tagi_t const *t, size_t offset);
+SOFIAPUBFUN int t_str_snprintf(tagi_t const *t, char b[], size_t size);
+SOFIAPUBFUN int t_str_scan(tag_type_t, su_home_t *, char const *,
+ tag_value_t *return_value);
+
+SOFIA_END_DECLS
+
+#endif /* !defined(SU_TAG_CLASS_H) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tag_inline.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tag_inline.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,150 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_TAG_INLINE_H
+/** Defined when <sofia-sip/su_tag_inline.h> has been included */
+#define SU_TAG_INLINE_H
+/**@SU_TAG
+ * @file sofia-sip/su_tag_inline.h
+ * Inline functions for object tags and tag lists.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Feb 20 19:48:18 2001 ppessi
+ */
+
+#ifndef SU_TAG_H
+#include <sofia-sip/su_tag.h>
+#endif
+#ifndef SU_TAG_CLASS_H
+#include <sofia-sip/su_tag_class.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+#define tt_next tt_class->tc_next
+#define tt_len tt_class->tc_len
+#define tt_move tt_class->tc_move
+#define tt_xtra tt_class->tc_xtra
+#define tt_dup tt_class->tc_dup
+#define tt_free tt_class->tc_free
+#define tt_find tt_class->tc_find
+#define tt_snprintf tt_class->tc_snprintf
+#define tt_filter tt_class->tc_filter
+
+#define TAG_TYPE_OF(t) ((t) && (t)->t_tag ? (t)->t_tag : tag_null)
+
+/** Check if the tag item is last in current list */
+static inline int t_end(tagi_t const *t)
+{
+ tag_type_t tt = TAG_TYPE_OF(t);
+
+ /* XXX - virtualize this */
+
+ return tt == tag_null || tt == tag_next;
+}
+
+static inline tagi_t const *t_next(tagi_t const *t)
+{
+ tag_type_t tt = TAG_TYPE_OF(t);
+
+ if (tt->tt_next)
+ return tt->tt_next(t);
+ else
+ return t + 1;
+}
+
+static inline tagi_t *t_move(tagi_t *dst, tagi_t const *src)
+{
+ tag_type_t tt = TAG_TYPE_OF(src);
+
+ if (tt->tt_move)
+ return tt->tt_move(dst, src);
+
+ *dst = *src;
+ return dst + 1;
+}
+
+static inline size_t t_xtra(tagi_t const *t, size_t offset)
+{
+ tag_type_t tt = TAG_TYPE_OF(t);
+
+ if (tt->tt_xtra)
+ return tt->tt_xtra(t, offset);
+
+ return 0;
+}
+
+static inline tagi_t *t_dup(tagi_t *dst, tagi_t const *src, void **bb)
+{
+ tag_type_t tt = TAG_TYPE_OF(src);
+
+ if (tt->tt_dup)
+ return tt->tt_dup(dst, src, bb);
+
+ *dst = *src;
+ return dst + 1;
+}
+
+static inline tagi_t const *t_find(tag_type_t tt, tagi_t const *lst)
+{
+ if (!tt)
+ return NULL;
+
+ if (tt->tt_find)
+ return tt->tt_find(tt, lst);
+
+ for (; lst; lst = t_next(lst)) {
+ if (tt == lst->t_tag)
+ return lst;
+ }
+
+ return NULL;
+}
+
+static inline tagi_t *t_free(tagi_t *t)
+{
+ tag_type_t tt = TAG_TYPE_OF(t);
+
+ if (tt->tt_free)
+ return tt->tt_free(t);
+ else if (tt->tt_next)
+ return (tagi_t *)tt->tt_next(t);
+ else
+ return t + 1;
+}
+
+static inline size_t t_len(tagi_t const *t)
+{
+ tag_type_t tt = TAG_TYPE_OF(t);
+
+ if (tt->tt_len)
+ return tt->tt_len(t);
+
+ return sizeof(*t);
+}
+
+SOFIA_END_DECLS
+
+#endif /* !defined(SU_TAG_INLINE_H) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tag_io.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tag_io.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,65 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_TAG_IO_H
+/** Defined when <sofia-sip/su_tag_io.h> has been included */
+#define SU_TAG_IO_H
+
+/**@SU_TAG
+ * @file sofia-sip/su_tag_io.h
+ * @brief I/O interface for tag lists
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Feb 21 12:10:06 2001 ppessi
+ */
+
+#ifndef SU_TAG_H
+#include <sofia-sip/su_tag.h>
+#endif
+#ifndef SU_H
+#include <sofia-sip/su.h>
+#endif
+
+#include <stdio.h>
+
+SOFIA_BEGIN_DECLS
+
+SOFIAPUBFUN void tl_print(FILE *f, char const *title, tagi_t const lst[]);
+
+#if SU_HAVE_INLINE
+su_inline tag_value_t tag_socket_v(su_socket_t v) {
+ return (tag_value_t)v;
+}
+su_inline tag_value_t tag_socket_vr(su_socket_t *vp) {
+ return (tag_value_t)vp;
+}
+#else
+#define tag_socket_v(v) (tag_value_t)(v)
+#define tag_socket_vr(v) (tag_value_t)(v)
+#endif
+
+SOFIA_END_DECLS
+
+#endif
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tagarg.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tagarg.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,190 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_TAGARG_H
+/** Defined when <sofia-sip/su_tagarg.h> has been included. */
+#define SU_TAGARG_H
+
+/**@SU_TAG
+ * @file sofia-sip/su_tagarg.h Tagged argument lists
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Feb 20 19:48:18 2001 ppessi
+ */
+
+#ifndef SU_TAG_H
+#include <sofia-sip/su_tag.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/**@page tagarg Tagarg Functions
+ *
+ * A @em tagarg function may be called with a varying number of tagged
+ * arguments. The include file <su_tagarg.h> declares a type ta_list and
+ * defines four macros (ta_start(), ta_args(), ta_tags() and ta_end()) for
+ * accessing the argument list.
+ *
+ * An example of prototype of a a @em tagarg function is as follows:
+ * @code
+ * int tag_print(FILE *f, tag_type_t tag, tag_value_t value, ...);
+ * @endcode
+ *
+ * Such a function could be called as follows:
+ * @code
+ * tag_print(stdout,
+ * TAG_STRING("a is"), TAG_INT(a),
+ * TAG_STRING("b is"), URLTAG_URL(b),
+ * TAG_IF(c, TAG_STRING("and c is true")),
+ * TAG_END());
+ * @endcode
+ *
+ * @note
+ * The tagged argument list @b must be terminated by a TAG_END(),
+ * TAG_NULL() or TAG_NEXT().
+ */
+
+/**Object for accessing tagged argument lists.
+ *
+ * The called function must declare an object of type ta_list which is
+ * used by the macros ta_start(), ta_args(), ta_tags(), and ta_end().
+ *
+ * If a tagged list is not finished with TAG_END(), TAG_NULL(), or
+ * TAG_NEXT() items, random errors may occur.
+ *
+ * @hideinitializer
+ */
+typedef struct {
+ tagi_t tl[2];
+ va_list ap;
+} ta_list;
+
+/**Macro initializing a ta_list object.
+ *
+ * The ta_start() macro initializes @a ta for subsequent use by ta_args(),
+ * ta_tags() and ta_end(), and must be called first.
+ *
+ * The parameters @a t and @a v are the names of the @c tag and @c value in
+ * the first tag list item before the variable argument list (...).
+ *
+ * The ta_start() macro returns no value.
+ *
+ * @hideinitializer
+ */
+#if SU_HAVE_TAGSTACK
+/* All arguments are saved into stack (left-to-right) */
+#define ta_start(ta, t, v) \
+ do { \
+ tag_type_t ta_start__tag = (t); tag_value_t ta_start__value = (v); \
+ va_start((ta).ap, (v)); \
+ while ((ta_start__tag) == tag_next && (ta_start__value) != 0) { \
+ ta_start__tag = ((tagi_t *)ta_start__value)->t_tag; \
+ if (ta_start__tag == tag_null || ta_start__tag == NULL) \
+ break; \
+ if (ta_start__tag == tag_next) { \
+ ta_start__value = ((tagi_t *)ta_start__value)->t_value; } \
+ else { \
+ ta_start__tag = tag_next; \
+ break; \
+ } \
+ } \
+ (ta).tl->t_tag = ta_start__tag; (ta).tl->t_value = ta_start__value; \
+ if (ta_start__tag != NULL && \
+ ta_start__tag != tag_null && \
+ ta_start__tag != tag_next) { \
+ (ta).tl[1].t_tag = tag_next; \
+ (ta).tl[1].t_value = (tag_value_t)(&(v) + 1); \
+ } else { \
+ (ta).tl[1].t_tag = 0; (ta).tl[1].t_value = (tag_value_t)0; \
+ } \
+ } while(0)
+#else
+/* Tagged arguments are in registers - copy all of them. */
+#define ta_start(ta, t, v) \
+ do { \
+ tag_type_t ta_start__tag = (t); tag_value_t ta_start__value = (v); \
+ va_start((ta).ap, (v)); \
+ while ((ta_start__tag) == tag_next && (ta_start__value) != 0) { \
+ ta_start__tag = ((tagi_t *)ta_start__value)->t_tag; \
+ if (ta_start__tag == tag_null || ta_start__tag == NULL) \
+ break; \
+ if (ta_start__tag == tag_next) { \
+ ta_start__value = ((tagi_t *)ta_start__value)->t_value; \
+ } else { \
+ ta_start__tag = tag_next; \
+ break; \
+ } \
+ } \
+ (ta).tl->t_tag = ta_start__tag; (ta).tl->t_value = ta_start__value; \
+ if (ta_start__tag != NULL && \
+ ta_start__tag != tag_null && \
+ ta_start__tag != tag_next) { \
+ (ta).tl[1].t_tag = tag_next; \
+ (ta).tl[1].t_value = (tag_value_t)tl_vlist((ta).ap); \
+ } else { \
+ (ta).tl[1].t_value = 0; (ta).tl[1].t_value = (tag_value_t)0; \
+ } \
+ } while(0)
+#endif
+
+/**Macro accessing tagged argument list.
+ *
+ * The ta_args() returns a pointer to tag list containing the arguments.
+ *
+ * @hideinitializer
+ */
+#define ta_args(ta) (ta).tl
+
+/**Macro passing tagged argument list as an argument to another function.
+ *
+ * The ta_tags() macro expands to an tag list that can be given as arguments
+ * to a function taking an variable tag item list as an argument.
+ *
+ * @hideinitializer
+ */
+#define ta_tags(ta) \
+ (ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).tl[1].t_value
+
+/**Handle return from function with tagged argument list
+ *
+ * The ta_end() macro handles return from function whose tagged argument
+ * list was initialized by ta_start().
+ *
+ * The ta_end() macro returns no value.
+ *
+ * @hideinitializer
+ */
+#if SU_HAVE_TAGSTACK
+#define ta_end(ta) (va_end((ta).ap), (ta).tl->t_tag = NULL, 0)
+#else
+#define ta_end(ta) \
+ ((((ta).tl[1].t_value) ? \
+ (tl_vfree((tagi_t *)((ta).tl[1].t_value))) : (void)0), \
+ (ta).tl[1].t_value = 0, va_end((ta).ap), 0)
+#endif
+
+SOFIA_END_DECLS
+
+#endif /* !defined(SU_TAGARG_H) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_time.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_time.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,137 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_TIME_H
+/** Defined when <sofia-sip/su_time.h> has been included. */
+#define SU_TIME_H
+/**@ingroup su_time
+ * @file sofia-sip/su_time.h
+ * @brief Time types and functions.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @date Created: Thu Mar 18 19:40:51 1999 pessi
+ *
+ */
+
+#ifndef SU_TYPES_H
+#include "sofia-sip/su_types.h"
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** Time in seconds and microsecondcs.
+ *
+ * The structure su_time_t contains time in seconds and microseconds since
+ * epoch (January 1, 1900).
+ */
+struct su_time_s {
+ unsigned long tv_sec; /**< Seconds */
+ unsigned long tv_usec; /**< Microseconds */
+};
+/** Time in seconds and microsecondcs. */
+typedef struct su_time_s su_time_t;
+
+/** Time difference in microseconds.
+ *
+ * The type su_duration_t is used to present small time differences (24
+ * days), usually calculated between two su_time_t timestamps. Note that
+ * the su_duration_t is signed.
+ */
+typedef long su_duration_t;
+
+enum {
+ /** Maximum duration in milliseconds. */
+ SU_DURATION_MAX = 0x7fffffffL
+};
+#define SU_DURATION_MAX SU_DURATION_MAX
+
+/** NTP timestamp.
+ *
+ * NTP timestamp is defined as microseconds since epoch (1-Jan-1900)
+ * with 64-bit resolution.
+ */
+typedef uint64_t su_ntp_t;
+
+/** Represent NTP consttant */
+#define SU_NTP_C(x) SU_U64_C(x)
+
+#define SU_TIME_CMP(t1, t2) su_time_cmp(t1, t2)
+
+/** Seconds from 1.1.1900 to 1.1.1970. @NEW_1_12_4 */
+#define SU_TIME_EPOCH 2208988800UL
+
+SOFIAPUBFUN su_time_t su_now(void);
+SOFIAPUBFUN void su_time(su_time_t *tv);
+SOFIAPUBFUN long su_time_cmp(su_time_t const t1, su_time_t const t2);
+SOFIAPUBFUN double su_time_diff(su_time_t const t1, su_time_t const t2);
+SOFIAPUBFUN su_duration_t su_duration(su_time_t const t1, su_time_t const t2);
+
+SOFIAPUBFUN su_time_t su_time_add(su_time_t t, su_duration_t dur);
+SOFIAPUBFUN su_time_t su_time_dadd(su_time_t t, double dur);
+
+SOFIAPUBFUN int su_time_print(char *s, int n, su_time_t const *tv);
+
+#define SU_SEC_TO_DURATION(sec) ((su_duration_t)(1000 * (sec)))
+
+SOFIAPUBFUN su_ntp_t su_ntp_now(void);
+SOFIAPUBFUN uint32_t su_ntp_sec(void);
+SOFIAPUBFUN uint32_t su_ntp_hi(su_ntp_t);
+SOFIAPUBFUN uint32_t su_ntp_lo(su_ntp_t);
+SOFIAPUBFUN uint32_t su_ntp_mw(su_ntp_t ntp);
+
+#if !SU_HAVE_INLINE
+SOFIAPUBFUN uint32_t su_ntp_fraq(su_time_t t);
+SOFIAPUBFUN uint32_t su_time_ms(su_time_t t);
+#else
+static SU_INLINE
+/** Middle 32 bit of NTP timestamp. */
+uint32_t su_ntp_fraq(su_time_t t)
+{
+ /*
+ * Multiply usec by 0.065536 (ie. 2**16 / 1E6)
+ *
+ * Utilize fact that 0.065536 == 1024 / 15625
+ */
+ return (t.tv_sec << 16) + (1024 * t.tv_usec + 7812) / 15625;
+}
+
+static SU_INLINE
+/** Time as milliseconds. */
+uint32_t su_time_ms(su_time_t t)
+{
+ return t.tv_sec * 1000 + (t.tv_usec + 500) / 1000;
+}
+#endif
+
+SOFIAPUBFUN su_ntp_t su_ntp_hilo(uint32_t hi, uint32_t lo);
+
+SOFIAPUBFUN uint64_t su_counter(void);
+
+SOFIAPUBFUN uint64_t su_nanocounter(void);
+
+SOFIAPUBFUN uint32_t su_random();
+
+SOFIA_END_DECLS
+
+#endif /* !defined(SU_TIME_H) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_types.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_types.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,166 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_TYPES_H
+/** Defined when <sofia-sip/su_types.h> has been included */
+#define SU_TYPES_H
+/**@file sofia-sip/su_types.h Basic integer types for @b su library.
+ *
+ * This include file provides <stdint.h> or <inttypes.h> types.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @date Created: Thu Mar 18 19:40:51 1999 pessi
+ */
+
+#ifndef SU_CONFIG_H
+#include "sofia-sip/su_config.h"
+#endif
+
+#if SU_HAVE_STDINT
+#include <stdint.h>
+#elif SU_HAVE_INTTYPES
+#include <inttypes.h>
+#endif
+
+#if SU_HAVE_SYS_TYPES
+#include <sys/types.h>
+#endif
+
+#include <stddef.h>
+
+SOFIA_BEGIN_DECLS
+
+#if SU_HAVE_STDINT || SU_HAVE_INTTYPES
+#define SU_S64_T int64_t
+#define SU_U64_T uint64_t
+#define SU_S32_T int32_t
+#define SU_U32_T uint32_t
+#define SU_S16_T int16_t
+#define SU_U16_T uint16_t
+#define SU_S8_T int8_t
+#define SU_U8_T uint8_t
+#define SU_LEAST64_T int_least64_t
+#define SU_LEAST32_T int_least32_t
+#define SU_LEAST16_T int_least16_t
+#define SU_LEAST8_T int_least8_t
+#endif
+
+#if DOXYGEN_ONLY || (!SU_HAVE_STDINT && !SU_HAVE_INTTYPES && SU_HAVE_WIN32)
+
+/* Use macros defined in <su_configure_win32.h> */
+
+#ifndef _INTPTR_T_DEFINED
+/** Integer type large enough to store pointers */
+typedef SU_INTPTR_T intptr_t;
+#endif
+#ifndef _UINTPTR_T_DEFINED
+/** Unsigned integer type large enough to store pointers */
+typedef unsigned SU_INTPTR_T uintptr_t;
+#endif
+
+/** 64-bit unsigned integer */
+typedef SU_U64_T uint64_t;
+/** 64-bit signed integer */
+typedef SU_S64_T int64_t;
+/** 32-bit unsigned integer */
+typedef SU_U32_T uint32_t;
+/** 32-bit signed integer */
+typedef SU_S32_T int32_t;
+/** 16-bit unsigned integer */
+typedef SU_U16_T uint16_t;
+/** 16-bit signed integer */
+typedef SU_S16_T int16_t;
+/** 8-bit unsigned integer */
+typedef SU_U8_T uint8_t;
+/** 8-bit signed integer */
+typedef SU_S8_T int8_t;
+
+/** At least 64-bit integer */
+typedef SU_LEAST64_T int_least64_t;
+/** At least 32-bit integer */
+typedef SU_LEAST32_T int_least32_t;
+/** At least 16-bit integer */
+typedef SU_LEAST16_T int_least16_t;
+/** At least 8-bit integer */
+typedef SU_LEAST8_T int_least8_t;
+#endif
+
+#if !SU_HAVE_STDINT && !SU_HAVE_INTTYPES && !SU_HAVE_WIN32
+#error "no integer types available."
+#endif
+
+/* ---------------------------------------------------------------------- */
+/* size_t types for binary compatibility */
+
+#ifdef SOFIA_SSIZE_T
+/** POSIX type used for a count of bytes or an error indication. */
+typedef SOFIA_SSIZE_T ssize_t;
+#endif
+
+#ifdef SOFIA_ISIZE_T
+/** Compatibility type.
+ *
+ * sofia-sip <= 1.12.1 often used int for count of bytes.
+ * When configured for compatibility with sofia-sip 1.12.0, this is defined
+ * as int, otherwise as size_t. Note that int is signed and size_t is
+ * unsigned.
+ *
+ * @since New in @VERSION_1_12_2.
+ */
+typedef SOFIA_ISIZE_T isize_t;
+#else
+typedef size_t isize_t;
+#endif
+
+#ifdef SOFIA_ISSIZE_T
+/**Compatibility type.
+ *
+ * sofia-sip <= 1.12.1 used int for count of bytes.
+ * When configured for compatibility with sofia-sip 1.12.0, this is defined
+ * as int, otherwise as ssize_t. (-1 is used for error indication).
+ *
+ * @since New in @VERSION_1_12_2.
+ */
+typedef SOFIA_ISSIZE_T issize_t;
+#else
+typedef ssize_t issize_t;
+#endif
+
+#ifdef SOFIA_USIZE_T
+/**Compatibility type.
+ *
+ * sofia-sip <= 1.12.1 sometimes used unsigned int for count of bytes.
+ * When configured for compatibility with sofia-sip 1.12.0, this is defined
+ * as unsigned int, otherwise as size_t.
+ *
+ * @since New in @VERSION_1_12_2.
+ */
+typedef SOFIA_USIZE_T usize_t;
+#else
+typedef size_t usize_t;
+#endif
+
+SOFIA_END_DECLS
+
+#endif /* SU_TYPES_H */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_uniqueid.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_uniqueid.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,124 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_UNIQUEID_H
+/** Defined when <sofia-sip/su_uniqueid.h> has been included. */
+#define SU_UNIQUEID_H
+
+
+/**@ingroup su_uniqueid
+ * @file sofia-sip/su_uniqueid.h
+ *
+ * Functions to handle GloballyUniqueIDs.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Apr 15 06:31:41 1997 pessi
+ *
+ */
+
+#ifndef SU_TYPES_H
+#include <sofia-sip/su_types.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** Globally unique identifier type. */
+typedef union GloballyUniqueIdentifier {
+ unsigned char id[16];
+ struct {
+ uint32_t time_low;
+ uint16_t time_mid;
+ uint16_t time_high_and_version;
+ uint8_t clock_seq_hi_and_reserved;
+ uint8_t clock_seq_low;
+ uint8_t node[6];
+ } s;
+} su_guid_t;
+
+/** Return node identifier */
+SOFIAPUBFUN size_t su_node_identifier(void *address, size_t addrlen);
+
+/** Generate a GUID
+ *
+ * The function guid_generate() generates a new globally unique identifier
+ * for an IP telephony call. The guid follows the structure specified in
+ * the ITU-T recommendation H.225.0 v2. The guid is usable also in SIP
+ * @b Call-ID header.
+ *
+ * @param guid [out] pointer to structure for new call identifier
+ */
+SOFIAPUBFUN void su_guid_generate(su_guid_t *guid);
+
+/** Print guid.
+ *
+ * The function guid_sprintf() formats the IP telephony call identifier
+ * according the human-readable format specified in the ITU-T recommendation
+ * H.225.0 v2. The printed identifier can be used as a SIP @b Call-ID if
+ * the colons in IEEE MAC address are replaced with '-', '+' or other
+ * character allowed in SIP @e token.
+ *
+ * @param buf [out] buffer to store the formatted globally unique identifier
+ * @param len [in] size of buffer @a buf (should be at least guid_strlen bytes)
+ * @param guid [in] pointer to structure containing globally unique identifier
+ *
+ * @retval
+ * The function guid_sprintf() returns length of the formatted
+ * globally unique identifier excluding the final NUL.
+ */
+SOFIAPUBFUN isize_t su_guid_sprintf(char* buf, size_t len, su_guid_t const *guid);
+
+enum {
+ /** Length of guid in hex format */
+ su_guid_strlen = 8 + 5 + 5 + 5 + 13
+};
+
+/** Random integer in range [lb, ub] (inclusive).
+ *
+ * The function randint() generates a pseudo-random integer in the range
+ * [ln, ub] (inclusive).
+ *
+ * @param lb [in] lower bound
+ * @param ub [in] upper bound
+ *
+ * @return
+* The function randint() returns a pseudo-random integer.
+ */
+SOFIAPUBFUN int su_randint(int lb, int ub);
+
+/** Fill memory with random values.
+ *
+ * The function randmem() fills the given memory range with pseudo-random data.
+ *
+ * @param mem [out] pointer to the beginning of the memory area to be filled
+ * @param siz [in] size fo the memory area in bytes
+ */
+SOFIAPUBFUN void *su_randmem(void *mem, size_t siz);
+
+/** Generate a random 32-bit integer. */
+SOFIAPUBFUN uint32_t su_random();
+
+SOFIA_END_DECLS
+
+#endif
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_vector.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_vector.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,89 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_VECTOR_H
+/** Defined when <sofia-sip/su_vector.h> has been included. */
+#define SU_VECTOR_H
+
+/**@file sofia-sip/su_vector.h
+ * @brief Vector interface
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Fri Sep 27 14:31:15 2002 ppessi
+ */
+
+#ifndef SU_ALLOC_H
+#include <sofia-sip/su_alloc.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+typedef struct su_vector_s su_vector_t;
+typedef void (* su_free_func_t) (void *data);
+
+/** Create a vector. */
+SU_DLL su_vector_t *su_vector_create(su_home_t *home, su_free_func_t free_f)
+ __attribute__((__malloc__));
+
+/** Destroy a vector. */
+SU_DLL void su_vector_destroy(su_vector_t *);
+
+/** Insert an item to vector. */
+SU_DLL int su_vector_insert(su_vector_t *vector, usize_t index, void *item);
+
+SU_DLL int su_vector_remove(su_vector_t *vector, usize_t index);
+
+/** Append a item to vector. */
+SU_DLL int su_vector_append(su_vector_t *, void *item);
+
+/** Get a numbered item from vector. */
+SU_DLL void *su_vector_item(su_vector_t const *, usize_t i);
+
+/** Get number of items in vector. */
+SU_DLL usize_t su_vector_len(su_vector_t const *l);
+
+SU_DLL int su_vector_empty(su_vector_t *vector);
+SU_DLL int su_vector_is_empty(su_vector_t const *vector);
+
+#if SU_HAVE_INLINE
+static inline
+su_home_t *su_vector_home(su_vector_t *s)
+{
+ return (su_home_t *)s;
+}
+#else
+#define su_vector_home(s) ((su_home_t *)(s))
+#endif
+
+/** Get an array of pointers from the vector. */
+SU_DLL void **su_vector_get_array(su_vector_t *)
+ __attribute__((__malloc__));
+
+/** Free the array */
+SU_DLL void su_vector_free_array(su_vector_t *, void *array[]);
+
+SOFIA_END_DECLS
+
+#endif /* !defined SU_VECTOR_H */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_wait.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_wait.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,477 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_WAIT_H
+/** Defined when <sofia-sip/su_wait.h> has been included. */
+#define SU_WAIT_H
+
+/**@ingroup su_wait
+ * @file sofia-sip/su_wait.h Syncronization and threading interface.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Sep 14 15:51:04 1999 ppessi
+ */
+
+/* ---------------------------------------------------------------------- */
+/* Includes */
+
+#ifndef SU_H
+#include "sofia-sip/su.h"
+#endif
+
+#ifndef SU_TIME_H
+#include "sofia-sip/su_time.h"
+#endif
+#if SU_HAVE_POLL
+#include <sys/poll.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/* ---------------------------------------------------------------------- */
+/* Constants */
+
+#if SU_HAVE_POLL || DOCUMENTATION_ONLY
+/** Compare wait object. @HI */
+#define SU_WAIT_CMP(x, y) \
+ (((x).fd - (y).fd) ? ((x).fd - (y).fd) : ((x).events - (y).events))
+
+/** Incoming data is available on socket. @HI */
+#define SU_WAIT_IN (POLLIN)
+/** Data can be sent on socket. @HI */
+#define SU_WAIT_OUT (POLLOUT)
+/** Socket is connected. @HI */
+#define SU_WAIT_CONNECT (POLLOUT)
+/** An error occurred on socket. @HI */
+#define SU_WAIT_ERR (POLLERR)
+/** The socket connection was closed. @HI */
+#define SU_WAIT_HUP (POLLHUP)
+/** A listening socket accepted a new connection. @HI */
+#define SU_WAIT_ACCEPT (POLLIN)
+
+/** No timeout for su_wait(). */
+#define SU_WAIT_FOREVER (-1)
+/** The return value of su_wait() if timeout occurred. */
+#define SU_WAIT_TIMEOUT (-2)
+
+/** Initializer for a wait object. @HI */
+#define SU_WAIT_INIT { INVALID_SOCKET, 0, 0 }
+
+/** Maximum number of sources supported by su_wait() */
+#define SU_WAIT_MAX (0x7fffffff)
+
+#elif SU_HAVE_WINSOCK
+
+#define SU_WAIT_CMP(x, y) ((intptr_t)(x) - (intptr_t)(y))
+
+#define SU_WAIT_IN (FD_READ)
+#define SU_WAIT_OUT (FD_WRITE)
+#define SU_WAIT_CONNECT (FD_CONNECT)
+#define SU_WAIT_ERR (0) /* let's get it on */
+#define SU_WAIT_HUP (FD_CLOSE)
+#define SU_WAIT_ACCEPT (FD_ACCEPT)
+
+#define SU_WAIT_FOREVER (WSA_INFINITE)
+#define SU_WAIT_TIMEOUT (WSA_WAIT_TIMEOUT)
+
+#define SU_WAIT_INIT NULL
+
+#define SU_WAIT_MAX (64)
+
+#else
+#define SU_WAIT_CMP(x, y)
+#define SU_WAIT_IN
+#define SU_WAIT_OUT
+#define SU_WAIT_ERR
+#define SU_WAIT_HUP
+#define SU_WAIT_ACCEPT
+#define SU_WAIT_FOREVER
+#define SU_WAIT_TIMEOUT
+
+#define SU_WAIT_INIT
+
+#endif
+
+/* ---------------------------------------------------------------------- */
+/* Types */
+
+#if 0
+typedef struct _pollfd {
+ su_socket_t fd; /* file descriptor */
+ short events; /* requested events */
+ short revents; /* returned events */
+} su_wait_t;
+#elif SU_HAVE_POLL
+typedef struct pollfd su_wait_t;
+#elif SU_HAVE_WINSOCK
+typedef HANDLE su_wait_t;
+#else
+/** Wait object. */
+typedef struct os_specific su_wait_t;
+#endif
+
+/* Used by AD */
+typedef int su_success_t;
+
+/* ---------------------------------------------------------------------- */
+
+/** <a href="#su_root_t">Root object</a> type. */
+typedef struct su_root_s su_root_t;
+
+#ifndef SU_ROOT_MAGIC_T
+/**Default type of application context for <a href="#su_root_t">su_root_t</a>.
+ *
+ * Application may define the typedef ::su_root_magic_t to appropriate type
+ * by defining macro SU_ROOT_MAGIC_T before including <su_wait.h>, for
+ * example,
+ * @code
+ * #define SU_ROOT_MAGIC_T struct context
+ * #include <su_wait.h>
+ * @endcode
+ */
+#define SU_ROOT_MAGIC_T void
+#endif
+
+/** <a href="#su_root_t">Root context</a> pointer type.
+ *
+ * Application may define the typedef ::su_root_magic_t to appropriate type
+ * by defining macro SU_ROOT_MAGIC_T () before including <su_wait.h>, for
+ * example,
+ * @code
+ * #define SU_ROOT_MAGIC_T struct context
+ * #include <su_wait.h>
+ * @endcode
+ */
+typedef SU_ROOT_MAGIC_T su_root_magic_t;
+
+#ifndef SU_WAKEUP_ARG_T
+/**Default type of @link ::su_wakeup_f wakeup function @endlink
+ * @link ::su_wakeup_arg_t argument type @endlink.
+ *
+ * The application can define the typedef ::su_wakeup_arg_t by defining
+ * the SU_WAKEUP_ARG_T () before including <su_wait.h>, for example,
+ * @code
+ * #define SU_WAKEUP_ARG_T struct transport
+ * #include <su_wait.h>
+ * @endcode
+ */
+#define SU_WAKEUP_ARG_T void
+#endif
+
+/** @link ::su_wakeup_f Wakeup callback @endlink argument type.
+ *
+ * The application can define the typedef ::su_wakeup_arg_t by defining
+ * the SU_WAKEUP_ARG_T () before including <su_wait.h>, for example,
+ * @code
+ * #define SU_WAKEUP_ARG_T struct transport
+ * #include <su_wait.h>
+ * @endcode
+ */
+typedef SU_WAKEUP_ARG_T su_wakeup_arg_t;
+
+/** Wakeup callback function prototype.
+ *
+ * Whenever a registered wait object receives an event, the @link
+ * ::su_wakeup_f callback function @endlink is invoked.
+ */
+typedef int (*su_wakeup_f)(su_root_magic_t *,
+ su_wait_t *,
+ su_wakeup_arg_t *arg);
+
+enum {
+ su_pri_normal, /**< Normal priority */
+ su_pri_first, /**< Elevated priority */
+ su_pri_realtime /**< Real-time priority */
+};
+
+struct _GSource;
+
+/** Hint for number of registered fds in su_root */
+SOFIAPUBVAR int su_root_size_hint;
+
+/* ---------------------------------------------------------------------- */
+/* Pre-poll callback */
+
+#ifndef SU_PREPOLL_MAGIC_T
+/**Default type of application context for prepoll function.
+ *
+ * Application may define the typedef ::su_prepoll_magic_t to appropriate type
+ * by defining macro #SU_PREPOLL_MAGIC_T before including <su_wait.h>, for
+ * example,
+ * @code
+ * #define SU_PREPOLL_MAGIC_T struct context
+ * #include <su_wait.h>
+ * @endcode
+ */
+#define SU_PREPOLL_MAGIC_T void
+#endif
+
+/** <a href="#su_root_t">Root context</a> pointer type.
+ *
+ * Application may define the typedef ::su_prepoll_magic_t to appropriate type
+ * by defining macro #SU_PREPOLL_MAGIC_T before including <su_wait.h>, for
+ * example,
+ * @code
+ * #define SU_PREPOLL_MAGIC_T struct context
+ * #include <su_wait.h>
+ * @endcode
+ */
+typedef SU_PREPOLL_MAGIC_T su_prepoll_magic_t;
+
+
+/** Pre-poll callback function prototype.
+ *
+ *
+ */
+typedef void su_prepoll_f(su_prepoll_magic_t *, su_root_t *);
+
+/* ---------------------------------------------------------------------- */
+
+/* Timers */
+#ifdef SU_TIMER_T
+#error SU_TIMER_T defined
+#endif
+
+#ifndef SU_TIMER_ARG_T
+/** Default type of timer expiration callback function argument type.
+ * Application may define this to appropriate type before including
+ * <su_wait.h>. */
+#define SU_TIMER_ARG_T void
+#endif
+
+/** Timer object type. */
+typedef struct su_timer_s su_timer_t;
+
+/** Timer callback argument type. */
+typedef SU_TIMER_ARG_T su_timer_arg_t;
+
+/** Timeout function type. */
+typedef void (*su_timer_f)(su_root_magic_t *magic,
+ su_timer_t *t,
+ su_timer_arg_t *arg);
+
+/* ---------------------------------------------------------------------- */
+
+/* Tasks */
+
+/** Port type. */
+typedef struct su_port_s su_port_t;
+
+typedef struct { su_port_t *sut_port; su_root_t *sut_root; } _su_task_t;
+
+/** Task reference type. */
+typedef _su_task_t su_task_r[1];
+
+/** Initializer for a task reference. @HI */
+#define SU_TASK_R_INIT {{ NULL, NULL }}
+
+/* This must be used instead of su_task_r as return value type. */
+typedef _su_task_t const *_su_task_r;
+
+/* ---------------------------------------------------------------------- */
+
+/* Messages */
+#ifndef SU_MSG_ARG_T
+/** Default type of su_msg_t message data. Application may define this to
+ * appropriate type before including <su_wait.h>.
+ */
+#define SU_MSG_ARG_T void
+#endif
+
+/** Message argument type. */
+typedef SU_MSG_ARG_T su_msg_arg_t;
+
+/** Message type. */
+typedef struct su_msg_s su_msg_t;
+
+/** Message reference type. */
+typedef su_msg_t *su_msg_r[1];
+
+/** Contstant reference to su_msg */
+typedef su_msg_t * const su_msg_cr[1];
+
+/** Initializer for a message reference. @HI */
+#define SU_MSG_R_INIT { NULL }
+
+/** Message delivery function type. */
+typedef void (*su_msg_f)(su_root_magic_t *magic,
+ su_msg_r msg,
+ su_msg_arg_t *arg);
+
+/* ---------------------------------------------------------------------- */
+
+/* Clones */
+#ifndef SU_CLONE_T
+#define SU_CLONE_T struct su_clone_s
+#endif
+
+/** Clone reference. */
+typedef SU_CLONE_T *su_clone_r[1];
+
+/** Clone reference initializer. */
+#define SU_CLONE_R_INIT {NULL}
+
+/** Clone initialization function type. */
+typedef int (*su_root_init_f)(su_root_t *, su_root_magic_t *);
+
+/** Clone finalization function type. */
+typedef void (*su_root_deinit_f)(su_root_t *, su_root_magic_t *);
+
+/* ---------------------------------------------------------------------- */
+/* Functions */
+
+/* Wait */
+SOFIAPUBFUN void su_wait_init(su_wait_t dst[1]);
+SOFIAPUBFUN int su_wait_create(su_wait_t *dst, su_socket_t s, int events);
+SOFIAPUBFUN int su_wait_destroy(su_wait_t *dst);
+SOFIAPUBFUN int su_wait(su_wait_t waits[], unsigned n, su_duration_t timeout);
+SOFIAPUBFUN int su_wait_events(su_wait_t *wait, su_socket_t s);
+SOFIAPUBFUN int su_wait_mask(su_wait_t *dst, su_socket_t s, int events);
+
+#if SU_HAVE_POLL
+static inline
+su_socket_t su_wait_socket(su_wait_t *wait)
+{
+ return wait->fd;
+}
+#endif
+
+/* Root */
+SOFIAPUBFUN su_root_t *su_root_create(su_root_magic_t *magic)
+ __attribute__((__malloc__));
+SOFIAPUBFUN void su_root_destroy(su_root_t*);
+SOFIAPUBFUN int su_root_set_magic(su_root_t *self, su_root_magic_t *magic);
+SOFIAPUBFUN su_root_magic_t *su_root_magic(su_root_t *root);
+SOFIAPUBFUN int su_root_register(su_root_t*, su_wait_t *,
+ su_wakeup_f, su_wakeup_arg_t *,
+ int priority);
+/* This is slow. Deprecated. */
+SOFIAPUBFUN int su_root_unregister(su_root_t*, su_wait_t *,
+ su_wakeup_f, su_wakeup_arg_t*);
+SOFIAPUBFUN int su_root_deregister(su_root_t*, int);
+SOFIAPUBFUN int su_root_eventmask(su_root_t *,
+ int index, int socket, int events);
+SOFIAPUBFUN su_duration_t su_root_step(su_root_t *root, su_duration_t timeout);
+SOFIAPUBFUN su_duration_t su_root_sleep(su_root_t *root, su_duration_t);
+SOFIAPUBFUN int su_root_multishot(su_root_t *root, int multishot);
+SOFIAPUBFUN void su_root_run(su_root_t *root);
+SOFIAPUBFUN void su_root_break(su_root_t *root);
+SOFIAPUBFUN _su_task_r su_root_task(su_root_t const *root);
+SOFIAPUBFUN _su_task_r su_root_parent(su_root_t const *root);
+
+SOFIAPUBFUN int su_root_add_prepoll(su_root_t *root,
+ su_prepoll_f *,
+ su_prepoll_magic_t *);
+SOFIAPUBFUN int su_root_remove_prepoll(su_root_t *root);
+
+SOFIAPUBFUN struct _GSource *su_root_gsource(su_root_t *self);
+
+SOFIAPUBFUN int su_root_yield(su_root_t *root);
+
+/* Timers */
+SOFIAPUBFUN su_timer_t *su_timer_create(su_task_r const, su_duration_t msec)
+ __attribute__((__malloc__));
+SOFIAPUBFUN void su_timer_destroy(su_timer_t *);
+SOFIAPUBFUN int su_timer_set(su_timer_t *, su_timer_f, su_timer_arg_t *);
+SOFIAPUBFUN int su_timer_set_interval(su_timer_t *t, su_timer_f,
+ su_timer_arg_t *, su_duration_t);
+SOFIAPUBFUN int su_timer_set_at(su_timer_t *, su_timer_f,
+ su_timer_arg_t *, su_time_t);
+SOFIAPUBFUN int su_timer_run(su_timer_t *, su_timer_f, su_timer_arg_t *);
+SOFIAPUBFUN int su_timer_set_for_ever(su_timer_t *, su_timer_f,
+ su_timer_arg_t *);
+SOFIAPUBFUN int su_timer_reset(su_timer_t *);
+
+SOFIAPUBFUN su_root_t *su_timer_root(su_timer_t const *);
+
+SOFIAPUBFUN int su_timer_expire(su_timer_t ** const,
+ su_duration_t *tout,
+ su_time_t now);
+
+/* Tasks */
+
+/** NULL task. */
+SOFIAPUBVAR su_task_r const su_task_null;
+
+SOFIAPUBFUN _su_task_r su_task_init(su_task_r task);
+SOFIAPUBFUN void su_task_deinit(su_task_r task);
+
+SOFIAPUBFUN void su_task_copy(su_task_r dst, su_task_r const src);
+SOFIAPUBFUN void su_task_move(su_task_r dst, su_task_r src);
+SOFIAPUBFUN int su_task_cmp(su_task_r const, su_task_r const);
+SOFIAPUBFUN int su_task_is_running(su_task_r const);
+
+SOFIAPUBFUN su_root_t *su_task_root(su_task_r const self);
+SOFIAPUBFUN su_timer_t **su_task_timers(su_task_r const self);
+
+SOFIAPUBFUN int su_task_execute(su_task_r const task,
+ int (*function)(void *), void *arg,
+ int *return_value);
+
+/* Messages */
+SOFIAPUBFUN int su_msg_create(su_msg_r msg,
+ su_task_r const to, su_task_r const from,
+ su_msg_f wakeup, isize_t size);
+SOFIAPUBFUN int su_msg_report(su_msg_r msg, su_msg_f report);
+SOFIAPUBFUN int su_msg_reply(su_msg_r reply, su_msg_r const msg,
+ su_msg_f wakeup, isize_t size);
+SOFIAPUBFUN void su_msg_destroy(su_msg_r msg);
+SOFIAPUBFUN void su_msg_save(su_msg_r msg, su_msg_r msg0);
+SOFIAPUBFUN void su_msg_remove_refs(su_msg_cr msg);
+SOFIAPUBFUN su_msg_arg_t *su_msg_data(su_msg_cr msg);
+SOFIAPUBFUN isize_t su_msg_size(su_msg_cr msg);
+SOFIAPUBFUN _su_task_r su_msg_from(su_msg_cr msg);
+SOFIAPUBFUN _su_task_r su_msg_to(su_msg_cr msg);
+SOFIAPUBFUN int su_msg_send(su_msg_r msg);
+
+/** Does reference contain a message? */
+#if SU_HAVE_INLINE
+static SU_INLINE
+int su_msg_is_non_null(su_msg_cr msg)
+{
+ return msg && *msg != NULL;
+}
+#else
+#define su_msg_is_non_null(msg) ((msg) && (*(msg)) != NULL)
+#endif
+
+/* Clones */
+SOFIAPUBFUN int su_root_threading(su_root_t *self, int enable);
+SOFIAPUBFUN int su_clone_start(su_root_t *root,
+ su_clone_r,
+ su_root_magic_t *magic,
+ su_root_init_f,
+ su_root_deinit_f);
+SOFIAPUBFUN _su_task_r su_clone_task(su_clone_r);
+SOFIAPUBFUN void su_clone_forget(su_clone_r);
+SOFIAPUBFUN void su_clone_stop(su_clone_r);
+SOFIAPUBFUN void su_clone_wait(su_root_t *root, su_clone_r clone);
+
+SOFIAPUBFUN int su_clone_pause(su_clone_r);
+SOFIAPUBFUN int su_clone_resume(su_clone_r);
+
+SOFIA_END_DECLS
+
+#endif /* SU_WAIT_H */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/tstdef.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/tstdef.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,355 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@file sofia-sip/tstdef.h Macros for unit tests
+ *
+ * The macros defined here can be used by unit test programs. When a test
+ * fails, the TEST macros print the offending file name and line number.
+ * They use format that is accepted by Emacs and other fine editors so you
+ * can directly go to the source code of the failed test with next-error.
+ *
+ * @note There is no protection agains multiple inclusion.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Aug 22 13:53:24 2001 ppessi
+ *
+ * @par Example Program
+ *
+ * You should define the macro TSTFLAGS to a int variable possibly
+ * containing a flag #tst_verbatim. As a convention, the int variable should
+ * be set when your test program is run with @c -v or @c --verbatim command
+ * line option. If the (TSTFLAGS & tst_verbatim) is true, the test macros
+ * log the test before executing it and the result of successful tests, too.
+ *
+ * You should typedef longlong to integer type at least 64 bit wide before
+ * including <sofia-sip/tstdef.h>, too.
+ *
+ * As an example, we provide a test program making sure that inet_ntop() and
+ * inet_pton() behave as expected and that we can create UDP/IPv4 sockets
+ * with @b su library:
+ *
+ * @code
+ * #include "config.h"
+ *
+ * #include <stdio.h>
+ * #include <limits.h>
+ *
+ * #include <sofia-sip/su.h>
+ *
+ * #define TSTFLAGS tstflags
+ *
+ * #include <stdlib.h>
+ * #include <sofia-sip/tstdef.h>
+ *
+ * static int tstflags = 0;
+ *
+ * void usage(void)
+ * {
+ * fprintf(stderr, "usage: %s [-v|--verbatim]\n", name);
+ * exit(2);
+ * }
+ *
+ * static int socket_test(void);
+ *
+ * int main(int argc, char *argv[])
+ * {
+ * int retval = 0, i;
+ *
+ * for (i = 1; argv[i]; i++) {
+ * if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--verbatim") == 0)
+ * tstflags |= tst_verbatim;
+ * else
+ * usage();
+ * }
+ *
+ * retval |= socket_test(); fflush(stdout);
+ *
+ * return retval;
+ * }
+ *
+ * double max_bandwidth()
+ *
+ * int socket_test(void)
+ * {
+ * su_socket_t s;
+ * char buf[64];
+ * unsigned long localhost = htonl(0x7f000001);
+ * unsigned long addr;
+ *
+ * BEGIN();
+ *
+ * // Check inet_ntop() return value (Tests equality of integral values)
+ * TEST(inet_ntop(AF_INET, &localhost, buf, sizeof buf), buf);
+ *
+ * // Check inet_ntop() result (Tests equality of strings)
+ * TEST_S(buf, "127.0.0.1");
+ *
+ * // Check inet_pton() argument validation (Tests equality of ints)
+ * TEST(inet_pton(0, buf, &addr), -1);
+ *
+ * // Check inet_pton() return value (Tests for true value (non-zero))
+ * TEST_1(inet_pton(AF_INET, buf, &addr) > 0);
+ *
+ * // Check inet_pton() result (Tests equality of memory areas)
+ * TEST_M(&addr, &localhost, sizeof(addr));
+ *
+ * // Test to create UDP socket (Test for true value)
+ * TEST_1((s = su_socket(AF_INET, SOCK_DGRAM, 0)) != INVALID_SOCKET);
+ *
+ * // Check max bandwidth
+ * TEST_D(max_bandwidth(), DBL_MAX);
+ *
+ * END();
+ * }
+ * @endcode
+ */
+
+#ifndef SU_TYPES_H
+#include <sofia-sip/su_types.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+#if HAVE_FUNC
+#define TSTNAME name, __func__, "() "
+#elif HAVE_FUNCTION
+#define TSTNAME name, __FUNCTION__, "() "
+#else
+#define TSTNAME name, "", ""
+#endif
+
+enum {
+ /** If (TSTFLAGS & tst_verbatim) is non-zero, be verbatim. */
+ tst_verbatim = 1,
+ /** If (TSTFLAGS & tst_abort) is non-zero, abort() when failed. */
+ tst_abort = 2,
+};
+
+#ifndef TSTFLAGS
+#error <TSTFLAGS is not defined>
+#endif
+
+#ifdef TSTFLAGS
+/** Begin a test function. @HIDE */
+#define BEGIN() BEGIN_(TSTFLAGS); { extern int tstdef_dummy
+/** End a test function. @HIDE */
+#define END() (void) tstdef_dummy; } END_(TSTFLAGS)
+/**Test that @a suite returns a nonzero value.
+ * @deprecated Use TEST_1()
+ * @HIDE */
+#define TEST0(suite) TEST_1_(TSTFLAGS, suite)
+/** Test that @a suite returns a nonzero value. @HIDE */
+#define TEST_1(suite) TEST_1_(TSTFLAGS, suite)
+/** Test a void suite. @HIDE */
+#define TEST_VOID(suite) TEST_VOID_(TSTFLAGS, suite)
+/** Test that @a suite is equal to @a expected. @HIDE */
+#define TEST(suite, expected) TEST_(TSTFLAGS, suite, expected)
+/** Test that @a suite is same pointer as @a expected. @HIDE */
+#define TEST_P(suite, expected) TEST_P_(TSTFLAGS, suite, expected)
+/** Test that 64-bit @a suite is equal to @a expect. @HIDE */
+#define TEST64(suite, expected) TEST64_(TSTFLAGS, suite, expected)
+/** Test that @a suite is same double as @a expected. @HIDE */
+#define TEST_D(suite, expected) TEST_D_(TSTFLAGS, suite, expected)
+/** Test that @a suite is same string as @a expected. @HIDE */
+#define TEST_S(suite, expected) TEST_S_(TSTFLAGS, suite, expected)
+/** Test that @a suite is results as identical memory as @a expected. @HIDE */
+#define TEST_M(suite, expected, len) TEST_M_(TSTFLAGS, suite, expected, len)
+/** Test that @a suite has same size as @a expected. @HIDE */
+#define TEST_SIZE(suite, expected) TEST_SIZE_(TSTFLAGS, suite, expected)
+
+#else
+/* Deprecated */
+#define TEST0(flags, suite) TEST_1_(flags, suite)
+#define TEST_1(flags, suite) TEST_1_(flags, suite)
+#define TEST_VOID(flags, suite) TEST_VOID_(flags, suite)
+#define TEST(flags, suite, expect) TEST_(flags, suite, expect)
+#define TEST64(flags, suite, expect) TEST64_(flags, suite, expect)
+#define TEST_S(flags, suite, expect) TEST_S_(flags, suite, expect)
+#define BEGIN(flags) BEGIN_(flags) { extern int tstdef_dummy
+#define END(flags) (void) tstdef_dummy; } END_(flags)
+#endif
+
+#define TEST_FAILED(flags) \
+ ((flags) & tst_abort) ? abort() : (void)0; return 1
+
+/** @HIDE */
+#define TEST_1_(flags, suite) do { \
+ if (flags & tst_verbatim) { \
+ printf("%s: %s%stesting %s\n", TSTNAME, #suite); \
+ fflush(stdout); } \
+ if ((suite)) { if (flags & tst_verbatim) \
+ printf("%s: %s%sok: (%s)\n", TSTNAME, #suite); break ; } \
+ fprintf(stderr, "%s:%u: %s %s%sFAILED: (%s)\n", \
+ __FILE__, __LINE__, TSTNAME, #suite); fflush(stderr); \
+ TEST_FAILED(flags); } \
+ while(0)
+
+/** @HIDE */
+#define TEST_VOID_(flags, suite) do { \
+ if (flags & tst_verbatim) { \
+ printf("%s: %s%stesting %s\n", TSTNAME, #suite); \
+ fflush(stdout); } \
+ (suite); } while(0)
+
+/** @HIDE */
+#define TEST_(flags, suite, expect) do { \
+ uintptr_t _value, _expect; \
+ if (flags & tst_verbatim) { \
+ printf("%s: %s%stesting %s == %s\n", TSTNAME, #suite, #expect); \
+ fflush(stdout); } \
+ _value = (uintptr_t)(suite); \
+ _expect = (uintptr_t)(expect); \
+ if (_value == _expect) { \
+ if (flags & tst_verbatim) \
+ printf("%s: %s%sok: %s == %s \n", \
+ TSTNAME, #suite, #expect); \
+ break; \
+ } \
+ fprintf(stderr, "%s:%u: %s %s%sFAILED: " \
+ "%s != %s or "MOD_ZU" != "MOD_ZU"\n", \
+ __FILE__, __LINE__, TSTNAME, \
+ #suite, #expect, (size_t)_value, (size_t)_expect); \
+ fflush(stderr); \
+ TEST_FAILED(flags); \
+ } while(0)
+
+/** @HIDE */
+#define TEST_P_(flags, suite, expect) do { \
+ void const * _value, * _expect; \
+ if (flags & tst_verbatim) { \
+ printf("%s: %s%stesting %s == %s\n", TSTNAME, #suite, #expect); \
+ fflush(stdout); } \
+ if ((_value = (suite)) == (_expect = (expect))) { \
+ if (flags & tst_verbatim) \
+ printf("%s: %s%sok: %s == %s \n", TSTNAME, #suite, #expect); \
+ break; \
+ } \
+ fprintf(stderr, "%s:%u: %s %s%sFAILED: %s != %s or %p != %p\n", \
+ __FILE__, __LINE__, TSTNAME, \
+ #suite, #expect, _value, _expect); fflush(stderr); \
+ TEST_FAILED(flags); \
+ } while(0)
+
+/** @HIDE */
+#define TEST_SIZE_(flags, suite, expect) do { \
+ size_t _value, _expect; \
+ if (flags & tst_verbatim) { \
+ printf("%s: %s%stesting %s == %s\n", TSTNAME, #suite, #expect); \
+ fflush(stdout); } \
+ if ((_value = (size_t)(suite)) == \
+ (_expect = (size_t)(expect))) \
+ { if (flags & tst_verbatim) \
+ printf("%s: %s%sok: %s == %s \n", TSTNAME, #suite, #expect); break; } \
+ fprintf(stderr, "%s:%u: %s %s%sFAILED: %s != %s or "MOD_ZU" != "MOD_ZU"\n", \
+ __FILE__, __LINE__, TSTNAME, \
+ #suite, #expect, _value, _expect); fflush(stderr); \
+ TEST_FAILED(flags); \
+ } while(0)
+
+
+/** @HIDE */
+#define TEST64_(flags, suite, expect) do { \
+ uint64_t _value, _expect; \
+ if (flags & tst_verbatim) { \
+ printf("%s: %s%stesting %s == %s\n", TSTNAME, #suite, #expect); \
+ fflush(stdout); } \
+ if ((_value = (uint64_t)(suite)) == (_expect = (uint64_t)(expect))) \
+ { if (flags & tst_verbatim) \
+ printf("%s: %s%sok: %s == %s \n", TSTNAME, #suite, #expect); break; } \
+ fprintf(stderr, "%s:%u: %s %s%sFAILED: %s != %s or "LLU" != "LLU"\n", \
+ __FILE__, __LINE__, TSTNAME, \
+ #suite, #expect, (unsigned longlong)_value, \
+ (unsigned longlong)_expect); fflush(stderr); \
+ TEST_FAILED(flags); \
+ } while(0)
+
+/** @HIDE */
+#define TEST_D_(flags, suite, expect) do { \
+ double _value, _expect; \
+ if (flags & tst_verbatim) { \
+ printf("%s: %s%stesting %s == %s\n", TSTNAME, #suite, #expect); \
+ fflush(stdout); } \
+ if ((_value = (double)(suite)) == (_expect = (double)(expect))) \
+ { if (flags & tst_verbatim) \
+ printf("%s: %s%sok: %s == %s \n", TSTNAME, #suite, #expect); break; } \
+ fprintf(stderr, "%s:%u: %s %s%sFAILED: %s != %s or %g != %g\n", \
+ __FILE__, __LINE__, TSTNAME, \
+ #suite, #expect, _value, _expect); fflush(stderr); \
+ TEST_FAILED(flags); \
+ } while(0)
+
+/** @HIDE */
+#define TEST_S_(flags, suite, expect) do { \
+ char const * _value, * _expect; \
+ if (flags & tst_verbatim) { \
+ printf("%s: %s%stesting %s is %s\n", TSTNAME, #suite, #expect); \
+ fflush(stdout); } \
+ _value = (suite); \
+ _expect = (expect); \
+ if (((_value == NULL || _expect == NULL) && _value == _expect) || \
+ (_value != NULL && _expect != NULL && strcmp(_value, _expect) == 0)) \
+ { if (flags & tst_verbatim) \
+ printf("%s: %s%sok: %s == %s \n", TSTNAME, #suite, #expect);break;}\
+ fprintf(stderr, "%s:%u: %s %s%sFAILED: %s != %s or %s%s%s != \"%s\"\n", \
+ __FILE__, __LINE__, TSTNAME, \
+ #suite, #expect, \
+ _value ? "\"" : "", _value ? _value : "NULL", _value ? "\"" : "", \
+ _expect); fflush(stderr); \
+ TEST_FAILED(flags); \
+ } while(0)
+
+/** @HIDE */
+#define TEST_M_(flags, suite, expect, len) do { \
+ void const * _value, * _expect; \
+ int _len; \
+ if (flags & tst_verbatim) { \
+ printf("%s: %s%stesting %s is %s\n", TSTNAME, #suite, #expect); \
+ fflush(stdout); } \
+ _value = (suite); \
+ _expect = (expect); \
+ _len = (len); \
+ if (((_value == NULL || _expect == NULL) && _value == _expect) || \
+ memcmp(_value, _expect, _len) == 0) \
+ { if (flags & tst_verbatim) \
+ printf("%s: %s%sok: %s == %s \n", TSTNAME, #suite, #expect);break;}\
+ fprintf(stderr, "%s:%u: %s %s%sFAILED: %s != %s "\
+ "or \"%.*s\" != \"%.*s\"\n", \
+ __FILE__, __LINE__, TSTNAME, \
+ #suite, #expect, _len, (char *)_value, _len, (char *)_expect); \
+ fflush(stderr); \
+ TEST_FAILED(flags); \
+ } while(0)
+
+/** @HIDE */
+#define BEGIN_(flags) \
+ if (flags & tst_verbatim) printf("%s: %s%sstarting\n", TSTNAME)
+
+/** @HIDE */
+#define END_(flags) \
+ if (flags & tst_verbatim) \
+ printf("%s: %s%sfinished fully successful\n", TSTNAME); \
+ return 0
+
+SOFIA_END_DECLS
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/strcasestr.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/strcasestr.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,73 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@file strcasestr.c
+ * @brief Backup implementation of strcasestr()
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ */
+
+#include "config.h"
+
+#include <ctype.h>
+#include <stddef.h>
+
+/* Naive implementation of strcasestr() */
+char *strcasestr(const char *haystack,
+ const char *needle)
+{
+ unsigned char lcn, ucn;
+ unsigned i;
+
+ if (haystack == NULL || needle == NULL)
+ return NULL;
+
+ lcn = ucn = needle[0];
+ if (isupper(lcn))
+ lcn = tolower(lcn);
+ else if (islower(ucn))
+ ucn = toupper(ucn);
+
+ if (lcn == 0)
+ return (char *)haystack;
+
+ while (haystack[0] != 0) {
+ if (lcn == haystack[0] || ucn == haystack[0]) {
+ for (i = 1; ; i++) {
+ char n = needle[i], h = haystack[i];
+ if (n == 0)
+ return (char *)haystack;
+ if (h == 0)
+ return NULL;
+ if (isupper(n)) n = tolower(n);
+ if (isupper(h)) h = tolower(h);
+ if (n != h)
+ break;
+ }
+ }
+ haystack++;
+ }
+
+ return NULL; /* Not found */
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/strtoull.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/strtoull.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,286 @@
+/*
+ * strtoull.c --
+ *
+ * Source code for the "strtoull" library procedure.
+ *
+ * Copyright (c) 1988 The Regents of the University of California.
+ * Copyright (c) 1994 Sun Microsystems, Inc.
+ *
+The following license.terms for information on usage and redistribution
+of this individual file, and for a DISCLAIMER OF ALL WARRANTIES.
+
+This software is copyrighted by the Regents of the University of
+California, Sun Microsystems, Inc., Scriptics Corporation, ActiveState
+Corporation and other parties. The following terms apply to all files
+associated with the software unless explicitly disclaimed in
+individual files.
+
+The authors hereby grant permission to use, copy, modify, distribute,
+and license this software and its documentation for any purpose, provided
+that existing copyright notices are retained in all copies and that this
+notice is included verbatim in any distributions. No written agreement,
+license, or royalty fee is required for any of the authorized uses.
+Modifications to this software may be copyrighted by their authors
+and need not follow the licensing terms described here, provided that
+the new terms are clearly indicated on the first page of each file where
+they apply.
+
+IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
+FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
+DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
+IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
+NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
+MODIFICATIONS.
+
+GOVERNMENT USE: If you are acquiring this software on behalf of the
+U.S. government, the Government shall have only "Restricted Rights"
+in the software and related documentation as defined in the Federal
+Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you
+are acquiring the software on behalf of the Department of Defense, the
+software shall be classified as "Commercial Computer Software" and the
+Government shall have only "Restricted Rights" as defined in Clause
+252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the
+authors grant the U.S. Government and others acting in its behalf
+permission to use and distribute the software in accordance with the
+terms specified in this license.
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <ctype.h>
+
+/*
+ * The table below is used to convert from ASCII digits to a
+ * numerical equivalent. It maps from '0' through 'z' to integers
+ * (100 for non-digit characters).
+ */
+
+static char cvtIn[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, /* '0' - '9' */
+ 100, 100, 100, 100, 100, 100, 100, /* punctuation */
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, /* 'A' - 'Z' */
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ 30, 31, 32, 33, 34, 35,
+ 100, 100, 100, 100, 100, 100, /* punctuation */
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, /* 'a' - 'z' */
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ 30, 31, 32, 33, 34, 35};
+
+
+/**Convert an ASCII string into an unsigned long long integer.
+ *
+ * @param[in] string String of ASCII digits, possibly preceded by white
+ * space. For bases greater than 10, either lower- or
+ * upper-case digits may be used.
+ *
+ * @param[out] endPtr Where to store address of terminating character, or
+ * NULL.
+ *
+ * @param[in] base Base for conversion. Must be less than 37. If 0, then
+ * the base is chosen from the leading characters of
+ * string: "0x" means hex, "0" means octal, anything
+ * else means decimal.
+ *
+ * @return
+ * The integer equivalent of string. If @a endPtr is non-NULL, then pointer
+ * to the character after the last one that was part of the integer is
+ * stored to @a *endPtr.
+ *
+ * If string doesn't contain a valid integer value, then zero is
+ * returned and *endPtr is set to original value of @a string.
+ */
+
+unsigned longlong
+strtoull(const char *string, char **endPtr, int base)
+{
+ register const char *p;
+ register unsigned longlong result = 0;
+ register unsigned digit;
+ register unsigned longlong shifted;
+ int anyDigits = 0, negative = 0;
+
+ /*
+ * Skip any leading blanks.
+ */
+
+ p = string;
+ while (isspace(*p)) { /* INTL: locale-dependent */
+ p += 1;
+ }
+
+ /*
+ * Check for a sign.
+ */
+
+ if (*p == '-') {
+ p += 1;
+ negative = 1;
+ } else {
+ if (*p == '+') {
+ p += 1;
+ }
+ }
+
+ /*
+ * If no base was provided, pick one from the leading characters
+ * of the string.
+ */
+
+ if (base == 0) {
+ if (*p == '0') {
+ p += 1;
+ if (*p == 'x' || *p == 'X') {
+ p += 1;
+ base = 16;
+ } else {
+
+ /*
+ * Must set anyDigits here, otherwise "0" produces a
+ * "no digits" error.
+ */
+
+ anyDigits = 1;
+ base = 8;
+ }
+ } else {
+ base = 10;
+ }
+ } else if (base == 16) {
+
+ /*
+ * Skip a leading "0x" from hex numbers.
+ */
+
+ if ((p[0] == '0') && (p[1] == 'x' || *p == 'X')) {
+ p += 2;
+ }
+ }
+
+ /*
+ * Sorry this code is so messy, but speed seems important. Do
+ * different things for base 8, 10, 16, and other.
+ */
+
+ if (base == 8) {
+ for ( ; ; p += 1) {
+ digit = *p - '0';
+ if (digit > 7) {
+ break;
+ }
+ shifted = result << 3;
+ if ((shifted >> 3) != result) {
+ goto overflow;
+ }
+ result = shifted + digit;
+ if ( result < shifted ) {
+ goto overflow;
+ }
+ anyDigits = 1;
+ }
+ } else if (base == 10) {
+ for ( ; ; p += 1) {
+ digit = *p - '0';
+ if (digit > 9) {
+ break;
+ }
+ shifted = 10 * result;
+ if ((shifted / 10) != result) {
+ goto overflow;
+ }
+ result = shifted + digit;
+ if ( result < shifted ) {
+ goto overflow;
+ }
+ anyDigits = 1;
+ }
+ } else if (base == 16) {
+ for ( ; ; p += 1) {
+ digit = *p - '0';
+ if (digit > ('z' - '0')) {
+ break;
+ }
+ digit = cvtIn[digit];
+ if (digit > 15) {
+ break;
+ }
+ shifted = result << 4;
+ if ((shifted >> 4) != result) {
+ goto overflow;
+ }
+ result = shifted + digit;
+ if ( result < shifted ) {
+ goto overflow;
+ }
+ anyDigits = 1;
+ }
+ } else if ( base >= 2 && base <= 36 ) {
+ for ( ; ; p += 1) {
+ digit = *p - '0';
+ if (digit > ('z' - '0')) {
+ break;
+ }
+ digit = cvtIn[digit];
+ if (digit >= (unsigned) base) {
+ break;
+ }
+ shifted = result * base;
+ if ((shifted/base) != result) {
+ goto overflow;
+ }
+ result = shifted + digit;
+ if ( result < shifted ) {
+ goto overflow;
+ }
+ anyDigits = 1;
+ }
+ }
+
+ /*
+ * Negate if we found a '-' earlier.
+ */
+
+ if (negative) {
+ result = (unsigned longlong)(-((longlong)result));
+ }
+
+ if (endPtr != 0) {
+ /*
+ * See if there were any digits at all.
+ */
+ if (!anyDigits) {
+ p = string;
+ }
+ *endPtr = (char *) p;
+ }
+
+ return result;
+
+ /*
+ * On overflow generate the right output
+ */
+
+ overflow:
+ errno = ERANGE;
+ if (endPtr != 0) {
+ for ( ; ; p += 1) {
+ digit = *p - '0';
+ if (digit > ('z' - '0')) {
+ break;
+ }
+ digit = cvtIn[digit];
+ if (digit >= (unsigned) base) {
+ break;
+ }
+ }
+ *endPtr = (char *) p;
+ }
+
+ return (unsigned longlong)-1;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,443 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_socket
+ * @CFILE su.c OS-independent socket functions
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Mar 18 19:40:51 1999 pessi
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+
+#include "sofia-sip/su.h"
+#include "sofia-sip/su_log.h"
+#include "sofia-sip/su_alloc.h"
+
+#if !SU_HAVE_BSDSOCK && !SU_HAVE_WINSOCK
+#error Bad configuration
+#endif
+
+#ifndef FD_CLOEXEC
+#define FD_CLOEXEC (1)
+#endif
+
+int su_socket_close_on_exec = 0;
+
+/** Create an endpoint for communication. */
+su_socket_t su_socket(int af, int socktype, int proto)
+{
+ su_socket_t s = socket(af, socktype, proto);
+#if SU_HAVE_BSDSOCK
+ if (s != INVALID_SOCKET && su_socket_close_on_exec) {
+ fcntl(s, F_SETFD, FD_CLOEXEC); /* Close on exec */
+ }
+#endif
+ return s;
+}
+
+#if SU_HAVE_BSDSOCK
+int su_init(void)
+{
+ su_home_threadsafe(NULL);
+
+ signal(SIGPIPE, SIG_IGN); /* we want to get EPIPE instead */
+
+ su_log_init(su_log_default);
+ su_log_init(su_log_global);
+
+ return 0;
+}
+
+void su_deinit(void)
+{
+}
+
+/** Close an socket descriptor. */
+int su_close(su_socket_t s)
+{
+ return close(s);
+}
+
+int su_setblocking(su_socket_t s, int blocking)
+{
+ int mode = fcntl(s, F_GETFL, 0);
+
+ if (mode < 0)
+ return -1;
+
+ if (blocking)
+ mode &= ~(O_NDELAY | O_NONBLOCK);
+ else
+ mode |= O_NDELAY | O_NONBLOCK;
+
+ return fcntl(s, F_SETFL, mode);
+}
+#endif
+
+#if SU_HAVE_WINSOCK
+int su_init(void)
+{
+ WORD wVersionRequested;
+ WSADATA wsaData;
+
+ wVersionRequested = MAKEWORD(2, 0);
+
+ if (WSAStartup(wVersionRequested, &wsaData) !=0) {
+ return -1;
+ }
+
+ su_log_init(su_log_default);
+
+ su_log_init(su_log_global);
+
+ return 0;
+}
+
+void su_deinit(void)
+{
+ WSACleanup();
+}
+
+/** Close an socket descriptor. */
+int su_close(su_socket_t s)
+{
+ return closesocket(s);
+}
+
+/** Control socket. */
+int su_ioctl(su_socket_t s, int request, ...)
+{
+ int retval;
+ void *argp;
+ va_list va;
+ va_start(va, request);
+ argp = va_arg(va, void *);
+ retval = ioctlsocket(s, request, argp);
+ va_end(va);
+ return retval;
+}
+
+int su_is_blocking(int errcode)
+{
+ return errcode == EAGAIN || errcode == EWOULDBLOCK || errcode == EINPROGRESS;
+}
+
+int su_setblocking(su_socket_t s, int blocking)
+{
+ unsigned long nonBlock = !blocking;
+
+ return ioctlsocket(s, FIONBIO, &nonBlock);
+}
+
+
+#endif /* SU_HAVE_WINSOCK */
+
+int su_soerror(su_socket_t s)
+{
+ int error = 0;
+ socklen_t errorlen = sizeof(error);
+
+ getsockopt(s, SOL_SOCKET, SO_ERROR, (void *)&error, &errorlen);
+
+ return error;
+}
+
+int su_setreuseaddr(su_socket_t s, int reuse)
+{
+ return setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
+ (void *)&reuse, (socklen_t)sizeof(reuse));
+}
+
+
+#if HAVE_SYS_FILIO_H
+#include <sys/filio.h>
+#endif
+
+#if SU_HAVE_WINSOCK
+issize_t su_getmsgsize(su_socket_t s)
+{
+ unsigned long n = (unsigned long)-1;
+ if (ioctlsocket(s, FIONREAD, &n) == -1)
+ return -1;
+ return (issize_t)n;
+}
+#else
+issize_t su_getmsgsize(su_socket_t s)
+{
+ int n = -1;
+ if (su_ioctl(s, FIONREAD, &n) == -1)
+ return -1;
+ return (issize_t)n;
+}
+#endif
+
+#if SU_HAVE_WINSOCK && SU_HAVE_IN6
+/** Return a pointer to the in6addr_any. */
+struct in_addr6 const *su_in6addr_any(void)
+{
+ static const struct in_addr6 a = SU_IN6ADDR_ANY_INIT;
+ return &a;
+}
+
+/** Return a pointer to IPv6 loopback address */
+struct in_addr6 const *su_in6addr_loopback(void)
+{
+ static const struct in_addr6 a = SU_IN6ADDR_LOOPBACK_INIT;
+ return &a;
+}
+#endif
+
+#if SU_HAVE_WINSOCK
+
+ssize_t su_send(su_socket_t s, void *buffer, size_t length, int flags)
+{
+ if (length > INT_MAX)
+ length = INT_MAX;
+ return (ssize_t)send(s, buffer, (int)length, flags);
+}
+
+ssize_t su_sendto(su_socket_t s, void *buffer, size_t length, int flags,
+ su_sockaddr_t const *to, socklen_t tolen)
+{
+ if (length > INT_MAX)
+ length = INT_MAX;
+ return (ssize_t)sendto(s, buffer, (int)length, flags,
+ &to->su_sa, (int) tolen);
+}
+
+ssize_t su_recv(su_socket_t s, void *buffer, size_t length, int flags)
+{
+ if (length > INT_MAX)
+ length = INT_MAX;
+
+ return (ssize_t)recv(s, buffer, (int)length, flags);
+}
+
+ssize_t su_recvfrom(su_socket_t s, void *buffer, size_t length, int flags,
+ su_sockaddr_t *from, socklen_t *fromlen)
+{
+ int retval, ilen;
+
+ if (fromlen)
+ ilen = *fromlen;
+
+ if (length > INT_MAX)
+ length = INT_MAX;
+
+ retval = recvfrom(s, buffer, (int)length, flags,
+ &from->su_sa, fromlen ? &ilen : NULL);
+
+ if (fromlen)
+ *fromlen = ilen;
+
+ return (ssize_t)retval;
+}
+
+/** Scatter/gather send */
+issize_t su_vsend(su_socket_t s,
+ su_iovec_t const iov[], isize_t iovlen, int flags,
+ su_sockaddr_t const *su, socklen_t sulen)
+{
+ int ret;
+ DWORD bytes_sent = (DWORD)su_failure;
+
+ ret = WSASendTo(s,
+ (LPWSABUF)iov,
+ (DWORD)iovlen,
+ &bytes_sent,
+ flags,
+ &su->su_sa,
+ sulen,
+ NULL,
+ NULL);
+ if (ret < 0)
+ return (issize_t)ret;
+ else
+ return (issize_t)bytes_sent;
+}
+
+
+/** Scatter/gather recv */
+issize_t su_vrecv(su_socket_t s, su_iovec_t iov[], isize_t iovlen, int flags,
+ su_sockaddr_t *su, socklen_t *sulen)
+{
+ int ret;
+ DWORD bytes_recv = (DWORD)su_failure;
+ DWORD dflags = flags;
+ int fromlen = sulen ? *sulen : 0;
+
+ ret = WSARecvFrom(s,
+ (LPWSABUF)iov,
+ (DWORD)iovlen,
+ &bytes_recv,
+ &dflags,
+ &su->su_sa,
+ sulen ? &fromlen : NULL,
+ NULL,
+ NULL);
+
+ if (sulen) *sulen = fromlen;
+
+ if (ret < 0)
+ return (issize_t)ret;
+ else
+ return (issize_t)bytes_recv;
+}
+
+
+#else
+
+issize_t su_vsend(su_socket_t s,
+ su_iovec_t const iov[], isize_t iovlen, int flags,
+ su_sockaddr_t const *su, socklen_t sulen)
+{
+ struct msghdr hdr[1] = {{0}};
+
+ hdr->msg_name = (void *)su;
+ hdr->msg_namelen = sulen;
+ hdr->msg_iov = (struct iovec *)iov;
+ hdr->msg_iovlen = iovlen;
+
+ return sendmsg(s, hdr, flags);
+}
+
+issize_t su_vrecv(su_socket_t s, su_iovec_t iov[], isize_t iovlen, int flags,
+ su_sockaddr_t *su, socklen_t *sulen)
+{
+ struct msghdr hdr[1] = {{0}};
+ issize_t retval;
+
+ hdr->msg_name = (void *)su;
+ if (su && sulen)
+ hdr->msg_namelen = *sulen;
+ hdr->msg_iov = (struct iovec *)iov;
+ hdr->msg_iovlen = iovlen;
+
+ retval = recvmsg(s, hdr, flags);
+
+ if (su && sulen)
+ *sulen = hdr->msg_namelen;
+
+ return retval;
+}
+
+#endif
+
+/** Compare two socket addresses */
+int su_cmp_sockaddr(su_sockaddr_t const *a, su_sockaddr_t const *b)
+{
+ int rv;
+
+ /* Check that a and b are non-NULL */
+ if ((rv = (a != NULL) - (b != NULL)) || a == NULL /* && b == NULL */)
+ return rv;
+
+ if ((rv = a->su_family - b->su_family))
+ return rv;
+
+ if (a->su_family == AF_INET)
+ rv = memcmp(&a->su_sin.sin_addr, &b->su_sin.sin_addr,
+ sizeof(struct in_addr));
+#if SU_HAVE_IN6
+ else if (a->su_family == AF_INET6)
+ rv = memcmp(&a->su_sin6.sin6_addr, &b->su_sin6.sin6_addr,
+ sizeof(struct in6_addr));
+#endif
+ else
+ rv = memcmp(a, b, sizeof(struct sockaddr));
+
+ if (rv)
+ return rv;
+
+ return a->su_port - b->su_port;
+}
+
+/** Check if socket address b match with a.
+ *
+ * The function su_match_sockaddr() returns true if the socket address @a b
+ * matches with the socket address @a a. This happens if either all the
+ * interesting fields are identical: address family, port number, address,
+ * and scope ID (in case of IPv6) or that the @a a contains a wildcard
+ * (zero) in their place.
+ */
+int su_match_sockaddr(su_sockaddr_t const *a, su_sockaddr_t const *b)
+{
+ /* Check that a and b are non-NULL */
+ if (a == NULL)
+ return 1;
+ if (b == NULL)
+ return 0;
+
+ if (a->su_family != 0 && a->su_family != b->su_family)
+ return 0;
+
+ if (a->su_family == 0 || SU_SOCKADDR_INADDR_ANY(a))
+ ;
+ else if (a->su_family == AF_INET) {
+ if (memcmp(&a->su_sin.sin_addr, &b->su_sin.sin_addr,
+ sizeof(struct in_addr)))
+ return 0;
+ }
+#if SU_HAVE_IN6
+ else if (a->su_family == AF_INET6) {
+ if (a->su_scope_id != 0 && a->su_scope_id != b->su_scope_id)
+ return 0;
+ if (memcmp(&a->su_sin6.sin6_addr, &b->su_sin6.sin6_addr,
+ sizeof(struct in6_addr)))
+ return 0;
+ }
+#endif
+ else if (memcmp(a, b, sizeof(struct sockaddr)))
+ return 0;
+
+ if (a->su_port == 0)
+ return 1;
+
+ return a->su_port == b->su_port;
+}
+
+/** Convert mapped/compat address to IPv4 address */
+void su_canonize_sockaddr(su_sockaddr_t *su)
+{
+#if SU_HAVE_IN6
+ if (su->su_family != AF_INET6)
+ return;
+
+ if (!IN6_IS_ADDR_V4MAPPED(&su->su_sin6.sin6_addr) &&
+ !IN6_IS_ADDR_V4COMPAT(&su->su_sin6.sin6_addr))
+ return;
+
+ su->su_family = AF_INET;
+ su->su_array32[1] = su->su_array32[5];
+ su->su_array32[2] = 0;
+ su->su_array32[3] = 0;
+#endif
+}
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su.docs Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1352 @@
+/* -*- C -*- */
+
+/**@MODULEPAGE "su" - OS Services and Utilities
+ *
+ * @section su_meta Module Information
+ *
+ * The @b su module contains a simple, portable socket/timing/synchronizing
+ * library developed for Sofia communications software.
+ *
+ * @CONTACT Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @STATUS @SofiaSIP Core library
+ *
+ * @LICENSE LGPL
+ *
+ * @section su_overview Overview
+ *
+ * The @b su module provides following interfaces for application programs:
+ *
+ * - su_types.h - integral types
+ * - su.h - @ref su_socket
+ * - su_localinfo.h - get list of local IP addresses
+ * - su_wait.h - @ref su_wait
+ * - su_time.h - @ref su_time
+ * - su_alloc.h - @ref su_alloc
+ * - su_log.h - @ref su_log
+ * - su_tag.h - @ref su_tag
+ * - su_md5.h - @ref su_md5
+ * - su_uniqueid.h - @ref su_uniqueid
+ *
+ * The @b su library also contains some collection datatypes:
+ * - htable.h - @ref su_htable
+ * - rbtree.h - balanced red-black trees
+ * - su_strlst.h - @ref su_strlst
+ * - su_vector.h - @ref su_vector
+ *
+ * There are also some convenience macros for unit test programs:
+ * - tstdef.h - macros for unit tests
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Jari Selin <Jari.Selin at nokia.com>
+ *
+ * @par SU Debug Log
+ *
+ * The debugging output from @b su module is controlled by #su_log_global
+ * log object. The environment variable #SU_DEBUG sets the default log
+ * level.
+ */
+
+/**@maindefgroup su OS Utilities
+ *
+ * The "su" module contains OS utilies for Sofia.
+ *
+ * The @b su is a simple, portable socket/timing/synchronizing library
+ * developed for Sofia communications software. Currently, interface to
+ * it consists of following parts:
+ *
+ * - <a href=su_types_h.html>su_types</a> - basic integer types
+ * - <a href=group_su_socket.html>su_socket</a> - socket functions
+ * - <a href=group_su_wait.html>su_wait</a> - synchronization functions
+ * - <a href=group_su_time.html>su_time</a> - time functions
+ * - <a href=group_su_alloc.html>su_alloc</a> - memory management functions
+ * - <a href=group_su_log.html>su_log</a> - generic logging functions
+ * - <a href=group_su_tag.html>su_tag</a> - tag list function
+ * - <a href=group_su_md5.html>su_md5</a> - MD5 hashing
+ */
+
+/**@defgroup su_programs Shell Programs
+ *
+ * The @b su module provides few shell utilities:
+ * - @ref localinfo (localinfo.c)
+ * - @ref addrinfo (addrinfo.c)
+ */
+
+/**@defgroup su_socket Socket Functions
+ *
+ * @brief The <su.h> contains the portable socket functions.
+ *
+ * The <su.h> contains following functions, macros, and types:
+ * - su_init(): initializes sockets
+ * - su_deinit(): deinitializes sockets
+ * - su_socket(): creates a socket
+ * - su_close(): closes a socket
+ * - su_ioctl(): ioctl to a socket
+ * - su_setreuseaddr(): set/reset reusing the addresses/ports for a socket
+ * - su_setblocking(): enables/disables blocking
+ * - su_isblocking(): checks if the previous call failed because it
+ * would have blocked
+ * - su_errno(): the latest socket error
+ * - su_perror(): prints the latest socket error message to stderr
+ * - su_strerror(): returns the given socket error message
+ * - su_perror2(): prints the given socket error message to stderr
+ * - su_soerror(): returns the error code associated with the socket
+ * - su_getmsgsize(): return the number of bytes that can be recv()ed from
+ * a socket
+ * - su_getlocalip(): return an IP address belonging to the local host
+ * - su_vsend(): scatter-gather send
+ * - su_vrecv(): scatter-gather receive
+ * - #su_iovec_t: structure holding scatter-gather IO vector
+ */
+
+/**@defgroup su_htable Hash tables
+ *
+ * Hash tables.
+ *
+ * The hash table interface and implementation is defined in
+ * <sofia-sip/htable.h>. Example code and tests for the implementation is in
+ * test_htable.c.
+ */
+
+
+/* <a name="su_wallclock"></a>
+ * <h3>Function @c su_wallclock() - get current time</h3>
+ *
+ * <h4>Synopsis</h4>
+ *
+ * <blockquote><pre>
+ * #include <su_time.h>
+ *
+ * void su_wallclock(su_time_t *tv);
+ * </pre></blockquote>
+ *
+ * <h4>Description</h4>
+ * <blockquote>
+ * Fills the @a tv with the current NTP timestamp.
+ * </blockquote>
+ *
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ * <tr><td>@c tv <td>pointer to the timeval object
+ * </table>
+ * </blockquote>
+ *
+ * <a name="su_now"></a>
+ * <h3>Function @c su_now() - get current time</h3>
+ *
+ * <h4>Synopsis</h4>
+ *
+ * <blockquote><pre>
+ * #include <su_time.h>
+ *
+ * su_time_t su_now(void);
+ * </pre></blockquote>
+ *
+ * <h4>Description</h4>
+ * <blockquote>
+ * Return the current NTP timestamp.
+ * </blockquote>
+ *
+ *
+ * <h4>Return Value</h4>
+ * <blockquote>
+ * The structure containing the current NTP timestamp.
+ * </blockquote>
+ *
+ * <a name="su_time_print"></a>
+ * <h3>Function @c su_time_print() - print an NTP timestamp</h3>
+ *
+ * <h4>Synopsis</h4>
+ *
+ * <blockquote><pre>
+ * #include <su_time.h>
+ *
+ * int su_time_print(char *s, int n, su_time_t const *tv);
+ * </pre></blockquote>
+ *
+ * <h4>Description</h4>
+ * <blockquote>
+ * This function prints an NTP timestamp as a decimal number to the
+ * given buffer.
+ * </blockquote>
+ *
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ * <tr><td>@c char *s <td>pointer to buffer
+ * <tr><td>@c int n <td>buffer size
+ * <tr><td>@c su_time_t const tv <td>pointer to the timeval object
+ * </table>
+ * </blockquote>
+ *
+ * <h4>Return Value</h4>
+ * <blockquote>
+ * The number of characters printed, excluding the final NUL.
+ * </blockquote>
+ *
+ * <a name="su_duration"></a>
+ * <h3>Function @c su_duration() - return time difference in milliseconds</h3>
+ *
+ * <h4>Synopsis</h4>
+ *
+ * <blockquote><pre>
+ * #include <su_time.h>
+ *
+ * su_duration_t su_duration(su_time_t t1, su_time_t t2);
+ * </pre></blockquote>
+ *
+ * <h4>Description</h4>
+ * <blockquote>
+ * Calculates the duration in milliseconds from @a t2 to @a t1 in milliseconds. If the difference is bigger
+ * than @c SU_MAX_DURATION, return @c SU_MAX_DURATION instead.
+ * </blockquote>
+ *
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ * <tr><td>@c t1 <td>after time
+ * <tr><td>@c t2 <td>before time
+ * </table>
+ * </blockquote>
+ *
+ * <h4>Return Value</h4>
+ * <blockquote>
+ * The duration in milliseconds between the two times.
+ * </blockquote>
+ *
+ * <a name="su_alloc.h"></a>
+ * <h1><su_alloc.h></h1>
+ *
+ * This section describes memory management functions.
+ *
+ *
+ * The
+ * @c su_alloc library provides convenience functions for
+ * memory management. The library defines an object @c su_home_t for
+ * collecting multiple memory allocations under one handle.
+ *
+ * <ul>
+ * - Function @c su_home_create()
+ * - create an su_home_t object
+ *
+ * - Function @c su_home_destroy()
+ * - free a home object
+ *
+ * - Function @c su_alloc()
+ * - allocate a memory block
+ *
+ * - Function @c su_zalloc()
+ * - allocate and zero a memory block
+ *
+ * - Function @c su_salloc()
+ * - allocate a structure
+ *
+ * - Function @c su_free()
+ * - free a memory block
+ *
+ * </ul>
+ *
+ *
+ * The functions for implementing objects derived from @c su_home_t
+ * are as follows:
+ * <ul>
+ * - Function @c su_home_init()
+ * - initialize an @c su_home_t object
+ *
+ * - Function @c su_home_deinit()
+ * - free memory blocks from home
+ *
+ * </ul>
+ *
+ * <a name="su_home_create"></a>
+ * <h3>Function @c su_home_create() - create an su_home_t object</h3>
+ *
+ * <h4>Synopsis</h4>
+ *
+ * <blockquote><pre>
+ * #include <su_alloc.h>
+ *
+ * su_home_t *su_home_create(void);
+ * </pre></blockquote>
+ *
+ * <h4>Description</h4>
+ * <blockquote>
+ * The function @c su_home_create() creates a home object used to
+ * collect multiple memory allocations under one handle, so that they can be
+ * freed by calling <dfn>su_home_destroy()</dfn>.
+ * </blockquote>
+ *
+ * <h4>Return Value</h4>
+ * <blockquote>
+ * This function returns a pointer to an @c su_home_t object, or
+ * @c NULL upon an error.
+ * </blockquote>
+ *
+ * <a name="su_home_destroy"></a>
+ * <h3>Function @c su_home_destroy() - free a home object</h3>
+ *
+ * <h4>Synopsis</h4>
+ *
+ * <blockquote><pre>
+ * #include <su_alloc.h>
+ *
+ * void su_home_destroy(su_home_t *h);
+ * </pre></blockquote>
+ *
+ * <h4>Description</h4>
+ * <blockquote>
+ * The function @c su_home_destroy() frees a home object, and all
+ * memory blocks associated with it.
+ * </blockquote>
+ *
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ * <tr><td>@c su_home_t *h <td>pointer to a home object
+ * </table>
+ * </blockquote>
+ *
+ * <a name="su_alloc"></a>
+ * <h3>Function @c su_alloc() - allocate a memory block</h3>
+ *
+ * <h4>Synopsis</h4>
+ *
+ * <blockquote><pre>
+ * #include <su_alloc.h>
+ *
+ * void *su_alloc(su_home_t *h, int n);
+ * </pre></blockquote>
+ *
+ * <h4>Description</h4>
+ * <blockquote>
+ * The function @c su_alloc() allocates a memory block of a given size.
+ *
+ *
+ * If @a h is @c NULL, this function behaves exactly like
+ * @c malloc().
+ * </blockquote>
+ *
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ * <tr><td>@c su_home_t *h <td>pointer to a home object
+ * <tr><td>@c int n <td>size of the memory block to be allocated
+ * </table>
+ * </blockquote>
+ *
+ * <h4>Return Value</h4>
+ * <blockquote>
+ * This function returns a pointer to the allocated memory block, or
+ * @c NULL, if an error occurred.
+ * </blockquote>
+ *
+ * <a name="su_zalloc"></a>
+ * <h3>Function @c su_zalloc() - allocate and zero a memory block</h3>
+ *
+ * <h4>Synopsis</h4>
+ *
+ * <blockquote><pre>
+ * #include <su_alloc.h>
+ *
+ * void *su_zalloc(su_home_t *h, int n)
+ * </pre></blockquote>
+ *
+ * <h4>Description</h4>
+ * <blockquote>
+ * The function @c su_zalloc() allocates a memory block with a given
+ * size and zeroes the allocated block.
+ * </blockquote>
+ *
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ * <tr><td>@c su_home_t *h <td>pointer to a home object
+ * <tr><td>@c int n <td>size of the memory block to be allocated
+ * </table>
+ * </blockquote>
+ *
+ * <h4>Return Value</h4>
+ * <blockquote>
+ * This function returns a pointer to the allocated memory block, or
+ * @c NULL, if an error occurred.
+ * </blockquote>
+ *
+ * <a name="su_salloc"></a>
+ * <h3>Function @c su_salloc() - allocate a structure</h3>
+ *
+ * <h4>Synopsis</h4>
+ *
+ * <blockquote><pre>
+ * #include <su_alloc.h>
+ *
+ * void *su_salloc(su_home_t *h, int s);
+ * </pre></blockquote>
+ *
+ * <h4>Description</h4>
+ * <blockquote>
+ * The function su_salloc() allocates a structure with a given size,
+ * zeros it, and initializes the size field to the given size.
+ * </blockquote>
+ *
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ * <tr><td>@c su_home_t *h <td>pointer to a home object
+ * <tr><td>@c int n <td>size of the structure to be allocated
+ * </table>
+ * </blockquote>
+ *
+ * <h4>Return Value</h4>
+ * <blockquote>
+ * This function returns a pointer to the allocated memory block, or
+ * @c NULL, if an error occurred.
+ * </blockquote>
+ *
+ * <a name="su_free"></a>
+ * <h3>Function @c su_free() - free a memory block</h3>
+ *
+ * <h4>Synopsis</h4>
+ *
+ * <blockquote><pre>
+ * #include <su_alloc.h>
+ *
+ * void su_free(su_home_t *h, void *vb);
+ * </pre></blockquote>
+ *
+ * <h4>Description</h4>
+ * <blockquote>
+ * The function @c su_free() frees a single memory block.
+ * </blockquote>
+ *
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ * <tr><td>@c su_home_t *h <td>pointer to a home object
+ * <tr><td>@c void *vb <td>pointer to the memory block to be freed
+ * </table>
+ * </blockquote>
+ *
+ * <h4>Return Value</h4>
+ * <blockquote>
+ * </blockquote>
+ *
+ * <a name="su_home_init"></a>
+ * <h3>Function @c su_home_init() - initialize an @c su_home_t object</h3>
+ *
+ * <h4>Synopsis</h4>
+ *
+ * <blockquote><pre>
+ * #include <su_alloc.h>
+ *
+ * int su_home_init(su_home_t *h);
+ * </pre></blockquote>
+ *
+ * <h4>Description</h4>
+ * <blockquote>
+ * The function @c su_home_init() initializes an object derived from
+ * @c su_home_t. It checks that the @a suh_size field is valid.
+ * </blockquote>
+ *
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ * <tr><td>@c su_home_t *h <td>pointer to a home object
+ * </table>
+ * </blockquote>
+ *
+ * <h4>Return Value</h4>
+ * <blockquote>
+ * The function @c su_home_init() returns @c 0 when
+ * successful, or @c -1 upon an error.
+ * </blockquote>
+ *
+ * <h4>Note</h4>
+ * <blockquote><strong>This is an internal function, and it is intended for
+ * implementing the objects derived from @c su_home_t.</strong>
+ * </blockquote>
+ *
+ * <a name="su_home_deinit"></a>
+ * <h3>Function @c su_home_deinit() - free memory blocks from home </h3>
+ *
+ * <h4>Synopsis</h4>
+ *
+ * <blockquote><pre>
+ * #include <su_alloc.h>
+ *
+ * void su_home_deinit(su_home_t *h);
+ * </pre></blockquote>
+ *
+ * <h4>Description</h4>
+ * <blockquote>
+ * The function @c su_home_deinit() frees the memory blocks
+ * associated with the home object.
+ * </blockquote>
+ *
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ * <tr><td>@c su_home_t *h <td>pointer to a home object
+ * </table>
+ * </blockquote>
+ *
+ * <h4>Note</h4>
+ * <blockquote><strong>This is an internal function, and it is intended for
+ * implementing the objects derived from @c su_home_t.</strong>
+ * </blockquote>
+ *
+ *
+ * <a name="su_wait.h"></a>
+ * <h1><su_wait.h></h1>
+ *
+ * This section describes synchronization functionality.
+ * The @c su_wait library provides portable synchronization
+ * primitives needed for running communication software.
+ *
+ * Synchronization means that the program can stop waiting for events,
+ * set callback functions for events, schedule timers, and set callback
+ * functions for timers. In other words, it is an OS-independent
+ * @c poll()/@c select()/@c WaitForMultipleObjects()
+ * interface, spiced up with timer interface.
+ *
+ * The library provides three kinds of objects: root
+ * objects (@c su_root_t), wait objects
+ * (@c su_wait_t), and timer objects
+ * (@c su_timer_t).
+ *
+ * <a name="wait"></a>
+ * <h2>Wait Objects</h2>
+ *
+ *
+ * Wait objects are used to signal I/O events to the process.
+ * The events are as follows:
+ *
+ * <dl>
+ * <dt>SU_WAIT_IN
+ * <dd>incoming data is available
+ *
+ * <dt>SU_WAIT_OUT
+ * <dd>data can be output
+ *
+ * <dt>SU_WAIT_ERR
+ * <dd>an error occurred
+ *
+ * <dt>SU_WAIT_HUP
+ * <dd>the socket connection was closed
+ *
+ * <dt>SU_WAIT_ACCEPT
+ * <dd>a listening socket accepted a new connection attempt
+ * </dl>
+ *
+ *
+ * It is possible to combine several events with |, binary or operator.
+ *
+ *
+ * Public API contains functions as follows:
+ * <ul>
+ * - su_wait_create()
+ * - su_wait_destroy()
+ * - su_wait()
+ * - su_wait_events()
+ * </ul>
+ *
+ *
+ * In Unix, the wait object is @c struct poll. The structure contains a file
+ * handle, a mask describing expected events, and a mask containing the
+ * occurred events after calling @c poll(), ie. @c su_wait().
+ *
+ *
+ * In Windows, the wait object is a @c HANDLE (a descriptor of a Windows
+ * kernel entity).
+ *
+ *
+ * <a name="su_wait_create"></a>
+ * <h3>Function @c su_wait_create()</h3>
+ *
+ * <h4>Synopsis</h4>
+ *
+ * <blockquote><pre>
+ * #include <su_wait.h>
+ *
+ * int su_wait_create(su_wait_t *newwait, su_socket_t socket, int events)</pre></blockquote>
+ *
+ * <h4>Description</h4>
+ *
+ * <blockquote>
+ * @c Su_wait_create() creates a new wait object for a
+ * @a socket with given @a events. The new wait object is
+ * assigned to the @a newwait parameter.
+ * </blockquote>
+ *
+ * <h4>Parameters</h4>
+ *
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ * <tr><td>@c newwait<td>the newly created wait object
+ * <tr><td>@c socket <td>socket descriptor
+ * <tr><td>@c events <td>mask for events that can signal this wait object
+ * </table>
+ * </blockquote>
+ *
+ * <h4>Return Value</h4>
+ *
+ * <blockquote>
+ * 0 if the call was successful, -1 otherwise.
+ * </blockquote>
+ *
+ * <a name="su_wait_destroy"></a>
+ * <h3>Function @c su_wait_destroy()</h3>
+ *
+ * <h4>Synopsis</h4>
+ *
+ * <blockquote><pre> #include <su_wait.h>
+ *
+ * int su_wait_destroy(su_wait_t *waitobj);
+ * </pre></blockquote>
+ *
+ * <h4>Description</h4>
+ * <blockquote>Destroy a wait object.
+ * </blockquote>
+ *
+ *
+ * <h4>Parameters</h4>
+ *
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ * <tr><td>@c waitobj <td>pointer to wait object
+ * </table>
+ * </blockquote>
+ *
+ * <h4>Return Value</h4>
+ *
+ * <blockquote>
+ * 0 when successful, -1 upon an error.
+ * </blockquote>
+ *
+ * <a name="su_wait"></a>
+ * <h3>Function @c su_wait()</h3>
+ *
+ * <h4>Synopsis</h4>
+ *
+ * <blockquote><pre>
+ * #include <su_wait.h>
+ *
+ * int su_wait(su_wait_t waits[], unsigned n, long timeout);
+ * </pre></blockquote>
+ *
+ * <h4>Description</h4>
+ * <blockquote> Block until a event specified by wait objects or a timeout occurs.
+ *
+ *
+ * In Unix, this is poll.
+ *
+ *
+ * In Windows, this is WSAWaitForMultipleEvents
+ * </blockquote>
+ *
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ * <tr><td>@c waits <td>array of wait objects
+ * <tr><td>@c n <td>number of wait objects in array waits
+ * <tr><td>@c timeout <td>timeout in milliseocnds
+ * </table>
+ * </blockquote>
+ *
+ * <h4>Return Value</h4>
+ * <blockquote>
+ * Index of the signaled wait object, if any, SU_WAIT_TIMEOUT if timeout
+ * occurred, and -1 upon an error.
+ * </blockquote>
+ *
+ * <a name="su_wait_events"></a>
+ * <h3>Function @c su_wait_events()</h3>
+ *
+ * <h4>Synopsis</h4>
+ *
+ * <blockquote><pre>
+ * #include <su_wait.h>
+ *
+ * int su_wait_events(su_wait_t *waitobj, su_socket_t s);
+ * </pre></blockquote>
+ *
+ * <h4>Description</h4>
+ * <blockquote> Return an mask describing events occurred.
+ * </blockquote>
+ *
+ *
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ * <tr><td>@c waitobj <td>pointer to wait object
+ * <tr><td>@c s <td>socket
+ * </table>
+ * </blockquote>
+ *
+ * <h4>Return Value</h4>
+ * <blockquote> Binary mask describing the events.
+ * </blockquote>
+ *
+ * <a name="su_wait_mask"></a>
+ * <h3>Function @c su_wait_mask()</h3>
+ *
+ * <h4>Synopsis</h4>
+ *
+ * <blockquote><pre>
+ * #include <su_wait.h>
+ *
+ * int su_wait_mask(su_wait_t *waitobj, su_socket_t s, int events);
+ * </pre></blockquote>
+ *
+ * <h4>Description</h4>
+ * <blockquote>
+ * Sets the mask describing events that can signal the wait object.
+ * </blockquote>
+ *
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ * <tr><td>@c waitobj <td>pointer to wait object
+ * <tr><td>@c s <td>socket
+ * <tr><td>@c events <td>new event mask
+ * </table>
+ * </blockquote>
+ *
+ * <h4>Return Value</h4>
+ * <blockquote>
+ * 0 when successful, -1 upon an error.
+ * </blockquote>
+ *
+ * <a name="root"></a>
+ * <h2>Root objects</h2>
+ *
+ *
+ * Root object is a structure containing a list of wait objects,
+ * associated callback functions, and arguments to these functions.
+ * It can also contain a list of timers, and a magic cookie (a pointer
+ * defined by root object user.)
+ *
+ *
+ * The public API contains following functions:
+ * <ul>
+ * - su_root_create()
+ * - su_root_destroy()
+ * - su_root_magic()
+ * - su_root_register()
+ * - su_root_unregister()
+ * - su_root_run()
+ * - su_root_break()
+ * - su_root_step()
+ * </ul>
+ *
+ * These functions are intended for implementing su_root API:
+ * <ul>
+ * - su_root_init()
+ * - su_root_deinit()
+ * - su_root_query()
+ * - su_root_event()
+ * </ul>
+ *
+ * <a name="su_root_create"></a>
+ * <h3>Function @c su_root_create()</h3>
+ *
+ * <h4>Synopsis</h4>
+ *
+ * <blockquote><pre>
+ * #include <su_wait.h>
+ *
+ * su_root_t *su_root_create(su_root_magic_t *magic);
+ * </pre></blockquote>
+ *
+ * <h4>Description</h4>
+ * <blockquote> Allocate and initialize an instance of su_root_t
+ * </blockquote>
+ *
+ *
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ * <tr><td>@c magic <td>pointer to user data
+ * </table>
+ * </blockquote>
+ *
+ * <h4>Return Value</h4>
+ * <blockquote> A pointer to allocated su_root_t instance, NULL on error.
+ * </blockquote>
+ *
+ *
+ * <a name="su_root_destroy"></a>
+ * <h3>Function @c su_root_destroy()</h3>
+ *
+ * <h4>Synopsis</h4>
+ *
+ * <blockquote><pre>
+ * #include <su_wait.h>
+ *
+ * void su_root_destroy(su_root_t *root);
+ * </pre></blockquote>
+ *
+ * <h4>Description</h4>
+ * <blockquote> Deinitialize and free an instance of su_root_t
+ * </blockquote>
+ *
+ *
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ * <tr><td>@c root <td>pointer to a root structure
+ * </table>
+ * </blockquote>
+ *
+ *
+ * <a name="su_root_magic"></a>
+ * <h3>Function @c su_root_magic()</h3>
+ *
+ * <h4>Synopsis</h4>
+ *
+ * <blockquote><pre>
+ * #include <su_wait.h>
+ *
+ * su_root_magic_t *su_root_magic(su_root_t *root);
+ * </pre></blockquote>
+ *
+ * <h4>Description</h4>
+ * <blockquote> Return the user data pointer that was given input to su_root_create() or
+ *
+ * su_root_init().
+ * </blockquote>
+ *
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ * <tr><td>@c root <td>pointer to a root object
+ * </table>
+ * </blockquote>
+ *
+ * <h4>Return Value</h4>
+ * <blockquote> A pointer to user data
+ * </blockquote>
+ *
+ *
+ * <a name="su_root_register"></a>
+ * <h3>Function @c su_root_register()</h3>
+ *
+ * <h4>Synopsis</h4>
+ *
+ * <blockquote><pre>
+ * #include <su_wait.h>
+ *
+ * int su_root_register(su_root_t *root,
+ * su_wait_t *waits,
+ * su_wakeup_f callback,
+ * su_wakeup_arg_t arg,
+ * int priority);
+ * </pre></blockquote>
+ *
+ * <h4>Description</h4>
+ * <blockquote> Register a su_wait_t object. The wait object, a callback function and
+ *
+ * a argument is stored to the root object. The callback function is called,
+ * when the wait object is signaled.
+ *
+ * Please note if identical wait objects are inserted, only first one is
+ * ever signalled.
+ * </blockquote>
+ *
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ * <tr><td>@c root <td>pointer to root object
+ * <tr><td>@c waits <td>pointer to wait object
+ * <tr><td>@c callback <td>callback function pointer
+ * <tr><td>@c arg <td>argument given to callback function when it is invoked
+ * <tr><td>@c priority <td>relative priority of the wait object
+ * (0 is normal, 1 important, 2 realtime)
+ * </table>
+ * </blockquote>
+ *
+ * <h4>Return Value</h4>
+ * <blockquote> Index of the wait object, or -1 upon an error.
+ * </blockquote>
+ *
+ *
+ * <a name="su_root_unregister"></a>
+ * <h3>Function @c su_root_unregister()</h3>
+ *
+ * <h4>Synopsis</h4>
+ *
+ * <blockquote><pre>
+ * #include <su_wait.h>
+ *
+ * int su_root_unregister(su_root_t *root,
+ * su_wait_t *wait,
+ * su_wakeup_f callback,
+ * su_wakeup_arg_t arg);
+ * </pre></blockquote>
+ *
+ * <h4>Description</h4>
+ * <blockquote> UnRegisters a su_wait_t object. The wait object, a callback function and
+ *
+ * a argument are removed from the root object. The callback function is called,
+ * when the wait object is signaled.
+ * </blockquote>
+ *
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ * <tr><td>@c root <td>pointer to root object
+ * <tr><td>@c waits <td>pointer to wait object
+ * <tr><td>@c callback <td>callback function pointer (may be NULL)
+ * <tr><td>@c arg <td>argument given to callback function when it
+ * is invoked (may be NULL)
+ * </table>
+ * </blockquote>
+ *
+ * <h4>Return Value</h4>
+ * <blockquote> Index of the wait object, or -1 upon an error.
+ * </blockquote>
+ *
+ *
+ * <a name="su_root_run"></a>
+ * <h3>Function @c su_root_run()</h3>
+ *
+ * <h4>Synopsis</h4>
+ *
+ * <blockquote><pre>
+ * #include <su_wait.h>
+ *
+ * void su_root_run(su_root_t *root);
+ * </pre></blockquote>
+ *
+ * <h4>Description</h4>
+ * <blockquote> This function waits for wait objects and the timers associated with
+ * the root object. When any wait object is signaled or timer is
+ * expired, it invokes the callbacks, and returns waiting.
+ *
+ *
+ * This function returns when su_root_break() is called from a callback.
+ * </blockquote>
+ *
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ * <tr><td>@c root <td>pointer to root object
+ * </table>
+ * </blockquote>
+ *
+ *
+ * <a name="su_root_break"></a>
+ * <h3>Function @c su_root_break()</h3>
+ *
+ * <h4>Synopsis</h4>
+ *
+ * <blockquote><pre>
+ * #include <su_wait.h>
+ *
+ * void su_root_break(su_root_t *root);
+ * </pre></blockquote>
+ *
+ * <h4>Description</h4>
+ * <blockquote> If this function is used to terminate execution of su_root_run(). It
+ *
+ * can be called from a callback function.
+ * </blockquote>
+ *
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ * <tr><td>@c root <td>pointer to root object
+ * </table>
+ * </blockquote>
+ *
+ *
+ * <a name="su_root_step"></a>
+ * <h3>Function @c su_root_step()</h3>
+ *
+ * <h4>Synopsis</h4>
+ *
+ * <blockquote><pre>
+ * #include <su_wait.h>
+ *
+ * su_duration_t su_root_step(su_root_t *root, su_duration_t tout);
+ * </pre></blockquote>
+ *
+ * <h4>Description</h4>
+ * <blockquote> This function waits for wait objects and the timers associated with
+ * the @a root object. When any wait object is signaled or timer is
+ * expired, it invokes the callbacks, and returns.
+ *
+ *
+ * This function returns when a callback has been invoked or @a tout
+ * milliseconds is elapsed.
+ * </blockquote>
+ *
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ * <tr><td>@c root <td>pointer to root object
+ * <tr><td>@c tout <td>timeout in milliseconds
+ * </table>
+ * </blockquote>
+ *
+ * <h4>Return Value</h4>
+ * <blockquote>
+ * Milliseconds to the next invocation of timer, or SU_WAIT_FOREVER if
+ * there are no active timers.
+ * </blockquote>
+ *
+ * <a name="timer"></a>
+ * <h2>Timer objects</h2>
+ *
+ * Timers are used to schedule some task to be executed at given time or
+ * after a default interval. The default interval is specified when the
+ * timer is created. We call timer activation "setting the timer", and
+ * deactivation "resetting the timer" (as in SDL). When the given time has
+ * arrived or the default interval has elapsed, the timer expires and
+ * it is ready for execution.
+ *
+ * These functions are available for handling timers:
+ *
+ * - su_timer_create()
+ * - su_timer_destroy()
+ * - su_timer_set()
+ * - su_timer_set_at()
+ * - su_timer_reset()
+ * - su_timer_run()
+ *
+ * <a name="su_timer_create"></a>
+ * <h3>Function @c su_timer_create()</h3>
+ *
+ * <h4>Synopsis</h4>
+ *
+ * <blockquote><pre>
+ * #include <su_wait.h>
+ *
+ * su_timer_t *su_timer_create(su_root_t *root, su_duration_t msec);
+ * </pre></blockquote>
+ *
+ * <h4>Description</h4>
+ *
+ * <blockquote>
+ * Allocate and initialize an instance of su_timer_t.
+ * </blockquote>
+ *
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ * <tr><td>@c root <td>the root object with which the timer will be associated
+ * <tr><td>@c msec <td>the default duration of the timer
+ * </table>
+ * </blockquote>
+ *
+ * <h4>Return Value</h4>
+ * <blockquote> A pointer to allocated timer instance, NULL on error.
+ * </blockquote>
+ *
+ *
+ * <a name="su_timer_destroy"></a>
+ * <h3>Function @c su_timer_destroy()</h3>
+ *
+ * <h4>Synopsis</h4>
+ *
+ * <blockquote><pre>
+ * #include <su_wait.h>
+ *
+ * void su_timer_destroy(su_timer_t *t);
+ * </pre></blockquote>
+ *
+ * <h4>Description</h4>
+ * <blockquote> Deinitialize and free an instance of su_timer_t.
+ * </blockquote>
+ *
+ *
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ * <tr><td>@c t <td>pointer to the timer object
+ * </table>
+ * </blockquote>
+ *
+ *
+ * <a name="su_timer_set"></a>
+ * <h3>Function @c su_timer_set()</h3>
+ *
+ * <h4>Synopsis</h4>
+ *
+ * <blockquote><pre>
+ * #include <su_wait.h>
+ *
+ * int su_timer_set(su_timer_t *t,
+ * su_timer_f wakeup,
+ * su_wakeup_arg_t arg);
+ * </pre></blockquote>
+ *
+ * <h4>Description</h4>
+ * <blockquote> Sets the given timer to expire after the default duration.
+ *
+ * The timer must have an default duration.
+ * </blockquote>
+ *
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ * <tr><td>@c t <td>pointer to the timer object
+ * <tr><td>@c wakeup <td>pointer to the wakeup function
+ * <tr><td>@c arg <td>argument given to the wakeup function
+ * </table>
+ * </blockquote>
+ *
+ * <h4>Return Value</h4>
+ * <blockquote> 0 if successful, -1 otherwise.
+ * </blockquote>
+ *
+ *
+ * <a name="su_timer_set_at"></a>
+ * <h3>Function @c su_timer_set_at()</h3>
+ *
+ * <h4>Synopsis</h4>
+ *
+ * <blockquote><pre>
+ * #include <su_wait.h>
+ *
+ * int su_timer_set_at(su_timer_t *t,
+ * su_timer_f wakeup,
+ * su_wakeup_arg_t arg,
+ * su_time_t when);
+ * </pre></blockquote>
+ *
+ * <h4>Description</h4>
+ * <blockquote> Sets the timer to expire at given time.
+ * </blockquote>
+ *
+ *
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ * <tr><td>@c t <td>pointer to the timer object
+ * <tr><td>@c wakeup <td>pointer to the wakeup function
+ * <tr><td>@c arg <td>argument given to the wakeup function
+ * <tr><td>@c when <td>time structure defining the wakeup time
+ * </table>
+ * </blockquote>
+ *
+ * <h4>Return Value</h4>
+ * <blockquote> 0 if successful, -1 otherwise.
+ * </blockquote>
+ *
+ *
+ * <a name="su_timer_reset"></a>
+ * <h3>Function @c su_timer_reset()</h3>
+ *
+ * <h4>Synopsis</h4>
+ *
+ * <blockquote><pre>
+ * #include <su_wait.h>
+ *
+ * int su_timer_reset(su_timer_t *t);
+ * </pre></blockquote>
+ *
+ * <h4>Description</h4>
+ * <blockquote> Resets the given timer.
+ * </blockquote>
+ *
+ *
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ * <tr><td>@c t <td>pointer to the timer object
+ * </table>
+ * </blockquote>
+ *
+ * <h4>Return Value</h4>
+ * <blockquote> 0 if successful, -1 otherwise.
+ * </blockquote>
+ *
+ * <a name="su_timer_run"></a>
+ * <h3>Function @c su_timer_run()</h3>
+ *
+ * <h4>Synopsis</h4>
+ *
+ * <blockquote><pre>
+ * #include <su_wait.h>
+ *
+ * su_duration_t su_timer_run(su_timer_t ** const t0, su_duration_t tout);
+ * </pre></blockquote>
+ *
+ * <h4>Description</h4>
+ * <blockquote> Expires and executes expired timers in queue.
+ * </blockquote>
+ *
+ *
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ * <tr><td>@c t0 <td>pointer to the timer queue
+ * <tr><td>@c tout <td>timeout in milliseconds
+ * </table>
+ * </blockquote>
+ *
+ * <h4>Return Value</h4>
+ * <blockquote>
+ * The duration in milliseconds before the next timer expires, or timeout (2**31 - 1
+ * ms), whichever is shorter.
+ * </blockquote>
+ *
+ * <!--
+ * Root object is used for synchronizing. There must be one root object per
+ * thread. There are two alternative ways for creating a root object. If you
+ * are just using su_root_t, and don't want to <a
+ * href="#inherit_su_root_t">inherit from it</a>, you can use
+ * @c su_create().
+ * -->
+ *
+ * <a name="su_wait_internal.h"></a>
+ * <h1><su_wait_internal.h></h1>
+ *
+ *
+ * This section contains the internal functions, that is, functions used to
+ * implement objects in @c <su_wait.h>.
+ *
+ * <a name="su_root_init"></a>
+ * <h3>Function @c su_root_init()</h3>
+ *
+ * <h4>Synopsis</h4>
+ *
+ * <blockquote><pre>
+ * #include <su_wait.h>
+ * #include <su_wait_internal.h>
+ *
+ * int su_root_init(su_root_t *root, su_root_magic_t *magic);
+ * </pre></blockquote>
+ *
+ * <h4>Description</h4>
+ *
+ * <blockquote>
+ *
+ * Initialize an instance of @c su_root_t. The caller should allocate
+ * the memory required for su_root_t, and set the sur_size to the size of the
+ * allocated structure.
+ *
+ * </blockquote>
+ *
+ * <h4>Parameters</h4>
+ *
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ * <tr><td>@c root <td>pointer to a uninitialized root structure
+ * </table>
+ * </blockquote>
+ *
+ * <h4>Return Value</h4>
+ * <blockquote> 0 when call was successful, -1 otherwise.
+ * </blockquote>
+ *
+ *
+ * <h4>Note</h4>
+ * <blockquote>
+ * <strong>This is an internal function, and it is intended for implementing
+ * the objects derived from @c su_root_t.</strong>
+ * </blockquote>
+ *
+ *
+ * <a name="su_root_deinit"></a>
+ * <h3>Function @c su_root_deinit()</h3>
+ *
+ * <h4>Synopsis</h4>
+ *
+ * <blockquote><pre>
+ * #include <su_wait.h>
+ * #include <su_wait_internal.h>
+ *
+ * void su_root_deinit(su_root_t *root);
+ * </pre></blockquote>
+ *
+ * <h4>Description</h4>
+ * <blockquote> Deinitialize an instance of su_root_t
+ * </blockquote>
+ *
+ *
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ * <tr><td>@c root <td>pointer to a root structure
+ * </table>
+ * </blockquote>
+ *
+ * <h4>Note</h4>
+ * <blockquote> <strong>This is an internal function, and it is intended for
+ * implementing the objects derived from @c su_root_t.</strong>
+ * </blockquote>
+ *
+ * <a name="su_root_query"></a>
+ * <h3>Function @c su_root_query()</h3>
+ *
+ * <h4>Synopsis</h4>
+ *
+ * <blockquote><pre>
+ * #include <su_wait.h>
+ * #include <su_wait_internal.h>
+ *
+ * unsigned su_root_query(su_root_t *root, su_wait_t *waits, unsigned n_waits);
+ * </pre></blockquote>
+ *
+ * <h4>Description</h4>
+ * <blockquote> Copies the su_wait_t objects from the root. The number of wait objects
+ *
+ * can be found out by calling su_root_query() with n_waits as zero.
+ * </blockquote>
+ *
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ * <tr><td>@c waits <td>pointer to array to which wait objects are copied
+ * <tr><td>@c root <td>pointer to root object
+ * <tr><td>@c n_waits <td>number of wait objects fitting in array waits
+ * </table>
+ * </blockquote>
+ *
+ * <h4>Return Value</h4>
+ * <blockquote> Number of wait objects, or 0 upon an error.
+ * </blockquote>
+ *
+ *
+ * <h4>Note</h4>
+ * <blockquote><strong>This is an internal function, and it is intended for
+ * implementing the objects derived from @c su_root_t.</strong>
+ * </blockquote>
+ *
+ *
+ * <a name="su_root_event"></a>
+ * <h3>Function @c su_root_event()</h3>
+ *
+ * <h4>Synopsis</h4>
+ *
+ * <blockquote><pre>
+ * #include <su_wait.h>
+ * #include <su_wait_internal.h>
+ *
+ * void su_root_event(su_root_t *root, su_wait_t *waitobj);
+ * </pre></blockquote>
+ *
+ * <h4>Description</h4>
+ * <blockquote> Invokes the callback function associated with the wait object.
+ *
+ *
+ * If waitobj is NULL, check if a wait object associated with root is
+ * signaled, and its callback is invoked.
+ * </blockquote>
+ *
+ * <h4>Parameters</h4>
+ * <blockquote>
+ * <table cellpadding=3 cellspacing=0 border=1>
+ * <tr><td>@c root <td>pointer to root object
+ * <tr><td>@c waitobj <td>pointer to wait object, or NULL
+ * </table>
+ * </blockquote>
+ *
+ * <h4>Note</h4>
+ * <blockquote><strong>This is an internal function, and it is intended for
+ * implementing the objects derived from @c su_root_t.</strong>
+ * </blockquote>
+ *
+ */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_addrinfo.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_addrinfo.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,956 @@
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sofia-sip/su_addrinfo.h>
+#include <sofia-sip/su.h>
+
+#ifndef IN_LOOPBACKNET
+#define IN_LOOPBACKNET 127
+#endif
+
+#ifndef IN_EXPERIMENTAL
+#define IN_EXPERIMENTAL(a) ((((long int) (a)) & 0xf0000000) == 0xf0000000)
+#endif
+
+#if !HAVE_GETADDRINFO
+
+#include <string.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+/*
+ * "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator.
+ *
+ * Issues to be discussed:
+ * - Thread safe-ness must be checked.
+ * - Return values. There are nonstandard return values defined and used
+ * in the source code. This is because RFC2133 is silent about which error
+ * code must be returned for which situation.
+ * - PF_UNSPEC case would be handled in getipnodebyname() with the AI_ALL flag.
+ */
+
+#if defined(__KAME__) && defined(INET6)
+# define FAITH
+#endif
+
+#define SUCCESS 0
+#define GAI_ANY 0
+#define YES 1
+#define NO 0
+
+#undef SU_HAVE_IN6
+
+#ifdef FAITH
+static int translate = NO;
+static struct in6_addr faith_prefix = IN6ADDR_GAI_ANY_INIT;
+#endif
+
+static const char in_addrany[] = { 0, 0, 0, 0 };
+static const char in6_addrany[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+
+};
+static const char in_loopback[] = { 127, 0, 0, 1 };
+static const char in6_loopback[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
+};
+
+struct sockinet {
+ u_char si_len;
+ u_char si_family;
+ u_short si_port;
+};
+
+static struct gai_afd {
+ int a_af;
+ int a_addrlen;
+ int a_socklen;
+ int a_off;
+ const char *a_addrany;
+ const char *a_loopback;
+} gai_afdl [] = {
+#if SU_HAVE_IN6
+#define N_INET6 0
+ {PF_INET6, sizeof(struct in6_addr),
+ sizeof(struct sockaddr_in6),
+ offsetof(struct sockaddr_in6, sin6_addr),
+ in6_addrany, in6_loopback},
+#define N_INET 1
+#else
+#define N_INET 0
+#endif
+ {PF_INET, sizeof(struct in_addr),
+ sizeof(struct sockaddr_in),
+ offsetof(struct sockaddr_in, sin_addr),
+ in_addrany, in_loopback},
+ {0, 0, 0, 0, NULL, NULL},
+};
+
+#if SU_HAVE_IN6
+#define PTON_MAX 16
+#else
+#define PTON_MAX 4
+#endif
+
+#if SU_HAVE_IN6 && !defined(s6_addr8)
+# define s6_addr8 s6_addr
+#endif
+
+#if !SU_HAVE_IN6
+#if defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
+#else
+extern int h_errno;
+#endif
+#endif
+
+static int get_name(const char *, struct gai_afd *,
+ struct addrinfo **, char *, struct addrinfo *,
+ int);
+static int get_addr(const char *, int, struct addrinfo **,
+ struct addrinfo *, int);
+static int str_isnumber(const char *);
+
+#define GET_CANONNAME(ai, str) \
+if (pai->ai_flags & AI_CANONNAME) {\
+ if (((ai)->ai_canonname = (char *)malloc(strlen(str) + 1)) != NULL) {\
+ strcpy((ai)->ai_canonname, (str));\
+ } else {\
+ error = EAI_MEMORY;\
+ goto free;\
+ }\
+}
+
+#if SU_HAVE_SOCKADDR_SA_LEN
+#define GET_AI(ai, gai_afd, addr, port) {\
+ char *p;\
+ if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\
+ ((gai_afd)->a_socklen)))\
+ == NULL) goto free;\
+ memcpy(ai, pai, sizeof(struct addrinfo));\
+ (ai)->ai_addr = (struct sockaddr *)((ai) + 1);\
+ memset((ai)->ai_addr, 0, (gai_afd)->a_socklen);\
+ (ai)->ai_addr->sa_len = (ai)->ai_addrlen = (gai_afd)->a_socklen;\
+ (ai)->ai_addr->sa_family = (ai)->ai_family = (gai_afd)->a_af;\
+ ((struct sockinet *)(ai)->ai_addr)->si_port = port;\
+ p = (char *)((ai)->ai_addr);\
+ memcpy(p + (gai_afd)->a_off, (addr), (gai_afd)->a_addrlen);\
+}
+#else
+#define GET_AI(ai, gai_afd, addr, port) {\
+ char *p;\
+ if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\
+ ((gai_afd)->a_socklen)))\
+ == NULL) goto free;\
+ memcpy(ai, pai, sizeof(struct addrinfo));\
+ (ai)->ai_addr = (struct sockaddr *)((ai) + 1);\
+ memset((ai)->ai_addr, 0, (gai_afd)->a_socklen);\
+ (ai)->ai_addrlen = (gai_afd)->a_socklen; \
+ (ai)->ai_addr->sa_family = (ai)->ai_family = (gai_afd)->a_af;\
+ ((struct sockinet *)(ai)->ai_addr)->si_port = port;\
+ p = (char *)((ai)->ai_addr);\
+ memcpy(p + (gai_afd)->a_off, (addr), (gai_afd)->a_addrlen);\
+}
+#endif
+
+#define ERR(err) { error = (err); goto bad; }
+
+static int
+str_isnumber(p)
+ const char *p;
+{
+ char *q = (char *)p;
+ while (*q) {
+ if (! isdigit(*q))
+ return NO;
+ q++;
+ }
+ return YES;
+}
+
+static
+int
+getaddrinfo(hostname, servname, hints, res)
+ const char *hostname, *servname;
+ const struct addrinfo *hints;
+ struct addrinfo **res;
+{
+ struct addrinfo sentinel;
+ struct addrinfo *top = NULL;
+ struct addrinfo *cur;
+ int i, error = 0;
+ char pton[PTON_MAX];
+ struct addrinfo ai;
+ struct addrinfo *pai;
+ u_short port;
+
+#ifdef FAITH
+ static int firsttime = 1;
+
+ if (firsttime) {
+ /* translator hack */
+ {
+ char *q = getenv("GAI");
+ if (q && inet_pton(AF_INET6, q, &faith_prefix) == 1)
+ translate = YES;
+ }
+ firsttime = 0;
+ }
+#endif
+
+ /* initialize file static vars */
+ sentinel.ai_next = NULL;
+ cur = &sentinel;
+ pai = &ai;
+ pai->ai_flags = 0;
+ pai->ai_family = PF_UNSPEC;
+ pai->ai_socktype = GAI_ANY;
+ pai->ai_protocol = GAI_ANY;
+ pai->ai_addrlen = 0;
+ pai->ai_canonname = NULL;
+ pai->ai_addr = NULL;
+ pai->ai_next = NULL;
+ port = GAI_ANY;
+
+ if (hostname == NULL && servname == NULL)
+ return EAI_NONAME;
+ if (hints) {
+ /* error check for hints */
+ if (hints->ai_addrlen || hints->ai_canonname ||
+ hints->ai_addr || hints->ai_next)
+ ERR(EAI_BADHINTS); /* xxx */
+ if (hints->ai_flags & ~AI_MASK)
+ ERR(EAI_BADFLAGS);
+ switch (hints->ai_family) {
+ case PF_UNSPEC:
+ case PF_INET:
+#if SU_HAVE_IN6
+ case PF_INET6:
+#endif
+ break;
+ default:
+ ERR(EAI_FAMILY);
+ }
+ memcpy(pai, hints, sizeof(*pai));
+ switch (pai->ai_socktype) {
+ case GAI_ANY:
+ switch (pai->ai_protocol) {
+ case GAI_ANY:
+ break;
+ case IPPROTO_UDP:
+ pai->ai_socktype = SOCK_DGRAM;
+ break;
+ case IPPROTO_TCP:
+ pai->ai_socktype = SOCK_STREAM;
+ break;
+#if HAVE_SCTP
+ case IPPROTO_SCTP:
+ pai->ai_socktype = SOCK_STREAM;
+ break;
+#endif
+ default:
+ pai->ai_socktype = SOCK_RAW;
+ break;
+ }
+ break;
+ case SOCK_RAW:
+ break;
+ case SOCK_DGRAM:
+ if (pai->ai_protocol != IPPROTO_UDP &&
+#if HAVE_SCTP
+ pai->ai_protocol != IPPROTO_SCTP &&
+#endif
+ pai->ai_protocol != GAI_ANY)
+ ERR(EAI_BADHINTS); /*xxx*/
+ if (pai->ai_protocol == GAI_ANY)
+ pai->ai_protocol = IPPROTO_UDP;
+ break;
+ case SOCK_STREAM:
+ if (pai->ai_protocol != IPPROTO_TCP &&
+#if HAVE_SCTP
+ pai->ai_protocol != IPPROTO_SCTP &&
+#endif
+ pai->ai_protocol != GAI_ANY)
+ ERR(EAI_BADHINTS); /*xxx*/
+ if (pai->ai_protocol == GAI_ANY)
+ pai->ai_protocol = IPPROTO_TCP;
+ break;
+#if HAVE_SCTP
+ case SOCK_SEQPACKET:
+ if (pai->ai_protocol != IPPROTO_SCTP &&
+ pai->ai_protocol != GAI_ANY)
+ ERR(EAI_BADHINTS); /*xxx*/
+
+ if (pai->ai_protocol == GAI_ANY)
+ pai->ai_protocol = IPPROTO_SCTP;
+ break;
+#endif
+ default:
+ ERR(EAI_SOCKTYPE);
+ break;
+ }
+ }
+
+ /*
+ * service port
+ */
+ if (servname) {
+ if (str_isnumber(servname)) {
+ if (pai->ai_socktype == GAI_ANY) {
+ /* caller accept *GAI_ANY* socktype */
+ pai->ai_socktype = SOCK_DGRAM;
+ pai->ai_protocol = IPPROTO_UDP;
+ }
+ port = htons(atoi(servname));
+ } else {
+ struct servent *sp;
+ char *proto;
+
+ proto = NULL;
+ switch (pai->ai_socktype) {
+ case GAI_ANY:
+ proto = NULL;
+ break;
+ case SOCK_DGRAM:
+ proto = "udp";
+ break;
+ case SOCK_STREAM:
+ proto = "tcp";
+ break;
+ default:
+ fprintf(stderr, "panic!\n");
+ break;
+ }
+ if ((sp = getservbyname(servname, proto)) == NULL)
+ ERR(EAI_SERVICE);
+ port = sp->s_port;
+ if (pai->ai_socktype == GAI_ANY) {
+ if (strcmp(sp->s_proto, "udp") == 0) {
+ pai->ai_socktype = SOCK_DGRAM;
+ pai->ai_protocol = IPPROTO_UDP;
+ } else if (strcmp(sp->s_proto, "tcp") == 0) {
+ pai->ai_socktype = SOCK_STREAM;
+ pai->ai_protocol = IPPROTO_TCP;
+#if HAVE_SCTP
+ } else if (strcmp(sp->s_proto, "sctp") == 0) {
+ pai->ai_socktype = SOCK_STREAM;
+ pai->ai_protocol = IPPROTO_SCTP;
+#endif
+ } else
+ ERR(EAI_PROTOCOL); /*xxx*/
+ }
+ }
+ }
+
+ /*
+ * hostname == NULL.
+ * passive socket -> anyaddr (0.0.0.0 or ::)
+ * non-passive socket -> localhost (127.0.0.1 or ::1)
+ */
+ if (hostname == NULL) {
+ struct gai_afd *gai_afd;
+
+ for (gai_afd = &gai_afdl[0]; gai_afd->a_af; gai_afd++) {
+ if (!(pai->ai_family == PF_UNSPEC
+ || pai->ai_family == gai_afd->a_af)) {
+ continue;
+ }
+
+ if (pai->ai_flags & AI_PASSIVE) {
+ GET_AI(cur->ai_next, gai_afd, gai_afd->a_addrany, port);
+ /* xxx meaningless?
+ * GET_CANONNAME(cur->ai_next, "anyaddr");
+ */
+ } else {
+ GET_AI(cur->ai_next, gai_afd, gai_afd->a_loopback,
+ port);
+ /* xxx meaningless?
+ * GET_CANONNAME(cur->ai_next, "localhost");
+ */
+ }
+ cur = cur->ai_next;
+ }
+ top = sentinel.ai_next;
+ if (top)
+ goto good;
+ else
+ ERR(EAI_FAMILY);
+ }
+
+ /* hostname as numeric name */
+ for (i = 0; gai_afdl[i].a_af; i++) {
+ if (inet_pton(gai_afdl[i].a_af, hostname, pton)) {
+ u_long v4a;
+ u_char pfx;
+
+ switch (gai_afdl[i].a_af) {
+ case AF_INET:
+ v4a = ((struct in_addr *)pton)->s_addr;
+ if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
+ pai->ai_flags &= ~AI_CANONNAME;
+ v4a >>= IN_CLASSA_NSHIFT;
+ if (v4a == 0 || v4a == IN_LOOPBACKNET)
+ pai->ai_flags &= ~AI_CANONNAME;
+ break;
+#if SU_HAVE_IN6
+ case AF_INET6:
+ pfx = ((struct in6_addr *)pton)->s6_addr8[0];
+ if (pfx == 0 || pfx == 0xfe || pfx == 0xff)
+ pai->ai_flags &= ~AI_CANONNAME;
+ break;
+#endif
+ }
+
+ if (pai->ai_family == gai_afdl[i].a_af ||
+ pai->ai_family == PF_UNSPEC) {
+ if (! (pai->ai_flags & AI_CANONNAME)) {
+ GET_AI(top, &gai_afdl[i], pton, port);
+ goto good;
+ }
+ /*
+ * if AI_CANONNAME and if reverse lookup
+ * fail, return ai anyway to pacify
+ * calling application.
+ *
+ * XXX getaddrinfo() is a name->address
+ * translation function, and it looks strange
+ * that we do addr->name translation here.
+ */
+ get_name(pton, &gai_afdl[i], &top, pton, pai, port);
+ goto good;
+ } else
+ ERR(EAI_FAMILY); /*xxx*/
+ }
+ }
+
+ if (pai->ai_flags & AI_NUMERICHOST)
+ ERR(EAI_NONAME);
+
+ /* hostname as alphabetical name */
+ error = get_addr(hostname, pai->ai_family, &top, pai, port);
+ if (error == 0) {
+ if (top) {
+ good:
+ *res = top;
+ return SUCCESS;
+ } else
+ error = EAI_FAIL;
+ }
+ free:
+ if (top)
+ freeaddrinfo(top);
+ bad:
+ *res = NULL;
+ return error;
+}
+
+static int
+get_name(addr, gai_afd, res, numaddr, pai, port0)
+ const char *addr;
+ struct gai_afd *gai_afd;
+ struct addrinfo **res;
+ char *numaddr;
+ struct addrinfo *pai;
+ int port0;
+{
+ u_short port = port0 & 0xffff;
+ struct hostent *hp;
+ struct addrinfo *cur;
+ int error = 0, h_error;
+
+#if SU_HAVE_IN6
+ hp = getipnodebyaddr(addr, gai_afd->a_addrlen, gai_afd->a_af, &h_error);
+#else
+ hp = gethostbyaddr(addr, gai_afd->a_addrlen, AF_INET);
+#endif
+ if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
+ GET_AI(cur, gai_afd, hp->h_addr_list[0], port);
+ GET_CANONNAME(cur, hp->h_name);
+ } else
+ GET_AI(cur, gai_afd, numaddr, port);
+
+#if SU_HAVE_IN6
+ if (hp)
+ freehostent(hp);
+#endif
+ *res = cur;
+ return SUCCESS;
+ free:
+ if (cur)
+ freeaddrinfo(cur);
+#if SU_HAVE_IN6
+ if (hp)
+ freehostent(hp);
+#endif
+ /* bad: */
+ *res = NULL;
+ return error;
+}
+
+static int
+get_addr(hostname, af, res, pai, port0)
+ const char *hostname;
+ int af;
+ struct addrinfo **res;
+ struct addrinfo *pai;
+ int port0;
+{
+ u_short port = port0 & 0xffff;
+ struct addrinfo sentinel;
+ struct hostent *hp;
+ struct addrinfo *top, *cur;
+ struct gai_afd *gai_afd;
+ int i, error = 0, h_error;
+ char *ap;
+
+ top = NULL;
+ sentinel.ai_next = NULL;
+ cur = &sentinel;
+#if SU_HAVE_IN6
+ if (af == AF_UNSPEC) {
+ hp = getipnodebyname(hostname, AF_INET6,
+ AI_ADDRCONFIG|AI_ALL|AI_V4MAPPED, &h_error);
+ } else
+ hp = getipnodebyname(hostname, af, AI_ADDRCONFIG, &h_error);
+#else
+ hp = gethostbyname(hostname);
+ h_error = h_errno;
+#endif
+ if (hp == NULL) {
+ switch (h_error) {
+ case HOST_NOT_FOUND:
+ case NO_DATA:
+ error = EAI_NODATA;
+ break;
+ case TRY_AGAIN:
+ error = EAI_AGAIN;
+ break;
+ case NO_RECOVERY:
+ default:
+ error = EAI_FAIL;
+ break;
+ }
+ goto bad;
+ }
+
+ if ((hp->h_name == NULL) || (hp->h_name[0] == 0) ||
+ (hp->h_addr_list[0] == NULL))
+ ERR(EAI_FAIL);
+
+ for (i = 0; (ap = hp->h_addr_list[i]) != NULL; i++) {
+ switch (af) {
+#if SU_HAVE_IN6
+ case AF_INET6:
+ gai_afd = &gai_afdl[N_INET6];
+ break;
+#endif
+#ifndef INET6
+ default: /* AF_UNSPEC */
+#endif
+ case AF_INET:
+ gai_afd = &gai_afdl[N_INET];
+ break;
+#if SU_HAVE_IN6
+ default: /* AF_UNSPEC */
+ if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) {
+ ap += sizeof(struct in6_addr) -
+ sizeof(struct in_addr);
+ gai_afd = &gai_afdl[N_INET];
+ } else
+ gai_afd = &gai_afdl[N_INET6];
+ break;
+#endif
+ }
+#ifdef FAITH
+ if (translate && gai_afd->a_af == AF_INET) {
+ struct in6_addr *in6;
+
+ GET_AI(cur->ai_next, &gai_afdl[N_INET6], ap, port);
+ in6 = &((struct sockaddr_in6 *)cur->ai_next->ai_addr)->sin6_addr;
+ memcpy(&in6->s6_addr32[0], &faith_prefix,
+ sizeof(struct in6_addr) - sizeof(struct in_addr));
+ memcpy(&in6->s6_addr32[3], ap, sizeof(struct in_addr));
+ } else
+#endif /* FAITH */
+ GET_AI(cur->ai_next, gai_afd, ap, port);
+ if (cur == &sentinel) {
+ top = cur->ai_next;
+ GET_CANONNAME(top, hp->h_name);
+ }
+ cur = cur->ai_next;
+ }
+#if SU_HAVE_IN6
+ freehostent(hp);
+#endif
+ *res = top;
+ return SUCCESS;
+ free:
+ if (top)
+ freeaddrinfo(top);
+#if SU_HAVE_IN6
+ if (hp)
+ freehostent(hp);
+#endif
+ bad:
+ *res = NULL;
+ return error;
+}
+
+/*
+ * Issues to be discussed:
+ * - Thread safe-ness must be checked
+ * - Return values. There seems to be no standard for return value (RFC2133)
+ * but INRIA implementation returns EAI_xxx defined for getaddrinfo().
+ */
+
+#define SUCCESS 0
+#define YES 1
+#define NO 0
+
+static struct gni_afd {
+ int a_af;
+ int a_addrlen;
+ int a_socklen;
+ int a_off;
+} gni_afdl [] = {
+#if SU_HAVE_IN6
+ {PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6),
+ offsetof(struct sockaddr_in6, sin6_addr)},
+#endif
+ {PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in),
+ offsetof(struct sockaddr_in, sin_addr)},
+ {0, 0, 0},
+};
+
+struct gni_sockinet {
+ u_char si_len;
+ u_char si_family;
+ u_short si_port;
+};
+
+#define ENI_NOSOCKET EAI_FAIL
+#define ENI_NOSERVNAME EAI_NONAME
+#define ENI_NOHOSTNAME EAI_NONAME
+#define ENI_MEMORY EAI_MEMORY
+#define ENI_SYSTEM EAI_SYSTEM
+#define ENI_FAMILY EAI_FAMILY
+#define ENI_SALEN EAI_MEMORY
+
+static
+int
+getnameinfo(sa, salen, host, hostlen, serv, servlen, flags)
+ const struct sockaddr *sa;
+ size_t salen;
+ char *host;
+ size_t hostlen;
+ char *serv;
+ size_t servlen;
+ int flags;
+{
+ struct gni_afd *gni_afd;
+ struct servent *sp;
+ struct hostent *hp;
+ u_short port;
+ int family, len, i;
+ char *addr, *p;
+ u_long v4a;
+ u_char pfx;
+ int h_error;
+ char numserv[512];
+ char numaddr[512];
+
+ if (sa == NULL)
+ return ENI_NOSOCKET;
+
+#if SU_HAVE_SOCKADDR_SA_LEN
+ len = sa->sa_len;
+ if (len != salen) return ENI_SALEN;
+#else
+ len = salen;
+#endif
+
+ family = sa->sa_family;
+ for (i = 0; gni_afdl[i].a_af; i++)
+ if (gni_afdl[i].a_af == family) {
+ gni_afd = &gni_afdl[i];
+ goto found;
+ }
+ return ENI_FAMILY;
+
+ found:
+ if (len != gni_afd->a_socklen) return ENI_SALEN;
+
+ port = ((struct gni_sockinet *)sa)->si_port; /* network byte order */
+ addr = (char *)sa + gni_afd->a_off;
+
+ if (serv == NULL || servlen == 0) {
+ /* what we should do? */
+ } else if (flags & NI_NUMERICSERV) {
+ snprintf(numserv, sizeof(numserv), "%d", ntohs(port));
+ if (strlen(numserv) > servlen)
+ return ENI_MEMORY;
+ strcpy(serv, numserv);
+ } else {
+ sp = getservbyport(port, (flags & NI_DGRAM) ? "udp" : "tcp");
+ if (sp) {
+ if (strlen(sp->s_name) > servlen)
+ return ENI_MEMORY;
+ strcpy(serv, sp->s_name);
+ } else
+ return ENI_NOSERVNAME;
+ }
+
+ switch (sa->sa_family) {
+ case AF_INET:
+ v4a = ((struct sockaddr_in *)sa)->sin_addr.s_addr;
+ if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
+ flags |= NI_NUMERICHOST;
+ v4a >>= IN_CLASSA_NSHIFT;
+ if (v4a == 0 || v4a == IN_LOOPBACKNET)
+ flags |= NI_NUMERICHOST;
+ break;
+#if SU_HAVE_IN6
+ case AF_INET6:
+ pfx = ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr8[0];
+ if (pfx == 0 || pfx == 0xfe || pfx == 0xff)
+ flags |= NI_NUMERICHOST;
+ break;
+#endif
+ }
+ if (host == NULL || hostlen == 0) {
+ /* what should we do? */
+ } else if (flags & NI_NUMERICHOST) {
+ if (inet_ntop(gni_afd->a_af, addr, numaddr, sizeof(numaddr))
+ == NULL)
+ return ENI_SYSTEM;
+ if (strlen(numaddr) > hostlen)
+ return ENI_MEMORY;
+ strcpy(host, numaddr);
+ } else {
+#if SU_HAVE_IN6
+ hp = getipnodebyaddr(addr, gni_afd->a_addrlen, gni_afd->a_af, &h_error);
+#else
+ hp = gethostbyaddr(addr, gni_afd->a_addrlen, gni_afd->a_af);
+ h_error = h_errno;
+#endif
+
+ if (hp) {
+ if (flags & NI_NOFQDN) {
+ p = strchr(hp->h_name, '.');
+ if (p) *p = '\0';
+ }
+ if (strlen(hp->h_name) > hostlen) {
+#if SU_HAVE_IN6
+ freehostent(hp);
+#endif
+ return ENI_MEMORY;
+ }
+ strcpy(host, hp->h_name);
+#if SU_HAVE_IN6
+ freehostent(hp);
+#endif
+ } else {
+ if (flags & NI_NAMEREQD)
+ return ENI_NOHOSTNAME;
+ if (inet_ntop(gni_afd->a_af, addr, numaddr, sizeof(numaddr))
+ == NULL)
+ return ENI_NOHOSTNAME;
+ if (strlen(numaddr) > hostlen)
+ return ENI_MEMORY;
+ strcpy(host, numaddr);
+ }
+ }
+ return SUCCESS;
+}
+
+#endif /* !HAVE_GETNAMEINFO */
+
+#if !HAVE_FREEADDRINFO
+static
+void
+freeaddrinfo(ai)
+ struct addrinfo *ai;
+{
+ struct addrinfo *next;
+
+ do {
+ next = ai->ai_next;
+ if (ai->ai_canonname)
+ free(ai->ai_canonname);
+ /* no need to free(ai->ai_addr) */
+ free(ai);
+ } while ((ai = next) != NULL);
+}
+#endif
+
+#if !HAVE_GAI_STRERROR
+static
+char *
+gai_strerror(ecode)
+ int ecode;
+{
+ switch (ecode) {
+ case 0:
+ return "success.";
+#if defined(EAI_ADDRFAMILY)
+ case EAI_ADDRFAMILY:
+ return "address family for hostname not supported.";
+#endif
+#if defined(EAI_AGAIN)
+ case EAI_AGAIN:
+ return "temporary failure in name resolution.";
+#endif
+#if defined(EAI_BADFLAGS)
+ case EAI_BADFLAGS:
+ return "invalid value for ai_flags.";
+#endif
+#if defined(EAI_FAIL)
+ case EAI_FAIL:
+ return "non-recoverable failure in name resolution.";
+#endif
+#if defined(EAI_FAMILY)
+ case EAI_FAMILY:
+ return "ai_family not supported.";
+#endif
+#if defined(EAI_MEMORY)
+ case EAI_MEMORY:
+ return "memory allocation failure.";
+#endif
+#if defined(EAI_NODATA)
+ case EAI_NODATA:
+ return "no address associated with hostname.";
+#endif
+#if defined(EAI_NONAME)
+ case EAI_NONAME:
+ return "hostname nor servname provided, or not known.";
+#endif
+#if defined(EAI_SERVICE)
+ case EAI_SERVICE:
+ return "servname not supported for ai_socktype.";
+#endif
+#if defined(EAI_SOCKTYPE)
+ case EAI_SOCKTYPE:
+ return "ai_socktype not supported.";
+#endif
+#if defined(EAI_SYSTEM)
+ case EAI_SYSTEM:
+ return "system error returned in errno.";
+#endif
+#if defined(EAI_BADHINTS)
+ case EAI_BADHINTS:
+ return "invalid value for hints.";
+#endif
+#if defined(EAI_PROTOCOL)
+ case EAI_PROTOCOL:
+ return "resolved protocol is unknown.";
+#endif
+ default:
+ return "unknown error.";
+ }
+}
+#endif
+
+
+/** Translate address and service.
+ *
+ * This is a getaddrinfo() supporting SCTP and other exotic protocols.
+ */
+int su_getaddrinfo(char const *node, char const *service,
+ su_addrinfo_t const *hints,
+ su_addrinfo_t **res)
+{
+#if HAVE_SCTP
+ if (res && hints && hints->ai_protocol == IPPROTO_SCTP) {
+ su_addrinfo_t *ai, system_hints[1];
+ int retval, socktype;
+
+ socktype = hints->ai_socktype;
+
+ if (!(socktype == 0 ||
+ socktype == SOCK_SEQPACKET ||
+ socktype == SOCK_STREAM ||
+ socktype == SOCK_DGRAM))
+ return EAI_SOCKTYPE;
+
+ *system_hints = *hints;
+ system_hints->ai_protocol = IPPROTO_TCP;
+ system_hints->ai_socktype = SOCK_STREAM;
+
+ retval = getaddrinfo(node, service, system_hints, res);
+ if (retval)
+ return retval;
+
+ if (socktype == 0)
+ socktype = SOCK_STREAM;
+
+ for (ai = *res; ai; ai = ai->ai_next) {
+ ai->ai_protocol = IPPROTO_SCTP;
+ ai->ai_socktype = socktype;
+ }
+
+ return 0;
+ }
+#endif
+
+ return getaddrinfo(node, service, hints, res);
+}
+
+/** Free su_addrinfo_t structure allocated by su_getaddrinfo(). */
+void su_freeaddrinfo(su_addrinfo_t *res)
+{
+ freeaddrinfo(res);
+}
+
+/** Return string describing address translation error. */
+char const *su_gai_strerror(int errcode)
+{
+ return (char const *)gai_strerror(errcode);
+}
+
+/** Resolve socket address into hostname and service name.
+ *
+ * @note
+ * This function uses now @RFC2133 prototype. The @RFC3493 redefines the
+ * prototype as well as ai_addrlen to use socklen_t instead of size_t.
+ * If your application allocates more than 2 gigabytes for resolving the
+ * hostname, you probably lose.
+ */
+int
+su_getnameinfo(const su_sockaddr_t *su, size_t sulen,
+ char *return_host, size_t hostlen,
+ char *return_serv, size_t servlen,
+ int flags)
+{
+ return getnameinfo(&su->su_sa, (socklen_t)sulen,
+ return_host, (socklen_t)hostlen,
+ return_serv, (socklen_t)servlen,
+ flags);
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_alloc.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_alloc.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1583 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_alloc
+ * @CFILE su_alloc.c Home-based memory management.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>.
+ *
+ * @date Created: Thu Aug 19 01:12:25 1999 ppessi
+ */
+
+#include "config.h"
+
+/**@defgroup su_alloc Memory Management Tutorial
+ *
+ * This page gives a short overview of home-based memory management used
+ * with Sofia. Such home-based memory management is useful when a lot of
+ * memory blocks are allocated for given task. The allocations are done via
+ * the @e memory @e home, which keeps a reference to each block. When the
+ * memory home is then freed, it will free all blocks to which it has
+ * reference.
+ *
+ * Typically, there is a @e home @e object which contains a su_home_t
+ * structure in the beginning of the object (sort of inheritance from
+ * su_home_t):
+ * @code
+ * struct context {
+ * su_home_t ctx_home[1];
+ * other_t *ctx_stuff;
+ * ...
+ * }
+ * @endcode
+ *
+ * A new home memory pool can be created with su_home_new():
+ * @code
+ * struct context *ctx = su_home_new(sizeof (struct context));
+ * @endcode
+ *
+ * It is also possible to create a secondary memory pool that can be
+ * released separately:
+ *
+ * @code
+ * struct context *ctx = su_home_clone(tophome, sizeof (struct context));
+ * @endcode
+ *
+ * Note that the tophome has a reference to @a ctx structure; whenever
+ * tophome is freed, the @a ctx is also freed.
+ *
+ * You can also create an independent home object by passing NULL as @a
+ * tophome argument. This is identical to the call to su_home_new().
+ *
+ * The memory allocations using @a ctx proceed then as follows:
+ * @code
+ * zeroblock = su_zalloc(ctx->ctx_home, sizeof (*zeroblock));
+ * @endcode
+ *
+ * The home memory pool - the home object and all the memory blocks
+ * allocated using it - are freed when su_home_unref() is called:
+ *
+ * @code
+ * su_home_unref(ctx->ctx_home).
+ * @endcode
+ *
+ * @note For historical reasons, su_home_unref() is also known as
+ * su_home_zap().
+ *
+ * As you might have guessed, it is also possible to use reference counting
+ * with home objects. The function su_home_ref() increases the reference
+ * count, su_home_unref() decreases. A newly allocated home object has
+ * reference count of 1.
+ *
+ * @note Please note that while it is possible to create new references to
+ * secondary home objects which have a parent home, the secondary home
+ * objects will always be destroyed when the parent home is destroyed even
+ * if there are other references left to them.
+ *
+ * The memory blocks in a cloned home object are freed when the object with
+ * home itself is freed:
+ * @code
+ * su_free(tophome, ctx);
+ * @endcode
+ *
+ * @note
+ *
+ * The su_home_destroy() function is deprecated as it does not free the home
+ * object itself.
+ *
+ * The function su_home_init() initializes a home object with infinite
+ * reference count. It must be deinitialized with su_home_deinit().
+ *
+ * @section su_home_destructor_usage Destructors
+ *
+ * It is possible to give a destructor function to a home object. The
+ * destructor releases other resources associated with the home object
+ * besides memory. The destructor function will be called when the reference
+ * count of home reaches zero (upon calling su_home_unref()) or the home
+ * object is otherwise deinitialized (calling su_home_deinit() on
+ * objects allocated from stack).
+ *
+ * @section su_home_move_example Combining Allocations
+ *
+ * In some cases, an operation that makes multiple memory allocations may
+ * fail, making those allocations redundant. If the allocations are made
+ * through a temporary home, they can be conveniently freed by calling
+ * su_home_deinit(), for instance. If, however, the operation is successful,
+ * and one wants to keep the allocations, the allocations can be combined
+ * into an existing home with su_home_move(). For example,
+ * @code
+ * int example(su_home_t *home, ...)
+ * {
+ * su_home_t temphome[1] = { SU_HOME_INIT(temphome) };
+ *
+ * ... do lot of allocations with temphome ...
+ *
+ * if (success)
+ * su_home_move(home, temphome);
+ * su_home_deinit(temphome);
+ *
+ * return success;
+ * }
+ * @endcode
+ *
+ * Note that the @a temphome is deinitialized in every case, but when
+ * operation is successful, the allocations are moved from @a temphome to @a
+ * home.
+ *
+ * @section su_alloc_threadsafe Threadsafe Operation
+ *
+ * If multiple threads need to access same home object, it must be marked as
+ * @c threadsafe by calling su_home_threadsafe() with the home pointer as
+ * argument. The threadsafeness is not inherited by clones.
+ *
+ * The threadsafe home objects can be locked and unlocked with
+ * su_home_mutex_lock() and su_home_mutex_unlock().
+ *
+ * @section su_alloc_preloading Preloading a Memory Home
+ *
+ * In some situations there is quite heavy overhead when using the global
+ * heap allocator. The overhead caused by the large number of small
+ * allocations can be reduced by using su_home_preload(): it allocates or
+ * preloads some a memory to home to be used as a kind of private heap. The
+ * preloaded memory area is then used to satisfy small enough allocations.
+ * For instance, the SIP parser typically preloads some 2K of memory when it
+ * starts to parse the message.
+ *
+ * @section su_alloc_stack Using Stack
+ *
+ * In some situation, it is sensible to use memory allocated from stack for
+ * some operations. The su_home_auto() function can be used for that
+ * purpose. The memory area from stack is used to satisfy the allocations as
+ * far as possible; if it is not enough, allocation is made from heap.
+ *
+ * The word @e auto refers to the automatic scope; however, the home object
+ * initialized with su_home_auto() must be explicitly deinitialized with
+ * su_home_deinit() when the program exits the scope where the stack frame
+ * used in su_home_auto() was allocate.
+ *
+ */
+
+#include <sofia-sip/su_config.h>
+#include "sofia-sip/su_alloc.h"
+#include "sofia-sip/su_alloc_stat.h"
+#include "sofia-sip/su_errno.h"
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <memory.h>
+#include <limits.h>
+
+#include <assert.h>
+
+void (*su_home_locker)(void *mutex);
+void (*su_home_unlocker)(void *mutex);
+
+void (*su_home_mutex_locker)(void *mutex);
+void (*su_home_mutex_unlocker)(void *mutex);
+
+#define MEMLOCK(h) \
+ (((h) && (h)->suh_lock ? su_home_locker((h)->suh_lock) : (void)0), (h)->suh_blocks)
+#define UNLOCK(h) (((h) && (h)->suh_lock ? su_home_unlocker((h)->suh_lock) : (void)0), NULL)
+
+#ifdef NDEBUG
+#define MEMCHECK 0
+#define MEMCHECK_EXTRA 0
+#elif !defined(MEMCHECK)
+/* Default settings for valgrinding */
+#define MEMCHECK 1
+#define MEMCHECK_EXTRA 0
+#elif !defined(MEMCHECK_EXTRA)
+#define MEMCHECK_EXTRA sizeof (size_t)
+#endif
+
+enum {
+ SUB_N = 31, /**< Initial size */
+ SUB_N_AUTO = 7, /**< Initial size for autohome */
+ SUB_P = 29 /**< Secondary probe.
+ * Secondary probe must be relative prime
+ * with all sub_n values */
+};
+
+#define ALIGNMENT (8)
+#define ALIGN(n) (size_t)(((n) + (ALIGNMENT - 1)) & (size_t)~(ALIGNMENT - 1))
+#define SIZEBITS (sizeof (size_t) * 8 - 1)
+
+typedef struct {
+ size_t sua_size:SIZEBITS; /**< Size of the block */
+ unsigned sua_home:1; /**< Is this another home? */
+ unsigned :0;
+ void *sua_data; /**< Data pointer */
+} su_alloc_t;
+
+struct su_block_s {
+ su_home_t *sub_parent; /**< Parent home */
+ char *sub_preload; /**< Preload area */
+ su_home_stat_t *sub_stats; /**< Statistics.. */
+ void (*sub_destructor)(void *); /**< Destructor function */
+ size_t sub_ref; /**< Reference count */
+#define REF_MAX SIZE_MAX
+ size_t sub_used; /**< Number of blocks allocated */
+ size_t sub_n; /**< Size of hash table */
+
+ unsigned sub_prsize:16; /**< Preload size */
+ unsigned sub_prused:16; /**< Used from preload */
+ unsigned sub_auto:1; /**< struct su_block_s is from stack! */
+ unsigned sub_preauto:1; /**< Preload is from stack! */
+ unsigned sub_auto_all:1; /**< Everything is from stack! */
+ unsigned :0;
+
+ su_alloc_t sub_nodes[SUB_N]; /**< Pointers to data/lower blocks */
+};
+
+static void su_home_check_blocks(su_block_t const *b);
+
+static void su_home_stats_alloc(su_block_t *, void *p, void *preload,
+ size_t size, int zero);
+static void su_home_stats_free(su_block_t *sub, void *p, void *preload,
+ size_t size);
+
+static void _su_home_deinit(su_home_t *home);
+
+#define SU_ALLOC_STATS 1
+
+#if SU_ALLOC_STATS
+size_t count_su_block_find, count_su_block_find_loop;
+size_t size_su_block_find, used_su_block_find;
+size_t max_size_su_block_find, max_used_su_block_find;
+size_t su_block_find_collision, su_block_find_collision_used,
+ su_block_find_collision_size;
+#endif
+
+static inline su_alloc_t *su_block_find(su_block_t *b, void const *p)
+{
+ size_t h, h0, probe;
+
+#if SU_ALLOC_STATS
+ size_t collision = 0;
+
+ count_su_block_find++;
+ size_su_block_find += b->sub_n;
+ used_su_block_find += b->sub_used;
+ if (b->sub_n > max_size_su_block_find)
+ max_size_su_block_find = b->sub_n;
+ if (b->sub_used > max_used_su_block_find)
+ max_used_su_block_find = b->sub_used;
+#endif
+
+ assert(p != NULL);
+
+ h = h0 = (size_t)((uintptr_t)p % b->sub_n);
+
+ probe = (b->sub_n > SUB_P) ? SUB_P : 1;
+
+ do {
+ if (b->sub_nodes[h].sua_data == p)
+ return &b->sub_nodes[h];
+ h += probe;
+ if (h >= b->sub_n)
+ h -= b->sub_n;
+#if SU_ALLOC_STATS
+ if (++collision > su_block_find_collision)
+ su_block_find_collision = collision,
+ su_block_find_collision_used = b->sub_used,
+ su_block_find_collision_size = b->sub_n;
+ count_su_block_find_loop++;
+#endif
+ } while (h != h0);
+
+ return NULL;
+}
+
+static inline su_alloc_t *su_block_add(su_block_t *b, void *p)
+{
+ size_t h, probe;
+
+ assert(p != NULL);
+
+ h = (size_t)((uintptr_t)p % b->sub_n);
+
+ probe = (b->sub_n > SUB_P) ? SUB_P : 1;
+
+ while (b->sub_nodes[h].sua_data) {
+ h += probe;
+ if (h >= b->sub_n)
+ h -= b->sub_n;
+ }
+
+ b->sub_used++;
+ b->sub_nodes[h].sua_data = p;
+
+ return &b->sub_nodes[h];
+}
+
+static inline int su_is_preloaded(su_block_t const *sub, char *data)
+{
+ return
+ sub->sub_preload &&
+ sub->sub_preload <= data &&
+ sub->sub_preload + sub->sub_prsize > data;
+}
+
+static inline int su_alloc_check(su_block_t const *sub, su_alloc_t const *sua)
+{
+#if MEMCHECK_EXTRA
+ size_t size, term;
+ assert(sua);
+ if (sua) {
+ size = sua->sua_size;
+ memcpy(&term, (char *)sua->sua_data + size, sizeof (term));
+ assert(size - term == 0);
+ return size - term == 0;
+ }
+ else
+ return 0;
+#endif
+ return sua != NULL;
+}
+
+/** Allocate the block hash table.
+ *
+ * The function su_hash_alloc() allocates a block hash table of @a n
+ * elements.
+ *
+ * @param home pointer to home object
+ * @param n number of buckets in hash table
+ *
+ * @return
+ * This function returns a pointer to the allocated hash table or
+ * NULL if an error occurred.
+ */
+static inline su_block_t *su_hash_alloc(size_t n)
+{
+ su_block_t *b = calloc(1, offsetof(su_block_t, sub_nodes[n]));
+
+ if (b)
+ b->sub_n = n;
+
+ return b;
+}
+
+enum sub_zero { do_malloc, do_calloc, do_clone };
+
+/** Allocate a memory block.
+ *
+ * Precondition: locked home
+ *
+ * @param home home to allocate
+ * @param sub block structure used to allocate
+ * @param size
+ * @param zero if true, zero allocated block;
+ * if > 1, allocate a subhome
+ *
+ */
+static
+void *sub_alloc(su_home_t *home,
+ su_block_t *sub,
+ size_t size,
+ enum sub_zero zero)
+{
+ void *data, *preload = NULL;
+
+ assert (size < (1UL << SIZEBITS));
+
+ if (sub == NULL || 3 * sub->sub_used > 2 * sub->sub_n) {
+ /* Resize the hash table */
+ size_t i, n, n2, used;
+ su_block_t *b2;
+
+ if (sub)
+ n = home->suh_blocks->sub_n, n2 = 4 * n + 3, used = sub->sub_used;
+ else
+ n = 0, n2 = SUB_N, used = 0;
+
+#if 0
+ printf("su_alloc(home = %p): realloc block hash of size %d\n", home, n2);
+#endif
+
+ if (!(b2 = su_hash_alloc(n2)))
+ return NULL;
+
+ for (i = 0; i < n; i++) {
+ if (sub->sub_nodes[i].sua_data)
+ su_block_add(b2, sub->sub_nodes[i].sua_data)[0] = sub->sub_nodes[i];
+ }
+
+ if (sub) {
+ b2->sub_parent = sub->sub_parent;
+ b2->sub_ref = sub->sub_ref;
+ b2->sub_preload = sub->sub_preload;
+ b2->sub_prsize = sub->sub_prsize;
+ b2->sub_prused = sub->sub_prused;
+ b2->sub_preauto = sub->sub_preauto;
+ b2->sub_destructor = sub->sub_destructor;
+ /* auto_all is not copied! */
+ b2->sub_stats = sub->sub_stats;
+ }
+
+ home->suh_blocks = b2;
+
+ if (sub && !sub->sub_auto)
+ free(sub);
+ sub = b2;
+ }
+
+ if (size && sub && zero < do_clone &&
+ sub->sub_preload && size <= sub->sub_prsize) {
+ /* Use preloaded memory */
+ size_t prused = sub->sub_prused + size + MEMCHECK_EXTRA;
+ prused = ALIGN(prused);
+ if (prused <= sub->sub_prsize) {
+ preload = (char *)sub->sub_preload + sub->sub_prused;
+ sub->sub_prused = (unsigned)prused;
+ }
+ }
+
+ if (preload && zero)
+ data = memset(preload, 0, size);
+ else if (preload)
+ data = preload;
+ else if (zero)
+ data = calloc(1, size + MEMCHECK_EXTRA);
+ else
+ data = malloc(size + MEMCHECK_EXTRA);
+
+ if (data) {
+ su_alloc_t *sua;
+
+#if MEMCHECK_EXTRA
+ size_t term = 0 - size;
+ memcpy((char *)data + size, &term, sizeof (term));
+#endif
+
+ if (!preload)
+ sub->sub_auto_all = 0;
+
+ if (zero == do_clone) {
+ /* Prepare cloned home */
+ su_home_t *subhome = data;
+
+ assert(preload == 0);
+
+ subhome->suh_blocks = su_hash_alloc(SUB_N);
+ if (!subhome->suh_blocks)
+ return (void)free(data), NULL;
+
+ subhome->suh_size = (unsigned)size;
+ subhome->suh_blocks->sub_parent = home;
+ subhome->suh_blocks->sub_ref = 1;
+ }
+
+ /* OK, add the block to the hash table. */
+
+ sua = su_block_add(sub, data); assert(sua);
+ sua->sua_size = size;
+ sua->sua_home = zero > 1;
+
+ if (sub->sub_stats)
+ su_home_stats_alloc(sub, data, preload, size, zero);
+ }
+
+ return data;
+}
+
+/**Create a new su_home_t object.
+ *
+ * Create a home object used to collect multiple memory allocations under
+ * one handle. The memory allocations made using this home object is freed
+ * either when this home is destroyed.
+ *
+ * The maximum @a size of a home object is INT_MAX (2 gigabytes).
+ *
+ * @param size size of home object
+ *
+ * The memory home object allocated with su_home_new() can be reclaimed with
+ * su_home_unref().
+ *
+ * @return
+ * This function returns a pointer to an su_home_t object, or NULL upon
+ * an error.
+ */
+void *su_home_new(isize_t size)
+{
+ su_home_t *home;
+
+ assert(size >= sizeof (*home));
+
+ if (size < sizeof (*home))
+ return (errno = EINVAL), NULL;
+ else if (size > INT_MAX)
+ return (errno = ENOMEM), NULL;
+
+ home = calloc(1, size);
+ if (home) {
+ home->suh_size = (int)size;
+ home->suh_blocks = su_hash_alloc(SUB_N);
+ if (home->suh_blocks)
+ home->suh_blocks->sub_ref = 1;
+ else
+ free(home), home = NULL;
+ }
+
+ return home;
+}
+
+/** Create a new reference to a home object. */
+void *su_home_ref(su_home_t const *home)
+{
+ if (home) {
+ su_block_t *sub = MEMLOCK(home);
+
+ if (sub == NULL || sub->sub_ref == 0) {
+ assert(sub && sub->sub_ref != 0);
+ UNLOCK(home);
+ return NULL;
+ }
+
+ if (sub->sub_ref != REF_MAX)
+ sub->sub_ref++;
+ UNLOCK(home);
+ }
+ else
+ su_seterrno(EFAULT);
+
+ return (void *)home;
+}
+
+/** Set destructor function.
+ *
+ * The destructor function is called after the reference count of a
+ * #su_home_t object reaches zero or a home object is deinitialized, but
+ * before any of the memory areas within the home object are freed.
+ *
+ * @since New in @VERSION_1_12_4.
+ * Earlier versions had su_home_desctructor() (spelling).
+ */
+int su_home_destructor(su_home_t *home, void (*destructor)(void *))
+{
+ int retval = -1;
+
+ if (home) {
+ su_block_t *sub = MEMLOCK(home);
+ if (sub && sub->sub_destructor == NULL) {
+ sub->sub_destructor = destructor;
+ retval = 0;
+ }
+ UNLOCK(home);
+ }
+ else
+ su_seterrno(EFAULT);
+
+ return retval;
+}
+
+#undef su_home_desctructor
+
+/** Set destructor function.
+ *
+ * @deprecated The su_home_destructor() was added in @VERSION_1_12_4. The
+ * su_home_desctructor() is now defined as a macro expanding as
+ * su_home_destructor(). If you want to compile an application as binary
+ * compatible with earlier versions, you have to define su_home_desctructor
+ * as itself, e.g.,
+ * @code
+ * #define su_home_desctructor su_home_desctructor
+ * #include <sofia-sip/su_alloc.h>
+ * @endcode
+ */
+int su_home_desctructor(su_home_t *home, void (*destructor)(void *))
+{
+ return su_home_destructor(home, destructor);
+}
+
+/**Unreference a su_home_t object.
+ *
+ * The function su_home_unref() decrements the reference count on a home
+ * object and destroys and frees it and the memory allocations using it.
+ *
+ * @param home memory pool object to be unreferences
+ *
+ * The function return values is
+ *
+ * @retval 1 if object was freed
+ * @retval 0 if object is still alive
+ */
+int su_home_unref(su_home_t *home)
+{
+ su_block_t *sub;
+
+ if (home == NULL)
+ return 0;
+
+ sub = MEMLOCK(home);
+
+ if (sub == NULL) {
+ /* Xyzzy */
+ return 0;
+ }
+ else if (sub->sub_ref == REF_MAX) {
+ UNLOCK(home);
+ return 0;
+ }
+ else if (--sub->sub_ref > 0) {
+ UNLOCK(home);
+ return 0;
+ }
+ else if (sub->sub_parent) {
+ su_home_t *parent = sub->sub_parent;
+ UNLOCK(home);
+ su_free(parent, home);
+ return 1;
+ }
+ else {
+ _su_home_deinit(home);
+ free(home);
+ /* UNLOCK(home); */
+ return 1;
+ }
+}
+
+/** Return reference count of home. */
+size_t su_home_refcount(su_home_t *home)
+{
+ size_t count = 0;
+
+ if (home) {
+ su_block_t *sub = MEMLOCK(home);
+
+ if (sub)
+ count = sub->sub_ref;
+
+ UNLOCK(home);
+ }
+
+ return count;
+}
+
+/**Clone a su_home_t object.
+ *
+ * Clone a secondary home object used to collect multiple memoryf
+ * allocations under one handle. The memory is freed either when the cloned
+ * home is destroyed or when the parent home is destroyed.
+ *
+ * An independent
+ * home object is created if NULL is passed as @a parent argument.
+ *
+ * @param parent a parent object (may be NULL)
+ * @param size size of home object
+ *
+ * The memory home object allocated with su_home_clone() can be freed with
+ * su_home_unref().
+ *
+ * @return
+ * This function returns a pointer to an su_home_t object, or NULL upon
+ * an error.
+ */
+void *su_home_clone(su_home_t *parent, isize_t size)
+{
+ su_home_t *home;
+
+ assert(size >= sizeof (*home));
+
+ if (size < sizeof (*home))
+ return (void)(errno = EINVAL), NULL;
+ else if (size > INT_MAX)
+ return (void)(errno = ENOMEM), NULL;
+
+ if (parent) {
+ su_block_t *sub = MEMLOCK(parent);
+ home = sub_alloc(parent, sub, size, 2);
+ UNLOCK(parent);
+ }
+ else {
+ home = su_home_new(size);
+ }
+
+ return home;
+}
+
+/** Return true if home is a clone. */
+int su_home_has_parent(su_home_t const *home)
+{
+ return home && !home->suh_lock &&
+ home->suh_blocks && home->suh_blocks->sub_parent;
+}
+
+/** Allocate a memory block.
+ *
+ * The function su_alloc() allocates a memory block of a given @a size.
+ *
+ * If @a home is NULL, this function behaves exactly like malloc().
+ *
+ * @param home pointer to home object
+ * @param size size of the memory block to be allocated
+ *
+ * @return
+ * This function returns a pointer to the allocated memory block or
+ * NULL if an error occurred.
+ */
+void *su_alloc(su_home_t *home, isize_t size)
+{
+ void *data;
+
+ if (home) {
+ data = sub_alloc(home, MEMLOCK(home), size, 0);
+ UNLOCK(home);
+ }
+ else
+ data = malloc(size);
+
+ return data;
+}
+
+/**Free a memory block.
+ *
+ * The function su_free() frees a single memory block. The @a home must be
+ * the owner of the memory block (usually the memory home used to allocate
+ * the memory block, or NULL if no home was used).
+ *
+ * @param home pointer to home object
+ * @param data pointer to the memory block to be freed
+ */
+void su_free(su_home_t *home, void *data)
+{
+ if (home && data) {
+ su_alloc_t *allocation;
+ su_block_t *sub = MEMLOCK(home);
+
+ assert(sub);
+ allocation = su_block_find(sub, data);
+ assert(allocation);
+
+ if (su_alloc_check(sub, allocation)) {
+ void *preloaded = NULL;
+
+ /* Is this preloaded data? */
+ if (su_is_preloaded(sub, data))
+ preloaded = data;
+
+ if (sub->sub_stats)
+ su_home_stats_free(sub, data, preloaded, allocation->sua_size);
+
+ if (allocation->sua_home) {
+ su_home_t *subhome = data;
+ su_block_t *sub = MEMLOCK(subhome);
+
+ assert(sub->sub_ref != REF_MAX);
+ /* assert(sub->sub_ref > 0); */
+
+ sub->sub_ref = 0; /* Zap all references */
+
+ _su_home_deinit(subhome);
+ }
+
+#if MEMCHECK != 0
+ memset(data, 0xaa, allocation->sua_size);
+#endif
+
+ memset(allocation, 0, sizeof (*allocation));
+ sub->sub_used--;
+
+ if (preloaded)
+ data = NULL;
+ }
+
+ UNLOCK(home);
+ }
+
+ free(data);
+}
+
+/** Check home consistency.
+ *
+ * The function su_home_check() ensures that the home structure and all
+ * memory blocks allocated through it are consistent. It can be used to
+ * catch memory allocation and usage errors.
+ *
+ * @param home Pointer to a memory home.
+ */
+void su_home_check(su_home_t const *home)
+{
+#if MEMCHECK != 0
+ su_block_t const *b = MEMLOCK(home);
+
+ su_home_check_blocks(b);
+
+ UNLOCK(home);
+#endif
+}
+
+/** Check home blocks. */
+static
+void su_home_check_blocks(su_block_t const *b)
+{
+#if MEMCHECK != 0
+ if (b) {
+ size_t i, used;
+ assert(b->sub_used <= b->sub_n);
+
+ for (i = 0, used = 0; i < b->sub_n; i++)
+ if (b->sub_nodes[i].sua_data) {
+ su_alloc_check(b, &b->sub_nodes[i]), used++;
+ if (b->sub_nodes[i].sua_home)
+ su_home_check((su_home_t *)b->sub_nodes[i].sua_data);
+ }
+
+ assert(used == b->sub_used);
+ }
+#endif
+}
+
+/**
+ * Create an su_home_t object.
+ *
+ * The function su_home_create() creates a home object. A home object is
+ * used to collect multiple memory allocations, so that they all can be
+ * freed by calling su_home_unref().
+ *
+ * @return This function returns a pointer to an @c su_home_t object, or @c
+ * NULL upon an error.
+ */
+su_home_t *su_home_create(void)
+{
+ return su_home_new(sizeof(su_home_t));
+}
+
+/** Deinitialize a home object
+ *
+ * The function su_home_destroy() frees all memory blocks associated with a
+ * home object. Note that the home object is not freed.
+ *
+ * @param home pointer to a home object
+ *
+ * @deprecated
+ * su_home_destroy() is included for backwards compatibility only. Use
+ * su_home_unref() instead of su_home_destroy().
+ */
+void su_home_destroy(su_home_t *home)
+{
+ su_home_deinit(home);
+ /* XXX - home itself is not destroyed */
+}
+
+/** Initialize an su_home_t struct.
+ *
+ * The function su_home_init() initializes an su_home_t structure. It can be
+ * used when the home structure is allocated from stack.
+ *
+ * @param home pointer to home object
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error.
+ *
+ * @sa SU_HOME_INIT(), su_home_deinit(), su_home_new(), su_home_clone()
+ */
+int su_home_init(su_home_t *home)
+{
+ if (home == NULL)
+ return -1;
+
+ home->suh_blocks = su_hash_alloc(SUB_N);
+
+ return 0;
+}
+
+/** Internal deinitialization */
+static
+void _su_home_deinit(su_home_t *home)
+{
+ if (home->suh_blocks) {
+ size_t i;
+ su_block_t *b;
+
+ if (home->suh_blocks->sub_destructor) {
+ void (*destructor)(void *) = home->suh_blocks->sub_destructor;
+ home->suh_blocks->sub_destructor = NULL;
+ destructor(home);
+ }
+
+ b = home->suh_blocks;
+
+ su_home_check_blocks(b);
+
+ for (i = 0; i < b->sub_n; i++) {
+ if (b->sub_nodes[i].sua_data) {
+ if (b->sub_nodes[i].sua_home) {
+ su_home_t *subhome = b->sub_nodes[i].sua_data;
+ su_block_t *subb = MEMLOCK(subhome);
+
+ assert(subb); assert(subb->sub_ref >= 1);
+#if 0
+ if (subb->sub_ref > 0)
+ SU_DEBUG_7(("su_home_unref: subhome %p with destructor %p has still %u refs\n",
+ subhome, subb->sub_destructor, subb->sub_ref));
+#endif
+ subb->sub_ref = 0; /* zap them all */
+ _su_home_deinit(subhome);
+ }
+ else if (su_is_preloaded(b, b->sub_nodes[i].sua_data))
+ continue;
+ free(b->sub_nodes[i].sua_data);
+ }
+ }
+
+ if (b->sub_preload && !b->sub_preauto)
+ free(b->sub_preload);
+ if (b->sub_stats)
+ free(b->sub_stats);
+ if (!b->sub_auto)
+ free(b);
+
+ home->suh_blocks = NULL;
+ }
+
+ home->suh_lock = NULL;
+}
+
+/** Free memory blocks allocated through home.
+ *
+ * The function @c su_home_deinit() frees the memory blocks associated with
+ * the home object allocated otherwise. It does not free the home object
+ * itself. Use su_home_unref() to free the home object.
+ *
+ * @param home pointer to home object
+ *
+ * @sa su_home_init()
+ */
+void su_home_deinit(su_home_t *home)
+{
+ if (MEMLOCK(home)) {
+ assert(home->suh_blocks && home->suh_blocks->sub_ref == 0);
+ _su_home_deinit(home);
+ /* UNLOCK(home); */
+ }
+}
+
+/**Move allocations from a su_home_t object to another.
+ *
+ * The function su_home_move() moves allocations made through the @a src
+ * home object under the @a dst home object. It is handy, for example, if an
+ * operation allocates some number of blocks that should be freed upon an
+ * error. It uses a temporary home and moves the blocks from temporary to a
+ * proper home when successful, but frees the temporary home upon an error.
+ *
+ * If @a src has destructor, it is called before starting to move.
+ *
+ * @param dst destination home
+ * @param src source home
+ *
+ * @retval 0 if succesful
+ * @retval -1 upon an error
+ */
+int su_home_move(su_home_t *dst, su_home_t *src)
+{
+ size_t i, n, n2, used;
+ su_block_t *s, *d, *d2;
+
+ if (src == NULL || dst == src)
+ return 0;
+
+ if (dst) {
+ s = MEMLOCK(src); d = MEMLOCK(dst);
+
+ if (s && s->sub_n) {
+
+ if (s->sub_destructor) {
+ void (*destructor)(void *) = s->sub_destructor;
+ s->sub_destructor = NULL;
+ destructor(src);
+ }
+
+ if (d)
+ used = s->sub_used + d->sub_used;
+ else
+ used = s->sub_used;
+
+ if ((used && d == NULL) || 3 * used > 2 * d->sub_n) {
+ if (d)
+ for (n = n2 = d->sub_n; 3 * used > 2 * n2; n2 = 4 * n2 + 3)
+ ;
+ else
+ n = 0, n2 = s->sub_n;
+
+ if (!(d2 = su_hash_alloc(n2))) {
+ UNLOCK(dst); UNLOCK(src);
+ return -1;
+ }
+
+ dst->suh_blocks = d2;
+
+ for (i = 0; i < n; i++)
+ if (d->sub_nodes[i].sua_data)
+ su_block_add(d2, d->sub_nodes[i].sua_data)[0] = d->sub_nodes[i];
+
+ if (d) {
+ d2->sub_parent = d->sub_parent;
+ d2->sub_ref = d->sub_ref;
+ d2->sub_preload = d->sub_preload;
+ d2->sub_prsize = d->sub_prsize;
+ d2->sub_prused = d->sub_prused;
+ d2->sub_preauto = d->sub_preauto;
+ d2->sub_stats = d->sub_stats;
+ }
+
+ if (d && !d->sub_auto)
+ free(d);
+
+ d = d2;
+ }
+
+ if ((n = s->sub_n)) {
+ for (i = 0; i < n; i++)
+ if (s->sub_nodes[i].sua_data) {
+ su_block_add(d, s->sub_nodes[i].sua_data)[0] = s->sub_nodes[i];
+ }
+
+ s->sub_used = 0;
+
+ memset(s->sub_nodes, 0, n * sizeof (s->sub_nodes[0]));
+ }
+
+ if (s->sub_stats) {
+ }
+ }
+
+ UNLOCK(dst); UNLOCK(src);
+ }
+ else {
+ s = MEMLOCK(src);
+
+ if (s && s->sub_used) {
+ s->sub_used = 0;
+ memset(s->sub_nodes, 0, s->sub_n * sizeof (s->sub_nodes[0]));
+ }
+
+ UNLOCK(src);
+ }
+
+ return 0;
+}
+
+/** Preload a memory home.
+ *
+ * The function su_home_preload() preloads a memory home.
+ */
+void su_home_preload(su_home_t *home, isize_t n, isize_t isize)
+{
+ su_block_t *sub;
+
+ if (home == NULL)
+ return;
+
+ if (home->suh_blocks == NULL)
+ su_home_init(home);
+
+ sub = MEMLOCK(home);
+ if (!sub->sub_preload) {
+ size_t size;
+ void *preload;
+
+ size = n * ALIGN(isize);
+ if (size > 65535) /* We have 16 bits... */
+ size = 65535 & (ALIGNMENT - 1);
+
+ preload = malloc(size);
+
+ home->suh_blocks->sub_preload = preload;
+ home->suh_blocks->sub_prsize = (unsigned)size;
+ }
+ UNLOCK(home);
+}
+
+/** Preload a memory home from stack.
+ *
+ * The function su_home_auto() initalizes a memory home using an area
+ * allocated from stack. Poor mans alloca().
+ */
+su_home_t *su_home_auto(void *area, isize_t size)
+{
+ su_home_t *home;
+ su_block_t *sub;
+ size_t homesize = ALIGN(sizeof *home);
+ size_t subsize = ALIGN(offsetof(su_block_t, sub_nodes[SUB_N_AUTO]));
+ size_t prepsize;
+
+ char *p = area;
+
+ prepsize = homesize + subsize + (ALIGN((intptr_t)p) - (intptr_t)p);
+
+ if (area == NULL || size < prepsize)
+ return NULL;
+
+ if (size > INT_MAX)
+ size = INT_MAX;
+
+ home = memset(p, 0, homesize);
+ home->suh_size = (int)size;
+
+ sub = memset(p + homesize, 0, subsize);
+ home->suh_blocks = sub;
+
+ if (size > prepsize + 65535)
+ size = prepsize + 65535;
+
+ sub->sub_n = SUB_N_AUTO;
+ sub->sub_preload = p + prepsize;
+ sub->sub_prsize = (unsigned)(size - prepsize);
+ sub->sub_preauto = 1;
+ sub->sub_auto = 1;
+ sub->sub_auto_all = 1;
+
+ return home;
+}
+
+
+/** Reallocate a memory block.
+ *
+ * The function su_realloc() allocates a memory block of @a size bytes.
+ * It copies the old block contents to the new block and frees the old
+ * block.
+ *
+ * If @a home is NULL, this function behaves exactly like realloc().
+ *
+ * @param home pointer to memory pool object
+ * @param data pointer to old memory block
+ * @param size size of the memory block to be allocated
+ *
+ * @return
+ * This function returns a pointer to the allocated memory block or
+ * NULL if an error occurred.
+ */
+void *su_realloc(su_home_t *home, void *data, isize_t size)
+{
+ void *ndata;
+ su_alloc_t *sua;
+ su_block_t *sub;
+ size_t p;
+ size_t term = 0 - size;
+
+ if (!home)
+ return realloc(data, size);
+
+ if (size == 0) {
+ if (data)
+ su_free(home, data);
+ return NULL;
+ }
+
+ sub = MEMLOCK(home);
+ if (!data) {
+ data = sub_alloc(home, sub, size, 0);
+ UNLOCK(home);
+ return data;
+ }
+
+ sua = su_block_find(sub, data);
+
+ if (!su_alloc_check(sub, sua))
+ return UNLOCK(home);
+
+ assert(!sua->sua_home);
+ if (sua->sua_home)
+ return UNLOCK(home);
+
+ if (!su_is_preloaded(sub, data)) {
+ ndata = realloc(data, size + MEMCHECK_EXTRA);
+ if (ndata) {
+ if (sub->sub_stats) {
+ su_home_stats_free(sub, data, 0, sua->sua_size);
+ su_home_stats_alloc(sub, data, 0, size, 1);
+ }
+
+#if MEMCHECK_EXTRA
+ memcpy((char *)ndata + size, &term, sizeof (term));
+#else
+ (void)term;
+#endif
+ memset(sua, 0, sizeof *sua);
+ sub->sub_used--;
+ su_block_add(sub, ndata)->sua_size = size;
+ }
+ UNLOCK(home);
+
+ return ndata;
+ }
+
+ p = (char *)data - home->suh_blocks->sub_preload;
+ p += sua->sua_size + MEMCHECK_EXTRA;
+ p = ALIGN(p);
+
+ if (p == sub->sub_prused) {
+ size_t p2 = (char *)data - sub->sub_preload + size + MEMCHECK_EXTRA;
+ p2 = ALIGN(p2);
+ if (p2 <= sub->sub_prsize) {
+ /* Extend/reduce existing preload */
+ if (sub->sub_stats) {
+ su_home_stats_free(sub, data, data, sua->sua_size);
+ su_home_stats_alloc(sub, data, data, size, 0);
+ }
+
+ sub->sub_prused = (unsigned)p2;
+ sua->sua_size = size;
+
+#if MEMCHECK_EXTRA
+ memcpy((char *)data + size, &term, sizeof (term));
+#endif
+ UNLOCK(home);
+ return data;
+ }
+ }
+ else if (size < sua->sua_size) {
+ /* Reduce existing preload */
+ if (sub->sub_stats) {
+ su_home_stats_free(sub, data, data, sua->sua_size);
+ su_home_stats_alloc(sub, data, data, size, 0);
+ }
+#if MEMCHECK_EXTRA
+ memcpy((char *)data + size, &term, sizeof (term));
+#endif
+ sua->sua_size = size;
+ UNLOCK(home);
+ return data;
+ }
+
+ ndata = malloc(size + MEMCHECK_EXTRA);
+
+ if (ndata) {
+ if (p == sub->sub_prused) {
+ /* Free preload */
+ sub->sub_prused = (char *)data - home->suh_blocks->sub_preload;
+ if (sub->sub_stats)
+ su_home_stats_free(sub, data, data, sua->sua_size);
+ }
+
+ memcpy(ndata, data, sua->sua_size < size ? sua->sua_size : size);
+#if MEMCHECK_EXTRA
+ memcpy((char *)ndata + size, &term, sizeof (term));
+#endif
+
+ if (sub->sub_stats)
+ su_home_stats_alloc(sub, data, 0, size, 1);
+
+ memset(sua, 0, sizeof *sua); sub->sub_used--;
+
+ su_block_add(sub, ndata)->sua_size = size;
+ }
+
+ UNLOCK(home);
+
+ return ndata;
+}
+
+
+/**Check if a memory block has been allocated from the @a home.
+ *
+ * Check if the given memory block has been allocated from the home.
+ *
+ * @param home pointer to memory pool object
+ * @param memory ponter to memory block
+ *
+ * @retval 1 if @a memory has been allocated from @a home.
+ * @retval 0 otherwise
+ *
+ * @since New in @VERSION_1_12_4.
+ */
+int su_in_home(su_home_t *home, void const *memory)
+{
+ su_alloc_t *sua;
+ su_block_t *sub;
+ int retval = 0;
+
+ if (!home || !memory)
+ return 0;
+
+ sub = MEMLOCK(home);
+
+ if (sub) {
+ sua = su_block_find(sub, memory);
+
+ retval = su_alloc_check(sub, sua);
+
+ UNLOCK(home);
+ }
+
+ return retval;
+}
+
+
+/**Allocate and zero a memory block.
+ *
+ * The function su_zalloc() allocates a memory block with a given size from
+ * given memory home @a home and zeroes the allocated block.
+ *
+ * @param home pointer to memory pool object
+ * @param size size of the memory block
+ *
+ * @note The memory home pointer @a home may be @c NULL. In that case, the
+ * allocated memory block is not associated with any memory home, and it
+ * must be freed by calling su_free() or free().
+ *
+ * @return
+ * The function su_zalloc() returns a pointer to the allocated memory block,
+ * or NULL upon an error.
+ */
+void *su_zalloc(su_home_t *home, isize_t size)
+{
+ void *data;
+
+ assert (size >= 0);
+
+ if (home) {
+ data = sub_alloc(home, MEMLOCK(home), size, 1);
+ UNLOCK(home);
+ }
+ else
+ data = calloc(1, size);
+
+ return data;
+}
+
+/** Allocate a structure
+ *
+ * The function su_salloc() allocates a structure with a given size, zeros
+ * it, and initializes the size field to the given size. The size field
+ * is the first in the structure. It has type of int.
+ *
+ * @param home pointer to memory pool object
+ * @param size size of the structure
+ *
+ * @par Example
+ * The structure is defined and allocated as follows:
+ * @code
+ * struct test {
+ * int tst_size;
+ * char *tst_name;
+ * void *tst_ptr[3];
+ * };
+ *
+ * struct test *t;
+ * ...
+ * t = su_salloc(home, sizeof (*t));
+ * assert(t && t->t_size == sizeof (*t));
+ *
+ * @endcode
+ * After calling su_salloc() we get a pointer t to a struct test,
+ * initialized to zero except the tst_size field, which is initialized to
+ * sizeof (*t).
+ *
+ * @return A pointer to the allocated structure, or NULL upon an error.
+ */
+void *su_salloc(su_home_t *home, isize_t size)
+{
+ struct { int size; } *retval;
+
+ if (size < sizeof (*retval))
+ size = sizeof (*retval);
+
+ if (size > INT_MAX)
+ return (void)(errno = ENOMEM), NULL;
+
+ if (home) {
+ retval = sub_alloc(home, MEMLOCK(home), size, 1);
+ UNLOCK(home);
+ }
+ else
+ retval = calloc(1, size);
+
+ if (retval)
+ retval->size = (int)size;
+
+ return retval;
+}
+
+/** Check if a memory home is threadsafe */
+int su_home_is_threadsafe(su_home_t const *home)
+{
+ return home && home->suh_lock;
+}
+
+/** Obtain exclusive lock on home (if home is threadsafe). */
+int su_home_mutex_lock(su_home_t *home)
+{
+ if (home == NULL)
+ return su_seterrno(EFAULT);
+
+ if (home->suh_lock) {
+ su_home_ref(home);
+ su_home_mutex_locker(home->suh_lock);
+ }
+ else if (home->suh_blocks) {
+ if (!su_home_ref(home))
+ return -1;
+ }
+
+ return 0;
+}
+
+/** Release exclusive lock on home (if home is threadsafe) */
+int su_home_mutex_unlock(su_home_t *home)
+{
+ if (home == NULL)
+ return su_seterrno(EFAULT);
+
+ if (home->suh_lock) {
+ su_home_mutex_unlocker(home->suh_lock);
+ su_home_unref(home);
+ }
+ else if (home->suh_blocks) {
+ su_home_unref(home);
+ }
+
+ return 0;
+}
+
+
+/** Initialize statistics structure */
+void su_home_init_stats(su_home_t *home)
+{
+ su_block_t *sub;
+ size_t size;
+
+ if (home == NULL)
+ return;
+
+ sub = home->suh_blocks;
+
+ if (!sub)
+ sub = home->suh_blocks = su_hash_alloc(SUB_N);
+ if (!sub)
+ return;
+
+ if (!sub->sub_stats) {
+ size = sizeof (*sub->sub_stats);
+ sub->sub_stats = malloc(size);
+ if (!sub->sub_stats)
+ return;
+ }
+ else
+ size = sub->sub_stats->hs_size;
+
+ memset(sub->sub_stats, 0, size);
+ sub->sub_stats->hs_size = (int)size;
+ sub->sub_stats->hs_blocksize = sub->sub_n;
+}
+
+/** Retrieve statistics from memory home.
+ */
+void su_home_get_stats(su_home_t *home, int include_clones,
+ su_home_stat_t hs[1],
+ isize_t size)
+{
+ su_block_t *sub;
+
+ if (hs == NULL || size < (sizeof hs->hs_size))
+ return;
+
+ memset(hs, 0, size);
+
+ sub = MEMLOCK(home);
+
+ if (sub && sub->sub_stats) {
+ int sub_size = sub->sub_stats->hs_size;
+ if (sub_size > (int)size)
+ sub_size = (int)size;
+ sub->sub_stats->hs_preload.hsp_size = sub->sub_prsize;
+ sub->sub_stats->hs_preload.hsp_used = sub->sub_prused;
+ memcpy(hs, sub->sub_stats, sub_size);
+ hs->hs_size = sub_size;
+ }
+
+ UNLOCK(home);
+}
+
+static
+void su_home_stats_alloc(su_block_t *sub, void *p, void *preload,
+ size_t size, int zero)
+{
+ su_home_stat_t *hs = sub->sub_stats;
+
+ size_t rsize = ALIGN(size);
+
+ hs->hs_rehash += (sub->sub_n != hs->hs_blocksize);
+ hs->hs_blocksize = sub->sub_n;
+
+ hs->hs_clones += zero > 1;
+
+ if (preload) {
+ hs->hs_allocs.hsa_preload++;
+ return;
+ }
+
+ hs->hs_allocs.hsa_number++;
+ hs->hs_allocs.hsa_bytes += size;
+ hs->hs_allocs.hsa_rbytes += rsize;
+ if (hs->hs_allocs.hsa_rbytes > hs->hs_allocs.hsa_maxrbytes)
+ hs->hs_allocs.hsa_maxrbytes = hs->hs_allocs.hsa_rbytes;
+
+ hs->hs_blocks.hsb_number++;
+ hs->hs_blocks.hsb_bytes += size;
+ hs->hs_blocks.hsb_rbytes += rsize;
+}
+
+static
+void su_home_stats_free(su_block_t *sub, void *p, void *preload, size_t size)
+{
+ su_home_stat_t *hs = sub->sub_stats;
+
+ size_t rsize = ALIGN(size);
+
+ if (preload) {
+ hs->hs_frees.hsf_preload++;
+ return;
+ }
+
+ hs->hs_frees.hsf_number++;
+ hs->hs_frees.hsf_bytes += size;
+ hs->hs_frees.hsf_rbytes += rsize;
+
+ hs->hs_blocks.hsb_number--;
+ hs->hs_blocks.hsb_bytes -= size;
+ hs->hs_blocks.hsb_rbytes -= rsize;
+}
+
+void su_home_stat_add(su_home_stat_t total[1], su_home_stat_t const hs[1])
+{
+ total->hs_clones += hs->hs_clones;
+ total->hs_rehash += hs->hs_rehash;
+
+ if (total->hs_blocksize < hs->hs_blocksize)
+ total->hs_blocksize = hs->hs_blocksize;
+
+ total->hs_allocs.hsa_number += hs->hs_allocs.hsa_number;
+ total->hs_allocs.hsa_bytes += hs->hs_allocs.hsa_bytes;
+ total->hs_allocs.hsa_rbytes += hs->hs_allocs.hsa_rbytes;
+ total->hs_allocs.hsa_maxrbytes += hs->hs_allocs.hsa_maxrbytes;
+
+ total->hs_frees.hsf_number += hs->hs_frees.hsf_number;
+ total->hs_frees.hsf_bytes += hs->hs_frees.hsf_bytes;
+ total->hs_frees.hsf_rbytes += hs->hs_frees.hsf_rbytes;
+
+ total->hs_blocks.hsb_number += hs->hs_blocks.hsb_number;
+ total->hs_blocks.hsb_bytes += hs->hs_blocks.hsb_bytes;
+ total->hs_blocks.hsb_rbytes += hs->hs_blocks.hsb_rbytes;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_alloc_lock.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_alloc_lock.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,114 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_alloc
+ * @CFILE su_alloc_lock.c
+ * @brief Thread-locking for su_alloc module.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Fri Feb 23 17:38:11 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <sofia-sip/su_alloc.h>
+#include <sofia-sip/su.h>
+
+#if SU_HAVE_PTHREADS
+#include <pthread.h>
+#include <assert.h>
+
+extern void (*su_home_locker)(void *mutex);
+extern void (*su_home_unlocker)(void *mutex);
+
+extern void (*su_home_mutex_locker)(void *mutex);
+extern void (*su_home_mutex_unlocker)(void *mutex);
+
+/** Mutex */
+static void mutex_locker(void *_mutex)
+{
+ pthread_mutex_t *mutex = _mutex;
+ pthread_mutex_lock(mutex + 1);
+}
+
+static void mutex_unlocker(void *_mutex)
+{
+ pthread_mutex_t *mutex = _mutex;
+ pthread_mutex_unlock(mutex + 1);
+}
+#endif
+
+
+/** Convert su_home_t object to a thread-safe one.
+ *
+ * Convert a memory home object as thread-safe by allocating mutexes and
+ * modifying function pointers in su_alloc.c module.
+
+ * @param home memory home object to be converted thread-safe.
+ *
+ * @retval 0 when successful,
+ * @retval -1 upon an error.
+ */
+int su_home_threadsafe(su_home_t *home)
+{
+ pthread_mutex_t *mutex;
+
+ if (home == NULL)
+ return su_seterrno(EFAULT);
+
+ if (home->suh_lock) /* Already? */
+ return 0;
+
+#if 0 /* Allow threadsafe subhomes */
+ assert(!su_home_has_parent(home));
+ if (su_home_has_parent(home))
+ return su_seterrno(EINVAL);
+#endif
+
+#if SU_HAVE_PTHREADS
+ if (!su_home_unlocker) {
+ /* Avoid linking pthread library just for memory management */
+ su_home_mutex_locker = mutex_locker;
+ su_home_mutex_unlocker = mutex_unlocker;
+ su_home_locker = (void (*)(void *))pthread_mutex_lock;
+ su_home_unlocker = (void (*)(void *))pthread_mutex_unlock;
+ }
+
+ mutex = su_alloc(home, 2 * sizeof (pthread_mutex_t));
+ assert(mutex);
+ if (mutex) {
+ /* Mutex for memory operations */
+ pthread_mutex_init(mutex, NULL);
+ /* Mutex used for explicit locking */
+ pthread_mutex_init(mutex + 1, NULL);
+ home->suh_lock = (void *)mutex;
+ return 0;
+ }
+#else
+ su_seterrno(ENOSYS);
+#endif
+
+ return -1;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_bm.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_bm.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,273 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**
+ * @file su_bm.c
+ * @brief Search with Boyer-Moore algorithm
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Mon Apr 11 16:35:16 2005 ppessi
+ *
+ */
+
+#include "config.h"
+
+#include <sofia-sip/su_bm.h>
+
+#include <sys/types.h>
+#include <stddef.h>
+#include <limits.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef TORTURELOG
+#define TORTURELOG(x) (void)0
+#endif
+
+struct bw_fwd_table {
+ unsigned char table[UCHAR_MAX + 1];
+};
+
+/** Build forward skip table #bm_fwd_table_t for Boyer-Moore algorithm. */
+static
+bm_fwd_table_t *
+bm_memmem_study0(char const *needle, size_t nlen, bm_fwd_table_t *fwd)
+{
+ size_t i;
+
+ if (nlen >= UCHAR_MAX) {
+ needle += nlen - UCHAR_MAX;
+ nlen = UCHAR_MAX;
+ }
+
+ memset(&fwd->table, (unsigned char)nlen, sizeof fwd->table);
+
+ for (i = 0; i < nlen; i++) {
+ fwd->table[(unsigned short)needle[i]] = (unsigned char)(nlen - i - 1);
+ }
+
+ return fwd;
+}
+
+/** @defgroup su_bm Fast string searching with Boyer-Moore algorithm
+ *
+ * The Boyer-Moore algorithm is used to implement fast substring search. The
+ * algorithm has some overhead caused by filling a table. Substring search
+ * then requires at most 1 / substring-length less string comparisons. On
+ * modern desktop hardware, Boyer-Moore algorithm is seldom faster than the
+ * naive implementation if the searched substring is shorter than the cache
+ * line.
+ *
+ */
+
+/**@ingroup su_bm
+ * @typedef struct bw_fwd_table bm_fwd_table_t;
+ *
+ * Forward skip table for Boyer-Moore algorithm.
+ *
+ */
+
+/** Build case-sensitive forward skip table #bm_fwd_table_t
+ * for Boyer-Moore algorithm.
+ * @ingroup su_bm
+ */
+bm_fwd_table_t *
+bm_memmem_study(char const *needle, size_t nlen)
+{
+ bm_fwd_table_t *fwd = malloc(sizeof *fwd);
+
+ if (fwd)
+ bm_memmem_study0(needle, nlen, fwd);
+
+ return fwd;
+}
+
+/** Search for a substring using Boyer-Moore algorithm.
+ * @ingroup su_bm
+ */
+char const*
+bm_memmem(char const *haystack, size_t hlen,
+ char const *needle, size_t nlen,
+ bm_fwd_table_t *fwd)
+{
+ size_t i, j;
+ bm_fwd_table_t fwd0[1];
+
+ if (nlen == 0)
+ return haystack;
+ if (needle == NULL || haystack == NULL || nlen > hlen)
+ return NULL;
+
+ if (nlen == 1) {
+ for (i = 0; i < hlen; i++)
+ if (haystack[i] == needle[0])
+ return haystack + i;
+ return NULL;
+ }
+
+ if (!fwd)
+ fwd = bm_memmem_study0(needle, nlen, fwd0);
+
+ for (i = j = nlen - 1; i < hlen;) {
+ unsigned char h = haystack[i];
+ if (h == needle[j]) {
+ TORTURELOG(("match \"%s\" at %u\nwith %*s\"%.*s*%s\": %s\n",
+ haystack, (unsigned)i,
+ (int)(i - j), "", (int)j, needle, needle + j + 1,
+ j == 0 ? "match!" : "back by 1"));
+ if (j == 0)
+ return haystack + i;
+ i--, j--;
+ }
+ else {
+ if (fwd->table[h] > nlen - j) {
+ TORTURELOG(("match \"%s\" at %u\n"
+ "last %*s\"%.*s*%s\": (by %u)\n",
+ haystack, (unsigned)i,
+ (int)(i - j), "",
+ (int)j, needle, needle + j + 1, fwd->table[h]));
+ i += fwd->table[h];
+ }
+ else {
+ TORTURELOG(("match \"%s\" at %u\n"
+ "2nd %*s\"%.*s*%s\": (by %u)\n",
+ haystack, (unsigned)i,
+ (int)(i - j), "",
+ (int)j, needle, needle + j + 1, (unsigned)(nlen - j)));
+ i += nlen - j;
+ }
+ j = nlen - 1;
+ }
+ }
+
+ return NULL;
+}
+
+
+/** Build forward skip table for Boyer-Moore algorithm */
+static
+bm_fwd_table_t *
+bm_memcasemem_study0(char const *needle, size_t nlen, bm_fwd_table_t *fwd)
+{
+ size_t i;
+
+ if (nlen >= UCHAR_MAX) {
+ needle += nlen - UCHAR_MAX;
+ nlen = UCHAR_MAX;
+ }
+
+ for (i = 0; i < UCHAR_MAX; i++)
+ fwd->table[i] = (unsigned char)nlen;
+
+ for (i = 0; i < nlen; i++) {
+ unsigned char n = tolower(needle[i]);
+ fwd->table[n] = (unsigned char)(nlen - i - 1);
+ }
+
+ return fwd;
+}
+
+/** Build case-insensitive forward skip table for Boyer-Moore algorithm.
+ * @ingroup su_bm
+ */
+bm_fwd_table_t *
+bm_memcasemem_study(char const *needle, size_t nlen)
+{
+ bm_fwd_table_t *fwd = malloc(sizeof *fwd);
+
+ if (fwd)
+ bm_memcasemem_study0(needle, nlen, fwd);
+
+ return fwd;
+}
+
+/** Search for substring using Boyer-Moore algorithm.
+ * @ingroup su_bm
+ */
+char const*
+bm_memcasemem(char const *haystack, size_t hlen,
+ char const *needle, size_t nlen,
+ bm_fwd_table_t *fwd)
+{
+ size_t i, j;
+ bm_fwd_table_t fwd0[1];
+
+ if (nlen == 0)
+ return haystack;
+ if (needle == 0 || haystack == 0 || nlen > hlen)
+ return NULL;
+
+ if (nlen == 1) {
+ for (i = 0; i < hlen; i++)
+ if (haystack[i] == needle[0])
+ return haystack + i;
+ return NULL;
+ }
+
+ if (!fwd) {
+ fwd = bm_memcasemem_study0(needle, nlen, fwd0);
+ }
+
+ for (i = j = nlen - 1; i < hlen;) {
+ unsigned char h = haystack[i], n = needle[j];
+ if (isupper(h))
+ h = tolower(h);
+ if (isupper(n))
+ n = tolower(n);
+
+ if (h == n) {
+ TORTURELOG(("match \"%s\" at %u\n"
+ "with %*s\"%.*s*%s\": %s\n",
+ haystack, (unsigned)i,
+ (int)(i - j), "", (int)j, needle, needle + j + 1,
+ j == 0 ? "match!" : "back by 1"));
+ if (j == 0)
+ return haystack + i;
+ i--, j--;
+ }
+ else {
+ if (fwd->table[h] > nlen - j) {
+ TORTURELOG(("match \"%s\" at %u\n"
+ "last %*s\"%.*s*%s\": (by %u)\n",
+ haystack, (unsigned)i,
+ (int)(i - j), "", (int)j, needle, needle + j + 1,
+ fwd->table[h]));
+ i += fwd->table[h];
+ }
+ else {
+ TORTURELOG(("match \"%s\" at %u\n"
+ "2nd %*s\"%.*s*%s\": (by %u)\n",
+ haystack, (unsigned)i,
+ (int)(i - j), "", (int)j, needle, needle + j + 1,
+ (unsigned)(nlen - j)));
+ i += nlen - j;
+ }
+ j = nlen - 1;
+ }
+ }
+
+ return NULL;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_default_log.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_default_log.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,92 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_log
+ * @CFILE su_default_log.c
+ *
+ * Default debug log object.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Fri Feb 23 17:30:46 2001 ppessi
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#include <sofia-sip/su_log.h>
+#include <sofia-sip/su_debug.h>
+
+/** Log into FILE, by default stderr. */
+static void default_logger(void *stream, char const *fmt, va_list ap)
+{
+ FILE *f = stream ? (FILE *)stream : stderr;
+
+ vfprintf(f, fmt, ap);
+}
+
+/**@var SOFIA_DEBUG
+ *
+ * Environment variable determining the default debug log level.
+ *
+ * The SOFIA_DEBUG environment variable is used to determine the default
+ * debug logging level. The normal level is 3.
+ *
+ * @sa <su_debug.h>, su_log_global
+ */
+extern char const SOFIA_DEBUG[];
+
+#ifdef SU_DEBUG
+#define SOFIA_DEBUG_ SU_DEBUG
+#else
+#define SOFIA_DEBUG_ 3
+#endif
+
+/**Default debug log.
+ *
+ * If a source module does not define a log object, the output from su_log()
+ * function or SU_DEBUG_X() macros use this log object. Also, if a log
+ * function references log object with NULL pointer, the su_log_default
+ * object is used.
+ *
+ * If output from another log object is not redirected with
+ * su_log_redirect(), the output can be redirected via this log object.
+ *
+ * If the logging level of a log object is not set with su_log_set_level(),
+ * or the environment variable directing its level is not set, the log level
+ * from the #su_log_default object is used.
+ *
+ * The level of #su_log_default is set using SOFIA_DEBUG environment
+ * variable.
+ */
+su_log_t su_log_default[1] = {{
+ sizeof(su_log_t),
+ "sofia", /* Log name */
+ "SOFIA_DEBUG", /* Environment variable controlling logging level */
+ SOFIA_DEBUG_, /* Default level */
+ SU_LOG_MAX, /* Maximum log level */
+ 0,
+ default_logger,
+ NULL
+}};
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_errno.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_errno.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,160 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE su_errno.c errno compatibility
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Original: Thu Mar 18 19:40:51 1999 pessi
+ * @date Split to su_errno.c: Thu Dec 22 18:37:02 EET 2005 pessi
+ */
+
+#include "config.h"
+
+#include <sofia-sip/su_errno.h>
+#include <sofia-sip/su.h>
+
+#include <string.h>
+
+#if SU_HAVE_WINSOCK
+
+#include <stdio.h>
+
+/** Get the latest socket error. */
+int su_errno(void)
+{
+ return WSAGetLastError();
+}
+
+/** Set the socket error. */
+int su_seterrno(int errcode)
+{
+ WSASetLastError(errcode);
+
+ return -1;
+}
+
+const char *su_strerror(int errcode)
+{
+ struct errmsg { int no; const char *msg; };
+ static struct errmsg *msgp;
+ static struct errmsg msgs[] = {
+ { 0, "Success" },
+ { WSAEINTR, "Interrupted system call" },
+ { WSAEBADF, "Bad file descriptor" },
+ { WSAEACCES, "Permission denied" },
+ { WSAEFAULT, "Bad address" },
+ { WSAEINVAL, "Invalid argument" },
+ { WSAEMFILE, "Too many open files" },
+ { WSAEWOULDBLOCK, "Another winsock call while a "
+ "blocking function was in progress" },
+ { WSAEINPROGRESS, "Operation now in progress" },
+ { WSAEALREADY, "Operation already in progress" },
+ { WSAENOTSOCK, "Socket operation on non-socket" },
+ { WSAEDESTADDRREQ, "Destination address required" },
+ { WSAEMSGSIZE, "Message too long" },
+ { WSAEPROTOTYPE, "Protocol wrong type for socket" },
+ { WSAENOPROTOOPT, "Protocol not available" },
+ { WSAEPROTONOSUPPORT, "Protocol not supported" },
+ { WSAESOCKTNOSUPPORT, "Socket type not supported" },
+ { WSAEOPNOTSUPP, "Operation not supported" },
+ { WSAEPFNOSUPPORT, "Protocol family not supported" },
+ { WSAEAFNOSUPPORT, "Address family not supported" },
+ { WSAEADDRINUSE, "Address already in use" },
+ { WSAEADDRNOTAVAIL, "Can't assign requested address" },
+ { WSAENETDOWN, "Network is down" },
+ { WSAENETUNREACH, "Network is unreachable" },
+ { WSAENETRESET, "Network dropped connection on reset" },
+ { WSAECONNABORTED, "Software caused connection abort" },
+ { WSAECONNRESET, "Connection reset by peer" },
+ { WSAENOBUFS, "No buffer space available" },
+ { WSAEISCONN, "Socket is already connected" },
+ { WSAENOTCONN, "Socket is not connected" },
+ { WSAESHUTDOWN, "Can't send after socket shutdown" },
+ { WSAETOOMANYREFS, "Too many references: "
+ "can't splice" },
+ { WSAETIMEDOUT, "Operation timed out" },
+ { WSAECONNREFUSED, "Connection refused" },
+ { WSAELOOP, "Too many levels of symbolic links" },
+ { WSAENAMETOOLONG, "File name too long" },
+ { WSAEHOSTDOWN, "Host is down" },
+ { WSAEHOSTUNREACH, "No route to host" },
+ { WSAENOTEMPTY, "Directory not empty" },
+ { WSAEPROCLIM, "Too many processes" },
+ { WSAEUSERS, "Too many users" },
+ { WSAEDQUOT, "Disc quota exceeded" },
+ { WSAESTALE, "Stale NFS file handle" },
+ { WSAEREMOTE, "Too many levels of remote in path" },
+ { WSASYSNOTREADY, "Network subsystem is unvailable" },
+ { WSAVERNOTSUPPORTED, "WinSock version is not "
+ "supported" },
+ { WSANOTINITIALISED, "Successful WSAStartup() not yet "
+ "performed" },
+ { WSAEDISCON, "Graceful shutdown in progress" },
+ /* Resolver errors */
+ { WSAHOST_NOT_FOUND, "No such host is known" },
+ { WSATRY_AGAIN, "Host not found, or server failed" },
+ { WSANO_RECOVERY, "Unexpected server error "
+ "encountered" },
+ { WSANO_DATA, "Valid name without requested data" },
+ { WSANO_ADDRESS, "No address, look for MX record" },
+ { 0, NULL }
+ };
+ static struct errmsg sofia_msgs[] = {
+ { EBADMSG, "Bad message" },
+ { EPROTO, "Protocol error" },
+ { 0, NULL }
+ };
+ static char buf[64];
+
+ if (errcode < WSABASEERR)
+ return strerror(errcode);
+
+ if (errcode < 20000)
+ for (msgp = msgs; msgp->msg; msgp++) {
+ if (errcode == msgp->no) {
+ return msgp->msg;
+ }
+ }
+ else
+ for (msgp = sofia_msgs; msgp->msg; msgp++) {
+ if (errcode == msgp->no) {
+ return msgp->msg;
+ }
+ }
+
+ /* This can not overflow, but in other hand, it is not thread-safe */
+ sprintf(buf, "winsock error %d", errcode);
+
+ return buf;
+}
+
+#else
+
+const char *su_strerror(int errcode)
+{
+ return strerror(errcode);
+}
+
+#endif /* SU_HAVE_WINSOCK */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_global_log.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_global_log.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,72 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_log
+ * @CFILE su_global_log.c
+ *
+ * Global SU debug log.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Mon May 7 11:08:36 2001 ppessi
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#include <sofia-sip/su_log.h>
+#include <sofia-sip/su_debug.h>
+
+/**@var SU_DEBUG
+ *
+ * Environment variable determining the debug log level for @b su module.
+ *
+ * The SU_DEBUG environment variable is used to determine the debug logging
+ * level for @b su module. The default level is 3.
+ *
+ * @sa <su_debug.h>, su_log_global
+ */
+extern char const SU_DEBUG[];
+
+#ifdef SU_DEBUG
+#define SU_DEBUG_ SU_DEBUG
+#else
+#define SU_DEBUG_ 3
+#endif
+
+/**Debug log for @b su module.
+ *
+ * The su_log_global is the log object used by @b su module. The level of
+ * #su_log_global is set using #SU_DEBUG environment variable.
+ */
+su_log_t su_log_global[1] = {{
+ sizeof(su_log_t),
+ "su",
+ "SU_DEBUG",
+ SU_DEBUG_,
+ SU_LOG_MAX,
+ 0,
+ NULL,
+ NULL
+}};
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_localinfo.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_localinfo.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1537 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_socket
+ * @CFILE su_localinfo.c
+ *
+ * Obtain list of local addresses.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Oct 4 14:09:29 EET 2000 ppessi
+ */
+
+#include "config.h"
+
+#include "sofia-sip/su.h"
+#include "sofia-sip/su_localinfo.h"
+#include "su_module_debug.h"
+
+#if HAVE_SYS_SOCKIO_H
+#include <sys/sockio.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+#if HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#if HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#if HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#if HAVE_NET_IF_TYPES_H
+#include <net/if_types.h>
+#endif
+
+#if HAVE_GETIFADDRS
+
+#define USE_LOCALINFO0 1
+#define localinfo0 bsd_localinfo
+static int bsd_localinfo(su_localinfo_t const *, su_localinfo_t **);
+
+#elif HAVE_IPHLPAPI_H
+
+#include <iphlpapi.h>
+#define USE_LOCALINFO0 1
+#define localinfo0 win_localinfo
+static int win_localinfo(su_localinfo_t const *, su_localinfo_t **);
+
+#else
+
+#undef USE_LOCALINFO0
+static int localinfo4(su_localinfo_t const *, su_localinfo_t **);
+# if SU_HAVE_IN6
+static int localinfo6(su_localinfo_t const *, su_localinfo_t **);
+# endif
+
+#endif
+
+static int li_name(su_localinfo_t const*, int, su_sockaddr_t const*, char **);
+static void li_sort(su_localinfo_t *i, su_localinfo_t **rresult);
+static int li_scope4(uint32_t ip4);
+
+/** @brief Request local address information.
+ *
+ * Gather the network interfaces and the addresses corresponding to them,
+ * check if they match to the search criteria specifed by @a hints and
+ * return a list of matching local address information in the @a
+ * return_localinfo. The local address information may include IPv4/IPv6
+ * addresses, interface name, interface index, address scope, and domain
+ * names corresponding to the local addresses.
+ *
+ * @param[in] hints specifies selection criteria
+ * @param[out] return_localinfo return list of local addresses
+ *
+ * @par Selection criteria - hints
+ *
+ * The selection criteria @a hints is used to select which addresses are
+ * returned and what kind of information is included in the @a res list.
+ *
+ * @par Selection by flags - hints->li_flags
+ *
+ * The @a hints->li_flags contain flags, which can be combined with bit-wise
+ * or. The currently defined flags are as follows:
+ *
+ * - #LI_V4MAPPED: when returning IPv4 addresses, map them as IPv6
+ * addresses. If this flag is specified, IPv4 addresses are returned even
+ * if @a hints->li_family is set to @c AF_INET6.
+ * - #LI_CANONNAME: return the domain name (DNS PTR) corresponding to the
+ * local address in @a li_canonname.
+ * - #LI_NAMEREQD: Do not return addresses not in DNS.
+ * - #LI_NUMERIC: instead of domain name, return the text presentation of
+ * the addresss in @a li_canonname.
+ * - #LI_DOWN: include interfaces and their addresses even if the interfaces
+ * are down. New in @VERSION_1_12_2.
+ * - #LI_IFNAME: return the interface name in @a li_ifname.
+ *
+ * @par Selection by address family - hints->li_family
+ *
+ * The address family can have three values: 0, AF_INET and AF_INET6. If
+ * address family @a hints->li_family, both IPv4 and IPv6 addresses are
+ * returned.
+ *
+ * @par Selection by interface index - hints->li_index
+ *
+ * If the field @a hints->li_index is non-zero, only the addresses assigned
+ * to the interface with given index are returned. The list of interface
+ * indices and names can be obtained by the function @c su_if_names().
+ *
+ * @par Selection by interface name - hints->li_ifname
+ *
+ * If the field @a hints->li_ifname is not NULL, only the addresses assigned
+ * to the named interface are returned. The list of interface names can be
+ * obtained by the function @c su_if_names().
+ *
+ * @par Selection by address scope - hints->li_scope
+ *
+ * If the field @a hints->li_scope is nonzero, only the addresses with
+ * matching scope are returned. The different address scopes can be combined
+ * with bitwise or. They are defined as follows
+ * - #LI_SCOPE_HOST: host-local address, valid within host (::1, 127.0.0.1/8)
+ * - #LI_SCOPE_LINK: link-local address, valid within link
+ * (IP6 addresses with prefix fe80::/10,
+ * IP4 addresses in net 169.254.0.0/16).
+ * - #LI_SCOPE_SITE: site-local address, addresses valid within organization
+ * (IPv6 addresses with prefix fec::/10,
+ * private IPv4 addresses in nets 10.0.0.0/8, 172.16.0.0/12,
+ * and 192.168.0.0/16 as defined in @RFC1918)
+ * - #LI_SCOPE_GLOBAL: global address.
+ *
+ * For instance, setting @a hints->li_scope to @c LI_SCOPE_GLOBAL | @c
+ * LI_SCOPE_SITE, both the @e global and @e site-local addresses are
+ * returned.
+ *
+ * @sa @RFC1918, @RFC4291, su_sockaddr_scope()
+ *
+ * @par Selection by domain name - hints->li_canonname
+ *
+ * If this field is non-null, the domain name (DNS PTR) corresponding to
+ * local IP addresses should match to the name given in this field.
+ *
+ * @return Zero (#ELI_NOERROR) when successful, or negative error code when
+ * failed.
+ *
+ * @par Diagnostics
+ * Use su_gli_strerror() in order to obtain a string describing the error
+ * code returned by su_getlocalinfo().
+ *
+ */
+int su_getlocalinfo(su_localinfo_t const *hints,
+ su_localinfo_t **return_localinfo)
+{
+ int error = 0, ip4 = 0, ip6 = 0;
+ su_localinfo_t *result = NULL, **rr = &result;
+ su_localinfo_t hh[1] = {{ 0 }};
+
+ assert(return_localinfo);
+
+ *return_localinfo = NULL;
+
+ if (hints) {
+ /* Copy hints so that it can be modified */
+ *hh = *hints;
+ if (hh->li_canonname)
+ hh->li_flags |= LI_CANONNAME;
+ if ((hh->li_flags & LI_IFNAME) && hh->li_ifname == NULL)
+ return ELI_BADHINTS;
+ }
+
+ switch (hh->li_family) {
+#if SU_HAVE_IN6
+ case AF_INET6:
+ if (hh->li_flags & LI_V4MAPPED)
+ ip6 = ip4 = 1, hh->li_family = 0;
+ else
+ ip6 = 1;
+ break;
+#endif
+
+ case AF_INET:
+ ip4 = 1;
+ break;
+
+ case 0:
+ ip6 = ip4 = 1;
+ break;
+
+ default:
+ return -1;
+ }
+
+#if USE_LOCALINFO0
+ error = localinfo0(hh, rr);
+#else
+
+# if SU_HAVE_IN6
+ if (ip6) {
+ error = localinfo6(hh, rr);
+ if (error == ELI_NOADDRESS && ip4)
+ error = 0;
+
+ if (!error)
+ /* Search end of list */
+ for (; *rr; rr = &(*rr)->li_next)
+ ;
+ }
+# endif
+ if (ip4 && !error) {
+ /* Append IPv4 addresses */
+ error = localinfo4(hh, rr);
+ }
+#endif
+
+ if (!result)
+ error = ELI_NOADDRESS;
+
+ if (!error)
+ li_sort(result, return_localinfo);
+ else
+ su_freelocalinfo(result);
+
+ return error;
+}
+
+/** Free local address information.
+ *
+ * Free a list of su_localinfo_t structures obtained with su_getlocalinfo()
+ * or su_copylocalinfo() along with socket addresses and strings associated
+ * with them.
+ *
+ * @sa su_getlocalinfo(), su_copylocalinfo(), #su_localinfo_t
+ */
+void su_freelocalinfo(su_localinfo_t *tbf)
+{
+ su_localinfo_t *li;
+
+ for (li = tbf; li; li = tbf) {
+ tbf = li->li_next;
+ if (li->li_canonname)
+ free(li->li_canonname);
+ free(li);
+ }
+}
+
+/** Describe su_localinfo errors.
+ *
+ * The function su_gli_strerror() returns a string describing the error
+ * condition indicated by the code that was returned by the function
+ * su_getlocalinfo().
+ *
+ * @param error error code returned by su_getlocalinfo()
+ *
+ * @return
+ * A pointer to string describing the error condition.
+ */
+char const *su_gli_strerror(int error)
+{
+ switch (error) {
+ case ELI_NOERROR: return "No error";
+ case ELI_NOADDRESS: return "No matching address";
+ case ELI_MEMORY: return "Memory allocation error";
+ case ELI_FAMILY: return "Unknown address family";
+ case ELI_RESOLVER: return "Error when resolving address";
+ case ELI_SYSTEM: return "System error";
+ case ELI_BADHINTS: return "Invalid value for hints";
+ default: return "Unknown error";
+ }
+}
+
+/** Duplicate su_localinfo structure.
+ */
+su_localinfo_t *su_copylocalinfo(su_localinfo_t const *li0)
+{
+ size_t n;
+ su_localinfo_t *li, *retval = NULL, **lli = &retval;
+
+# define SLEN(s) ((s) ? strlen(s) + 1 : 0)
+
+ for (; li0 ; li0 = li0->li_next) {
+ n = sizeof(*li0) + li0->li_addrlen + SLEN(li0->li_ifname);
+ if (!(li = calloc(1, n))) {
+ su_freelocalinfo(retval);
+ return NULL;
+ }
+ *lli = li;
+ lli = &li->li_next;
+ li->li_flags = li0->li_flags;
+ li->li_family = li0->li_family;
+ li->li_index = li0->li_index;
+ li->li_scope = li0->li_scope;
+ li->li_addrlen = li0->li_addrlen;
+ li->li_addr = memcpy(li + 1, li0->li_addr, li0->li_addrlen);
+
+ if (li0->li_canonname) {
+ if (!(li->li_canonname = malloc(SLEN(li0->li_canonname)))) {
+ su_freelocalinfo(retval);
+ return NULL;
+ }
+ strcpy(li->li_canonname, li0->li_canonname);
+ }
+
+ if (li0->li_ifname)
+ li->li_ifname = strcpy(li->li_addrlen + (char *)li->li_addr,
+ li0->li_ifname);
+ }
+
+ return retval;
+}
+
+
+/** Return IPv4 address scope */
+static int
+li_scope4(uint32_t ip4)
+{
+ ip4 = ntohl(ip4);
+
+ if (0x7f000000 == (ip4 & 0xff000000))
+ return LI_SCOPE_HOST;
+ /* draft-ietf-zeroconf-ipv4-linklocal-02.txt - 169.254/16. */
+ else if (0xa9fe0000 == (ip4 & 0xffff0000))
+ return LI_SCOPE_LINK;
+ /* RFC1918 - 10/8, 172.16/12, 192.168/16. */
+ else if (0x0a000000 == (ip4 & 0xff000000) ||
+ 0xac100000 == (ip4 & 0xfff00000) ||
+ 0xc0a80000 == (ip4 & 0xffff0000))
+ return LI_SCOPE_SITE;
+ else
+ return LI_SCOPE_GLOBAL;
+}
+
+#if SU_HAVE_IN6
+
+#if HAVE_WINSOCK2_H
+#define IN6_IS_ADDR_LOOPBACK SU_IN6_IS_ADDR_LOOPBACK
+static inline int
+IN6_IS_ADDR_LOOPBACK(void const *ip6)
+{
+ uint8_t const *u = ip6;
+
+ return
+ u[0] == 0 && u[1] == 0 && u[2] == 0 && u[3] == 0 &&
+ u[4] == 0 && u[5] == 0 && u[6] == 0 && u[7] == 0 &&
+ u[8] == 0 && u[9] == 0 && u[10] == 0 && u[11] == 0 &&
+ u[12] == 0 && u[13] == 0 && u[14] == 0 && u[15] == 1;
+}
+#endif
+
+/** Return IPv6 address scope */
+static int
+li_scope6(struct in6_addr const *ip6)
+{
+ if (IN6_IS_ADDR_V4MAPPED(ip6) || IN6_IS_ADDR_V4COMPAT(ip6)) {
+ uint32_t ip4 = *(uint32_t *)(ip6->s6_addr + 12);
+ return li_scope4(ip4);
+ }
+ else if (IN6_IS_ADDR_LOOPBACK(ip6))
+ return LI_SCOPE_HOST;
+ else if (IN6_IS_ADDR_LINKLOCAL(ip6))
+ return LI_SCOPE_LINK;
+ else if (IN6_IS_ADDR_SITELOCAL(ip6))
+ return LI_SCOPE_SITE;
+ else
+ return LI_SCOPE_GLOBAL;
+}
+#endif
+
+/** Return the scope of address in the sockaddr structure */
+int su_sockaddr_scope(su_sockaddr_t const *su, socklen_t sulen)
+{
+ if (sulen >= (sizeof su->su_sin) && su->su_family == AF_INET)
+ return li_scope4(su->su_sin.sin_addr.s_addr);
+
+#if SU_HAVE_IN6
+ if (sulen >= (sizeof su->su_sin6) && su->su_family == AF_INET6)
+ return li_scope6(&su->su_sin6.sin6_addr);
+#endif
+
+ return 0;
+}
+
+#if USE_LOCALINFO0
+
+#elif HAVE_IFCONF
+/** Build a list of local IPv4 addresses and append it to *rresult. */
+static
+int localinfo4(su_localinfo_t const *hints, su_localinfo_t **rresult)
+{
+ su_localinfo_t *tbf = NULL, **lli = &tbf;
+ su_localinfo_t *li = NULL, *li_first = NULL;
+ su_sockaddr_t *su;
+ int error = ELI_NOADDRESS;
+ char *canonname = NULL;
+ su_socket_t s;
+
+#if SU_HAVE_IN6
+ int su_xtra = (hints->li_flags & LI_V4MAPPED) ? sizeof(*su) : 0;
+#else
+ int const su_xtra = 0;
+#endif
+
+ struct ifconf ifc;
+ int numifs;
+ char *buffer;
+ struct ifreq *ifr, *ifr_next;
+
+ s = su_socket(AF_INET, SOCK_DGRAM, 0);
+ if (s == -1) {
+ SU_DEBUG_1(("su_localinfo: su_socket failed: %s\n",
+ su_strerror(su_errno())));
+ return ELI_SYSTEM;
+ }
+
+#if defined(__APPLE_CC__)
+ {
+ su_sockaddr_t *sa;
+ socklen_t salen = sizeof(*sa);
+ int scope = 0, gni_flags = 0;
+
+ li = calloc(1, sizeof(su_localinfo_t));
+ sa = calloc(1, sizeof(su_sockaddr_t));
+
+ error = getsockname(s, (struct sockaddr *) sa, &salen);
+ if (error < 0 && errno == SOCKET_ERROR) {
+ SU_DEBUG_1(("%s: getsockname() failed: %s\n", __func__,
+ su_strerror(su_errno())));
+ }
+
+ error = bind(s, (struct sockaddr *) sa, salen);
+
+ if (error < 0) {
+ SU_DEBUG_1(("%s: bind() failed: %s\n", __func__,
+ su_strerror(su_errno())));
+ goto err;
+ }
+
+ su_close(s);
+
+ scope = li_scope4(sa->su_sin.sin_addr.s_addr);
+
+ if (scope == LI_SCOPE_HOST || scope == LI_SCOPE_LINK)
+ gni_flags = NI_NUMERICHOST;
+
+ if (su_xtra) {
+ /* Map IPv4 address to IPv6 address */
+ memset(sa, 0, sizeof(*sa));
+ sa->su_family = AF_INET6;
+ ((int32_t*)&sa->su_sin6.sin6_addr)[3] = sa->su_sin.sin_addr.s_addr;
+ ((int32_t*)&sa->su_sin6.sin6_addr)[2] = htonl(0xffff);
+ }
+
+ li->li_family = sa->su_family;
+ li->li_scope = scope;
+ li->li_index = 0;
+ li->li_addrlen = su_sockaddr_size(sa);
+ li->li_addr = sa;
+
+ if ((error = li_name(hints, gni_flags, sa, &canonname)) < 0)
+ goto err;
+
+ if (canonname) {
+ if (strchr(canonname, ':') ||
+ strspn(canonname, "0123456789.") == strlen(canonname))
+ li->li_flags |= LI_NUMERIC;
+ }
+ else
+ li->li_flags = 0;
+
+ li->li_canonname = canonname;
+
+ canonname = NULL;
+
+ *rresult = li;
+ return 0;
+ }
+#endif
+
+
+# if HAVE_IFNUM
+ /* Get the list of known IP address from the kernel */
+ if (ioctl(s, SIOCGIFNUM, (char *) &numifs) < 0) {
+ /* can't get number of interfaces -- fall back */
+ SU_DEBUG_1(("su_localinfo: SIOCGIFNUM failed: %s\n",
+ su_strerror(su_errno())));
+ error = ELI_SYSTEM;
+ goto err;
+ }
+
+ SU_DEBUG_9(("su_localinfo: %d active interfaces according to SIOCGIFNUM\n",
+ numifs));
+
+ if (numifs < 0)
+# endif
+ /* Default to 64 interfaces. Enough? */
+ numifs = 64;
+
+ if (numifs == 0)
+ return 0;
+
+ /*
+ * Allocate memory for SIOCGIFCONF ioctl buffer. This memory block is also
+ * used as li_first, first localinfo struct that is returned, so it can be
+ * freed by freelocalinfo() without any complications.
+ */
+ ifc.ifc_len = numifs * sizeof (struct ifreq);
+ buffer = malloc(sizeof(su_localinfo_t) + ifc.ifc_len + su_xtra);
+ if (!buffer) {
+ SU_DEBUG_1(("su_localinfo: memory exhausted\n"));
+ error = ELI_MEMORY;
+ goto err;
+ }
+
+ li_first = (su_localinfo_t *)buffer;
+ memset(li_first, 0, sizeof(su_localinfo_t) + su_xtra);
+ ifc.ifc_buf = buffer + sizeof(su_localinfo_t) + su_xtra;
+ if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) {
+ SU_DEBUG_1(("su_localinfo: SIOCGIFCONF failed: %s\n",
+ su_strerror(su_errno())));
+ error = ELI_SYSTEM;
+ goto err;
+ }
+
+ buffer = ifc.ifc_buf + ifc.ifc_len;
+
+ for (ifr = ifc.ifc_req;
+ (void *)ifr < (void *)buffer;
+ ifr = ifr_next) {
+ struct ifreq ifreq[1];
+ int scope, if_index, flags = 0, gni_flags = 0;
+ char *if_name;
+ su_sockaddr_t su2[1];
+
+#if SA_LEN
+ if (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_addr))
+ ifr_next = (struct ifreq *)
+ (ifr->ifr_addr.sa_len + (char *)(&ifr->ifr_addr));
+ else
+#else
+ ifr_next = ifr + 1;
+#endif
+
+ if_name = ifr->ifr_name;
+
+#if defined(SIOCGIFINDEX)
+ ifreq[0] = *ifr;
+ if (ioctl(s, SIOCGIFINDEX, ifreq) < 0) {
+ SU_DEBUG_1(("su_localinfo: SIOCGIFINDEX failed: %s\n",
+ su_strerror(su_errno())));
+ error = ELI_SYSTEM;
+ goto err;
+ }
+#if HAVE_IFR_INDEX
+ if_index = ifreq->ifr_index;
+#elif HAVE_IFR_IFINDEX
+ if_index = ifreq->ifr_ifindex;
+#else
+#error Unknown index field in struct ifreq
+#endif
+
+#else
+#warning su_localinfo() cannot map interface name to number
+ if_index = 0;
+#endif
+
+ SU_DEBUG_9(("su_localinfo: if %s with index %d\n", if_name, if_index));
+
+#if defined(SIOCGIFFLAGS)
+ ifreq[0] = *ifr;
+ if (ioctl(s, SIOCGIFFLAGS, ifreq) < 0) {
+ SU_DEBUG_1(("su_localinfo: SIOCGIFFLAGS failed: %s\n",
+ su_strerror(su_errno())));
+ error = ELI_SYSTEM;
+ goto err;
+ }
+ /* Do not include interfaces that are down unless explicitly asked */
+ if ((ifreq->ifr_flags & IFF_UP) == 0 && (hints->li_flags & LI_DOWN) == 0) {
+ SU_DEBUG_9(("su_localinfo: if %s with index %d is down\n",
+ if_name, if_index));
+ continue;
+ }
+#else
+#error su_localinfo() cannot determine interface status
+#endif
+
+#if 0
+ *ifreq = *ifr;
+ ifreq->ifr_addr.sa_family = AF_INET;
+ if (ioctl(s, SIOCGIFADDR, ifreq) < 0) {
+ SU_DEBUG_1(("su_localinfo: SIOCGIFADDR failed: %s\n",
+ su_strerror(su_errno())));
+ error = ELI_SYSTEM;
+ goto err;
+ }
+ ifr->ifr_addr = ifreq->ifr_addr;
+#endif
+
+ su = (su_sockaddr_t *)&ifr->ifr_addr;
+
+ if (SU_HAS_INADDR_ANY(su))
+ continue;
+
+ scope = li_scope4(su->su_sin.sin_addr.s_addr);
+
+ if ((hints->li_scope && (hints->li_scope & scope) == 0) ||
+ (hints->li_ifname && strcmp(hints->li_ifname, if_name) != 0) ||
+ (hints->li_index && hints->li_index != if_index))
+ continue;
+
+#if SU_HAVE_IN6
+ if (su_xtra) {
+ /* Map IPv4 address to IPv6 address */
+ memset(su2, 0, sizeof(*su2));
+ su2->su_family = AF_INET6;
+ ((int32_t*)&su2->su_sin6.sin6_addr)[2] = htonl(0xffff);
+ ((int32_t*)&su2->su_sin6.sin6_addr)[3] = su->su_sin.sin_addr.s_addr;
+ su = su2;
+ }
+#endif
+
+ if (scope == LI_SCOPE_HOST || scope == LI_SCOPE_LINK)
+ gni_flags = NI_NUMERICHOST;
+
+ if ((error = li_name(hints, gni_flags, su, &canonname)) < 0)
+ goto err;
+ else if (error > 0)
+ continue;
+
+ if (canonname)
+ if (strchr(canonname, ':') ||
+ strspn(canonname, "0123456789.") == strlen(canonname))
+ flags |= LI_NUMERIC;
+
+ if (li_first)
+ li = li_first; /* Use li_first with all ifr structs to be freed */
+ else if (!(li = calloc(1, (sizeof *li) + su_xtra))) {
+ error = ELI_MEMORY;
+ goto err;
+ }
+ if (!tbf) tbf = li;
+ *lli = li; lli = &li->li_next;
+
+ if (su_xtra)
+ su = (su_sockaddr_t *)memcpy(li + 1, su, su_xtra);
+
+ li->li_flags = flags;
+ li->li_family = su->su_family;
+ li->li_scope = scope;
+ li->li_index = if_index;
+ li->li_addrlen = su_sockaddr_size(su);
+ li->li_addr = su;
+ li->li_canonname = canonname;
+ if (hints->li_flags & LI_IFNAME)
+ li->li_ifname = if_name;
+
+ canonname = NULL;
+ li_first = NULL;
+ }
+
+ if (canonname) free(canonname);
+ if (li_first) free(li_first);
+ su_close(s);
+
+ if (tbf) *rresult = tbf;
+ return 0;
+
+err:
+ if (canonname) free(canonname);
+ if (li_first) free(li_first);
+ su_freelocalinfo(tbf);
+ su_close(s);
+
+ return error;
+}
+#else
+static
+int localinfo4(su_localinfo_t const *hints, su_localinfo_t **rresult)
+{
+ /* Kikka #3: resolve hostname */
+ char hostname[SU_MAXHOST] = "";
+ char *name, *ifname;
+ struct hostent *h;
+ int i, flags, error, gni_flags = 0;
+ su_localinfo_t *tbf = NULL;
+ su_localinfo_t *li = NULL, **lli = &tbf;
+ su_sockaddr_t *su;
+#if SU_HAVE_IN6
+ socklen_t su_sockaddr_size =
+ (hints->li_flags & LI_V4MAPPED) ? sizeof(*su) : sizeof(struct sockaddr_in);
+ flags = hints->li_flags & (LI_V4MAPPED|LI_CANONNAME|LI_NUMERIC|LI_IFNAME);
+#else
+ socklen_t su_sockaddr_size = sizeof(struct sockaddr_in);
+ flags = hints->li_flags & (LI_CANONNAME|LI_NUMERIC|LI_IFNAME);
+#endif
+
+ error = ELI_NOERROR;
+
+ if (hints->li_scope == 0 || (hints->li_scope & LI_SCOPE_GLOBAL)) {
+ if (hints->li_canonname)
+ name = hints->li_canonname;
+ else if (gethostname(name = hostname, sizeof(hostname)) != 0)
+ return ELI_SYSTEM;
+
+ h = gethostbyname(name);
+
+ if (name)
+ if (strchr(name, ':') ||
+ strspn(name, "0123456789.") == strlen(name))
+ flags |= LI_NUMERIC;
+
+ for (i = 0; h && h->h_addr_list[i]; i++) {
+ if ((li = calloc(1, sizeof(*li) + su_sockaddr_size)) == NULL) {
+ error = ELI_MEMORY;
+ goto err;
+ }
+ li->li_flags = flags;
+
+ li->li_scope = li_scope4(*(uint32_t *)h->h_addr_list[i]);
+ if (li->li_scope == LI_SCOPE_HOST)
+ li->li_index = 1, ifname = "lo";
+ else
+ li->li_index = 2, ifname = "eth";
+
+ li->li_addrlen = su_sockaddr_size;
+ li->li_addr = su = (su_sockaddr_t *)(li + 1);
+ su->su_family = li->li_family =
+ li->li_flags & LI_V4MAPPED ? AF_INET6 : AF_INET;
+
+#if SU_HAVE_IN6
+ if (li->li_flags & LI_V4MAPPED) {
+ ((int32_t*)&su->su_sin6.sin6_addr)[2] = htonl(0xffff);
+ memcpy(&((int32_t*)&su->su_sin6.sin6_addr)[3],
+ h->h_addr_list[i], h->h_length);
+ }
+ else
+#endif
+ memcpy(&su->su_sin.sin_addr.s_addr, h->h_addr_list[i], h->h_length);
+ if (li->li_flags & LI_IFNAME)
+ li->li_ifname = ifname;
+ if (li->li_scope == LI_SCOPE_HOST || li->li_scope == LI_SCOPE_LINK)
+ gni_flags = NI_NUMERICHOST;
+ if ((error = li_name(hints, gni_flags, su, &li->li_canonname)) < 0)
+ goto err;
+ else if (error > 0) {
+ free(li); li = NULL; continue;
+ } else
+ error = ELI_NOADDRESS;
+ *lli = li; lli = &li->li_next; li = NULL;
+ }
+ }
+
+ if (hints->li_scope == 0 || (hints->li_scope & LI_SCOPE_HOST)) {
+ if ((li = calloc(1, sizeof(*li) + su_sockaddr_size)) == NULL) {
+ error = ELI_MEMORY;
+ goto err;
+ }
+ li->li_flags = hints->li_flags &
+ (LI_V4MAPPED|LI_CANONNAME|LI_NUMERIC|LI_IFNAME);
+ li->li_scope = LI_SCOPE_HOST, li->li_index = 1;
+ if (li->li_flags & LI_IFNAME)
+ li->li_ifname = "lo";
+ li->li_addrlen = su_sockaddr_size;
+ li->li_addr = su = (su_sockaddr_t *)(li + 1);
+#if SU_HAVE_IN6
+ if (li->li_flags & LI_V4MAPPED) {
+ su->su_family = li->li_family = AF_INET6;
+ ((int32_t*)&su->su_sin6.sin6_addr)[2] = htonl(0xffff);
+ ((int32_t*)&su->su_sin6.sin6_addr)[3] = htonl(0x7f000001);
+ }
+ else
+#endif
+ su->su_family = li->li_family = AF_INET,
+ su->su_sin.sin_addr.s_addr = htonl(0x7f000001);
+
+ if ((error = li_name(hints, NI_NUMERICHOST, su, &li->li_canonname)) < 0) {
+ goto err;
+ } else if (error > 0) {
+ free(li); li = NULL;
+ } else {
+ *lli = li; lli = &li->li_next; li = NULL;
+ }
+ }
+
+ *rresult = tbf;
+
+ return 0;
+
+err:
+ if (li) su_freelocalinfo(li);
+ su_freelocalinfo(tbf);
+
+ return error;
+}
+
+#endif
+
+#if USE_LOCALINFO0 || !SU_HAVE_IN6
+
+#elif HAVE_PROC_NET_IF_INET6
+/** Build a list of local IPv6 addresses and append it to *return_result. */
+static
+int localinfo6(su_localinfo_t const *hints, su_localinfo_t **return_result)
+{
+ su_localinfo_t *li = NULL;
+ su_sockaddr_t su[1] = {{ 0 }}, *addr;
+ int error = ELI_NOADDRESS;
+ char *canonname = NULL;
+ char line[80];
+ FILE *f;
+
+ if ((f = fopen("/proc/net/if_inet6", "r"))) {
+ for (;error;) {
+ struct in6_addr in6;
+ unsigned if_index, prefix_len, scope, flags;
+ int addrlen, if_namelen;
+ char ifname[16];
+
+ if (!fgets(line, sizeof(line), f)) {
+ if (feof(f))
+ error = ELI_NOERROR;
+ break;
+ }
+
+ if (sscanf(line, "%08x%08x%08x%08x %2x %2x %2x %02x %016s\n",
+ &in6.s6_addr32[0],
+ &in6.s6_addr32[1],
+ &in6.s6_addr32[2],
+ &in6.s6_addr32[3],
+ &if_index, &prefix_len, &scope, &flags, ifname) != 9)
+ break;
+
+ flags = 0;
+
+ /* Fix global scope (it is 0) */
+ if (!scope) scope = LI_SCOPE_GLOBAL;
+
+ in6.s6_addr32[0] = htonl(in6.s6_addr32[0]);
+ in6.s6_addr32[1] = htonl(in6.s6_addr32[1]);
+ in6.s6_addr32[2] = htonl(in6.s6_addr32[2]);
+ in6.s6_addr32[3] = htonl(in6.s6_addr32[3]);
+
+ if (IN6_IS_ADDR_V4MAPPED(&in6) || IN6_IS_ADDR_V4COMPAT(&in6)) {
+ uint32_t ip4 = *(uint32_t *)(in6.s6_addr + 12);
+ scope = li_scope4(ip4);
+ }
+
+ if ((hints->li_scope && (hints->li_scope & scope) == 0) ||
+ (hints->li_index && hints->li_index != if_index) ||
+ (hints->li_ifname && strcmp(hints->li_ifname, ifname) != 0))
+ continue;
+
+ su->su_family = AF_INET6;
+ su->su_sin6.sin6_addr = in6;
+
+ addrlen = su_sockaddr_size(su);
+
+ if ((error = li_name(hints, 0, su, &canonname)) < 0)
+ break;
+ else if (error > 0)
+ continue;
+ else
+ error = ELI_NOADDRESS;
+
+ if (canonname &&
+ (strchr(canonname, ':') ||
+ strspn(canonname, "0123456789.") == strlen(canonname)))
+ flags |= LI_NUMERIC;
+
+ if (hints->li_flags & LI_IFNAME)
+ if_namelen = strlen(ifname) + 1;
+ else
+ if_namelen = 0;
+
+ if ((li = calloc(1, sizeof *li + addrlen + if_namelen)) == NULL) {
+ error = ELI_MEMORY;
+ break;
+ }
+ addr = (su_sockaddr_t*)memcpy((li + 1), su, addrlen);
+ *return_result = li; return_result = &li->li_next;
+
+ li->li_flags = flags;
+ li->li_family = AF_INET6;
+ li->li_scope = scope;
+ li->li_index = if_index;
+ li->li_addr = addr;
+ li->li_addrlen = addrlen;
+ li->li_canonname = canonname;
+ if (if_namelen)
+ li->li_ifname = memcpy(addrlen + (char *)addr, ifname, if_namelen);
+
+ canonname = NULL;
+ }
+
+ fclose(f);
+ }
+
+ if (canonname)
+ free(canonname);
+
+ return error;
+}
+#else
+/* Use HOSTADDR6 */
+static
+int localinfo6(su_localinfo_t const *hints, su_localinfo_t **rresult)
+{
+ char *addr, *ifname;
+ int flags, error;
+ su_localinfo_t *li = NULL;
+ su_sockaddr_t *su;
+ int const su_sockaddr_size = sizeof(*su);
+
+ error = ELI_NOADDRESS;
+
+#if defined(__APPLE_CC__)
+ {
+ su_sockaddr_t *sa;
+ int salen = sizeof(*sa);
+ int s;
+
+ if (hints->li_scope == 0 || (hints->li_scope & LI_SCOPE_GLOBAL)) {
+ if ((addr = getenv("HOSTADDR6"))) {
+
+ li = calloc(1, sizeof(su_localinfo_t));
+ sa = calloc(1, sizeof(su_sockaddr_t));
+
+ sa->su_family = AF_INET6;
+ if (inet_pton(AF_INET6, addr, &sa->su_sin6.sin6_addr) <= 0)
+ goto err;
+
+ s = su_socket(AF_INET6, SOCK_DGRAM, 0);
+ if (s == -1) {
+ SU_DEBUG_1(("su_localinfo: su_socket failed: %s\n",
+ su_strerror(su_errno())));
+ return ELI_SYSTEM;
+ }
+
+ error = getsockname(s, (struct sockaddr *) sa, &salen);
+ if (error < 0 && errno == SOCKET_ERROR) {
+ SU_DEBUG_1(("%s: getsockname() failed: %s\n", __func__,
+ su_strerror(su_errno())));
+ }
+
+ error = bind(s, (struct sockaddr *) sa, salen);
+
+ if (error < 0) {
+ SU_DEBUG_1(("%s: bind() failed: %s\n", __func__,
+ su_strerror(su_errno())));
+ goto err;
+ }
+
+ su_close(s);
+
+ li->li_family = sa->su_family;
+ li->li_scope = LI_SCOPE_GLOBAL;
+ li->li_index = 0;
+ li->li_addrlen = su_sockaddr_size(sa);
+ li->li_addr = sa;
+
+ if ((error = li_name(hints, NI_NUMERICHOST, sa, &li->li_canonname)) < 0)
+ goto err;
+
+ li->li_flags = NI_NUMERICHOST;
+ }
+ }
+
+ *rresult = li;
+ return 0;
+ }
+#endif
+
+
+ if (hints->li_scope == 0 || (hints->li_scope & LI_SCOPE_GLOBAL)) {
+ if ((addr = getenv("HOSTADDR6"))) {
+ flags = hints->li_flags & (LI_CANONNAME|LI_NUMERIC|LI_IFNAME);
+
+ if ((li = calloc(1, sizeof(*li) + su_sockaddr_size)) == NULL) {
+ error = ELI_MEMORY;
+ goto err;
+ }
+ li->li_flags = flags;
+ li->li_scope = LI_SCOPE_GLOBAL, li->li_index = 2, ifname = "eth";
+ li->li_addrlen = sizeof(*su);
+ li->li_addr = su = (su_sockaddr_t *)(li + 1);
+ su->su_family = li->li_family = AF_INET6;
+ if (inet_pton(AF_INET6, addr, &su->su_sin6.sin6_addr) <= 0)
+ goto err;
+ if (li->li_flags & LI_IFNAME)
+ li->li_ifname = ifname;
+ if ((error = li_name(hints, NI_NUMERICHOST, su, &li->li_canonname)) < 0)
+ goto err;
+ else if (error > 0) {
+ free(li); li = NULL;
+ }
+ }
+ }
+
+ *rresult = li;
+
+ return 0;
+
+err:
+ if (li) su_freelocalinfo(li);
+ return error;
+}
+#endif
+
+
+#if HAVE_GETIFADDRS
+
+#include <ifaddrs.h>
+
+static
+int bsd_localinfo(su_localinfo_t const hints[1],
+ su_localinfo_t **return_result)
+{
+ struct ifaddrs *ifa, *results;
+ int error = 0;
+ int v4_mapped = (hints->li_flags & LI_V4MAPPED) != 0;
+ char *canonname = NULL;
+
+ if (getifaddrs(&results) < 0) {
+ if (errno == ENOMEM)
+ return ELI_MEMORY;
+ else
+ return ELI_SYSTEM;
+ }
+
+ for (ifa = results; ifa; ifa = ifa->ifa_next) {
+ su_localinfo_t *li;
+ su_sockaddr_t *su, su2[1];
+ socklen_t sulen;
+ int scope, flags = 0, gni_flags = 0, if_index = 0;
+ char const *ifname = 0;
+ size_t ifnamelen = 0;
+
+ /* no ip address from if that is down */
+ if ((ifa->ifa_flags & IFF_UP) == 0 && (hints->li_flags & LI_DOWN) == 0)
+ continue;
+
+ su = (su_sockaddr_t *)ifa->ifa_addr;
+
+ if (!su)
+ continue;
+
+ if (su->su_family == AF_INET) {
+ sulen = sizeof(su->su_sin);
+ scope = li_scope4(su->su_sin.sin_addr.s_addr);
+ if (v4_mapped)
+ sulen = sizeof(su->su_sin6);
+ }
+ else if (su->su_family == AF_INET6) {
+ if (IN6_IS_ADDR_MULTICAST(&su->su_sin6.sin6_addr))
+ continue;
+ sulen = sizeof(su->su_sin6);
+ scope = li_scope6(&su->su_sin6.sin6_addr);
+ }
+ else
+ continue;
+
+ if (hints->li_flags & LI_IFNAME) {
+ ifname = ifa->ifa_name;
+ if (ifname)
+ ifnamelen = strlen(ifname) + 1;
+ }
+
+ if ((hints->li_scope && (hints->li_scope & scope) == 0) ||
+ (hints->li_family && hints->li_family != su->su_family) ||
+ (hints->li_ifname && (!ifname || strcmp(hints->li_ifname, ifname))) ||
+ (hints->li_index && hints->li_index != if_index))
+ continue;
+
+ if (scope == LI_SCOPE_HOST || scope == LI_SCOPE_LINK)
+ gni_flags = NI_NUMERICHOST;
+
+ if (v4_mapped && su->su_family == AF_INET) {
+ /* Map IPv4 address to IPv6 address */
+ memset(su2, 0, sizeof(*su2));
+ su2->su_family = AF_INET6;
+ ((int32_t*)&su2->su_sin6.sin6_addr)[2] = htonl(0xffff);
+ ((int32_t*)&su2->su_sin6.sin6_addr)[3] = su->su_sin.sin_addr.s_addr;
+ su = su2;
+ }
+
+ if ((error = li_name(hints, gni_flags, su, &canonname)) < 0)
+ break;
+
+ if (error > 0) {
+ error = 0;
+ continue;
+ }
+
+ if (canonname)
+ if (strchr(canonname, ':') ||
+ canonname[strspn(canonname, "0123456789.")] == '\0')
+ flags |= LI_NUMERIC;
+
+ if (!(li = calloc(1, sizeof(*li) + sulen + ifnamelen))) {
+ SU_DEBUG_1(("su_getlocalinfo: memory exhausted\n"));
+ error = ELI_MEMORY;
+ break;
+ }
+ *return_result = li, return_result = &li->li_next;
+
+ li->li_flags = flags;
+ li->li_family = su->su_family;
+ li->li_scope = scope;
+ li->li_index = if_index;
+ li->li_addrlen = sulen;
+ li->li_addr = memcpy(li + 1, su, sulen);
+ li->li_canonname = canonname;
+ if (ifnamelen) {
+ li->li_ifname = strcpy((char *)(li + 1) + sulen, ifname);
+ }
+
+ canonname = NULL;
+ }
+
+ if (canonname)
+ free(canonname);
+
+ freeifaddrs(results);
+
+ return error;
+}
+
+#elif USE_LOCALINFO0 && HAVE_IPHLPAPI_H && SU_HAVE_IN6
+
+static
+char const *ws2ifname(DWORD iftype)
+{
+ switch (iftype) {
+ case IF_TYPE_ETHERNET_CSMACD: return "eth";
+ case IF_TYPE_IEEE80212: return "eth";
+ case IF_TYPE_FASTETHER: return "eth";
+ case IF_TYPE_GIGABITETHERNET: return "eth";
+ case IF_TYPE_ISO88025_TOKENRING: return "token";
+ case IF_TYPE_FDDI: return "fddi";
+ case IF_TYPE_PPP: return "ppp";
+ case IF_TYPE_SOFTWARE_LOOPBACK: return "lo";
+ case IF_TYPE_SLIP: return "sl";
+ case IF_TYPE_FRAMERELAY: return "fr";
+ case IF_TYPE_ATM: return "atm";
+ case IF_TYPE_HIPPI: return "hippi";
+ case IF_TYPE_ISDN: return "isdn";
+ case IF_TYPE_IEEE80211: return "wlan";
+ case IF_TYPE_ADSL: return "adsl";
+ case IF_TYPE_RADSL: return "radsl";
+ case IF_TYPE_SDSL: return "sdsl";
+ case IF_TYPE_VDSL: return "vdsl";
+ case IF_TYPE_TUNNEL: return "tunnel";
+ case IF_TYPE_IEEE1394: return "fw";
+ case IF_TYPE_OTHER:
+ default: return "other";
+ }
+}
+
+static
+int win_localinfo(su_localinfo_t const hints[1], su_localinfo_t **rresult)
+{
+ /* This is Windows XP code, for both IPv6 and IPv4. */
+ size_t iaa_size = 2048;
+ IP_ADAPTER_ADDRESSES *iaa0, *iaa;
+ int error, loopback_seen = 0;
+ int v4_mapped = (hints->li_flags & LI_V4MAPPED) != 0;
+ char *canonname = NULL;
+ su_localinfo_t *li, **next;
+ int flags = GAA_FLAG_SKIP_MULTICAST;
+ *rresult = NULL; next = rresult;
+
+ iaa0 = malloc(iaa_size);
+ if (!iaa0) {
+ SU_DEBUG_1(("su_localinfo: memory exhausted\n"));
+ error = ELI_MEMORY;
+ goto err;
+ }
+ error = GetAdaptersAddresses(hints->li_family, flags, NULL, iaa0, &iaa_size);
+ if (error == ERROR_BUFFER_OVERFLOW) {
+ if ((iaa0 = realloc(iaa0, iaa_size)))
+ error = GetAdaptersAddresses(hints->li_family, flags, NULL, iaa0, &iaa_size);
+ }
+ if (error) {
+ SU_DEBUG_1(("su_localinfo: GetAdaptersAddresses failed: %d\n", error));
+ error = ELI_SYSTEM;
+ goto err;
+ }
+
+ for (iaa = iaa0; iaa; iaa = iaa->Next) {
+ IP_ADAPTER_UNICAST_ADDRESS *ua;
+ IP_ADAPTER_UNICAST_ADDRESS lua[1];
+ int if_index = iaa->IfIndex;
+ int ifnamelen = 0;
+ char ifname[16];
+
+ for (ua = iaa->FirstUnicastAddress; ;ua = ua->Next) {
+ su_sockaddr_t *su;
+ socklen_t sulen;
+ su_sockaddr_t su2[1];
+ int scope, flags = 0, gni_flags = 0;
+
+ if (ua == NULL) {
+ /* There is no loopback interface in windows */
+ if (!loopback_seen && iaa->Next == NULL) {
+ struct sockaddr_in loopback_sin = { AF_INET, 0, {{ 127, 0, 0, 1 }}};
+
+ lua->Address.lpSockaddr = (struct sockaddr *)&loopback_sin;
+ lua->Address.iSockaddrLength = sizeof(loopback_sin);
+ lua->Next = NULL;
+
+ iaa->IfType = IF_TYPE_SOFTWARE_LOOPBACK;
+ if_index = 1;
+
+ ua = lua;
+ }
+ else
+ break;
+ }
+
+ su = (su_sockaddr_t *)ua->Address.lpSockaddr;
+ sulen = ua->Address.iSockaddrLength;
+
+ if (su->su_family == AF_INET) {
+ scope = li_scope4(su->su_sin.sin_addr.s_addr);
+ if (v4_mapped)
+ sulen = sizeof(su->su_sin6);
+ if (scope == LI_SCOPE_HOST)
+ loopback_seen = 1;
+ }
+ else if (su->su_family == AF_INET6) {
+ if (IN6_IS_ADDR_MULTICAST(&su->su_sin6.sin6_addr))
+ continue;
+ scope = li_scope6(&su->su_sin6.sin6_addr);
+ }
+ else
+ continue;
+
+ if (hints->li_flags & LI_IFNAME) {
+ snprintf(ifname, sizeof(ifname), "%s%u",
+ ws2ifname(iaa->IfType), if_index);
+ ifnamelen = strlen(ifname) + 1;
+ }
+
+ if ((hints->li_scope && (hints->li_scope & scope) == 0) ||
+ (hints->li_family && hints->li_family != su->su_family) ||
+ /* (hints->li_ifname && strcmp(hints->li_ifname, ifname) != 0) || */
+ (hints->li_index && hints->li_index != if_index))
+ continue;
+
+ if (scope == LI_SCOPE_HOST || scope == LI_SCOPE_LINK)
+ gni_flags = NI_NUMERICHOST;
+
+ if (v4_mapped && su->su_family == AF_INET) {
+ /* Map IPv4 address to IPv6 address */
+ memset(su2, 0, sizeof(*su2));
+ su2->su_family = AF_INET6;
+ ((int32_t*)&su2->su_sin6.sin6_addr)[2] = htonl(0xffff);
+ ((int32_t*)&su2->su_sin6.sin6_addr)[3] = su->su_sin.sin_addr.s_addr;
+ su = su2;
+ }
+
+ if ((error = li_name(hints, gni_flags, su, &canonname)) < 0)
+ goto err;
+ else if (error > 0)
+ continue;
+
+ if (canonname)
+ if (strchr(canonname, ':') ||
+ strspn(canonname, "0123456789.") == strlen(canonname))
+ flags |= LI_NUMERIC;
+
+ if (!(li = calloc(1, sizeof(*li) + sulen + ifnamelen))) {
+ SU_DEBUG_1(("su_getlocalinfo: memory exhausted\n"));
+ error = ELI_MEMORY; goto err;
+ }
+ *next = li, next = &li->li_next;
+
+ li->li_flags = flags;
+ li->li_family = su->su_family;
+ li->li_scope = scope;
+ li->li_index = if_index;
+ li->li_addrlen = sulen;
+ li->li_addr = memcpy(li + 1, su, sulen);
+ li->li_canonname = canonname;
+ if (ifnamelen) {
+ li->li_ifname = strcpy((char *)(li + 1) + sulen, ifname);
+ /* WideCharToMultiByte(CP_ACP, 0,
+ ifname, -1, (char *)(li + 1) + sulen, ifnamelen,
+ NULL, NULL); */
+ }
+
+ canonname = NULL;
+ }
+ }
+
+ if (iaa0) free(iaa0);
+ return 0;
+
+err:
+ if (iaa0) free(iaa0);
+ if (canonname) free(canonname);
+ su_freelocalinfo(*rresult), *rresult = NULL;
+ return error;
+}
+
+#elif HAVE_SIO_ADDRESS_LIST_QUERY
+static
+int localinfo0(su_localinfo_t const *hints, su_localinfo_t **rresult)
+{
+ /* This is Windows IPv4 code */
+ short family = AF_INET;
+ su_socket_t s;
+ union {
+ SOCKET_ADDRESS_LIST sal[1];
+#if HAVE_INTERFACE_INFO_EX
+ INTERFACE_INFO_EX ii[1];
+#else
+ INTERFACE_INFO ii[1];
+#endif
+ char buffer[2048];
+ } b = {{ 1 }};
+ DWORD salen = sizeof(b);
+ int i, error = -1;
+#if SU_HAVE_IN6
+ int v4_mapped = (hints->li_flags & LI_V4MAPPED) != 0;
+#endif
+ su_localinfo_t *li, *head = NULL, **next = &head;
+ char *canonname = NULL, *if_name = NULL;
+
+ *rresult = NULL;
+
+ s = su_socket(family, SOCK_DGRAM, 0);
+ if (s == INVALID_SOCKET) {
+ SU_DEBUG_1(("su_getlocalinfo: %s: %s\n", "su_socket",
+ su_strerror(su_errno())));
+ return -1;
+ }
+
+ /* get the list of known IP address (NT5 and up) */
+ if (WSAIoctl(s, SIO_ADDRESS_LIST_QUERY, NULL, 0,
+ &b, sizeof(b), &salen, NULL, NULL) == SOCKET_ERROR) {
+ SU_DEBUG_1(("su_getlocalinfo: %s: %s\n", "SIO_ADDRESS_LIST_QUERY",
+ su_strerror(su_errno())));
+ error = -1; goto err;
+ }
+ if (b.sal->iAddressCount < 1) {
+ SU_DEBUG_1(("su_getlocalinfo: no local addresses\n"));
+ error = -1; goto err;
+ }
+
+ for (i = 0; i < b.sal->iAddressCount; i++) {
+ su_sockaddr_t *su = (su_sockaddr_t *)b.sal->Address[i].lpSockaddr;
+#if SU_HAVE_IN6
+ socklen_t sulen = v4_mapped ? sizeof(*su) : b.sal->Address[i].iSockaddrLength;
+ su_sockaddr_t su2[1];
+#else
+ socklen_t sulen = b.sal->Address[i].iSockaddrLength;
+#endif
+ int scope, flags = 0, gni_flags = 0;
+
+ scope = li_scope4(su->su_sin.sin_addr.s_addr);
+
+ if (hints->li_scope && (hints->li_scope & scope) == 0)
+ continue;
+
+ if (scope == LI_SCOPE_HOST || scope == LI_SCOPE_LINK)
+ gni_flags = NI_NUMERICHOST;
+
+ if (!(li = calloc(1, sizeof(*li) + sulen))) {
+ SU_DEBUG_1(("su_getlocalinfo: memory exhausted\n"));
+ error = -1; goto err;
+ }
+ *next = li, next = &li->li_next;
+
+#if SU_HAVE_IN6
+ if (v4_mapped) {
+ /* Map IPv4 address to IPv6 address */
+ memset(su2, 0, sizeof(*su2));
+ su2->su_family = AF_INET6;
+ ((int32_t*)&su2->su_sin6.sin6_addr)[2] = htonl(0xffff);
+ ((int32_t*)&su2->su_sin6.sin6_addr)[3] = su->su_sin.sin_addr.s_addr;
+ su = su2;
+ }
+#endif
+
+ if ((error = li_name(hints, gni_flags, su, &canonname)) < 0)
+ goto err;
+ else if (error > 0)
+ continue;
+
+ if (canonname)
+ if (strchr(canonname, ':') ||
+ strspn(canonname, "0123456789.") == strlen(canonname))
+ flags |= LI_NUMERIC;
+
+ li->li_flags = flags;
+ li->li_family = su->su_family;
+ li->li_scope = scope;
+ li->li_index = i;
+ li->li_addrlen = su_sockaddr_size(su);
+ li->li_addr = su;
+ li->li_canonname = canonname, canonname = NULL;
+ if (hints->li_flags & LI_IFNAME)
+ li->li_ifname = if_name;
+ li->li_addr = (su_sockaddr_t *)(li + 1);
+ li->li_addrlen = sulen;
+ memcpy(li->li_addr, su, sulen);
+ }
+
+ *rresult = head;
+ su_close(s);
+
+ return 0;
+
+err:
+ if (canonname) free(canonname);
+ su_freelocalinfo(head);
+ su_close(s);
+
+ return error;
+}
+#endif
+
+static
+int li_name(su_localinfo_t const *hints,
+ int gni_flags,
+ su_sockaddr_t const *su,
+ char **ccanonname)
+{
+ char name[SU_MAXHOST];
+ int error;
+ int flags = hints->li_flags;
+
+ *ccanonname = NULL;
+
+ if ((flags & LI_CANONNAME) || hints->li_canonname) {
+ if ((flags & LI_NAMEREQD) == LI_NAMEREQD)
+ gni_flags |= NI_NAMEREQD;
+ if (flags & LI_NUMERIC)
+ gni_flags |= NI_NUMERICHOST;
+
+ error = su_getnameinfo(su, su_sockaddr_size(su),
+ name, sizeof(name), NULL, 0,
+ gni_flags);
+ if (error) {
+ if ((flags & LI_NAMEREQD) == LI_NAMEREQD)
+ return 1;
+ SU_DEBUG_7(("li_name: getnameinfo() failed\n"));
+ if (!inet_ntop(su->su_family, SU_ADDR(su), name, sizeof name))
+ return ELI_RESOLVER;
+ }
+
+ if (hints->li_canonname && strcasecmp(name, hints->li_canonname))
+ return 1;
+
+ if (!(flags & LI_CANONNAME))
+ return 0;
+
+ if (!(*ccanonname = strdup(name)))
+ return ELI_MEMORY;
+ }
+ return 0;
+}
+
+static
+void li_sort(su_localinfo_t *i, su_localinfo_t **rresult)
+{
+ su_localinfo_t *li, **lli;
+
+#define LI_MAPPED(li) \
+ ((li)->li_family == AF_INET6 && \
+ (IN6_IS_ADDR_V4MAPPED(&(li)->li_addr->su_sin6.sin6_addr) || \
+ IN6_IS_ADDR_V4COMPAT(&(li)->li_addr->su_sin6.sin6_addr)))
+
+ /* Sort addresses according to scope (and mappedness) */
+ for (li = i; li; li = i) {
+ i = li->li_next;
+ for (lli = rresult; *lli; lli = &(*lli)->li_next) {
+ if ((*lli)->li_scope < li->li_scope)
+ break;
+#if SU_HAVE_IN6
+ if (LI_MAPPED(*lli) > LI_MAPPED(li))
+ break;
+#endif
+ }
+ li->li_next = *lli;
+ *lli = li;
+ }
+}
+
+/**Get local IP address.
+ *
+ * @deprecated
+ * Use su_getlocalinfo() instead.
+ */
+int su_getlocalip(su_sockaddr_t *sa)
+{
+ su_localinfo_t *li = NULL, hints[1] = {{ 0 }};
+
+ hints->li_family = sa->su_sa.sa_family ? sa->su_sa.sa_family : AF_INET;
+
+ if (su_getlocalinfo(hints, &li) == 0) {
+ memcpy(sa, li->li_addr, li->li_addrlen);
+ su_freelocalinfo(li);
+ return 0;
+ }
+ else
+ return -1;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_log.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_log.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,253 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_log
+ * @CFILE su_log.c
+ *
+ * Implementation of generic logging interface.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Fri Feb 23 17:30:13 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <sofia-sip/su_log.h>
+#include <sofia-sip/su_errno.h>
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#if SU_HAVE_PTHREADS
+#include <pthread.h>
+#define SU_LOG_IS_INIT(log) pthread_mutex_trylock((log)->log_init)
+#define SU_LOG_DO_INIT(log)
+#define SU_LOG_LOCK(log) pthread_mutex_lock((log)->log_lock)
+#define SU_LOG_UNLOCK(log) pthread_mutex_unlock((log)->log_lock)
+#else
+#define SU_LOG_IS_INIT(log) ((log)->log_init)
+#define SU_LOG_DO_INIT(log) ((log)->log_init = 1)
+#define SU_LOG_LOCK(log)
+#define SU_LOG_UNLOCK(log)
+#endif
+
+/**@defgroup su_log Logging Interface
+ *
+ * Generic logging interface.
+ *
+ * The @b su_log submodule contains a generic logging interface. The
+ * interface provides means for redirecting the log and filtering log
+ * messages based on message priority.
+ *
+ * @sa @ref debug_logs, <sofia-sip/su_log.h>,
+ * su_llog(), su_vllog(), #su_log_t, #SU_LOG,
+ * SU_DEBUG_0(), SU_DEBUG_1(), SU_DEBUG_2(), SU_DEBUG_3(), SU_DEBUG_5(),
+ * SU_DEBUG_7(), SU_DEBUG_9()
+ */
+
+/** Log message of socket error @errcode at level 0. */
+void su_perror2(const char *s, int errcode)
+{
+ su_log("%s: %s\n", s, su_strerror(errcode));
+}
+
+/** Log socket error message at level 0. */
+void su_perror(const char *s)
+{
+ su_perror2(s, su_errno());
+}
+
+/** Log a message to default log.
+ *
+ * This function is a replacement for printf().
+ *
+ * Messages are always logged to the default log.
+ */
+void su_log(char const *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ su_vllog(su_log_default, 0, fmt, ap);
+ va_end(ap);
+}
+
+/** Log a message with level.
+ *
+ * @note This function is used mainly by SU_DEBUG_n() macros.
+ */
+void su_llog(su_log_t *log, unsigned level, char const *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ su_vllog(log, level, fmt, ap);
+ va_end(ap);
+}
+
+/** Log a message with level (stdarg version). */
+void su_vllog(su_log_t *log, unsigned level, char const *fmt, va_list ap)
+{
+ su_logger_f *logger;
+ void *stream;
+
+ assert(log);
+
+ if (!log->log_init)
+ su_log_init(log);
+
+ if (log->log_init > 1 ?
+ level > log->log_level :
+ level > su_log_default->log_level)
+ return;
+
+ logger = log->log_logger;
+ stream = log->log_stream;
+
+ if (!logger) {
+ logger = su_log_default->log_logger;
+ stream = su_log_default->log_stream;
+ }
+
+ if (logger)
+ logger(stream, fmt, ap);
+}
+
+static char const not_initialized[1];
+static char const *explicitly_initialized = not_initialized;
+
+/** Initialize a log */
+void su_log_init(su_log_t *log)
+{
+ char *env;
+
+ if (log->log_init)
+ return;
+
+ if (explicitly_initialized == not_initialized)
+ explicitly_initialized = getenv("SHOW_DEBUG_LEVELS");
+
+ if (log != su_log_default && !su_log_default->log_init)
+ su_log_init(su_log_default);
+
+ if (log->log_env && (env = getenv(log->log_env))) {
+ int level = atoi(env);
+
+ /* Why? */
+ /* if (level == 0) level = 1; */
+ log->log_level = level;
+ log->log_init = 2;
+
+ if (explicitly_initialized)
+ su_llog(log, 0, "%s: initialized log to level %u (%s=%s)\n",
+ log->log_name, log->log_level, log->log_env, env);
+ }
+ else {
+ log->log_level = log->log_default;
+ log->log_init = 1;
+ if (explicitly_initialized) {
+ if (log != su_log_default)
+ su_llog(log, 0, "%s: logging at default level %u\n",
+ log->log_name, su_log_default->log_level);
+ else
+ su_llog(log, 0, "%s: initialized log to level %u (default)\n",
+ log->log_name, log->log_level);
+ }
+ }
+}
+
+/**Redirect a log.
+ *
+ * The function su_log_redirect() redirects the su_log() output to
+ * @a logger function. The @a logger function has following prototype:
+ *
+ * @code
+ * void logger(void *logarg, char const *format, va_list ap);
+ * @endcode
+ *
+ * If @a logger is NULL, the default logger will be used. If @a log is NULL,
+ * the default logger is changed.
+ */
+void su_log_redirect(su_log_t *log, su_logger_f *logger, void *logarg)
+{
+ if (log == NULL)
+ log = su_log_default;
+ /* XXX - locking ? */
+ log->log_logger = logger;
+ log->log_stream = logarg;
+}
+
+/** Set log level.
+ *
+ * The function su_log_set_level() sets the logging level. The log events
+ * have certain level (0..9); if logging level is lower than the level of
+ * the event, the log message is ignored.
+ *
+ * If @a log is NULL, the default log level is changed.
+ */
+void su_log_set_level(su_log_t *log, unsigned level)
+{
+ if (log == NULL)
+ log = su_log_default;
+
+ log->log_level = level;
+ log->log_init = 2;
+
+ if (explicitly_initialized == not_initialized)
+ explicitly_initialized = getenv("SHOW_DEBUG_LEVELS");
+
+ if (explicitly_initialized)
+ su_llog(log, 0, "%s: set log to level %u\n",
+ log->log_name, log->log_level);
+}
+
+/** Set log level.
+ *
+ * The function su_log_soft_set_level() sets the logging level if it is not
+ * already set, or the environment variable controlling the log level is not
+ * set.
+ *
+ * The log events have certain level (0..9); if logging level is lower than
+ * the level of the event, the log message is ignored.
+ *
+ * If @a log is NULL, the default log level is changed.
+ */
+void su_log_soft_set_level(su_log_t *log, unsigned level)
+{
+ if (log == NULL)
+ log = su_log_default;
+ if (log->log_init > 1)
+ return;
+ if (log->log_env && getenv(log->log_env)) {
+ su_log_init(log);
+ } else {
+ log->log_level = level;
+ log->log_init = 2;
+ if (explicitly_initialized)
+ su_llog(log, 0, "%s: soft set log to level %u\n",
+ log->log_name, log->log_level);
+ }
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_md5.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_md5.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,491 @@
+#define compile \
+{ gcc -o su_md5 -O2 -g -Wall -DTEST -I. su_md5.c } ; exit 0
+/* -*- c-style: java -*- */
+
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/*
+ * This code implements the MD5 message-digest algorithm. The algorithm is
+ * due to Ron Rivest. This code was initially written by Colin Plumb in
+ * 1993, no copyright is claimed. This code is in the public domain; do with
+ * it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc. This code has
+ * been tested against that, and is equivalent, except that you don't need
+ * to include two pages of legalese with every copy.
+ */
+
+/** @ingroup su_md5
+ *
+ * @CFILE su_md5.c MD5 Implementation
+ *
+ * To compute the message digest of a chunk of bytes, declare an su_md5_t
+ * context structure, pass it to su_md5_init(), call su_md5_update() as
+ * needed on buffers full of bytes, and then call su_md5_digest(), which
+ * will fill a supplied 16-byte array with the current digest.
+ *
+ * @note
+ * This code was modified in 1997 by Jim Kingdon of Cyclic Software to
+ * not require an integer type which is exactly 32 bits. This work
+ * draws on the changes for the same purpose by Tatu Ylonen
+ * <ylo at cs.hut.fi> as part of SSH, but since I didn't actually use
+ * that code, there is no copyright issue. I hereby disclaim
+ * copyright in any changes I have made; this code remains in the
+ * public domain.
+ *
+ * @note Regarding su_* namespace: this avoids potential conflicts
+ * with libraries such as some versions of Kerberos. No particular
+ * need to worry about whether the system supplies an MD5 library, as
+ * this file is only about 3k of object code.
+ *
+ */
+
+#include <string.h> /* for memcpy() and memset() */
+
+#include "sofia-sip/su_md5.h"
+
+static void su_md5_transform(uint32_t buf[4], const unsigned char inraw[64]);
+
+/* Little-endian byte-swapping routines. Note that these do not depend on
+ the size of datatypes such as cvs_uint32, nor do they require us to
+ detect the endianness of the machine we are running on. It is possible
+ they should be macros for speed, but I would be surprised if they were a
+ performance bottleneck for MD5. These are inlined by any sane compiler,
+ anyways. */
+
+static uint32_t getu32(const unsigned char *addr)
+{
+ return (((((unsigned long)addr[3] << 8) | addr[2]) << 8)
+ | addr[1]) << 8 | addr[0];
+}
+
+static void putu32(uint32_t data, unsigned char *addr)
+{
+ addr[0] = (unsigned char)data;
+ addr[1] = (unsigned char)(data >> 8);
+ addr[2] = (unsigned char)(data >> 16);
+ addr[3] = (unsigned char)(data >> 24);
+}
+
+/** Initialize MD5 context.
+ *
+ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ *
+ * @param ctx Pointer to context structure.
+ */
+void
+su_md5_init(su_md5_t *ctx)
+{
+ ctx->buf[0] = 0x67452301;
+ ctx->buf[1] = 0xefcdab89;
+ ctx->buf[2] = 0x98badcfe;
+ ctx->buf[3] = 0x10325476;
+
+ ctx->bits[0] = 0;
+ ctx->bits[1] = 0;
+}
+
+/** Clear MD5 context.
+ *
+ * The function su_md5_deinit() clears MD5 context.
+ *
+ * @param context Pointer to MD5 context structure.
+ */
+void su_md5_deinit(su_md5_t *context)
+{
+ memset(context, 0, sizeof *context);
+}
+
+/** Update MD5 context.
+ *
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ *
+ * @param ctx Pointer to context structure
+ * @param b Pointer to data
+ * @param len Length of @a b as bytes
+ */
+void
+su_md5_update(su_md5_t *ctx,
+ void const *b,
+ usize_t len)
+{
+ unsigned char const *buf = (unsigned char const *)b;
+ uint32_t t;
+
+ /* Update bitcount */
+
+ t = ctx->bits[0];
+ if ((ctx->bits[0] = (t + ((uint32_t)len << 3)) & 0xffffffff) < t)
+ ctx->bits[1]++; /* Carry from low to high */
+ ctx->bits[1] += (uint32_t)(len >> 29);
+
+ t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
+
+ /* Handle any leading odd-sized chunks */
+
+ if ( t ) {
+ unsigned char *p = ctx->in + t;
+
+ t = 64 - t;
+
+ if (len < t) {
+ memcpy(p, buf, len);
+ return;
+ }
+
+ memcpy(p, buf, t);
+ su_md5_transform (ctx->buf, ctx->in);
+ buf += t;
+ len -= t;
+ }
+
+ /* Process data in 64-byte chunks */
+
+ while (len >= 64) {
+ su_md5_transform(ctx->buf, buf);
+ buf += 64;
+ len -= 64;
+ }
+
+ /* Handle any remaining bytes of data. */
+ memcpy(ctx->in, buf, len);
+}
+
+/** Copy memory, fix case to lower. */
+static
+void mem_i_cpy(unsigned char *d, unsigned char const *s, size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len; i++)
+ if (s[i] >= 'A' && s[i] <= 'Z')
+ d[i] = s[i] + ('a' - 'A');
+ else
+ d[i] = s[i];
+}
+
+/**Update MD5 context.
+ *
+ * The function su_md5_iupdate() updates context to reflect the
+ * concatenation of another buffer full of case-independent characters.
+ *
+ * @param ctx Pointer to context structure
+ * @param b Pointer to data
+ * @param len Length of @a b as bytes
+ */
+void
+su_md5_iupdate(su_md5_t *ctx,
+ void const *b,
+ usize_t len)
+{
+ unsigned char const *buf = (unsigned char const *)b;
+ uint32_t t;
+
+ /* Update bitcount */
+
+ t = ctx->bits[0];
+ if ((ctx->bits[0] = (t + ((uint32_t)len << 3)) & 0xffffffff) < t)
+ ctx->bits[1]++; /* Carry from low to high */
+ ctx->bits[1] += (uint32_t)(len >> 29);
+
+ t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
+
+ /* Handle any leading odd-sized chunks */
+
+ if ( t ) {
+ unsigned char *p = ctx->in + t;
+
+ t = sizeof(ctx->in) - t;
+
+ if (len < t) {
+ mem_i_cpy(p, buf, len);
+ return;
+ }
+ mem_i_cpy(p, buf, t);
+ su_md5_transform (ctx->buf, ctx->in);
+ buf += t;
+ len -= t;
+ }
+
+ /* Process data in 64-byte chunks */
+ while (len >= sizeof(ctx->in)) {
+ mem_i_cpy(ctx->in, buf, sizeof(ctx->in));
+ su_md5_transform(ctx->buf, ctx->in);
+ buf += sizeof(ctx->in);
+ len -= sizeof(ctx->in);
+ }
+
+ /* Handle any remaining bytes of data. */
+ mem_i_cpy(ctx->in, buf, len);
+}
+
+/** Update MD5 context with contents of string.
+ *
+ * The function su_md5_strupdate() updates context to reflect the
+ * concatenation of NUL-terminated string.
+ *
+ * @param ctx Pointer to context structure
+ * @param s Pointer to string
+ */
+void su_md5_strupdate(su_md5_t *ctx, char const *s)
+{
+ if (s)
+ su_md5_update(ctx, s, strlen(s));
+}
+
+/** Update MD5 context with contents of string, including final NUL.
+ *
+ * The function su_md5_str0update() updates context to reflect the
+ * concatenation of NUL-terminated string, including the final NUL.
+ *
+ * @param ctx Pointer to context structure
+ * @param s Pointer to string
+ */
+void su_md5_str0update(su_md5_t *ctx, char const *s)
+{
+ if (!s)
+ s = "";
+
+ su_md5_update(ctx, s, strlen(s) + 1);
+}
+
+/** Update MD5 context with contents of case-independent string.
+ *
+ * The function su_md5_striupdate() updates context to reflect the
+ * concatenation of NUL-terminated string.
+ *
+ * @param ctx Pointer to context structure
+ * @param s Pointer to string
+ */
+void su_md5_striupdate(su_md5_t *ctx, char const *s)
+{
+ if (s)
+ su_md5_iupdate(ctx, s, strlen(s));
+}
+
+/** Update MD5 context with contents of case-independent string, including
+ * final NUL.
+ *
+ * The function su_md5_stri0update() updates context to reflect the
+ * concatenation of NUL-terminated string, including the final NUL.
+ *
+ * @param ctx Pointer to context structure
+ * @param s Pointer to string
+ */
+void su_md5_stri0update(su_md5_t *ctx, char const *s)
+{
+ if (!s)
+ s = "";
+
+ su_md5_iupdate(ctx, s, strlen(s) + 1);
+}
+
+
+/** Generate digest.
+ *
+ * Final wrapup. Pad message to 64-byte boundary with the bit pattern 1 0*
+ * (64-bit count of bits processed, MSB-first), then concatenate message
+ * with its length (measured in bits) as 64-byte big-endian integer.
+ *
+ * @param context Pointer to context structure
+ * @param digest Digest array to be filled
+ */
+void
+su_md5_digest(su_md5_t const *context, uint8_t digest[16])
+{
+ unsigned count;
+ unsigned char *p;
+
+ su_md5_t ctx[1];
+
+ ctx[0] = context[0];
+
+ /* Compute number of bytes mod 64 */
+ count = (ctx->bits[0] >> 3) & 0x3F;
+
+ /* Set the first char of padding to 0x80. This is safe since there is
+ always at least one byte free */
+ p = ctx->in + count;
+ *p++ = 0x80;
+
+ /* Bytes of padding needde to make 64 bytes */
+ count = 64 - 1 - count;
+
+ /* Pad out to 56 mod 64 */
+ if (count < 8) {
+ /* Two lots of padding: Pad the first block to 64 bytes */
+ memset(p, 0, count);
+ su_md5_transform (ctx->buf, ctx->in);
+
+ /* Now fill the next block with 56 bytes */
+ memset(ctx->in, 0, 56);
+ } else {
+ /* Pad block to 56 bytes */
+ memset(p, 0, count-8);
+ }
+
+ /* Append length in bits and transform */
+ putu32(ctx->bits[0], ctx->in + 56);
+ putu32(ctx->bits[1], ctx->in + 60);
+
+ su_md5_transform(ctx->buf, ctx->in);
+ putu32(ctx->buf[0], digest);
+ putu32(ctx->buf[1], digest + 4);
+ putu32(ctx->buf[2], digest + 8);
+ putu32(ctx->buf[3], digest + 12);
+ memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
+}
+
+void su_md5_hexdigest(su_md5_t const *ctx,
+ char digest[2 * SU_MD5_DIGEST_SIZE + 1])
+{
+ uint8_t b, bin[SU_MD5_DIGEST_SIZE];
+ short i, j;
+
+ su_md5_digest(ctx, bin);
+
+ for (i = j = 0; i < 16; i++) {
+ b = (bin[i] >> 4) & 15;
+ digest[j++] = b + (b > 9 ? 'a' - 10 : '0');
+ b = bin[i] & 15;
+ digest[j++] = b + (b > 9 ? 'a' - 10 : '0');
+ }
+
+ digest[j] = '\0';
+}
+
+#ifndef ASM_MD5
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+ ( w += f(x, y, z) + data, w &= 0xffffffff, w = w<<s | w>>(32-s), w += x )
+
+/** @internal
+ *
+ * Add 64 bytes of data to hash.
+ *
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data. MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+static void
+su_md5_transform(uint32_t buf[4], const unsigned char inraw[64])
+{
+ register uint32_t a, b, c, d;
+ uint32_t in[16];
+ int i;
+
+ for (i = 0; i < 16; ++i)
+ in[i] = getu32 (inraw + 4 * i);
+
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[3];
+
+ MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+#endif
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_module_debug.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_module_debug.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,53 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_MODULE_DEBUG_H
+/** Defined when <su_module_debug.h> has been included. */
+#define SU_MODULE_DEBUG_H
+
+/**@ingroup su_log
+ * @file su_module_debug.h
+ * @brief Debug log for @b su module
+ *
+ * The su_module_debug.h defines a common debug log #su_log_global for all
+ * functions within @b su module.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Jan 29 18:18:49 2003 ppessi
+ *
+ */
+
+#include <sofia-sip/su_log.h>
+
+SOFIA_BEGIN_DECLS
+
+/** Debugging log for @b su module. */
+SOFIAPUBVAR su_log_t su_log_global[];
+#define SU_LOG (su_log_global)
+#include <sofia-sip/su_debug.h>
+
+SOFIA_END_DECLS
+
+#endif /* !defined SU_MODULE_DEBUG_H */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_os_nw.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_os_nw.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,307 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_os_nw
+ *
+ * @CFILE su_os_nw.c
+ * Implementation of OS-specific network events interface.
+ *
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ * @date Created: Fri Aug 11 07:30:04 2006 mela
+ *
+ */
+
+#include "config.h"
+#include <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+
+#define SU_MSG_ARG_T struct su_network_changed_s
+
+#include "sofia-sip/su.h"
+#include "sofia-sip/su_alloc.h"
+#include "sofia-sip/su_wait.h"
+#include "sofia-sip/su_debug.h"
+#include "sofia-sip/su_os_nw.h"
+#include "sofia-sip/su_debug.h"
+
+/* Works only with pthreads */
+#if SU_HAVE_PTHREADS
+
+#include <pthread.h>
+
+#if defined(__APPLE_CC__)
+#include <AvailabilityMacros.h>
+#include <sys/cdefs.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <SystemConfiguration/SCDynamicStore.h>
+#include <SystemConfiguration/SCDynamicStoreKey.h>
+#include <SystemConfiguration/SCSchemaDefinitions.h>
+#endif /* __APPLE_CC__ */
+
+struct su_network_changed_s {
+ su_root_t *su_root;
+ su_home_t *su_home;
+
+#if defined (__APPLE_CC__)
+ SCDynamicStoreRef su_storeRef[1];
+ CFRunLoopSourceRef su_sourceRef[1];
+#endif
+
+ pthread_t su_os_thread;
+
+ su_network_changed_f *su_network_changed_cb;
+ su_network_changed_magic_t *su_network_changed_magic;
+};
+
+#if defined(__APPLE_CC__)
+static void su_nw_changed_msg_recv(su_root_magic_t *rm,
+ su_msg_r msg,
+ su_network_changed_t *snc)
+{
+ su_network_changed_magic_t *magic = snc->su_network_changed_magic;
+
+ assert(magic);
+
+ /* SU_DEBUG_5(("su_nw_changed_msg_recv: entering.\n")); */
+
+ snc->su_network_changed_cb(magic, snc->su_root);
+
+ return;
+}
+
+
+void nw_changed_cb(SCDynamicStoreRef store,
+ CFArrayRef changedKeys,
+ void *info)
+{
+ su_network_changed_t *snc = (su_network_changed_t *) info;
+ su_network_changed_t *snc2;
+ su_msg_r rmsg = SU_MSG_R_INIT;
+
+ SU_DEBUG_7(("nw_changed_cb: entering.\n"));
+
+ if (su_msg_create(rmsg,
+ su_root_task(snc->su_root),
+ su_root_task(snc->su_root),
+ su_nw_changed_msg_recv,
+ sizeof *snc) == SU_FAILURE) {
+
+ return;
+ }
+
+ snc2 = su_msg_data(rmsg); assert(snc2);
+ snc2->su_root = snc->su_root;
+ snc2->su_home = snc->su_home;
+ memcpy(snc2->su_storeRef, snc->su_storeRef, sizeof(SCDynamicStoreRef));
+ memcpy(snc2->su_sourceRef, snc->su_sourceRef, sizeof(CFRunLoopSourceRef));
+ snc2->su_os_thread = snc->su_os_thread;
+ snc2->su_network_changed_cb = snc->su_network_changed_cb;
+ snc2->su_network_changed_magic = snc->su_network_changed_magic;
+
+ if (su_msg_send(rmsg) == SU_FAILURE) {
+ su_msg_destroy(rmsg);
+ return;
+ }
+
+ return;
+}
+
+static OSStatus
+CreateIPAddressListChangeCallbackSCF(SCDynamicStoreCallBack callback,
+ void *contextPtr,
+ SCDynamicStoreRef *storeRef,
+ CFRunLoopSourceRef *sourceRef)
+ // Create a SCF dynamic store reference and a
+ // corresponding CFRunLoop source. If you add the
+ // run loop source to your run loop then the supplied
+ // callback function will be called when local IP
+ // address list changes.
+{
+ OSStatus err = 0;
+ SCDynamicStoreContext context = {0, NULL, NULL, NULL, NULL};
+ SCDynamicStoreRef ref;
+ CFStringRef pattern;
+ CFArrayRef patternList;
+ CFRunLoopSourceRef rls;
+
+ assert(callback != NULL);
+ assert( storeRef != NULL);
+ assert(*storeRef == NULL);
+ assert( sourceRef != NULL);
+ assert(*sourceRef == NULL);
+
+ ref = NULL;
+ pattern = NULL;
+ patternList = NULL;
+ rls = NULL;
+
+ // Create a connection to the dynamic store, then create
+ // a search pattern that finds all IPv4 entities.
+ // The pattern is "State:/Network/Service/[^/]+/IPv4".
+
+ context.info = contextPtr;
+ ref = SCDynamicStoreCreate( NULL,
+ CFSTR("AddIPAddressListChangeCallbackSCF"),
+ callback,
+ &context);
+ //err = MoreSCError(ref);
+ if (err == noErr) {
+ pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(
+ NULL,
+ kSCDynamicStoreDomainState,
+ kSCCompAnyRegex,
+ kSCEntNetIPv4);
+ //err = MoreSCError(pattern);
+ }
+
+ // Create a pattern list containing just one pattern,
+ // then tell SCF that we want to watch changes in keys
+ // that match that pattern list, then create our run loop
+ // source.
+
+ if (err == noErr) {
+ patternList = CFArrayCreate(NULL,
+ (const void **) &pattern, 1,
+ &kCFTypeArrayCallBacks);
+ //err = CFQError(patternList);
+ }
+ if (err == noErr) {
+ //err = MoreSCErrorBoolean(
+ SCDynamicStoreSetNotificationKeys(
+ ref,
+ NULL,
+ patternList);
+ // );
+ }
+ if (err == noErr) {
+ rls = SCDynamicStoreCreateRunLoopSource(NULL, ref, 0);
+ //err = MoreSCError(rls);
+ }
+
+ CFRunLoopAddSource(CFRunLoopGetCurrent(), rls,
+ kCFRunLoopDefaultMode);
+
+ // Clean up.
+
+ //CFQRelease(pattern);
+ //CFQRelease(patternList);
+ if (err != noErr) {
+ //CFQRelease(ref);
+ ref = NULL;
+ }
+ *storeRef = ref;
+ *sourceRef = rls;
+
+ assert( (err == noErr) == (*storeRef != NULL) );
+ assert( (err == noErr) == (*sourceRef != NULL) );
+
+ return err;
+}
+#endif /* __APPLE_CC__ */
+
+
+#if defined(__APPLE_CC__)
+static void *su_start_nw_os_thread(void *ptr)
+{
+ su_network_changed_t *snc = (su_network_changed_t *) ptr;
+
+ assert(snc);
+
+ CreateIPAddressListChangeCallbackSCF(nw_changed_cb,
+ (void *) snc,
+ snc->su_storeRef,
+ snc->su_sourceRef);
+
+ CFRunLoopRun();
+
+ return NULL;
+}
+#endif
+
+/** Register a callback for the network change event.
+ *
+ * @since New in @VERSION_1_12_2.
+ */
+su_network_changed_t
+*su_root_add_network_changed(su_home_t *home, su_root_t *root,
+ su_network_changed_f *network_changed_cb,
+ su_network_changed_magic_t *magic)
+{
+#if defined (__APPLE_CC__)
+ su_network_changed_t *snc = NULL;
+#endif
+
+ assert(home && root && network_changed_cb && magic);
+
+ /* Not implemented for others than OSX */
+#if !defined (__APPLE_CC__)
+ return NULL;
+#else
+
+ snc = su_zalloc(home, sizeof *snc);
+
+ if (!snc)
+ return NULL;
+
+ snc->su_home = home;
+ snc->su_root = root;
+ snc->su_network_changed_cb = network_changed_cb;
+ snc->su_network_changed_magic = magic;
+
+ if ((pthread_create(&(snc->su_os_thread), NULL,
+ su_start_nw_os_thread,
+ (void *) snc)) != 0) {
+ return NULL;
+ }
+
+ return snc;
+#endif
+}
+
+/** Remove a callback registered for the network change event.
+ *
+ * @since New in @VERSION_1_12_2.
+ */
+int su_root_remove_network_changed(su_network_changed_t *snc)
+{
+ return -1;
+}
+
+#else
+
+su_network_changed_t
+*su_root_add_network_changed(su_home_t *home, su_root_t *root,
+ su_network_changed_f *network_changed_cb,
+ su_network_changed_magic_t *magic)
+{
+ return NULL;
+}
+
+int su_root_remove_network_changed(su_network_changed_t *snc)
+{
+ return -1;
+}
+
+#endif /* SU_HAVE_PTHREADS */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_osx_runloop.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_osx_runloop.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1787 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_wait
+ * @CFILE su_osx_runloop.c
+ *
+ * OS-Independent Socket Syncronization Interface.
+ *
+ * This looks like nth reincarnation of "reactor". It implements the
+ * poll/select/WaitForMultipleObjects and message passing functionality.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Kai Vehmanen <kai.vehmanen at nokia.com>
+ *
+ * @date Created: Tue Sep 14 15:51:04 1999 ppessi
+ */
+
+#include "config.h"
+
+/* React to multiple events per one poll() to make sure
+ * that high-priority events can never completely mask other events.
+ * Enabled by default on all platforms except WIN32 */
+#ifndef WIN32
+#define SU_ENABLE_MULTISHOT_POLL 1
+#else
+#define SU_ENABLE_MULTISHOT_POLL 0
+#endif
+
+#include <stdlib.h>
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <errno.h>
+
+#define SU_PORT_IMPLEMENTATION 1
+
+#include "sofia-sip/su.h"
+#include "su_port.h"
+#include "sofia-sip/su_osx_runloop.h"
+#include "sofia-sip/su_alloc.h"
+#include "sofia-sip/su_debug.h"
+
+#if HAVE_FUNC
+#define enter (void)SU_DEBUG_9(("%s: entering\n", __func__))
+#elif HAVE_FUNCTION
+#define enter (void)SU_DEBUG_9(("%s: entering\n", __FUNCTION__))
+#else
+#define enter (void)0
+#endif
+
+
+#if SU_HAVE_PTHREADS
+/* Pthread implementation */
+#include <pthread.h>
+#define SU_HAVE_MBOX 1
+#else
+#define SU_HAVE_MBOX 0
+#endif
+
+#if HAVE_SOCKETPAIR
+#define MBOX_SEND 1
+#else
+#define MBOX_SEND 0
+#endif
+
+static su_port_t *su_osx_runloop_create(void) __attribute__((__malloc__));
+
+/* Callback for CFObserver and CFSocket */
+static
+void cf_observer_cb(CFRunLoopObserverRef observer,
+ CFRunLoopActivity activity,
+ void *info);
+static void su_port_osx_socket_cb(CFSocketRef s,
+ CFSocketCallBackType callbackType,
+ CFDataRef address,
+ const void *data,
+ void *info);
+static CFSocketCallBackType map_poll_event_to_cf_event(int events);
+
+static void su_port_osx_lock(su_port_t *self, char const *who);
+static void su_port_osx_unlock(su_port_t *self, char const *who);
+static void su_port_osx_incref(su_port_t *self, char const *who);
+static void su_port_osx_decref(su_port_t *self, int blocking, char const *who);
+
+static int su_port_osx_send(su_port_t *self, su_msg_r rmsg);
+
+static int su_port_osx_register(su_port_t *self,
+ su_root_t *root,
+ su_wait_t *wait,
+ su_wakeup_f callback,
+ su_wakeup_arg_t *arg,
+ int priority);
+static int su_port_osx_unregister(su_port_t *port,
+ su_root_t *root,
+ su_wait_t *wait,
+ su_wakeup_f callback,
+ su_wakeup_arg_t *arg);
+
+static int su_port_osx_deregister(su_port_t *self, int i);
+
+static int su_port_osx_unregister_all(su_port_t *self,
+ su_root_t *root);
+
+static int su_port_osx_getmsgs(su_port_t *self);
+static
+int su_port_osx_eventmask(su_port_t *self, int index, int socket, int events);
+static
+void su_port_osx_run(su_port_t *self);
+static
+void su_port_osx_break(su_port_t *self);
+static
+su_duration_t su_port_osx_step(su_port_t *self, su_duration_t tout);
+
+#if 0
+unsigned su_port_query(su_port_t *, su_wait_t *, unsigned n_waits);
+void su_port_event(su_port_t *, su_wait_t *waitobj);
+#endif
+
+static
+int su_port_osx_own_thread(su_port_t const *port);
+
+static
+int su_port_osx_add_prepoll(su_port_t *port,
+ su_root_t *root,
+ su_prepoll_f *,
+ su_prepoll_magic_t *);
+
+static
+int su_port_osx_remove_prepoll(su_port_t *port,
+ su_root_t *root);
+
+static
+su_timer_t **su_port_osx_timers(su_port_t *port);
+
+static
+int su_port_osx_multishot(su_port_t *port, int multishot);
+
+static
+int su_port_osx_threadsafe(su_port_t *port);
+
+static
+int su_port_osx_yield(su_port_t *port);
+
+su_port_vtable_t const su_port_osx_vtable[1] =
+ {{
+ /* su_vtable_size: */ sizeof su_port_osx_vtable,
+ su_port_osx_lock,
+ su_port_osx_unlock,
+ su_port_osx_incref,
+ su_port_osx_decref,
+ NULL /* su_port_osx_runloop */, /* XXX - was: gsource, */
+ su_port_osx_send,
+ su_port_osx_register,
+ su_port_osx_unregister,
+ su_port_osx_deregister,
+ su_port_osx_unregister_all,
+ su_port_osx_eventmask,
+ su_port_osx_run,
+ su_port_osx_break,
+ su_port_osx_step,
+ su_port_osx_own_thread,
+ su_port_osx_add_prepoll,
+ su_port_osx_remove_prepoll,
+ su_port_osx_timers,
+ su_port_osx_multishot,
+ su_port_osx_threadsafe,
+ su_port_osx_yield
+ }};
+
+static int su_port_osx_wait_events(su_port_t *self, su_duration_t tout);
+
+
+/* *
+ * Port is a per-thread reactor.
+ *
+ * Multiple root objects executed by single thread share a su_port_t object.
+ */
+struct su_port_s {
+ su_home_t sup_home[1];
+
+ su_port_vtable_t const *sup_vtable;
+
+ unsigned sup_running;
+ unsigned sup_source_fired;
+
+
+#if SU_HAVE_PTHREADS
+ pthread_t sup_tid;
+ pthread_mutex_t sup_mutex[1];
+#if __CYGWIN__
+ pthread_mutex_t sup_reflock[1];
+ int sup_ref;
+#else
+ pthread_rwlock_t sup_ref[1];
+#endif
+#else
+ int sup_ref;
+#endif
+
+#if SU_HAVE_MBOX
+ su_socket_t sup_mbox[MBOX_SEND + 1];
+ su_wait_t sup_mbox_wait;
+#endif
+
+ CFRunLoopRef sup_main_loop;
+ CFRunLoopSourceRef *sup_sources;
+ CFSocketRef *sup_sockets;
+
+ unsigned sup_multishot; /**< Multishot operation? */
+
+ unsigned sup_registers; /** Counter incremented by
+ su_port_register() or
+ su_port_unregister()
+ */
+ int sup_n_waits; /**< Active su_wait_t in su_waits */
+ int sup_size_waits; /**< Size of allocate su_waits */
+
+ int sup_pri_offset; /**< Offset to prioritized waits */
+
+#define INDEX_MAX (0x7fffffff)
+
+ /** Indices from index returned by su_root_register() to tables below.
+ *
+ * Free elements are negative. Free elements form a list, value of free
+ * element is (0 - index of next free element).
+ *
+ * First element sup_indices[0] points to first free element.
+ */
+ int *sup_indices;
+
+ int *sup_reverses; /** Reverse index */
+ su_wakeup_f *sup_wait_cbs;
+ su_wakeup_arg_t**sup_wait_args;
+ su_root_t **sup_wait_roots;
+
+ su_wait_t *sup_waits;
+
+ /* Pre-poll callback */
+ su_prepoll_f *sup_prepoll;
+ su_prepoll_magic_t *sup_pp_magic;
+ su_root_t *sup_pp_root;
+
+ /* Timer list */
+ su_timer_t *sup_timers;
+
+ /* Message list - this is protected by lock */
+ su_msg_t *sup_head;
+ su_msg_t **sup_tail;
+
+#if 0
+ int sup_free_index; /**< Number of first free index */
+ int *sup_indices; /** Indices to registrations */
+
+ int *sup_reverses; /** Reverse index */
+ su_wakeup_f *sup_wait_cbs;
+ su_wakeup_arg_t**sup_wait_args;
+ su_root_t **sup_wait_roots;
+
+ su_wait_t *sup_waits;
+
+ /* Pre-poll callback */
+ su_prepoll_f *sup_prepoll;
+ su_prepoll_magic_t *sup_pp_magic;
+ su_root_t *sup_pp_root;
+
+ /* Timer list */
+ su_timer_t *sup_timers;
+
+ /* Message list - this is protected by lock */
+ su_msg_t *sup_head;
+ su_msg_t **sup_tail;
+#endif
+};
+
+
+/* Struct for CFSocket callbacks; contains current CFSource index */
+typedef struct {
+ su_port_t *o_port;
+ int o_current;
+ int o_count;
+} osx_magic_t;
+
+
+#if SU_HAVE_PTHREADS
+#define SU_PORT_OSX_OWN_THREAD(p) (pthread_equal((p)->sup_tid, pthread_self()))
+
+#if __CYGWIN__
+
+/* Debugging versions */
+#define SU_PORT_OSX_INITREF(p) (pthread_mutex_init((p)->sup_reflock, NULL), printf("initref(%p)\n", (p)))
+#define SU_PORT_OSX_INCREF(p, f) (pthread_mutex_lock(p->sup_reflock), p->sup_ref++, pthread_mutex_unlock(p->sup_reflock), printf("incref(%p) by %s\n", (p), f))
+#define SU_PORT_OSX_DECREF(p, f) do { \
+ pthread_mutex_lock(p->sup_reflock); p->sup_ref--; pthread_mutex_unlock(p->sup_reflock); \
+ if ((p->sup_ref) == 0) { \
+ printf("decref(%p) to 0 by %s\n", (p), f); su_port_osx_destroy(p); } \
+ else { printf("decref(%p) to %u by %s\n", (p), p->sup_ref, f); } } while(0)
+
+#define SU_PORT_OSX_ZAPREF(p, f) do { printf("zapref(%p) by %s\n", (p), f), \
+ pthread_mutex_lock(p->sup_reflock); p->sup_ref--; pthread_mutex_unlock(p->sup_reflock); \
+ if ((p->sup_ref) != 0) { \
+ assert(!"SU_PORT_OSX_ZAPREF"); } \
+ su_port_osx_destroy(p); } while(0)
+
+#define SU_PORT_OSX_INITLOCK(p) \
+ (pthread_mutex_init((p)->sup_mutex, NULL), printf("init_lock(%p)\n", p))
+
+#define SU_PORT_OSX_LOCK(p, f) \
+ (printf("%ld at %s locking(%p)...", pthread_self(), f, p), pthread_mutex_lock((p)->sup_mutex), printf(" ...%ld at %s locked(%p)...", pthread_self(), f, p))
+
+#define SU_PORT_OSX_UNLOCK(p, f) \
+ (pthread_mutex_unlock((p)->sup_mutex), printf(" ...%ld at %s unlocked(%p)\n", pthread_self(), f, p))
+
+#elif 1
+#define SU_PORT_OSX_INITREF(p) (pthread_rwlock_init(p->sup_ref, NULL))
+#define SU_PORT_OSX_INCREF(p, f) (pthread_rwlock_rdlock(p->sup_ref))
+#define SU_PORT_OSX_DECREF(p, f) do { pthread_rwlock_unlock(p->sup_ref); \
+ if (pthread_rwlock_trywrlock(p->sup_ref) == 0) su_port_osx_destroy(p); } while(0)
+
+#define SU_PORT_OSX_ZAPREF(p, f) do { pthread_rwlock_unlock(p->sup_ref); \
+ if (pthread_rwlock_trywrlock(p->sup_ref) != 0) { \
+ assert(!"SU_PORT_OSX_ZAPREF"); pthread_rwlock_wrlock(p->sup_ref); } \
+ su_port_osx_destroy(p); } while(0)
+
+#define SU_PORT_OSX_INITLOCK(p) (pthread_mutex_init((p)->sup_mutex, NULL))
+#define SU_PORT_OSX_LOCK(p, f) (pthread_mutex_lock((p)->sup_mutex))
+#define SU_PORT_OSX_UNLOCK(p, f) (pthread_mutex_unlock((p)->sup_mutex))
+
+#else
+
+/* Debugging versions */
+#define SU_PORT_OSX_INITREF(p) (pthread_rwlock_init((p)->sup_ref, NULL), printf("initref(%p)\n", (p)))
+#define SU_PORT_OSX_INCREF(p, f) (pthread_rwlock_rdlock(p->sup_ref), printf("incref(%p) by %s\n", (p), f))
+#define SU_PORT_OSX_DECREF(p, f) do { \
+ pthread_rwlock_unlock(p->sup_ref); \
+ if (pthread_rwlock_trywrlock(p->sup_ref) == 0) { \
+ printf("decref(%p) to 0 by %s\n", (p), f); su_port_osx_destroy(p); } \
+ else { printf("decref(%p) by %s\n", (p), f); } } while(0)
+
+#define SU_PORT_OSX_ZAPREF(p, f) do { printf("zapref(%p) by %s\n", (p), f), \
+ pthread_rwlock_unlock(p->sup_ref); \
+ if (pthread_rwlock_trywrlock(p->sup_ref) != 0) { \
+ assert(!"SU_PORT_OSX_ZAPREF"); pthread_rwlock_wrlock(p->sup_ref); } \
+ su_port_osx_destroy(p); } while(0)
+
+#define SU_PORT_OSX_INITLOCK(p) \
+ (pthread_mutex_init((p)->sup_mutex, NULL), printf("init_lock(%p)\n", p))
+
+#define SU_PORT_OSX_LOCK(p, f) \
+ (printf("%ld at %s locking(%p)...", pthread_self(), f, p), pthread_mutex_lock((p)->sup_mutex), printf(" ...%ld at %s locked(%p)...", pthread_self(), f, p))
+
+#define SU_PORT_OSX_UNLOCK(p, f) \
+ (pthread_mutex_unlock((p)->sup_mutex), printf(" ...%ld at %s unlocked(%p)\n", pthread_self(), f, p))
+
+#endif
+
+#else /* !SU_HAVE_PTHREADS */
+
+#define SU_PORT_OSX_OWN_THREAD(p) 1
+#define SU_PORT_OSX_INITLOCK(p) (void)(p)
+#define SU_PORT_OSX_LOCK(p, f) (void)(p)
+#define SU_PORT_OSX_UNLOCK(p, f) (void)(p)
+#define SU_PORT_OSX_ZAPREF(p, f) ((p)->sup_ref--)
+
+#define SU_PORT_OSX_INITREF(p) ((p)->sup_ref = 1)
+#define SU_PORT_OSX_INCREF(p, f) ((p)->sup_ref++)
+#define SU_PORT_OSX_DECREF(p, f) \
+do { if (--((p)->sup_ref) == 0) su_port_osx_destroy(p); } while (0);
+
+#endif
+
+#if SU_HAVE_MBOX
+static int su_port_osx_wakeup(su_root_magic_t *magic,
+ su_wait_t *w,
+ su_wakeup_arg_t *arg);
+#endif
+
+static void su_port_osx_destroy(su_port_t *self);
+
+/** Create a reactor object.
+ *
+ * Allocate and initialize the instance of su_root_t.
+ *
+ * @param magic pointer to user data
+ *
+ * @return A pointer to allocated su_root_t instance, NULL on error.
+ *
+ * @NEW_1_12_4.
+ */
+su_root_t *su_root_osx_runloop_create(su_root_magic_t *magic)
+{
+ return su_root_create_with_port(magic, su_osx_runloop_create());
+}
+
+
+void osx_enabler_cb(CFSocketRef s,
+ CFSocketCallBackType type,
+ CFDataRef address,
+ const void *data,
+ void *info)
+{
+ CFRunLoopRef rl;
+ osx_magic_t *magic = (osx_magic_t *) info;
+ su_port_t *self = magic->o_port;
+ su_duration_t tout = 0;
+ su_time_t now = su_now();
+
+ rl = CFRunLoopGetCurrent();
+
+ if (self->sup_running) {
+
+ if (self->sup_prepoll)
+ self->sup_prepoll(self->sup_pp_magic, self->sup_pp_root);
+
+ if (self->sup_head)
+ su_port_osx_getmsgs(self);
+
+ if (self->sup_timers)
+ su_timer_expire(&self->sup_timers, &tout, now);
+ }
+
+ CFRunLoopWakeUp(rl);
+
+}
+
+
+/**@internal
+ *
+ * Allocates and initializes a message port. It creates a mailbox used to.
+ * wake up the tasks waiting on the port if needed. Currently, the
+ * mailbox is simply an UDP socket connected to itself.
+ *
+ * @return
+ * If successful a pointer to the new message port is returned, otherwise
+ * NULL is returned.
+ */
+su_port_t *su_osx_runloop_create(void)
+{
+ su_port_t *self;
+
+ SU_DEBUG_9(("su_osx_runloop_create() called\n"));
+
+ self = su_home_clone(NULL, sizeof(*self));
+
+ if (self) {
+#if SU_HAVE_MBOX
+ int af;
+ su_socket_t mb = INVALID_SOCKET;
+ char const *why;
+#endif
+ CFRunLoopObserverRef cf_observer;
+ osx_magic_t *osx_magic = NULL;
+ CFRunLoopObserverContext cf_observer_cntx[1] = {{0, NULL, NULL,
+ NULL, NULL}};
+
+ self->sup_vtable = su_port_osx_vtable;
+
+ SU_PORT_OSX_INITREF(self);
+ SU_PORT_OSX_INITLOCK(self);
+ self->sup_tail = &self->sup_head;
+
+ self->sup_multishot = 0; /* XXX (SU_ENABLE_MULTISHOT_POLL) != 0; */
+
+#if SU_HAVE_PTHREADS
+ self->sup_tid = pthread_self();
+#endif
+
+#if SU_HAVE_MBOX
+#if HAVE_SOCKETPAIR
+#if defined(AF_LOCAL)
+ af = AF_LOCAL;
+#else
+ af = AF_UNIX;
+#endif
+ if (socketpair(af, SOCK_STREAM, 0, self->sup_mbox) == -1) {
+ why = "su_port_osx_init: socketpair"; goto error;
+ }
+
+ mb = self->sup_mbox[0];
+ su_setblocking(self->sup_mbox[0], 0);
+ su_setblocking(self->sup_mbox[1], 0);
+#else
+ {
+ struct sockaddr_in sin = { sizeof(struct sockaddr_in), 0 };
+ socklen_t sinsize = sizeof sin;
+ struct sockaddr *sa = (struct sockaddr *)&sin;
+
+ af = PF_INET;
+
+ self->sup_mbox[0] = mb = su_socket(af, SOCK_DGRAM, IPPROTO_UDP);
+ if (mb == INVALID_SOCKET) {
+ why = "su_port_osx_init: socket"; goto error;
+ }
+
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); /* 127.1 */
+
+ /* Get a port for us */
+ if (bind(mb, sa, sizeof sin) == -1) {
+ why = "su_port_osx_init: bind"; goto error;
+ }
+
+ if (getsockname(mb, sa, &sinsize) == -1) {
+ why = "su_port_osx_init: getsockname"; goto error;
+ }
+
+ if (connect(mb, sa, sinsize) == -1) {
+ why = "su_port_osx_init: connect"; goto error;
+ }
+ }
+#endif
+
+ if (su_wait_create(&self->sup_mbox_wait, mb, SU_WAIT_IN) == -1) {
+ why = "su_port_osx_init: su_wait_create"; goto error;
+ }
+
+ if (su_port_osx_register(self, NULL, &self->sup_mbox_wait,
+ su_port_osx_wakeup,
+ (su_wakeup_arg_t *)self->sup_mbox, 0)
+ == -1) {
+ why = "su_port_osx_create: su_port_osx_register"; goto error;
+ }
+
+ osx_magic = calloc(1, sizeof(*osx_magic));
+ osx_magic->o_port = self;
+ cf_observer_cntx->info = osx_magic;
+
+ cf_observer =
+ CFRunLoopObserverCreate(NULL, kCFRunLoopAfterWaiting | kCFRunLoopBeforeWaiting,
+ TRUE, 0, cf_observer_cb, cf_observer_cntx);
+
+ CFRunLoopAddObserver(CFRunLoopGetCurrent(),
+ cf_observer,
+ kCFRunLoopDefaultMode);
+
+ SU_DEBUG_9(("su_port_osx_create() returns %p\n", self));
+
+ return self;
+
+ error:
+ su_perror(why);
+ su_port_osx_destroy(self), self = NULL;
+#endif
+ }
+
+ SU_DEBUG_9(("su_port_osx_create() returns %p\n", self));
+
+ return self;
+}
+
+
+static
+void cf_observer_cb(CFRunLoopObserverRef observer,
+ CFRunLoopActivity activity,
+ void *info)
+{
+ CFRunLoopRef rl;
+ osx_magic_t *magic = (osx_magic_t *) info;
+ su_port_t *self = magic->o_port;
+ su_duration_t tout = 0;
+ su_time_t now = su_now();
+
+ rl = CFRunLoopGetCurrent();
+
+ if (self->sup_running) {
+
+ if (self->sup_prepoll)
+ self->sup_prepoll(self->sup_pp_magic, self->sup_pp_root);
+
+ if (self->sup_head)
+ su_port_osx_getmsgs(self);
+
+ if (self->sup_timers)
+ su_timer_expire(&self->sup_timers, &tout, now);
+ } else
+ SU_DEBUG_9(("cf_observer_cb(): PORT IS NOT RUNNING!\n"));
+
+ CFRunLoopWakeUp(rl);
+
+ return;
+}
+
+/** @internal Destroy a port. */
+void su_port_osx_destroy(su_port_t *self)
+{
+ assert(self);
+
+ SU_DEBUG_9(("su_port_osx_destroy() called\n"));
+
+#if SU_HAVE_MBOX
+ if (self->sup_mbox[0] != INVALID_SOCKET) {
+ su_port_osx_unregister(self, NULL, &self->sup_mbox_wait, NULL,
+ (su_wakeup_arg_t *)self->sup_mbox);
+ su_wait_destroy(&self->sup_mbox_wait);
+ su_close(self->sup_mbox[0]); self->sup_mbox[0] = INVALID_SOCKET;
+#if HAVE_SOCKETPAIR
+ su_close(self->sup_mbox[1]); self->sup_mbox[1] = INVALID_SOCKET;
+#endif
+ SU_DEBUG_9(("su_port_osx_destroy() close mailbox\n"));
+ }
+#endif
+ if (self->sup_sources)
+ free(self->sup_sources), self->sup_sources = NULL;
+ if (self->sup_sockets)
+ free(self->sup_sockets), self->sup_sockets = NULL;
+ if (self->sup_waits)
+ free(self->sup_waits), self->sup_waits = NULL;
+ if (self->sup_wait_cbs)
+ free(self->sup_wait_cbs), self->sup_wait_cbs = NULL;
+ if (self->sup_wait_args)
+ free(self->sup_wait_args), self->sup_wait_args = NULL;
+ if (self->sup_wait_roots)
+ free(self->sup_wait_roots), self->sup_wait_roots = NULL;
+ if (self->sup_reverses)
+ free(self->sup_reverses), self->sup_reverses = NULL;
+ if (self->sup_indices)
+ free(self->sup_indices), self->sup_indices = NULL;
+
+ SU_DEBUG_9(("su_port_osx_destroy() freed registrations\n"));
+
+ su_home_zap(self->sup_home);
+
+ SU_DEBUG_9(("su_port_osx_destroy() returns\n"));
+
+}
+
+static void su_port_osx_lock(su_port_t *self, char const *who)
+{
+ SU_PORT_OSX_LOCK(self, who);
+}
+
+static void su_port_osx_unlock(su_port_t *self, char const *who)
+{
+ SU_PORT_OSX_UNLOCK(self, who);
+}
+
+static void su_port_osx_incref(su_port_t *self, char const *who)
+{
+ SU_PORT_OSX_INCREF(self, who);
+}
+
+static void su_port_osx_decref(su_port_t *self, int blocking, char const *who)
+{
+ if (blocking)
+ SU_PORT_OSX_ZAPREF(self, who);
+ else
+ SU_PORT_OSX_DECREF(self, who);
+}
+
+static
+CFSocketCallBackType map_poll_event_to_cf_event(int events)
+{
+ CFSocketCallBackType type = 0;
+
+ if (events & SU_WAIT_IN)
+ type |= kCFSocketReadCallBack;
+
+ if (events & SU_WAIT_OUT)
+ type |= kCFSocketWriteCallBack;
+
+#if 0
+ if (events & SU_WAIT_CONNECT)
+ type |= kCFSocketConnectCallBack;
+
+ if (events & SU_WAIT_ACCEPT)
+ type |= kCFSocketAcceptCallBack;
+#endif
+
+ return type;
+}
+
+
+static
+int map_cf_event_to_poll_event(CFSocketCallBackType type)
+{
+ int event = 0;
+
+ if (type & kCFSocketReadCallBack)
+ event |= SU_WAIT_IN;
+
+ if (type & kCFSocketWriteCallBack)
+ event |= SU_WAIT_OUT;
+
+ if (type & kCFSocketConnectCallBack)
+ event |= SU_WAIT_CONNECT;
+
+ if (type & kCFSocketAcceptCallBack)
+ event |= SU_WAIT_ACCEPT;
+
+ return event;
+}
+
+
+static
+void su_port_osx_socket_cb(CFSocketRef s,
+ CFSocketCallBackType type,
+ CFDataRef address,
+ const void *data,
+ void *info)
+{
+ osx_magic_t *magic = (osx_magic_t *) info;
+ su_port_t *self = magic->o_port;
+ int curr = magic->o_current;
+ su_duration_t tout = 0;
+
+#if SU_HAVE_POLL
+ {
+ su_root_t *root;
+ su_wait_t *waits = self->sup_waits;
+ int n = self->sup_indices[curr];
+
+ assert(self->sup_reverses[n] == curr);
+
+ SU_DEBUG_9(("socket_cb(%p): count %u index %d\n", self->sup_sources[n], magic->o_count, curr));
+
+ waits[n].revents = map_poll_event_to_cf_event(type);
+
+ root = self->sup_wait_roots[n];
+ self->sup_wait_cbs[n](root ? su_root_magic(root) : NULL,
+ &waits[n],
+ self->sup_wait_args[n]);
+
+ if (self->sup_running) {
+ su_port_osx_getmsgs(self);
+
+ if (self->sup_timers)
+ su_timer_expire(&self->sup_timers, &tout, su_now());
+
+ if (self->sup_head)
+ tout = 0;
+
+ /* CFRunLoopWakeUp(CFRunLoopGetCurrent()); */
+ }
+
+ /* Tell to run loop an su socket fired */
+ self->sup_source_fired = 1;
+ }
+#endif
+
+}
+
+#if SU_HAVE_MBOX
+/** @internal Message box wakeup function. */
+static int su_port_osx_wakeup(su_root_magic_t *magic, /* NULL */
+ su_wait_t *w,
+ su_wakeup_arg_t *arg)
+{
+ char buf[32];
+ su_socket_t s = *(su_socket_t *)arg;
+ su_wait_events(w, s);
+ recv(s, buf, sizeof(buf), 0);
+
+ /* CFRunLoopWakeUp(CFRunLoopGetCurrent()); */
+
+ return 0;
+}
+#endif
+
+/** @internal Send a message to the port. */
+int su_port_osx_send(su_port_t *self, su_msg_r rmsg)
+{
+ CFRunLoopRef rl;
+
+ if (self) {
+ int wakeup;
+
+ SU_PORT_OSX_LOCK(self, "su_port_osx_send");
+
+ wakeup = self->sup_head == NULL;
+
+ *self->sup_tail = rmsg[0]; rmsg[0] = NULL;
+ self->sup_tail = &(*self->sup_tail)->sum_next;
+
+#if SU_HAVE_MBOX
+ /* if (!pthread_equal(pthread_self(), self->sup_tid)) */
+ if (wakeup)
+ {
+ assert(self->sup_mbox[MBOX_SEND] != INVALID_SOCKET);
+
+ if (send(self->sup_mbox[MBOX_SEND], "X", 1, 0) == -1) {
+#if HAVE_SOCKETPAIR
+ if (su_errno() != EWOULDBLOCK)
+#endif
+ su_perror("su_msg_send: send()");
+ }
+ }
+#endif
+
+ SU_PORT_OSX_UNLOCK(self, "su_port_osx_send");
+
+ rl = CFRunLoopGetCurrent();
+ CFRunLoopWakeUp(rl);
+
+ return 0;
+ }
+ else {
+ su_msg_destroy(rmsg);
+ return -1;
+ }
+}
+
+/** @internal
+ * Execute the messages in the incoming queue until the queue is empty..
+ *
+ * @param self - pointer to a port object
+ *
+ * @retval Number of messages sent
+ */
+int su_port_osx_getmsgs(su_port_t *self)
+{
+ int n = 0;
+
+ if (self->sup_head) {
+ su_msg_f f;
+ su_msg_t *msg, *queue;
+
+ SU_PORT_OSX_LOCK(self, "su_port_getmsgs");
+
+ queue = self->sup_head;
+ self->sup_tail = &self->sup_head;
+ self->sup_head = NULL;
+
+ SU_PORT_OSX_UNLOCK(self, "su_port_osx_getmsgs");
+
+ for (msg = queue; msg; msg = queue) {
+ queue = msg->sum_next;
+ msg->sum_next = NULL;
+
+ f = msg->sum_func;
+ if (f)
+ f(SU_ROOT_MAGIC(msg->sum_to->sut_root), &msg, msg->sum_data);
+ su_msg_delivery_report(&msg);
+ n++;
+ }
+
+ /* Check for wait events that may have been generated by messages */
+ su_port_osx_wait_events(self, 0);
+ }
+
+ return n;
+}
+
+static int o_count;
+
+/** @internal
+ *
+ * Register a @c su_wait_t object. The wait object, a callback function and
+ * a argument pointer is stored in the port object. The callback function
+ * will be called when the wait object is signaled.
+ *
+ * Please note if identical wait objects are inserted, only first one is
+ * ever signalled.
+ *
+ * @param self pointer to port
+ * @param root pointer to root object
+ * @param waits pointer to wait object
+ * @param callback callback function pointer
+ * @param arg argument given to callback function when it is invoked
+ * @param priority relative priority of the wait object
+ * (0 is normal, 1 important, 2 realtime)
+ *
+ * @return
+ * The function @su_port_osx_register returns nonzero index of the wait object,
+ * or -1 upon an error. */
+int su_port_osx_register(su_port_t *self,
+ su_root_t *root,
+ su_wait_t *wait,
+ su_wakeup_f callback,
+ su_wakeup_arg_t *arg,
+ int priority)
+{
+ int i, j, n;
+ CFRunLoopRef rl;
+ CFRunLoopSourceRef *sources, source;
+ CFSocketRef cf_socket, *sockets;
+ int events = 0;
+ osx_magic_t *osx_magic = NULL;
+ CFSocketContext cf_socket_cntx[1] = {{0, NULL, NULL, NULL, NULL}};
+ CFOptionFlags flags = 0;
+
+ assert(SU_PORT_OSX_OWN_THREAD(self));
+
+ n = self->sup_n_waits;
+
+ if (n >= SU_WAIT_MAX)
+ return su_seterrno(ENOMEM);
+
+ if (n >= self->sup_size_waits) {
+ /* Reallocate size arrays */
+ int size;
+ int *indices;
+ int *reverses;
+ su_wait_t *waits;
+ su_wakeup_f *wait_cbs;
+ su_wakeup_arg_t **wait_args;
+ su_root_t **wait_tasks;
+
+ if (self->sup_size_waits == 0)
+ size = su_root_size_hint;
+ else
+ size = 2 * self->sup_size_waits;
+
+ if (size < SU_WAIT_MIN)
+ size = SU_WAIT_MIN;
+
+ /* Too large */
+ if (-3 - size > 0)
+ return (errno = ENOMEM), -1;
+
+ indices = realloc(self->sup_indices, (size + 1) * sizeof(*indices));
+ if (indices) {
+ self->sup_indices = indices;
+
+ for (i = self->sup_size_waits; i <= size; i++)
+ indices[i] = -1 - i;
+ }
+
+ reverses = realloc(self->sup_reverses, size * sizeof(*waits));
+ if (reverses) {
+ for (i = self->sup_size_waits; i < size; i++)
+ reverses[i] = -1;
+ self->sup_reverses = reverses;
+ }
+
+ sources = realloc(self->sup_sources, size * sizeof(*sources));
+ if (sources)
+ self->sup_sources = sources;
+
+ sockets = realloc(self->sup_sockets, size * sizeof(*sockets));
+ if (sockets)
+ self->sup_sockets = sockets;
+
+ waits = realloc(self->sup_waits, size * sizeof(*waits));
+ if (waits)
+ self->sup_waits = waits;
+
+ wait_cbs = realloc(self->sup_wait_cbs, size * sizeof(*wait_cbs));
+ if (wait_cbs)
+ self->sup_wait_cbs = wait_cbs;
+
+ wait_args = realloc(self->sup_wait_args, size * sizeof(*wait_args));
+ if (wait_args)
+ self->sup_wait_args = wait_args;
+
+ /* Add sup_wait_roots array, if needed */
+ wait_tasks = realloc(self->sup_wait_roots, size * sizeof(*wait_tasks));
+ if (wait_tasks)
+ self->sup_wait_roots = wait_tasks;
+
+ if (!(indices &&
+ reverses && sources && sockets && waits && wait_cbs && wait_args && wait_tasks)) {
+ return -1;
+ }
+
+ self->sup_size_waits = size;
+ }
+
+ i = -self->sup_indices[0]; assert(i <= self->sup_size_waits);
+
+ if (priority > 0) {
+ /* Insert */
+ for (n = self->sup_n_waits; n > 0; n--) {
+ j = self->sup_reverses[n-1]; assert(self->sup_indices[j] == n - 1);
+ self->sup_indices[j] = n;
+ self->sup_reverses[n] = self->sup_reverses[n-1];
+ self->sup_sources[n] = self->sup_sources[n-1];
+ self->sup_sockets[n] = self->sup_sockets[n-1];
+ self->sup_waits[n] = self->sup_waits[n-1];
+ self->sup_wait_cbs[n] = self->sup_wait_cbs[n-1];
+ self->sup_wait_args[n] = self->sup_wait_args[n-1];
+ self->sup_wait_roots[n] = self->sup_wait_roots[n-1];
+ }
+
+ self->sup_pri_offset++;
+ }
+ else {
+ /* Append - no need to move anything */
+ n = self->sup_n_waits;
+ }
+
+ self->sup_n_waits++;
+
+ self->sup_indices[0] = self->sup_indices[i]; /* Free index */
+ self->sup_indices[i] = n;
+
+ self->sup_reverses[n] = i;
+ self->sup_waits[n] = *wait;
+ self->sup_wait_cbs[n] = callback;
+ self->sup_wait_args[n] = arg;
+ self->sup_wait_roots[n] = root;
+
+ self->sup_registers++;
+
+ /* XXX -- mela: leak, leak -- free() somewheeeere */
+ osx_magic = calloc(1, sizeof(*osx_magic));
+ osx_magic->o_port = self;
+ osx_magic->o_current = i;
+ osx_magic->o_count = ++o_count;
+ cf_socket_cntx->info = osx_magic;
+
+ events = map_poll_event_to_cf_event(wait->events);
+
+ cf_socket = CFSocketCreateWithNative(NULL,
+ (CFSocketNativeHandle) su_wait_socket(wait),
+ events, su_port_osx_socket_cb, cf_socket_cntx);
+
+ flags = CFSocketGetSocketFlags(cf_socket);
+ flags &= ~kCFSocketCloseOnInvalidate;
+
+ CFSocketSetSocketFlags(cf_socket, flags);
+
+ CFRetain(cf_socket);
+ source = CFSocketCreateRunLoopSource(NULL, cf_socket, 0);
+
+ SU_DEBUG_9(("source(%p): count %u index %d\n", source, o_count, i));
+
+ rl = CFRunLoopGetCurrent();
+
+ CFRunLoopAddSource(rl, source, kCFRunLoopDefaultMode);
+
+ CFRetain(source);
+ self->sup_sources[n] = source;
+ self->sup_sockets[n] = cf_socket;
+
+ CFRunLoopWakeUp(rl);
+
+ /* Just like epoll, we return -1 or positive integer */
+
+ return i;
+}
+
+/** Deregister a su_wait_t object. */
+static
+int su_port_osx_deregister0(su_port_t *self, int i)
+{
+ CFRunLoopRef rl;
+ int n, N, *indices, *reverses;
+
+ indices = self->sup_indices;
+ reverses = self->sup_reverses;
+
+ n = indices[i]; assert(n >= 0); assert(i == reverses[n]);
+
+ N = --self->sup_n_waits;
+
+ rl = CFRunLoopGetCurrent();
+ CFSocketInvalidate(self->sup_sockets[n]);
+ CFRelease(self->sup_sockets[n]);
+ CFRunLoopRemoveSource(rl, self->sup_sources[n], kCFRunLoopDefaultMode);
+ CFRelease(self->sup_sources[n]);
+
+ CFRunLoopWakeUp(rl);
+
+ if (n < self->sup_pri_offset) {
+ int j = --self->sup_pri_offset;
+ if (n != j) {
+ assert(reverses[j] > 0);
+ assert(indices[reverses[j]] == j);
+ indices[reverses[j]] = n;
+ reverses[n] = reverses[j];
+
+ self->sup_sources[n] = self->sup_sources[j];
+ self->sup_sockets[n] = self->sup_sockets[j];
+ self->sup_waits[n] = self->sup_waits[j];
+ self->sup_wait_cbs[n] = self->sup_wait_cbs[j];
+ self->sup_wait_args[n] = self->sup_wait_args[j];
+ self->sup_wait_roots[n] = self->sup_wait_roots[j];
+ n = j;
+ }
+ }
+
+ if (n < N) {
+ assert(reverses[N] > 0);
+ assert(indices[reverses[N]] == N);
+
+ indices[reverses[N]] = n;
+ reverses[n] = reverses[N];
+
+ self->sup_sources[n] = self->sup_sources[N];
+ self->sup_sockets[n] = self->sup_sockets[N];
+ self->sup_waits[n] = self->sup_waits[N];
+ self->sup_wait_cbs[n] = self->sup_wait_cbs[N];
+ self->sup_wait_args[n] = self->sup_wait_args[N];
+ self->sup_wait_roots[n] = self->sup_wait_roots[N];
+ n = N;
+ }
+
+
+ reverses[n] = -1;
+ memset(&self->sup_waits[n], 0, sizeof self->sup_waits[n]);
+ self->sup_sources[n] = NULL;
+ self->sup_sockets[n] = NULL;
+ self->sup_wait_cbs[n] = NULL;
+ self->sup_wait_args[n] = NULL;
+ self->sup_wait_roots[n] = NULL;
+
+ indices[i] = indices[0];
+ indices[0] = -i;
+
+ self->sup_registers++;
+
+ return i;
+}
+
+
+/** Unregister a su_wait_t object.
+ *
+ * The function su_port_osx_unregister() unregisters a su_wait_t object. The
+ * wait object, a callback function and a argument are removed from the
+ * port object.
+ *
+ * @param self - pointer to port object
+ * @param root - pointer to root object
+ * @param wait - pointer to wait object
+ * @param callback - callback function pointer (may be NULL)
+ * @param arg - argument given to callback function when it is invoked
+ * (may be NULL)
+ *
+ * @return Nonzero index of the wait object, or -1 upon an error.
+ */
+int su_port_osx_unregister(su_port_t *self,
+ su_root_t *root,
+ su_wait_t *wait,
+ su_wakeup_f callback, /* XXX - ignored */
+ su_wakeup_arg_t *arg)
+{
+ int n, N;
+
+ assert(self);
+ assert(SU_PORT_OSX_OWN_THREAD(self));
+
+ N = self->sup_n_waits;
+
+ for (n = 0; n < N; n++) {
+ if (SU_WAIT_CMP(wait[0], self->sup_waits[n]) == 0) {
+ return su_port_osx_deregister0(self, self->sup_reverses[n]);
+ }
+ }
+
+ su_seterrno(ENOENT);
+
+ return -1;
+}
+
+/** Deregister a su_wait_t object.
+ *
+ * The function su_port_osx_deregister() deregisters a su_wait_t registrattion.
+ * The wait object, a callback function and a argument are removed from the
+ * port object.
+ *
+ * @param self - pointer to port object
+ * @param i - registration index
+ *
+ * @return Index of the wait object, or -1 upon an error.
+ */
+int su_port_osx_deregister(su_port_t *self, int i)
+{
+ su_wait_t wait[1] = { SU_WAIT_INIT };
+ int retval;
+
+ assert(self);
+ assert(SU_PORT_OSX_OWN_THREAD(self));
+
+ if (i <= 0 || i > self->sup_size_waits)
+ return su_seterrno(EBADF);
+
+ if (self->sup_indices[i] < 0)
+ return su_seterrno(EBADF);
+
+ retval = su_port_osx_deregister0(self, i);
+
+ su_wait_destroy(wait);
+
+ return retval;
+}
+
+
+/** @internal
+ * Unregister all su_wait_t objects.
+ *
+ * The function su_port_osx_unregister_all() unregisters all su_wait_t objects
+ * and destroys all queued timers associated with given root object.
+ *
+ * @param self - pointer to port object
+ * @param root - pointer to root object
+ *
+ * @return Number of wait objects removed.
+ */
+int su_port_osx_unregister_all(su_port_t *self,
+ su_root_t *root)
+{
+ int i, j, index, N;
+ int *indices, *reverses;
+ su_wait_t *waits;
+ su_wakeup_f *wait_cbs;
+ su_wakeup_arg_t **wait_args;
+ su_root_t **wait_roots;
+ CFRunLoopRef rl;
+ CFRunLoopSourceRef *sources;
+ CFSocketRef *sockets;
+
+ assert(SU_PORT_OSX_OWN_THREAD(self));
+
+ N = self->sup_n_waits;
+ indices = self->sup_indices;
+ reverses = self->sup_reverses;
+ sources = self->sup_sources;
+ sockets = self->sup_sockets;
+ waits = self->sup_waits;
+ wait_cbs = self->sup_wait_cbs;
+ wait_args = self->sup_wait_args;
+ wait_roots = self->sup_wait_roots;
+
+ rl = CFRunLoopGetCurrent();
+
+ for (i = j = 0; i < N; i++) {
+ index = reverses[i]; assert(index > 0 && indices[index] == i);
+
+ if (wait_roots[i] == root) {
+ if (i < self->sup_pri_offset)
+ self->sup_pri_offset--;
+
+ indices[index] = indices[0];
+ indices[0] = -index;
+ continue;
+ }
+
+ if (i != j) {
+ indices[index] = j;
+
+ CFSocketInvalidate(self->sup_sockets[j]);
+ CFRelease(self->sup_sockets[j]);
+ CFRunLoopRemoveSource(rl, sources[j], kCFRunLoopDefaultMode);
+ CFRelease(sources[j]);
+
+ reverses[j] = reverses[i];
+ sources[j] = sources[i];
+ sockets[j] = sockets[i];
+ waits[j] = waits[i];
+ wait_cbs[j] = wait_cbs[i];
+ wait_args[j] = wait_args[i];
+ wait_roots[j] = wait_roots[i];
+ }
+
+ j++;
+ }
+
+ /* Prepare for removing CFSources */
+ for (i = j; i < N; i++) {
+ reverses[i] = -1;
+
+ CFSocketInvalidate(self->sup_sockets[i]);
+ CFRelease(self->sup_sockets[i]);
+ CFRunLoopRemoveSource(rl, sources[i], kCFRunLoopDefaultMode);
+ CFRunLoopSourceInvalidate(sources[i]);
+
+ sources[i] = NULL;
+ sockets[i] = NULL;
+ wait_cbs[i] = NULL;
+ wait_args[i] = NULL;
+ wait_roots[i] = NULL;
+ }
+ memset(&waits[j], 0, (char *)&waits[N] - (char *)&waits[j]);
+
+ /* Tell run loop things have changed */
+ CFRunLoopWakeUp(rl);
+
+ self->sup_n_waits = j;
+ self->sup_registers++;
+
+ return N - j;
+}
+
+/**Set mask for a registered event. @internal
+ *
+ * The function su_port_osx_eventmask() sets the mask describing events that can
+ * signal the registered callback.
+ *
+ * @param port pointer to port object
+ * @param index registration index
+ * @param socket socket
+ * @param events new event mask
+ *
+ * @retval 0 when successful,
+ * @retval -1 upon an error.
+ */
+int su_port_osx_eventmask(su_port_t *self, int index, int socket, int events)
+{
+ int n, ret;
+
+ assert(self);
+ assert(SU_PORT_OSX_OWN_THREAD(self));
+
+ if (index <= 0 || index > self->sup_size_waits)
+ return su_seterrno(EBADF);
+ n = self->sup_indices[index];
+ if (n < 0)
+ return su_seterrno(EBADF);
+
+ ret = su_wait_mask(&self->sup_waits[n], socket, events);
+
+ CFSocketSetSocketFlags(self->sup_sockets[n],
+ map_poll_event_to_cf_event(events));
+
+ return ret;
+}
+
+/** @internal
+ *
+ * Copies the su_wait_t objects from the port. The number of wait objects
+ * can be found out by calling su_port_osx_query() with @a n_waits as zero.
+ *
+ * @note This function is called only by friends.
+ *
+ * @param self - pointer to port object
+ * @param waits - pointer to array to which wait objects are copied
+ * @param n_waits - number of wait objects fitting in array waits
+ *
+ * @return Number of wait objects, or 0 upon an error.
+ */
+unsigned su_port_osx_query(su_port_t *self, su_wait_t *waits, unsigned n_waits)
+{
+ unsigned n;
+
+ assert(SU_PORT_OSX_OWN_THREAD(self));
+
+ n = self->sup_n_waits;
+
+ if (n_waits != 0) {
+ if (waits && n_waits >= n)
+ memcpy(waits, self->sup_waits, n * sizeof(*waits));
+ else
+ n = 0;
+ }
+
+ return n;
+}
+
+/** @internal Enable multishot mode.
+ *
+ * The function su_port_osx_multishot() enables, disables or queries the
+ * multishot mode for the port. The multishot mode determines how the events
+ * are scheduled by port. If multishot mode is enabled, port serves all the
+ * sockets that have received network events. If it is disables, only first
+ * socket event is served.
+ *
+ * @param self pointer to port object
+ * @param multishot multishot mode (0 => disables, 1 => enables, -1 => query)
+ *
+ * @retval 0 multishot mode is disabled
+ * @retval 1 multishot mode is enabled
+ * @retval -1 an error occurred
+ */
+int su_port_osx_multishot(su_port_t *self, int multishot)
+{
+ if (multishot < 0)
+ return self->sup_multishot;
+ else if (multishot == 0 || multishot == 1)
+ return self->sup_multishot = multishot;
+ else
+ return (errno = EINVAL), -1;
+}
+
+/** @internal Enable threadsafe operation. */
+static
+int su_port_osx_threadsafe(su_port_t *port)
+{
+ return su_home_threadsafe(port->sup_home);
+}
+
+/** Prepare root to be run on OSX Run Loop.
+ *
+ * Sets #su_root_t object to be callable by the application's run loop. This
+ * function is to be used instead of su_root_run() for OSX applications
+ * using Core Foundation's Run Loop.
+ *
+ * The function su_root_osx_prepare_run() returns immmediately.
+ *
+ * @param root pointer to root object
+ *
+ * @NEW_1_12_4.
+ */
+void su_root_osx_prepare_run(su_root_t *root)
+{
+ su_port_t *self = root->sur_task->sut_port;
+ CFRunLoopRef rl;
+ su_duration_t tout = 0;
+
+ assert(SU_PORT_OSX_OWN_THREAD(self));
+
+ enter;
+
+ self->sup_running = 1;
+ rl = CFRunLoopGetCurrent();
+
+ if (self->sup_prepoll)
+ self->sup_prepoll(self->sup_pp_magic, self->sup_pp_root);
+
+ if (self->sup_head)
+ su_port_osx_getmsgs(self);
+
+ if (self->sup_timers)
+ su_timer_expire(&self->sup_timers, &tout, su_now());
+
+ if (!self->sup_running)
+ return;
+
+ CFRetain(rl);
+ self->sup_main_loop = rl;
+
+ return;
+}
+
+/** @internal Main loop.
+ *
+ * The function @c su_port_osx_run() waits for wait objects and the timers
+ * associated with the port object. When any wait object is signaled or
+ * timer is expired, it invokes the callbacks, and returns waiting.
+ *
+ * The function @c su_port_osx_run() runs until @c su_port_osx_break() is called
+ * from a callback.
+ *
+ * @param self pointer to port object
+ *
+ */
+void su_port_osx_run(su_port_t *self)
+{
+ CFRunLoopRef rl;
+ su_duration_t tout = 0;
+
+ assert(SU_PORT_OSX_OWN_THREAD(self));
+
+ enter;
+
+ self->sup_running = 1;
+ rl = CFRunLoopGetCurrent();
+
+ if (self->sup_prepoll)
+ self->sup_prepoll(self->sup_pp_magic, self->sup_pp_root);
+
+ if (self->sup_head)
+ su_port_osx_getmsgs(self);
+
+ if (self->sup_timers)
+ su_timer_expire(&self->sup_timers, &tout, su_now());
+
+ if (!self->sup_running)
+ return;
+
+ CFRetain(rl);
+ self->sup_main_loop = rl;
+
+ /* if there are messages do a quick wait */
+ if (self->sup_head)
+ tout = 0;
+
+ CFRunLoopRun();
+
+ self->sup_main_loop = NULL;
+
+}
+
+#if tuning
+/* This version can help tuning... */
+void su_port_osx_run_tune(su_port_t *self)
+{
+ int i;
+ int timers = 0, messages = 0, events = 0;
+ su_duration_t tout = 0, tout0;
+ su_time_t started = su_now(), woken = started, bedtime = woken;
+
+ assert(SU_PORT_OSX_OWN_THREAD(self));
+
+ for (self->sup_running = 1; self->sup_running;) {
+ tout0 = tout, tout = 2000;
+
+ timers = 0, messages = 0;
+
+ if (self->sup_prepoll)
+ self->sup_prepoll(self->sup_pp_magic, self->sup_pp_root);
+
+ if (self->sup_head)
+ messages = su_port_osx_getmsgs(self);
+
+ if (self->sup_timers)
+ timers = su_timer_expire(&self->sup_timers, &tout, su_now());
+
+ if (!self->sup_running)
+ break;
+
+ if (self->sup_head) /* if there are messages do a quick wait */
+ tout = 0;
+
+ bedtime = su_now();
+
+ events = su_port_osx_wait_events(self, tout);
+
+ woken = su_now();
+
+ if (messages || timers || events)
+ SU_DEBUG_1(("su_port_osx_run(%p): %.6f: %u messages %u timers %u "
+ "events slept %.6f/%.3f\n",
+ self, su_time_diff(woken, started), messages, timers, events,
+ su_time_diff(woken, bedtime), tout0 * 1e-3));
+
+ if (!self->sup_running)
+ break;
+ }
+}
+#endif
+
+/** @internal
+ * The function @c su_port_osx_break() is used to terminate execution of @c
+ * su_port_osx_run(). It can be called from a callback function.
+ *
+ * @param self pointer to port
+ *
+ */
+void su_port_osx_break(su_port_t *self)
+{
+ if (self->sup_main_loop)
+ CFRunLoopStop(self->sup_main_loop);
+
+ self->sup_running = 0;
+}
+
+/** @internal
+ * The function @c su_port_osx_wait_events() is used to poll() for wait objects
+ *
+ * @param self pointer to port
+ * @param tout timeout in milliseconds
+ *
+ * @return number of events handled
+ */
+static
+int su_port_osx_wait_events(su_port_t *self, su_duration_t tout)
+{
+ int i, events = 0;
+ su_wait_t *waits = self->sup_waits;
+ unsigned n = self->sup_n_waits;
+#if HAVE_POLL
+ unsigned version = self->sup_registers;
+#endif
+ su_root_t *root;
+
+ i = su_wait(waits, n, tout);
+
+ if (i >= 0 && (unsigned)i < n) {
+#if HAVE_POLL
+ /* poll() can return events for multiple wait objects */
+ if (self->sup_multishot) {
+ for (; i < n; i++) {
+ if (waits[i].revents) {
+ root = self->sup_wait_roots[i];
+ self->sup_wait_cbs[i](root ? su_root_magic(root) : NULL,
+ &waits[i],
+ self->sup_wait_args[i]);
+ events++;
+ /* Callback function used su_register()/su_deregister() */
+ if (version != self->sup_registers)
+ break;
+ }
+ }
+ }
+#else /* !HAVE_POLL */
+ if (0) {
+ }
+#endif
+ else {
+ root = self->sup_wait_roots[i];
+ self->sup_wait_cbs[i](root ? su_root_magic(root) : NULL,
+ &self->sup_waits[i],
+ self->sup_wait_args[i]);
+ events++;
+ }
+ }
+
+ return events;
+}
+
+/** @internal
+ * Used to check wait events in callbacks that take lots of time
+ *
+ * This function does a timeout 0 poll() and runs wait objects.
+ *
+ * @param port pointer to port
+ *
+ * @return number of events handled
+ */
+static
+int su_port_osx_yield(su_port_t *port)
+{
+ return su_port_osx_wait_events(port, 0);
+}
+
+/** @internal Block until wait object is signaled or timeout.
+ *
+ * This function waits for wait objects and the timers associated with
+ * the root object. When any wait object is signaled or timer is
+ * expired, it invokes the callbacks.
+ *
+ * This function returns when a callback has been invoked or @c tout
+ * milliseconds is elapsed.
+ *
+ * @param self pointer to port
+ * @param tout timeout in milliseconds
+ *
+ * @return
+ * Milliseconds to the next invocation of timer, or @c SU_WAIT_FOREVER if
+ * there are no active timers.
+ */
+su_duration_t su_port_osx_step(su_port_t *self, su_duration_t tout)
+{
+ CFRunLoopRef rl;
+ su_time_t now = su_now();
+ CFAbsoluteTime start;
+ int ret, timeout = tout > INT32_MAX ? INT32_MAX : tout;
+
+ assert(SU_PORT_OSX_OWN_THREAD(self));
+
+ rl = CFRunLoopGetCurrent();
+
+ if (!rl)
+ return -1;
+
+ CFRunLoopWakeUp(rl);
+
+ if (tout < timeout)
+ timeout = tout;
+
+ if (self->sup_prepoll)
+ self->sup_prepoll(self->sup_pp_magic, self->sup_pp_root);
+
+ if (self->sup_head)
+ su_port_osx_getmsgs(self);
+
+ if (self->sup_timers)
+ su_timer_expire(&self->sup_timers, &tout, now);
+
+ /* if there are messages do a quick wait */
+ if (self->sup_head)
+ tout = 0;
+
+ start = CFAbsoluteTimeGetCurrent();
+ for (;;) {
+ /* Run loop with only one pass, indicate if a source was processed */
+ ret = CFRunLoopRunInMode(kCFRunLoopDefaultMode,
+ 0,
+ TRUE);
+
+ /* Ok, one of our sources was fired */
+ if (self->sup_source_fired == 1) {
+ self->sup_source_fired = 0;
+ break;
+ }
+
+ /* Check how long to run this loop */
+ if (CFAbsoluteTimeGetCurrent() >= start + timeout / 1000)
+ break;
+ }
+
+ if (self->sup_head)
+ su_port_osx_getmsgs(self);
+
+ if (self->sup_timers)
+ su_timer_expire(&self->sup_timers, &tout, su_now());
+
+ if (self->sup_head)
+ tout = 0;
+
+ return tout;
+}
+
+
+/** @internal
+ * Checks if the calling thread owns the port object.
+ *
+ * @param self pointer to a port object
+ *
+ * @retval true (nonzero) if the calling thread owns the port,
+ * @retval false (zero) otherwise.
+ */
+int su_port_osx_own_thread(su_port_t const *self)
+{
+ return self == NULL || SU_PORT_OSX_OWN_THREAD(self);
+}
+
+#if 0
+/** @internal
+ * Prints out the contents of the port.
+ *
+ * @param self pointer to a port
+ * @param f pointer to a file (if @c NULL, uses @c stdout).
+ */
+void su_port_osx_dump(su_port_t const *self, FILE *f)
+{
+ int i;
+#define IS_WAIT_IN(x) (((x)->events & SU_WAIT_IN) ? "IN" : "")
+#define IS_WAIT_OUT(x) (((x)->events & SU_WAIT_OUT) ? "OUT" : "")
+#define IS_WAIT_ACCEPT(x) (((x)->events & SU_WAIT_ACCEPT) ? "ACCEPT" : "")
+
+ if (f == NULL)
+ f = stdout;
+
+ fprintf(f, "su_port_osx_t at %p:\n", self);
+ fprintf(f, "\tport is%s running\n", self->sup_running ? "" : "not ");
+#if SU_HAVE_PTHREADS
+ fprintf(f, "\tport tid %p\n", (void *)self->sup_tid);
+#endif
+#if SU_HAVE_MBOX
+ fprintf(f, "\tport mbox %d (%s%s%s)\n", self->sup_mbox[0],
+ IS_WAIT_IN(&self->sup_mbox_wait),
+ IS_WAIT_OUT(&self->sup_mbox_wait),
+ IS_WAIT_ACCEPT(&self->sup_mbox_wait));
+#endif
+ fprintf(f, "\t%d wait objects\n", self->sup_n_waits);
+ for (i = 0; i < self->sup_n_waits; i++) {
+
+ }
+}
+
+#endif
+
+/* =========================================================================
+ * Pre-poll() callback
+ */
+
+int su_port_osx_add_prepoll(su_port_t *port,
+ su_root_t *root,
+ su_prepoll_f *callback,
+ su_prepoll_magic_t *magic)
+{
+ if (port->sup_prepoll)
+ return -1;
+
+ port->sup_prepoll = callback;
+ port->sup_pp_magic = magic;
+ port->sup_pp_root = root;
+
+ return 0;
+}
+
+int su_port_osx_remove_prepoll(su_port_t *port,
+ su_root_t *root)
+{
+ if (port->sup_pp_root != root)
+ return -1;
+
+ port->sup_prepoll = NULL;
+ port->sup_pp_magic = NULL;
+ port->sup_pp_root = NULL;
+
+ return 0;
+}
+
+/* =========================================================================
+ * Timers
+ */
+
+static
+su_timer_t **su_port_osx_timers(su_port_t *self)
+{
+ return &self->sup_timers;
+}
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_perf.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_perf.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,188 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_root_ex
+ * @CFILE su_perf.c
+ *
+ * Performance test for su message passing
+ *
+ * @internal
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Mar 18 19:40:51 1999 pessi
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+struct perf;
+#define SU_ROOT_MAGIC_T struct perf
+#define SU_MSG_ARG_T struct message
+
+#include "sofia-sip/su.h"
+#include "sofia-sip/su_wait.h"
+
+struct perf {
+ enum { PINGER = 1, PONGER = 2 } const sort;
+ char const *const name;
+ unsigned running : 1;
+ unsigned target;
+ unsigned n;
+ su_root_t *root;
+ struct sockaddr_in sin;
+};
+
+struct message {
+ su_time_t started;
+};
+
+void
+do_exit(struct perf *x, su_msg_r msg, struct message *m)
+{
+ su_root_break(su_task_root(su_msg_to(msg)));
+}
+
+int
+do_init(su_root_t *root, struct perf *p)
+{
+ p->root = root;
+ return 0;
+}
+
+void
+do_print(struct perf *p, su_msg_r msg, struct message *m)
+{
+ su_time_t now = su_now();
+ double dur = su_time_diff(now, m->started);
+
+ printf("su_perf: %g message exchanges per second"
+ " (%d message exchanges in %g seconds)\n",
+ (double)p->n / dur, p->n, dur);
+ su_msg_create(msg, su_root_parent(p->root), su_root_task(p->root),
+ do_exit, sizeof(*m));
+ *su_msg_data(msg) = *m;
+ su_msg_send(msg);
+}
+
+void
+do_ping(struct perf *p, su_msg_r msg, struct message *m)
+{
+ if (p->sort == PINGER) {
+ p->n++;
+
+ if (p->n % 100 == 0) {
+ if (su_duration(su_now(), m->started) > p->target) {
+ do_print(p, msg, m);
+ return;
+ }
+ }
+ }
+
+ su_msg_reply(msg, msg, do_ping, sizeof(*m));
+ *su_msg_data(msg) = *m;
+ su_msg_send(msg);
+}
+
+void
+do_destroy(su_root_t *t, struct perf *p)
+{
+ p->running = 0;
+}
+
+void usage(char *name)
+{
+ fprintf(stderr, "usage: %s [-1] [n]\n", name);
+ exit(2);
+}
+
+/*
+ * Measure how many message passes can be done in a second.
+ *
+ * Create a ponger and pinger, responding to incoming message do_ping
+ *
+ * After "target" rounds, print out elapsed time and number of messages
+ * passed.
+ *
+ */
+int main(int argc, char *argv[])
+{
+ su_root_t *root;
+ su_clone_r ping = SU_CLONE_R_INIT, pong = SU_CLONE_R_INIT;
+ su_msg_r start_msg = SU_MSG_R_INIT;
+
+ struct perf
+ pinger = { PINGER, "ping", 1, 0 },
+ ponger = { PONGER, "pong", 1, 0x7fffffff};
+
+ int have_threads = 1;
+ char *argv0 = argv[0];
+ char *argv1 = argv[1];
+
+ if (argv1 && strcmp(argv1, "-1") == 0)
+ have_threads = 0, argv1 = argv[2];
+
+ if (!argv1)
+ argv1 = "10000";
+
+ if (strlen(argv1) != strspn(argv1, "0123456789"))
+ usage(argv0);
+
+ pinger.target = strtoul(argv1, NULL, 0);
+
+ su_init(); atexit(su_deinit);
+
+ root = su_root_create(NULL);
+
+ su_root_threading(root, have_threads);
+
+ if (su_clone_start(root, ping, &pinger, do_init, do_destroy) != 0)
+ perror("su_clone_start"), exit(1);
+ if (su_clone_start(root, pong, &ponger, do_init, do_destroy) != 0)
+ perror("su_clone_start"), exit(1);
+
+ if (su_msg_create(start_msg, su_clone_task(pong), su_clone_task(ping),
+ do_ping, sizeof(struct message)) == 0) {
+ su_msg_data(start_msg)->started = su_now();
+ su_msg_send(start_msg);
+
+ su_root_run(root);
+ }
+
+#if 0
+ su_clone_wait(root, ping);
+ su_clone_wait(root, pong);
+
+ while (pinger.running || ponger.running)
+ su_root_step(root, 100L);
+#endif
+
+ su_root_destroy(root);
+
+ return 0;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_port.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_port.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1480 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_wait
+ * @CFILE su_port.c
+ *
+ * OS-Independent Socket Syncronization Interface.
+ *
+ * This looks like nth reincarnation of "reactor". It implements the
+ * poll/select/WaitForMultipleObjects and message passing functionality.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Kai Vehmanen <kai.vehmanen at nokia.com>
+ *
+ * @date Created: Tue Sep 14 15:51:04 1999 ppessi
+ */
+
+#include "config.h"
+
+/* React to multiple events per one poll() to make sure
+ * that high-priority events can never completely mask other events.
+ * Enabled by default on all platforms except WIN32 */
+#ifndef WIN32
+#define SU_ENABLE_MULTISHOT_POLL 1
+#else
+#define SU_ENABLE_MULTISHOT_POLL 0
+#endif
+
+#include <stdlib.h>
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <errno.h>
+
+#define SU_PORT_IMPLEMENTATION 1
+
+#include "sofia-sip/su.h"
+#include "su_port.h"
+#include "sofia-sip/su_alloc.h"
+
+#if SU_HAVE_PTHREADS
+/* Pthread implementation */
+#include <pthread.h>
+#define SU_HAVE_MBOX 1
+#else
+#define SU_HAVE_MBOX 0
+#endif
+
+#if HAVE_SOCKETPAIR
+#define MBOX_SEND 1
+#else
+#define MBOX_SEND 0
+#endif
+
+#if HAVE_EPOLL
+#include <sys/epoll.h>
+
+#define POLL2EPOLL_NEEDED \
+ (POLLIN != EPOLLIN || POLLOUT != EPOLLOUT || POLLPRI != EPOLLPRI || \
+ POLLERR != EPOLLERR || POLLHUP != EPOLLHUP)
+
+#define POLL2EPOLL(e) (e & (POLLIN|POLLOUT|POLLPRI|POLLERR|POLLHUP))
+#define EPOLL2POLL(e) (e & (POLLIN|POLLOUT|POLLPRI|POLLERR|POLLHUP))
+
+#endif
+
+static void su_port_lock(su_port_t *self, char const *who);
+static void su_port_unlock(su_port_t *self, char const *who);
+static void su_port_incref(su_port_t *self, char const *who);
+static void su_port_decref(su_port_t *self, int blocking, char const *who);
+
+static struct _GSource *su_port_gsource(su_port_t *port);
+
+static int su_port_send(su_port_t *self, su_msg_r rmsg);
+
+static int su_port_register(su_port_t *self,
+ su_root_t *root,
+ su_wait_t *wait,
+ su_wakeup_f callback,
+ su_wakeup_arg_t *arg,
+ int priority);
+static int su_port_unregister(su_port_t *port,
+ su_root_t *root,
+ su_wait_t *wait,
+ su_wakeup_f callback,
+ su_wakeup_arg_t *arg);
+
+static int su_port_deregister(su_port_t *self, int i);
+
+static int su_port_unregister_all(su_port_t *self,
+ su_root_t *root);
+static
+int su_port_eventmask(su_port_t *self, int index, int socket, int events);
+static
+void su_port_run(su_port_t *self);
+static
+void su_port_break(su_port_t *self);
+static
+su_duration_t su_port_step(su_port_t *self, su_duration_t tout);
+
+static
+int su_port_own_thread(su_port_t const *port);
+
+static
+int su_port_add_prepoll(su_port_t *port,
+ su_root_t *root,
+ su_prepoll_f *,
+ su_prepoll_magic_t *);
+
+static
+int su_port_remove_prepoll(su_port_t *port,
+ su_root_t *root);
+
+static
+su_timer_t **su_port_timers(su_port_t *port);
+
+static
+int su_port_multishot(su_port_t *port, int multishot);
+
+static
+int su_port_threadsafe(su_port_t *port);
+
+static
+int su_port_yield(su_port_t *port);
+
+su_port_vtable_t const su_port_vtable[1] =
+ {{
+ /* su_vtable_size: */ sizeof su_port_vtable,
+ su_port_lock,
+ su_port_unlock,
+ su_port_incref,
+ su_port_decref,
+ su_port_gsource,
+ su_port_send,
+ su_port_register,
+ su_port_unregister,
+ su_port_deregister,
+ su_port_unregister_all,
+ su_port_eventmask,
+ su_port_run,
+ su_port_break,
+ su_port_step,
+ su_port_own_thread,
+ su_port_add_prepoll,
+ su_port_remove_prepoll,
+ su_port_timers,
+ su_port_multishot,
+ su_port_threadsafe,
+ su_port_yield
+ }};
+
+static int su_port_wait_events(su_port_t *self, su_duration_t tout);
+
+
+/**
+ * Port is a per-thread reactor.
+ *
+ * Multiple root objects executed by single thread share a su_port_t object.
+ */
+struct su_port_s {
+ su_home_t sup_home[1];
+
+ su_port_vtable_t const *sup_vtable;
+
+ unsigned sup_running;
+
+#if SU_HAVE_PTHREADS
+ pthread_t sup_tid;
+ pthread_mutex_t sup_mutex[1];
+#if __CYGWIN__
+ pthread_mutex_t sup_reflock[1];
+ int sup_ref;
+#else
+ pthread_rwlock_t sup_ref[1];
+#endif
+#else
+ int sup_ref;
+#endif
+
+#if SU_HAVE_MBOX
+ su_socket_t sup_mbox[MBOX_SEND + 1];
+ su_wait_t sup_mbox_wait;
+#endif
+
+#if HAVE_EPOLL
+ /** epoll() fd */
+ int sup_epoll;
+#endif
+
+ unsigned sup_multishot; /**< Multishot operation? */
+
+ unsigned sup_registers; /** Counter incremented by
+ su_port_register() or
+ su_port_unregister()
+ */
+ int sup_n_waits; /**< Active su_wait_t in su_waits */
+ int sup_size_waits; /**< Size of allocate su_waits */
+
+ int sup_pri_offset; /**< Offset to prioritized waits */
+
+#if !SU_HAVE_WINSOCK
+#define INDEX_MAX (0x7fffffff)
+#else
+ /* We use WSAWaitForMultipleEvents() */
+#define INDEX_MAX (64)
+#endif
+
+ /** Indices from index returned by su_root_register() to tables below.
+ *
+ * Free elements are negative. Free elements form a list, value of free
+ * element is (0 - index of next free element).
+ *
+ * First element sup_indices[0] points to first free element.
+ */
+ int *sup_indices;
+
+ int *sup_reverses; /** Reverse index */
+ su_wakeup_f *sup_wait_cbs;
+ su_wakeup_arg_t**sup_wait_args;
+ su_root_t **sup_wait_roots;
+
+ su_wait_t *sup_waits;
+
+ /* Pre-poll callback */
+ su_prepoll_f *sup_prepoll;
+ su_prepoll_magic_t *sup_pp_magic;
+ su_root_t *sup_pp_root;
+
+ /* Timer list */
+ su_timer_t *sup_timers;
+
+ /* Message list - this is protected by lock */
+ su_msg_t *sup_head;
+ su_msg_t **sup_tail;
+};
+
+#if SU_HAVE_PTHREADS
+#define SU_PORT_OWN_THREAD(p) (pthread_equal((p)->sup_tid, pthread_self()))
+
+#if __CYGWIN__
+
+/* Debugging versions */
+#define SU_PORT_INITREF(p) (pthread_mutex_init((p)->sup_reflock, NULL), printf("initref(%p)\n", (p)))
+#define SU_PORT_INCREF(p, f) (pthread_mutex_lock(p->sup_reflock), p->sup_ref++, pthread_mutex_unlock(p->sup_reflock), printf("incref(%p) by %s\n", (p), f))
+#define SU_PORT_DECREF(p, f) do { \
+ pthread_mutex_lock(p->sup_reflock); p->sup_ref--; pthread_mutex_unlock(p->sup_reflock); \
+ if ((p->sup_ref) == 0) { \
+ printf("decref(%p) to 0 by %s\n", (p), f); su_port_destroy(p); } \
+ else { printf("decref(%p) to %u by %s\n", (p), p->sup_ref, f); } } while(0)
+
+#define SU_PORT_ZAPREF(p, f) do { printf("zapref(%p) by %s\n", (p), f), \
+ pthread_mutex_lock(p->sup_reflock); p->sup_ref--; pthread_mutex_unlock(p->sup_reflock); \
+ if ((p->sup_ref) != 0) { \
+ assert(!"SU_PORT_ZAPREF"); } \
+ su_port_destroy(p); } while(0)
+
+#define SU_PORT_INITLOCK(p) \
+ (pthread_mutex_init((p)->sup_mutex, NULL), printf("init_lock(%p)\n", p))
+
+#define SU_PORT_LOCK(p, f) \
+ (printf("%ld at %s locking(%p)...", pthread_self(), f, p), pthread_mutex_lock((p)->sup_mutex), printf(" ...%ld at %s locked(%p)...", pthread_self(), f, p))
+
+#define SU_PORT_UNLOCK(p, f) \
+ (pthread_mutex_unlock((p)->sup_mutex), printf(" ...%ld at %s unlocked(%p)\n", pthread_self(), f, p))
+
+#elif 1
+#define SU_PORT_INITREF(p) (pthread_rwlock_init(p->sup_ref, NULL))
+#define SU_PORT_INCREF(p, f) (pthread_rwlock_rdlock(p->sup_ref))
+#define SU_PORT_DECREF(p, f) do { pthread_rwlock_unlock(p->sup_ref); \
+ if (pthread_rwlock_trywrlock(p->sup_ref) == 0) su_port_destroy(p); } while(0)
+
+#define SU_PORT_ZAPREF(p, f) do { pthread_rwlock_unlock(p->sup_ref); \
+ if (pthread_rwlock_trywrlock(p->sup_ref) != 0) { \
+ assert(!"SU_PORT_ZAPREF"); pthread_rwlock_wrlock(p->sup_ref); } \
+ su_port_destroy(p); } while(0)
+
+#define SU_PORT_INITLOCK(p) (pthread_mutex_init((p)->sup_mutex, NULL))
+#define SU_PORT_LOCK(p, f) (pthread_mutex_lock((p)->sup_mutex))
+#define SU_PORT_UNLOCK(p, f) (pthread_mutex_unlock((p)->sup_mutex))
+
+#else
+
+/* Debugging versions */
+#define SU_PORT_INITREF(p) (pthread_rwlock_init((p)->sup_ref, NULL), printf("initref(%p)\n", (p)))
+#define SU_PORT_INCREF(p, f) (pthread_rwlock_rdlock(p->sup_ref), printf("incref(%p) by %s\n", (p), f))
+#define SU_PORT_DECREF(p, f) do { \
+ pthread_rwlock_unlock(p->sup_ref); \
+ if (pthread_rwlock_trywrlock(p->sup_ref) == 0) { \
+ printf("decref(%p) to 0 by %s\n", (p), f); su_port_destroy(p); } \
+ else { printf("decref(%p) by %s\n", (p), f); } } while(0)
+
+#define SU_PORT_ZAPREF(p, f) do { printf("zapref(%p) by %s\n", (p), f), \
+ pthread_rwlock_unlock(p->sup_ref); \
+ if (pthread_rwlock_trywrlock(p->sup_ref) != 0) { \
+ assert(!"SU_PORT_ZAPREF"); pthread_rwlock_wrlock(p->sup_ref); } \
+ su_port_destroy(p); } while(0)
+
+#define SU_PORT_INITLOCK(p) \
+ (pthread_mutex_init((p)->sup_mutex, NULL), printf("init_lock(%p)\n", p))
+
+#define SU_PORT_LOCK(p, f) \
+ (printf("%ld at %s locking(%p)...", pthread_self(), f, p), pthread_mutex_lock((p)->sup_mutex), printf(" ...%ld at %s locked(%p)...", pthread_self(), f, p))
+
+#define SU_PORT_UNLOCK(p, f) \
+ (pthread_mutex_unlock((p)->sup_mutex), printf(" ...%ld at %s unlocked(%p)\n", pthread_self(), f, p))
+
+#endif
+
+#else /* !SU_HAVE_PTHREADS */
+
+#define SU_PORT_OWN_THREAD(p) 1
+#define SU_PORT_INITLOCK(p) (void)(p)
+#define SU_PORT_LOCK(p, f) (void)(p)
+#define SU_PORT_UNLOCK(p, f) (void)(p)
+#define SU_PORT_ZAPREF(p, f) ((p)->sup_ref--)
+
+#define SU_PORT_INITREF(p) ((p)->sup_ref = 1)
+#define SU_PORT_INCREF(p, f) ((p)->sup_ref++)
+#define SU_PORT_DECREF(p, f) \
+do { if (--((p)->sup_ref) == 0) su_port_destroy(p); } while (0);
+
+#endif
+
+#if SU_HAVE_MBOX
+static int su_port_wakeup(su_root_magic_t *magic,
+ su_wait_t *w,
+ su_wakeup_arg_t *arg);
+#endif
+
+static void su_port_destroy(su_port_t *self);
+
+/**@internal
+ *
+ * Allocates and initializes a message port. It creates a mailbox used to.
+ * wake up the tasks waiting on the port if needed. Currently, the
+ * mailbox is simply an UDP socket connected to itself.
+ *
+ * @return
+ * If successful a pointer to the new message port is returned, otherwise
+ * NULL is returned.
+ */
+su_port_t *su_port_create(void)
+{
+ su_port_t *self;
+
+ SU_DEBUG_9(("su_port_create() called\n"));
+
+ self = su_home_clone(NULL, sizeof(*self));
+
+ if (self) {
+#if SU_HAVE_MBOX
+ int af;
+ su_socket_t mb = INVALID_SOCKET;
+ char const *why;
+#endif
+
+ self->sup_vtable = su_port_vtable;
+
+ SU_PORT_INITREF(self);
+ SU_PORT_INITLOCK(self);
+ self->sup_tail = &self->sup_head;
+
+ self->sup_multishot = (SU_ENABLE_MULTISHOT_POLL) != 0;
+
+#if SU_HAVE_PTHREADS
+ self->sup_tid = pthread_self();
+#endif
+
+#if HAVE_EPOLL
+ self->sup_epoll = epoll_create(su_root_size_hint);
+ if (self->sup_epoll == -1)
+ SU_DEBUG_3(("su_port(%p): epoll_create(): %s\n", self, strerror(errno)));
+ else
+ SU_DEBUG_9(("su_port(%p): epoll_create() => %u: OK\n",
+ self, self->sup_epoll));
+#endif
+
+#if SU_HAVE_MBOX
+#if HAVE_SOCKETPAIR
+#if defined(AF_LOCAL)
+ af = AF_LOCAL;
+#else
+ af = AF_UNIX;
+#endif
+ if (socketpair(af, SOCK_STREAM, 0, self->sup_mbox) == -1) {
+ why = "su_port_init: socketpair"; goto error;
+ }
+
+ mb = self->sup_mbox[0];
+ su_setblocking(self->sup_mbox[0], 0);
+ su_setblocking(self->sup_mbox[1], 0);
+#else
+ {
+ struct sockaddr_in sin = { sizeof(struct sockaddr_in), 0 };
+ socklen_t sinsize = sizeof sin;
+ struct sockaddr *sa = (struct sockaddr *)&sin;
+
+ af = PF_INET;
+
+ self->sup_mbox[0] = mb = su_socket(af, SOCK_DGRAM, IPPROTO_UDP);
+ if (mb == INVALID_SOCKET) {
+ why = "su_port_init: socket"; goto error;
+ }
+
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); /* 127.1 */
+
+ /* Get a port for us */
+ if (bind(mb, sa, sizeof sin) == -1) {
+ why = "su_port_init: bind"; goto error;
+ }
+
+ if (getsockname(mb, sa, &sinsize) == -1) {
+ why = "su_port_init: getsockname"; goto error;
+ }
+
+ if (connect(mb, sa, sinsize) == -1) {
+ why = "su_port_init: connect"; goto error;
+ }
+ }
+#endif
+
+ if (su_wait_create(&self->sup_mbox_wait, mb, SU_WAIT_IN) == -1) {
+ why = "su_port_init: su_wait_create"; goto error;
+ }
+
+ if (su_port_register(self, NULL, &self->sup_mbox_wait, su_port_wakeup,
+ (su_wakeup_arg_t *)self->sup_mbox, 0)
+ == -1) {
+ why = "su_port_create: su_port_register"; goto error;
+ }
+
+ SU_DEBUG_9(("su_port_create() returns %p\n", self));
+
+ return self;
+
+ error:
+ su_perror(why);
+ su_port_destroy(self), self = NULL;
+#endif
+ }
+
+ SU_DEBUG_9(("su_port_create() returns %p\n", self));
+
+ return self;
+}
+
+/** @internal Destroy a port. */
+void su_port_destroy(su_port_t *self)
+{
+ assert(self);
+
+ SU_DEBUG_9(("su_port_destroy() called\n"));
+
+#if SU_HAVE_MBOX
+ if (self->sup_mbox[0] != INVALID_SOCKET) {
+ su_port_unregister(self, NULL, &self->sup_mbox_wait, NULL,
+ (su_wakeup_arg_t *)self->sup_mbox);
+ su_wait_destroy(&self->sup_mbox_wait);
+ su_close(self->sup_mbox[0]); self->sup_mbox[0] = INVALID_SOCKET;
+#if HAVE_SOCKETPAIR
+ su_close(self->sup_mbox[1]); self->sup_mbox[1] = INVALID_SOCKET;
+#endif
+ SU_DEBUG_9(("su_port_destroy() close mailbox\n"));
+ }
+#endif
+ if (self->sup_waits)
+ free(self->sup_waits), self->sup_waits = NULL;
+ if (self->sup_wait_cbs)
+ free(self->sup_wait_cbs), self->sup_wait_cbs = NULL;
+ if (self->sup_wait_args)
+ free(self->sup_wait_args), self->sup_wait_args = NULL;
+ if (self->sup_wait_roots)
+ free(self->sup_wait_roots), self->sup_wait_roots = NULL;
+ if (self->sup_reverses)
+ free(self->sup_reverses), self->sup_reverses = NULL;
+ if (self->sup_indices)
+ free(self->sup_indices), self->sup_indices = NULL;
+
+ SU_DEBUG_9(("su_port_destroy() freed registrations\n"));
+
+ su_home_zap(self->sup_home);
+
+ SU_DEBUG_9(("su_port_destroy() returns\n"));
+
+}
+
+static void su_port_lock(su_port_t *self, char const *who)
+{
+ SU_PORT_LOCK(self, who);
+}
+
+static void su_port_unlock(su_port_t *self, char const *who)
+{
+ SU_PORT_UNLOCK(self, who);
+}
+
+static void su_port_incref(su_port_t *self, char const *who)
+{
+ SU_PORT_INCREF(self, who);
+}
+
+static void su_port_decref(su_port_t *self, int blocking, char const *who)
+{
+ if (blocking)
+ SU_PORT_ZAPREF(self, who);
+ else
+ SU_PORT_DECREF(self, who);
+}
+
+static struct _GSource *su_port_gsource(su_port_t *self)
+{
+ return NULL;
+}
+
+#if SU_HAVE_MBOX
+/** @internal Message box wakeup function. */
+static int su_port_wakeup(su_root_magic_t *magic, /* NULL */
+ su_wait_t *w,
+ su_wakeup_arg_t *arg)
+{
+ char buf[32];
+ su_socket_t s = *(su_socket_t *)arg;
+ su_wait_events(w, s);
+ recv(s, buf, sizeof(buf), 0);
+ return 0;
+}
+#endif
+
+/** @internal Send a message to the port. */
+int su_port_send(su_port_t *self, su_msg_r rmsg)
+{
+ if (self) {
+ int wakeup;
+
+ SU_PORT_LOCK(self, "su_port_send");
+
+ wakeup = self->sup_head == NULL;
+
+ *self->sup_tail = rmsg[0]; rmsg[0] = NULL;
+ self->sup_tail = &(*self->sup_tail)->sum_next;
+
+#if SU_HAVE_MBOX
+ /* if (!pthread_equal(pthread_self(), self->sup_tid)) */
+ if (wakeup)
+ {
+ assert(self->sup_mbox[MBOX_SEND] != INVALID_SOCKET);
+
+ if (send(self->sup_mbox[MBOX_SEND], "X", 1, 0) == -1) {
+#if HAVE_SOCKETPAIR
+ if (su_errno() != EWOULDBLOCK)
+#endif
+ su_perror("su_msg_send: send()");
+ }
+ }
+#endif
+
+ SU_PORT_UNLOCK(self, "su_port_send");
+
+ return 0;
+ }
+ else {
+ su_msg_destroy(rmsg);
+ return -1;
+ }
+}
+
+/** @internal
+ * Execute the messages in the incoming queue until the queue is empty..
+ *
+ * @param self - pointer to a port object
+ *
+ * @retval Number of messages sent
+ */
+int su_port_getmsgs(su_port_t *self)
+{
+ int n = 0;
+
+ if (self->sup_head) {
+ su_msg_f f;
+ su_msg_t *msg, *queue;
+
+ SU_PORT_LOCK(self, "su_port_getmsgs");
+
+ queue = self->sup_head;
+ self->sup_tail = &self->sup_head;
+ self->sup_head = NULL;
+
+ SU_PORT_UNLOCK(self, "su_port_getmsgs");
+
+ for (msg = queue; msg; msg = queue) {
+ queue = msg->sum_next;
+ msg->sum_next = NULL;
+
+ f = msg->sum_func;
+ if (f)
+ f(SU_ROOT_MAGIC(msg->sum_to->sut_root), &msg, msg->sum_data);
+ su_msg_delivery_report(&msg);
+ n++;
+ }
+
+ /* Check for wait events that may have been generated by messages */
+ su_port_wait_events(self, 0);
+ }
+
+ return n;
+}
+
+/** @internal
+ *
+ * Register a @c su_wait_t object. The wait object, a callback function and
+ * a argument pointer is stored in the port object. The callback function
+ * will be called when the wait object is signaled.
+ *
+ * Please note if identical wait objects are inserted, only first one is
+ * ever signalled.
+ *
+ * @param self pointer to port
+ * @param root pointer to root object
+ * @param waits pointer to wait object
+ * @param callback callback function pointer
+ * @param arg argument given to callback function when it is invoked
+ * @param priority relative priority of the wait object
+ * (0 is normal, 1 important, 2 realtime)
+ *
+ * @return
+ * Positive index of the wait object,
+ * or -1 upon an error.
+ */
+int su_port_register(su_port_t *self,
+ su_root_t *root,
+ su_wait_t *wait,
+ su_wakeup_f callback,
+ su_wakeup_arg_t *arg,
+ int priority)
+{
+ int i, j, n;
+
+ assert(SU_PORT_OWN_THREAD(self));
+
+ n = self->sup_n_waits;
+
+ if (n >= SU_WAIT_MAX)
+ return su_seterrno(ENOMEM);
+
+ if (n >= self->sup_size_waits) {
+ /* Reallocate size arrays */
+ int size;
+ int *indices;
+ int *reverses;
+ su_wait_t *waits;
+ su_wakeup_f *wait_cbs;
+ su_wakeup_arg_t **wait_args;
+ su_root_t **wait_tasks;
+
+ if (self->sup_size_waits == 0)
+ size = su_root_size_hint;
+ else
+ size = 2 * self->sup_size_waits;
+
+ if (size < SU_WAIT_MIN)
+ size = SU_WAIT_MIN;
+
+ /* Too large */
+ if (-3 - size > 0)
+ return (errno = ENOMEM), -1;
+
+ indices = realloc(self->sup_indices, (size + 1) * sizeof(*indices));
+ if (indices) {
+ self->sup_indices = indices;
+
+ if (self->sup_size_waits == 0)
+ indices[0] = -1;
+
+ for (i = self->sup_size_waits + 1; i <= size; i++)
+ indices[i] = -1 - i;
+ }
+
+ reverses = realloc(self->sup_reverses, size * sizeof(*waits));
+ if (reverses) {
+ for (i = self->sup_size_waits; i < size; i++)
+ reverses[i] = -1;
+ self->sup_reverses = reverses;
+ }
+
+ waits = realloc(self->sup_waits, size * sizeof(*waits));
+ if (waits)
+ self->sup_waits = waits;
+
+ wait_cbs = realloc(self->sup_wait_cbs, size * sizeof(*wait_cbs));
+ if (wait_cbs)
+ self->sup_wait_cbs = wait_cbs;
+
+ wait_args = realloc(self->sup_wait_args, size * sizeof(*wait_args));
+ if (wait_args)
+ self->sup_wait_args = wait_args;
+
+ /* Add sup_wait_roots array, if needed */
+ wait_tasks = realloc(self->sup_wait_roots, size * sizeof(*wait_tasks));
+ if (wait_tasks)
+ self->sup_wait_roots = wait_tasks;
+
+ if (!(indices &&
+ reverses && waits && wait_cbs && wait_args && wait_tasks)) {
+ return -1;
+ }
+
+ self->sup_size_waits = size;
+ }
+
+ i = -self->sup_indices[0]; assert(i <= self->sup_size_waits);
+
+#if HAVE_EPOLL
+ if (self->sup_epoll != -1) {
+ struct epoll_event ev;
+
+ ev.events = POLL2EPOLL(wait->events);
+ ev.data.u64 = 0;
+ ev.data.u32 = (uint32_t)i;
+
+ if (epoll_ctl(self->sup_epoll, EPOLL_CTL_ADD, wait->fd, &ev) == -1) {
+ SU_DEBUG_0(("EPOLL_CTL_ADD(%u, %u) failed: %s\n",
+ wait->fd, ev.events, strerror(errno)));
+ return -1;
+ }
+ }
+ else
+#endif
+ if (priority > 0) {
+ /* Insert */
+ for (n = self->sup_n_waits; n > 0; n--) {
+ j = self->sup_reverses[n-1]; assert(self->sup_indices[j] == n - 1);
+ self->sup_indices[j] = n;
+ self->sup_reverses[n] = j;
+ self->sup_waits[n] = self->sup_waits[n-1];
+ self->sup_wait_cbs[n] = self->sup_wait_cbs[n-1];
+ self->sup_wait_args[n] = self->sup_wait_args[n-1];
+ self->sup_wait_roots[n] = self->sup_wait_roots[n-1];
+ }
+
+ self->sup_pri_offset++;
+ }
+ else {
+ /* Append - no need to move anything */
+ n = self->sup_n_waits;
+ }
+
+ self->sup_n_waits++;
+
+ self->sup_indices[0] = self->sup_indices[i]; /* Free index */
+ self->sup_indices[i] = n;
+
+ self->sup_reverses[n] = i;
+ self->sup_waits[n] = *wait;
+ self->sup_wait_cbs[n] = callback;
+ self->sup_wait_args[n] = arg;
+ self->sup_wait_roots[n] = root;
+
+ self->sup_registers++;
+
+ /* Just like epoll, we return -1 or positive integer */
+
+ return i;
+}
+
+/** Deregister a su_wait_t object. */
+static
+int su_port_deregister0(su_port_t *self, int i)
+{
+ int n, N, *indices, *reverses;
+
+ indices = self->sup_indices;
+ reverses = self->sup_reverses;
+
+ n = indices[i]; assert(n >= 0);
+
+#if HAVE_EPOLL
+ if (self->sup_epoll != -1) {
+ su_wait_t *wait = &self->sup_waits[n];
+ struct epoll_event ev;
+
+ ev.events = POLL2EPOLL(wait->events);
+ ev.data.u64 = (uint64_t)0;
+ ev.data.u32 = (uint32_t)i;
+
+ if (epoll_ctl(self->sup_epoll, EPOLL_CTL_DEL, wait->fd, &ev) == -1) {
+ SU_DEBUG_1(("su_port(%p): EPOLL_CTL_DEL(%u): %s\n", self,
+ wait->fd, su_strerror(su_errno())));
+ }
+ }
+#endif
+
+ N = --self->sup_n_waits;
+
+ if (n < self->sup_pri_offset) {
+ int j = --self->sup_pri_offset;
+ if (n != j) {
+ assert(reverses[j] > 0);
+ assert(indices[reverses[j]] == j);
+ indices[reverses[j]] = n;
+ reverses[n] = reverses[j];
+
+ self->sup_waits[n] = self->sup_waits[j];
+ self->sup_wait_cbs[n] = self->sup_wait_cbs[j];
+ self->sup_wait_args[n] = self->sup_wait_args[j];
+ self->sup_wait_roots[n] = self->sup_wait_roots[j];
+ n = j;
+ }
+ }
+
+ if (n < N) {
+ assert(reverses[N] > 0);
+ assert(indices[reverses[N]] == N);
+
+ indices[reverses[N]] = n;
+ reverses[n] = reverses[N];
+
+ self->sup_waits[n] = self->sup_waits[N];
+ self->sup_wait_cbs[n] = self->sup_wait_cbs[N];
+ self->sup_wait_args[n] = self->sup_wait_args[N];
+ self->sup_wait_roots[n] = self->sup_wait_roots[N];
+ n = N;
+ }
+
+ reverses[n] = -1;
+ memset(&self->sup_waits[n], 0, sizeof self->sup_waits[n]);
+ self->sup_wait_cbs[n] = NULL;
+ self->sup_wait_args[n] = NULL;
+ self->sup_wait_roots[n] = NULL;
+
+ indices[i] = indices[0];
+ indices[0] = -i;
+
+ self->sup_registers++;
+
+ return i;
+}
+
+
+/** Unregister a su_wait_t object.
+ *
+ * The function su_port_unregister() unregisters a su_wait_t object. The
+ * wait object, a callback function and a argument are removed from the
+ * port object.
+ *
+ * @param self - pointer to port object
+ * @param root - pointer to root object
+ * @param wait - pointer to wait object
+ * @param callback - callback function pointer (may be NULL)
+ * @param arg - argument given to callback function when it is invoked
+ * (may be NULL)
+ *
+ * @deprecated Use su_port_deregister() instead.
+ *
+ * @return Nonzero index of the wait object, or -1 upon an error.
+ */
+int su_port_unregister(su_port_t *self,
+ su_root_t *root,
+ su_wait_t *wait,
+ su_wakeup_f callback, /* XXX - ignored */
+ su_wakeup_arg_t *arg)
+{
+ int n, N;
+
+ assert(self);
+ assert(SU_PORT_OWN_THREAD(self));
+
+ N = self->sup_n_waits;
+
+ for (n = 0; n < N; n++) {
+ if (SU_WAIT_CMP(wait[0], self->sup_waits[n]) == 0) {
+ return su_port_deregister0(self, self->sup_reverses[n]);
+ }
+ }
+
+ su_seterrno(ENOENT);
+
+ return -1;
+}
+
+/** Deregister a su_wait_t object.
+ *
+ * The function su_port_deregister() deregisters a su_wait_t registrattion.
+ * The wait object, a callback function and a argument are removed from the
+ * port object.
+ *
+ * @param self - pointer to port object
+ * @param i - registration index
+ *
+ * @return Index of the wait object, or -1 upon an error.
+ */
+int su_port_deregister(su_port_t *self, int i)
+{
+ su_wait_t wait[1] = { SU_WAIT_INIT };
+ int retval;
+
+ assert(self);
+ assert(SU_PORT_OWN_THREAD(self));
+
+ if (i <= 0 || i > self->sup_size_waits)
+ return su_seterrno(EBADF);
+
+ if (self->sup_indices[i] < 0)
+ return su_seterrno(EBADF);
+
+ retval = su_port_deregister0(self, i);
+
+ su_wait_destroy(wait);
+
+ return retval;
+}
+
+
+/** @internal
+ * Unregister all su_wait_t objects.
+ *
+ * The function su_port_unregister_all() unregisters all su_wait_t objects
+ * and destroys all queued timers associated with given root object.
+ *
+ * @param self - pointer to port object
+ * @param root - pointer to root object
+ *
+ * @return Number of wait objects removed.
+ */
+int su_port_unregister_all(su_port_t *self,
+ su_root_t *root)
+{
+ int i, j, index, N;
+ int *indices, *reverses;
+ su_wait_t *waits;
+ su_wakeup_f *wait_cbs;
+ su_wakeup_arg_t**wait_args;
+ su_root_t **wait_roots;
+
+ assert(SU_PORT_OWN_THREAD(self));
+
+ N = self->sup_n_waits;
+ indices = self->sup_indices;
+ reverses = self->sup_reverses;
+ waits = self->sup_waits;
+ wait_cbs = self->sup_wait_cbs;
+ wait_args = self->sup_wait_args;
+ wait_roots = self->sup_wait_roots;
+
+ for (i = j = 0; i < N; i++) {
+ index = reverses[i]; assert(index > 0 && indices[index] == i);
+
+ if (wait_roots[i] == root) {
+ /* XXX - we should free all resources associated with this, too */
+#if HAVE_EPOLL
+ if (self->sup_epoll != -1) {
+ int fd = waits[i].fd;
+ struct epoll_event ev;
+
+ ev.events = POLL2EPOLL(waits[i].events);
+ ev.data.u64 = (uint64_t)0;
+ ev.data.u32 = (uint32_t)index;
+
+ if (epoll_ctl(self->sup_epoll, EPOLL_CTL_DEL, fd, &ev) == -1) {
+ SU_DEBUG_1(("EPOLL_CTL_DEL(%u): %s\n",
+ waits[i].fd, su_strerror(su_errno())));
+ }
+ }
+#endif
+ if (i < self->sup_pri_offset)
+ self->sup_pri_offset--;
+
+ indices[index] = indices[0];
+ indices[0] = -index;
+ continue;
+ }
+
+ if (i != j) {
+ indices[index] = j;
+ reverses[j] = reverses[i];
+ waits[j] = waits[i];
+ wait_cbs[j] = wait_cbs[i];
+ wait_args[j] = wait_args[i];
+ wait_roots[j] = wait_roots[i];
+ }
+
+ j++;
+ }
+
+ for (i = j; i < N; i++) {
+ reverses[i] = -1;
+ wait_cbs[i] = NULL;
+ wait_args[i] = NULL;
+ wait_roots[i] = NULL;
+ }
+ memset(&waits[j], 0, (char *)&waits[N] - (char *)&waits[j]);
+
+ self->sup_n_waits = j;
+ self->sup_registers++;
+
+ return N - j;
+}
+
+/**Set mask for a registered event. @internal
+ *
+ * The function su_port_eventmask() sets the mask describing events that can
+ * signal the registered callback.
+ *
+ * @param port pointer to port object
+ * @param index registration index
+ * @param socket socket
+ * @param events new event mask
+ *
+ * @retval 0 when successful,
+ * @retval -1 upon an error.
+ */
+int su_port_eventmask(su_port_t *self, int index, int socket, int events)
+{
+ int n;
+ assert(self);
+ assert(SU_PORT_OWN_THREAD(self));
+
+ if (index <= 0 || index > self->sup_size_waits)
+ return su_seterrno(EBADF);
+ n = self->sup_indices[index];
+ if (n < 0)
+ return su_seterrno(EBADF);
+
+#if HAVE_EPOLL
+ if (self->sup_epoll != -1) {
+ su_wait_t *wait = &self->sup_waits[n];
+ struct epoll_event ev;
+
+ wait->events = events;
+
+ ev.events = POLL2EPOLL(events);
+ ev.data.u64 = (uint64_t)0;
+ ev.data.u32 = (uint32_t)index;
+
+ if (epoll_ctl(self->sup_epoll, EPOLL_CTL_MOD, wait->fd, &ev) == -1) {
+ SU_DEBUG_1(("su_port(%p): EPOLL_CTL_MOD(%u): %s\n", self,
+ wait->fd, su_strerror(su_errno())));
+ return -1;
+ }
+ }
+#endif
+
+ return su_wait_mask(&self->sup_waits[n], socket, events);
+}
+
+#if 0
+/** @internal
+ *
+ * Copies the su_wait_t objects from the port. The number of wait objects
+ * can be found out by calling su_port_query() with @a n_waits as zero.
+ *
+ * @note This function is called only by friends.
+ *
+ * @param self - pointer to port object
+ * @param waits - pointer to array to which wait objects are copied
+ * @param n_waits - number of wait objects fitting in array waits
+ *
+ * @return Number of wait objects, or 0 upon an error.
+ */
+unsigned su_port_query(su_port_t *self, su_wait_t *waits, unsigned n_waits)
+{
+ unsigned n;
+
+ assert(SU_PORT_OWN_THREAD(self));
+
+ n = self->sup_n_waits;
+
+ if (n_waits != 0) {
+ if (waits && n_waits >= n)
+ memcpy(waits, self->sup_waits, n * sizeof(*waits));
+ else
+ n = 0;
+ }
+
+ return n;
+}
+#endif
+
+/** @internal Enable multishot mode.
+ *
+ * The function su_port_multishot() enables, disables or queries the
+ * multishot mode for the port. The multishot mode determines how the events
+ * are scheduled by port. If multishot mode is enabled, port serves all the
+ * sockets that have received network events. If it is disables, only first
+ * socket event is served.
+ *
+ * @param self pointer to port object
+ * @param multishot multishot mode (0 => disables, 1 => enables, -1 => query)
+ *
+ * @retval 0 multishot mode is disabled
+ * @retval 1 multishot mode is enabled
+ * @retval -1 an error occurred
+ */
+int su_port_multishot(su_port_t *self, int multishot)
+{
+ if (multishot < 0)
+ return self->sup_multishot;
+ else if (multishot == 0 || multishot == 1)
+ return self->sup_multishot = multishot;
+ else
+ return (errno = EINVAL), -1;
+}
+
+/** @internal Enable threadsafe operation. */
+static
+int su_port_threadsafe(su_port_t *port)
+{
+ return su_home_threadsafe(port->sup_home);
+}
+
+/** @internal Main loop.
+ *
+ * The function @c su_port_run() waits for wait objects and the timers
+ * associated with the port object. When any wait object is signaled or
+ * timer is expired, it invokes the callbacks, and returns waiting.
+ *
+ * The function @c su_port_run() runs until @c su_port_break() is called
+ * from a callback.
+ *
+ * @param self pointer to port object
+ *
+ */
+void su_port_run(su_port_t *self)
+{
+ su_duration_t tout = 0;
+
+ assert(SU_PORT_OWN_THREAD(self));
+
+ for (self->sup_running = 1; self->sup_running;) {
+ tout = 2000;
+
+ if (self->sup_prepoll)
+ self->sup_prepoll(self->sup_pp_magic, self->sup_pp_root);
+
+ if (self->sup_head)
+ su_port_getmsgs(self);
+
+ if (self->sup_timers)
+ su_timer_expire(&self->sup_timers, &tout, su_now());
+
+ if (!self->sup_running)
+ break;
+
+ if (self->sup_head) /* if there are messages do a quick wait */
+ tout = 0;
+
+ su_port_wait_events(self, tout);
+ }
+}
+
+#if tuning
+/* This version can help tuning... */
+void su_port_run_tune(su_port_t *self)
+{
+ int i;
+ int timers = 0, messages = 0, events = 0;
+ su_duration_t tout = 0, tout0;
+ su_time_t started = su_now(), woken = started, bedtime = woken;
+
+ assert(SU_PORT_OWN_THREAD(self));
+
+ for (self->sup_running = 1; self->sup_running;) {
+ tout0 = tout, tout = 2000;
+
+ timers = 0, messages = 0;
+
+ if (self->sup_prepoll)
+ self->sup_prepoll(self->sup_pp_magic, self->sup_pp_root);
+
+ if (self->sup_head)
+ messages = su_port_getmsgs(self);
+
+ if (self->sup_timers)
+ timers = su_timer_expire(&self->sup_timers, &tout, su_now());
+
+ if (!self->sup_running)
+ break;
+
+ if (self->sup_head) /* if there are messages do a quick wait */
+ tout = 0;
+
+ bedtime = su_now();
+
+ events = su_port_wait_events(self, tout);
+
+ woken = su_now();
+
+ if (messages || timers || events)
+ SU_DEBUG_1(("su_port_run(%p): %.6f: %u messages %u timers %u "
+ "events slept %.6f/%.3f\n",
+ self, su_time_diff(woken, started), messages, timers, events,
+ su_time_diff(woken, bedtime), tout0 * 1e-3));
+
+ if (!self->sup_running)
+ break;
+ }
+}
+#endif
+
+/** @internal
+ * The function @c su_port_break() is used to terminate execution of @c
+ * su_port_run(). It can be called from a callback function.
+ *
+ * @param self pointer to port
+ *
+ */
+void su_port_break(su_port_t *self)
+{
+ self->sup_running = 0;
+}
+
+/** @internal
+ * The function @c su_port_wait_events() is used to poll() for wait objects
+ *
+ * @param self pointer to port
+ * @param tout timeout in milliseconds
+ *
+ * @return number of events handled
+ */
+static
+int su_port_wait_events(su_port_t *self, su_duration_t tout)
+{
+ int i, events = 0;
+ su_wait_t *waits = self->sup_waits;
+ int n = self->sup_n_waits;
+ su_root_t *root;
+#if HAVE_POLL
+ unsigned version = self->sup_registers;
+#endif
+#if HAVE_EPOLL
+
+ if (self->sup_epoll != -1) {
+ int const M = 4;
+ struct epoll_event ev[M];
+ int j, index;
+ int *indices = self->sup_indices;
+
+ n = epoll_wait(self->sup_epoll, ev, self->sup_multishot ? M : 1, tout);
+
+ assert(n <= M);
+
+ for (j = 0; j < n; j++) {
+ su_root_t *root;
+ su_root_magic_t *magic;
+
+ if (!ev[j].events || ev[j].data.u32 > INDEX_MAX)
+ continue;
+ index = (int)ev[j].data.u32;
+ assert(index > 0 && index <= self->sup_size_waits);
+ i = indices[index]; assert(i >= 0 && i <= self->sup_n_waits);
+ root = self->sup_wait_roots[i];
+ magic = root ? su_root_magic(root) : NULL;
+ waits[i].revents = ev[j].events;
+ self->sup_wait_cbs[i](magic, &waits[i], self->sup_wait_args[i]);
+ events++;
+ /* Callback function used su_register()/su_deregister() */
+ if (version != self->sup_registers)
+ break;
+ }
+
+ return n < 0 ? n : events;
+ }
+#endif
+
+ i = su_wait(waits, (unsigned)n, tout);
+
+ if (i >= 0 && i < n) {
+#if HAVE_POLL
+ /* poll() can return events for multiple wait objects */
+ if (self->sup_multishot) {
+ for (; i < n; i++) {
+ if (waits[i].revents) {
+ root = self->sup_wait_roots[i];
+ self->sup_wait_cbs[i](root ? su_root_magic(root) : NULL,
+ &waits[i],
+ self->sup_wait_args[i]);
+ events++;
+ /* Callback function used su_register()/su_deregister() */
+ if (version != self->sup_registers)
+ break;
+ }
+ }
+ }
+#else /* !HAVE_POLL */
+ if (0) {
+ }
+#endif
+ else {
+ root = self->sup_wait_roots[i];
+ self->sup_wait_cbs[i](root ? su_root_magic(root) : NULL,
+ &self->sup_waits[i],
+ self->sup_wait_args[i]);
+ events++;
+ }
+ }
+
+ return events;
+}
+
+/** @internal
+ * Used to check wait events in callbacks that take lots of time
+ *
+ * This function does a timeout 0 poll() and runs wait objects.
+ *
+ * @param port pointer to port
+ *
+ * @return number of events handled
+ */
+static
+int su_port_yield(su_port_t *port)
+{
+ return su_port_wait_events(port, 0);
+}
+
+/** @internal Block until wait object is signaled or timeout.
+ *
+ * This function waits for wait objects and the timers associated with
+ * the root object. When any wait object is signaled or timer is
+ * expired, it invokes the callbacks.
+ *
+ * This function returns when a callback has been invoked or @c tout
+ * milliseconds is elapsed.
+ *
+ * @param self pointer to port
+ * @param tout timeout in milliseconds
+ *
+ * @return
+ * Milliseconds to the next invocation of timer, or @c SU_WAIT_FOREVER if
+ * there are no active timers.
+ */
+su_duration_t su_port_step(su_port_t *self, su_duration_t tout)
+{
+ su_time_t now = su_now();
+
+ assert(SU_PORT_OWN_THREAD(self));
+
+ if (self->sup_prepoll)
+ self->sup_prepoll(self->sup_pp_magic, self->sup_pp_root);
+
+ if (self->sup_head)
+ su_port_getmsgs(self);
+
+ if (self->sup_timers)
+ su_timer_expire(&self->sup_timers, &tout, now);
+
+ /* if there are messages do a quick wait */
+ if (self->sup_head)
+ tout = 0;
+
+ if (su_port_wait_events(self, tout))
+ tout = 0;
+ else
+ tout = SU_WAIT_FOREVER;
+
+ if (self->sup_head)
+ su_port_getmsgs(self);
+
+ if (self->sup_timers)
+ su_timer_expire(&self->sup_timers, &tout, su_now());
+
+ if (self->sup_head)
+ tout = 0;
+
+ return tout;
+}
+
+
+/** @internal
+ * Checks if the calling thread owns the port object.
+ *
+ * @param self pointer to a port object
+ *
+ * @retval true (nonzero) if the calling thread owns the port,
+ * @retval false (zero) otherwise.
+ */
+int su_port_own_thread(su_port_t const *self)
+{
+ return self == NULL || SU_PORT_OWN_THREAD(self);
+}
+
+#if 0
+/** @internal
+ * Prints out the contents of the port.
+ *
+ * @param self pointer to a port
+ * @param f pointer to a file (if @c NULL, uses @c stdout).
+ */
+void su_port_dump(su_port_t const *self, FILE *f)
+{
+ int i;
+#define IS_WAIT_IN(x) (((x)->events & SU_WAIT_IN) ? "IN" : "")
+#define IS_WAIT_OUT(x) (((x)->events & SU_WAIT_OUT) ? "OUT" : "")
+#define IS_WAIT_ACCEPT(x) (((x)->events & SU_WAIT_ACCEPT) ? "ACCEPT" : "")
+
+ if (f == NULL)
+ f = stdout;
+
+ fprintf(f, "su_port_t at %p:\n", self);
+ fprintf(f, "\tport is%s running\n", self->sup_running ? "" : "not ");
+#if SU_HAVE_PTHREADS
+ fprintf(f, "\tport tid %p\n", (void *)self->sup_tid);
+#endif
+#if SU_HAVE_MBOX
+ fprintf(f, "\tport mbox %d (%s%s%s)\n", self->sup_mbox[0],
+ IS_WAIT_IN(&self->sup_mbox_wait),
+ IS_WAIT_OUT(&self->sup_mbox_wait),
+ IS_WAIT_ACCEPT(&self->sup_mbox_wait));
+#endif
+ fprintf(f, "\t%d wait objects\n", self->sup_n_waits);
+ for (i = 0; i < self->sup_n_waits; i++) {
+
+ }
+}
+
+#endif
+
+/* =========================================================================
+ * Pre-poll() callback
+ */
+
+int su_port_add_prepoll(su_port_t *port,
+ su_root_t *root,
+ su_prepoll_f *callback,
+ su_prepoll_magic_t *magic)
+{
+ if (port->sup_prepoll)
+ return -1;
+
+ port->sup_prepoll = callback;
+ port->sup_pp_magic = magic;
+ port->sup_pp_root = root;
+
+ return 0;
+}
+
+int su_port_remove_prepoll(su_port_t *port,
+ su_root_t *root)
+{
+ if (port->sup_pp_root != root)
+ return -1;
+
+ port->sup_prepoll = NULL;
+ port->sup_pp_magic = NULL;
+ port->sup_pp_root = NULL;
+
+ return 0;
+}
+
+/* =========================================================================
+ * Timers
+ */
+
+static
+su_timer_t **su_port_timers(su_port_t *self)
+{
+ return &self->sup_timers;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_port.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_port.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,360 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SU_PORT_H
+/** Defined when <su_port.h> has been included. */
+#define SU_PORT_H
+
+/**@IFILE su_port.h
+ *
+ * @brief Internal OS-independent syncronization interface.
+ *
+ * This looks like the "reactor" pattern.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Fri May 12 14:13:34 2000 ppessi
+ */
+
+#ifndef SU_MSG_ARG_T
+#define SU_MSG_ARG_T union { char anoymous[4]; }
+#endif
+
+#ifndef SU_WAIT_H
+#include "sofia-sip/su_wait.h"
+#endif
+
+#ifndef SU_MODULE_DEBUG_H
+#include "su_module_debug.h"
+#endif
+
+#ifndef SU_ALLOC_H
+#include <sofia-sip/su_alloc.h>
+#endif
+
+#include <assert.h>
+
+#define SU_WAIT_MIN (16)
+
+SOFIA_BEGIN_DECLS
+
+/** Message */
+struct su_msg_s {
+ isize_t sum_size;
+ su_msg_t *sum_next;
+ su_task_r sum_to;
+ su_task_r sum_from;
+ su_msg_f sum_func;
+ su_msg_f sum_report;
+ su_msg_arg_t sum_data[1]; /* minimum size, may be extended */
+};
+
+struct _GSource;
+
+/** Root structure */
+struct su_root_s {
+ int sur_size;
+ su_root_magic_t *sur_magic;
+ su_root_deinit_f sur_deinit;
+ su_task_r sur_task;
+ su_task_r sur_parent;
+ unsigned sur_threading : 1;
+ unsigned sur_deiniting : 1;
+};
+
+#define SU_ROOT_MAGIC(r) ((r) ? (r)->sur_magic : NULL)
+
+/** Virtual function table for port */
+typedef struct {
+ unsigned su_vtable_size;
+ void (*su_port_lock)(su_port_t *port, char const *who);
+ void (*su_port_unlock)(su_port_t *port, char const *who);
+ void (*su_port_incref)(su_port_t *port, char const *who);
+ void (*su_port_decref)(su_port_t *port, int block, char const *who);
+ struct _GSource *(*su_port_gsource)(su_port_t *port);
+ int (*su_port_send)(su_port_t *self, su_msg_r rmsg);
+ int (*su_port_register)(su_port_t *self,
+ su_root_t *root,
+ su_wait_t *wait,
+ su_wakeup_f callback,
+ su_wakeup_arg_t *arg,
+ int priority);
+ int (*su_port_unregister)(su_port_t *port,
+ su_root_t *root,
+ su_wait_t *wait,
+ su_wakeup_f callback,
+ su_wakeup_arg_t *arg);
+ int (*su_port_deregister)(su_port_t *self, int i);
+ int (*su_port_unregister_all)(su_port_t *self,
+ su_root_t *root);
+ int (*su_port_eventmask)(su_port_t *self, int index, int socket, int events);
+ void (*su_port_run)(su_port_t *self);
+ void (*su_port_break)(su_port_t *self);
+ su_duration_t (*su_port_step)(su_port_t *self, su_duration_t tout);
+
+ int (*su_port_own_thread)(su_port_t const *port);
+
+ int (*su_port_add_prepoll)(su_port_t *port,
+ su_root_t *root,
+ su_prepoll_f *,
+ su_prepoll_magic_t *);
+
+ int (*su_port_remove_prepoll)(su_port_t *port,
+ su_root_t *root);
+
+ su_timer_t **(*su_port_timers)(su_port_t *port);
+
+ int (*su_port_multishot)(su_port_t *port, int multishot);
+
+ int (*su_port_threadsafe)(su_port_t *port);
+
+ /* Extension from > 1.12.0 */
+ int (*su_port_yield)(su_port_t *port);
+} su_port_vtable_t;
+
+SOFIAPUBFUN su_port_t *su_port_create(void)
+ __attribute__((__malloc__));
+
+SOFIAPUBFUN void su_msg_delivery_report(su_msg_r msg);
+SOFIAPUBFUN su_duration_t su_timer_next_expires(su_timer_t const * t,
+ su_time_t now);
+SOFIAPUBFUN su_root_t *su_root_create_with_port(su_root_magic_t *magic,
+ su_port_t *port);
+
+#if SU_PORT_IMPLEMENTATION
+
+#else
+struct su_port_s {
+ su_home_t sup_home[1];
+ su_port_vtable_t const *sup_vtable;
+};
+
+static inline
+void su_port_lock(su_port_t *self, char const *who)
+{
+ if (self) self->sup_vtable->su_port_lock(self, who);
+}
+
+#define SU_PORT_LOCK(p, f) (su_port_lock(p, #f))
+
+static inline
+void su_port_unlock(su_port_t *self, char const *who)
+{
+ if (self) self->sup_vtable->su_port_unlock(self, who);
+}
+
+#define SU_PORT_UNLOCK(p, f) (su_port_unlock(p, #f))
+
+static inline
+void su_port_incref(su_port_t *self, char const *who)
+{
+ if (self) self->sup_vtable->su_port_incref(self, who);
+}
+
+#define SU_PORT_INCREF(p, f) (su_port_incref(p, #f))
+
+static inline
+void su_port_decref(su_port_t *self, char const *who)
+{
+ if (self) self->sup_vtable->su_port_decref(self, 0, who);
+}
+
+#define SU_PORT_DECREF(p, f) (su_port_decref(p, #f))
+
+static inline
+void su_port_zapref(su_port_t *self, char const *who)
+{
+ if (self) self->sup_vtable->su_port_decref(self, 1, who);
+}
+
+#define SU_PORT_ZAPREF(p, f) (su_port_zapref(p, #f))
+
+static inline
+struct _GSource *su_port_gsource(su_port_t *self)
+{
+ return self ? self->sup_vtable->su_port_gsource(self) : NULL;
+}
+
+
+static inline
+int su_port_send(su_port_t *self, su_msg_r rmsg)
+{
+ if (self)
+ return self->sup_vtable->su_port_send(self, rmsg);
+ errno = EINVAL;
+ return -1;
+}
+
+
+static inline
+int su_port_register(su_port_t *self,
+ su_root_t *root,
+ su_wait_t *wait,
+ su_wakeup_f callback,
+ su_wakeup_arg_t *arg,
+ int priority)
+{
+ if (self)
+ return self->sup_vtable->su_port_register(self, root, wait,
+ callback, arg, priority);
+ errno = EINVAL;
+ return -1;
+}
+
+static inline
+int su_port_unregister(su_port_t *self,
+ su_root_t *root,
+ su_wait_t *wait,
+ su_wakeup_f callback,
+ su_wakeup_arg_t *arg)
+{
+ if (self)
+ return self->sup_vtable->
+ su_port_unregister(self, root, wait, callback, arg);
+ errno = EINVAL;
+ return -1;
+}
+
+static inline
+int su_port_deregister(su_port_t *self, int i)
+{
+ if (self)
+ return self->sup_vtable->
+ su_port_deregister(self, i);
+ errno = EINVAL;
+ return -1;
+}
+
+static inline
+int su_port_unregister_all(su_port_t *self,
+ su_root_t *root)
+{
+ if (self)
+ return self->sup_vtable->
+ su_port_unregister_all(self, root);
+ errno = EINVAL;
+ return -1;
+}
+
+static inline
+int su_port_eventmask(su_port_t *self, int index, int socket, int events)
+{
+ if (self)
+ return self->sup_vtable->
+ su_port_eventmask(self, index, socket, events);
+ assert(self);
+ errno = EINVAL;
+ return -1;
+}
+
+static inline
+void su_port_run(su_port_t *self)
+{
+ if (self)
+ self->sup_vtable->su_port_run(self);
+}
+
+static inline
+void su_port_break(su_port_t *self)
+{
+ if (self)
+ self->sup_vtable->su_port_break(self);
+}
+
+static inline
+su_duration_t su_port_step(su_port_t *self, su_duration_t tout)
+{
+ if (self)
+ return self->sup_vtable->su_port_step(self, tout);
+ errno = EINVAL;
+ return (su_duration_t)-1;
+}
+
+
+static inline
+int su_port_own_thread(su_port_t const *self)
+{
+ return self == NULL || self->sup_vtable->su_port_own_thread(self);
+}
+
+static inline
+int su_port_add_prepoll(su_port_t *self,
+ su_root_t *root,
+ su_prepoll_f *prepoll,
+ su_prepoll_magic_t *magic)
+{
+ if (self)
+ return self->sup_vtable->
+ su_port_add_prepoll(self, root, prepoll, magic);
+ errno = EINVAL;
+ return -1;
+}
+
+static inline
+int su_port_remove_prepoll(su_port_t *self,
+ su_root_t *root)
+{
+ if (self)
+ return self->sup_vtable->su_port_remove_prepoll(self, root);
+ errno = EINVAL;
+ return -1;
+}
+
+static inline
+su_timer_t **su_port_timers(su_port_t *self)
+{
+ if (self)
+ return self->sup_vtable->su_port_timers(self);
+ errno = EINVAL;
+ return NULL;
+}
+
+static inline
+int su_port_multishot(su_port_t *self, int multishot)
+{
+ if (self)
+ return self->sup_vtable->su_port_multishot(self, multishot);
+
+ assert(self);
+ errno = EINVAL;
+ return -1;
+}
+
+static inline
+int su_port_threadsafe(su_port_t *self)
+{
+ if (self)
+ return self->sup_vtable->su_port_threadsafe(self);
+
+ assert(self);
+ errno = EINVAL;
+ return -1;
+}
+
+
+#endif
+
+SOFIA_END_DECLS
+
+#endif /* SU_PORT_H */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_proxy.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_proxy.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,672 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_root_ex
+ *
+ * @file su_proxy.c
+ *
+ * @brief Transport level proxy demonstrating various @b su features.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed May 23 17:42:40 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <errno.h>
+
+#include <assert.h>
+
+typedef struct proxy_s proxy_t;
+typedef struct forwarder_s forwarder_t;
+typedef struct buffer_s buffer_t;
+
+#define SU_ROOT_MAGIC_T proxy_t
+#define SU_MSG_ARG_T su_socket_t
+#define SU_WAKEUP_ARG_T forwarder_t
+
+#include "sofia-sip/su.h"
+#include "sofia-sip/su_wait.h"
+#include "sofia-sip/su_alloc.h"
+#include "su_module_debug.h"
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+#define __func__ "su_proxy"
+#endif
+
+struct proxy_s
+{
+ su_home_t pr_home[1];
+ su_root_t *pr_root;
+ su_addrinfo_t *pr_addrinfo;
+ forwarder_t *pr_forwarders;
+};
+
+struct forwarder_s
+{
+ forwarder_t *f_next;
+ forwarder_t **f_prev;
+ proxy_t *f_pr;
+ su_socket_t f_socket;
+ su_wait_t f_wait[2];
+ forwarder_t *f_peer;
+ su_sockaddr_t f_dest[1];
+ buffer_t *f_buf;
+ unsigned long f_sent; /* bytes sent */
+ unsigned f_shutdown : 1;
+ unsigned f_upstream : 1;
+};
+
+struct buffer_s
+{
+ buffer_t *b_next;
+ buffer_t **b_prev;
+ int b_sent;
+ int b_used;
+ char b_data[8192];
+};
+
+char const help[] =
+"usage: su_proxy [-ntu] remotehost remoteport [localport]\n";
+
+void usage(void)
+{
+ fputs(help, stderr);
+}
+
+static int pr_init(proxy_t *pr);
+static int pr_config(proxy_t *pr, int argc, char *argv[]);
+static int pr_run(proxy_t *pr);
+static void pr_deinit(proxy_t *pr);
+
+static forwarder_t *forwarder_create(proxy_t *pr);
+static forwarder_t *forwarder_create_listener(proxy_t *pr, su_addrinfo_t *ai);
+static void forwarder_deinit(forwarder_t *f);
+static int forwarder_init_stream(forwarder_t *f);
+static int forwarder_init_dgram(forwarder_t *f);
+static int forwarder_accept(proxy_t *pr, su_wait_t *w, forwarder_t *f);
+static int forwarder_stream_peer(proxy_t *pr, forwarder_t *f);
+static int forwarder_connected(proxy_t *pr, su_wait_t *w, forwarder_t *f);
+static int forwarder_recv(proxy_t *pr, su_wait_t *w, forwarder_t *f);
+static int forwarder_send(proxy_t *pr, forwarder_t *f, buffer_t *b);
+static int forwarder_append(forwarder_t *f, buffer_t *b0);
+static int forwarder_empty(proxy_t *pr, su_wait_t *w, forwarder_t *f);
+static int forwarder_shutdown(forwarder_t *f);
+static void forwarder_close(forwarder_t *f1);
+
+int main(int argc, char *argv[])
+{
+ proxy_t pr[1] = {{{ SU_HOME_INIT(pr) }}};
+ int error;
+
+ error = pr_init(pr);
+ if (error == 0) {
+ if ((error = pr_config(pr, argc, argv)) > 1)
+ usage();
+ }
+
+ if (error == 0)
+ error = pr_run(pr);
+
+ pr_deinit(pr);
+
+ su_deinit();
+
+ exit(error);
+}
+
+int pr_init(proxy_t *pr)
+{
+ su_init();
+ su_home_init(pr->pr_home);
+ pr->pr_root = su_root_create(pr);
+ return pr->pr_root ? 0 : 1;
+}
+
+int pr_config(proxy_t *pr, int argc, char *argv[])
+{
+ su_addrinfo_t *res = NULL, *ai, hints[1] = {{ 0 }};
+ char *service;
+ int error;
+ char const *option;
+
+ /* char const *argv0 = argv[0]; */
+
+ while (argv[1][0] == '-') {
+ option = argv[1];
+ argv++, argc--;
+ if (strcmp(option, "--") == 0)
+ break;
+ else if (strcmp(option, "-n") == 0) {
+ hints->ai_flags |= AI_NUMERICHOST;
+ }
+ else if (strcmp(option, "-d") == 0) {
+ hints->ai_socktype = SOCK_DGRAM;
+ }
+ else if (strcmp(option, "-s") == 0) {
+ hints->ai_socktype = SOCK_STREAM;
+ }
+ else if (strcmp(option, "-4") == 0) {
+ hints->ai_family = AF_INET;
+ }
+#if SU_HAVE_IN6
+ else if (strcmp(option, "-6") == 0) {
+ hints->ai_family = AF_INET6;
+ }
+#endif
+ }
+
+ if (argc < 3)
+ return 2;
+
+ if ((error = su_getaddrinfo(argv[1], argv[2], hints, &res))) {
+ fprintf(stderr, "getaddrinfo: %s:%s: %s\n",
+ argv[1], argv[2], su_gai_strerror(error));
+ return 1;
+ }
+
+ pr->pr_addrinfo = res;
+
+ if (argv[3])
+ service = argv[3];
+ else
+ service = argv[2];
+
+ hints->ai_flags |= AI_PASSIVE;
+
+ if ((error = su_getaddrinfo(NULL, service, hints, &res))) {
+ fprintf(stderr, "getaddrinfo: %s: %s\n", service, su_gai_strerror(error));
+ return 1;
+ }
+
+ for (ai = res;
+ ai;
+ ai = ai->ai_next) {
+ forwarder_create_listener(pr, ai);
+ }
+
+ su_freeaddrinfo(res);
+
+ if (!pr->pr_forwarders) {
+ fprintf(stderr, "%s:%s: %s\n", argv[1], argv[2], "unable to forward");
+ return 1;
+ }
+
+ return 0;
+}
+
+void pr_deinit(proxy_t *pr)
+{
+ if (pr->pr_addrinfo)
+ su_freeaddrinfo(pr->pr_addrinfo), pr->pr_addrinfo = NULL;
+
+ if (pr->pr_root)
+ su_root_destroy(pr->pr_root), pr->pr_root = NULL;
+
+ su_home_deinit(pr->pr_home);
+
+ su_deinit();
+}
+
+static int pr_run(proxy_t *pr)
+{
+ su_root_run(pr->pr_root);
+
+ return 0;
+}
+
+forwarder_t *forwarder_create(proxy_t *pr)
+{
+ forwarder_t *f;
+
+ assert(pr);
+
+ f = su_zalloc(pr->pr_home, sizeof (*f));
+
+ if (f) {
+ f->f_socket = INVALID_SOCKET;
+ su_wait_init(f->f_wait);
+ su_wait_init(f->f_wait + 1);
+ f->f_pr = pr;
+ if ((f->f_next = pr->pr_forwarders))
+ f->f_next->f_prev = &f->f_next;
+ f->f_prev = &pr->pr_forwarders;
+ pr->pr_forwarders = f;
+ }
+
+ return f;
+}
+
+void forwarder_destroy(forwarder_t *f)
+{
+ if (f) {
+ forwarder_deinit(f);
+
+ if (f->f_peer) {
+ f->f_peer->f_peer = NULL;
+ forwarder_destroy(f->f_peer);
+ f->f_peer = NULL;
+ }
+ assert(f->f_prev);
+
+ if ((*f->f_prev = f->f_next))
+ f->f_next->f_prev = f->f_prev;
+
+ su_free(f->f_pr->pr_home, f);
+ }
+}
+
+void forwarder_deinit(forwarder_t *f)
+{
+ su_root_unregister(f->f_pr->pr_root, f->f_wait, NULL, f);
+ su_wait_destroy(f->f_wait);
+ su_root_unregister(f->f_pr->pr_root, f->f_wait + 1, NULL, f);
+ su_wait_destroy(f->f_wait + 1);
+ if (f->f_socket != INVALID_SOCKET)
+ su_close(f->f_socket), f->f_socket = INVALID_SOCKET;
+ if (f->f_buf)
+ su_free(f->f_pr->pr_home, f->f_buf), f->f_buf = NULL;
+}
+
+static forwarder_t *forwarder_create_listener(proxy_t *pr, su_addrinfo_t *ai)
+{
+ forwarder_t *f;
+ su_socket_t s;
+
+ if (ai->ai_socktype != SOCK_STREAM &&
+ ai->ai_socktype != SOCK_DGRAM)
+ return NULL;
+
+ f = forwarder_create(pr);
+
+ if (f) {
+ s = su_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+ if (s != INVALID_SOCKET) {
+ f->f_socket = s;
+ su_setblocking(s, 0);
+ su_setreuseaddr(s, 1);
+ if (bind(s, ai->ai_addr, ai->ai_addrlen) >= 0) {
+ if (ai->ai_socktype == SOCK_STREAM ?
+ forwarder_init_stream(f) >= 0 :
+ forwarder_init_dgram(f) >= 0)
+ return f;
+ }
+ else {
+ SU_DEBUG_1(("%s: bind: %s\n", __func__, su_strerror(su_errno())));
+ }
+ }
+ }
+
+ forwarder_destroy(f);
+
+ return NULL;
+}
+
+int forwarder_init_stream(forwarder_t *f)
+{
+ if (listen(f->f_socket, SOMAXCONN) < 0)
+ return SOCKET_ERROR;
+
+ if (su_wait_create(f->f_wait, f->f_socket, SU_WAIT_ACCEPT) < 0)
+ return SOCKET_ERROR;
+
+ if (su_root_register(f->f_pr->pr_root, f->f_wait,
+ forwarder_accept, f, 0) < 0)
+ return SOCKET_ERROR;
+
+ return 0;
+}
+
+int forwarder_init_dgram(forwarder_t *f)
+{
+ /* Unimplemented */
+ return SOCKET_ERROR;
+}
+
+/** Accept a connection. */
+int forwarder_accept(proxy_t *pr, su_wait_t *w, forwarder_t *f0)
+{
+ forwarder_t *f;
+ su_sockaddr_t *su;
+ socklen_t sulen;
+ int events;
+
+ events = su_wait_events(w, f0->f_socket);
+
+ f = forwarder_create(pr);
+
+ if (f) {
+ su = f->f_dest;
+ sulen = sizeof(f->f_dest);
+ f->f_socket = accept(f0->f_socket, &su->su_sa, &sulen);
+ f->f_upstream = 1;
+ if (f->f_socket != INVALID_SOCKET) {
+ char buf[SU_ADDRSIZE];
+
+ SU_DEBUG_3(("accept: connection from %s:%u\n",
+ inet_ntop(su->su_family, SU_ADDR(su), buf, sizeof(buf)),
+ ntohs(su->su_port)));
+
+ if (!su_wait_create(f->f_wait, f->f_socket, SU_WAIT_IN) &&
+ !su_wait_create(f->f_wait + 1, f->f_socket, SU_WAIT_OUT)) {
+ if (forwarder_stream_peer(pr, f) != SOCKET_ERROR) {
+ /* success */
+ return 0;
+ }
+ }
+ else {
+ SU_DEBUG_1(("%s: cannot create wait objects\n", __func__));
+ }
+ }
+ }
+
+ forwarder_destroy(f);
+
+ return 0;
+}
+
+int forwarder_stream_peer(proxy_t *pr, forwarder_t *f_peer)
+{
+ forwarder_t *f;
+ su_addrinfo_t *ai;
+
+ assert(f_peer);
+
+ f = forwarder_create(pr);
+ if (!f) {
+ SU_DEBUG_1(("%s: cannot allocate peer\n", __func__));
+ goto error;
+ }
+
+ for (ai = pr->pr_addrinfo; ai; ai = ai->ai_next) {
+ if (ai->ai_socktype == SOCK_STREAM)
+ break;
+ }
+
+ if (!ai) {
+ SU_DEBUG_1(("%s: no matching destination\n", __func__));
+ goto error;
+ }
+
+ f->f_socket = su_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+ if (f->f_socket == INVALID_SOCKET) {
+ SU_DEBUG_1(("%s: socket: %s\n", __func__, su_strerror(su_errno())));
+ goto error;
+ }
+
+ if (su_wait_create(f->f_wait, f->f_socket, SU_WAIT_IN) ||
+ su_wait_create(f->f_wait + 1, f->f_socket, SU_WAIT_OUT)) {
+ SU_DEBUG_1(("%s: cannot create wait objects\n", __func__));
+ goto error;
+ }
+
+ /* Asynchronous connect */
+ su_setblocking(f->f_socket, 0);
+ su_seterrno(0);
+ connect(f->f_socket, ai->ai_addr, ai->ai_addrlen);
+ memcpy(f->f_dest, ai->ai_addr, ai->ai_addrlen);
+
+ if (su_errno() != EINPROGRESS) {
+ SU_DEBUG_1(("%s: connect: %s\n", __func__, su_strerror(su_errno())));
+ goto error;
+ }
+
+ if (su_root_register(pr->pr_root, f->f_wait + 1,
+ forwarder_connected, f, 0) == -1) {
+ SU_DEBUG_1(("%s: cannot register\n", __func__));
+ goto error;
+ }
+
+ f->f_peer = f_peer;
+ f_peer->f_peer = f;
+ return 0;
+
+ error:
+ forwarder_destroy(f);
+ return SOCKET_ERROR;
+}
+
+/** Connection is complete. */
+int forwarder_connected(proxy_t *pr, su_wait_t *w, forwarder_t *f)
+{
+ int events, error;
+ forwarder_t *f_peer;
+
+ events = su_wait_events(w, f->f_socket);
+
+ error = su_soerror(f->f_socket);
+
+ if (error) {
+ SU_DEBUG_1(("connect: %s\n", su_strerror(error)));
+ forwarder_destroy(f);
+ return 0;
+ }
+
+ su_root_unregister(pr->pr_root, f->f_wait + 1, forwarder_connected, f);
+
+ /* Wait for data, forward it to peer */
+ assert(f->f_peer);
+ f_peer = f->f_peer;
+ su_root_register(pr->pr_root, f->f_wait, forwarder_recv, f, 0);
+ su_root_register(pr->pr_root, f_peer->f_wait, forwarder_recv, f_peer, 0);
+
+ return 0;
+}
+
+/** Receive data, forward it to peer */
+int forwarder_recv(proxy_t *pr, su_wait_t *w, forwarder_t *f)
+{
+ buffer_t b[1];
+ int n, events;
+
+ events = su_wait_events(w, f->f_socket);
+
+ n = recv(f->f_socket, b->b_data, sizeof(b->b_data), 0);
+
+ if (n > 0) {
+ b->b_sent = 0; b->b_used = n;
+ if (f->f_peer->f_buf) {
+ forwarder_append(f, b);
+ return 0;
+ }
+ if (forwarder_send(pr, f->f_peer, b) >= 0) {
+ if (b->b_sent < b->b_used) {
+ su_root_unregister(pr->pr_root, w, forwarder_recv, f);
+ su_root_register(pr->pr_root, f->f_peer->f_wait + 1,
+ forwarder_empty, f->f_peer, 0);
+ forwarder_append(f, b);
+ }
+ return 0;
+ }
+ else {
+ /* Error when sending */
+ }
+ }
+ if (n < 0) {
+ int error = su_errno();
+ SU_DEBUG_1(("recv: %s\n", su_strerror(error)));
+
+ if (error == EINTR || error == EAGAIN || error == EWOULDBLOCK) {
+ return 0;
+ }
+ /* XXX */
+ forwarder_destroy(f);
+ }
+
+ /* shutdown */
+ forwarder_shutdown(f);
+
+ return 0;
+}
+
+int forwarder_send(proxy_t *pr, forwarder_t *f, buffer_t *b)
+{
+ int n, error;
+
+ do {
+ n = send(f->f_socket, b->b_data + b->b_sent, b->b_used - b->b_sent, 0);
+
+ if (n < 0) {
+ error = su_errno();
+ if (error == EINTR)
+ continue;
+ SU_DEBUG_1(("send: %s\n", su_strerror(error)));
+ if (error != EAGAIN && error != EWOULDBLOCK)
+ return -error;
+ }
+ else {
+ f->f_sent += n;
+ }
+ }
+ while (n > 0 && (b->b_sent += n) < b->b_used);
+
+ return b->b_used - b->b_sent;
+}
+
+int forwarder_append(forwarder_t *f, buffer_t *b0)
+{
+ buffer_t *b, **bb;
+ int unsent;
+
+ /* Find last buffer */
+ for (bb = &f->f_buf; *bb; bb = &(*bb)->b_next)
+ ;
+
+ unsent = b0->b_used - b0->b_sent;
+ assert(unsent > 0);
+
+ b = su_alloc(f->f_pr->pr_home, offsetof(buffer_t, b_data[unsent]));
+ if (b) {
+ *bb = b;
+ b->b_next = NULL;
+ b->b_prev = bb;
+ b->b_used = unsent;
+ b->b_sent = 0;
+ memcpy(b->b_data, b0->b_data + b->b_sent, unsent);
+ }
+
+ return b ? 0 : -1;
+}
+
+/** Empty forwarder buffers */
+int forwarder_empty(proxy_t *pr, su_wait_t *w, forwarder_t *f)
+{
+ buffer_t *b;
+ int n, events;
+
+ events = su_wait_events(w, f->f_socket);
+
+ while ((b = f->f_buf)) {
+ n = forwarder_send(f->f_pr, f, b);
+ if (n == 0) {
+ if ((f->f_buf = b->b_next))
+ b->b_next->b_prev = &f->f_buf;
+ su_free(f->f_pr->pr_home, b);
+ continue;
+ }
+ else if (n < 0) {
+ /* XXX */
+ }
+ break;
+ }
+
+ if (!f->f_buf) {
+ forwarder_t *f_peer = f->f_peer;
+
+ su_root_unregister(pr->pr_root, w, forwarder_empty, f);
+
+ if (!f->f_shutdown) {
+ /* Buffer is empty - start receiving */
+ su_root_register(pr->pr_root, f_peer->f_wait, forwarder_recv, f_peer, 0);
+ }
+ else {
+ if (shutdown(f->f_socket, 1) < 0) {
+ SU_DEBUG_1(("shutdown(1): %s\n", su_strerror(su_errno())));
+ }
+ if (f_peer->f_shutdown) {
+ forwarder_close(f);
+ }
+ }
+ }
+
+ return 0;
+}
+
+int forwarder_shutdown(forwarder_t *f)
+{
+ forwarder_t *f_peer = f->f_peer;
+ su_sockaddr_t *su = f->f_dest;
+ char buf[SU_ADDRSIZE];
+
+ SU_DEBUG_3(("forwarder_shutdown: shutdown from %s:%u\n",
+ inet_ntop(su->su_family, SU_ADDR(su), buf, sizeof(buf)),
+ ntohs(su->su_port)));
+
+ if (su_root_unregister(f->f_pr->pr_root, f->f_wait, forwarder_recv, f) < 0) {
+ SU_DEBUG_1(("%s: su_root_unregister failed\n", __func__));
+ }
+
+ if (shutdown(f->f_socket, 0) < 0) {
+ SU_DEBUG_1(("shutdown(0): %s\n", su_strerror(su_errno())));
+ }
+ f_peer->f_shutdown = 1;
+ if (!f_peer->f_buf) {
+ if (shutdown(f_peer->f_socket, 1) < 0) {
+ SU_DEBUG_1(("shutdown(1): %s\n", su_strerror(su_errno())));
+ }
+ if (f->f_shutdown) {
+ forwarder_close(f);
+ }
+ }
+ return 0;
+}
+
+/** Close a peer pair */
+void forwarder_close(forwarder_t *f)
+{
+ su_sockaddr_t *su1, *su2;
+ char const *d1, *d2;
+ char buf1[SU_ADDRSIZE], buf2[SU_ADDRSIZE];
+
+ if (f->f_upstream)
+ su1 = f->f_dest, su2 = f->f_peer->f_dest, d1 = "up", d2 = "down";
+ else
+ su2 = f->f_dest, su1 = f->f_peer->f_dest, d2 = "up", d1 = "down";
+
+ SU_DEBUG_3(("forwarder_close: connection from %s:%u to %s:%d\n",
+ inet_ntop(su1->su_family, SU_ADDR(su1), buf1, sizeof(buf1)),
+ ntohs(su1->su_port),
+ inet_ntop(su2->su_family, SU_ADDR(su2), buf2, sizeof(buf2)),
+ ntohs(su2->su_port)));
+
+ forwarder_destroy(f);
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_root.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_root.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1630 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_wait
+ * @CFILE su_root.c
+ * OS-independent synchronization interface.
+ * @internal
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Sep 14 15:51:04 1999 ppessi
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "sofia-sip/su.h"
+
+#if SU_HAVE_PTHREADS
+#include <pthread.h>
+#endif
+
+struct su_root_s;
+
+typedef struct su_cloned_s {
+ struct su_root_s *sc_root;
+ int *sc_wait;
+#if SU_HAVE_PTHREADS
+ pthread_t sc_tid;
+ pthread_mutex_t sc_pause[1];
+ pthread_cond_t sc_resume[1];
+ int sc_paused;
+#endif
+} su_cloned_t;
+
+#define SU_ROOT_MAGIC_T struct su_root_magic_s
+#define SU_WAKEUP_ARG_T struct su_wakeup_arg_s
+#define SU_TIMER_ARG_T struct su_timer_arg_s
+#define SU_CLONE_T su_msg_t
+#define SU_MSG_ARG_T struct su_cloned_s
+
+#include "su_port.h"
+#include "sofia-sip/su_alloc.h"
+
+/**@ingroup su_wait
+ *
+ * @page su_root_t Tasks and root objects
+ *
+ * A task is the basic execution unit for the Sofia event-driven programming
+ * model. According to the model, the program can ask that the event loop
+ * invokes a callback function when a certain event occurs. Such events
+ * include @ref su_root_register "I/O activity", @ref su_timer_t "timers" or
+ * a @ref su_msg_t "message" from other task. The event loop is run with
+ * function su_root_run() or su_root_step().
+ *
+ * Root object gives access to the task control. The root object represents
+ * the task to the code running within task. Through the root, the task code
+ * can access its context object (magic) and thread-synchronization features
+ * like wait objects, timers, and messages.
+ *
+ * When a message is sent between tasks, a task reference #su_task_r is used
+ * to reprent the task address. Reference counting is used to make sure that
+ * the task references stay valid.
+ *
+ * The public API contains following functions:
+ * - su_root_create() [Do not call from cloned task]
+ * - su_root_destroy() [Do not call from cloned task]
+ * - su_root_magic()
+ * - su_root_register()
+ * - su_root_deregister()
+ * - su_root_unregister()
+ * - su_root_threading()
+ * - su_root_run() [Do not call from cloned task]
+ * - su_root_break() [Do not call from cloned task]
+ * - su_root_step() [Do not call from cloned task]
+ * - su_root_task()
+ *
+ * New tasks can be created via su_clone_start() function.
+ */
+
+/**@ingroup su_wait
+ *
+ * @page su_root_register Registering Wait Objects
+ *
+ * When application expects I/O events, it can create a wait object and
+ * register it, a callback function and a context pointer to the #su_root_t
+ * object using the su_root_register() function. Whenever the wait object
+ * receives an event, the registered @link ::su_wakeup_f callback function
+ * @endlink is invoked.
+ *
+ * When successful, the su_root_register() returns an small non-negative
+ * integer representing the registration. The registration can be
+ * manipulated with su_root_eventmask() function, for instance, when sending
+ * through a socket block, the application can add SU_WAIT_OUT event to the
+ * mask.
+ *
+ * The registration can be removed using su_root_deregister() function.
+ */
+
+/**@ingroup su_wait
+ *
+ * Contains hint of number of sockets supported by su_root_t */
+int su_root_size_hint = 64;
+
+/* =========================================================================
+ * Tasks
+ */
+
+su_task_r const su_task_null = SU_TASK_R_INIT;
+
+#define SU_TASK_ZAP(t, f) \
+ while (t->sut_port) { \
+ SU_PORT_DECREF(t->sut_port, f); t->sut_port = NULL; break; }
+
+#define SU_TASK_ZAPP(t, f) \
+ do { if (t->sut_port) { \
+ SU_PORT_DECREF(t->sut_port, f); t->sut_port = NULL; } \
+ t->sut_root = NULL; } while(0)
+
+/**
+ * Initialize a task handle with su_task_null.
+ *
+ * @param task task handle
+ *
+ * @return A reference to the initialized task handle.
+ */
+_su_task_r su_task_init(su_task_r task)
+{
+ assert(task);
+
+ memset(task, 0, sizeof(task));
+ return task;
+}
+
+/**
+ * Destroy a task handle
+ *
+ * @param task task handle
+ */
+void su_task_deinit(su_task_r task)
+{
+ assert(task);
+
+ SU_TASK_ZAP(task, su_task_deinit);
+ task->sut_root = NULL;
+}
+
+/**
+ * Create a new task handle.
+ *
+ * @param task task reference
+ * @param root pointer to root object
+ * @param port pointer to port object
+ *
+ * @return New task handle.
+ */
+_su_task_r su_task_new(su_task_r task, su_root_t *root, su_port_t *port)
+{
+ assert(task);
+
+ task->sut_root = root;
+ if ((task->sut_port = port)) {
+ SU_PORT_INCREF(port, su_task_new);
+ }
+ return task;
+}
+
+/**
+ * Duplicates a task handle.
+ *
+ * @param dst destination task reference
+ * @param src source task reference
+ */
+void su_task_copy(su_task_r dst, su_task_r const src)
+{
+ su_port_t *port;
+
+ assert(src); assert(dst);
+
+ SU_TASK_ZAP(dst, su_task_copy);
+
+ port = src->sut_port;
+ if (port) {
+ SU_PORT_INCREF(port, su_task_copy);
+ }
+
+ dst[0] = src[0];
+}
+
+#define SU_TASK_COPY(d, s, by) (void)((d)[0]=(s)[0], \
+ (s)->sut_port?(void)SU_PORT_INCREF(s->sut_port, by):(void)0)
+
+/**
+ * Moves a task handle.
+ *
+ * @param dst destination task reference
+ * @param src source task reference
+ */
+void su_task_move(su_task_r dst, su_task_r src)
+{
+ SU_TASK_ZAP(dst, su_task_move);
+ dst[0] = src[0];
+ src->sut_port = 0;
+ src->sut_root = 0;
+}
+
+/**
+ * Compare two tasks with each other.
+ *
+ * @param a First task
+ * @param b Second task
+ *
+ * @retval negative number, if a < b
+ * @retval positive number, if a > b
+ * @retval 0, if a == b.
+ */
+int su_task_cmp(su_task_r const a, su_task_r const b)
+{
+ intptr_t retval = a->sut_port - b->sut_port;
+ retval = retval ? retval : (char *)a->sut_root - (char *)b->sut_root;
+
+ if (sizeof(retval) != sizeof(int)) {
+ if (retval < 0)
+ retval = -1;
+ else if (retval > 0)
+ retval = 1;
+ }
+
+ return (int)retval;
+}
+
+/**
+ * Tests if a task is running.
+ *
+ * @param task task handle
+ *
+ * @retval true (nonzero) if task is not stopped,
+ * @retval zero if it is null or stopped.
+ */
+int su_task_is_running(su_task_r const task)
+{
+ return
+ task &&
+ task->sut_port &&
+ task->sut_root;
+}
+
+/** @internal
+ * Attach a root object to the task handle.
+ *
+ * @param self task handle
+ * @param root pointer to the root object
+ *
+ * @retval 0 if successful,
+ * @retval -1 otherwise.
+ */
+int su_task_attach(su_task_r self, su_root_t *root)
+{
+ if (self->sut_port) {
+ self->sut_root = root;
+ return 0;
+ }
+ else
+ return -1;
+}
+
+/**
+ * Get root pointer attached to a task handle.
+ *
+ * @param self task handle
+ *
+ * @return
+ * A pointer to root object attached to the task handle, or NULL if no root
+ * object has been attached.
+ */
+su_root_t *su_task_root(su_task_r const self)
+{
+ if (self->sut_port) return self->sut_root; else return NULL;
+}
+
+#if 0
+/** @internal
+ * Detach a root pointer from task handle.
+ * @bug Not used anymore.
+ */
+int su_task_detach(su_task_r self)
+{
+ self->sut_root = NULL;
+ return 0;
+}
+#endif
+
+/**
+ * Return the timer list associated with given task.
+ *
+ * @param task task handle
+ *
+ * @return A timer list of the task. If there are no timers, it returns
+ * NULL.
+ */
+su_timer_t **su_task_timers(su_task_r const task)
+{
+ return task ? su_port_timers(task->sut_port) : NULL;
+}
+
+#if SU_HAVE_PTHREADS
+
+struct su_task_execute
+{
+ pthread_mutex_t mutex[1];
+ pthread_cond_t cond[1];
+ int (*function)(void *);
+ void *arg;
+ int value;
+};
+
+static void _su_task_execute(su_root_magic_t *m,
+ su_msg_r msg,
+ su_msg_arg_t *a)
+{
+ struct su_task_execute *frame = *(struct su_task_execute **)a;
+ pthread_mutex_lock(frame->mutex);
+ frame->value = frame->function(frame->arg);
+ frame->function = NULL; /* Mark as completed */
+ pthread_cond_signal(frame->cond);
+ pthread_mutex_unlock(frame->mutex);
+}
+
+#endif
+
+/** Execute by task thread
+ *
+ * @retval 0 if successful
+ * @retval -1 upon an error
+ */
+int su_task_execute(su_task_r const task,
+ int (*function)(void *), void *arg,
+ int *return_value)
+{
+ if (function == NULL)
+ return (errno = EFAULT), -1;
+
+ if (!su_port_own_thread(task->sut_port)) {
+#if SU_HAVE_PTHREADS
+ int success;
+ su_msg_r m = SU_MSG_R_INIT;
+ struct su_task_execute frame = {
+ { PTHREAD_MUTEX_INITIALIZER },
+ { PTHREAD_COND_INITIALIZER },
+ function, arg, 0
+ };
+
+ if (su_msg_create(m, task, su_task_null,
+ _su_task_execute, (sizeof &frame)) < 0)
+ return -1;
+
+ *(struct su_task_execute **)su_msg_data(m) = &frame;
+
+ pthread_mutex_lock(frame.mutex);
+
+ success = su_msg_send(m);
+
+ if (success == 0)
+ while (frame.function)
+ pthread_cond_wait(frame.cond, frame.mutex);
+ else
+ su_msg_destroy(m);
+
+ pthread_mutex_unlock(frame.mutex);
+ pthread_mutex_destroy(frame.mutex);
+ pthread_cond_destroy(frame.cond);
+
+ if (return_value)
+ *return_value = frame.value;
+
+ return success;
+#else
+ return (errno = ENOSYS), -1;
+#endif
+ }
+ else {
+ int value = function(arg);
+
+ if (return_value)
+ *return_value = value;
+
+ return 0;
+ }
+}
+
+_su_task_r su_task_new(su_task_r task, su_root_t *root, su_port_t *port);
+int su_task_attach(su_task_r self, su_root_t *root);
+int su_task_detach(su_task_r self);
+
+int su_timer_reset_all(su_timer_t **t0, su_task_r);
+
+/**@ingroup su_wait
+ *
+ * @page su_clone_t Clone Objects
+ *
+ * The process may be divided into many tasks via cloning. Several tasks may
+ * run in context of one thread, or each task may be run by its own thread.
+ * However, only a single thread can execute code within a task. There can
+ * be a 1-to-N mapping from thread to tasks. Thus, software using tasks can
+ * be executed by multiple threads in a multithreaded environment and by a
+ * single thread in a singlethreaded environment.
+ *
+ * The clones are useful for handling tasks that can be executed by a
+ * separate threads, but which do not block excessively. When threads are
+ * not available or they are not needed, clones can also be run in a
+ * single-threaded mode. Running in single-threaded mode is especially
+ * useful while debugging.
+ *
+ * A clone task is created with function su_clone_start(). Each clone has
+ * its own root object (su_root_t), which holds a context pointer
+ * (su_root_magic_t *). The context object can be different from that of
+ * parent task.
+ *
+ * When a clone is started, the clone initialization function is called. The
+ * initialization function should do whatever initialization there is to be
+ * performed, register I/O events and timers, and then return. If the
+ * initialization is successful, the clone task reverts to run the event
+ * loop and invoking the event callbacks until its parent stops it by
+ * calling su_clone_wait() which invokes the deinit function. The clone task
+ * is destroyed when the deinit function returns.
+ *
+ * The public API consists of following functions:
+ * - su_clone_start()
+ * - su_clone_task()
+ * - su_clone_wait()
+ * - su_clone_forget()
+ *
+ * @note
+ * There is only one event loop for each thread which can be shared by
+ * multiple clone tasks. Therefore, the clone tasks can not explicitly run
+ * or step the event loop, but they are limited to event callbacks. A clone
+ * task may not call su_root_break(), su_root_run() or su_root_step().
+ */
+
+static void su_root_deinit(su_root_t *self);
+
+/* Note that is *not* necessary same as su_root_t,
+ * as su_root_t can be extended */
+
+#define sur_port sur_task->sut_port
+#define sur_root sur_task->sut_root
+
+#define SU_ROOT_OWN_THREAD(r) (su_port_own_thread(r->sur_port))
+
+/** Create a reactor object.
+ *
+ * Allocate and initialize the instance of su_root_t.
+ *
+ * @param magic pointer to user data
+ *
+ * @return A pointer to allocated su_root_t instance, NULL on error.
+ */
+su_root_t *su_root_create(su_root_magic_t *magic)
+{
+ return su_root_create_with_port(magic, su_port_create());
+}
+
+/** Create a reactor object using given message port.
+ *
+ * Allocate and initialize the instance of su_root_t.
+ *
+ * @param magic pointer to user data
+ * @param port pointer to a message port
+ *
+ * @return A pointer to allocated su_root_t instance, NULL on error.
+ */
+su_root_t *su_root_create_with_port(su_root_magic_t *magic,
+ su_port_t *port)
+{
+ su_root_t *self;
+
+ if (!port)
+ return NULL;
+
+ self = su_salloc(NULL, sizeof(struct su_root_s));
+
+ if (self) {
+ self->sur_magic = magic;
+#if SU_HAVE_PTHREADS
+ self->sur_threading = SU_HAVE_PTHREADS;
+#else
+ self->sur_threading = 0;
+#endif
+ su_task_new(self->sur_task, self, port);
+ } else {
+ su_port_decref(port, "su_root_create");
+ }
+
+ return self;
+}
+
+/** Destroy a synchronization object.
+ *
+ * Stop and free an instance of su_root_t
+ *
+ * @param self pointer to a root object.
+ */
+void su_root_destroy(su_root_t *self)
+{
+ if (self) {
+ assert(SU_ROOT_OWN_THREAD(self));
+ su_root_deinit(self);
+ su_free(NULL, self);
+ }
+}
+
+/** @internal Deinitialize a synchronization object.
+ *
+ * Deinitialize an instance of su_root_t
+ *
+ * @param self pointer to a root object.
+ */
+static void su_root_deinit(su_root_t *self)
+{
+ self->sur_deiniting = 1;
+
+ if (self->sur_deinit) {
+ su_root_deinit_f deinit = self->sur_deinit;
+ su_root_magic_t *magic = self->sur_magic;
+ self->sur_deinit = NULL;
+ deinit(self, magic);
+ }
+
+ if (self->sur_port) {
+ int n_w = su_port_unregister_all(self->sur_port, self);
+ int n_t = su_timer_reset_all(su_task_timers(self->sur_task), self->sur_task);
+
+ if (n_w || n_t)
+ SU_DEBUG_1(("su_root_deinit: "
+ "%u registered waits, %u timers\n", n_w, n_t));
+ }
+
+ SU_TASK_ZAP(self->sur_parent, su_root_deinit);
+ SU_TASK_ZAP(self->sur_task, su_root_deinit);
+}
+
+/** Set the context pointer.
+ *
+ * Set the context pointer (magic) of a root object.
+ *
+ * @param self pointer to a root object
+ * @param magic pointer to user data
+ *
+ * @retval 0 when successful,
+ * @retval -1 upon error.
+ */
+int su_root_set_magic(su_root_t *self, su_root_magic_t *magic)
+{
+ assert(SU_ROOT_OWN_THREAD(self));
+
+ if (self) {
+ self->sur_magic = magic;
+ }
+
+ return 0;
+}
+
+/** Set threading option.
+ *
+ * Controls whether su_clone_start() creates a new thread.
+ *
+ * @param self pointer to a root object
+ * @param enable if true, enable threading, if false, disable threading
+ *
+ * @return True if threading is enabled.
+ */
+int su_root_threading(su_root_t *self, int enable)
+{
+ if (self) {
+ assert(SU_ROOT_OWN_THREAD(self));
+
+#if SU_HAVE_PTHREADS
+ self->sur_threading = enable = enable != 0;
+ return enable;
+#endif
+ }
+
+ return 0;
+}
+
+/** Get context pointer.
+ *
+ * The function su_root_magic() returns the user context pointer that was
+ * given input to su_root_create() or su_root_set_magic().
+ *
+ * @param self pointer to a root object
+ *
+ * @return A pointer to user data
+ */
+su_root_magic_t *su_root_magic(su_root_t *self)
+{
+ return self ? self->sur_magic : NULL;
+}
+
+/** Get a GSource */
+struct _GSource *su_root_gsource(su_root_t *self)
+{
+ return self ? su_port_gsource(self->sur_port) : NULL;
+}
+
+/** Register a su_wait_t object.
+ *
+ * The function su_root_register() registers a su_wait_t object. The wait
+ * object, a callback function and a argument are stored to the root
+ * object. The callback function is called, when the wait object is
+ * signaled.
+ *
+ * Please note if identical wait objects are inserted, only first one is
+ * ever signalled.
+ *
+ * @param self pointer to root object
+ * @param wait pointer to wait object
+ * @param callback callback function pointer
+ * @param arg argument given to callback function when it is invoked
+ * @param priority relative priority of the wait object
+ * (0 is normal, 1 important, 2 realtime)
+ *
+ * @return Nonzero index of the wait object, or -1 upon an error.
+ */
+int su_root_register(su_root_t *self,
+ su_wait_t *wait,
+ su_wakeup_f callback,
+ su_wakeup_arg_t *arg,
+ int priority)
+{
+ assert(self && self->sur_port);
+
+ if (!self || !self->sur_port)
+ return -1;
+
+ return su_port_register(self->sur_port, self, wait, callback, arg, priority);
+}
+
+/** Unregister a su_wait_t object.
+ *
+ * The function su_root_unregister() unregisters a su_wait_t object. The
+ * wait object, a callback function and a argument are removed from the
+ * root object.
+ *
+ * @param self pointer to root object
+ * @param wait pointer to wait object
+ * @param callback callback function pointer (may be NULL)
+ * @param arg argument given to callback function when it is invoked
+ * (may be NULL)
+ *
+ * @return Nonzero index of the wait object, or -1 upon an error.
+ */
+int su_root_unregister(su_root_t *self,
+ su_wait_t *wait,
+ su_wakeup_f callback, /* XXX - ignored */
+ su_wakeup_arg_t *arg)
+{
+ assert(self && self->sur_port);
+
+ if (!self || !self->sur_port)
+ return -1;
+
+ return su_port_unregister(self->sur_port, self, wait, callback, arg);
+}
+
+/** Remove a su_wait_t registration.
+ *
+ * The function su_root_deregister() deregisters a su_wait_t object. The
+ * wait object, a callback function and a argument are removed from the
+ * root object. The wait object is destroyed.
+ *
+ * @param self pointer to root object
+ * @param i registration index
+ *
+ * @return Index of the wait object, or -1 upon an error.
+ */
+int su_root_deregister(su_root_t *self, int i)
+{
+ if (i == 0 || i == -1)
+ return -1;
+
+ assert(self && self->sur_port);
+
+ if (!self || !self->sur_port)
+ return -1;
+
+ return su_port_deregister(self->sur_port, i);
+}
+
+/** Set mask for a registered event.
+ *
+ * The function su_root_eventmask() sets the mask describing events that can
+ * signal the registered callback.
+ *
+ * @param self pointer to root object
+ * @param index registration index
+ * @param socket socket
+ * @param events new event mask
+ *
+ * @retval 0 when successful,
+ * @retval -1 upon an error.
+ */
+int su_root_eventmask(su_root_t *self, int index, int socket, int events)
+{
+ assert(self && self->sur_port);
+
+ if (!self || !self->sur_port)
+ return -1;
+
+ return su_port_eventmask(self->sur_port, index, socket, events);
+}
+
+/** Set multishot mode.
+ *
+ * The function su_root_multishot() enables, disables or queries the
+ * multishot mode for the root. The multishot mode determines how the events
+ * are scheduled by root. If multishot mode is enabled, root serves all the
+ * sockets that have received network events. If it is disables, only first
+ * socket event is served.
+ *
+ * @param self pointer to root object
+ * @param multishot multishot mode (0 => disables, 1 => enables, -1 => query)
+ *
+ * @retval 0 multishot mode is disabled
+ * @retval 1 multishot mode is enabled
+ * @retval -1 an error occurred
+ */
+int su_root_multishot(su_root_t *self, int multishot)
+{
+ if (self && self->sur_port) {
+ return su_port_multishot(self->sur_port, multishot);
+ } else {
+ return (errno = EINVAL), -1;
+ }
+}
+
+
+/** Run event and message loop.
+ *
+ * The function su_root_run() runs the root main loop. The root loop waits
+ * for wait objects and the timers associated with the root object. When any
+ * wait object is signaled or timer is expired, it invokes the callbacks,
+ * and returns waiting.
+ *
+ * This function returns when su_root_break() is called from a callback.
+ *
+ * @param self pointer to root object
+ *
+ */
+void su_root_run(su_root_t *self)
+{
+ assert(self && self->sur_port);
+
+ if (self && self->sur_port)
+ su_port_run(self->sur_port);
+}
+
+/** Terminate event loop.
+ *
+ * The function su_root_break() is used to terminate execution of
+ * su_root_run(). It can be called from a callback function.
+ *
+ * @param self pointer to root object
+ */
+void su_root_break(su_root_t *self)
+{
+ assert(self && self->sur_port);
+
+ if (self && self->sur_port)
+ su_port_break(self->sur_port);
+}
+
+/** Process events, timers and messages.
+ *
+ * The function su_root_step() waits for wait objects and the timers
+ * associated with the root object. When any wait object is signaled or
+ * timer is expired, it invokes the callbacks.
+ *
+ * This function returns when a callback has been invoked or tout
+ * milliseconds is elapsed.
+ *
+ * @param self pointer to root object
+ * @param tout timeout in milliseconds
+ *
+ * @return Milliseconds to the next invocation of timer, or SU_WAIT_FOREVER
+ * if there are no active timers.
+ */
+su_duration_t su_root_step(su_root_t *self, su_duration_t tout)
+{
+ assert(self && self->sur_port);
+
+ return su_port_step(self->sur_port, tout);
+}
+
+/**Run event and message loop for given duration.
+ *
+ * The function su_root_sleep() runs event loop for @a duration milliseconds.
+ * The event loop waits for wait objects and the timers associated with the
+ * @a root object. When any wait object is signaled, timer is expired, or
+ * message is received, it invokes the callbacks and returns waiting.
+ *
+ * @param self pointer to root object
+ * @param duration milliseconds to run event loop
+ */
+su_duration_t su_root_sleep(su_root_t *self, su_duration_t duration)
+{
+ su_duration_t retval, accrued = 0;
+ su_time_t started = su_now();
+
+ assert(self && self->sur_port);
+
+ do {
+ retval = su_port_step(self->sur_port, duration - accrued);
+ accrued = su_duration(su_now(), started);
+ } while (accrued < duration);
+
+ return retval;
+}
+
+/** Check wait events in callbacks that take lots of time
+ *
+ * This function does a 0 timeout poll() and runs wait objects
+ *
+ * @param self pointer to root object
+ */
+int su_root_yield(su_root_t *self)
+{
+ if (self && self->sur_task[0].sut_port) {
+ su_port_t *port = self->sur_task[0].sut_port;
+ /* Make sure we have su_port_yield extension */
+ if (port->sup_vtable->su_vtable_size >=
+ offsetof(su_port_vtable_t, su_port_yield)
+ && port->sup_vtable->su_port_yield)
+ return port->sup_vtable->su_port_yield(port);
+ }
+ errno = EINVAL;
+ return -1;
+}
+
+/** Get task reference.
+ *
+ * The function su_root_task() is used to retrieve the task reference
+ * (PId) related with the root object.
+ *
+ * @param self a pointer to a root object
+ *
+ * @return The function su_root_task() returns a reference to the task
+ * object.
+ */
+_su_task_r su_root_task(su_root_t const *self)
+{
+ if (self)
+ return self->sur_task;
+ else
+ return su_task_null;
+}
+
+/** Get parent task reference.
+ *
+ * The function su_root_parent() is used to retrieve the task reference
+ * (PId) of the parent task.
+ *
+ * @param self a pointer to a root object
+ *
+ * @return The function su_root_parent() returns a reference to the parent
+ * task object.
+ */
+_su_task_r su_root_parent(su_root_t const *self)
+{
+ if (self)
+ return self->sur_parent;
+ else
+ return su_task_null;
+}
+
+/** Add a pre-poll callback. */
+int su_root_add_prepoll(su_root_t *root,
+ su_prepoll_f *callback,
+ su_prepoll_magic_t *magic)
+{
+ if (root == NULL || root->sur_port == NULL)
+ return -1;
+
+ return su_port_add_prepoll(root->sur_port, root, callback, magic);
+}
+
+/** Remove a pre-poll callback */
+int su_root_remove_prepoll(su_root_t *root)
+{
+ if (root == NULL || root->sur_port == NULL)
+ return -1;
+
+ return su_port_remove_prepoll(root->sur_port, root);
+}
+
+/* ========================================================================
+ * su_clone_t
+ */
+
+/* - su_clone_forget() */
+
+#if SU_HAVE_PTHREADS
+struct clone_args
+{
+ su_root_t * self;
+ su_root_init_f init;
+ su_root_deinit_f deinit;
+ pthread_mutex_t mutex;
+ pthread_cond_t cv;
+ int retval;
+ su_msg_r clone;
+ su_root_t const *parent;
+};
+
+static void su_clone_report2(su_root_magic_t *m,
+ su_msg_r msg,
+ su_cloned_t *sc);
+
+static void su_clone_signal_parent(void *varg)
+{
+ struct clone_args *arg = (struct clone_args *)varg;
+
+ pthread_mutex_lock(&arg->mutex);
+ pthread_cond_signal(&arg->cv);
+ pthread_mutex_unlock(&arg->mutex);
+}
+
+/** Message function for clone message.
+ *
+ * This calls the clone task deinitialization function, which should make
+ * sure that no more messages are sent by clone task.
+ *
+ * @sa su_clone_wait()
+ */
+static void su_clone_break(su_root_magic_t *m,
+ su_msg_r msg,
+ su_cloned_t *sc)
+{
+ su_root_t *root = sc->sc_root;
+
+ root->sur_deiniting = 1;
+
+ if (root->sur_deinit) {
+ su_root_deinit_f deinit = root->sur_deinit;
+ su_root_magic_t *magic = root->sur_magic;
+ root->sur_deinit = NULL;
+ deinit(root, magic);
+ }
+}
+
+/** Delivery report function for clone message.
+ *
+ * This is executed by parent task. This is the last message sent by clone task.
+ */
+static void su_clone_report(su_root_magic_t *m,
+ su_msg_r msg,
+ su_cloned_t *sc)
+{
+ su_msg_report(msg, su_clone_report2);
+}
+
+/** Back delivery report function for clone message.
+ *
+ * This is executed by clone task. It completes the three way handshake and
+ * it is used to signal clone that it can destroy its port.
+ */
+static void su_clone_report2(su_root_magic_t *m,
+ su_msg_r msg,
+ su_cloned_t *sc)
+{
+ su_root_break(sc->sc_root);
+ if (sc->sc_wait)
+ *sc->sc_wait = 0;
+}
+
+static void *su_clone_main(void *varg)
+{
+ struct clone_args *arg = (struct clone_args *)varg;
+ su_root_t *self = arg->self;
+ su_port_t *port;
+ su_cloned_t *sc;
+
+ pthread_cleanup_push(su_clone_signal_parent, varg);
+
+#if SU_HAVE_WINSOCK
+ su_init();
+#endif
+
+ port = su_port_create();
+ if (!port)
+ pthread_exit(NULL);
+ su_port_threadsafe(port);
+ SU_PORT_INCREF(port, su_clone_main);
+
+ /* Change task ownership */
+ SU_PORT_INCREF(self->sur_task->sut_port = port, su_clone_main);
+ self->sur_task->sut_root = self;
+
+ if (su_msg_create(arg->clone,
+ self->sur_task, su_root_task(arg->parent),
+ su_clone_break, sizeof(self)) != 0) {
+ su_port_decref(self->sur_port, "su_clone_main");
+ self->sur_port = NULL;
+ pthread_exit(NULL);
+ }
+
+ su_msg_report(arg->clone, su_clone_report);
+
+ sc = su_msg_data(arg->clone);
+ sc->sc_root = self;
+ sc->sc_tid = pthread_self();
+
+ pthread_mutex_init(sc->sc_pause, NULL);
+ pthread_cond_init(sc->sc_resume, NULL);
+ pthread_mutex_lock(sc->sc_pause);
+
+ if (arg->init && arg->init(self, self->sur_magic) != 0) {
+ if (arg->deinit)
+ arg->deinit(self, self->sur_magic);
+ su_msg_destroy(arg->clone);
+ su_port_decref(self->sur_port, "su_clone_main");
+ self->sur_port = NULL;
+ pthread_exit(NULL);
+ }
+
+ arg->retval = 0;
+
+ pthread_cleanup_pop(1); /* signal change of ownership */
+
+ su_root_run(self); /* Do the work */
+
+ su_root_destroy(self); /* Cleanup root */
+
+ SU_PORT_ZAPREF(port, su_clone_main);
+
+#if SU_HAVE_WINSOCK
+ su_deinit();
+#endif
+
+ return NULL;
+}
+#endif
+
+static void su_clone_xyzzy(su_root_magic_t *m,
+ su_msg_r msg,
+ su_cloned_t *sc)
+{
+ su_root_destroy(sc->sc_root);
+ if (sc->sc_wait)
+ *sc->sc_wait = 0;
+}
+
+/** Start a clone task.
+ *
+ * The function su_clone_start() allocates and initializes a sub-task.
+ * Depending on the settings, a separate thread may be created to execute
+ * the sub-task. The sub-task is represented by clone handle to the rest of
+ * the application. The function su_clone_start() returns the clone handle
+ * in @a return_clone. The clone handle is used to communicate with the
+ * newly created clone task using messages.
+ *
+ * A new #su_root_t object is created for the sub-task with the @a magic as
+ * the root context pointer. Because the sub-task may or may not have its
+ * own thread, all its activity must be scheduled via this root object. In
+ * other words, the sub-task can be schedule
+ * -# I/O events with su_root_register()
+ * -# timers with su_timer_set(), su_timer_set_at() or su_timer_run()
+ * -# messages with su_msg_send().
+ *
+ * Messages can also be used to pass information between tasks or threads.
+ *
+ * In multi-threaded implementation, su_clone_start() launches a new thread,
+ * and the initialization routine is executed by this newly created thread.
+ * The calling thread blocks until the initialization routine completes. If
+ * the initialization routine returns #su_success (0), the sub-task is
+ * considered to be created successfully. After the successful
+ * initialization, the sub-task continues to execeute the function
+ * su_root_run().
+ *
+ * In single-threaded implementations, just a new root object is created.
+ * The initialization routine is called directly from su_clone_start().
+ *
+ * If the initalization function @a init fails, the sub-task (either the
+ * newly created thread or the current thread executing the su_clone_start()
+ * function) calls the deinitialization function, and su_clone_start()
+ * returns NULL.
+ *
+ * @param parent root to be cloned (may be NULL if multi-threaded)
+ * @param return_clone reference to a clone [OUT]
+ * @param magic pointer to user data
+ * @param init initialization function
+ * @param deinit deinitialization function
+ *
+ * @return 0 if successfull, -1 upon an error.
+ *
+ * @sa su_root_threading(), su_clone_task(), su_clone_stop(), su_clone_wait(),
+ * su_clone_forget().
+ */
+int su_clone_start(su_root_t *parent,
+ su_clone_r return_clone,
+ su_root_magic_t *magic,
+ su_root_init_f init,
+ su_root_deinit_f deinit)
+{
+ su_root_t *child;
+ int retval = -1;
+
+ if (parent) {
+ assert(SU_ROOT_OWN_THREAD(parent));
+ assert(parent->sur_port);
+ }
+#if !SU_HAVE_PTHREADS
+ else {
+ /* if we don't have threads, we *must* have parent root */
+ return -1;
+ }
+#endif
+
+ child = su_salloc(NULL, sizeof(struct su_root_s));
+
+#if SU_HAVE_PTHREADS
+ if (child && (parent == NULL || parent->sur_threading)) {
+ struct clone_args arg = {
+ NULL, NULL, NULL,
+ PTHREAD_MUTEX_INITIALIZER,
+ PTHREAD_COND_INITIALIZER,
+ -1,
+ SU_MSG_R_INIT,
+ NULL
+ };
+
+ int thread_created = 0;
+ pthread_t tid;
+
+ su_port_threadsafe(parent->sur_port);
+
+ arg.self = child;
+ arg.init = init;
+ arg.deinit = deinit;
+ arg.parent = parent;
+
+ child->sur_magic = magic;
+ child->sur_deinit = deinit;
+ child->sur_threading = parent->sur_threading;
+
+ SU_TASK_COPY(child->sur_parent, su_root_task(parent), su_clone_start);
+
+ pthread_mutex_lock(&arg.mutex);
+ if (pthread_create(&tid, NULL, su_clone_main, &arg) == 0) {
+ pthread_cond_wait(&arg.cv, &arg.mutex);
+ thread_created = 1;
+ }
+ pthread_mutex_unlock(&arg.mutex);
+
+ if (arg.retval != 0) {
+ if (thread_created)
+ pthread_join(tid, NULL);
+ su_root_destroy(child), child = NULL;
+ }
+ else {
+ retval = 0;
+ *return_clone = *arg.clone;
+ }
+ } else
+#endif
+ if (child) {
+ assert(parent);
+
+ child->sur_magic = magic;
+ child->sur_deinit = deinit;
+ child->sur_threading = parent->sur_threading;
+
+ SU_TASK_COPY(child->sur_parent, su_root_task(parent), su_clone_start);
+ SU_TASK_COPY(child->sur_task, child->sur_parent, su_clone_start);
+ su_task_attach(child->sur_task, child);
+
+ if (su_msg_create(return_clone,
+ child->sur_task, su_root_task(parent),
+ su_clone_xyzzy, sizeof(child)) == 0) {
+ if (init == NULL || init(child, magic) == 0) {
+ su_cloned_t *sc = su_msg_data(return_clone);
+ sc->sc_root = child;
+#if SU_HAVE_PTHREADS
+ sc->sc_tid = pthread_self();
+ pthread_mutex_init(sc->sc_pause, NULL);
+ pthread_cond_init(sc->sc_resume, NULL);
+ pthread_mutex_lock(sc->sc_pause);
+#endif
+ retval = 0;
+ } else {
+ if (deinit)
+ deinit(child, magic);
+ su_msg_destroy(return_clone);
+ su_root_destroy(child), child = NULL;
+ }
+ }
+ else {
+ su_root_destroy(child), child = NULL;
+ }
+ }
+
+ return retval;
+}
+
+/** Get reference to clone task.
+ *
+ * @param clone Clone pointer
+ *
+ * @return A reference to the task structure of the clone.
+ */
+_su_task_r su_clone_task(su_clone_r clone)
+{
+ return su_msg_to(clone);
+}
+
+/**Forget the clone.
+ *
+ * Normally, the clone task executes until it is stopped. If the parent
+ * task does not need to stop the task, it can "forget" the clone. The
+ * clone exits independently of the parent task.
+ *
+ * @param rclone Reference to the clone.
+ */
+void su_clone_forget(su_clone_r rclone)
+{
+ su_msg_destroy(rclone);
+}
+
+/** Stop the clone.
+ *
+ * @deprecated. Use su_clone_wait().
+ */
+void su_clone_stop(su_clone_r rclone)
+{
+ su_msg_send(rclone);
+}
+
+/** Stop a clone and wait until it is has completed.
+ *
+ * The function su_clone_wait() is used to stop the clone task and wait
+ * until it has cleaned up. The clone task is destroyed asynchronously. The
+ * parent sends a message to clone, clone deinitializes itself and then
+ * replies. After the reply message is received by the parent, it will send
+ * a third message back to clone.
+ *
+ * The parent destroy all messages to or from clone task before calling
+ * su_clone_wait(). The parent task may not send any messages to the clone
+ * after calling su_clone_wait(). The su_clone_wait() function blocks until
+ * the cloned task is destroyed. During that time, the parent task must be
+ * prepared to process all the messages sent by clone task. This includes
+ * all the messages sent by clone before destroy message reached the clone.
+ */
+void su_clone_wait(su_root_t *root, su_clone_r rclone)
+{
+ su_cloned_t *sc = su_msg_data(rclone);
+
+ if (sc) {
+#if SU_HAVE_PTHREADS
+ pthread_t clone_tid = sc->sc_tid;
+#endif
+ int one = 1;
+ /* This does 3-way handshake.
+ * First, su_clone_break() is executed by clone.
+ * The message is returned to parent (this task),
+ * which executes su_clone_report().
+ * Then the message is again returned to clone,
+ * which executes su_clone_report2() and exits.
+ */
+ sc->sc_wait = &one;
+ su_msg_send(rclone);
+
+ su_root_step(root, 0);
+ su_root_step(root, 0);
+
+ while (one)
+ su_root_step(root, 10);
+
+#if SU_HAVE_PTHREADS
+ if (!pthread_equal(clone_tid, pthread_self()))
+ pthread_join(clone_tid, NULL);
+#endif
+ }
+}
+
+#if SU_HAVE_PTHREADS /* No-op without threads */
+static
+void su_clone_paused(su_root_magic_t *magic, su_msg_r msg, su_msg_arg_t *arg)
+{
+ su_cloned_t *cloned = *(su_cloned_t **)arg;
+ assert(cloned);
+ pthread_cond_wait(cloned->sc_resume, cloned->sc_pause);
+}
+#endif
+
+/** Pause a clone.
+ *
+ * Obtain a exclusive lock on clone's private data.
+ *
+ * @retval 0 if successful (and clone is paused)
+ * @retval -1 upon an error
+ */
+int su_clone_pause(su_clone_r rclone)
+{
+#if SU_HAVE_PTHREADS /* No-op without threads */
+ su_cloned_t *cloned = su_msg_data(rclone);
+ su_msg_r m = SU_MSG_R_INIT;
+
+ if (!cloned)
+ return (errno = EFAULT), -1;
+
+ if (pthread_equal(pthread_self(), cloned->sc_tid))
+ return 0;
+
+ if (su_msg_create(m, su_clone_task(rclone), su_task_null,
+ su_clone_paused, sizeof cloned) < 0)
+ return -1;
+
+ *(su_cloned_t **)su_msg_data(m) = cloned;
+
+ if (su_msg_send(m) < 0)
+ return -1;
+
+ if (pthread_mutex_lock(cloned->sc_pause) < 0)
+ return -1;
+ pthread_cond_signal(cloned->sc_resume);
+#endif
+
+ return 0;
+}
+
+/** Resume a clone.
+ *
+ * Give up a exclusive lock on clone's private data.
+ *
+ * @retval 0 if successful (and clone is resumed)
+ * @retval -1 upon an error
+ */
+int su_clone_resume(su_clone_r rclone)
+{
+#if SU_HAVE_PTHREADS /* No-op without threads */
+ su_cloned_t *cloned = su_msg_data(rclone);
+
+ if (!cloned)
+ return (errno = EFAULT), -1;
+
+ if (pthread_equal(pthread_self(), cloned->sc_tid))
+ return 0;
+
+ if (pthread_mutex_unlock(cloned->sc_pause) < 0)
+ return -1;
+#endif
+
+ return 0;
+}
+
+
+/* =========================================================================
+ * Messages
+ */
+
+/**
+ * Allocates a message of given size.
+ *
+ * The function @c su_msg_create() allocates a message with given data size.
+ * If successful, it moves the new message handle to the @c rmsg.
+ *
+ * @param rmsg handle to the new message (may be uninitialized prior calling)
+ * @param to the recipient task
+ * @param from the sender task
+ * @param wakeup function that is called when message is delivered
+ * @param size size of the message data
+ *
+ * @retval 0 if successful,
+ * @retval -1 if message allocation fails.
+ */
+int su_msg_create(su_msg_r rmsg,
+ su_task_r const to,
+ su_task_r const from,
+ su_msg_f wakeup,
+ isize_t size)
+{
+ su_port_t *port = to->sut_port;
+ su_msg_t *msg;
+
+ SU_PORT_LOCK(port, su_msg_create);
+ msg = su_zalloc(NULL /*port->sup_home*/, sizeof(*msg) + size);
+ SU_PORT_UNLOCK(port, su_msg_create);
+
+ if (msg) {
+ msg->sum_size = sizeof(*msg) + size;
+ SU_TASK_COPY(msg->sum_to, to, su_msg_create);
+ SU_TASK_COPY(msg->sum_from, from, su_msg_create);
+ msg->sum_func = wakeup;
+ *rmsg = msg;
+ return 0;
+ }
+
+ *rmsg = NULL;
+ return -1;
+}
+
+/** Add a delivery report function to a message.
+ *
+ * The delivery report funcgtion gets called by the sending task after the
+ * message was delivered and the message function was executed. (The
+ * su_root_t message delivery loop calls su_msg_delivery_report()
+ *
+ */
+int su_msg_report(su_msg_r msg,
+ su_msg_f report)
+{
+ if (msg && msg[0] && msg[0]->sum_report == NULL) {
+ msg[0]->sum_report = report;
+ return 0;
+ }
+
+ return -1;
+}
+
+/**
+ * Allocates a reply message of given size.
+ *
+ * @param reply handle to the new message (may be uninitialized prior calling)
+ * @param msg the incoming message
+ * @param wakeup function that is called when message is delivered
+ * @param size size of the message data
+ *
+ * @retval 0 if successful,
+ * @retval -1 otherwise.
+ */
+
+int su_msg_reply(su_msg_r reply, su_msg_r const msg,
+ su_msg_f wakeup, isize_t size)
+{
+ su_msg_r msg0;
+
+ assert(msg != reply);
+
+ *msg0 = *msg;
+ *reply = NULL;
+
+ return su_msg_create(reply, su_msg_from(msg0), su_msg_to(msg0), wakeup, size);
+}
+
+
+/** Send a delivery report.
+ *
+ * If the sender has attached a delivery report function to message with
+ * su_msg_report(), the message is returned to the message queue of the
+ * sending task. The sending task calls the delivery report function when it
+ * has received the message.
+ */
+void su_msg_delivery_report(su_msg_r msg)
+{
+ su_task_r swap;
+
+ if (!msg || !msg[0])
+ return;
+
+ if (!msg[0]->sum_report) {
+ su_msg_destroy(msg);
+ return;
+ }
+
+ *swap = *msg[0]->sum_from;
+ *msg[0]->sum_from = *msg[0]->sum_to;
+ *msg[0]->sum_to = *swap;
+
+ msg[0]->sum_func = msg[0]->sum_report;
+ msg[0]->sum_report = NULL;
+ su_msg_send(msg);
+}
+
+/** Save a message. */
+void su_msg_save(su_msg_r save, su_msg_r msg)
+{
+ if (save) {
+ if (msg)
+ save[0] = msg[0];
+ else
+ save[0] = NULL;
+ }
+ if (msg)
+ msg[0] = NULL;
+}
+
+/**
+ * Destroys an unsent message.
+ *
+ * @param rmsg message handle.
+ */
+void su_msg_destroy(su_msg_r rmsg)
+{
+ assert(rmsg);
+
+ if (rmsg[0]) {
+ /* su_port_t *port = rmsg[0]->sum_to->sut_port; */
+
+ /* SU_PORT_INCREF(port, su_msg_destroy); */
+ SU_TASK_ZAP(rmsg[0]->sum_to, su_msg_destroy);
+ SU_TASK_ZAP(rmsg[0]->sum_from, su_msg_destroy);
+
+ su_free(NULL /* port->sup_home */, rmsg[0]);
+ /* SU_PORT_UNLOCK(port, su_msg_destroy); */
+
+ /* SU_PORT_DECREF(port, su_msg_destroy); */
+ }
+
+ rmsg[0] = NULL;
+}
+
+/** Gets a pointer to the message data area.
+ *
+ * The function @c su_msg_data() returns a pointer to the message data
+ * area. If @c rmsg contains a @c NULL handle, or message size is 0, @c NULL
+ * pointer is returned.
+ *
+ * @param rmsg message handle
+ *
+ * @return A pointer to the message data area is returned.
+ */
+su_msg_arg_t *su_msg_data(su_msg_cr rmsg)
+{
+ if (rmsg[0] && rmsg[0]->sum_size > sizeof(su_msg_t))
+ return rmsg[0]->sum_data;
+ else
+ return NULL;
+}
+
+/** Get size of message data area. */
+isize_t su_msg_size(su_msg_cr rmsg)
+{
+ return rmsg[0] ? rmsg[0]->sum_size - sizeof(su_msg_t) : 0;
+}
+
+/** Get sending task.
+ *
+ * Returns the task handle belonging to the sender of the message.
+ *
+ * If the message handle contains NULL the function @c su_msg_from
+ * returns NULL.
+ *
+ * @param msg message handle
+ *
+ * @return The task handle of the sender is returned.
+ */
+_su_task_r su_msg_from(su_msg_r const msg)
+{
+ return msg[0] ? msg[0]->sum_from : NULL;
+}
+
+/** Get destination task.
+ *
+ * The function @c su_msg_from returns the task handle belonging to the
+ * recipient of the message.
+ *
+ * If the message handle contains NULL the function @c su_msg_to
+ * returns NULL.
+ *
+ * @param msg message handle
+ *
+ * @return The task handle of the recipient is returned.
+ */
+_su_task_r su_msg_to(su_msg_r const msg)
+{
+ return msg[0] ? msg[0]->sum_to : NULL;
+}
+
+/** Remove references to 'from' and 'to' tasks from a message.
+ *
+ * @param msg message handle
+ */
+void su_msg_remove_refs(su_msg_r const msg)
+{
+ if (msg[0]) {
+ su_task_deinit(msg[0]->sum_to);
+ su_task_deinit(msg[0]->sum_from);
+ }
+}
+
+/**Send a message.
+ *
+ * The function @c su_msg_send() sends the message. The message is added to
+ * the recipients message queue, and recipient is waken up. The caller may
+ * not alter the message or the data associated with it after the message
+ * has been sent.
+ *
+ * @param rmsg message handle
+ *
+ * @retval 0 if signal was sent successfully or handle was @c NULL,
+ * @retval -1 otherwise.
+ */
+int su_msg_send(su_msg_r rmsg)
+{
+ assert(rmsg);
+
+ if (rmsg[0]) {
+ su_msg_t *msg = rmsg[0];
+ assert(msg->sum_to->sut_port);
+ return su_port_send(msg->sum_to->sut_port, rmsg);
+ }
+
+ return 0;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_sprintf.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_sprintf.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,129 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_alloc
+ *
+ * @CFILE su_sprintf.c su_*sprintf() functions
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Apr 17 20:05:21 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.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 "sofia-sip/su_alloc.h"
+
+/**Copy a formatted string.
+ *
+ * The function su_vsprintf() print a string according to a @a fmt like
+ * vprintf() or vsnprintf(). The resulting string is copied to a memory area
+ * fresly allocated from a memory @a home. The returned string is reclaimed
+ * when @a home is destroyed. It can explicitly be freed with su_free() or
+ * free() if @a home is NULL.
+ *
+ * @param home pointer to memory home (may be NULL)
+ * @param fmt format string
+ * @param ap @e stdarg argument list (must match with the @a fmt format string)
+ *
+ * @return A pointer to a fresh copy of formatting result, or NULL upon an
+ * error.
+ */
+char *su_vsprintf(su_home_t *home, char const *fmt, va_list ap)
+{
+ int n;
+ size_t len;
+ char *rv, s[128];
+ va_list aq;
+
+ va_copy(aq, ap);
+ n = vsnprintf(s, sizeof(s), fmt, aq);
+ va_end(aq);
+
+ if (n >= 0 && (size_t)n + 1 < sizeof(s))
+ return su_strdup(home, s);
+
+ len = n > 0 ? (size_t)n + 1 : 2 * sizeof(s);
+
+ for (rv = su_alloc(home, len);
+ rv;
+ rv = su_realloc(home, rv, len)) {
+ va_copy(aq, ap);
+ n = vsnprintf(rv, len, fmt, aq);
+ va_end(aq);
+ if (n > -1 && (size_t)n < len)
+ break;
+ if (n > -1) /* glibc >2.1 */
+ len = (size_t)n + 1;
+ else /* glibc 2.0 */
+ len *= 2;
+
+ if (len > INT_MAX)
+ return (void)su_free(home, rv), NULL;
+ }
+
+ return rv;
+}
+
+/**Copy a formatted string.
+ *
+ * The function su_sprintf() print a string according to a @a fmt like
+ * printf() or snprintf(). The resulting string is copied to a memory area
+ * freshly allocated from a memory @a home. The returned string is reclaimed
+ * when @a home is destroyed. It can explicitly be freed with su_free() or
+ * free() if @a home is NULL.
+ *
+ * @param home pointer to memory home (may be NULL)
+ * @param fmt format string
+ * @param ... argument list (must match with the @a fmt format string)
+ *
+ * @return A pointer to a fresh copy of formatting result, or NULL upon an
+ * error.
+ */
+char *su_sprintf(su_home_t *home, char const *fmt, ...)
+{
+ va_list ap;
+ char *rv;
+
+ va_start(ap, fmt);
+ rv = su_vsprintf(home, fmt, ap);
+ va_end(ap);
+
+ return rv;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_strdup.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_strdup.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,168 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_alloc
+ *
+ * @CFILE su_strdup.c Home-based string duplication functions
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Jul 19 10:06:14 2000 ppessi
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include "sofia-sip/su_alloc.h"
+
+/** Duplicate a string, allocate memory from @a home.
+ *
+ * The function su_strdup() duplicates the string @a s. It allocates @c
+ * strlen(s)+1 bytes from @a home, copies the contents of @a s to the newly
+ * allocated memory, and returns pointer to the duplicated string.
+ *
+ * @param home pointer to memory home
+ * @param s string to be duplicated
+ *
+ * @return The function su_strdup() returns pointer to the newly created
+ * string, or @c NULL upon an error.
+ */
+char *su_strdup(su_home_t *home, char const *s)
+{
+ if (s) {
+ size_t n = strlen(s);
+ char *retval = su_alloc(home, n + 1);
+ if (retval)
+ strncpy(retval, s, n)[n] = 0;
+ return retval;
+ }
+ return NULL;
+}
+
+/**Concate two strings, allocate memory for result from @a home.
+ *
+ * Concatenate the strings @a s1 and @a s2. The @c strlen(s1)+strlen(s2)+1
+ * bytes is allocated from @a home, the contents of @a s1 and @a s2 is
+ * copied to the newly allocated memory area, and pointer to the
+ * concatenated string is returned.
+ *
+ * @param home pointer to memory home
+ * @param s1 string to be first string
+ * @param s2 string to be first string
+ *
+ * @return Pointer to the newly created string is returned, or @c NULL upon
+ * an error.
+ */
+char *su_strcat(su_home_t *home, char const *s1, char const *s2)
+{
+ size_t n1, n2;
+ char *retval;
+
+ if (s1 == NULL)
+ return su_strdup(home, s2);
+ else if (s2 == NULL)
+ return su_strdup(home, s1);
+
+ n1 = strlen(s1); n2 = strlen(s2);
+ retval = su_alloc(home, n1 + n2 + 1);
+ if (retval) {
+ memcpy(retval, s1, n1);
+ memcpy(retval + n1, s2, n2);
+ retval[n1 + n2] = '\0';
+ }
+
+ return retval;
+}
+
+/**Concate multiple strings, allocate memory for result from @a home.
+ *
+ * Concatenate the strings in list. The lenght of result is calculate,
+ * result is allocated from @a home, the contents of strings is copied to
+ * the newly allocated memory arex, and pointer to the concatenated string is
+ * returned.
+ *
+ * @param home pointer to memory home
+ * @param ... NULL-terminated list of strings to be concatenated
+ *
+ * @return Pointer to the newly created string is returned, or @c NULL upon
+ * an error.
+ */
+char *su_strcat_all(su_home_t *home, ...)
+{
+ int i, n;
+ size_t size = 0;
+ va_list va;
+ char *s, *retval, *end;
+
+ /* Count number arguments and their size */
+ va_start(va, home);
+ s = va_arg(va, char *);
+ for (n = 0; s; s = va_arg(va, char *), n++)
+ size += strlen(s);
+ va_end(va);
+
+ retval = su_alloc(home, size + 1);
+ if (retval) {
+ s = retval;
+ end = s + size + 1;
+
+ va_start(va, home);
+
+ for (i = 0; i < n; i++)
+ s = (char *)memccpy(s, va_arg(va, char const *), '\0', end - s) - 1;
+
+ va_end(va);
+
+ retval[size] = '\0';
+ }
+
+ return retval;
+}
+
+
+
+/** Duplicate a string with given size, allocate memory from @a home.
+ *
+ * The function su_strndup() duplicates the string @a s. It allocates @c n+1
+ * bytes from @a home, copies the contents of @a s to the newly allocated
+ * memory, and returns pointer to the duplicated string. The duplicated
+ * string is always NUL-terminated.
+ *
+ * @param home pointer to memory home
+ * @param s string to be duplicated
+ * @param n size of the resulting string
+ *
+ * @return The function su_strndup() returns pointer to the newly created
+ * string, or @c NULL upon an error.
+ */
+char *su_strndup(su_home_t *home, char const *s, isize_t n)
+{
+ if (s) {
+ char *retval = su_alloc(home, n + 1);
+ if (retval)
+ strncpy(retval, s, n)[n] = 0;
+ return retval;
+ }
+ return NULL;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_strlst.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_strlst.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,712 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@defgroup su_strlst String Lists
+ *
+ * Lists of strings.
+ *
+ * String lists using #su_home_t.
+ *
+ */
+
+/**@ingroup su_strlst
+ * @CFILE su_strlst.c
+ * @brief String lists.
+ *
+ * The string lists can be used to concatenate a large number of strings, or
+ * split a string to smaller pieces (e.g., lines).
+ *
+ * Example of concatenating a number of strings to @a s:
+ * @code
+ * su_strlst_t *l = su_strlist_create(home);
+ * su_strlst_append(l, "=============");
+ * su_slprintf(l, "a is: %d", a)
+ * su_slprintf(l, "b is: %d", b)
+ * su_slprintf(l, "c is: %d", c)
+ * su_strlst_append(l, "------------");
+ * su_slprintf(l, "total: %d", a + b + c));
+ * su_strlst_append(l, "=============");
+ * s = su_strlst_join(l, "\n");
+ * @endcode
+ *
+ * Another example, splitting a string into lines and counting the number of
+ * non-empty ones:
+ * @code
+ * usize_t i, n;
+ * su_strlst_t *l;
+ *
+ * l = su_strlst_split(NULL, buf, "\n");
+ *
+ * nonempty = 0;
+ *
+ * for (i = 0; i < su_strlst_len(l); i++) {
+ * n = strcspn(su_strlst_item(l, i), " \t");
+ * if (su_strlst_item(l, i)[n])
+ * nonempty++;
+ * }
+ *
+ * su_strlst_destroy(l);
+ * @endcode
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Fri May 3 09:22:59 2002 ppessi
+ */
+
+#include "config.h"
+
+#include "sofia-sip/su_config.h"
+#include "sofia-sip/su_strlst.h"
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <memory.h>
+#include <limits.h>
+#include <string.h>
+
+#include <assert.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
+
+enum { N = 8 };
+
+struct su_strlst_s
+{
+ su_home_t sl_home[1];
+ size_t sl_size;
+ size_t sl_len;
+ size_t sl_total;
+ char const **sl_list;
+};
+
+/** Create a list with initial values */
+static
+su_strlst_t *su_strlst_vcreate_with_by(su_home_t *home,
+ char const *value,
+ va_list va,
+ int deeply)
+{
+ su_strlst_t *self;
+ size_t i, n, m;
+ size_t total, size;
+
+ m = 0, total = 0;
+
+ /* Count arguments and their length */
+ if (value) {
+ char const *s;
+ va_list va0;
+
+ va_copy(va0, va);
+ for (s = value; s; m++, s = va_arg(va0, char *))
+ total += strlen(s);
+ va_end(va0);
+ }
+
+ for (n = N; m > n; n *= 2)
+ ;
+
+ size = sizeof(*self) + n * sizeof(*self->sl_list);
+ if (deeply)
+ size += total + m;
+
+ self = su_home_clone(home, size);
+ if (self) {
+ self->sl_size = n;
+ self->sl_list = (char const **)(self + 1);
+ self->sl_len = m;
+ self->sl_total = total;
+
+ if (deeply) {
+ char *s = (char *)(self->sl_list + self->sl_size);
+ char *end = s + total + m;
+
+ for (i = 0; i < m; i++) {
+ assert(s);
+ self->sl_list[i] = s;
+ s = memccpy(s, value, '\0', end - s);
+ value = va_arg(va, char const *);
+ }
+ }
+ else {
+ for (i = 0; i < m; i++) {
+ self->sl_list[i] = value;
+ value = va_arg(va, char const *);
+ }
+ }
+ }
+
+ return self;
+}
+
+/** Create an empty string list.
+ *
+ * The list is initially empty. The memory home for the list is cloned from
+ * @a home.
+ *
+ */
+su_strlst_t *su_strlst_create(su_home_t *home)
+{
+ su_strlst_t *self;
+
+ self = su_home_clone(home, sizeof(*self) + N * sizeof(*self->sl_list));
+ if (self) {
+ self->sl_size = N;
+ self->sl_list = (char const **)(self + 1);
+ }
+ return self;
+}
+
+/** Create a string list with initial values.
+ *
+ * The list is initialized with strings in argument. The argument list is
+ * terminated with NULL. The memory home for the list is cloned from @a
+ * home.
+ */
+su_strlst_t *su_strlst_create_with(su_home_t *home, char const *value, ...)
+{
+ va_list va;
+ su_strlst_t *l;
+
+ va_start(va, value);
+ l = su_strlst_vcreate_with_by(home, value, va, 0);
+ va_end(va);
+
+ return l;
+}
+
+/** Create a string list with initial values.
+ *
+ * The string list is initialized with strings from @a va_list @a va. The
+ * argument list is terminated with NULL. The memory home for the list is
+ * cloned from @a home.
+ */
+su_strlst_t *su_strlst_vcreate_with(su_home_t *home,
+ char const *value,
+ va_list va)
+{
+ return su_strlst_vcreate_with_by(home, value, va, 0);
+}
+
+/** Create a string list with duplicatedd initial values.
+ *
+ * The list is initialized with copies of strings in argument list. The
+ * argument list is terminated with NULL. The memory home for the list is
+ * cloned from @a home.
+ */
+su_strlst_t *su_strlst_create_with_dup(su_home_t *home, char const *value, ...)
+{
+ va_list va;
+ su_strlst_t *l;
+
+ va_start(va, value);
+ l = su_strlst_vcreate_with_by(home, value, va, 1);
+ va_end(va);
+
+ return l;
+}
+
+/** Create a string list with duplicates of initial values.
+ *
+ * The string list is initialized with copies of strings from @a va_list @a
+ * va. The argument list is terminated with NULL. The memory home for the
+ * list is cloned from @a home.
+ */
+su_strlst_t *su_strlst_vcreate_with_dup(su_home_t *home,
+ char const *value,
+ va_list va)
+{
+ return su_strlst_vcreate_with_by(home, value, va, 1);
+}
+
+
+/** Copy a string list */
+static
+su_strlst_t *su_strlst_copy_by(su_home_t *home,
+ su_strlst_t const *orig,
+ int deeply)
+{
+ su_strlst_t *self;
+ size_t N, i, size, deepsize = 0;
+
+ if (orig == NULL)
+ return NULL;
+
+ N = orig->sl_size;
+
+ if (deeply)
+ deepsize = orig->sl_len + orig->sl_total;
+
+ size = sizeof(*self) + N * sizeof(self->sl_list[0]) + deepsize;
+
+ self = su_home_clone(home, size);
+ if (self) {
+ self->sl_size = N;
+ self->sl_list = (char const **)(self + 1);
+
+ self->sl_len = N = orig->sl_len;
+ self->sl_total = orig->sl_total;
+
+ if (deeply) {
+ char *s = (char *)(self->sl_list + self->sl_size);
+ char *end = s + deepsize;
+ for (i = 0; i < N; i++) {
+ self->sl_list[i] = s;
+ s = memccpy(s, orig->sl_list[i], '\0', end - s);
+ assert(s);
+ }
+ }
+ else {
+ for (i = 0; i < N; i++) {
+ self->sl_list[i] = orig->sl_list[i];
+ }
+ }
+ }
+
+ return self;
+}
+
+/** Shallow copy a string list. */
+su_strlst_t *su_strlst_copy(su_home_t *home, su_strlst_t const *orig)
+{
+ return su_strlst_copy_by(home, orig, 0);
+}
+
+/** Deep copy a string list. */
+su_strlst_t *su_strlst_dup(su_home_t *home, su_strlst_t const *orig)
+{
+ return su_strlst_copy_by(home, orig, 1);
+}
+
+/** Destroy a string list.
+ *
+ * The function su_strlst_destroy() destroys a list of strings and frees all
+ * duplicated strings belonging to it.
+ */
+void su_strlst_destroy(su_strlst_t *self)
+{
+ su_home_zap(self->sl_home);
+}
+
+/** Increase the list size for next item, if necessary. */
+static int su_strlst_increase(su_strlst_t *self)
+{
+ if (self->sl_size <= self->sl_len + 1) {
+ size_t size = 2 * self->sl_size * sizeof(self->sl_list[0]);
+ char const **list;
+
+ if (self->sl_list != (char const **)(self + 1)) {
+ list = su_realloc(self->sl_home, (void *)self->sl_list, size);
+ } else {
+ list = su_alloc(self->sl_home, size);
+ if (list)
+ memcpy(list, self->sl_list, self->sl_len * sizeof(*self->sl_list));
+ }
+
+ if (!list)
+ return 0;
+
+ self->sl_list = list;
+ self->sl_size = 2 * self->sl_size;
+ }
+
+ return 1;
+}
+
+/**Duplicate and append a string to list.
+ *
+ * @param self pointer to a string list object
+ * @param str string to be duplicated and appended
+ *
+ * @return
+ * Pointer to duplicated string, if successful, or NULL upon an error.
+ */
+char *su_strlst_dup_append(su_strlst_t *self, char const *str)
+{
+ size_t len;
+
+ if (str == NULL)
+ str = "";
+
+ len = strlen(str);
+
+ if (self && su_strlst_increase(self)) {
+ char *retval = su_alloc(self->sl_home, len + 1);
+ if (retval) {
+ memcpy(retval, str, len);
+ retval[len] = 0;
+ self->sl_list[self->sl_len++] = retval;
+ self->sl_total += len;
+ }
+ return retval;
+ }
+ return NULL;
+}
+
+/**Append a string to list.
+ *
+ * The string is not copied, and it @b must not be modified while string
+ * list exists.
+ *
+ * @param self pointer to a string list object
+ * @param str string to be appended
+ *
+ * @return
+ * Pointer to string, if successful, or NULL upon an error.
+ */
+char const *su_strlst_append(su_strlst_t *self, char const *str)
+{
+ if (str == NULL)
+ str = "";
+
+ if (self && su_strlst_increase(self)) {
+ self->sl_list[self->sl_len++] = str;
+ self->sl_total += strlen(str);
+ return str;
+ }
+ return NULL;
+}
+
+/**Append a formatted string to the list.
+ *
+ * Format a string according to a @a fmt like printf(). The resulting string
+ * is copied to a memory area freshly allocated from a the memory home of
+ * the list and appended to the string list.
+ *
+ * @param self pointer to a string list object
+ * @param fmt format string
+ * @param ... argument list (must match with the @a fmt format string)
+ *
+ * @return A pointer to a fresh copy of formatting result, or NULL upon an
+ * error.
+ */
+char const *su_slprintf(su_strlst_t *self, char const *fmt, ...)
+{
+ char const *str;
+ va_list ap;
+ va_start(ap, fmt);
+ str = su_slvprintf(self, fmt, ap);
+ va_end(ap);
+
+ return str;
+}
+
+/**Append a formatted string to the list.
+ *
+ * Format a string according to a @a fmt like vprintf(). The resulting
+ * string is copied to a memory area freshly allocated from a the memory
+ * home of the list and appended to the string list.
+ *
+ * @param self pointer to a string list object
+ * @param fmt format string
+ * @param ap stdarg argument list (must match with the @a fmt format string)
+ *
+ * @return A pointer to a fresh copy of formatting result, or NULL upon an
+ * error.
+ */
+char const *su_slvprintf(su_strlst_t *self, char const *fmt, va_list ap)
+{
+ char *str = NULL;
+
+ if (self && su_strlst_increase(self)) {
+ str = su_vsprintf(self->sl_home, fmt, ap);
+ if (str) {
+ self->sl_list[self->sl_len++] = str;
+ self->sl_total += strlen(str);
+ }
+ }
+ return str;
+}
+
+/**Returns a numbered item from the list of strings. The numbering starts from
+ * 0.
+ *
+ * @param self pointer to a string list object
+ * @param i string index
+ *
+ * @return
+ * Pointer to string, if item exists, or NULL if index is out of bounds or
+ * list does not exist.
+ */
+char const *su_strlst_item(su_strlst_t const *self, usize_t i)
+{
+ if (self && i < self->sl_len)
+ return self->sl_list[i];
+ else
+ return NULL;
+}
+
+/**Sets a item to the list of strings.
+ *
+ * Note that the item numbering starts from 0.
+ *
+ * @param self pointer to a string list object
+ * @param i string index
+ * @param s string to be set as item @a i
+ *
+ * @return
+ * Pointer to string, if item exists, or NULL if index is out of bounds or
+ * list does not exist.
+ */
+char const *su_strlst_set_item(su_strlst_t *self, usize_t i, char const *s)
+{
+ char const *old = NULL;
+
+ if (self == NULL)
+ return NULL;
+ else if (i == self->sl_len)
+ return (void)su_strlst_append(self, s), NULL;
+ else if (i > self->sl_len)
+ return NULL;
+
+ if (s == NULL)
+ s = "";
+
+ old = self->sl_list[i];
+
+ self->sl_list[i] = s;
+
+ return old;
+}
+
+/**Removes a numbered item from the list of strings. The numbering starts from
+ * 0. The caller is responsible of reclaiming memory used by the removed string.
+ *
+ * @param self pointer to a string list object
+ * @param i string index
+ *
+ * @return
+ * Pointer to string, if item exists, or NULL if index is out of bounds or
+ * list does not exist.
+ */
+SU_DLL char const *su_strlst_remove(su_strlst_t *self, usize_t i)
+{
+ if (self && i < self->sl_len) {
+ char const *s = self->sl_list[i];
+
+ memmove(&self->sl_list[i], &self->sl_list[i + 1],
+ &self->sl_list[self->sl_len] - &self->sl_list[i]);
+
+ self->sl_len--;
+
+ return s;
+ }
+ else
+ return NULL;
+}
+
+
+
+/** Concatenate list of strings to one string.
+ *
+ * The function su_strlst_join() concatenates the list of strings. Between
+ * each string in list it uses @a sep. The separator is not inserted after
+ * the last string in list, but one can always append an empty string to the
+ * list.
+ *
+ * The string is allocated from the memory @a home. If @a home is NULL, the
+ * string is allocated using malloc().
+ *
+ * @param self pointer to a string list object
+ * @param home home pointer
+ * @param sep separator (may be NULL)
+ *
+ * @return
+ *
+ * The function su_strlst_join() returns a concatenation of the strings in
+ * list, or NULL upon an error.
+ */
+char *su_strlst_join(su_strlst_t *self, su_home_t *home, char const *sep)
+{
+ if (!sep)
+ sep = "";
+
+ if (self && self->sl_len > 0) {
+ size_t seplen = strlen(sep);
+ size_t total = self->sl_total + seplen * (self->sl_len - 1);
+ char *retval;
+
+ retval = su_alloc(home, total + 1);
+
+ if (retval) {
+ char *s = retval;
+ size_t i = 0, len;
+
+ for (;;) {
+ len = strlen(self->sl_list[i]);
+ memcpy(s, self->sl_list[i], len), s += len;
+ if (++i >= self->sl_len)
+ break;
+ memcpy(s, sep, seplen), s += seplen;
+ }
+ *s = '\0';
+ assert(s == retval + total);
+ }
+
+ return retval;
+ }
+
+ return su_strdup(home, "");
+}
+
+static inline
+su_strlst_t *
+su_strlst_split0(su_strlst_t *l, char *str, char const *sep)
+{
+ size_t n = sep ? strlen(sep) : 0;
+ char *s;
+
+ if (n > 0) {
+ while ((s = strstr(str, sep))) {
+ *s = '\0';
+ if (!su_strlst_append(l, str))
+ return NULL;
+ str = s + n;
+ }
+ }
+
+ if (!su_strlst_append(l, str))
+ return NULL;
+
+ return l;
+}
+
+/**Split a string.
+ *
+ * Splits a string to substrings. It returns a string list object. The
+ * string to be split is not copied but instead modified in place. Use
+ * su_strlst_dup_split() if you do not want to modify @a str.
+ *
+ * @param home home pointer
+ * @param str string to be split
+ * @param sep separator between substrings
+ *
+ * @return
+ * Pointer to list of strings, if successful, or NULL upon an error.
+ */
+su_strlst_t *
+su_strlst_split(su_home_t *home, char *str, char const *sep)
+{
+ if (str) {
+ su_strlst_t *l = su_strlst_create(home);
+
+ if (!su_strlst_split0(l, str, sep))
+ su_strlst_destroy(l), l = NULL;
+
+ return l;
+ }
+ return NULL;
+}
+
+/**Duplicate and split a string.
+ *
+ * Duplicates a string and splits the result to substrings. It returns a
+ * string list object. The string to be splitted is not modified.
+ *
+ * @param home home pointer
+ * @param cstr string to be split
+ * @param sep separator between substrings
+ *
+ * @return
+ * Pointer to list of strings, if successful, or NULL upon an error.
+ */
+su_strlst_t *su_strlst_dup_split(su_home_t *home,
+ char const *cstr,
+ char const *sep)
+{
+ if (cstr) {
+ su_strlst_t *l = su_strlst_create(home);
+
+ if (l) {
+ char *s = su_strdup(su_strlst_home(l), cstr);
+
+ if (s && !su_strlst_split0(l, s, sep))
+ su_strlst_destroy(l), l = NULL;
+ }
+
+ return l;
+ }
+ return NULL;
+}
+
+/** Get number of items in list.
+ *
+ * The function su_strlst_len() returns the number of items in the
+ * string list.
+ *
+ */
+usize_t su_strlst_len(su_strlst_t const *l)
+{
+ return l ? l->sl_len : 0;
+}
+
+/**Get a string array from list.
+ *
+ * The function su_strlst_get_array() returns an array of strings. The
+ * length of the array is always one longer than the length of the string
+ * list, and the last string in the returned array is always NULL.
+ *
+ * @param self pointer to a string list object
+ *
+ * @return
+ * Pointer to array of strings, or NULL if error occurred.
+ */
+char const **su_strlst_get_array(su_strlst_t *self)
+{
+ if (self) {
+ char const **retval;
+ size_t size = sizeof(retval[0]) * (self->sl_len + 1);
+
+ retval = su_alloc(self->sl_home, size);
+
+ if (retval) {
+ memcpy(retval, self->sl_list, sizeof(retval[0]) * self->sl_len);
+ retval[self->sl_len] = NULL;
+ return retval;
+ }
+ }
+
+ return NULL;
+}
+
+/**Free a string array.
+ *
+ * The function su_strlst_free_array() discards a string array allocated
+ * with su_strlst_get_array().
+ *
+ * @param self pointer to a string list object
+ * @param array string array to be freed
+ *
+ */
+void su_strlst_free_array(su_strlst_t *self, char const **array)
+{
+ if (array)
+ su_free(self->sl_home, (void *)array);
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_tag.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_tag.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,47 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@SU_TAG
+ *
+ * @CFILE su_tag.c
+ *
+ * Special tags.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Feb 20 20:03:38 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <assert.h>
+
+#include <sofia-sip/su_config.h>
+#include <sofia-sip/su_tag_class.h>
+
+extern tag_class_t null_tag_class[1];
+extern tag_class_t skip_tag_class[1];
+extern tag_class_t next_tag_class[1];
+extern tag_class_t any_tag_class[1];
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_tag_io.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_tag_io.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,69 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@SU_TAG
+ *
+ * @CFILE su_tag_io.c
+ * @brief Printing tag lists.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Feb 21 12:12:27 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#include <sofia-sip/su_tag.h>
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/su_tag_io.h>
+#include <sofia-sip/su_tag_inline.h>
+
+/** Print tags */
+void tl_print(FILE *f, char const *title, tagi_t const lst[])
+{
+ fputs(title, f);
+
+ for (; lst; lst = t_next(lst)) {
+ char buffer[4096];
+ char const *fmt = " %s\n";
+ int n;
+
+ buffer[0] = '\0';
+
+ n = t_snprintf(lst, buffer, sizeof(buffer));
+
+ if (n + 1 < (int)sizeof(buffer)) {
+ if (n > 0 && buffer[n - 1] == '\n')
+ fmt = " %s";
+ }
+ else
+ buffer[sizeof(buffer) - 1] = '\0';
+ fprintf(f, fmt, buffer);
+ }
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_taglist.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_taglist.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1606 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@SU_TAG
+ *
+ * @CFILE su_taglist.c
+ *
+ * Implementation of tag items and lists.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Feb 20 20:03:38 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <limits.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>
+
+#include <sofia-sip/su_config.h>
+
+#include <sofia-sip/su_tag.h>
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/su_tag_inline.h>
+#include <sofia-sip/su_tagarg.h>
+
+/**@defgroup su_tag Tag Item Lists
+ *
+ * Object-oriented tag routines for Sofia utility library.
+ *
+ * The <su_tag.h> defines a interface to object-oriented tag list routines.
+ * A tag list is a linear list (array) of tag items, tagi_t structures,
+ * terminated by a TAG_END() item. Each tag item has a label, tag, (@c
+ * t_tag) and a value (@c t_value). The tag is a pointer (tag_type_t) to a
+ * structure defining how the value should be interpreted, in other words,
+ * the name and the type of the value. The value or pointer to the actual
+ * value is stored as opaque data (tag_value_t). The tag item structure is
+ * defined as follows:
+ *
+ * @code
+ * typedef struct {
+ * tag_type_t t_tag;
+ * tag_value_t t_value;
+ * } tagi_t;
+ * @endcode
+ *
+ * The tag lists are central concept in the Sofia APIs. The tags lists can
+ * be used to a list of named arguments to a @ref tagarg "@em tagarg"
+ * function, to store variable amount of data in a memory area, and pass
+ * data between processes and threads.
+ *
+ * The tagged argument lists can be used like named arguments in
+ * higher-level languages. The argument list consists of tag-value pairs;
+ * tags specify the name and type of the value. All the tag items are not
+ * necessarily interpreted by the called function, but it can pass the list
+ * to other functions. This feature is used also by the Sofia APIs, the
+ * lower-layer settings and options are frequently passed through the
+ * upper-layer API in the tag lists.
+ *
+ * The tagged argument lists are constructed using special macros that
+ * expand to two function arguments, tag and value. Each tag item macro
+ * checks its arguments type so the tagged argument lists are typesafe if
+ * the list is correctly constructed.
+ *
+ * Each function documents the tags it accepts and also the tags it may pass
+ * to the lower layers (at least in theory).
+ *
+ * @par Special Tags
+ *
+ * There are a new special tags that are used to control and modify the tag
+ * list processing itself. These special tags are as follows:
+ * - TAG_NULL() or TAG_END() - indicates the end of tag list
+ * - TAG_SKIP() - indicates an empty (overwritten) tag item
+ * - TAG_NEXT() - contains a pointer to the next tag list.
+ *
+ * The tag type structures are declared as tag_typedef_t. They can be
+ * defined by the macros found in <su_tag_class.h>. See nta_tag.c or
+ * su_tag_test.c for an example.
+ *
+ */
+
+/**@class tag_class_s sofia-sip/su_tag_class.h <sofia-sip/su_tag_class.h>
+ *
+ * @brief Virtual function table for @ref su_tag "tags".
+ *
+ * The struct tag_class_s contains virtual function table for tags,
+ * specifying non-default behaviour of different tags. It provides functions
+ * for copying, matching, printing and converting the tagged values.
+ */
+
+#ifdef longlong
+typedef longlong unsigned llu;
+#else
+typedef long unsigned llu;
+#endif
+
+/** Print a tag. */
+int t_snprintf(tagi_t const *t, char b[], size_t size)
+{
+ tag_type_t tt = TAG_TYPE_OF(t);
+ int n, m;
+
+ n = snprintf(b, size, "%s::%s: ",
+ tt->tt_ns ? tt->tt_ns : "",
+ tt->tt_name ? tt->tt_name : "null");
+ if (n < 0)
+ return n;
+
+ if ((size_t)n > size)
+ size = n;
+
+ if (tt->tt_snprintf)
+ m = tt->tt_snprintf(t, b + n, size - n);
+ else
+ m = snprintf(b + n, size - n, "%llx", (llu)t->t_value);
+
+ if (m < 0)
+ return m;
+
+ if (m == 0 && (size_t)n < size)
+ b[--n] = '\0';
+
+ return n + m;
+}
+
+/** Get next tag item from list.
+ */
+tagi_t *tl_next(tagi_t const *t)
+{
+ tag_type_t tt;
+
+ t = t_next(t);
+
+ for (tt = TAG_TYPE_OF(t); t && tt->tt_next; tt = TAG_TYPE_OF(t)) {
+ t = tt->tt_next(t);
+ }
+
+ return (tagi_t *)t;
+}
+
+/**Move a tag list.
+ *
+ * The function tl_tmove() moves the tag list arguments to @a dst. The @a
+ * dst must have big enough for all arguments.
+ *
+ * @param dst pointer to the destination buffer
+ * @param size sizeof @a dst
+ * @param t_tag,t_value,... tag list
+ *
+ * @return
+ * The function tl_tmove() returns number of tag list items initialized.
+ */
+size_t tl_tmove(tagi_t *dst, size_t size,
+ tag_type_t t_tag, tag_value_t t_value, ...)
+{
+ size_t n = 0, N = size / sizeof(tagi_t);
+ tagi_t tagi[1];
+ va_list ap;
+
+ va_start(ap, t_value);
+
+ tagi->t_tag = t_tag, tagi->t_value = t_value;
+
+ for (;;) {
+ assert((size_t)((char *)&dst[n] - (char *)dst) < size);
+ if (n < N)
+ dst[n] = *tagi;
+ n++;
+ if (t_end(tagi))
+ break;
+
+ tagi->t_tag = va_arg(ap, tag_type_t);
+ tagi->t_value = va_arg(ap, tag_value_t);
+ }
+
+ va_end(ap);
+
+ return n;
+}
+
+/**Move a tag list.
+ *
+ * The function tl_move() copies the tag list @a src to the buffer @a
+ * dst. The size of the @a dst list must be at least @c tl_len(src) bytes.
+ *
+ * @param dst pointer to the destination buffer
+ * @param src tag list to be moved
+ *
+ * @return
+ * The function tl_move() returns a pointer to the @a dst list after last
+ * moved element.
+ */
+tagi_t *tl_move(tagi_t *dst, tagi_t const src[])
+{
+ do {
+ dst = t_move(dst, src);
+ }
+ while ((src = t_next(src)));
+
+ return dst;
+}
+
+/** Calculate effective length of a tag list as bytes. */
+size_t tl_len(tagi_t const lst[])
+{
+ size_t len = 0;
+
+ do {
+ len += t_len(lst);
+ }
+ while ((lst = t_next(lst)));
+
+ return len;
+}
+
+/** Calculate the size of extra memory areas associated with tag list. */
+size_t tl_xtra(tagi_t const lst[], size_t offset)
+{
+ size_t xtra = offset;
+
+ for (; lst; lst = t_next(lst))
+ xtra += t_xtra(lst, xtra);
+
+ return xtra - offset;
+}
+
+/** Duplicate a tag list.
+ *
+ * Deep copy the tag list @a src to the buffer @a dst. Memory areas
+ * associated with @a src are copied to buffer at @a **bb.
+ *
+ * This is a rather low-level function. See tl_adup() for a more convenient
+ * functionality.
+ *
+ * The size of the @a dst buffer must be at least @c tl_len(src) bytes. The
+ * size of buffer @a **bb must be at least @c tl_dup_xtra(src) bytes.
+ *
+ * @param[out] dst pointer to the destination buffer
+ * @param[in] src tag list to be duplicated
+ * @param[in,out] bb pointer to pointer to buffer
+ *
+ * @return
+ * A pointer to the @a dst list after last
+ * duplicated taglist element.
+ *
+ * The pointer at @a *bb is updated to the byte after last duplicated memory
+ * area.
+ */
+tagi_t *tl_dup(tagi_t dst[], tagi_t const src[], void **bb)
+{
+ do {
+ dst = t_dup(dst, src, bb);
+ } while ((src = t_next(src)));
+
+ return dst;
+}
+
+
+/** Free a tag list.
+ *
+ * The function tl_free() frees resources associated with a tag list.
+ * In other words, it calls t_free on each tag item on the list.
+ *
+ */
+void tl_free(tagi_t list[])
+{
+ while (list)
+ list = t_free(list);
+}
+
+/** Allocate and duplicate a tag list using memory home. */
+tagi_t *tl_adup(su_home_t *home, tagi_t const lst[])
+{
+ size_t len = tl_len(lst);
+ size_t xtra = tl_xtra(lst, 0);
+ void *b = su_alloc(home, len + xtra);
+ tagi_t *d, *newlst = b;
+
+ void *end = (char *)b + len + xtra;
+ tagi_t *tend = (tagi_t*)((char *)b + len);
+
+ b = (char *)b + len;
+
+ d = tl_dup(newlst, lst, &b);
+
+ assert(b == end); assert(tend == d); (void)end; (void)tend;
+
+ return newlst;
+}
+
+/** Allocate and duplicate tagged arguments as a tag list using memory home. */
+tagi_t *tl_tlist(su_home_t *home, tag_type_t tag, tag_value_t value, ...)
+{
+ tagi_t *tl;
+ ta_list ta;
+
+ ta_start(ta, tag, value);
+ tl = tl_adup(home, ta_args(ta));
+ ta_end(ta);
+
+ return tl;
+}
+
+/** Find first tag item with type @a tt from list. */
+tagi_t *tl_find(tagi_t const lst[], tag_type_t tt)
+{
+ return (tagi_t *)t_find(tt, lst);
+}
+
+/** Find last tag item with type @a tt from list. */
+tagi_t *tl_find_last(tagi_t const lst[], tag_type_t tt)
+{
+ tagi_t const *last, *next;
+
+ for (next = last = t_find(tt, lst); next; next = t_find(tt, t_next(last)))
+ last = next;
+
+ return (tagi_t *)last;
+}
+
+static inline
+int t_ref_set(tag_type_t tt, void *ref, tagi_t const value[])
+{
+ if (value == NULL)
+ return 0;
+
+ if (tt->tt_class->tc_ref_set)
+ return tt->tt_class->tc_ref_set(tt, ref, value);
+
+ *(tag_value_t *)ref = value->t_value;
+
+ return 1;
+}
+
+static int tl_get(tag_type_t tt, void *p, tagi_t const lst[])
+{
+ tagi_t const *t, *latest = NULL;
+
+ assert(tt);
+
+ if (tt == NULL || p == NULL)
+ return 0;
+
+ if (tt->tt_class == ref_tag_class)
+ tt = (tag_type_t)tt->tt_magic;
+
+ for (t = t_find(tt, lst); t; t = t_find(tt, t_next(t)))
+ latest = t;
+
+ return t_ref_set(tt, p, latest);
+}
+
+/** Find tags from given list. */
+int tl_gets(tagi_t const lst[], tag_type_t tag, tag_value_t value, ...)
+{
+ int n = 0;
+ tagi_t *t;
+ ta_list ta;
+
+ ta_start(ta, tag, value);
+
+ for (t = ta_args(ta); t; t = (tagi_t *)t_next(t)) {
+ tag_type_t tt = t->t_tag;
+
+ if (!tt)
+ continue;
+
+ if (tt->tt_class == ref_tag_class) {
+ assert(((tag_type_t)tt->tt_magic)->tt_class->tc_ref_set);
+ n += tl_get(tt, (void *)t->t_value, lst);
+ }
+#if !defined(NDEBUG)
+ else if (tt->tt_class && tt->tt_class->tc_ref_set) {
+ fprintf(stderr, "WARNING: tag %s::%s directly used by tl_gets()\n",
+ tt->tt_ns, tt->tt_name);
+ assert(tt->tt_class == ref_tag_class);
+ }
+#endif
+ }
+
+ ta_end(ta);
+
+ return n;
+}
+
+/** Find tags from given list.
+ *
+ * Copies values of argument tag list into the reference tags in the tag
+ * list @a lst.
+ *
+ * @sa tl_gets()
+ */
+int tl_tgets(tagi_t lst[], tag_type_t tag, tag_value_t value, ...)
+{
+ int n = 0;
+ tagi_t *t;
+
+ ta_list ta;
+ ta_start(ta, tag, value);
+
+ for (t = lst; t; t = (tagi_t *)t_next(t)) {
+ tag_type_t tt = t->t_tag;
+
+ if (!tt)
+ continue;
+
+ if (tt->tt_class == ref_tag_class) {
+ assert(((tag_type_t)tt->tt_magic)->tt_class->tc_ref_set);
+ n += tl_get(tt, (void *)t->t_value, ta_args(ta));
+ }
+#if !defined(NDEBUG)
+ else if (tt->tt_class->tc_ref_set) {
+ fprintf(stderr, "WARNING: tag %s::%s used in tl_tgets(lst)\n",
+ tt->tt_ns, tt->tt_name);
+ assert(tt->tt_class == ref_tag_class);
+ }
+#endif
+ }
+
+ ta_end(ta);
+
+ return n;
+}
+
+
+/** Filter an element in tag list */
+tagi_t *t_filter(tagi_t *dst,
+ tagi_t const filter[],
+ tagi_t const *src,
+ void **bb)
+{
+ tag_type_t tt = TAG_TYPE_OF(src);
+ tagi_t const *f;
+
+ if (dst) {
+ for (f = filter; f; f = t_next(f)) {
+ if (TAG_TYPE_OF(f)->tt_filter)
+ dst = TAG_TYPE_OF(f)->tt_filter(dst, f, src, bb);
+ else if (f->t_tag == tt)
+ dst = t_dup(dst, src, bb);
+ }
+ }
+ else {
+ size_t d = 0;
+
+ for (f = filter; f; f = t_next(f)) {
+ if (TAG_TYPE_OF(f)->tt_filter)
+ d += (size_t)TAG_TYPE_OF(f)->tt_filter(NULL, f, src, bb);
+ else if (tt == f->t_tag) {
+ d += t_len(src);
+ *bb = (char *)*bb + t_xtra(src, (size_t)*bb);
+ }
+ }
+
+ dst = (tagi_t *)d;
+ }
+
+ return dst;
+}
+
+/** Make filtered copy of a tag list @a src with @a filter to @a dst.
+ *
+ * Each tag in @a src is checked against tags in list @a filter. If the tag
+ * is in the @a filter list, or there is a special filter tag in the list
+ * which matches with the tag in @a src, the tag is duplicated to @a dst using
+ * memory buffer in @a b.
+ *
+ * When @a dst is NULL, this function calculates the size of the filtered list.
+ *
+ * @sa tl_afilter(), tl_tfilter(), tl_filtered_tlist(),
+ * TAG_FILTER(), TAG_ANY(), #ns_tag_class
+ */
+tagi_t *tl_filter(tagi_t dst[],
+ tagi_t const filter[],
+ tagi_t const src[],
+ void **b)
+{
+ tagi_t const *s;
+ tagi_t *d;
+
+ if (dst) {
+ for (s = src, d = dst; s; s = t_next(s))
+ d = t_filter(d, filter, s, b);
+ }
+ else {
+ size_t rv = 0;
+
+ for (s = src, d = dst; s; s = t_next(s)) {
+ d = t_filter(NULL, filter, s, b);
+ rv += (char *)d - (char *)NULL;
+ }
+
+ d = (tagi_t *)rv;
+ }
+
+ return d;
+}
+
+
+
+/**Filter a tag list.
+ *
+ * The function tl_afilter() will build a tag list containing tags specified
+ * in @a filter and extracted from @a src. It will allocate the memory used by
+ * tag list via the specified memory @a home, which may be also @c NULL.
+ *
+ * @sa tl_afilter(), tl_tfilter(), tl_filtered_tlist(),
+ * TAG_FILTER(), TAG_ANY(), #ns_tag_class
+ */
+tagi_t *tl_afilter(su_home_t *home, tagi_t const filter[], tagi_t const src[])
+{
+ tagi_t *dst, *d, *t_end = NULL;
+ void *b, *end = NULL;
+ size_t len;
+
+ /* Calculate length of the result */
+ t_end = tl_filter(NULL, filter, src, &end);
+ len = ((char *)t_end - (char *)NULL) + ((char *)end - (char*)NULL);
+
+ if (len == 0)
+ return NULL;
+
+ /* Allocate the result */
+ if (!(dst = su_alloc(home, len)))
+ return NULL;
+
+ /* Build the result */
+ b = (dst + (t_end - (tagi_t *)NULL));
+ d = tl_filter(dst, filter, src, (void **)&b);
+
+ /* Ensure that everything is consistent */
+ assert(d == dst + (t_end - (tagi_t *)NULL));
+ assert(b == (char *)dst + len);
+
+ return dst;
+}
+
+/** Filter tag list @a src with given tags.
+ *
+ * @sa tl_afilter(), tl_filtered_tlist(), TAG_FILTER(), TAG_ANY(), #ns_tag_class
+ */
+tagi_t *tl_tfilter(su_home_t *home, tagi_t const src[],
+ tag_type_t tag, tag_value_t value, ...)
+{
+ tagi_t *tl;
+ ta_list ta;
+ ta_start(ta, tag, value);
+ tl = tl_afilter(home, ta_args(ta), src);
+ ta_end(ta);
+ return tl;
+}
+
+/** Create a filtered tag list.
+ *
+ * @sa tl_afilter(), tl_tfilter(), TAG_FILTER(), TAG_ANY(), #ns_tag_class
+ */
+tagi_t *tl_filtered_tlist(su_home_t *home, tagi_t const filter[],
+ tag_type_t tag, tag_value_t value, ...)
+{
+ tagi_t *tl;
+ ta_list ta;
+
+ ta_start(ta, tag, value);
+ tl = tl_afilter(home, filter, ta_args(ta));
+ ta_end(ta);
+
+ return tl;
+}
+
+
+/** Remove listed tags from the list @a lst. */
+int tl_tremove(tagi_t lst[], tag_type_t tag, tag_value_t value, ...)
+{
+ tagi_t *l, *l_next;
+ int retval = 0;
+ ta_list ta;
+
+ ta_start(ta, tag, value);
+
+ for (l = lst; l; l = l_next) {
+ if ((l_next = (tagi_t *)t_next(l))) {
+ if (tl_find(ta_args(ta), l->t_tag))
+ l->t_tag = tag_skip;
+ else
+ retval++;
+ }
+ }
+
+ ta_end(ta);
+
+ return retval;
+}
+
+/** Calculate length of a tag list with a @c va_list. */
+size_t tl_vlen(va_list ap)
+{
+ size_t len = 0;
+ tagi_t tagi[2] = {{ NULL }};
+
+ do {
+ tagi->t_tag = va_arg(ap, tag_type_t );
+ tagi->t_value = va_arg(ap, tag_value_t);
+ len += sizeof(tagi_t);
+ } while (!t_end(tagi));
+
+ return len;
+}
+
+/** Convert va_list to tag list */
+tagi_t *tl_vlist(va_list ap)
+{
+ tagi_t *t, *rv;
+ va_list aq;
+
+ va_copy(aq, ap);
+ rv = malloc(tl_vlen(aq));
+ va_end(aq);
+
+ for (t = rv; t; t++) {
+ t->t_tag = va_arg(ap, tag_type_t);
+ t->t_value = va_arg(ap, tag_value_t);
+
+ if (t_end(t))
+ break;
+ }
+
+ return rv;
+}
+
+tagi_t *tl_vlist2(tag_type_t tag, tag_value_t value, va_list ap)
+{
+ tagi_t *t, *rv;
+ tagi_t tagi[1];
+ size_t size;
+
+ tagi->t_tag = tag, tagi->t_value = value;
+
+ if (!t_end(tagi)) {
+ va_list aq;
+ va_copy(aq, ap);
+ size = sizeof(tagi) + tl_vlen(aq);
+ va_end(aq);
+ }
+ else
+ size = sizeof(tagi);
+
+ t = rv = malloc(size);
+
+ for (;t;) {
+ *t++ = *tagi;
+
+ if (t_end(tagi))
+ break;
+
+ tagi->t_tag = va_arg(ap, tag_type_t);
+ tagi->t_value = va_arg(ap, tag_value_t);
+ }
+
+ assert((char *)rv + size == (char *)t);
+
+ return rv;
+}
+
+/** Make a tag list until TAG_NEXT() or TAG_END() */
+tagi_t *tl_list(tag_type_t tag, tag_value_t value, ...)
+{
+ va_list ap;
+ tagi_t *t;
+
+ va_start(ap, value);
+ t = tl_vlist2(tag, value, ap);
+ va_end(ap);
+
+ return t;
+}
+
+/** Calculate length of a linear tag list. */
+size_t tl_vllen(tag_type_t tag, tag_value_t value, va_list ap)
+{
+ size_t len = sizeof(tagi_t);
+ tagi_t const *next;
+ tagi_t tagi[3];
+
+ tagi[0].t_tag = tag;
+ tagi[0].t_value = value;
+ tagi[1].t_tag = tag_any;
+ tagi[1].t_value = 0;
+
+ for (;;) {
+ next = tl_next(tagi);
+ if (next != tagi + 1)
+ break;
+
+ if (tagi->t_tag != tag_skip)
+ len += sizeof(tagi_t);
+ tagi->t_tag = va_arg(ap, tag_type_t);
+ tagi->t_value = va_arg(ap, tag_value_t);
+ }
+
+ for (; next; next = tl_next(next))
+ len += sizeof(tagi_t);
+
+ return len;
+}
+
+/** Make a linear tag list. */
+tagi_t *tl_vllist(tag_type_t tag, tag_value_t value, va_list ap)
+{
+ va_list aq;
+ tagi_t *t, *rv;
+ tagi_t const *next;
+ tagi_t tagi[2];
+
+ size_t size;
+
+ va_copy(aq, ap);
+ size = tl_vllen(tag, value, aq);
+ va_end(aq);
+
+ t = rv = malloc(size);
+
+ tagi[0].t_tag = tag;
+ tagi[0].t_value = value;
+ tagi[1].t_tag = tag_any;
+ tagi[1].t_value = 0;
+
+ for (;;) {
+ next = tl_next(tagi);
+ if (next != tagi + 1)
+ break;
+
+ if (tagi->t_tag != tag_skip)
+ *t++ = *tagi;
+
+ tagi->t_tag = va_arg(ap, tag_type_t);
+ tagi->t_value = va_arg(ap, tag_value_t);
+ }
+
+ for (; next; next = tl_next(next))
+ *t++ = *next;
+
+ t->t_tag = NULL; t->t_value = 0; t++;
+
+ assert((char *)rv + size == (char *)t);
+
+ return rv;
+}
+
+/** Make a linear tag list until TAG_END().
+ *
+ */
+tagi_t *tl_llist(tag_type_t tag, tag_value_t value, ...)
+{
+ va_list ap;
+ tagi_t *t;
+
+ va_start(ap, value);
+ t = tl_vllist(tag, value, ap);
+ va_end(ap);
+
+ return t;
+}
+
+/** Free a tag list allocated by tl_list(), tl_llist() or tl_vlist(). */
+void tl_vfree(tagi_t *t)
+{
+ if (t)
+ free(t);
+}
+
+/** Convert a string to the a value of a tag. */
+int t_scan(tag_type_t tt, su_home_t *home, char const *s,
+ tag_value_t *return_value)
+{
+ if (tt == NULL || s == NULL || return_value == NULL)
+ return -1;
+
+ if (tt->tt_class->tc_scan) {
+ return tt->tt_class->tc_scan(tt, home, s, return_value);
+ }
+ else { /* Not implemented */
+ *return_value = (tag_value_t)0;
+ return -2;
+ }
+}
+
+
+/* ====================================================================== */
+/* null tag */
+
+tagi_t const *t_null_next(tagi_t const *t)
+{
+ return NULL;
+}
+
+tagi_t *t_null_move(tagi_t *dst, tagi_t const *src)
+{
+ memset(dst, 0, sizeof(*dst));
+ return dst + 1;
+}
+
+tagi_t *t_null_dup(tagi_t *dst, tagi_t const *src, void **bb)
+{
+ memset(dst, 0, sizeof(*dst));
+ return dst + 1;
+}
+
+tagi_t *t_null_copy(tagi_t *dst, tagi_t const *src, void **bb)
+{
+ memset(dst, 0, sizeof(*dst));
+ return dst + 1;
+}
+
+tagi_t const * t_null_find(tag_type_t tt, tagi_t const lst[])
+{
+ return NULL;
+}
+
+tagi_t *t_null_filter(tagi_t *dst,
+ tagi_t const filter[],
+ tagi_t const *src,
+ void **bb)
+{
+ if (TAG_TYPE_OF(src) == tag_null) {
+ if (dst) {
+ dst->t_tag = NULL;
+ dst->t_value = 0;
+ }
+ return dst + 1;
+ }
+ return dst;
+}
+
+tag_class_t null_tag_class[1] =
+ {{
+ sizeof(null_tag_class),
+ /* tc_next */ t_null_next,
+ /* tc_len */ NULL,
+ /* tc_move */ t_null_move,
+ /* tc_xtra */ NULL,
+ /* tc_dup */ t_null_dup,
+ /* tc_free */ NULL,
+ /* tc_find */ t_null_find,
+ /* tc_snprintf */ NULL,
+ /* tc_filter */ t_null_filter,
+ /* tc_ref_set */ NULL,
+ /* tc_scan */ NULL,
+ }};
+
+tag_typedef_t tag_null = TAG_TYPEDEF(tag_null, null);
+
+/* ====================================================================== */
+/* end tag */
+
+tagi_t *t_end_filter(tagi_t *dst,
+ tagi_t const filter[],
+ tagi_t const *src,
+ void **bb)
+{
+ return dst;
+}
+
+tag_class_t end_tag_class[1] =
+ {{
+ sizeof(end_tag_class),
+ /* tc_next */ NULL,
+ /* tc_len */ NULL,
+ /* tc_move */ NULL,
+ /* tc_xtra */ NULL,
+ /* tc_dup */ NULL,
+ /* tc_free */ NULL,
+ /* tc_find */ NULL,
+ /* tc_snprintf */ NULL,
+ /* tc_filter */ t_end_filter,
+ /* tc_ref_set */ NULL,
+ /* tc_scan */ NULL,
+ }};
+
+/* ====================================================================== */
+/* skip tag - placeholder in tag list */
+
+tagi_t const *t_skip_next(tagi_t const *t)
+{
+ return t + 1;
+}
+
+tagi_t *t_skip_move(tagi_t *dst, tagi_t const *src)
+{
+ return dst;
+}
+
+size_t t_skip_len(tagi_t const *t)
+{
+ return 0;
+}
+
+tagi_t *t_skip_dup(tagi_t *dst, tagi_t const *src, void **bb)
+{
+ return dst;
+}
+
+tagi_t *t_skip_filter(tagi_t *dst,
+ tagi_t const filter[],
+ tagi_t const *src,
+ void **bb)
+{
+ return dst;
+}
+
+tag_class_t skip_tag_class[1] =
+ {{
+ sizeof(skip_tag_class),
+ /* tc_next */ t_skip_next,
+ /* tc_len */ t_skip_len,
+ /* tc_move */ t_skip_move,
+ /* tc_xtra */ NULL,
+ /* tc_dup */ t_skip_dup,
+ /* tc_free */ NULL,
+ /* tc_find */ t_null_find,
+ /* tc_snprintf */ NULL,
+ /* tc_filter */ t_skip_filter,
+ /* tc_ref_set */ NULL,
+ /* tc_scan */ NULL,
+ }};
+
+tag_typedef_t tag_skip = TAG_TYPEDEF(tag_skip, skip);
+
+/* ====================================================================== */
+/* next tag - jump to next tag list */
+
+tagi_t const *t_next_next(tagi_t const *t)
+{
+ return (tagi_t *)(t->t_value);
+}
+
+tagi_t *t_next_move(tagi_t *dst, tagi_t const *src)
+{
+ if (!src->t_value)
+ return t_null_move(dst, src);
+ return dst;
+}
+
+size_t t_next_len(tagi_t const *t)
+{
+ if (!t->t_value)
+ return sizeof(*t);
+ return 0;
+}
+
+tagi_t *t_next_dup(tagi_t *dst, tagi_t const *src, void **bb)
+{
+ if (!src->t_value)
+ return t_null_dup(dst, src, bb);
+ return dst;
+}
+
+tagi_t *t_next_filter(tagi_t *dst,
+ tagi_t const filter[],
+ tagi_t const *src,
+ void **bb)
+{
+ return dst;
+}
+
+tag_class_t next_tag_class[1] =
+ {{
+ sizeof(next_tag_class),
+ /* tc_next */ t_next_next,
+ /* tc_len */ t_next_len,
+ /* tc_move */ t_next_move,
+ /* tc_xtra */ NULL,
+ /* tc_dup */ t_next_dup,
+ /* tc_free */ NULL,
+ /* tc_find */ t_null_find,
+ /* tc_snprintf */ NULL,
+ /* tc_filter */ t_next_filter,
+ /* tc_ref_set */ NULL,
+ /* tc_scan */ NULL,
+ }};
+
+tag_typedef_t tag_next = TAG_TYPEDEF(tag_next, next);
+
+/* ====================================================================== */
+/* filter tag - use function to filter tag */
+
+tagi_t *t_filter_with(tagi_t *dst,
+ tagi_t const *t,
+ tagi_t const *src,
+ void **bb)
+{
+ tag_filter_f *function;
+
+ if (!src || !t)
+ return dst;
+
+ function = (tag_filter_f *)t->t_value;
+
+ if (!function || !function(t, src))
+ return dst;
+
+ if (dst) {
+ return t_dup(dst, src, bb);
+ }
+ else {
+ dst = (tagi_t *)((char *)dst + t_len(src));
+ *bb = (char *)*bb + t_xtra(src, (size_t)*bb);
+ return dst;
+ }
+}
+
+tag_class_t filter_tag_class[1] =
+ {{
+ sizeof(filter_tag_class),
+ /* tc_next */ NULL,
+ /* tc_len */ NULL,
+ /* tc_move */ NULL,
+ /* tc_xtra */ NULL,
+ /* tc_dup */ NULL,
+ /* tc_free */ NULL,
+ /* tc_find */ NULL,
+ /* tc_snprintf */ NULL,
+ /* tc_filter */ t_filter_with,
+ /* tc_ref_set */ NULL,
+ /* tc_scan */ NULL,
+ }};
+
+/** Filter tag - apply function in order to filter tag. */
+tag_typedef_t tag_filter = TAG_TYPEDEF(tag_filter, filter);
+
+/* ====================================================================== */
+/* any tag - match to any tag when filtering */
+
+tagi_t *t_any_filter(tagi_t *dst,
+ tagi_t const filter[],
+ tagi_t const *src,
+ void **bb)
+{
+ if (!src)
+ return dst;
+ else if (dst) {
+ return t_dup(dst, src, bb);
+ }
+ else {
+ dst = (tagi_t *)((char *)dst + t_len(src));
+ *bb = (char *)*bb + t_xtra(src, (size_t)*bb);
+ return dst;
+ }
+}
+
+tag_class_t any_tag_class[1] =
+ {{
+ sizeof(any_tag_class),
+ /* tc_next */ NULL,
+ /* tc_len */ NULL,
+ /* tc_move */ NULL,
+ /* tc_xtra */ NULL,
+ /* tc_dup */ NULL,
+ /* tc_free */ NULL,
+ /* tc_find */ NULL,
+ /* tc_snprintf */ NULL,
+ /* tc_filter */ t_any_filter,
+ /* tc_ref_set */ NULL,
+ /* tc_scan */ NULL,
+ }};
+
+/** Any tag - match any tag when filtering. */
+tag_typedef_t tag_any = TAG_TYPEDEF(tag_any, any);
+
+/* ====================================================================== */
+/* ns tag - match to any tag with same namespace when filtering */
+
+static
+tagi_t *t_ns_filter(tagi_t *dst,
+ tagi_t const filter[],
+ tagi_t const *src,
+ void **bb)
+{
+ char const *match, *ns;
+
+ if (!src)
+ return dst;
+
+ assert(filter);
+
+ match = TAG_TYPE_OF(filter)->tt_ns;
+ ns = TAG_TYPE_OF(src)->tt_ns;
+
+ if (match == NULL)
+ /* everything matches with this */;
+ else if (match == ns)
+ /* namespaces matche */;
+ else if (ns == NULL)
+ /* no match */
+ return dst;
+ else if (strcmp(match, ns))
+ /* no match */
+ return dst;
+
+ if (dst) {
+ return t_dup(dst, src, bb);
+ }
+ else {
+ dst = (tagi_t *)((char *)dst + t_len(src));
+ *bb = (char *)*bb + t_xtra(src, (size_t)*bb);
+ return dst;
+ }
+}
+
+/** Namespace filtering class */
+tag_class_t ns_tag_class[1] =
+ {{
+ sizeof(ns_tag_class),
+ /* tc_next */ NULL,
+ /* tc_len */ NULL,
+ /* tc_move */ NULL,
+ /* tc_xtra */ NULL,
+ /* tc_dup */ NULL,
+ /* tc_free */ NULL,
+ /* tc_find */ NULL,
+ /* tc_snprintf */ NULL,
+ /* tc_filter */ t_ns_filter,
+ /* tc_ref_set */ NULL,
+ /* tc_scan */ NULL,
+ }};
+
+/* ====================================================================== */
+/* int tag - pass integer value */
+
+int t_int_snprintf(tagi_t const *t, char b[], size_t size)
+{
+ return snprintf(b, size, "%i", (int)t->t_value);
+}
+
+int t_int_ref_set(tag_type_t tt, void *ref, tagi_t const value[])
+{
+ *(int *)ref = (int)value->t_value;
+
+ return 1;
+}
+
+int t_int_scan(tag_type_t tt, su_home_t *home,
+ char const *s,
+ tag_value_t *return_value)
+{
+ int value;
+ char *rest;
+
+ value = strtol(s, &rest, 0);
+
+ if (s != rest) {
+ *return_value = (tag_value_t)value;
+ return 1;
+ }
+ else {
+ *return_value = (tag_value_t)0;
+ return -1;
+ }
+}
+
+tag_class_t int_tag_class[1] =
+ {{
+ sizeof(int_tag_class),
+ /* tc_next */ NULL,
+ /* tc_len */ NULL,
+ /* tc_move */ NULL,
+ /* tc_xtra */ NULL,
+ /* tc_dup */ NULL,
+ /* tc_free */ NULL,
+ /* tc_find */ NULL,
+ /* tc_snprintf */ t_int_snprintf,
+ /* tc_filter */ NULL,
+ /* tc_ref_set */ t_int_ref_set,
+ /* tc_scan */ t_int_scan,
+ }};
+
+/* ====================================================================== */
+/* uint tag - pass unsigned integer value */
+
+int t_uint_snprintf(tagi_t const *t, char b[], size_t size)
+{
+ return snprintf(b, size, "%u", (unsigned)t->t_value);
+}
+
+int t_uint_ref_set(tag_type_t tt, void *ref, tagi_t const value[])
+{
+ *(unsigned *)ref = (unsigned)value->t_value;
+
+ return 1;
+}
+
+int t_uint_scan(tag_type_t tt, su_home_t *home,
+ char const *s,
+ tag_value_t *return_value)
+{
+ unsigned value;
+ char *rest;
+
+ value = strtoul(s, &rest, 0);
+
+ if (s != rest) {
+ *return_value = (tag_value_t)value;
+ return 1;
+ }
+ else {
+ *return_value = (tag_value_t)0;
+ return -1;
+ }
+}
+
+tag_class_t uint_tag_class[1] =
+ {{
+ sizeof(int_tag_class),
+ /* tc_next */ NULL,
+ /* tc_len */ NULL,
+ /* tc_move */ NULL,
+ /* tc_xtra */ NULL,
+ /* tc_dup */ NULL,
+ /* tc_free */ NULL,
+ /* tc_find */ NULL,
+ /* tc_snprintf */ t_uint_snprintf,
+ /* tc_filter */ NULL,
+ /* tc_ref_set */ t_uint_ref_set,
+ /* tc_scan */ t_uint_scan,
+ }};
+
+
+/* ====================================================================== */
+/* size tag - pass size_t value @NEW_1_12_5 */
+
+static
+int t_size_snprintf(tagi_t const *t, char b[], size_t size)
+{
+ return snprintf(b, size, MOD_ZU, (size_t)t->t_value);
+}
+
+static
+int t_size_ref_set(tag_type_t tt, void *ref, tagi_t const value[])
+{
+ *(size_t *)ref = (size_t)value->t_value;
+
+ return 1;
+}
+
+static
+int t_size_scan(tag_type_t tt, su_home_t *home,
+ char const *s,
+ tag_value_t *return_value)
+{
+ unsigned longlong value;
+ char *rest;
+
+ value = strtoull(s, &rest, 0);
+
+ if (s != rest && value <= SIZE_MAX) {
+ *return_value = (tag_value_t)value;
+ return 1;
+ }
+ else {
+ *return_value = (tag_value_t)0;
+ return -1;
+ }
+}
+
+/** Tag class for tags with size_t value. @NEW_1_12_5 */
+tag_class_t size_tag_class[1] =
+ {{
+ sizeof(int_tag_class),
+ /* tc_next */ NULL,
+ /* tc_len */ NULL,
+ /* tc_move */ NULL,
+ /* tc_xtra */ NULL,
+ /* tc_dup */ NULL,
+ /* tc_free */ NULL,
+ /* tc_find */ NULL,
+ /* tc_snprintf */ t_size_snprintf,
+ /* tc_filter */ NULL,
+ /* tc_ref_set */ t_size_ref_set,
+ /* tc_scan */ t_size_scan,
+ }};
+
+/* ====================================================================== */
+/* usize tag - pass usize_t value */
+
+static
+int t_usize_ref_set(tag_type_t tt, void *ref, tagi_t const value[])
+{
+ *(usize_t *)ref = (usize_t)value->t_value;
+
+ return 1;
+}
+
+static
+int t_usize_scan(tag_type_t tt, su_home_t *home,
+ char const *s,
+ tag_value_t *return_value)
+{
+ unsigned longlong value;
+ char *rest;
+
+ value = strtoull(s, &rest, 0);
+
+ if (s != rest && value <= USIZE_MAX) {
+ *return_value = (tag_value_t)value;
+ return 1;
+ }
+ else {
+ *return_value = (tag_value_t)0;
+ return -1;
+ }
+}
+
+/** Tag class for tags with usize_t value. @NEW_1_12_5 */
+tag_class_t usize_tag_class[1] =
+ {{
+ sizeof(int_tag_class),
+ /* tc_next */ NULL,
+ /* tc_len */ NULL,
+ /* tc_move */ NULL,
+ /* tc_xtra */ NULL,
+ /* tc_dup */ NULL,
+ /* tc_free */ NULL,
+ /* tc_find */ NULL,
+ /* tc_snprintf */ t_size_snprintf,
+ /* tc_filter */ NULL,
+ /* tc_ref_set */ t_usize_ref_set,
+ /* tc_scan */ t_usize_scan,
+ }};
+
+
+/* ====================================================================== */
+/* bool tag - pass boolean value */
+
+int t_bool_snprintf(tagi_t const *t, char b[], size_t size)
+{
+ return snprintf(b, size, "%s", t->t_value ? "true" : "false");
+}
+
+int t_bool_ref_set(tag_type_t tt, void *ref, tagi_t const value[])
+{
+ *(int *)ref = (value->t_value != 0);
+
+ return 1;
+}
+
+int t_bool_scan(tag_type_t tt, su_home_t *home,
+ char const *s,
+ tag_value_t *return_value)
+{
+ int retval;
+ int value = 0;
+
+ if (strncasecmp(s, "true", 4) == 0
+ && strlen(s + 4) == strspn(s + 4, " \t\r\n")) {
+ value = 1, retval = 1;
+ } else if (strncasecmp(s, "false", 5) == 0
+ && strlen(s + 5) == strspn(s + 5, " \t\r\n")) {
+ value = 0, retval = 1;
+ } else {
+ retval = t_int_scan(tt, home, s, return_value);
+ value = *return_value != 0;
+ }
+
+ if (retval == 1)
+ *return_value = (tag_value_t)value;
+ else
+ *return_value = (tag_value_t)0;
+
+ return retval;
+}
+
+tag_class_t bool_tag_class[1] =
+ {{
+ sizeof(bool_tag_class),
+ /* tc_next */ NULL,
+ /* tc_len */ NULL,
+ /* tc_move */ NULL,
+ /* tc_xtra */ NULL,
+ /* tc_dup */ NULL,
+ /* tc_free */ NULL,
+ /* tc_find */ NULL,
+ /* tc_snprintf */ t_bool_snprintf,
+ /* tc_filter */ NULL,
+ /* tc_ref_set */ t_bool_ref_set,
+ /* tc_scan */ t_bool_scan,
+ }};
+
+/* ====================================================================== */
+/* ptr tag - pass pointer value */
+
+int t_ptr_snprintf(tagi_t const *t, char b[], size_t size)
+{
+ return snprintf(b, size, "%p", (void *)t->t_value);
+}
+
+int t_ptr_ref_set(tag_type_t tt, void *ref, tagi_t const value[])
+{
+ *(void **)ref = (void *)value->t_value;
+
+ return 1;
+}
+
+/* This is not usually very safe, so it is not used */
+int t_ptr_scan(tag_type_t tt, su_home_t *home,
+ char const *s,
+ tag_value_t *return_value)
+{
+ int retval;
+ void *ptr;
+
+ retval = sscanf(s, "%p", &ptr);
+
+ if (retval == 1)
+ *return_value = (tag_value_t)ptr;
+ else
+ *return_value = (tag_value_t)NULL;
+
+ return retval;
+}
+
+tag_class_t ptr_tag_class[1] =
+ {{
+ sizeof(ptr_tag_class),
+ /* tc_next */ NULL,
+ /* tc_len */ NULL,
+ /* tc_move */ NULL,
+ /* tc_xtra */ NULL,
+ /* tc_dup */ NULL,
+ /* tc_free */ NULL,
+ /* tc_find */ NULL,
+ /* tc_snprintf */ t_ptr_snprintf,
+ /* tc_filter */ NULL,
+ /* tc_ref_set */ t_ptr_ref_set,
+ /* tc_scan */ NULL,
+ }};
+
+/* ====================================================================== */
+/* socket tag - pass socket */
+
+#include <sofia-sip/su.h>
+
+int t_socket_snprintf(tagi_t const *t, char b[], size_t size)
+{
+ /* socket can be int or DWORD (or QWORD on win64?) */
+ return snprintf(b, size, LLI, (longlong)t->t_value);
+}
+
+int t_socket_ref_set(tag_type_t tt, void *ref, tagi_t const value[])
+{
+ *(su_socket_t *)ref = (su_socket_t)value->t_value;
+
+ return 1;
+}
+
+tag_class_t socket_tag_class[1] =
+ {{
+ sizeof(socket_tag_class),
+ /* tc_next */ NULL,
+ /* tc_len */ NULL,
+ /* tc_move */ NULL,
+ /* tc_xtra */ NULL,
+ /* tc_dup */ NULL,
+ /* tc_free */ NULL,
+ /* tc_find */ NULL,
+ /* tc_snprintf */ t_socket_snprintf,
+ /* tc_filter */ NULL,
+ /* tc_ref_set */ t_socket_ref_set,
+ /* tc_scan */ NULL,
+ }};
+
+/* ====================================================================== */
+/* str tag - pass string value */
+
+int t_str_snprintf(tagi_t const *t, char b[], size_t size)
+{
+ if (t->t_value)
+ return snprintf(b, size, "\"%s\"", (char const *)t->t_value);
+ else
+ return snprintf(b, size, "<null>");
+}
+
+int t_str_scan(tag_type_t tt, su_home_t *home,
+ char const *s,
+ tag_value_t *return_value)
+{
+ int retval;
+
+ s = su_strdup(home, s);
+
+ if (s)
+ *return_value = (tag_value_t)s, retval = 1;
+ else
+ *return_value = (tag_value_t)NULL, retval = -1;
+
+ return retval;
+}
+
+tagi_t *t_str_dup(tagi_t *dst, tagi_t const *src, void **bb)
+{
+ dst->t_tag = src->t_tag;
+ if (src->t_value) {
+ char const *s = (char const *)src->t_value;
+ size_t len = strlen(s) + 1;
+ dst->t_value = (tag_value_t)strcpy(*bb, s);
+ *bb = (char *)*bb + len;
+ }
+ else
+ dst->t_value = (tag_value_t)0;
+
+ return dst + 1;
+}
+
+size_t t_str_xtra(tagi_t const *t, size_t offset)
+{
+ return t->t_value ? strlen((char *)t->t_value) + 1 : 0;
+}
+
+tag_class_t str_tag_class[1] =
+ {{
+ sizeof(str_tag_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,
+ /* tc_ref_set */ t_ptr_ref_set,
+ /* tc_scan */ t_str_scan,
+ }};
+
+/* ====================================================================== */
+/* cstr tag - pass constant string value (no need to dup) */
+
+/** Tag class for constant strings */
+tag_class_t cstr_tag_class[1] =
+ {{
+ sizeof(cstr_tag_class),
+ /* tc_next */ NULL,
+ /* tc_len */ NULL,
+ /* tc_move */ NULL,
+ /* tc_xtra */ NULL,
+ /* tc_dup */ NULL,
+ /* tc_free */ NULL,
+ /* tc_find */ NULL,
+ /* tc_snprintf */ t_str_snprintf,
+ /* tc_filter */ NULL,
+ /* tc_ref_set */ t_ptr_ref_set,
+ /* tc_scan */ t_str_scan,
+ }};
+
+/* ====================================================================== */
+/* ref tag - pass reference */
+
+tag_class_t ref_tag_class[1] =
+ {{
+ sizeof(ref_tag_class),
+ /* tc_next */ NULL,
+ /* tc_len */ NULL,
+ /* tc_move */ NULL,
+ /* tc_xtra */ NULL,
+ /* tc_dup */ NULL,
+ /* tc_free */ NULL,
+ /* tc_find */ NULL,
+ /* tc_snprintf */ t_ptr_snprintf,
+ /* tc_filter */ NULL,
+ /* tc_ref_set */ t_ptr_ref_set,
+ /* tc_scan */ NULL,
+ }};
+
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_time.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_time.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,465 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005,2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_time
+ * @CFILE su_time.c
+ *
+ * @brief Implementation of OS-independent time functions.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Jari Selin <Jari.Selin at nokia.com>
+ * @author Kai Vehmanen <first.surname at nokia.com>
+ *
+ * @date Created: Thu Mar 18 19:40:51 1999 pessi
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <time.h>
+
+#include "sofia-sip/su_types.h"
+#include "sofia-sip/su_time.h"
+#include "su_module_debug.h"
+
+#if HAVE_SYS_TIME_H
+#include <sys/time.h> /* Get struct timeval */
+#endif
+
+/**@defgroup su_time Time Handling
+ *
+ * OS-independent timing functions and types for the @b su library.
+ *
+ * The @b su library provides three different time formats with different
+ * ranges and epochs in the file @b su_time.h:
+ *
+ * - #su_time_t, second and microsecond as 32-bit values since 1900,
+ * - #su_duration_t, milliseconds between two times, and
+ * - #su_ntp_t, standard NTP timestamp (seconds since 1900 as
+ * a fixed-point 64-bit value with 32 bits representing subsecond
+ * value).
+ */
+
+/**
+ * Compare two timestamps.
+ *
+ * The function su_time_cmp() compares two su_time_t timestamps.
+ *
+ * @param t1 first NTP timestamp in su_time_t structure
+ * @param t2 second NTP timestamp in su_time_t structure
+ *
+ * @retval Negative, if @a t1 is before @a t2,
+ * @retval Zero, if @a t1 is same as @a t2, or
+ * @retval Positive, if @a t1 is after @a t2.
+ *
+ */
+long su_time_cmp(su_time_t const t1, su_time_t const t2)
+{
+ long retval = 0;
+
+ if (t1.tv_sec > t2.tv_sec)
+ retval = 1;
+ else if (t1.tv_sec < t2.tv_sec)
+ retval = -1;
+ else {
+ if (t1.tv_usec > t2.tv_usec)
+ retval = 1;
+ else if (t1.tv_usec < t2.tv_usec)
+ retval = -1;
+ }
+
+ return retval;
+}
+
+/**@def SU_TIME_CMP(t1, t2)
+ *
+ * Compare two timestamps.
+ *
+ * The macro SU_TIME_CMP() compares two su_time_t timestamps.
+ *
+ * @param t1 first NTP timestamp in su_time_t structure
+ * @param t2 second NTP timestamp in su_time_t structure
+ *
+ * @retval negative, if t1 is before t2,
+ * @retval zero, if t1 is same as t2, or
+ * @retval positive, if t1 is after t2.
+ *
+ * @hideinitializer
+ */
+
+/** Difference between two timestamps.
+ *
+ * The function returns difference between two timestamps
+ * in seconds (t1 - t2).
+ *
+ * @param t1 first timeval
+ * @param t2 second timeval
+ *
+ * @return
+ * The difference between two timestamps in seconds as a double.
+ */
+double su_time_diff(su_time_t const t1, su_time_t const t2)
+{
+ return
+ ((double)t1.tv_sec - (double)t2.tv_sec)
+ + (double)((long)t1.tv_usec - (long)t2.tv_usec) / 1000000.0;
+}
+
+/** Get current time.
+ *
+ * Return the current timestamp in su_time_t structure.
+ *
+ * @return
+ * The structure containing the current NTP timestamp.
+ */
+su_time_t su_now(void)
+{
+ su_time_t retval;
+ su_time(&retval);
+ return retval;
+}
+
+/** Print su_time_t timestamp.
+ *
+ * This function prints a su_time_t timestamp as a decimal number to the
+ * given buffer.
+ *
+ * @param s pointer to buffer
+ * @param n buffer size
+ * @param tv pointer to the timeval object
+ *
+ * @return
+ * The number of characters printed, excluding the final @c NUL.
+ */
+int su_time_print(char *s, int n, su_time_t const *tv)
+{
+#ifdef _WIN32
+ return _snprintf(s, n, "%lu.%06lu", tv->tv_sec, tv->tv_usec);
+#else
+ return snprintf(s, n, "%lu.%06lu", tv->tv_sec, tv->tv_usec);
+#endif
+}
+
+/** Time difference in milliseconds.
+ *
+ * Calculates the duration from t2 to t1 in milliseconds.
+ *
+ * @param t1 after time
+ * @param t2 before time
+ *
+ * @return
+ * The duration in milliseconds between the two times. If the difference
+ * is bigger than @c SU_DURATION_MAX, the function su_duration() returns
+ * @c SU_DURATION_MAX instead. If the difference is smaller than @c
+ * -SU_DURATION_MAX, the function su_duration() returns @c
+ * -SU_DURATION_MAX.
+ */
+su_duration_t su_duration(su_time_t const t1, su_time_t const t2)
+{
+ su_duration_t diff, udiff, tdiff;
+
+ diff = t1.tv_sec - t2.tv_sec;
+ udiff = t1.tv_usec - t2.tv_usec;
+
+ tdiff = diff * 1000 + udiff / 1000;
+
+ if (diff > (SU_DURATION_MAX / 1000) || (diff > 0 && diff > tdiff))
+ return SU_DURATION_MAX;
+ if (diff < (-SU_DURATION_MAX / 1000) || (diff < 0 && diff < tdiff))
+ return -SU_DURATION_MAX;
+
+ return tdiff;
+}
+
+typedef uint64_t su_t64_t; /* time with 64 bits */
+
+const uint32_t su_res32 = 1000000UL;
+const su_t64_t su_res64 = (su_t64_t)1000000UL;
+
+#define SU_TIME_TO_T64(tv) \
+ (su_res64 * (su_t64_t)(tv).tv_sec + (su_t64_t)(tv).tv_usec)
+#define SU_DUR_TO_T64(d) (1000 * (int64_t)(d))
+
+/** Get NTP timestamp.
+ *
+ * The function su_ntp_now() returns the current NTP timestamp. NTP
+ * timestamp is seconds elapsed since January 1st, 1900.
+ *
+ * @return
+ * The current time as NTP timestamp is returned.
+ */
+su_ntp_t su_ntp_now(void)
+{
+ su_time_t t;
+ uint32_t sec, usec;
+
+ su_time(&t);
+
+ sec = t.tv_sec;
+ usec = t.tv_usec;
+
+ /*
+ * Multiply usec by 4294.967296 (ie. 2**32 / 1E6)
+ *
+ * Utilize fact that 4294.967296 == 4295 - 511 / 15625
+ */
+ usec = 4295 * usec - (511 * usec + 7812) / 15625;
+
+ return ((su_ntp_t)sec << 32) + (su_ntp_t)usec;
+}
+
+/** Get NTP seconds.
+ *
+ * The function su_ntp_sec() returns the seconds elapsed since January 1st,
+ * 1900.
+ *
+ * @return
+ * The current time as NTP seconds is returned.
+ */
+uint32_t su_ntp_sec(void)
+{
+ su_time_t t;
+ su_time(&t);
+ return t.tv_sec;
+}
+
+/** High 32 bit of NTP timestamp.
+ *
+ * @param ntp 64bit NTP timestamp.
+ *
+ * @return The function su_ntp_hi() returns high 32 bits of NTP timestamp.
+ */
+uint32_t su_ntp_hi(su_ntp_t ntp)
+{
+ return (uint32_t) (ntp >> 32) & 0xffffffffLU;
+}
+
+
+su_ntp_t su_ntp_hilo(uint32_t hi, uint32_t lo)
+{
+ return ((((su_ntp_t)hi) << 32)) | lo;
+}
+
+/** Low 32 bit of NTP timestamp.
+ *
+ * @param ntp 64bit NTP timestamp.
+ *
+ * @return The function su_ntp_hi() returns low 32 bits of NTP timestamp.
+ */
+uint32_t su_ntp_lo(su_ntp_t ntp)
+{
+ return (uint32_t) ntp & 0xffffffffLU;
+}
+
+/** Middle 32 bit of NTP timestamp.
+ *
+ * @param ntp 64bit NTP timestamp.
+ *
+ * @return The function su_ntp_mw() returns bits 48..16 (middle word) of NTP
+ * timestamp.
+ */
+uint32_t su_ntp_mw(su_ntp_t ntp)
+{
+ return (uint32_t) (ntp >> 16) & 0xffffffffLU;
+}
+
+su_time_t su_t64_to_time(su_t64_t const us)
+{
+ su_time_t tv;
+
+ tv.tv_sec = (unsigned long) (us / su_res64);
+ tv.tv_usec = (unsigned long) (us % su_res64);
+
+ return tv;
+}
+
+/**
+ * Add milliseconds to the time.
+ *
+ * @param t0 time in seconds and microseconds as @c su_time_t
+ * @param dur milliseconds to be added
+ */
+su_time_t su_time_add(su_time_t t0, su_duration_t dur)
+{
+ return su_t64_to_time(SU_TIME_TO_T64(t0) + SU_DUR_TO_T64(dur));
+}
+
+/**
+ * Add seconds to the time.
+ *
+ * @param t0 time in seconds and microseconds as @c su_time_t
+ * @param sec seconds to be added
+ *
+ * @return
+ * New time as @c su_time_t.
+ */
+su_time_t su_time_dadd(su_time_t t0, double sec)
+{
+ return su_t64_to_time(SU_TIME_TO_T64(t0) + (int64_t)(su_res32 * sec));
+}
+
+#ifdef WIN32
+
+#include <windows.h>
+
+uint64_t su_nanocounter(void)
+{
+ static ULONGLONG counterfreq = 0; /*performance counter frequency*/
+ LARGE_INTEGER LargeIntCount = { 0, 0 };
+ ULONGLONG count;
+
+ if(!counterfreq) {
+ LARGE_INTEGER Freq = { 0, 0 };
+ if (!QueryPerformanceFrequency(&Freq)) {
+ SU_DEBUG_1(("su_counter: QueryPerformanceFrequency failed\n"));
+ return 0;
+ }
+ counterfreq = Freq.QuadPart;
+ }
+
+ if (!QueryPerformanceCounter(&LargeIntCount)) {
+ SU_DEBUG_1(("su_counter: QueryPeformanceCounter failed\n"));
+ return 0;
+ }
+ count = (ULONGLONG) LargeIntCount.QuadPart;
+
+ /* return value is in ns */
+ return ((count * 1000 * 1000 * 1000) / counterfreq) ;
+}
+
+uint64_t su_counter(void)
+{
+ return su_nanocounter() / 1000U;
+}
+
+#elif HAVE_CLOCK_GETTIME
+
+/** Return CPU counter value in nanoseconds.
+ *
+ * The function su_nanocounter() returns a CPU counter value in nanoseconds
+ * for timing purposes.
+ *
+ * Parameters:
+ *
+ * @return
+ * The current CPU counter value in nanoseconds
+ */
+uint64_t su_nanocounter(void)
+{
+ struct timespec tp;
+ struct timeval tv;
+ static int init = 0;
+ static clockid_t cpu = CLOCK_REALTIME;
+
+# define CLOCK_GETTIMEOFDAY 0xdedbeefUL
+
+ if (init == 0) {
+ init = 1;
+
+ if (0)
+ ;
+#if HAVE_CLOCK_GETCPUCLOCKID
+ else if (clock_getcpuclockid(0, &cpu) != -1 &&
+ clock_gettime(cpu, &tp) != -1)
+ ;
+#endif
+#ifdef _POSIX_CPUTIME
+ else if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tp) >= 0)
+ cpu = CLOCK_PROCESS_CPUTIME_ID;
+#endif
+ else if (clock_gettime(CLOCK_REALTIME, &tp) >= 0)
+ cpu = CLOCK_REALTIME;
+ else
+ cpu = CLOCK_GETTIMEOFDAY;
+ }
+
+ if (cpu == CLOCK_GETTIMEOFDAY) {
+ gettimeofday(&tv, NULL);
+ tp.tv_sec = tv.tv_sec, tp.tv_nsec = tv.tv_usec * 1000;
+ }
+ else if (clock_gettime(cpu, &tp) < 0)
+ perror("clock_gettime");
+
+ /* return value is in nanoseconds */
+ return
+ (uint64_t)((unsigned long)tp.tv_nsec) +
+ (uint64_t)((unsigned long)tp.tv_sec) * 1000000000ULL;
+}
+
+/** Return CPU counter value in microseconds.
+ *
+ * The function su_counter() returns the CPU counter value in microseconds
+ * for timing purposes.
+ *
+ * Parameters:
+ *
+ * @return
+ * The current CPU counter value in microseconds.
+ */
+uint64_t su_counter(void)
+{
+ return su_nanocounter() / 1000U;
+}
+
+#elif HAVE_GETTIMEOFDAY
+uint64_t su_counter(void)
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ /* return value is in microseconds */
+ return
+ (uint64_t)((unsigned long)tv.tv_usec) +
+ (uint64_t)((unsigned long)tv.tv_sec) * 1000000ULL;
+}
+
+uint64_t su_nanocounter(void)
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ /* return value is in nanoseconds */
+ return
+ (uint64_t)((unsigned long)tv.tv_usec) * 1000ULL +
+ (uint64_t)((unsigned long)tv.tv_sec) * 1000000000ULL;
+}
+
+#else
+
+uint64_t su_counter(void)
+{
+ return (uint64_t)clock();
+}
+
+uint64_t su_nanocounter(void)
+{
+ return (uint64_t)clock() * 1000;
+}
+
+#endif /* WIN32 */
+
+
+
+
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_time0.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_time0.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,93 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_time
+ * @CFILE su_time0.c
+ * @brief su_time() implementation
+ *
+ * The file su_time0.c contains implementation of OS-independent wallclock
+ * time with microsecond resolution.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Jari Selin <Jari.Selin at nokia.com>
+ *
+ * @date Created: Fri May 10 18:13:19 2002 ppessi
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "sofia-sip/su_types.h"
+#include "sofia-sip/su_time.h"
+#include "su_module_debug.h"
+
+#if HAVE_SYS_TIME_H
+#include <sys/time.h> /* Get struct timeval */
+#endif
+
+#if defined(__MINGW32__)
+#define HAVE_FILETIME 1
+#include <windows.h>
+#endif
+
+#if HAVE_FILETIME
+#define HAVE_FILETIME 1
+#include <windows.h>
+#endif
+
+/** Seconds from 1.1.1900 to 1.1.1970 */
+#define NTP_EPOCH 2208988800UL
+
+/** Get current time.
+ *
+ * The function @c su_time() fills its argument with the current NTP
+ * timestamp expressed as a su_time_t structure.
+ *
+ * @param tv pointer to the timeval object
+ */
+void su_time(su_time_t *tv)
+{
+#if HAVE_GETTIMEOFDAY
+ if (tv) {
+ gettimeofday((struct timeval *)tv, NULL);
+ tv->tv_sec += NTP_EPOCH;
+ }
+#elif HAVE_FILETIME
+ union {
+ FILETIME ft[1];
+ ULARGE_INTEGER ull[1];
+ } date;
+
+ GetSystemTimeAsFileTime(date.ft);
+
+ tv->tv_usec = (unsigned long) ((date.ull->QuadPart % 10000000U) / 10);
+ tv->tv_sec = (unsigned long) ((date.ull->QuadPart / 10000000U) -
+ /* 1900-Jan-01 - 1601-Jan-01: 299 years, 72 leap years */
+ (299 * 365 + 72) * 24 * 60 * (uint64_t)60);
+#else
+#error no su_time() implementation
+#endif
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_timer.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_timer.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,634 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE su_timer.c
+ *
+ * Timer interface for su_root.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * Created: Fri Apr 28 15:45:41 2000 ppessi
+ */
+
+#include "config.h"
+
+#include "sofia-sip/su.h"
+#include "sofia-sip/su_wait.h"
+#include "sofia-sip/su_alloc.h"
+#include "sofia-sip/rbtree.h"
+
+#include "su_module_debug.h"
+
+#include <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+/**@ingroup su_wait
+ *
+ * @page su_timer_t Timer Objects
+ *
+ * Timers are used to schedule some task to be executed at given time or
+ * after a default interval. The default interval is specified when the
+ * timer is created. We call timer activation "setting the timer", and
+ * deactivation "resetting the timer" (as in SDL). When the given time has
+ * arrived or the default interval has elapsed, the timer expires and
+ * it is ready for execution.
+ *
+ * The functions used to create, destroy, activate, and manage timers are
+ * as follows:
+ * - su_timer_create(),
+ * - su_timer_destroy(),
+ * - su_timer_set_interval(),
+ * - su_timer_set_at(),
+ * - su_timer_set(),
+ * - su_timer_set_for_ever(),
+ * - su_timer_run(),
+ * - su_timer_reset(), and
+ * - su_timer_root().
+ *
+ * @note
+ * Timers use poll() to wake up waiting thread. On Linux, the timer
+ * granularity is determined by HZ kernel parameter, which decided when the
+ * kernel was compiled. With kernel 2.4 the default granularity is 10
+ * milliseconds, and minimum duration of a timer is approximately 20
+ * milliseconds. Naturally, using RTC would give better timing results, but
+ * RTC usage above 64 Hz is privileged operation.
+ *
+ * @par
+ * On Windows, the granularity is determined by the real-time clock timer.
+ * By default, it uses the 18.78 Hz granularity. That timer can be adjusted
+ * up to 1000 Hz using Windows multimedia library.
+ *
+ * @section su_timer_usage Using Timers
+ *
+ * A timer is created by calling su_timer_create():
+ * @code
+ * timer = su_timer_create(su_root_task(root), 200);
+ * @endcode
+ * The default duration is given in milliseconds.
+ *
+ * Usually, timer wakeup function should be called at regular intervals. In
+ * such case, the timer is activated using function su_timer_set_for_ever().
+ * When the timer is activated it is given the wakeup function and pointer to
+ * context data:
+ * @code
+ * su_timer_set_for_ever(timer, timer_wakeup, args);
+ * @endcode
+ *
+ * When the interval has passed, the root event loop calls the wakeup
+ * function:
+ * @code
+ * timer_wakeup(root, timer, args);
+ * @endcode
+ *
+ * If the number of calls to callback function is important, use
+ * su_timer_run() instead. The run timer tries to compensate for missed time
+ * and invokes the callback function several times if needed. (Because the
+ * real-time clock can be adjusted or the program suspended, e.g., while
+ * debugged, the callback function can be called thousends of times in a
+ * row.) Note that while the timer tries to compensate for delays occurred
+ * before and during the callback, it cannot be used as an exact source of
+ * timing information.
+ *
+ * Timer ceases running when su_timer_reset() is called.
+ *
+ * Alternatively, the timer can be @b set for one-time event invocation.
+ * When the timer is set, it is given the wakeup function and pointer to
+ * context data. The actual duration can also be specified using
+ * su_timer_set_at(). @code su_timer_set(timer, timer_wakeup, args);
+ * @endcode
+ *
+ * When the timer expires, the root event loop calls the wakeup function:
+ * @code
+ * timer_wakeup(root, timer, args);
+ * @endcode
+ *
+ * If the timed event is not needed anymore, the timer can be reset:
+ * @code
+ * su_timer_reset(timer);
+ * @endcode
+ *
+ * If the timer is expected to be called at regular intervals, it is
+ * possible to set ro run continously with su_timer_run(). While such a
+ * continously running timer is active it @b must @b not @b be @b set using
+ * su_timer_set() or su_timer_set_at().
+ *
+ * When the timer is not needed anymore, the timer object itself should be
+ * destroyed:
+ * @code
+ * su_timer_destroy(timer);
+ * @endcode
+ */
+
+struct su_timer_s {
+ /** Pointers within red-black tree */
+ su_timer_t *sut_left, *sut_right, *sut_parent;
+ su_task_r sut_task; /**< Task reference */
+ su_time_t sut_when; /**< When timer should be waken up next time */
+ su_duration_t sut_duration; /**< Timer duration */
+ su_timer_f sut_wakeup; /**< Function to call when waken up */
+ su_timer_arg_t *sut_arg; /**< Pointer to argument data */
+ su_time_t sut_run; /**< When this timer was last waken up */
+ unsigned sut_woken; /**< Timer has waken up this many times */
+ unsigned short sut_running; /**< Timer is running */
+
+ unsigned char sut_black; /**< Black node */
+ unsigned char sut_set; /**< Timer is set (inserted in tree) */
+};
+
+enum sut_running {
+ reset = 0,
+ run_at_intervals = 1, /**< Compensate missed wakeup calls */
+ run_for_ever = 2 /**< Do not compensate */
+};
+
+#define SU_TIMER_IS_SET(sut) ((sut)->sut_set)
+
+/* Accessor macros for rbtree */
+#define LEFT(sut) ((sut)->sut_left)
+#define RIGHT(sut) ((sut)->sut_right)
+#define PARENT(sut) ((sut)->sut_parent)
+#define SET_RED(sut) ((sut)->sut_black = 0)
+#define SET_BLACK(sut) ((sut)->sut_black = 1)
+#define CMP(a, b) SU_TIME_CMP((a)->sut_when, (b)->sut_when)
+#define IS_RED(sut) ((sut) && (sut)->sut_black == 0)
+#define IS_BLACK(sut) (!(sut) || (sut)->sut_black == 1)
+#define COPY_COLOR(dst, src) ((dst)->sut_black = (src)->sut_black)
+#define INSERT(sut) ((sut)->sut_set = 1)
+#define REMOVE(sut) ((sut)->sut_set = 0, \
+ (sut)->sut_left = (sut)->sut_right = (sut)->sut_parent = NULL)
+
+RBTREE_PROTOS(static inline, timers, su_timer_t);
+
+static inline int timers_append(su_timer_t **, su_timer_t *);
+static inline void timers_remove(su_timer_t **, su_timer_t *);
+static inline su_timer_t *timers_succ(su_timer_t const *);
+static inline su_timer_t *timers_prec(su_timer_t const *);
+static inline su_timer_t *timers_first(su_timer_t const *);
+static inline su_timer_t *timers_last(su_timer_t const *);
+
+RBTREE_BODIES(static inline, timers, su_timer_t,
+ LEFT, RIGHT, PARENT,
+ IS_RED, SET_RED, IS_BLACK, SET_BLACK, COPY_COLOR,
+ CMP, INSERT, REMOVE);
+
+/** Set the timer. */
+static inline int
+su_timer_set0(su_timer_t **timers,
+ su_timer_t *t,
+ su_timer_f wakeup,
+ su_wakeup_arg_t *arg,
+ su_time_t when,
+ su_duration_t offset)
+{
+ if (SU_TIMER_IS_SET(t))
+ timers_remove(timers, t);
+
+ t->sut_wakeup = wakeup;
+ t->sut_arg = arg;
+ t->sut_when = su_time_add(when, offset);
+
+ return timers_append(timers, t);
+}
+
+/** Reset the timer. */
+static inline int
+su_timer_reset0(su_timer_t **timers,
+ su_timer_t *t)
+{
+ if (SU_TIMER_IS_SET(t))
+ timers_remove(timers, t);
+
+ t->sut_wakeup = NULL;
+ t->sut_arg = NULL;
+ t->sut_running = reset;
+
+ memset(&t->sut_run, 0, sizeof(t->sut_run));
+
+ return 0;
+}
+
+
+/**Create a timer.
+ *
+ * Allocate and initialize an instance of su_timer_t.
+ *
+ * @param task a task for root object with which the timer will be associated
+ * @param msec the default duration of the timer
+ *
+ * @return A pointer to allocated timer instance, NULL on error.
+ */
+su_timer_t *su_timer_create(su_task_r const task, su_duration_t msec)
+{
+ su_timer_t *retval;
+
+ assert(msec >= 0);
+
+ if (su_task_cmp(task, su_task_null))
+ retval = su_zalloc(NULL, sizeof(*retval));
+ else
+ retval = NULL;
+
+ if (retval) {
+ su_task_copy(retval->sut_task, task);
+ retval->sut_duration = msec;
+ }
+
+ return retval;
+}
+
+/** Destroy a timer.
+ *
+ * Deinitialize and free an instance of su_timer_t.
+ *
+ * @param t pointer to the timer object
+ */
+void su_timer_destroy(su_timer_t *t)
+{
+ if (t) {
+ su_timer_t **timers = su_task_timers(t->sut_task);
+ if (timers)
+ su_timer_reset0(timers, t);
+ su_task_deinit(t->sut_task);
+ su_free(NULL, t);
+ }
+}
+
+/** Set the timer for the given @a interval.
+ *
+ * Sets (starts) the given timer to expire after the specified duration.
+ *
+ * @param t pointer to the timer object
+ * @param wakeup pointer to the wakeup function
+ * @param arg argument given to the wakeup function
+ * @param interval duration in milliseconds before timer wakeup is called
+ *
+ * @return 0 if successful, -1 otherwise.
+ */
+int su_timer_set_interval(su_timer_t *t,
+ su_timer_f wakeup,
+ su_timer_arg_t *arg,
+ su_duration_t interval)
+{
+ char const *func = "su_timer_set_interval";
+ su_timer_t **timers;
+
+ if (t == NULL) {
+ SU_DEBUG_1(("%s(%p): %s\n", func, t, "NULL argument"));
+ return -1;
+ }
+
+ timers = su_task_timers(t->sut_task);
+ if (timers == NULL) {
+ SU_DEBUG_1(("%s(%p): %s\n", func, t, "invalid timer"));
+ return -1;
+ }
+
+ su_timer_set0(timers, t, wakeup, arg, su_now(), interval);
+
+ return 0;
+}
+
+/** Set the timer for the default interval.
+ *
+ * Sets (starts) the given timer to expire after the default duration.
+ *
+ * The timer must have an default duration.
+ *
+ * @param t pointer to the timer object
+ * @param wakeup pointer to the wakeup function
+ * @param arg argument given to the wakeup function
+ *
+ * @return 0 if successful, -1 otherwise.
+ */
+int su_timer_set(su_timer_t *t,
+ su_timer_f wakeup,
+ su_timer_arg_t *arg)
+{
+ char const *func = "su_timer_set";
+
+ if (t == NULL)
+ return -1;
+
+ assert(t->sut_duration > 0);
+ if (t->sut_duration == 0) {
+ SU_DEBUG_0(("%s(%p): %s\n", func, t, "timer without default duration"));
+ return -1;
+ }
+
+ return su_timer_set_interval(t, wakeup, arg, t->sut_duration);
+}
+
+/** Set timer at known time.
+ *
+ * Sets the timer to expire at given time.
+ *
+ * @param t pointer to the timer object
+ * @param wakeup pointer to the wakeup function
+ * @param arg argument given to the wakeup function
+ * @param when time structure defining the wakeup time
+ *
+ * @return 0 if successful, -1 otherwise.
+ */
+int su_timer_set_at(su_timer_t *t,
+ su_timer_f wakeup,
+ su_wakeup_arg_t *arg,
+ su_time_t when)
+{
+ char const *func = "su_timer_set_at";
+ su_timer_t **timers;
+
+ if (t == NULL) {
+ SU_DEBUG_1(("%s(%p): %s\n", func, t, "NULL argument"));
+ return -1;
+ }
+
+ timers = su_task_timers(t->sut_task);
+ if (timers == NULL) {
+ SU_DEBUG_1(("%s(%p): %s\n", func, t, "invalid timer"));
+ return -1;
+ }
+
+ su_timer_set0(timers, t, wakeup, arg, when, 0);
+
+ return 0;
+}
+
+/** Set the timer for regular intervals.
+ *
+ * Run the given timer continuously, call wakeup function repeately in the
+ * default interval. If a wakeup call is missed, try to make it up (in other
+ * words, this kind of timer fails miserably if time is adjusted and it
+ * should really use /proc/uptime instead of gettimeofday()).
+ *
+ * While a continously running timer is active it @b must @b not @b be @b
+ * set using su_timer_set() or su_timer_set_at().
+ *
+ * The timer must have an non-zero default interval.
+ *
+ * @param t pointer to the timer object
+ * @param wakeup pointer to the wakeup function
+ * @param arg argument given to the wakeup function
+ *
+ * @return 0 if successful, -1 otherwise.
+ */
+int su_timer_run(su_timer_t *t,
+ su_timer_f wakeup,
+ su_timer_arg_t *arg)
+{
+ char const *func = "su_timer_run";
+ su_timer_t **timers;
+ su_time_t now = su_now();
+
+ if (t == NULL) {
+ SU_DEBUG_1(("%s(%p): %s\n", func, t, "NULL argument"));
+ return -1;
+ }
+
+ assert(t->sut_duration > 0);
+ if (t->sut_duration == 0) {
+ SU_DEBUG_1(("%s(%p): %s\n", func, t, "timer without default duration"));
+ return -1;
+ }
+
+ timers = su_task_timers(t->sut_task);
+ if (timers == NULL) {
+ SU_DEBUG_1(("%s(%p): %s\n", func, t, "invalid timer"));
+ return -1;
+ }
+
+ t->sut_running = run_at_intervals;
+ t->sut_run = now;
+ t->sut_woken = 0;
+
+ su_timer_set0(timers, t, wakeup, arg, now, t->sut_duration);
+
+ return 0;
+}
+
+/**Set the timer for regular intervals.
+ *
+ * Run the given timer continuously, call wakeup function repeately in the
+ * default interval. While a continously running timer is active it @b must
+ * @b not @b be @b set using su_timer_set() or su_timer_set_at(). Unlike
+ * su_timer_run(), set for ever timer does not try to catchup missed
+ * callbacks.
+ *
+ * The timer must have an non-zero default interval.
+ *
+ * @param t pointer to the timer object
+ * @param wakeup pointer to the wakeup function
+ * @param arg argument given to the wakeup function
+ *
+ * @return 0 if successful, -1 otherwise.
+ */
+int su_timer_set_for_ever(su_timer_t *t,
+ su_timer_f wakeup,
+ su_timer_arg_t *arg)
+{
+ char const *func = "su_timer_run";
+ su_timer_t **timers;
+ su_time_t now = su_now();
+
+ if (t == NULL) {
+ SU_DEBUG_1(("%s(%p): %s\n", func, t, "NULL argument"));
+ return -1;
+ }
+
+ assert(t->sut_duration > 0);
+ if (t->sut_duration == 0) {
+ SU_DEBUG_1(("%s(%p): %s\n", func, t, "timer without default duration"));
+ return -1;
+ }
+
+ timers = su_task_timers(t->sut_task);
+ if (timers == NULL) {
+ SU_DEBUG_1(("%s(%p): %s\n", func, t, "invalid timer"));
+ return -1;
+ }
+
+ t->sut_running = run_for_ever;
+ t->sut_run = now;
+ t->sut_woken = 0;
+
+ su_timer_set0(timers, t, wakeup, arg, now, t->sut_duration);
+
+ return 0;
+}
+
+
+/**Reset the timer.
+ *
+ * Resets (stops) the given timer.
+ *
+ * @param t pointer to the timer object
+ *
+ * @return 0 if successful, -1 otherwise.
+ */
+int su_timer_reset(su_timer_t *t)
+{
+ char const *func = "su_timer_reset";
+ su_timer_t **timers;
+
+ if (t == NULL) {
+ SU_DEBUG_1(("%s(%p): %s\n", func, t, "NULL argument"));
+ return -1;
+ }
+
+ timers = su_task_timers(t->sut_task);
+
+ su_timer_reset0(timers, t);
+
+ return 0;
+}
+
+/** @internal Check for expired timers in queue.
+ *
+ * The function su_timer_expire() checks a timer queue and executes and
+ * removes expired timers from the queue. It also calculates the time when
+ * the next timer expires.
+ *
+ * @param timers pointer to the timer queue
+ * @param timeout timeout in milliseconds [IN/OUT]
+ * @param now current timestamp
+ *
+ * @return
+ * The number of expired timers.
+ */
+int su_timer_expire(su_timer_t ** const timers,
+ su_duration_t *timeout,
+ su_time_t now)
+{
+ su_timer_t *t;
+ su_timer_f f;
+ int n = 0;
+
+ if (!*timers)
+ return n;
+
+ for (;;) {
+ t = timers_first(*timers);
+
+ if (t == NULL || SU_TIME_CMP(t->sut_when, now) > 0)
+ break;
+
+ timers_remove(timers, t);
+
+ f = t->sut_wakeup; t->sut_wakeup = NULL;
+ assert(f);
+
+ if (t->sut_running == run_at_intervals) {
+ while (t->sut_running == run_at_intervals &&
+ t->sut_duration > 0) {
+ if (su_time_diff(t->sut_when, now) > 0) {
+ su_timer_set0(timers, t, f, t->sut_arg, t->sut_run, 0);
+ break;
+ }
+ t->sut_when = t->sut_run = su_time_add(t->sut_run, t->sut_duration);
+ t->sut_woken++;
+ f(su_root_magic(su_task_root(t->sut_task)), t, t->sut_arg), n++;
+ }
+ }
+ else if (t->sut_running == run_for_ever) {
+ t->sut_woken++;
+ t->sut_when = now;
+ f(su_root_magic(su_task_root(t->sut_task)), t, t->sut_arg), n++;
+ if (t->sut_running == run_for_ever)
+ su_timer_set0(timers, t, f, t->sut_arg, now, t->sut_duration);
+ }
+ else {
+ t->sut_when = now;
+ f(su_root_magic(su_task_root(t->sut_task)), t, t->sut_arg); n++;
+ }
+ }
+
+ if (t) {
+ su_duration_t at = su_duration(t->sut_when, now);
+
+ if (at < *timeout)
+ *timeout = at;
+ }
+
+ return n;
+}
+
+
+su_duration_t su_timer_next_expires(su_timer_t const * t, su_time_t now)
+{
+ su_duration_t tout;
+
+ if (!t)
+ return SU_DURATION_MAX;
+
+ tout = su_duration(t->sut_when, now);
+
+ return tout > 0 ? tout : 0 ;
+}
+
+/**
+ * Resets and frees all timers belonging to a task.
+ *
+ * The function su_timer_destroy_all() resets and frees all timers belonging
+ * to the specified task in the queue.
+ *
+ * @param timers pointer to the timers
+ * @param task task owning the timers
+ *
+ * @return Number of timers reset.
+ */
+int su_timer_reset_all(su_timer_t **timers, su_task_r task)
+{
+ su_timer_t *t, *t_next;
+ int n = 0;
+
+ if (!timers || !*timers)
+ return 0;
+
+ for (t = timers_first(*timers); t; t = t_next) {
+ t_next = timers_succ(t);
+
+ if (su_task_cmp(task, t->sut_task))
+ continue;
+
+ n++;
+ timers_remove(timers, t);
+ su_free(NULL, t);
+ }
+
+ return n;
+}
+
+/** Get the root object owning the timer.
+ *
+ * The function su_timer_root() return pointer to the root object owning the
+ * timer.
+ *
+ * @param t pointer to the timer
+ *
+ * @return Pointer to the root object owning the timer.
+ */
+su_root_t *su_timer_root(su_timer_t const *t)
+{
+ return su_task_root(t->sut_task);
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_uniqueid.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_uniqueid.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,341 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@defgroup su_uniqueid GloballyUniqueIDs
+ *
+ * Globally unique IDs and random integers.
+ *
+ * GloballyUniqueID or #su_guid_t is a 128-bit identifier based on current
+ * time and MAC address of the node generating the ID. A new ID is generated
+ * each time su_guid_generate() is called. Please note that such IDs are @b
+ * not unique if multiple processes are run on the same node.
+ *
+ * Use su_guid_sprintf() to convert #su_guid_t to printable format.
+ *
+ * The random integers can be generated with functions
+ * - su_randint(),
+ * - su_randmem(), or
+ * - su_random().
+ */
+
+/**@ingroup su_uniqueid
+ *
+ * @CFILE su_uniqueid.c Construct a GloballyUniqueID as per H.225.0 v2.
+ *
+ * @author Pekka Pessi <pessi at research.nokia.com>
+ *
+ * @date Created: Tue Apr 15 06:31:41 1997 pessi
+ */
+
+#include "config.h"
+
+#if defined(_WIN32)
+int _getpid(void);
+#define getpid _getpid
+#endif
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#if HAVE_UNISTD_H
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
+#include "sofia-sip/su.h"
+#include "sofia-sip/su_time.h"
+#include "sofia-sip/su_uniqueid.h"
+
+/* For random number generator */
+static int initialized = 0;
+
+static void init(void);
+static void init_node(void);
+
+/* Constants */
+static const unsigned version = 1; /* Current version */
+static const unsigned reserved = 128; /* DCE variant */
+#define granularity (10000000UL)
+static const uint64_t mask60 = SU_U64_C(0xfffFFFFffffFFFF);
+#define MAGIC (16384)
+
+/* 100-nanosecond intervals between 15 October 1582 and 1 January 1900 */
+static const uint64_t ntp_epoch =
+(uint64_t)(141427) * (24 * 60 * 60L) * granularity;
+
+/* State */
+static uint64_t timestamp0 = 0;
+static unsigned clock_sequence = MAGIC;
+static unsigned char node[6];
+
+FILE *urandom;
+
+/*
+ * Get current timestamp
+ */
+static uint64_t timestamp(void)
+{
+ uint64_t tl = su_ntp_now();
+ uint64_t hi = su_ntp_hi(tl), lo = su_ntp_lo(tl);
+
+ lo *= granularity;
+ hi *= granularity;
+
+ tl = hi + (lo >> 32) + ntp_epoch;
+
+#ifdef TESTING
+ printf("timestamp %08x-%08x\n", (unsigned)(tl >>32), (unsigned)tl);
+#endif
+
+ tl &= mask60;
+
+ if (tl <= timestamp0)
+ clock_sequence = (clock_sequence + 1) & (MAGIC - 1);
+
+ timestamp0 = tl;
+
+ return tl;
+}
+
+#if !HAVE_RANDOM
+#define random() rand()
+#define srandom(x) srand(x)
+#endif
+
+/*
+ * Initialize clock_sequence and timestamp0
+ */
+static void init(void)
+{
+ int i;
+
+ static uint32_t seed[32] = { 0 };
+ su_time_t now;
+
+ initialized = 1;
+
+ /* Initialize our random number generator */
+#if HAVE_DEV_URANDOM
+ if (!urandom)
+ urandom = fopen("/dev/urandom", "rb");
+#endif /* HAVE_DEV_URANDOM */
+
+ if (urandom) {
+ size_t len = fread(seed, sizeof seed, 1, urandom); (void)len;
+ }
+ else {
+ for (i = 0; i < 16; i++) {
+#if HAVE_CLOCK_GETTIME
+ struct timespec ts;
+ (void)clock_gettime(CLOCK_REALTIME, &ts);
+ seed[2*i] ^= ts.tv_sec; seed[2*i+1] ^= ts.tv_nsec;
+#endif
+ su_time(&now);
+ seed[2*i] ^= now.tv_sec; seed[2*i+1] ^= now.tv_sec;
+ }
+
+ seed[30] ^= getuid();
+ seed[31] ^= getpid();
+ }
+
+#if HAVE_INITSTATE
+ initstate(seed[0] ^ seed[1], (char *)&seed, sizeof(seed));
+#else
+ srand(seed[0] ^ seed[1]);
+#endif
+
+ clock_sequence = su_randint(0, MAGIC - 1);
+
+ (void)timestamp();
+
+ init_node();
+}
+
+#if HAVE_GETIFADDRS
+#include <ifaddrs.h>
+#if HAVE_NETPACKET_PACKET_H
+#define HAVE_SOCKADDR_LL 1
+#include <netpacket/packet.h>
+#include <net/if_arp.h>
+#endif
+#endif
+
+static
+void init_node(void)
+{
+ size_t i;
+
+#if HAVE_GETIFADDRS && HAVE_SOCKADDR_LL
+ struct ifaddrs *ifa, *results;
+
+ if (getifaddrs(&results) == 0) {
+ for (ifa = results; ifa; ifa = ifa->ifa_next) {
+#if HAVE_SOCKADDR_LL
+ struct sockaddr_ll const *sll = (void *)ifa->ifa_addr;
+
+ if (sll == NULL || sll->sll_family != AF_PACKET)
+ continue;
+ switch (sll->sll_hatype) {
+ case ARPHRD_ETHER:
+ case ARPHRD_EETHER:
+ case ARPHRD_IEEE802:
+ break;
+ default:
+ continue;
+ }
+
+ memcpy(node, sll->sll_addr, sizeof node);
+
+ break;
+#endif
+ }
+
+ freeifaddrs(results);
+
+ if (ifa)
+ return; /* Success */
+ }
+#endif
+
+ if (urandom) {
+ size_t len = fread(node, sizeof node, 1, urandom); (void)len;
+ }
+ else for (i = 0; i < sizeof(node); i++) {
+ unsigned r = random();
+ node[i] = (r >> 24) ^ (r >> 16) ^ (r >> 8) ^ r;
+ }
+
+ node[0] |= 1; /* "multicast" address */
+}
+
+size_t su_node_identifier(void *address, size_t addrlen)
+{
+ if (addrlen > sizeof node)
+ addrlen = sizeof node;
+
+ if (!initialized) init();
+
+ memcpy(address, node, addrlen);
+
+ return addrlen;
+}
+
+void su_guid_generate(su_guid_t *v)
+{
+ uint64_t time;
+ unsigned clock;
+
+ if (!initialized) init();
+
+ time = timestamp();
+ clock = clock_sequence;
+
+ v->s.time_high_and_version =
+ htons((unsigned short)(((time >> 48) & 0x0fff) | (version << 12)));
+ v->s.time_mid = htons((unsigned short)((time >> 32) & 0xffff));
+ v->s.time_low = htonl((unsigned long)(time & 0xffffffffUL));
+ v->s.clock_seq_low = clock & 0xff;
+ v->s.clock_seq_hi_and_reserved = (clock >> 8) | reserved;
+ memcpy(v->s.node, node, sizeof(v->s.node));
+}
+
+/*
+ * Human-readable form of GloballyUniqueID
+ */
+isize_t su_guid_sprintf(char* buf, size_t len, su_guid_t const *v)
+{
+ char mybuf[su_guid_strlen + 1];
+ sprintf(mybuf, "%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ (unsigned long)ntohl(v->s.time_low),
+ ntohs(v->s.time_mid),
+ ntohs(v->s.time_high_and_version),
+ v->s.clock_seq_low,
+ v->s.clock_seq_hi_and_reserved,
+ v->s.node[0], v->s.node[1], v->s.node[2],
+ v->s.node[3], v->s.node[4], v->s.node[5]);
+ memcpy(buf, mybuf, len > sizeof(mybuf) ? sizeof(mybuf) : len);
+ return su_guid_strlen;
+}
+
+/*
+ * Generate random integer in range [lb, ub] (inclusive)
+ */
+int su_randint(int lb, int ub)
+{
+ unsigned rnd = 0;
+
+ if (!initialized) init();
+
+ if (urandom) {
+ size_t len = fread(&rnd, 1, sizeof rnd, urandom); (void)len;
+ }
+ else
+ rnd = random();
+
+ if (ub - lb + 1 != 0)
+ rnd %= (ub - lb + 1);
+
+ return rnd + lb;
+}
+
+void *su_randmem(void *mem, size_t siz)
+{
+ size_t i;
+
+ if (!initialized) init();
+
+ if (urandom) {
+ size_t len = fread(mem, 1, siz, urandom); (void)len;
+ }
+ else for (i = 0; i < siz; i++) {
+ unsigned r = random();
+ ((char *)mem)[i] = (r >> 24) ^ (r >> 16) ^ (r >> 8) ^ r;
+ }
+
+ return mem;
+}
+
+/** Get random number for RTP timestamps.
+ *
+ * This function returns a 32-bit random integer. It also initializes the
+ * random number generator, if needed.
+ */
+uint32_t su_random(void)
+{
+ if (!initialized) init();
+
+ if (urandom) {
+ uint32_t rnd;
+ size_t len = fread(&rnd, 1, sizeof rnd, urandom); (void)len;
+ return rnd;
+ }
+
+ return (uint32_t)random();
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_vector.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_vector.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,322 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@defgroup su_vector Vectors
+ *
+ * Pointer vectors.
+ *
+ * Unidimensional arrays using #su_home_t.
+ *
+ */
+
+/**@ingroup su_vector
+ * @CFILE su_vector.c
+ * @brief Simple pointer vectors
+ *
+ * The vectors are resizeable unidimensional arrays.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Fri Sep 27 14:43:29 2002 ppessi
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <memory.h>
+#include <limits.h>
+#include <string.h>
+
+#include <assert.h>
+
+#include "sofia-sip/su_config.h"
+#include "sofia-sip/su_vector.h"
+
+enum { N = 8 };
+
+struct su_vector_s
+{
+ su_home_t v_home[1];
+ su_home_t *v_parent;
+ size_t v_size;
+ size_t v_len;
+ su_free_func_t v_free_func;
+ void **v_list;
+};
+
+/** Create a vector.
+ *
+ * The function su_vector_create() creates a pointer vector object. The
+ * vector is initially empty. The function clones a memory home for the
+ * vector object from @a home. If a @a free_func is provided then that
+ * will be used to free the individual nodes (NULL if not used).
+ */
+su_vector_t *su_vector_create(su_home_t *home, su_free_func_t free_func)
+{
+ su_vector_t *vector;
+
+ vector = su_home_clone(home, sizeof(*vector) + N * sizeof(*vector->v_list));
+ if (vector) {
+ vector->v_parent = home;
+ vector->v_size = N;
+ vector->v_free_func = free_func;
+ vector->v_list = (void **)(vector + 1);
+ }
+ return vector;
+}
+
+/** Destroy a vector.
+ *
+ * The function su_vector_destroy() destroys a vector and frees all
+ * its nodes if a freeing function is available
+ */
+void su_vector_destroy(su_vector_t *vector)
+{
+ size_t i;
+
+ if (vector) {
+ if (vector->v_free_func != NULL) {
+ for (i = 0; i < vector->v_len; i++) {
+ (vector->v_free_func)(vector->v_list[i]);
+ }
+ }
+
+ su_home_zap(vector->v_home);
+ }
+}
+
+/** Increase the list size for next item, if necessary. */
+static int su_vector_make_place(su_vector_t *vector, usize_t index)
+{
+ if (vector->v_size <= vector->v_len + 1) {
+ size_t newsize = 2 * vector->v_size * sizeof(vector->v_list[0]);
+ void **list;
+
+ if (newsize < vector->v_size * sizeof(vector->v_list[0])) /* overflow */
+ return -1;
+
+ if (vector->v_list != (void **)(vector + 1) && index == vector->v_len) {
+ if (!(list = su_realloc(vector->v_home, vector->v_list, newsize)))
+ return 0;
+ }
+ else {
+ if (!(list = su_alloc(vector->v_home, newsize)))
+ return 0;
+
+ memcpy(list, vector->v_list, index * sizeof(vector->v_list[0]));
+ memcpy(list + index + 1, vector->v_list + index,
+ (vector->v_len - index) * sizeof(vector->v_list[0]));
+
+ if (vector->v_list != (void **)(vector + 1)) {
+ su_free(vector->v_home, vector->v_list);
+ }
+ }
+
+ vector->v_list = list;
+ vector->v_size *= 2;
+ }
+ else {
+ memmove(vector->v_list + index + 1, vector->v_list + index,
+ (vector->v_len - index) * sizeof(vector->v_list[0]));
+ }
+
+ vector->v_len++;
+
+ return 1;
+}
+
+/**Insert an item to vector.
+ *
+ * The function su_vector_insert() inserts an @a item to the @a vector.
+ * The items after the @a index will be moved further within the vector.
+ *
+ * @param vector pointer to a vector object
+ * @param item item to be appended
+ * @param index index for the new item
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error
+ */
+int su_vector_insert(su_vector_t *vector, usize_t index, void *item)
+{
+ if (vector &&
+ index <= vector->v_len &&
+ su_vector_make_place(vector, index) > 0) {
+ vector->v_list[index] = item;
+ return 0;
+ }
+ return -1;
+}
+
+/**Remove an item from vector.
+ *
+ * The function su_vector_remove() removes an item from the @a vector.
+ * The items after the @a index will be moved backwards within the vector.
+ *
+ * @param vector pointer to a vector object
+ * @param index index for the removed item
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error
+ */
+int su_vector_remove(su_vector_t *vector, usize_t index)
+{
+ if (vector && index < vector->v_len) {
+ if (vector->v_free_func)
+ (vector->v_free_func)(vector->v_list[index]);
+
+ memmove(vector->v_list + index,
+ vector->v_list + index + 1,
+ (vector->v_len - index - 1) * sizeof(vector->v_list[0]));
+ vector->v_len--;
+ return 0;
+ }
+
+ return -1;
+}
+
+/**Remove all items from vector.
+ *
+ * The function su_vector_empty() removes all items from the @a vector.
+ *
+ * @param vector pointer to a vector object
+ *
+ * @retval 0 if successful
+ * @retval -1 upon an error
+ */
+int su_vector_empty(su_vector_t *vector)
+{
+ size_t i;
+
+ if (vector) {
+ if (vector->v_free_func != NULL) {
+ for (i = 0; i < vector->v_len; i++) {
+ (vector->v_free_func)(vector->v_list[i]);
+ }
+ }
+
+ vector->v_len = 0;
+ return 0;
+ }
+
+ return -1;
+}
+
+/**Append an item to vector.
+ *
+ * The function su_vector_append() appends an @a item to the @a vector.
+ *
+ * @param vector pointer to a vector object
+ * @param item item to be appended
+ *
+ * @retval 0 if successful
+ * @retval -1 upon an error
+ */
+int su_vector_append(su_vector_t *vector, void *item)
+{
+ size_t index = vector->v_len;
+
+ if (vector && su_vector_make_place(vector, index)) {
+ vector->v_list[index] = item;
+ return 0;
+ }
+ return -1;
+}
+
+/**Get a numbered item from list.
+ *
+ * The function su_vector_item() returns a numbered item from vector. The
+ * numbering starts from 0.
+ *
+ * @param vector pointer to a vector object
+ * @param i index
+ *
+ * @return
+ * Pointer, if item exists, or NULL upon an error.
+ */
+void *su_vector_item(su_vector_t const *vector, usize_t i)
+{
+ if (vector && i < vector->v_len)
+ return vector->v_list[i];
+ else
+ return NULL;
+}
+
+/** Get number of items in list.
+ *
+ * The function su_vector_len() returns the number of items in the
+ * vector.
+ */
+usize_t su_vector_len(su_vector_t const *l)
+{
+ return l ? l->v_len : 0;
+}
+
+int su_vector_is_empty(su_vector_t const *vector)
+{
+ return su_vector_len(vector) == 0;
+}
+
+/**Get a pointer array from list.
+ *
+ * The function su_vector_get_array() returns an array of pointer. The
+ * length of the array is always one longer than the length of the vector,
+ * and the last item in the returned array is always NULL.
+ *
+ * @param vector pointer to a vector object
+ *
+ * @return
+ * Pointer to array, or NULL if error occurred.
+ */
+void **su_vector_get_array(su_vector_t *vector)
+{
+ if (vector) {
+ void **retval;
+ size_t newsize = sizeof(retval[0]) * (vector->v_len + 1);
+
+ retval = su_alloc(vector->v_home, newsize);
+
+ if (retval) {
+ retval[vector->v_len] = NULL;
+ return memcpy(retval, vector->v_list, sizeof(retval[0]) * vector->v_len);
+ }
+ }
+
+ return NULL;
+}
+
+/**Free a string array.
+ *
+ * The function su_vector_free_array() discards a string array allocated
+ * with su_vector_get_array().
+ *
+ * @param vector pointer to a vector object
+ * @param array string array to be freed
+ *
+ */
+void su_vector_free_array(su_vector_t *vector, void **array)
+{
+ su_free(vector->v_home, array);
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_wait.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_wait.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,313 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_wait
+ *
+ * @CFILE su_wait.c
+ * Implementation of OS-independent socket synchronization interface.
+ *
+ * This looks like nth reincarnation of "reactor". It implements the
+ * (poll()/select()/WaitForMultipleObjects()) functionality.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @date Created: Tue Sep 14 15:51:04 1999 ppessi
+ *
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+
+#define SU_INTERNAL_P su_root_t *
+
+#include "sofia-sip/su.h"
+#include "sofia-sip/su_wait.h"
+#include "sofia-sip/su_alloc.h"
+
+/**@defgroup su_wait Syncronization and Threading
+ * @brief Syncronization and threading interface.
+ *
+ * The Sofia utility library provides simple OS-independent synchronization
+ * interface. The synchronization interface contains primitives for managing
+ * events, messages, timers and threads.
+ *
+ */
+
+/**@ingroup su_wait
+ * @defgroup su_root_ex Example and test code for syncronization and threads
+ *
+ * Example programs demonstrate the su syncronization and threading
+ * primitives.
+ */
+
+
+/**@ingroup su_wait
+ *
+ * @page su_wait_t Wait objects
+ *
+ * Wait objects are used to signal I/O events to the process.
+ * The events are as follows:
+ *
+ * - SU_WAIT_IN - incoming data is available on socket
+ * - SU_WAIT_OUT - data can be sent on socket
+ * - SU_WAIT_ERR - an error occurred on socket
+ * - SU_WAIT_HUP - the socket connection was closed
+ * - SU_WAIT_ACCEPT - a listening socket accepted a new connection attempt
+ *
+ * It is possible to combine several events with |, binary or operator.
+ *
+ * The wait objects can be managed with functions as follows:
+ * - su_wait_create()
+ * - su_wait_destroy()
+ * - su_wait()
+ * - su_wait_events()
+ * - su_wait_mask()
+ *
+ * @note
+ * In Unix, the wait object is @c struct @c poll. The structure contains a
+ * file descriptor, a mask describing expected events, and a mask
+ * containing the occurred events after calling @c su_wait(), ie. poll().
+ *
+ * @note
+ * In Windows, the wait object is a @c HANDLE (a descriptor of a Windows
+ * kernel entity).
+ *
+ */
+
+/**Initialize a wait object.
+ *
+ * The function su_wait_init initializes a memory area of a su_wait_t
+ * object.
+ */
+void su_wait_init(su_wait_t dst[1])
+{
+ su_wait_t const src = SU_WAIT_INIT;
+ *dst = src;
+}
+
+/**Create a wait object.
+ *
+ * The function su_wait_create() creates a new su_wait_t object for an @a
+ * socket, with given @a events. The new wait object is assigned to the @a
+ * newwait parameter.
+ *
+ * There can be only one wait object per socket. (This is a limitation or
+ * feature of WinSock interface; the limitation is not enforced on other
+ * platforms).
+ *
+ * As a side-effect the socket is put into non-blocking mode when wait
+ * object is created.
+ *
+ * @param newwait the newly created wait object (output)
+ * @param socket socket
+ * @param events mask for events that can signal this wait object
+ *
+ * @retval 0 if the call was successful,
+ * @retval -1 upon an error.
+*/
+int su_wait_create(su_wait_t *newwait, su_socket_t socket, int events)
+{
+#if SU_HAVE_WINSOCK
+ HANDLE h = WSACreateEvent();
+
+ if (newwait == NULL || events == 0 || socket == INVALID_SOCKET) {
+ su_seterrno(WSAEINVAL);
+ return -1;
+ }
+
+ *newwait = 0;
+
+ if (WSAEventSelect(socket, h, events) != 0) {
+ int error = su_errno();
+ WSACloseEvent(h);
+ su_seterrno(error);
+ return -1;
+ }
+
+ *newwait = h;
+
+#elif SU_HAVE_POLL
+ int mode;
+
+ if (newwait == NULL || events == 0 || socket == INVALID_SOCKET) {
+ su_seterrno(EINVAL);
+ return -1;
+ }
+
+ mode = fcntl(socket, F_GETFL, 0);
+ if (mode < 0)
+ return -1;
+ mode |= O_NDELAY | O_NONBLOCK;
+ if (fcntl(socket, F_SETFL, mode) < 0)
+ return -1;
+
+ newwait->fd = socket;
+ newwait->events = events;
+ newwait->revents = 0;
+#endif
+
+ return 0;
+}
+
+/** Destroy a wait object.
+ *
+ * The function su_wait_destroy() destroys a su_wait_t object.
+ *
+ * @param waitobj pointer to wait object
+ *
+ * @retval 0 when successful,
+ * @retval -1 upon an error.
+ */
+int su_wait_destroy(su_wait_t *waitobj)
+{
+#if SU_HAVE_WINSOCK
+ su_wait_t w0 = NULL;
+ if (*waitobj)
+ WSACloseEvent(*waitobj);
+#elif SU_HAVE_POLL
+ su_wait_t w0 = { INVALID_SOCKET, 0, 0 };
+#endif
+ assert(waitobj != NULL);
+ *waitobj = w0;
+
+ return waitobj ? 0 : -1;
+}
+
+/**Wait for multiple events.
+ *
+ * The function su_wait() blocks until an event specified by wait objects in
+ * @a wait array. If @a timeout is not SU_WAIT_FOREVER, a timeout occurs
+ * after @a timeout milliseconds.
+ *
+ * In Unix, this is @c poll() or @c select().
+ *
+ * In Windows, this is @c WSAWaitForMultipleEvents().
+ *
+ * @param waits array of wait objects
+ * @param n number of wait objects in array waits
+ * @param timeout timeout in milliseconds
+ *
+ * @retval Index of the signaled wait object, if any,
+ * @retval SU_WAIT_TIMEOUT if timeout occurred, or
+ * @retval -1 upon an error.
+ */
+int su_wait(su_wait_t waits[], unsigned n, su_duration_t timeout)
+{
+#if SU_HAVE_WINSOCK
+ DWORD i;
+
+ if (n > 0)
+ i = WSAWaitForMultipleEvents(n, waits, FALSE, timeout, FALSE);
+ else
+ return Sleep(timeout), SU_WAIT_TIMEOUT;
+
+ if (i == WSA_WAIT_TIMEOUT)
+ return SU_WAIT_TIMEOUT;
+ else if (i == WSA_WAIT_FAILED)
+ return SOCKET_ERROR;
+ else
+ return i;
+
+#elif SU_HAVE_POLL
+ for (;;) {
+ int i = poll(waits, n, timeout);
+
+ if (i == 0)
+ return SU_WAIT_TIMEOUT;
+
+ if (i > 0) {
+ unsigned j;
+ for (j = 0; j < n; j++) {
+ if (waits[j].revents)
+ return j;
+ }
+ }
+
+ if (errno == EINTR)
+ continue;
+
+ return -1;
+ }
+#endif
+}
+
+/** Get events.
+ *
+ * The function su_wait_events() returns an mask describing events occurred.
+ *
+ * @param waitobj pointer to wait object
+ * @param s socket
+ *
+ * @return Binary mask describing the events.
+ */
+int su_wait_events(su_wait_t *waitobj, su_socket_t s)
+{
+#if SU_HAVE_WINSOCK
+ WSANETWORKEVENTS net_events;
+
+ if (WSAEnumNetworkEvents(s, *waitobj, &net_events) != 0)
+ return SOCKET_ERROR;
+
+ return net_events.lNetworkEvents;
+
+#elif SU_HAVE_POLL
+ /* poll(e, 1, 0); */
+ return waitobj->revents;
+#endif
+}
+
+/** Set event mask.
+ *
+ * The function su_wait_mask() sets the mask describing events that can
+ * signal the wait object.
+ *
+ * @param waitobj pointer to wait object
+ * @param s socket
+ * @param events new event mask
+ *
+ * @retval 0 when successful,
+ * @retval -1 upon an error.
+ */
+int su_wait_mask(su_wait_t *waitobj, su_socket_t s, int events)
+{
+#if SU_HAVE_WINSOCK
+ HANDLE e = *waitobj;
+
+ if (WSAEventSelect(s, e, events) != 0) {
+ int error = WSAGetLastError();
+ WSACloseEvent(e);
+ WSASetLastError(error);
+ return -1;
+ }
+#elif SU_HAVE_POLL
+ waitobj->fd = s;
+ waitobj->events = events;
+ waitobj->revents = 0;
+#endif
+
+ return 0;
+}
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/tag_dll.awk
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/tag_dll.awk Thu Dec 21 01:30:28 2006
@@ -0,0 +1,174 @@
+#! /usr/bin/env awk
+#
+# Create reference tags and WIN32 initialization functions for tags.
+#
+# --------------------------------------------------------------------
+#
+# This file is part of the Sofia-SIP package
+#
+# Copyright (C) 2005 Nokia Corporation.
+#
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+#
+# --------------------------------------------------------------------
+#
+# Author: Pekka Pessi <Pekka.Pessi at nokia.com>
+#
+# Created: Tue Feb 26 14:11:25 2002 ppessi
+#
+
+BEGIN {
+ DEFS = 0;
+ HEADER = 1;
+}
+
+HEADER {
+ HEADER = 0;
+
+ if (OUTNAME != "") {
+ fn = OUTNAME;
+ } else {
+ fn = FILENAME;
+ }
+
+ DLL = fn;
+ sub(/[.]c(at)?/, "_dll.c", DLL);
+
+ if (NODLL) DLL = "/dev/null";
+
+ base = fn;
+ sub(/.*\//, "", base);
+
+ printf("#ifdef _WIN32\n"\
+ "/*\n" \
+ " * PLEASE NOTE: \n" \
+ " * \n" \
+ " * This file is automatically generated by tag_dll.awk.\n"\
+ " * It contains magic required by Win32 DLLs to initialize\n"\
+ " * tag_typedef_t variables.\n"\
+ " * \n"\
+ " * Do not, repeat, do not edit this file. Edit '%s' instead.\n"\
+ " * \n"\
+ " */\n\n"\
+ "#define EXPORT __declspec(dllexport)\n\n", base) > DLL;
+
+ if (DLLREF) {
+ print \
+ "#include \"config.h\"\n\n" \
+ "#include <sofia-sip/su_tag_class.h>\n\n" > DLL;
+ }
+
+ REF = fn;
+ sub(/[.]c(at)?/, "_ref.c", REF);
+
+ printf("/*\n" \
+ " * PLEASE NOTE: \n" \
+ " * \n" \
+ " * This file is automatically generated by tag_dll.awk.\n"\
+ " * It contains tag_typedef_t for tag references.\n"\
+ " * \n"\
+ " * Do not, repeat, do not edit this file. Edit '%s' instead.\n"\
+ " * \n"\
+ " */\n\n"\
+ "#include \"config.h\"\n\n"\
+ "#include <sofia-sip/su_tag_class.h>\n"\
+ "\n"\
+ "#ifdef _WIN32\n"\
+ "#define EXPORT __declspec(dllexport)\n"\
+ "#else\n"\
+ "#define EXPORT\n"\
+ "#endif\n\n",
+ base) > REF;
+
+ if (LIST) {
+ print "#include <stddef.h>" >REF;
+ }
+ print "" > REF;
+}
+
+/^#define TAG_NAMESPACE/ {
+ print "#undef TAG_NAMESPACE" > REF;
+ print $0 > REF;
+ print "" > REF;
+ print "#undef TAG_NAMESPACE" > DLL;
+ print $0 > DLL;
+ print "" > DLL;
+}
+
+!DEFS && /^tag_typedef_t/ { DEFS = 1; }
+
+DEFS && /tag_typedef_t/ {
+ tag = $2;
+ typedefs[tag] = $0;
+
+ if ($0 !~ /NSTAG_TYPEDEF/) {
+ print "extern tag_typedef_t "tag";" > REF;
+ print "EXPORT tag_typedef_t "tag"_ref;" > DLL;
+ print "EXPORT tag_typedef_t "tag"_ref = \n REFTAG_TYPEDEF("tag");" > REF;
+ }
+
+ gsub(/ = .*$/, ";");
+}
+
+!DLLREF { print $0 > DLL; }
+
+END {
+ if (LIST) {
+ print "\nEXPORT tag_type_t " LIST "[] =\n{" > REF;
+ print "\nEXPORT tag_type_t " LIST "[] =\n{" > DLL;
+ for (tag in typedefs) {
+ if (typedefs[tag] !~ /NSTAG_TYPEDEF/) {
+ print " " tag "," > REF;
+ print " " tag "," > DLL;
+ }
+ }
+ print " NULL\n};" > REF;
+ print " NULL\n};" > DLL;
+ }
+
+ printf("\n" \
+ "#include <windows.h>\n"\
+ "\n"\
+ "BOOL WINAPI DllMain(HINSTANCE hInst, DWORD fwdReason, LPVOID fImpLoad)\n"\
+ "{\n") > DLL;
+
+ for (tag in typedefs) {
+ def = typedefs[tag];
+ if (!DLLREF) {
+ sub(/^tag_typedef_t /, " tag_typedef_t _", def);
+ print def > DLL;
+ }
+ else {
+ print " extern tag_typedef_t "tag";" > DLL;
+ }
+ print " tag_typedef_t _"tag"_ref =\n REFTAG_TYPEDEF("tag");" > DLL;
+ }
+
+ print "" > DLL;
+
+ for (tag in typedefs) {
+ if (!DLLREF) {
+ print " *(struct tag_type_s *)" tag " = *_" tag ";" > DLL;
+ }
+ print " *(struct tag_type_s *)" tag "_ref = *_" tag "_ref;" > DLL;
+ }
+
+ print "\n return TRUE;" > DLL;
+ print "}" > DLL;
+ print "\n#endif" > DLL;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/test_htable.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/test_htable.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,247 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_htable
+ *
+ * @CFILE test_htable.c
+ *
+ * Test functions for the @b su library hash table implementation.
+ *
+ * @internal
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Aug 21 15:18:26 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include "sofia-sip/su_alloc.h"
+#include "sofia-sip/htable.h"
+
+#define TSTFLAGS flags
+#include <sofia-sip/tstdef.h>
+
+char const name[] = "htable_test";
+
+void usage(void)
+{
+ fprintf(stderr, "usage: %s [-v|--verbatim]\n", name);
+ exit(2);
+}
+
+static int table_test(int flags);
+
+int main(int argc, char *argv[])
+{
+ int flags = 0;
+
+ int retval = 0;
+ int i;
+
+ for (i = 1; argv[i]; i++) {
+ if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--verbatim") == 0)
+ flags |= tst_verbatim;
+ else
+ usage();
+ }
+
+ retval |= table_test(flags); fflush(stdout);
+
+ return retval;
+}
+
+typedef struct hentry_s entry_t;
+HTABLE_DECLARE(htable, ht, entry_t);
+HTABLE_PROTOS(htable, ht, entry_t);
+
+struct hentry_s
+{
+ unsigned long e_value;
+ unsigned long e_n;
+};
+
+#define HENTRY_HASH(e) ((e)->e_value)
+
+HTABLE_BODIES(htable, ht, entry_t, HENTRY_HASH);
+
+typedef struct context_s
+{
+ su_home_t c_home[1];
+ htable_t c_hash[1];
+} context_t;
+
+context_t *context_create(void)
+{
+ context_t *c = su_home_clone(NULL, sizeof(*c));
+
+ if (c)
+ htable_resize(c->c_home, c->c_hash, 0);
+
+ return c;
+}
+
+static
+entry_t *search(context_t *c, unsigned long value, unsigned long n, int add)
+{
+ htable_t *ht = c->c_hash;
+ entry_t *e, **ee;
+ unsigned long hash = value;
+
+ /* Search for entry in hash table */
+ for (ee = htable_hash(ht, hash);
+ (e = *ee);
+ ee = htable_next(ht, ee)) {
+ if (e->e_value == value &&
+ e->e_n == n)
+ return e;
+ }
+
+ if (add) {
+ /* Resize hash table */
+ if (htable_is_full(ht)) {
+ htable_resize(c->c_home, ht, 0);
+ fprintf(stderr, "htable: resized to %u with %u entries\n",
+ ht->ht_size, ht->ht_used);
+ }
+
+ /* Add an entry */
+ e = su_zalloc(c->c_home, sizeof(*e)); assert(e);
+ e->e_value = value, e->e_n = n;
+
+ htable_append(ht, e);
+ }
+
+ return e;
+}
+
+static int add(context_t *c, unsigned long value, unsigned long n)
+{
+ return search(c, value, n, 1) != NULL;
+}
+
+static
+void zap(context_t *c, entry_t *e)
+{
+ htable_remove(c->c_hash, e);
+ su_free(c->c_home, e);
+}
+
+static unsigned long count(context_t *c, hash_value_t h)
+{
+ entry_t *e, **ee;
+ unsigned long n;
+
+ for (ee = htable_hash(c->c_hash, h), n = 0;
+ (e = *ee);
+ ee = htable_next(c->c_hash, ee)) {
+ if (e->e_value != h)
+ continue;
+ if (e->e_n == n)
+ n++;
+ }
+
+ return n;
+}
+
+int table_test(int flags)
+{
+ context_t *c;
+ entry_t *e;
+
+ BEGIN();
+
+ TEST0(c = context_create());
+ TEST0(add(c, 0, 1)); TEST0(c->c_hash->ht_table[0]);
+ TEST0(add(c, 1, 2)); TEST0(c->c_hash->ht_table[1]);
+ TEST0(add(c, 2, 3)); TEST0(c->c_hash->ht_table[2]);
+ TEST0(add(c, 0, 4)); TEST0(c->c_hash->ht_table[3]);
+ TEST0(add(c, 2, 5)); TEST0(c->c_hash->ht_table[4]);
+
+ TEST0(e = search(c, 1, 2, 0));
+ zap(c, e);
+ TEST0(c->c_hash->ht_table[0]);
+ TEST0(c->c_hash->ht_table[1]);
+ TEST0(c->c_hash->ht_table[2]);
+ TEST0(c->c_hash->ht_table[3]);
+ TEST0(c->c_hash->ht_table[4] == NULL);
+
+ zap(c, c->c_hash->ht_table[0]);
+
+ TEST0(c->c_hash->ht_table[0]);
+ TEST0(c->c_hash->ht_table[1] == NULL);
+ TEST0(c->c_hash->ht_table[2]);
+ TEST0(c->c_hash->ht_table[3]);
+ TEST0(c->c_hash->ht_table[4] == NULL);
+
+ TEST0(add(c, 0, 6)); TEST0(c->c_hash->ht_table[1]);
+ TEST0(add(c, 1, 7)); TEST0(c->c_hash->ht_table[4]);
+
+ /* Test that zapping entry 0 does not move 2 and 3 */
+ zap(c, c->c_hash->ht_table[0]);
+ TEST0(c->c_hash->ht_table[4] == NULL);
+
+ {
+ /* Insert entries at the end of hash, then resize and check
+ for correct ordering */
+ hash_value_t size = c->c_hash->ht_size, h = size - 1;
+
+ TEST0(add(c, h, 0)); TEST0(add(c, h, 1)); TEST0(add(c, h, 2));
+ TEST0(add(c, h, 3)); TEST0(add(c, h, 4)); TEST0(add(c, h, 5));
+ TEST0(add(c, h, 6)); TEST0(add(c, h, 7)); TEST0(add(c, h, 8));
+
+ TEST(count(c, h), 9);
+
+ TEST(htable_resize(c->c_home, c->c_hash, ++size), 0);
+ TEST(count(c, h), 9);
+ TEST(htable_resize(c->c_home, c->c_hash, ++size), 0);
+ TEST(count(c, h), 9);
+ TEST(htable_resize(c->c_home, c->c_hash, ++size), 0);
+ TEST(count(c, h), 9);
+ TEST(htable_resize(c->c_home, c->c_hash, ++size), 0);
+ TEST(count(c, h), 9);
+ TEST(htable_resize(c->c_home, c->c_hash, ++size), 0);
+ TEST(count(c, h), 9);
+ TEST(htable_resize(c->c_home, c->c_hash, ++size), 0);
+ TEST(count(c, h), 9);
+ TEST(htable_resize(c->c_home, c->c_hash, ++size), 0);
+ TEST(count(c, h), 9);
+ TEST(htable_resize(c->c_home, c->c_hash, ++size), 0);
+ TEST(count(c, h), 9);
+ TEST(htable_resize(c->c_home, c->c_hash, ++size), 0);
+ TEST(count(c, h), 9);
+ }
+
+ TEST_VOID(su_home_unref(c->c_home));
+
+ END();
+}
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/test_memmem.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/test_memmem.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,239 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup test_memmem
+ *
+ * @CFILE test_memmem.c
+ *
+ * Torture tests for memmem() and strcasestr().
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Aug 21 15:18:26 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <stdio.h>
+#include <assert.h>
+
+#if !HAVE_MEMMEM
+void *memmem(const void *haystack, size_t haystacklen,
+ const void *needle, size_t needlelen);
+#endif
+#if !HAVE_STRCASESTR
+char *strcasestr(const char *haystack, const char *needle);
+#endif
+
+#include <string.h>
+
+static int test_flags = 0;
+#define TSTFLAGS test_flags
+
+#include <sofia-sip/tstdef.h>
+
+char const name[] = "test_memmem";
+
+void usage(void)
+{
+ fprintf(stderr, "usage: %s [-v]\n", name);
+}
+
+static int test_notfound(void);
+static int test_pattern(void);
+
+char const *null = NULL;
+
+static int test_notfound(void)
+{
+ char const haystack[] = "abcabcabcabc";
+ char const needle[] = "cab";
+ char const *a;
+ BEGIN();
+
+ TEST_P(memmem(haystack, 12, needle, 3), haystack + 2);
+ TEST_P(memmem(needle, 3, haystack, 12), NULL);
+ TEST_P(memmem(haystack, 12, "", 0), haystack);
+ TEST_P(memmem(haystack, 12, null, 0), haystack);
+ TEST_P(memmem(haystack, 0, "", 0), haystack);
+ TEST_P(memmem(haystack, 0, null, 0), haystack);
+
+ TEST_P(memmem(haystack + 2, 3, needle, 3), haystack + 2);
+ TEST_P(memmem(haystack + 2, 2, needle, 3), NULL);
+ TEST_P(memmem(a = "a\0bc", 4, "a\0bc", 4), a);
+
+ END();
+}
+
+static int test_pattern(void)
+{
+ BEGIN();
+ END();
+}
+
+int test_strcasestr(void)
+{
+ BEGIN();
+
+ {
+ char const hs[] =
+ "A case-folding string searching test consisting of a Long String";
+ char const *s;
+
+ s = strcasestr(hs, "sting");
+ TEST_S(s, hs + 42);
+
+ s = strcasestr(hs, "String");
+ TEST_S(s, hs + 15);
+
+ s = strcasestr(hs, "S");
+ TEST_S(s, hs + 4);
+
+ s = strcasestr(hs, "L");
+ TEST_S(s, hs + 9);
+
+ s = strcasestr(hs, "trings");
+ TEST_1(s == NULL);
+
+ s = strcasestr(hs, "String");
+ TEST_S(s, hs + 15);
+
+ s = strcasestr(hs, "StRiNg");
+ TEST_S(s, hs + 15);
+
+ s = strcasestr(hs, "OnG");
+ TEST_S(s, hs + 54);
+
+ /* Special cases */
+ TEST_1(strcasestr(hs, "") == hs);
+ TEST_1(strcasestr("", "ong") == NULL);
+ TEST_1(strcasestr("", "OnG") == NULL);
+ TEST_1(strcasestr("ong", hs) == NULL);
+ TEST_1(strcasestr("OnG", hs) == NULL);
+ TEST_1(strcasestr(hs, "Z") == NULL);
+ TEST_1(strcasestr(hs, "z") == NULL);
+ }
+
+ {
+ char const hs[] =
+"A case-folding string searching test consisting of a Very Long String\n"
+
+"Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Integer felis. "
+"Suspendisse potenti. Morbi malesuada erat eget enim. Sed dui lorem, aliquam "
+"eu, lobortis eget, dapibus vitae, velit. Cras non purus. Suspendisse massa. "
+"Curabitur gravida condimentum massa. Donec nunc magna, lacinia non, "
+"pellentesque ac, laoreet vel, eros. Praesent lectus leo, vestibulum eu, "
+"tempus eu, ullamcorper tristique, mi. Duis fringilla ultricies lacus. Ut "
+"non pede. Donec id libero. Cum sociis natoque penatibus et magnis dis "
+"parturient montes, nascetur ridiculus mus. Phasellus bibendum.\n"
+
+"Vestibulum turpis. Nunc euismod. Maecenas venenatis, purus at pharetra "
+"ultrices, orci orci blandit nisl, eget vulputate enim tortor sed nunc. "
+"Proin sit amet elit. Donec ut justo. In quis nisi. Praesent posuere. "
+"Maecenas porta. Curabitur pharetra. Class aptent taciti sociosqu ad litora "
+"torquent per conubia nostra, per inceptos hymenaeos. Donec suscipit ligula. "
+"Quisque facilisis ante eget mi. Nunc ac est.\n"
+
+"Quisque in sapien eget justo aliquam laoreet. Nullam ultricies est id dolor. "
+"Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Suspendisse ante "
+"velit, eleifend at, ullamcorper ut, rutrum et, ipsum. Mauris luctus, tellus "
+"non elementum convallis, nunc ipsum hendrerit lectus, ut lacinia elit nulla "
+"ac tellus. In sit amet velit. Maecenas non dolor. Sed commodo diam a pede. "
+"Ut non pede. Vestibulum condimentum turpis vel lacus consectetuer dictum. "
+"Nulla ullamcorper mi eu pede. Donec mauris tortor, facilisis vitae, "
+"hendrerit nec, lobortis nec, eros. Nam sit amet mi. Ut pharetra, orci nec "
+"porta convallis, lacus velit blandit sapien, luctus nonummy lacus dolor vel "
+"sapien. Suspendisse placerat. Donec ante turpis, volutpat eu, hendrerit "
+"vel, eleifend ac, arcu. Nulla facilisi. Sed faucibus facilisis lectus. "
+"Aliquam congue justo nec dui.\n"
+
+"Donec dapibus dui sed nisl. Proin congue. Curabitur placerat diam id eros. "
+"Pellentesque vitae nulla. Quisque at lorem et dolor auctor consequat. Sed "
+"sed tellus non nibh imperdiet venenatis. Integer ultrices dapibus nisi. "
+"Aenean vehicula malesuada risus. Fusce egestas malesuada leo. In "
+"ullamcorper pretium lorem. Vestibulum ante ipsum primis in faucibus orci "
+"luctus et ultrices posuere cubilia Curae;\n"
+
+"Phasellus congue. Morbi lectus arcu, mattis non, pulvinar et, condimentum "
+"non, mi. Suspendisse vestibulum nunc eu neque. Sed rutrum felis aliquam "
+"urna. Ut tincidunt orci vitae ipsum. Nullam eros. Quisque augue. Quisque "
+"lacinia. Nunc ligula diam, nonummy a, porta in, tristique quis, leo. "
+"Phasellus nunc nulla, fringilla vel, lacinia et, suscipit a, turpis. "
+"Integer a est. Curabitur mauris lacus, vehicula sit amet, sodales vel, "
+"iaculis vitae, massa. Nam diam est, ultrices vitae, varius et, tempor a, "
+"leo. Class aptent taciti sociosqu ad litora torquent per conubia nostra, "
+"per inceptos hymenaeos. Fusce felis nibh, ullamcorper non, malesuada eget, "
+ "facilisis vel, purus.\n";
+
+char const needle[] =
+"Proin congue. Curabitur placerat diam id eros. "
+"Pellentesque vitae nulla. Quisque at lorem et dolor auctor consequat. Sed "
+"sed tellus non nibh imperdiet venenatis. Integer ultrices dapibus nisi. "
+"Aenean vehicula malesuada risus. Fusce egestas malesuada leo. In "
+"ullamcorper pretium lorem. Vestibulum ante ipsum primis in faucibus orci "
+"luctus et ultrices posuere cubilia Curae;\n";
+
+char const Needle[] =
+"PROIN CONGUE. CURABITUR PLACERAT DIAM ID EROS. "
+"PELLENTESQUE VITAE NULLA. QUISQUE AT LOREM ET DOLOR AUCTOR CONSEQUAT. SED "
+"SED TELLUS NON NIBH IMPERDIET VENENATIS. INTEGER ULTRICES DAPIBUS NISI. "
+"AENEAN VEHICULA MALESUADA RISUS. FUSCE EGESTAS MALESUADA LEO. IN "
+"ULLAMCORPER PRETIUM LOREM. VESTIBULUM ANTE IPSUM PRIMIS IN FAUCIBUS ORCI "
+"LUCTUS ET ULTRICES POSUERE CUBILIA CURAE;\n";
+
+ char const *s;
+
+ s = strcasestr(hs, needle);
+ TEST_S(s, hs + 1920);
+
+ s = strcasestr(hs, Needle);
+ TEST_S(s, hs + 1920);
+ }
+
+ END();
+}
+
+int main(int argc, char *argv[])
+{
+ int retval = 0;
+ int i;
+
+ for (i = 1; argv[i]; i++) {
+ if (strcmp(argv[i], "-v") == 0)
+ test_flags |= tst_verbatim;
+ else
+ usage();
+ }
+
+ retval |= test_notfound(); fflush(stdout);
+ retval |= test_pattern(); fflush(stdout);
+ retval |= test_strcasestr(); fflush(stdout);
+
+
+ return retval;
+}
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/test_poll.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/test_poll.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,108 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_root_ex
+ * @file test_poll.c
+ * Example code for su_wait.h.
+ *
+ * This file illustrates how the asynchronous connect can be used with @b su.
+ *
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <string.h>
+#include <assert.h>
+
+#include "sofia-sip/su.h"
+#include "sofia-sip/su_wait.h"
+#include "sofia-sip/su_types.h"
+#include "sofia-sip/su_log.h"
+
+void usage(char const *name)
+{
+ fprintf(stderr, "usage: %s [host]\n", name);
+ exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+ su_socket_t s;
+ su_sockaddr_t su = { 0 };
+ char *host = argv[1];
+ char *port = host ? argv[2] : NULL;
+ su_addrinfo_t *ai = NULL, hints[1] = {{ 0 }};
+ int error;
+
+ if (argv[1] && (strcmp(argv[1], "--help") == 0 ||
+ strcmp(argv[1], "-?") == 0))
+ usage(argv[0]);
+
+ if (!port) port = "echo";
+
+ if ((error = su_getaddrinfo(host, port, hints, &ai))) {
+ fprintf(stderr, "poll_test: su_getaddrinfo(): %s\n",
+ su_gai_strerror(error));
+ exit(1);
+ }
+
+ memcpy(SU_ADDR(&su), ai->ai_addr, ai->ai_addrlen);
+
+ s = su_socket(ai->ai_family, SOCK_STREAM, 0);
+ if (s == INVALID_SOCKET) {
+ su_perror("socket");
+ exit(1);
+ }
+
+ su_freeaddrinfo(ai);
+
+ su_setblocking(s, 0); /* Don't block */
+
+ if (connect(s, &su.su_sa, su_sockaddr_size(&su)) == -1) {
+ if (errno != EINPROGRESS) {
+ su_perror("connect");
+ exit(1);
+ }
+ }
+
+ {
+ su_wait_t w;
+ int n, err;
+
+ su_wait_create(&w, s, SU_WAIT_OUT);
+
+ n = su_wait(&w, 1, SU_WAIT_FOREVER);
+
+ printf("su_wait returned %d\n", n);
+
+ err = su_soerror(s);
+
+ printf("connect: %s\n", su_strerror(err));
+ }
+
+ exit(0);
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/test_su.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/test_su.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,578 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_root_ex
+ * @CFILE test_su.c
+ *
+ * @brief Test program for su wait objects, root, timers, clones, and messages.
+ *
+ * @internal
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Mar 18 19:40:51 1999 pessi
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <signal.h>
+
+#include <assert.h>
+
+struct pinger;
+#define SU_ROOT_MAGIC_T struct pinger
+#define SU_INTERNAL_P su_root_t *
+#define SU_MSG_ARG_T su_sockaddr_t
+
+#include "sofia-sip/su.h"
+#include "sofia-sip/su_wait.h"
+#include "sofia-sip/su_log.h"
+#include "sofia-sip/su_debug.h"
+
+char const name[] = "su_test";
+
+#if HAVE_FUNC
+#define enter (void)SU_DEBUG_9(("%s: %s: entering\n", name, __func__))
+#define nh_enter (void)SU_DEBUG_9(("%s %s(%p): entering\n", name, __func__, nh))
+#elif HAVE_FUNCTION
+#define enter (void)SU_DEBUG_9(("%s: %s: entering\n", name, __FUNCTION__))
+#define nh_enter (void)SU_DEBUG_9(("%s %s(%p): entering\n", name, __FUNCTION__, nh))
+#define __func__ __FUNCTION__
+#else
+#define enter ((void)0)
+#define nh_enter ((void)0)
+#define __func__ "su_test"
+#endif
+
+struct pinger {
+ enum { PINGER = 1, PONGER = 2 } const sort;
+ char const * name;
+ unsigned running : 1;
+ unsigned : 0;
+ su_root_t *root;
+ su_socket_t s;
+ su_timer_t *t;
+ int id;
+ int rindex;
+ su_time_t when;
+ su_sockaddr_t addr;
+ double rtt_total;
+ int rtt_n;
+};
+
+short opt_family = AF_INET;
+short opt_verbatim = 0;
+short opt_singlethread = 0;
+
+static su_socket_t udpsocket(void)
+{
+ su_socket_t s;
+ su_sockaddr_t su = { 0 };
+ socklen_t sulen = sizeof(su);
+ char nbuf[64];
+
+ su.su_family = opt_family;
+
+ su_getlocalip(&su);
+
+ s = su_socket(su.su_family, SOCK_DGRAM, 0);
+ if (s == INVALID_SOCKET) {
+ su_perror("udpsocket: socket");
+ exit(1);
+ }
+
+ if (bind(s, &su.su_sa, su_sockaddr_size(&su)) == SOCKET_ERROR) {
+ su_perror("udpsocket: bind");
+ exit(1);
+ }
+
+ if (getsockname(s, &su.su_sa, &sulen) == SOCKET_ERROR) {
+ su_perror("udpsocket: getsockname");
+ exit(1);
+ }
+
+ if (opt_verbatim)
+ printf("udpsocket: using address [%s]:%u\n",
+ inet_ntop(su.su_family, SU_ADDR(&su), nbuf, sizeof(nbuf)),
+ ntohs(su.su_sin.sin_port));
+
+ return s;
+}
+
+static char *snow(su_time_t now)
+{
+ static char buf[24];
+
+ su_time_print(buf, sizeof(buf), &now);
+
+ return buf;
+}
+
+void
+do_ping(struct pinger *p, su_timer_t *t, void *p0)
+{
+ char buf[1024];
+
+ assert(p == su_root_magic(su_timer_root(t)));
+ assert(p->sort == PINGER);
+
+ p->when = su_now();
+
+ snprintf(buf, sizeof(buf), "Ping %d at %s", p->id++, snow(p->when));
+ if (su_sendto(p->s, buf, strlen(buf), 0,
+ &p->addr, su_sockaddr_size(&p->addr)) == -1) {
+ su_perror("do_ping: send");
+ }
+
+ if (opt_verbatim) {
+ puts(buf);
+ fflush(stdout);
+ }
+}
+
+int
+do_rtt(struct pinger *p, su_wait_t *w, void *p0)
+{
+ su_sockaddr_t su;
+ struct sockaddr * const susa = &su.su_sa;
+ socklen_t susize[] = { sizeof(su)};
+ char buf[1024];
+ char nbuf[1024];
+ int n;
+ su_time_t now = su_now();
+ double rtt;
+
+ assert(p0 == p);
+ assert(p->sort == PINGER);
+
+ rtt = su_time_diff(now, p->when);
+
+ p->rtt_total += rtt, p->rtt_n++;
+
+ su_wait_events(w, p->s);
+
+ n = recvfrom(p->s, buf, sizeof(buf) - 1, 0, susa, susize);
+ if (n < 0) {
+ su_perror("do_rtt: recvfrom");
+ return 0;
+ }
+ buf[n] = 0;
+
+ if (opt_verbatim)
+ printf("do_rtt: %d bytes from [%s]:%u: \"%s\", rtt = %lg ms\n",
+ n, inet_ntop(su.su_family, SU_ADDR(&su), nbuf, sizeof(nbuf)),
+ ntohs(su.su_sin.sin_port), buf, rtt / 1000);
+
+ do_ping(p, p->t, NULL);
+
+ return 0;
+}
+
+void
+do_pong(struct pinger *p, su_timer_t *t, void *p0)
+{
+ char buf[1024];
+
+ assert(p == su_root_magic(su_timer_root(t)));
+ assert(p->sort == PONGER);
+
+ p->id = 0;
+
+ snprintf(buf, sizeof(buf), "Pong at %s", snow(su_now()));
+ if (su_sendto(p->s, buf, strlen(buf), 0,
+ &p->addr, su_sockaddr_size(&p->addr)) == -1) {
+ su_perror("do_pong: send");
+ }
+
+ if (opt_verbatim) {
+ puts(buf);
+ fflush(stdout);
+ }
+}
+
+int
+do_recv(struct pinger *p, su_wait_t *w, void *p0)
+{
+ su_sockaddr_t su;
+ socklen_t susize[] = { sizeof(su)};
+ char buf[1024];
+ char nbuf[1024];
+ int n;
+ su_time_t now = su_now();
+
+ assert(p0 == p);
+ assert(p->sort == PONGER);
+
+ su_wait_events(w, p->s);
+
+ n = recvfrom(p->s, buf, sizeof(buf) - 1, 0, &su.su_sa, susize);
+ if (n < 0) {
+ su_perror("do_recv: recvfrom");
+ return 0;
+ }
+ buf[n] = 0;
+
+ if (opt_verbatim)
+ printf("do_recv: %d bytes from [%s]:%u: \"%s\" at %s\n",
+ n, inet_ntop(su.su_family, SU_ADDR(&su), nbuf, sizeof(nbuf)),
+ ntohs(su.su_sin.sin_port), buf, snow(now));
+
+ fflush(stdout);
+
+#if 0
+ if (p->id)
+ puts("do_recv: already a pending reply");
+
+ if (su_timer_set(p->t, do_pong, p) < 0) {
+ fprintf(stderr, "do_recv: su_timer_set() error\n");
+ return 0;
+ }
+
+ p->id = 1;
+#else
+ do_pong(p, p->t, NULL);
+#endif
+
+ return 0;
+}
+
+void
+do_exit(struct pinger *x, su_timer_t *t, void *x0)
+{
+ if (opt_verbatim)
+ printf("do_exit at %s\n", snow(su_now()));
+ su_root_break(su_timer_root(t));
+}
+
+int
+do_init(su_root_t *root, struct pinger *p)
+{
+ su_wait_t w;
+ su_socket_t s;
+ long interval;
+ su_timer_t *t;
+ su_wakeup_f f;
+ int index;
+#if nomore
+ su_wait_t w0;
+ int index0
+#endif
+
+ enter;
+
+ switch (p->sort) {
+ case PINGER: f = do_rtt; interval = 200; break;
+ case PONGER: f = do_recv; interval = 40; break;
+ default:
+ return SU_FAILURE;
+ }
+
+ p->t = t = su_timer_create(su_root_task(root), interval);
+ if (t == NULL) {
+ su_perror("su_timer_create");
+ return SU_FAILURE;
+ }
+
+ /* Create a sockets, */
+ p->s = s = udpsocket();
+
+#if nomore
+ if (su_wait_create(&w0, s, SU_WAIT_IN) == SOCKET_ERROR) {
+ su_perror("su_wait_create");
+ return SU_FAILURE;
+ }
+
+ index0 = su_root_register(root, &w0, f, p, 0);
+ if (index0 == SOCKET_ERROR) {
+ su_perror("su_root_register");
+ return SU_FAILURE;
+ }
+#endif
+
+ if (su_wait_create(&w, s, SU_WAIT_IN) == SOCKET_ERROR) {
+ su_perror("su_wait_create");
+ return SU_FAILURE;
+ }
+
+ index = su_root_register(root, &w, f, p, 0);
+ if (index == SOCKET_ERROR) {
+ su_perror("su_root_register");
+ return SU_FAILURE;
+ }
+
+#if nomore
+ su_root_deregister(root, index0);
+#endif
+ p->rindex = index;
+
+ return 0;
+}
+
+void
+do_destroy(su_root_t *root, struct pinger *p)
+{
+ enter;
+
+ if (opt_verbatim)
+ printf("do_destroy %s at %s\n", p->name, snow(su_now()));
+ su_root_deregister(root, p->rindex);
+ su_timer_destroy(p->t), p->t = NULL;
+ p->running = 0;
+}
+
+void
+start_ping(struct pinger *p, su_msg_r msg, su_sockaddr_t *arg)
+{
+ enter;
+
+ if (!p->running)
+ return;
+
+ if (opt_verbatim)
+ printf("start_ping: %s\n", p->name);
+
+ p->addr = *arg;
+ p->id = 1;
+
+ su_timer_set_interval(p->t, do_ping, p, 0);
+}
+
+void
+start_pong(struct pinger *p, su_msg_r msg, su_sockaddr_t *arg)
+{
+ su_msg_r reply;
+
+ enter;
+
+ if (!p->running)
+ return;
+
+ if (opt_verbatim)
+ printf("start_pong: %s\n", p->name);
+
+ p->addr = *arg;
+
+ if (su_msg_reply(reply, msg, start_ping, sizeof(p->addr)) == 0) {
+ socklen_t sinsize[1] = { sizeof(p->addr) };
+ if (getsockname(p->s, (struct sockaddr*)su_msg_data(reply), sinsize)
+ == SOCKET_ERROR)
+ su_perror("start_pong: getsockname()"), exit(1);
+ su_msg_send(reply);
+ }
+ else {
+ fprintf(stderr, "su_msg_reply failed!\n");
+ }
+}
+
+void
+init_ping(struct pinger *p, su_msg_r msg, su_sockaddr_t *arg)
+{
+ su_msg_r reply;
+
+ enter;
+
+ if (opt_verbatim)
+ printf("init_ping: %s\n", p->name);
+
+ if (su_msg_reply(reply, msg, start_pong, sizeof(p->addr)) == 0) {
+ socklen_t sinsize[1] = { sizeof(p->addr) };
+ if (getsockname(p->s, (struct sockaddr*)su_msg_data(reply), sinsize)
+ == SOCKET_ERROR)
+ su_perror("start_pong: getsockname()"), exit(1);
+ su_msg_send(reply);
+ }
+ else {
+ fprintf(stderr, "su_msg_reply failed!\n");
+ }
+}
+
+static
+RETSIGTYPE term(int n)
+{
+ enter;
+
+ exit(1);
+}
+
+void
+time_test(void)
+{
+ su_time_t now = su_now(), then = now;
+ su_duration_t t1, t2;
+ su_duration_t us;
+
+ enter;
+
+ for (us = 0; us < 1000000; us += 300) {
+ then.tv_sec = now.tv_sec;
+ if ((then.tv_usec = now.tv_usec + us) >= 1000000)
+ then.tv_usec -= 1000000, then.tv_sec++;
+ t1 = su_duration(now, then);
+ t2 = su_duration(then, now);
+ assert(t1 == -t2);
+ }
+
+ if (opt_verbatim)
+ printf("time_test: passed\n");
+}
+
+#if HAVE_ALARM
+#include <unistd.h>
+#include <signal.h>
+
+static RETSIGTYPE sig_alarm(int s)
+{
+ enter;
+
+ fprintf(stderr, "%s: FAIL! test timeout!\n", name);
+ exit(1);
+}
+static char const no_alarm[] = " [--no-alarm]";
+#else
+static char const no_alarm[] = "";
+#endif
+
+void
+usage(int exitcode)
+{
+ fprintf(stderr, "usage: %s [-6vs]%s\n", name, no_alarm);
+
+ exit(exitcode);
+}
+
+/*
+ * test su_wait functionality:
+ *
+ * Create a ponger, waking up do_recv() when data arrives,
+ * then scheduling do_pong() by timer
+ *
+ * Create a pinger, executed from timer, scheduling do_ping(),
+ * waking up do_rtt() when data arrives
+ *
+ * Create a timer, executing do_exit() after 10 seconds
+ */
+int main(int argc, char *argv[])
+{
+ su_root_t *root;
+ su_clone_r ping = SU_CLONE_R_INIT, pong = SU_CLONE_R_INIT;
+ su_msg_r start_msg = SU_MSG_R_INIT;
+ su_timer_t *t;
+#if HAVE_ALARM
+ int opt_alarm = 1;
+#endif
+
+ struct pinger
+ pinger = { PINGER, "ping", 1 },
+ ponger = { PONGER, "pong", 1 };
+
+ char *argv0 = argv[0];
+
+ enter;
+
+ while (argv[1]) {
+ if (strcmp(argv[1], "-v") == 0) {
+ opt_verbatim = 1;
+ argv++;
+ }
+#if SU_HAVE_IN6
+ else if (strcmp(argv[1], "-6") == 0) {
+ opt_family = AF_INET6;
+ argv++;
+ }
+#endif
+ else if (strcmp(argv[1], "-s") == 0) {
+ opt_singlethread = 1;
+ argv++;
+ }
+#if HAVE_ALARM
+ else if (strcmp(argv[1], "--no-alarm") == 0) {
+ opt_alarm = 0;
+ argv++;
+ }
+#endif
+ else {
+ usage(1);
+ }
+ }
+
+ signal(SIGTERM, term);
+
+ su_init(); atexit(su_deinit);
+
+ time_test();
+
+#if HAVE_ALARM
+ if (opt_alarm) {
+ alarm(60);
+ signal(SIGALRM, sig_alarm);
+ }
+#endif
+
+ root = su_root_create(NULL);
+ if (!root) perror("su_root_create"), exit(1);
+
+ su_root_threading(root, !opt_singlethread);
+
+ if (su_clone_start(root, ping, &pinger, do_init, do_destroy) != 0)
+ perror("su_clone_start"), exit(1);
+ if (su_clone_start(root, pong, &ponger, do_init, do_destroy) != 0)
+ perror("su_clone_start"), exit(1);
+
+ /* Test timer, exiting after 200 milliseconds */
+ t = su_timer_create(su_root_task(root), 200L);
+ if (t == NULL)
+ su_perror("su_timer_create"), exit(1);
+ su_timer_set(t, (su_timer_f)do_exit, NULL);
+
+ su_clone_pause(ping);
+ su_clone_pause(pong);
+
+ su_msg_create(start_msg, su_clone_task(ping), su_clone_task(pong),
+ init_ping, 0);
+ su_msg_send(start_msg);
+
+ su_clone_resume(ping);
+ su_clone_resume(pong);
+
+ su_root_run(root);
+
+ su_clone_wait(root, ping);
+ su_clone_wait(root, pong);
+
+ su_timer_destroy(t);
+
+ if (pinger.rtt_n) {
+ printf("%s executed %u pings in %g, mean rtt=%g sec\n", name,
+ pinger.rtt_n, pinger.rtt_total, pinger.rtt_total / pinger.rtt_n);
+ }
+ su_root_destroy(root);
+
+ if (opt_verbatim)
+ printf("%s exiting\n", argv0);
+
+ return 0;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/test_su_osx.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/test_su_osx.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,581 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005-2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_root_ex
+ * @CFILE torture_su_root_osx.c
+ *
+ * @brief Test program for OSX Core Foundation Run Loop and su root
+ * event loop integration.
+ *
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Sep 26 17:16:02 EEST 2006 mela
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <signal.h>
+
+#include <assert.h>
+
+struct pinger;
+#define SU_ROOT_MAGIC_T struct pinger
+#define SU_INTERNAL_P su_root_t *
+#define SU_MSG_ARG_T su_sockaddr_t
+
+#define SU_HAVE_OSX_CF_API 1
+
+#include "sofia-sip/su.h"
+#include "sofia-sip/su_wait.h"
+#include "sofia-sip/su_log.h"
+#include "sofia-sip/su_debug.h"
+
+#include "sofia-sip/su_osx_runloop.h"
+
+#if HAVE_FUNC
+#define enter (void)SU_DEBUG_9(("torture_su_root_osx: %s: entering\n", __func__))
+#define nh_enter (void)SU_DEBUG_9(("torture_su_root_osx %s(%p): entering\n", __func__, nh))
+#elif HAVE_FUNCTION
+#define enter (void)SU_DEBUG_9(("torture_su_root_osx: %s: entering\n", __FUNCTION__))
+#define nh_enter (void)SU_DEBUG_9(("torture_su_root_osx %s(%p): entering\n", __FUNCTION__, nh))
+#define __func__ __FUNCTION__
+#else
+#define enter ((void)0)
+#define nh_enter ((void)0)
+#define __func__ "torture_su_root_osx"
+#endif
+
+struct pinger {
+ enum { PINGER = 1, PONGER = 2 } const sort;
+ char const * name;
+ unsigned running : 1;
+ unsigned : 0;
+ su_root_t *root;
+ su_socket_t s;
+ su_timer_t *t;
+ int id;
+ int rindex;
+ su_time_t when;
+ su_sockaddr_t addr;
+ double rtt_total;
+ int rtt_n;
+};
+
+short opt_family = AF_INET;
+short opt_verbatim = 0;
+short opt_singlethread = 0;
+short opt_root_run = 0;
+
+/* For run loop */
+int running = 0;
+
+static su_socket_t udpsocket(void)
+{
+ su_socket_t s;
+ su_sockaddr_t su = { 0 };
+ socklen_t sulen = sizeof(su);
+ char nbuf[64];
+
+ enter;
+
+ su.su_family = opt_family;
+
+ su_getlocalip(&su);
+
+ s = su_socket(su.su_family, SOCK_DGRAM, 0);
+ if (s == INVALID_SOCKET) {
+ su_perror("udpsocket: socket");
+ exit(1);
+ }
+
+ if (bind(s, &su.su_sa, su_sockaddr_size(&su)) == SOCKET_ERROR) {
+ su_perror("udpsocket: bind");
+ exit(1);
+ }
+
+ if (getsockname(s, &su.su_sa, &sulen) == SOCKET_ERROR) {
+ su_perror("udpsocket: getsockname");
+ exit(1);
+ }
+
+ if (opt_verbatim)
+ printf("udpsocket: using address [%s]:%u\n",
+ inet_ntop(su.su_family, SU_ADDR(&su), nbuf, sizeof(nbuf)),
+ ntohs(su.su_sin.sin_port));
+
+ return s;
+}
+
+static char *snow(su_time_t now)
+{
+ static char buf[24];
+
+ enter;
+
+ su_time_print(buf, sizeof(buf), &now);
+
+ return buf;
+}
+
+void
+do_ping(struct pinger *p, su_timer_t *t, void *p0)
+{
+ char buf[1024];
+
+ enter;
+
+ printf("%s: pinger p == %x\n", __func__, (unsigned int) p);
+
+ assert(p == su_root_magic(su_timer_root(t)));
+ assert(p->sort == PINGER);
+
+ p->when = su_now();
+
+ snprintf(buf, sizeof(buf), "Ping %d at %s", p->id++, snow(p->when));
+ if (su_sendto(p->s, buf, strlen(buf), 0,
+ &p->addr, su_sockaddr_size(&p->addr)) == -1) {
+ su_perror("do_ping: send");
+ }
+
+ if (opt_verbatim) {
+ puts(buf);
+ fflush(stdout);
+ }
+}
+
+int
+do_rtt(struct pinger *p, su_wait_t *w, void *p0)
+{
+ su_sockaddr_t su;
+ struct sockaddr * const susa = &su.su_sa;
+ socklen_t susize[] = { sizeof(su)};
+ char buf[1024];
+ char nbuf[1024];
+ int n;
+ su_time_t now = su_now();
+ double rtt;
+
+ enter;
+
+ assert(p0 == p);
+ assert(p->sort == PINGER);
+
+ rtt = su_time_diff(now, p->when);
+
+ p->rtt_total += rtt, p->rtt_n++;
+
+ su_wait_events(w, p->s);
+
+ n = recvfrom(p->s, buf, sizeof(buf) - 1, 0, susa, susize);
+ if (n < 0) {
+ su_perror("do_rtt: recvfrom");
+ return 0;
+ }
+ buf[n] = 0;
+
+ if (opt_verbatim)
+ printf("do_rtt: %d bytes from [%s]:%u: \"%s\", rtt = %lg ms\n",
+ n, inet_ntop(su.su_family, SU_ADDR(&su), nbuf, sizeof(nbuf)),
+ ntohs(su.su_sin.sin_port), buf, rtt / 1000);
+
+ do_ping(p, p->t, NULL);
+
+ return 0;
+}
+
+void
+do_pong(struct pinger *p, su_timer_t *t, void *p0)
+{
+ char buf[1024];
+
+ enter;
+
+ assert(p == su_root_magic(su_timer_root(t)));
+ assert(p->sort == PONGER);
+
+ p->id = 0;
+
+ snprintf(buf, sizeof(buf), "Pong at %s", snow(su_now()));
+ if (su_sendto(p->s, buf, strlen(buf), 0,
+ &p->addr, su_sockaddr_size(&p->addr)) == -1) {
+ su_perror("do_pong: send");
+ }
+
+ if (opt_verbatim) {
+ puts(buf);
+ fflush(stdout);
+ }
+}
+
+int
+do_recv(struct pinger *p, su_wait_t *w, void *p0)
+{
+ su_sockaddr_t su;
+ socklen_t susize[] = { sizeof(su)};
+ char buf[1024];
+ char nbuf[1024];
+ int n;
+ su_time_t now = su_now();
+
+ enter;
+
+ assert(p0 == p);
+ assert(p->sort == PONGER);
+
+ su_wait_events(w, p->s);
+
+ n = recvfrom(p->s, buf, sizeof(buf) - 1, 0, &su.su_sa, susize);
+ if (n < 0) {
+ su_perror("do_recv: recvfrom");
+ return 0;
+ }
+ buf[n] = 0;
+
+ if (opt_verbatim)
+ printf("do_recv: %d bytes from [%s]:%u: \"%s\" at %s\n",
+ n, inet_ntop(su.su_family, SU_ADDR(&su), nbuf, sizeof(nbuf)),
+ ntohs(su.su_sin.sin_port), buf, snow(now));
+
+ fflush(stdout);
+
+#if 0
+ if (p->id)
+ puts("do_recv: already a pending reply");
+
+ if (su_timer_set(p->t, do_pong, p) < 0) {
+ fprintf(stderr, "do_recv: su_timer_set() error\n");
+ return 0;
+ }
+
+ p->id = 1;
+#else
+ do_pong(p, p->t, NULL);
+#endif
+
+ return 0;
+}
+
+void
+do_exit(struct pinger *x, su_timer_t *t, void *x0)
+{
+ enter;
+
+ if (opt_verbatim)
+ printf("do_exit at %s\n", snow(su_now()));
+ su_root_break(su_timer_root(t));
+
+ running = 0;
+}
+
+int
+do_init(su_root_t *root, struct pinger *p)
+{
+ su_wait_t w;
+ su_socket_t s;
+ long interval;
+ su_timer_t *t;
+ su_wakeup_f f;
+ int index, index0;
+
+ enter;
+
+ switch (p->sort) {
+ case PINGER: f = do_rtt; interval = 200; break;
+ case PONGER: f = do_recv; interval = 40; break;
+ default:
+ return SU_FAILURE;
+ }
+
+ /* Create a sockets, */
+ s = udpsocket();
+ if (su_wait_create(&w, s, SU_WAIT_IN) == SOCKET_ERROR)
+ su_perror("su_wait_create"), exit(1);
+
+ /* CFSocketEnableCallbacks(s, map_poll_revent_to_cf_event(su_wait_events(&w, s))); */
+
+ p->s = s;
+ p->t = t = su_timer_create(su_root_task(root), interval);
+ if (t == NULL) {
+ su_perror("su_timer_create");
+ return SU_FAILURE;
+ }
+
+ index0 = su_root_register(root, &w, f, p, 0);
+ if (index0 == SOCKET_ERROR) {
+ su_perror("su_root_register");
+ return SU_FAILURE;
+ }
+
+ index = su_root_register(root, &w, f, p, 0);
+ if (index == SOCKET_ERROR) {
+ su_perror("su_root_register");
+ return SU_FAILURE;
+ }
+
+ su_root_deregister(root, index0);
+
+ p->rindex = index;
+
+ return 0;
+}
+
+void
+do_destroy(su_root_t *root, struct pinger *p)
+{
+ enter;
+
+ if (opt_verbatim)
+ printf("do_destroy %s at %s\n", p->name, snow(su_now()));
+
+ su_root_deregister(root, p->rindex);
+ su_timer_destroy(p->t), p->t = NULL;
+
+ p->running = 0;
+}
+
+void
+start_ping(struct pinger *p, su_msg_r msg, su_sockaddr_t *arg)
+{
+ enter;
+
+ if (!p->running)
+ return;
+
+ if (opt_verbatim)
+ printf("start_ping: %s\n", p->name);
+
+ p->addr = *arg;
+ p->id = 1;
+ su_timer_set_at(p->t, do_ping, p, su_now());
+}
+
+void
+start_pong(struct pinger *p, su_msg_r msg, su_sockaddr_t *arg)
+{
+ su_msg_r reply;
+
+ enter;
+
+ if (!p->running)
+ return;
+
+ if (opt_verbatim)
+ printf("start_pong: %s\n", p->name);
+
+ p->addr = *arg;
+
+ if (su_msg_reply(reply, msg, start_ping, sizeof(p->addr)) == 0) {
+ socklen_t sinsize[1] = { sizeof(p->addr) };
+ if (getsockname(p->s, (struct sockaddr*)su_msg_data(reply), sinsize)
+ == SOCKET_ERROR)
+ su_perror("start_pong: getsockname()"), exit(1);
+ su_msg_send(reply);
+ }
+ else {
+ fprintf(stderr, "su_msg_create failed!\n");
+ }
+}
+
+void
+init_ping(struct pinger *p, su_msg_r msg, su_sockaddr_t *arg)
+{
+ su_msg_r reply;
+
+ enter;
+
+ if (opt_verbatim)
+ printf("init_ping: %s\n", p->name);
+
+ if (su_msg_reply(reply, msg, start_pong, sizeof(p->addr)) == 0) {
+ socklen_t sinsize[1] = { sizeof(p->addr) };
+ if (getsockname(p->s, (struct sockaddr*)su_msg_data(reply), sinsize)
+ == SOCKET_ERROR)
+ su_perror("start_pong: getsockname()"), exit(1);
+ su_msg_send(reply);
+ }
+ else {
+ fprintf(stderr, "su_msg_reply failed!\n");
+ }
+}
+
+static
+RETSIGTYPE term(int n)
+{
+ enter;
+
+ exit(1);
+}
+
+void
+time_test(void)
+{
+ su_time_t now = su_now(), then = now;
+ su_duration_t t1, t2;
+ su_duration_t us;
+
+ enter;
+
+ for (us = 0; us < 1000000; us += 300) {
+ then.tv_sec = now.tv_sec;
+ if ((then.tv_usec = now.tv_usec + us) >= 1000000)
+ then.tv_usec -= 1000000, then.tv_sec++;
+ t1 = su_duration(now, then);
+ t2 = su_duration(then, now);
+ assert(t1 == -t2);
+ }
+
+ if (opt_verbatim)
+ printf("time_test: passed\n");
+}
+
+char const name[] = "torture_su_root_osx";
+
+void
+usage(int exitcode)
+{
+ fprintf(stderr, "usage: %s [-6vs] [pid]\n", name);
+ exit(exitcode);
+}
+
+/*
+ * test su_wait functionality:
+ *
+ * Create a ponger, waking up do_recv() when data arrives,
+ * then scheduling do_pong() by timer
+ *
+ * Create a pinger, executed from timer, scheduling do_ping(),
+ * waking up do_rtt() when data arrives
+ *
+ * Create a timer, executing do_exit() after 10 seconds
+ */
+int main(int argc, char *argv[])
+{
+ su_root_t *root;
+ su_clone_r ping = SU_CLONE_R_INIT, pong = SU_CLONE_R_INIT;
+ su_msg_r start_msg = SU_MSG_R_INIT;
+ su_timer_t *t;
+ unsigned long sleeppid = 0;
+
+ struct pinger
+ pinger = { PINGER, "ping", 1 },
+ ponger = { PONGER, "pong", 1 };
+
+ char *argv0 = argv[0];
+
+ enter;
+
+ /* Set static run loop variable on */
+ running = 1;
+
+ while (argv[1]) {
+ if (strcmp(argv[1], "-v") == 0) {
+ opt_verbatim = 1;
+ argv++;
+ }
+#if SU_HAVE_IN6
+ else if (strcmp(argv[1], "-6") == 0) {
+ opt_family = AF_INET6;
+ argv++;
+ }
+#endif
+ else if (strcmp(argv[1], "-s") == 0) {
+ opt_singlethread = 1;
+ argv++;
+ }
+ else if (strcmp(argv[1], "-r") == 0) {
+ opt_root_run = 1;
+ argv++;
+ }
+ else if (strlen(argv[1]) == strspn(argv[1], "0123456789")) {
+ sleeppid = strtoul(argv[1], NULL, 10);
+ argv++;
+ }
+ else {
+ usage(1);
+ }
+ }
+
+ signal(SIGTERM, term);
+
+ su_init(); atexit(su_deinit);
+
+ time_test();
+
+ root = su_root_osx_runloop_create(NULL);
+
+ if (!root) perror("su_root_osx_runloop_create"), exit(1);
+
+ su_root_threading(root, 0 && !opt_singlethread);
+
+ if (su_clone_start(root, ping, &pinger, do_init, do_destroy) != 0)
+ perror("su_clone_start"), exit(1);
+ if (su_clone_start(root, pong, &ponger, do_init, do_destroy) != 0)
+ perror("su_clone_start"), exit(1);
+
+ /* Test timer, exiting after 200 milliseconds */
+ t = su_timer_create(su_root_task(root), 2000L);
+ if (t == NULL)
+ su_perror("su_timer_create"), exit(1);
+ su_timer_set(t, (su_timer_f)do_exit, NULL);
+
+ su_msg_create(start_msg, su_clone_task(ping), su_clone_task(pong),
+ init_ping, 0);
+ su_msg_send(start_msg);
+
+ if (opt_root_run) {
+ su_root_osx_prepare_run(root);
+ CFRunLoopRun();
+ }
+ else
+ while (running == 1) {
+ su_root_step(root, 20);
+ }
+
+ su_clone_wait(root, ping);
+ su_clone_wait(root, pong);
+
+ su_timer_destroy(t);
+
+ if (pinger.rtt_n) {
+ printf("%s executed %u pings in %g, mean rtt=%g sec\n", name,
+ pinger.rtt_n, pinger.rtt_total, pinger.rtt_total / pinger.rtt_n);
+ }
+ su_root_destroy(root);
+
+ if (opt_verbatim)
+ printf("%s exiting\n", argv0);
+
+#ifndef HAVE_WIN32
+ if (sleeppid)
+ kill(sleeppid, SIGTERM);
+#endif
+
+ return 0;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_rbtree.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_rbtree.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,710 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**
+ * @file torture_rbtree.c
+ * @brief Test red-black tree
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Mar 10 17:05:23 2004 ppessi
+ *
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include "sofia-sip/rbtree.h"
+
+typedef struct node Node;
+
+struct node {
+ Node *left, *right, *parent;
+ int black;
+ int value;
+ int inserted;
+};
+
+int tstflags;
+
+#define TSTFLAGS tstflags
+
+#include <stdio.h>
+#include <sofia-sip/tstdef.h>
+
+char const *name = "torture_rbtree";
+
+/* Define accessor macros */
+#define LEFT(node) ((node)->left)
+#define RIGHT(node) ((node)->right)
+#define PARENT(node) ((node)->parent)
+#define SET_RED(node) ((node)->black = 0)
+#define SET_BLACK(node) ((node)->black = 1)
+#define CMP(a, b) ((a)->value - (b)->value)
+#define IS_RED(node) ((node) && (node)->black == 0)
+#define IS_BLACK(node) (!(node) || (node)->black == 1)
+#define COPY_COLOR(dst, src) ((dst)->black = (src)->black)
+#define INSERT(node) ((void)0)
+#define REMOVE(node) ((node)->left = (node)->right = (node)->parent = NULL)
+
+RBTREE_PROTOS(static inline, redblack, Node);
+
+RBTREE_BODIES(static inline, redblack, Node, LEFT, RIGHT, PARENT,
+ IS_RED, SET_RED, IS_BLACK, SET_BLACK, COPY_COLOR,
+ CMP, INSERT, REMOVE);
+
+#include <sofia-sip/su_alloc.h>
+
+static
+Node *node_new(su_home_t *home, int value)
+{
+ Node *n = su_zalloc(home, sizeof (*n));
+
+ n->value = value;
+
+ return n;
+}
+
+/** ceil of log2 */
+unsigned log2ceil(unsigned k)
+{
+ unsigned result = 0;
+
+#if 0
+ if (k > (1 << 32))
+ result += 32, k = (k >> 32) + ((k & ((1 << 32) - 1)) != 0);
+#endif
+ if (k > (1 << 16))
+ result += 16, k = (k >> 16) + ((k & ((1 << 16) - 1)) != 0);
+ if (k > (1 << 8))
+ result += 8, k = (k >> 8) + ((k & ((1 << 8) - 1)) != 0);
+ if (k > (1 << 4))
+ result += 4, k = (k >> 4) + ((k & 15) != 0);
+ if (k > (1 << 2))
+ result += 2, k = (k >> 2) + ((k & 3) != 0);
+ if (k > (1 << 1))
+ result += 1, k = (k >> 1) + (k & 1);
+ if (k > 1)
+ result += 1;
+
+ return result;
+}
+
+static
+Node *node_find(Node *tree, int value)
+{
+ while (tree) {
+ if (tree->value == value)
+ break;
+ else if (tree->value < value)
+ tree = tree->right;
+ else
+ tree = tree->left;
+ }
+
+ return tree;
+}
+
+/** Check consistency */
+static
+int redblack_check(Node const *n)
+{
+ Node const *l, *r;
+
+ if (!n)
+ return 1;
+
+ l = n->left, r = n->right;
+
+ if (n->black || ((!l || l->black) && (!r || r->black)))
+ return (!l || redblack_check(l)) && (!r || redblack_check(r));
+ else
+ return 0;
+}
+
+int test_insert(void)
+{
+ su_home_t *home;
+ Node *tree = NULL, *o, *old;
+ Node *one, *three, *five, *six, *seven;
+
+ BEGIN();
+
+ home = su_home_clone(NULL, sizeof(*home)); TEST_1(home);
+ one = node_new(home, 1);
+ three = node_new(home, 3);
+ five = node_new(home, 5);
+ six = node_new(home, 6);
+ seven = node_new(home, 7);
+
+ TEST_1(one);
+ TEST_1(three);
+ TEST_1(five);
+ TEST_1(six);
+ TEST_1(seven);
+
+ /* Check single node */
+ TEST(redblack_insert(&tree, five, &o), 0); TEST_P(o, NULL);
+ TEST_P(tree, five);
+ TEST_P(five->left, NULL); TEST_P(five->right, NULL);
+ TEST_P(five->parent, NULL); TEST(five->black, 1);
+
+ /* Check after another node:
+ *
+ * 5b
+ * /
+ * 3r
+ */
+ TEST(redblack_insert(&tree, three, &o), 0); TEST_P(o, NULL);
+ TEST_P(tree->left, three); TEST(tree->black, 1);
+ TEST_P(three->left, NULL); TEST_P(three->right, NULL);
+ TEST_P(three->parent, tree); TEST(three->black, 0);
+
+ /* Check third node
+ * 5b
+ * / \
+ * 3r 7r
+ */
+ TEST(redblack_insert(&tree, seven, &o), 0); TEST_P(o, NULL);
+ TEST_P(tree->right, seven); TEST(tree->black, 1);
+ TEST_P(seven->left, NULL); TEST_P(seven->right, NULL);
+ TEST_P(seven->parent, tree); TEST(seven->black, 0);
+
+ /* Check after fourth node:
+ * 5b
+ * / \
+ * 3b 7b
+ * /
+ * 1r
+ */
+ TEST(redblack_insert(&tree, one, &o), 0); TEST_P(o, NULL);
+ TEST_P(tree->left->left, one);
+ TEST(tree->black, 1);
+ TEST(tree->left->black, 1); TEST(tree->right->black, 1);
+ TEST_P(one->left, NULL); TEST_P(one->right, NULL);
+ TEST_P(one->parent, tree->left); TEST(one->black, 0);
+
+ /* Checks that we got after fifth node:
+ * 5b
+ * / \
+ * 3b 7b
+ * / /
+ * 1r 6r
+ */
+ TEST(redblack_insert(&tree, six, &o), 0); TEST_P(o, NULL);
+ TEST_P(tree, five); TEST(five->black, 1);
+ TEST_P(tree->left, three); TEST(three->black, 1);
+ TEST_P(tree->left->left, one); TEST(one->black, 0);
+ TEST_P(tree->right, seven); TEST(seven->black, 1);
+ TEST_P(tree->right->left, six); TEST(six->black, 0);
+
+ /* Insert five second time */
+ old = five;
+ five = node_new(home, 5);
+ TEST(redblack_insert(&tree, five, &o), 0); TEST_P(o, old);
+ TEST_P(tree, five); TEST(five->black, 1);
+ TEST_P(tree->left, three); TEST(three->black, 1);
+ TEST_P(three->parent, five);
+ TEST_P(tree->left->left, one); TEST(one->black, 0);
+ TEST_P(tree->right, seven); TEST(seven->black, 1);
+ TEST_P(seven->parent, five);
+ TEST_P(tree->right->left, six); TEST(six->black, 0);
+
+ su_home_check(home);
+ su_home_zap(home);
+
+ END();
+}
+
+int test_rotate(void)
+{
+ su_home_t *home;
+ Node *tree = NULL;
+ Node *x, *y, *o;
+
+ BEGIN();
+
+ home = su_home_clone(NULL, sizeof(*home)); TEST_1(home);
+
+ x = node_new(home, 1);
+ y = node_new(home, 2);
+
+ TEST_1(x);
+ TEST_1(y);
+
+ /*
+ * x y x
+ * Checks that \ transforms to / and back to \
+ * y x y
+ */
+ TEST(redblack_insert(&tree, x, &o), 0); TEST_P(o, NULL);
+ TEST(redblack_insert(&tree, y, &o), 0); TEST_P(o, NULL);
+
+ TEST_P(tree, x); TEST_P(x->right, y);
+ redblack_left_rotate(&tree, x);
+ TEST_P(tree, y); TEST_P(y->left, x);
+ redblack_right_rotate(&tree, y);
+ TEST_P(tree, x); TEST_P(x->right, y);
+
+ su_home_check(home);
+ su_home_zap(home);
+
+ END();
+}
+
+int test_simple(void)
+{
+ su_home_t *home;
+ Node *tree = NULL, *o;
+ int i;
+ Node *um, *um103, *um497, *um995;
+
+ BEGIN();
+
+ home = su_home_clone(NULL, sizeof(*home)); TEST_1(home);
+
+ for (i = 3; i < 1000; i += 3) {
+ um = node_new(home, i); TEST_1(um);
+ o = (void *)-1; TEST(redblack_insert(&tree, um, &o), 0); TEST_P(o, NULL);
+ }
+
+ um103 = node_new(home, 103); TEST_1(um103);
+ um497 = node_new(home, 497); TEST_1(um497);
+ um995 = node_new(home, 995); TEST_1(um995);
+
+ o = (void *)-1; TEST(redblack_insert(&tree, um995, &o), 0); TEST_P(o, NULL);
+ o = (void *)-1; TEST(redblack_insert(&tree, um497, &o), 0); TEST_P(o, NULL);
+ o = (void *)-1; TEST(redblack_insert(&tree, um103, &o), 0); TEST_P(o, NULL);
+
+ um = node_find(tree, 103); TEST_P(um, um103);
+ um = node_find(tree, 497); TEST_P(um, um497);
+ um = node_find(tree, 995); TEST_P(um, um995);
+ um = node_find(tree, 994); TEST_P(um, NULL);
+ um = node_find(tree, 1); TEST_P(um, NULL);
+
+ su_home_check(home);
+ su_home_zap(home);
+
+ END();
+}
+
+int test_balance(void)
+{
+ su_home_t *home;
+ Node *tree = NULL, *o = NULL;
+ Node *node, **nodes;
+ int i, j;
+ int const N = 1000;
+
+ BEGIN();
+
+ home = su_home_clone(NULL, sizeof(*home)); TEST_1(home);
+ nodes = su_zalloc(home, (N + 2) * (sizeof *nodes)); TEST_1(nodes);
+ nodes++;
+
+ for (i = 0; i < N; i++) {
+ nodes[i] = node = node_new(home, i); TEST_1(node);
+ TEST(redblack_insert(&tree, node, &o), 0);
+ TEST_P(o, NULL);
+ TEST_1(redblack_height(tree) <= 2 * (int)log2ceil(i + 1 + 1));
+ TEST_1(redblack_check(tree));
+ }
+
+ for (i = 0; i < N; i++) {
+ node = node_find(tree, i);
+ TEST_1(node);
+ TEST(node->value, i);
+ TEST_P(nodes[i], node);
+ }
+
+ node = node_find(tree, 0);
+
+ for (i = 0; i < N; i++) {
+ TEST_1(node); TEST(node->value, i);
+ node = redblack_succ(node);
+ }
+ TEST_1(node == NULL);
+
+ for (i = 0; i < N; i++) {
+ TEST_P(redblack_succ(nodes[i]), nodes[i + 1]);
+ TEST_P(redblack_prec(nodes[i]), nodes[i - 1]);
+ }
+
+ for (i = 0; i < N; i++) {
+ node = node_find(tree, i);
+ TEST_1(node); TEST(node->value, i);
+ redblack_remove(&tree, node);
+ TEST_1(node->parent == NULL &&
+ node->left == NULL &&
+ node->right == NULL);
+ TEST_1(redblack_height(tree) <= 2 * (int)log2ceil(N - i + 1));
+ TEST_1(redblack_check(tree));
+ }
+
+ TEST_P(tree, NULL);
+
+ for (i = N - 1; i >= 0; i--) {
+ o = (void *)-1;
+ TEST(redblack_insert(&tree, nodes[i], &o), 0);
+ TEST_P(o, NULL);
+ TEST_1(redblack_height(tree) <= 2 * (int)log2ceil(N - i + 1));
+ TEST_1(redblack_check(tree));
+ }
+
+ for (i = 0; i < N; i++) {
+ TEST_P(redblack_succ(nodes[i]), nodes[i + 1]);
+ TEST_P(redblack_prec(nodes[i]), nodes[i - 1]);
+ }
+
+ for (i = 0; i < N; i++) {
+ redblack_remove(&tree, nodes[i]);
+ TEST_1(redblack_height(tree) <= 2 * (int)log2ceil(N - i + 1));
+ TEST_1(redblack_check(tree));
+ }
+
+ TEST_P(tree, NULL);
+
+ for (i = 0; i < N; i++) {
+ int sn = (i * 57) % N;
+ o = (void *)-1;
+ TEST(nodes[sn]->inserted, 0);
+ TEST(redblack_insert(&tree, nodes[sn], &o), 0);
+ nodes[sn]->inserted = 1;
+ TEST_P(o, NULL);
+ TEST_1(redblack_height(tree) <= 2 * (int)log2ceil(i + 1 + 1));
+ TEST_1(redblack_check(tree));
+ }
+
+ for (i = 0; i < N; i++) {
+ TEST(nodes[i]->inserted, 1);
+ TEST_P(redblack_succ(nodes[i]), nodes[i + 1]);
+ TEST_P(redblack_prec(nodes[i]), nodes[i - 1]);
+ }
+
+ for (i = 0; i < N; i++) {
+ int sn = (i * 23) % N; /* 23 is relative prime to N */
+ TEST(nodes[sn]->inserted, 1);
+ redblack_remove(&tree, nodes[sn]);
+ nodes[sn]->inserted = 0;
+ TEST_1(redblack_height(tree) <= 2 * (int)log2ceil(N - i + 1));
+ TEST_1(redblack_check(tree));
+ }
+
+ TEST_P(tree, NULL);
+
+ for (i = 0; i < N; i++) {
+ int sn = (i * 517) % N; /* relative prime to N */
+ o = (void *)-1;
+ TEST(nodes[sn]->inserted, 0);
+ TEST(redblack_insert(&tree, nodes[sn], &o), 0);
+ nodes[sn]->inserted = 1;
+ TEST_P(o, NULL);
+ TEST_1(redblack_height(tree) <= 2 * (int)log2ceil(i + 1 + 1));
+ TEST_1(redblack_check(tree));
+ }
+
+ for (i = 0; i < N; i++) {
+ TEST(nodes[i]->inserted, 1);
+ TEST_P(redblack_succ(nodes[i]), nodes[i + 1]);
+ TEST_P(redblack_prec(nodes[i]), nodes[i - 1]);
+ }
+
+ for (i = 0; i < N; i++) {
+ int sn = (i * 497) % N; /* relative prime to N */
+ TEST(nodes[sn]->inserted, 1);
+ redblack_remove(&tree, nodes[sn]);
+ nodes[sn]->inserted = 0;
+ TEST_1(redblack_height(tree) <= 2 * (int)log2ceil(N - i + 1));
+ TEST_1(redblack_check(tree));
+ }
+
+ TEST_P(tree, NULL);
+
+ for (i = 0; i < N; i++) {
+ int sn = (i * 1957) % N; /* relative prime to N */
+ o = (void *)-1;
+ TEST(nodes[sn]->inserted, 0);
+ TEST(redblack_insert(&tree, nodes[sn], &o), 0);
+ nodes[sn]->inserted = 1;
+ TEST_P(o, NULL);
+ TEST_1(redblack_height(tree) <= 2 * (int)log2ceil(i + 1 + 1));
+ TEST_1(redblack_check(tree));
+ }
+
+ for (i = 0; i < N; i++) {
+ TEST(nodes[i]->inserted, 1);
+ TEST_P(redblack_succ(nodes[i]), nodes[i + 1]);
+ TEST_P(redblack_prec(nodes[i]), nodes[i - 1]);
+ }
+
+ for (i = 0; i < N; i++) {
+ int sn = (i * 1519) % N; /* relative prime to N */
+ TEST(nodes[sn]->inserted, 1);
+ redblack_remove(&tree, nodes[sn]);
+ nodes[sn]->inserted = 0;
+ TEST_1(redblack_height(tree) <= 2 * (int)log2ceil(N - i + 1));
+ TEST_1(redblack_check(tree));
+ }
+
+ TEST_P(tree, NULL);
+
+ /* Insert small, big, small, big ... */
+
+ for (i = 0; i < N / 2; i++) {
+ int sn = N - i - 1;
+ TEST(nodes[i]->inserted, 0);
+ o = (void *)-1;
+ TEST(redblack_insert(&tree, nodes[i], &o), 0);
+ TEST_P(o, NULL);
+ nodes[i]->inserted = 1;
+
+ TEST(nodes[sn]->inserted, 0);
+ o = (void *)-1;
+ TEST(redblack_insert(&tree, nodes[sn], &o), 0);
+ TEST_P(o, NULL);
+ nodes[sn]->inserted = 1;
+ }
+
+ for (i = 0; i < N; i++) {
+ TEST(nodes[i]->inserted, 1);
+ TEST_P(redblack_succ(nodes[i]), nodes[i + 1]);
+ TEST_P(redblack_prec(nodes[i]), nodes[i - 1]);
+ }
+
+ for (i = 0; i < N; i++) {
+ node = ((i & 1) ? redblack_succ(tree) : redblack_prec(tree));
+ if (node == NULL)
+ node = tree;
+ TEST(node->inserted, 1);
+ redblack_remove(&tree, node);
+ node->inserted = 0;
+ TEST_1(redblack_height(tree) <= 2 * (int)log2ceil(N - i + 1));
+ TEST_1(redblack_check(tree));
+ }
+
+ TEST_P(tree, NULL);
+
+ /* Insert small, big, small, big ... */
+
+ for (i = 0; i < N / 2; i++) {
+ int sn = N - i - 1;
+ TEST(nodes[i]->inserted, 0);
+ o = (void *)-1;
+ TEST(redblack_insert(&tree, nodes[i], &o), 0);
+ TEST_P(o, NULL);
+ nodes[i]->inserted = 1;
+
+ TEST(nodes[sn]->inserted, 0);
+ o = (void *)-1;
+ TEST(redblack_insert(&tree, nodes[sn], &o), 0);
+ TEST_P(o, NULL);
+ nodes[sn]->inserted = 1;
+ }
+
+ for (i = 0; i < N; i++) {
+ TEST(nodes[i]->inserted, 1);
+ TEST_P(redblack_succ(nodes[i]), nodes[i + 1]);
+ TEST_P(redblack_prec(nodes[i]), nodes[i - 1]);
+ }
+
+ /* Remove last, first, last, first, ... */
+ for (i = 0; i < N; i++) {
+ node = ((i & 1) ? redblack_first(tree) : redblack_last(tree));
+ TEST_1(node);
+ TEST(node->inserted, 1);
+ redblack_remove(&tree, node);
+ node->inserted = 0;
+ TEST_1(redblack_height(tree) <= 2 * (int)log2ceil(N - i + 1));
+ TEST_1(redblack_check(tree));
+ }
+
+ TEST_P(tree, NULL);
+
+ /* Insert small, big, small, big ... */
+
+ for (i = 0; i < N / 2; i++) {
+ int sn = N / 2 + i;
+ TEST(nodes[i]->inserted, 0);
+ o = (void *)-1;
+ TEST(redblack_insert(&tree, nodes[i], &o), 0);
+ TEST_P(o, NULL);
+ nodes[i]->inserted = 1;
+
+ TEST(nodes[sn]->inserted, 0);
+ o = (void *)-1;
+ TEST(redblack_insert(&tree, nodes[sn], &o), 0);
+ TEST_P(o, NULL);
+ nodes[sn]->inserted = 1;
+ }
+
+ for (i = 0; i < N; i++) {
+ TEST(nodes[i]->inserted, 1);
+ TEST_P(redblack_succ(nodes[i]), nodes[i + 1]);
+ TEST_P(redblack_prec(nodes[i]), nodes[i - 1]);
+ }
+
+ /* Remove last, first, last, first, ... */
+ for (i = 0; i < N; i++) {
+ node = ((i & 1) ? redblack_first(tree) : redblack_last(tree));
+ TEST_1(node);
+ TEST(node->inserted, 1);
+ redblack_remove(&tree, node);
+ node->inserted = 0;
+ TEST_1(redblack_height(tree) <= 2 * (int)log2ceil(N - i + 1));
+ TEST_1(redblack_check(tree));
+ }
+
+ TEST_P(tree, NULL);
+
+ /* Insert in perfect order ... */
+
+ for (j = N / 2; j > 0; j /= 2) {
+ for (i = N - j; i >= 0; i -= j) {
+ if (nodes[i]->inserted)
+ continue;
+ o = (void *)-1;
+ TEST(redblack_insert(&tree, nodes[i], &o), 0);
+ TEST_P(o, NULL);
+ nodes[i]->inserted = 1;
+ }
+ }
+
+ for (i = 0; i < N; i++) {
+ TEST(nodes[i]->inserted, 1);
+ TEST_P(redblack_succ(nodes[i]), nodes[i + 1]);
+ TEST_P(redblack_prec(nodes[i]), nodes[i - 1]);
+ }
+
+ /* Remove such nodes that inserts red uncles into tree */
+ for (i = 0; i < N; i++) {
+ node = redblack_last(tree);
+ for (o = node; o; o = redblack_prec(o)) {
+ Node *dad, *granddad, *uncle, *to_be_removed;
+ /* We must have a node with black dad, no brother, red granddad and uncle */
+ if (!(dad = o->parent) || !dad->black)
+ continue;
+ if (dad->left && dad->right)
+ continue;
+ if (!(granddad = dad->parent) || granddad->black)
+ continue;
+ if (granddad->left == dad)
+ uncle = granddad->right;
+ else
+ uncle = granddad->left;
+ if (!uncle || uncle->black)
+ continue;
+ to_be_removed = redblack_prec(o->parent);
+ if (to_be_removed == granddad || to_be_removed == uncle)
+ continue;
+ if (!to_be_removed->left || !to_be_removed->right)
+ continue;
+ node = to_be_removed;
+ break;
+ }
+ TEST(node->inserted, 1);
+ redblack_remove(&tree, node);
+ node->inserted = 0;
+ TEST_1(redblack_height(tree) <= 2 * (int)log2ceil(N - i + 1));
+ TEST_1(redblack_check(tree));
+ }
+
+ TEST_P(tree, NULL);
+
+ su_home_check(home);
+ su_home_zap(home);
+
+ END();
+}
+
+int test_speed(void)
+{
+ su_home_t *home;
+ Node *tree = NULL, *o = NULL;
+ Node *node;
+ unsigned i;
+ unsigned int const N = 1000000U;
+
+ BEGIN();
+
+ home = su_home_clone(NULL, sizeof(*home)); TEST_1(home);
+
+ for (i = 0; i < N; i++) {
+ node = node_new(home, i);
+ TEST(redblack_insert(&tree, node, &o), 0);
+ TEST_P(o, NULL);
+ }
+
+ TEST_1(redblack_height(tree) <= 2 * (int)log2ceil(i + 1));
+
+ for (i = 0; i < N; i++) {
+ node = node_find(tree, i);
+ TEST_1(node); TEST(node->value, i);
+ }
+
+ node = node_find(tree, 0);
+ for (i = 0; i < N; i++) {
+ TEST_1(node); TEST(node->value, i);
+ node = redblack_succ(node);
+ }
+ TEST_1(node == NULL);
+
+ su_home_check(home);
+ su_home_zap(home);
+
+ END();
+}
+
+
+void usage(void)
+{
+ fprintf(stderr,
+ "usage: %s [-v]\n",
+ name);
+}
+
+int main(int argc, char *argv[])
+{
+ int retval = 0;
+ int i;
+
+ for (i = 1; argv[i]; i++) {
+ if (strcmp(argv[i], "-v") == 0)
+ tstflags |= tst_verbatim;
+ else
+ usage();
+ }
+
+ retval |= test_insert(); fflush(stdout);
+ retval |= test_rotate(); fflush(stdout);
+ retval |= test_simple(); fflush(stdout);
+ retval |= test_balance(); fflush(stdout);
+ retval |= test_speed(); fflush(stdout);
+
+ return retval;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,404 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su
+ *
+ * @file torture_su.c
+ *
+ * Testing functions for su socket functions.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu May 2 18:17:46 2002 ppessi
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sofia-sip/su.h>
+#include <sofia-sip/su_localinfo.h>
+
+int tstflags;
+
+#define TSTFLAGS tstflags
+#include <sofia-sip/tstdef.h>
+
+char const *name = "su_torture";
+
+static int test_sockaddr(void);
+
+void usage(void)
+{
+ fprintf(stderr, "usage: %s [-v]\n", name);
+}
+
+/** */
+int test_sockaddr(void)
+{
+ su_localinfo_t hints[1] = {{ LI_CANONNAME }};
+ su_localinfo_t *li, *res = NULL;
+ int s;
+ su_sockaddr_t su[1], a[1], b[1];
+
+ BEGIN();
+
+ hints->li_family = AF_INET;
+
+ TEST(su_getlocalinfo(hints, &res), 0);
+
+ for (li = res; li; li = li->li_next) {
+ if (li->li_addrlen != res->li_addrlen ||
+ memcmp(li->li_addr, res->li_addr, li->li_addrlen) != 0)
+ TEST_1(su_cmp_sockaddr(li->li_addr, res->li_addr) != 0);
+ else
+ TEST_1(su_cmp_sockaddr(li->li_addr, res->li_addr) == 0);
+ }
+
+ memset(su, 0, sizeof su);
+ TEST(su_getlocalip(su), 0);
+
+ if (res->li_family == AF_INET)
+ TEST(su_cmp_sockaddr(res->li_addr, su), 0);
+
+ TEST_1(su_gli_strerror(ELI_NOERROR));
+ TEST_1(su_gli_strerror(ELI_NOADDRESS));
+ TEST_1(su_gli_strerror(ELI_FAMILY));
+ TEST_1(su_gli_strerror(ELI_MEMORY));
+ TEST_1(su_gli_strerror(ELI_RESOLVER));
+ TEST_1(su_gli_strerror(ELI_SYSTEM));
+ TEST_1(su_gli_strerror(-100));
+
+ li = su_copylocalinfo(res); TEST_1(li);
+ su_freelocalinfo(li);
+
+ s = su_socket(res->li_family, SOCK_DGRAM, 0); TEST_1(s != -1);
+ TEST(su_setblocking(s, 0), 0);
+ TEST(su_setblocking(s, 1), 0);
+ TEST(su_close(s), 0);
+
+ su_freelocalinfo(res);
+
+#if SU_HAVE_IN6
+ hints->li_family = AF_INET6;
+ hints->li_flags &= ~LI_CANONNAME;
+ hints->li_flags |= LI_V4MAPPED;
+
+ TEST(su_getlocalinfo(hints, &res), 0);
+ for (li = res; li; li = li->li_next)
+ TEST(li->li_family, AF_INET6);
+
+ su_freelocalinfo(res);
+#endif
+
+ hints->li_flags |= LI_NUMERIC;
+ TEST(su_getlocalinfo(hints, &res), 0);
+
+ hints->li_flags |= LI_NAMEREQD;
+ res = NULL;
+ su_getlocalinfo(hints, &res);
+ su_freelocalinfo(res);
+
+ memset(a, 0, sizeof *a);
+ memset(b, 0, sizeof *b);
+
+ TEST_1(su_match_sockaddr(a, b));
+ b->su_family = AF_INET;
+ TEST_1(su_match_sockaddr(a, b));
+ a->su_port = htons(12);
+ TEST_1(!su_match_sockaddr(a, b));
+ b->su_port = htons(12);
+ TEST_1(su_match_sockaddr(a, b));
+ a->su_sin.sin_addr.s_addr = htonl(0x7f000001);
+ TEST_1(su_match_sockaddr(a, b));
+ a->su_family = AF_INET;
+ TEST_1(!su_match_sockaddr(a, b));
+ b->su_sin.sin_addr.s_addr = htonl(0x7f000001);
+ TEST_1(su_match_sockaddr(a, b));
+ a->su_sin.sin_addr.s_addr = 0;
+ TEST_1(su_match_sockaddr(a, b));
+#if SU_HAVE_IN6
+ a->su_family = AF_INET6;
+ TEST_1(!su_match_sockaddr(a, b));
+ b->su_family = AF_INET6;
+ TEST_1(su_match_sockaddr(a, b));
+ b->su_sin6.sin6_addr.s6_addr[15] = 1;
+ TEST_1(su_match_sockaddr(a, b));
+ TEST_1(!su_match_sockaddr(b, a));
+ a->su_sin6.sin6_addr.s6_addr[15] = 2;
+ TEST_1(!su_match_sockaddr(a, b));
+ a->su_family = 0;
+ TEST_1(su_match_sockaddr(a, b));
+ TEST_1(!su_match_sockaddr(b, a));
+#endif
+ END();
+}
+
+#include <sofia-sip/su_wait.h>
+
+int test_sendrecv(void)
+{
+ int s, l, a;
+ int n;
+ su_sockaddr_t su, csu;
+ socklen_t sulen = sizeof su.su_sin, csulen = sizeof csu.su_sin;
+ char b1[8], b2[8], b3[8];
+ su_iovec_t sv[3], rv[3];
+
+ sv[0].siv_base = "one!one!", sv[0].siv_len = 8;
+ sv[1].siv_base = "two!two!", sv[1].siv_len = 8;
+ sv[2].siv_base = "third!", sv[2].siv_len = 6;
+
+ rv[0].siv_base = b1, rv[0].siv_len = 8;
+ rv[1].siv_base = b2, rv[1].siv_len = 8;
+ rv[2].siv_base = b3, rv[2].siv_len = 8;
+
+ BEGIN();
+
+ s = su_socket(AF_INET, SOCK_DGRAM, 0); TEST_1(s != -1);
+
+ memset(&su, 0, sulen);
+ su.su_len = sulen;
+ su.su_family = AF_INET;
+ TEST(inet_pton(AF_INET, "127.0.0.1", &su.su_sin.sin_addr), 1);
+
+ TEST(bind(s, &su.su_sa, sulen), 0);
+ TEST(getsockname(s, &su.su_sa, &sulen), 0);
+
+ n = su_vsend(s, sv, 3, 0, &su, sulen); TEST(n, 8 + 8 + 6);
+ n = su_vrecv(s, rv, 3, 0, &su, &sulen); TEST(n, 8 + 8 + 6);
+
+ TEST_M(rv[0].siv_base, sv[0].siv_base, sv[0].siv_len);
+ TEST_M(rv[1].siv_base, sv[1].siv_base, sv[1].siv_len);
+ TEST_M(rv[2].siv_base, sv[2].siv_base, sv[2].siv_len);
+
+ su_close(s);
+
+ l = su_socket(AF_INET, SOCK_STREAM, 0); TEST_1(l != -1);
+ s = su_socket(AF_INET, SOCK_STREAM, 0); TEST_1(s != -1);
+
+ memset(&su, 0, sulen);
+ su.su_len = sulen;
+ su.su_family = AF_INET;
+ TEST(inet_pton(AF_INET, "127.0.0.1", &su.su_sin.sin_addr), 1);
+
+ TEST(bind(l, &su.su_sa, sulen), 0);
+ TEST(bind(s, &su.su_sa, sulen), 0);
+
+ TEST(getsockname(l, &su.su_sa, &sulen), 0);
+ TEST(listen(l, 5), 0);
+
+ TEST(connect(s, &su.su_sa, sulen), 0);
+ a = accept(l, &csu.su_sa, &csulen); TEST_1(a != -1);
+
+ n = su_vsend(s, sv, 3, 0, NULL, 0); TEST(n, 8 + 8 + 6);
+ n = su_vrecv(a, rv, 3, 0, NULL, NULL); TEST(n, 8 + 8 + 6);
+
+ TEST_M(rv[0].siv_base, sv[0].siv_base, sv[0].siv_len);
+ TEST_M(rv[1].siv_base, sv[1].siv_base, sv[1].siv_len);
+ TEST_M(rv[2].siv_base, sv[2].siv_base, sv[2].siv_len);
+
+ n = send(a, "", 0, 0); TEST(n, 0);
+ n = su_vsend(a, sv, 3, 0, NULL, 0); TEST(n, 8 + 8 + 6);
+
+ {
+ su_wait_t w[1] = { SU_WAIT_INIT };
+
+ TEST(su_wait_create(w, s, SU_WAIT_IN | SU_WAIT_HUP), 0);
+
+ TEST(su_wait(w, 0, 500), SU_WAIT_TIMEOUT);
+
+ TEST(su_wait(w, 1, 500), 0);
+ TEST(su_wait_events(w, s), SU_WAIT_IN);
+
+ TEST_SIZE(su_getmsgsize(s), 8 + 8 + 6);
+ n = su_vrecv(s, rv, 3, 0, NULL, NULL); TEST(n, 8 + 8 + 6);
+
+ TEST(su_wait(w, 1, 100), SU_WAIT_TIMEOUT);
+
+ shutdown(a, 2);
+
+ TEST(su_wait(w, 1, 100), 0);
+#if SU_HAVE_WINSOCK
+ TEST_1(su_wait_events(w, s) & SU_WAIT_HUP);
+#else
+ TEST_1(su_wait_events(w, s));
+ n = su_vrecv(s, rv, 3, 0, NULL, NULL); TEST(n, 0);
+#endif
+
+ su_wait_destroy(w);
+ }
+
+ su_close(a);
+
+ su_close(l);
+ su_close(s);
+
+ END();
+}
+
+#include <sofia-sip/su_md5.h>
+
+int test_md5(void)
+{
+ BEGIN();
+
+ su_md5_t md5[1], md5i[1];
+ uint8_t digest[SU_MD5_DIGEST_SIZE];
+ char hexdigest[2 * SU_MD5_DIGEST_SIZE + 1];
+
+ struct { char *input; uint8_t digest[SU_MD5_DIGEST_SIZE]; } suite[] = {
+ { (""),
+ { 0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04,
+ 0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e } },
+ { ("a"), { 0x0c, 0xc1, 0x75, 0xb9, 0xc0, 0xf1, 0xb6, 0xa8,
+ 0x31, 0xc3, 0x99, 0xe2, 0x69, 0x77, 0x26, 0x61 } },
+ { ("abc"), { 0x90, 0x01, 0x50, 0x98, 0x3c, 0xd2, 0x4f, 0xb0,
+ 0xd6, 0x96, 0x3f, 0x7d, 0x28, 0xe1, 0x7f, 0x72 } },
+ { ("message digest"),
+ { 0xf9, 0x6b, 0x69, 0x7d, 0x7c, 0xb7, 0x93, 0x8d,
+ 0x52, 0x5a, 0x2f, 0x31, 0xaa, 0xf1, 0x61, 0xd0 } },
+ { ("abcdefghijklmnopqrstuvwxyz"),
+ { 0xc3, 0xfc, 0xd3, 0xd7, 0x61, 0x92, 0xe4, 0x00,
+ 0x7d, 0xfb, 0x49, 0x6c, 0xca, 0x67, 0xe1, 0x3b } },
+ { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+ { 0xd1, 0x74, 0xab, 0x98, 0xd2, 0x77, 0xd9, 0xf5,
+ 0xa5, 0x61, 0x1c, 0x2c, 0x9f, 0x41, 0x9d, 0x9f } },
+
+ { "1234567890123456789012345678901234567890"
+ "1234567890123456789012345678901234567890",
+ { 0x57, 0xed, 0xf4, 0xa2, 0x2b, 0xe3, 0xc9, 0x55,
+ 0xac, 0x49, 0xda, 0x2e, 0x21, 0x07, 0xb6, 0x7a } }};
+
+ su_md5_init(md5);
+ su_md5_update(md5, suite[0].input, 0);
+ su_md5_digest(md5, digest);
+ TEST_M(digest, suite[0].digest, SU_MD5_DIGEST_SIZE);
+ su_md5_deinit(md5);
+
+ su_md5_init(md5);
+ su_md5_strupdate(md5, suite[1].input);
+ su_md5_digest(md5, digest);
+ TEST_M(digest, suite[1].digest, SU_MD5_DIGEST_SIZE);
+ su_md5_deinit(md5);
+
+ su_md5_init(md5);
+ su_md5_iupdate(md5, suite[2].input, 3);
+ su_md5_digest(md5, digest);
+ TEST_M(digest, suite[2].digest, SU_MD5_DIGEST_SIZE);
+ su_md5_deinit(md5);
+
+ su_md5_init(md5);
+ su_md5_striupdate(md5, suite[3].input);
+ su_md5_digest(md5, digest);
+ TEST_M(digest, suite[3].digest, SU_MD5_DIGEST_SIZE);
+ su_md5_deinit(md5);
+
+ su_md5_init(md5);
+ su_md5_iupdate(md5, suite[4].input, 13);
+ su_md5_striupdate(md5, suite[4].input + 13);
+ su_md5_digest(md5, digest);
+ TEST_M(digest, suite[4].digest, SU_MD5_DIGEST_SIZE);
+ su_md5_deinit(md5);
+
+ su_md5_init(md5);
+ su_md5_update(md5, suite[5].input, 13);
+ su_md5_strupdate(md5, suite[5].input + 13);
+ su_md5_digest(md5, digest);
+ TEST_M(digest, suite[5].digest, SU_MD5_DIGEST_SIZE);
+ su_md5_deinit(md5);
+
+ su_md5_init(md5);
+ su_md5_update(md5, suite[6].input, 13);
+ su_md5_strupdate(md5, suite[6].input + 13);
+ su_md5_digest(md5, digest);
+ TEST_M(digest, suite[6].digest, SU_MD5_DIGEST_SIZE);
+ su_md5_deinit(md5);
+
+ su_md5_init(md5);
+ su_md5_str0update(md5, NULL);
+ su_md5_hexdigest(md5, hexdigest);
+ TEST_S(hexdigest, "93b885adfe0da089cdf634904fd59f71");
+ su_md5_deinit(md5);
+
+ su_md5_init(md5);
+ su_md5_stri0update(md5, NULL);
+ su_md5_stri0update(md5, "ABBADABBADOO");
+ su_md5_hexdigest(md5, hexdigest);
+ TEST_S(hexdigest, "101e6dd7cfabdb5c74f44b4c545c05cc");
+
+ su_md5_init(md5);
+ su_md5_update(md5, "\0abbadabbadoo\0", 14);
+ su_md5_hexdigest(md5, hexdigest);
+ TEST_S(hexdigest, "101e6dd7cfabdb5c74f44b4c545c05cc");
+ su_md5_deinit(md5);
+
+ /* Calculate md5 sum of 512 MB of zero */
+ if (getenv("EXPENSIVE_CHECKS")) {
+ char zerokilo[1024] = { '\0' };
+ int i;
+
+ su_md5_init(md5);
+ su_md5_iupdate(md5, zerokilo, 19);
+ for (i = 1; i < 512 * 1024; i++)
+ su_md5_update(md5, zerokilo, 1024);
+ *md5i = *md5;
+
+ su_md5_update(md5, zerokilo, 1024 - 19);
+ su_md5_hexdigest(md5, hexdigest);
+ TEST_S(hexdigest, "aa559b4e3523a6c931f08f4df52d58f2");
+ su_md5_deinit(md5);
+
+ su_md5_iupdate(md5i, zerokilo, 1024 - 19);
+ su_md5_hexdigest(md5i, hexdigest);
+ TEST_S(hexdigest, "aa559b4e3523a6c931f08f4df52d58f2");
+ }
+ END();
+}
+
+int main(int argc, char *argv[])
+{
+ int retval = 0;
+ int i;
+
+ su_init();
+
+ for (i = 1; argv[i]; i++) {
+ if (strcmp(argv[i], "-v") == 0)
+ tstflags |= tst_verbatim;
+ else
+ usage();
+ }
+
+ retval |= test_sockaddr();
+ retval |= test_sendrecv();
+ retval |= test_md5(); fflush(stdout);
+
+ su_deinit();
+
+ return retval;
+}
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_alloc.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_alloc.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,683 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_alloc
+ *
+ * @file su_alloc_test.c
+ *
+ * Testing functions for su_alloc functions.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu May 2 18:17:46 2002 ppessi
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <sofia-sip/su_alloc.h>
+#include <sofia-sip/su_strlst.h>
+#include <sofia-sip/su_alloc_stat.h>
+
+#define TSTFLAGS tstflags
+#include <sofia-sip/tstdef.h>
+
+int tstflags;
+
+char const *name = "su_alloc_test";
+
+/* Type derived from home */
+typedef struct { su_home_t home[1]; int *p; } exhome_t;
+
+void exdestructor(void *arg)
+{
+ exhome_t *ex = arg;
+ (*ex->p)++;
+}
+
+/** Test basic memory home operations */
+static int test_alloc(void)
+{
+ exhome_t *h0, *h1, *h2, *h3;
+ su_home_t home[1] = { SU_HOME_INIT(home) };
+ enum { N = 40 };
+ void *m0[N], *m1[N], *m;
+ char *c, *c0, *p0, *p1;
+ int i;
+ enum { destructed_once = 1 };
+ int d0, d1a, d1, d2, d3;
+
+ BEGIN();
+
+ TEST_1(h0 = su_home_new(sizeof(*h0)));
+ TEST_1(h1 = su_home_clone(h0->home, sizeof(*h1)));
+
+ d0 = d1a = d1 = d2 = d3 = 0;
+ h0->p = &d0; h1->p = &d1a;
+ TEST(su_home_desctructor(h0->home, exdestructor), 0);
+ TEST(su_home_desctructor(h1->home, exdestructor), 0);
+
+ TEST_1(h2 = su_home_ref(h0->home));
+ su_home_unref(h0->home);
+ TEST(d0, 0);
+
+ for (i = 0; i < 128; i++)
+ TEST_1(su_alloc(h0->home, 16));
+
+ for (i = 0; i < 128; i++)
+ TEST_1(su_alloc(h1->home, 16));
+
+ su_home_unref(h1->home);
+ TEST(d1a, destructed_once);
+
+ TEST_1(h1 = su_home_clone(h0->home, sizeof(*h1)));
+ TEST(su_home_desctructor(h1->home, exdestructor), 0);
+ h1->p = &d1;
+
+ for (i = 0; i < 128; i++)
+ TEST_1(su_alloc(h1->home, 16));
+
+ for (i = 0; i < 128; i++)
+ TEST_1(su_alloc(h2->home, 16));
+
+ su_home_unref(h2->home); /* Should call destructor of cloned home, too */
+
+ TEST(d0, destructed_once);
+ TEST(d1, destructed_once);
+
+ TEST_1(h0 = su_home_new(sizeof(*h0)));
+ TEST_1(h1 = su_home_clone(h0->home, sizeof(*h1)));
+ TEST_1(h2 = su_home_clone(h1->home, sizeof(*h2)));
+ TEST_1(h3 = su_home_clone(h2->home, sizeof(*h3)));
+
+ TEST(su_home_threadsafe(h0->home), 0);
+
+ for (i = 0; i < N; i++) {
+ TEST_1(m0[i] = su_zalloc(h3->home, 20));
+ TEST_1(m1[i] = su_zalloc(h2->home, 20));
+ }
+
+ TEST_1(m = su_zalloc(h2->home, 20));
+
+ TEST_1(su_in_home(h2->home, m));
+ TEST_1(!su_in_home(h2->home, (char *)m + 1));
+ TEST_1(!su_in_home(h2->home, su_in_home));
+ TEST_1(!su_in_home(h3->home, m));
+ TEST_1(!su_in_home(NULL, m));
+ TEST_1(!su_in_home(h3->home, NULL));
+
+ TEST(su_home_move(home, NULL), 0);
+ TEST(su_home_move(NULL, home), 0);
+ TEST(su_home_move(home, h3->home), 0);
+ TEST(su_home_move(h2->home, h3->home), 0);
+ TEST(su_home_move(h1->home, h2->home), 0);
+
+ su_home_preload(home, 1, 1024 + 2 * 8);
+
+ TEST_1(c = su_zalloc(home, 64)); p0 = c; p1 = c + 1024;
+ TEST_P(c = su_realloc(home, c0 = c, 127), c0);
+
+ TEST_1(c = c0 = su_zalloc(home, 1024 - 128));
+ TEST_1(p0 <= c); TEST_1(c < p1);
+ TEST_P(c = su_realloc(home, c, 128), c0);
+ TEST_P(c = su_realloc(home, c, 1023 - 128), c0);
+ TEST_P(c = su_realloc(home, c, 1024 - 128), c0);
+ TEST_1(c = su_realloc(home, c, 1024));
+ TEST_1(c = su_realloc(home, c, 2 * 1024));
+
+ TEST_P(c = su_realloc(home, p0, 126), p0);
+ TEST_1(c = su_realloc(home, p0, 1024));
+ TEST_P(c = su_realloc(home, c, 0), NULL);
+
+ su_home_check(home);
+ su_home_deinit(home);
+
+ su_home_check(h2->home);
+ su_home_zap(h2->home);
+ su_home_check(h0->home);
+ su_home_zap(h0->home);
+
+ END();
+}
+
+static int test_strdupcat(void)
+{
+ su_home_t home[1] = { SU_HOME_INIT(home) };
+
+ BEGIN();
+
+ TEST_S(su_strdup(home, "foo"), "foo");
+ TEST_S(su_strcat(home, "foo", "bar"), "foobar");
+ TEST_S(su_strndup(home, "foobar", 3), "foo");
+
+ TEST_S(su_strcat_all(home, NULL), "");
+ TEST_S(su_strcat_all(home, "a", "", "b", "", NULL), "ab");
+
+ su_home_deinit(home);
+
+ END();
+}
+
+#include <stdarg.h>
+
+static int test_sprintf(char const *fmt, ...)
+{
+ BEGIN();
+
+ su_home_t home[1] = { SU_HOME_INIT(home) };
+ va_list va;
+
+ TEST_S(su_sprintf(home, "foo%s", "bar"), "foobar");
+
+ va_start(va, fmt);
+ TEST_S(su_vsprintf(home, fmt, va), "foo.bar");
+
+ TEST_S(su_sprintf(home, "foo%200s", "bar"),
+ "foo "
+ " "
+ " "
+ " bar");
+
+ su_home_deinit(home);
+
+ END();
+}
+
+static int test_strlst(void)
+{
+ su_home_t home[1] = { SU_HOME_INIT(home) };
+ su_strlst_t *l, *l1, *l2;
+ char *s;
+ char foo[] = "foo";
+ char bar[] = "bar";
+ char baz[] = "baz";
+
+ su_home_stat_t parent[1], kids[2];
+
+ BEGIN();
+
+ parent->hs_size = (sizeof parent);
+ kids[0].hs_size = (sizeof kids[0]);
+ kids[1].hs_size = (sizeof kids[1]);
+
+ su_home_init_stats(home);
+
+ /* Test API for invalid arguments */
+ TEST_1(l = su_strlst_create(NULL));
+ TEST_1(l2 = su_strlst_dup(home, l));
+ TEST_VOID(su_strlst_destroy(l2));
+ TEST_1(!su_strlst_dup(home, NULL));
+ TEST_1(l1 = su_strlst_copy(home, l));
+ TEST_VOID(su_strlst_destroy(l1));
+ TEST_1(!su_strlst_copy(home, NULL));
+
+ TEST_VOID(su_strlst_destroy(NULL));
+ TEST_VOID(su_strlst_destroy(l));
+
+ TEST_1(!su_strlst_dup_append(NULL, "aa"));
+ TEST_1(!su_strlst_append(NULL, "bee"));
+ TEST_1(!su_strlst_item(NULL, 1));
+ TEST_1(!su_strlst_set_item(NULL, 1, "cee"));
+ TEST_1(!su_strlst_remove(NULL, 1));
+ TEST_S(s = su_strlst_join(NULL, home, "a"), "");
+ TEST_VOID(su_free(home, s));
+
+ TEST_1(!su_strlst_split(home, NULL, "."));
+
+ TEST_1(s = su_strdup(home, "aaa"));
+ TEST_1(l = su_strlst_split(home, s, NULL));
+ TEST_S(su_strlst_item(l, 0), "aaa");
+ TEST_VOID(su_strlst_destroy(l));
+
+ TEST_VOID(su_free(home, s));
+
+ TEST_1(!su_strlst_dup_split(home, NULL, "."));
+
+ TEST_1(l1 = su_strlst_dup_split(home, "aaa", ""));
+ TEST_S(su_strlst_item(l1, 0), "aaa");
+ TEST_VOID(su_strlst_destroy(l1));
+
+ TEST_SIZE(su_strlst_len(NULL), 0);
+ TEST_1(!su_strlst_get_array(NULL));
+ TEST_VOID(su_strlst_free_array(NULL, NULL));
+
+ TEST_1(l = su_strlst_create(home));
+ TEST_VOID(su_strlst_free_array(l, NULL));
+ TEST_S(su_strlst_dup_append(l, "oh"), "oh");
+ TEST_VOID(su_strlst_free_array(l, NULL));
+ TEST_VOID(su_strlst_destroy(l));
+
+ /* Test functionality */
+ TEST_1(l = su_strlst_create(home));
+
+ su_home_init_stats(su_strlst_home(l));
+
+ TEST_S(su_strlst_join(l, home, "bar"), "");
+ TEST_S(su_strlst_append(l, foo), "foo");
+ TEST_S(su_strlst_dup_append(l, bar), "bar");
+ TEST_S(su_strlst_append(l, baz), "baz");
+ TEST_S((s = su_strlst_join(l, home, "!")), "foo!bar!baz");
+
+ TEST_S(su_strlst_item(l, 0), foo);
+ TEST_S(su_strlst_item(l, 1), bar);
+ TEST_S(su_strlst_item(l, 2), baz);
+ TEST_P(su_strlst_item(l, 3), NULL);
+ TEST_P(su_strlst_item(l, (unsigned)-1), NULL);
+
+ TEST_1(l1 = su_strlst_copy(su_strlst_home(l), l));
+ TEST_1(l2 = su_strlst_dup(su_strlst_home(l), l));
+
+ strcpy(foo, "hum"); strcpy(bar, "pah"); strcpy(baz, "hah");
+
+ TEST_S(su_strlst_dup_append(l1, "kuik"), "kuik");
+ TEST_S(su_strlst_dup_append(l2, "uik"), "uik");
+
+ TEST_S((s = su_strlst_join(l, home, ".")), "hum.bar.hah");
+ TEST_S((su_strlst_join(l1, home, ".")), "hum.bar.hah.kuik");
+ TEST_S((su_strlst_join(l2, home, ".")), "foo.bar.baz.uik");
+
+ su_strlst_destroy(l2);
+
+ su_home_get_stats(su_strlst_home(l), 0, kids, sizeof kids);
+
+ TEST_SIZE(kids->hs_clones, 2);
+ TEST64(kids->hs_allocs.hsa_number, 3);
+ TEST64(kids->hs_frees.hsf_number, 1);
+
+ su_strlst_destroy(l);
+
+ TEST_S(s, "hum.bar.hah");
+
+ TEST_1(l = su_strlst_create(home));
+
+ su_home_init_stats(su_strlst_home(l));
+
+ TEST_S(su_strlst_join(l, home, "bar"), "");
+ TEST_S(su_strlst_append(l, "a"), "a");
+ TEST_S(su_strlst_append(l, "b"), "b");
+ TEST_S(su_strlst_append(l, "c"), "c");
+ TEST_S(su_strlst_append(l, "d"), "d");
+ TEST_S(su_strlst_append(l, "e"), "e");
+ TEST_S(su_strlst_append(l, "f"), "f");
+ TEST_S(su_strlst_append(l, "g"), "g");
+ TEST_S(su_strlst_append(l, "h"), "h");
+ TEST_S(su_strlst_append(l, "i"), "i");
+ TEST_S(su_strlst_append(l, "j"), "j");
+
+ TEST_S((s = su_strlst_join(l, home, "")), "abcdefghij");
+ TEST_S(su_strlst_append(l, "a"), "a");
+ TEST_S(su_strlst_append(l, "b"), "b");
+ TEST_S(su_strlst_append(l, "c"), "c");
+ TEST_S(su_strlst_append(l, "d"), "d");
+ TEST_S(su_strlst_append(l, "e"), "e");
+ TEST_S(su_strlst_append(l, "f"), "f");
+ TEST_S(su_strlst_append(l, "g"), "g");
+ TEST_S(su_strlst_append(l, "h"), "h");
+ TEST_S(su_strlst_append(l, "i"), "i");
+ TEST_S(su_strlst_append(l, "j"), "j");
+
+ TEST_S((s = su_strlst_join(l, home, "")), "abcdefghijabcdefghij");
+
+ su_home_get_stats(su_strlst_home(l), 0, kids + 1, (sizeof kids[1]));
+ su_home_stat_add(kids, kids + 1);
+
+ su_strlst_destroy(l);
+
+ su_home_get_stats(home, 1, parent, (sizeof parent));
+
+ su_home_check(home);
+ su_home_deinit(home);
+
+ su_home_init(home);
+
+ {
+ char s[] = "foo\nfaa\n";
+ TEST_1((l = su_strlst_split(home, s, "\n")));
+ TEST_SIZE(su_strlst_len(l), 3);
+ TEST_1(su_strlst_append(l, "bar"));
+ TEST_S(su_strlst_join(l, home, "\n"), "foo\nfaa\n\nbar");
+ }
+
+ {
+ char s[] = "foo";
+ TEST_1((l = su_strlst_split(home, s, "\n")));
+ TEST_SIZE(su_strlst_len(l), 1);
+ }
+
+ {
+ char s[] = "\n\n";
+ TEST_1((l = su_strlst_split(home, s, "\n")));
+ TEST_SIZE(su_strlst_len(l), 3);
+ }
+
+ {
+ char s[] = "";
+ TEST_1((l = su_strlst_split(home, s, "\n")));
+ TEST_SIZE(su_strlst_len(l), 1);
+ }
+
+ {
+ int i;
+
+#define S \
+ "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\n" \
+ "n\no\np\nq\nr\ns\nt\nu\nv\nw\nx\ny\nz\n" \
+ "A\nB\nC\nD\nE\nF\nG\nH\nI\nJ\nK\nL\nM\n" \
+ "N\nO\nP\nQ\nR\nS\nT\nU\nV\nW\nX\nY\nZ\n"
+
+ char s[] = S;
+
+ TEST_1((l = su_strlst_split(home, s, "\n")));
+ TEST_SIZE(su_strlst_len(l), 53);
+ TEST_1(su_strlst_append(l, "bar"));
+ TEST_S(su_strlst_join(l, home, "\n"), S "\nbar");
+
+ TEST_1(!su_strlst_remove(l, 54));
+
+ for (i = 0; i < 54; i++) {
+ TEST_1(su_strlst_remove(l, 0));
+ TEST_1(!su_strlst_remove(l, 53 - i));
+ TEST_SIZE(su_strlst_len(l), 53 - i);
+ }
+
+ TEST_1(!su_strlst_remove(l, 0));
+ TEST_SIZE(su_strlst_len(l), 0);
+ }
+
+ {
+ char const *s0;
+
+ TEST_1(l = su_strlst_create_with(NULL, s0 = "a", "b", NULL));
+ TEST_1(su_strlst_item(l, 0) == s0);
+ TEST_S(su_strlst_item(l, 0), "a");
+ TEST_S(su_strlst_item(l, 1), "b");
+ TEST_1(su_strlst_item(l, 2) == NULL);
+
+ TEST_S(su_slprintf(l, "1: %u", 1), "1: 1");
+ TEST_S(su_slprintf(l, "1.0: %g", 1.0), "1.0: 1");
+
+ TEST_1(su_strlst_append(l, ""));
+
+ TEST_S(su_strlst_join(l, home, "\n"),
+ "a\n" "b\n" "1: 1\n" "1.0: 1\n");
+
+ TEST_VOID(su_strlst_destroy(l));
+
+ TEST_1(l2 = su_strlst_create_with_dup(NULL,
+ s0 = "0", "1", "2", "3",
+ "4", "5", "6", "7",
+ NULL));
+ TEST_1(su_strlst_item(l2, 0) != s0);
+ TEST_S(su_strlst_item(l2, 0), "0");
+ TEST_S(su_strlst_item(l2, 1), "1");
+ TEST_S(su_strlst_item(l2, 2), "2");
+ TEST_S(su_strlst_item(l2, 3), "3");
+ TEST_S(su_strlst_item(l2, 4), "4");
+ TEST_S(su_strlst_item(l2, 5), "5");
+ TEST_S(su_strlst_item(l2, 6), "6");
+ TEST_S(su_strlst_item(l2, 7), "7");
+ TEST_1(su_strlst_item(l2, 8) == NULL);
+
+ TEST_S(su_strlst_join(l2, home, ""), "01234567");
+
+ TEST_VOID(su_strlst_destroy(l2));
+ }
+ su_home_check(home);
+ su_home_deinit(home);
+
+ END();
+}
+
+#include <sofia-sip/su_vector.h>
+
+typedef struct test_data_s {
+ su_home_t test_home[1];
+ int data;
+} test_data_t;
+
+static void test_vector_free(void *data)
+{
+ su_home_zap((su_home_t *) data);
+}
+
+static int test_vectors(void)
+{
+ su_home_t home[1] = { SU_HOME_INIT(home) };
+ su_vector_t *v, *w;
+ test_data_t *data1, *data2, *data3, *data4;
+ char foo[] = "foo";
+ char bar[] = "bar";
+ char baz[] = "baz";
+ void **a;
+ int i;
+
+ BEGIN();
+
+ TEST_1(v = su_vector_create(home, NULL));
+ TEST_1(su_vector_is_empty(v));
+ TEST(su_vector_append(v, foo), 0);
+ TEST(su_vector_append(v, bar), 0);
+ TEST(su_vector_insert(v, 0, baz), 0);
+
+ TEST_P(su_vector_item(v, 0), baz);
+ TEST_P(su_vector_item(v, 1), foo);
+ TEST_P(su_vector_item(v, 2), bar);
+ TEST_P(su_vector_item(v, 3), NULL);
+ TEST_P(su_vector_item(v, (unsigned)-1), NULL);
+ TEST_1(!su_vector_is_empty(v));
+
+ su_vector_destroy(v);
+
+ TEST_1(v = su_vector_create(home, NULL));
+ TEST(su_vector_insert(v, 0, "j"), 0);
+ TEST(su_vector_insert(v, 0, "i"), 0);
+ TEST(su_vector_insert(v, 0, "h"), 0);
+ TEST(su_vector_insert(v, 0, "g"), 0);
+ TEST(su_vector_insert(v, 0, "f"), 0);
+ TEST(su_vector_insert(v, 0, "e"), 0);
+ TEST(su_vector_insert(v, 0, "d"), 0);
+ TEST(su_vector_insert(v, 0, "c"), 0);
+ TEST(su_vector_insert(v, 0, "b"), 0);
+ TEST(su_vector_insert(v, 0, "a"), 0);
+
+ TEST_SIZE(su_vector_len(v), 10);
+ TEST_1(a = su_vector_get_array(v));
+
+ for (i = 0; i < 10; i++) {
+ TEST_S(su_vector_item(v, i), a[i]);
+ }
+
+ TEST_P(su_vector_item(v, 10), NULL);
+ TEST_P(a[10], NULL);
+
+ TEST_1(w = su_vector_create(home, NULL));
+ TEST(su_vector_append(w, "a"), 0);
+ TEST(su_vector_append(w, "b"), 0);
+ TEST(su_vector_append(w, "c"), 0);
+ TEST(su_vector_append(w, "d"), 0);
+ TEST(su_vector_append(w, "e"), 0);
+ TEST(su_vector_append(w, "f"), 0);
+ TEST(su_vector_append(w, "g"), 0);
+ TEST(su_vector_append(w, "h"), 0);
+ TEST(su_vector_append(w, "i"), 0);
+ TEST(su_vector_append(w, "j"), 0);
+
+ TEST_SIZE(su_vector_len(w), 10);
+
+ for (i = 0; i < 10; i++) {
+ TEST_S(su_vector_item(v, i), a[i]);
+ }
+
+ su_vector_empty(w);
+ TEST_1(su_vector_is_empty(w));
+
+ su_vector_destroy(v);
+ su_vector_destroy(w);
+
+ TEST_1(v = su_vector_create(home, test_vector_free));
+ data1 = su_home_clone(home, sizeof(test_data_t));
+ data1->data = 1;
+
+ data2 = su_home_clone(home, sizeof(test_data_t));
+ data2->data = 2;
+
+ data3 = su_home_clone(home, sizeof(test_data_t));
+ data3->data = 3;
+
+ data4 = su_home_clone(home, sizeof(test_data_t));
+ data4->data = 4;
+
+ TEST(su_vector_append(v, data1), 0);
+ TEST(su_vector_append(v, data2), 0);
+ TEST(su_vector_append(v, data3), 0);
+ TEST(su_vector_append(v, data4), 0);
+
+ TEST_SIZE(su_vector_len(v), 4);
+
+ TEST_P(su_vector_item(v, 0), data1);
+ TEST_P(su_vector_item(v, 1), data2);
+ TEST_P(su_vector_item(v, 2), data3);
+ TEST_P(su_vector_item(v, 3), data4);
+
+ TEST(data1->data, 1);
+ TEST(data2->data, 2);
+ TEST(data3->data, 3);
+ TEST(data4->data, 4);
+
+ TEST(su_vector_remove(v, 2), 0);
+
+ TEST_SIZE(su_vector_len(v), 3);
+
+ TEST_P(su_vector_item(v, 0), data1);
+ TEST_P(su_vector_item(v, 1), data2);
+ TEST_P(su_vector_item(v, 2), data4);
+
+ TEST(data1->data, 1);
+ TEST(data2->data, 2);
+ TEST(data4->data, 4);
+
+ su_vector_destroy(v);
+
+ su_home_check(home);
+ su_home_deinit(home);
+
+ END();
+}
+
+#define ALIGNMENT (8)
+#define ALIGN(n) ((size_t)((n) + (ALIGNMENT - 1)) & (size_t)~(ALIGNMENT - 1))
+
+static int test_auto(void)
+{
+ BEGIN();
+
+ int i;
+ su_home_t tmphome[SU_HOME_AUTO_SIZE(8000)];
+ char *b = NULL;
+ su_home_stat_t hs[1];
+
+ TEST_1(!su_home_auto(tmphome, sizeof tmphome[0]));
+ TEST_1(su_home_auto(tmphome, sizeof tmphome));
+
+ for (i = 0; i < 8192; i++)
+ TEST_1(su_alloc(tmphome, 12));
+
+ TEST_VOID(su_home_deinit(tmphome));
+
+ TEST_1(su_home_auto(tmphome, sizeof tmphome));
+
+ su_home_init_stats(tmphome);
+
+ for (i = 1; i < 8192; i++) {
+ TEST_1(b = su_realloc(tmphome, b, i));
+ b[i - 1] = '\125';
+ }
+
+ for (i = 1; i < 8192; i++) {
+ TEST(b[i - 1], '\125');
+ }
+
+ for (i = 1; i < 8192; i++) {
+ TEST_1(b = su_realloc(tmphome, b, i));
+ b[i - 1] = '\125';
+
+ if ((i % 32) == 0)
+ TEST_1(b = su_realloc(tmphome, b, 1));
+ }
+
+ su_home_get_stats(tmphome, 0, hs, sizeof *hs);
+
+ TEST64(hs->hs_allocs.hsa_preload + hs->hs_allocs.hsa_number,
+ 8191 + 8191 + 8191 / 32);
+ TEST64(hs->hs_frees.hsf_preload + hs->hs_frees.hsf_number,
+ 8191 + 8191 + 8191 / 32 - 1);
+ /*
+ This test depends on macro SU_HOME_AUTO_SIZE() calculating
+ offsetof(su_block_t, sub_nodes[7]) correctly with
+
+ ((3 * sizeof (void *) + 4 * sizeof(unsigned) +
+ 7 * (sizeof (long) + sizeof(void *)) + 7)
+ */
+ TEST_1(hs->hs_frees.hsf_preload == hs->hs_allocs.hsa_preload);
+
+ su_free(tmphome, b);
+
+ for (i = 1; i < 8192; i++)
+ TEST_1(b = su_alloc(tmphome, 1));
+
+ TEST_VOID(su_home_deinit(tmphome));
+
+ END();
+}
+
+void usage(void)
+{
+ fprintf(stderr, "usage: %s [-v]\n", name);
+}
+
+int main(int argc, char *argv[])
+{
+ int retval = 0;
+ int i;
+
+ for (i = 1; argv[i]; i++) {
+ if (strcmp(argv[i], "-v") == 0)
+ tstflags |= tst_verbatim;
+ else
+ usage();
+ }
+
+ retval |= test_alloc();
+ retval |= test_strdupcat();
+ retval |= test_sprintf("%s.%s", "foo", "bar");
+ retval |= test_strlst();
+ retval |= test_vectors();
+ retval |= test_auto();
+
+ return retval;
+}
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_bm.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_bm.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,245 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**
+ * @file torture_su_bm.c
+ * @brief Test string search with Boyer-Moore algorithm
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @date Created: Sun Apr 17 21:02:10 2005 ppessi
+ */
+
+#include "config.h"
+
+#define TSTFLAGS tstflags
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <sofia-sip/tstdef.h>
+
+char const *name = "torture_su_bm";
+int tstflags;
+
+#define TORTURELOG(x) \
+ do { \
+ if (tstflags & (2 * tst_verbatim)) \
+ printf x; \
+ } while(0)
+
+#include "su_bm.c"
+
+int test_bm(void)
+{
+ BEGIN();
+
+ {
+ char const hs[] =
+ "A Boyer-Moore string searching test consisting of a Long String";
+ char const *s;
+
+ s = bm_memmem(hs, strlen(hs), "sting", 5, NULL);
+
+ TEST_S(s, hs + 41);
+
+ s = bm_memmem(hs, strlen(hs), "String", 6, NULL);
+ TEST_S(s, hs + 57);
+
+ s = bm_memmem(hs, strlen(hs), "S", 1, NULL);
+ TEST_S(s, hs + 57);
+
+ s = bm_memmem(hs, strlen(hs), "M", 1, NULL);
+ TEST_S(s, hs + 8);
+
+ s = bm_memcasemem(hs, strlen(hs), "M", 1, NULL);
+ TEST_S(s, hs + 8);
+
+ s = bm_memcasemem(hs, strlen(hs), "trings", 6, NULL);
+ TEST_1(s == NULL);
+
+ s = bm_memcasemem(hs, strlen(hs), "String", 6, NULL);
+ TEST_S(s, hs + 14);
+
+ s = bm_memcasemem(hs, strlen(hs), "StRiNg", 6, NULL);
+ TEST_S(s, hs + 14);
+
+ s = bm_memcasemem(hs, strlen(hs), "OnG", 3, NULL);
+ TEST_S(s, hs + 53);
+
+ /* Special cases */
+ TEST_1(bm_memmem(hs, strlen(hs), "", 0, NULL) == hs);
+ TEST_1(bm_memmem(NULL, strlen(hs), "ong", 3, NULL) == NULL);
+ TEST_1(bm_memmem(hs, strlen(hs), NULL, 1, NULL) == NULL);
+ TEST_1(bm_memmem("ong", 3, hs, strlen(hs), NULL) == NULL);
+ TEST_1(bm_memmem(hs, 0, "ong", 3, NULL) == NULL);
+ TEST_1(bm_memmem(hs, strlen(hs), "Z", 1, NULL) == NULL);
+
+ TEST_1(bm_memcasemem(hs, strlen(hs), "", 0, NULL) == hs);
+ TEST_1(bm_memcasemem(NULL, strlen(hs), "OnG", 3, NULL) == NULL);
+ TEST_1(bm_memcasemem(hs, strlen(hs), NULL, 1, NULL) == NULL);
+ TEST_1(bm_memcasemem("OnG", 3, hs, strlen(hs), NULL) == NULL);
+ TEST_1(bm_memcasemem(hs, 0, "OnG", 3, NULL) == NULL);
+ TEST_1(bm_memcasemem(hs, strlen(hs), "Z", 1, NULL) == NULL);
+ }
+
+ END();
+}
+
+int test_bm_long(void)
+{
+ BEGIN();
+
+ {
+ char const hs[] =
+"A Boyer-Moore string searching test consisting of a Very Long String\n"
+
+"Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Integer felis. "
+"Suspendisse potenti. Morbi malesuada erat eget enim. Sed dui lorem, aliquam "
+"eu, lobortis eget, dapibus vitae, velit. Cras non purus. Suspendisse massa. "
+"Curabitur gravida condimentum massa. Donec nunc magna, lacinia non, "
+"pellentesque ac, laoreet vel, eros. Praesent lectus leo, vestibulum eu, "
+"tempus eu, ullamcorper tristique, mi. Duis fringilla ultricies lacus. Ut "
+"non pede. Donec id libero. Cum sociis natoque penatibus et magnis dis "
+"parturient montes, nascetur ridiculus mus. Phasellus bibendum.\n"
+
+"Vestibulum turpis. Nunc euismod. Maecenas venenatis, purus at pharetra "
+"ultrices, orci orci blandit nisl, eget vulputate enim tortor sed nunc. "
+"Proin sit amet elit. Donec ut justo. In quis nisi. Praesent posuere. "
+"Maecenas porta. Curabitur pharetra. Class aptent taciti sociosqu ad litora "
+"torquent per conubia nostra, per inceptos hymenaeos. Donec suscipit ligula. "
+"Quisque facilisis ante eget mi. Nunc ac est.\n"
+
+"Quisque in sapien eget justo aliquam laoreet. Nullam ultricies est id dolor. "
+"Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Suspendisse ante "
+"velit, eleifend at, ullamcorper ut, rutrum et, ipsum. Mauris luctus, tellus "
+"non elementum convallis, nunc ipsum hendrerit lectus, ut lacinia elit nulla "
+"ac tellus. In sit amet velit. Maecenas non dolor. Sed commodo diam a pede. "
+"Ut non pede. Vestibulum condimentum turpis vel lacus consectetuer dictum. "
+"Nulla ullamcorper mi eu pede. Donec mauris tortor, facilisis vitae, "
+"hendrerit nec, lobortis nec, eros. Nam sit amet mi. Ut pharetra, orci nec "
+"porta convallis, lacus velit blandit sapien, luctus nonummy lacus dolor vel "
+"sapien. Suspendisse placerat. Donec ante turpis, volutpat eu, hendrerit "
+"vel, eleifend ac, arcu. Nulla facilisi. Sed faucibus facilisis lectus. "
+"Aliquam congue justo nec dui.\n"
+
+"Donec dapibus dui sed nisl. Proin congue. Curabitur placerat diam id eros. "
+"Pellentesque vitae nulla. Quisque at lorem et dolor auctor consequat. Sed "
+"sed tellus non nibh imperdiet venenatis. Integer ultrices dapibus nisi. "
+"Aenean vehicula malesuada risus. Fusce egestas malesuada leo. In "
+"ullamcorper pretium lorem. Vestibulum ante ipsum primis in faucibus orci "
+"luctus et ultrices posuere cubilia Curae;\n"
+
+"Phasellus congue. Morbi lectus arcu, mattis non, pulvinar et, condimentum "
+"non, mi. Suspendisse vestibulum nunc eu neque. Sed rutrum felis aliquam "
+"urna. Ut tincidunt orci vitae ipsum. Nullam eros. Quisque augue. Quisque "
+"lacinia. Nunc ligula diam, nonummy a, porta in, tristique quis, leo. "
+"Phasellus nunc nulla, fringilla vel, lacinia et, suscipit a, turpis. "
+"Integer a est. Curabitur mauris lacus, vehicula sit amet, sodales vel, "
+"iaculis vitae, massa. Nam diam est, ultrices vitae, varius et, tempor a, "
+"leo. Class aptent taciti sociosqu ad litora torquent per conubia nostra, "
+"per inceptos hymenaeos. Fusce felis nibh, ullamcorper non, malesuada eget, "
+ "facilisis vel, purus.\n";
+
+char const needle[] =
+"Proin congue. Curabitur placerat diam id eros. "
+"Pellentesque vitae nulla. Quisque at lorem et dolor auctor consequat. Sed "
+"sed tellus non nibh imperdiet venenatis. Integer ultrices dapibus nisi. "
+"Aenean vehicula malesuada risus. Fusce egestas malesuada leo. In "
+"ullamcorper pretium lorem. Vestibulum ante ipsum primis in faucibus orci "
+"luctus et ultrices posuere cubilia Curae;\n";
+
+char const Needle[] =
+"PROIN CONGUE. CURABITUR PLACERAT DIAM ID EROS. "
+"PELLENTESQUE VITAE NULLA. QUISQUE AT LOREM ET DOLOR AUCTOR CONSEQUAT. SED "
+"SED TELLUS NON NIBH IMPERDIET VENENATIS. INTEGER ULTRICES DAPIBUS NISI. "
+"AENEAN VEHICULA MALESUADA RISUS. FUSCE EGESTAS MALESUADA LEO. IN "
+"ULLAMCORPER PRETIUM LOREM. VESTIBULUM ANTE IPSUM PRIMIS IN FAUCIBUS ORCI "
+"LUCTUS ET ULTRICES POSUERE CUBILIA CURAE;\n";
+
+ size_t nlen = strlen(needle);
+
+ bm_fwd_table_t *fwd;
+
+ char const *s;
+
+ s = bm_memmem(hs, strlen(hs), needle, nlen, NULL);
+
+ TEST_S(s, hs + 1919);
+
+ fwd = bm_memmem_study(needle, nlen);
+
+ s = bm_memmem(hs, strlen(hs), needle, nlen, fwd);
+
+ TEST_S(s, hs + 1919);
+
+ TEST_1(bm_memmem(hs, strlen(hs), Needle, nlen, NULL) == 0);
+
+ s = bm_memcasemem(hs, strlen(hs), Needle, nlen, NULL);
+
+ fwd = bm_memcasemem_study(Needle, nlen);
+
+ s = bm_memcasemem(hs, strlen(hs), Needle, nlen, fwd);
+
+ TEST_S(s, hs + 1919);
+
+ free(fwd);
+ }
+
+ END();
+}
+
+
+void usage(void)
+{
+ fprintf(stderr,
+ "usage: %s [-v]\n",
+ name);
+}
+
+int main(int argc, char *argv[])
+{
+ int retval = 0;
+ int i;
+
+ /* Set our name */
+ if (strchr(argv[0], '/'))
+ name = strrchr(argv[0], '/') + 1;
+ else
+ name = argv[0];
+
+ for (i = 1; argv[i]; i++) {
+ if (strcmp(argv[i], "-v") == 0)
+ tstflags |= tst_verbatim;
+ else if (strcmp(argv[i], "-l") == 0)
+ tstflags |= 2 * tst_verbatim;
+ else
+ usage();
+ }
+
+ retval |= test_bm(); fflush(stdout);
+ retval |= test_bm_long(); fflush(stdout);
+
+ return retval;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_port.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_port.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,333 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**
+ * @file torture_su_port.c
+ * @brief Test su_port interface
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @date Created: Wed Mar 10 17:05:23 2004 ppessi
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+struct su_root_magic_s;
+
+#define SU_ROOT_MAGIC_T struct su_root_magic_s
+
+#include "su_port.c"
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+static char const __func__[] = "torture_su_port";
+#endif
+
+int tstflags;
+
+#define TSTFLAGS tstflags
+
+#include <sofia-sip/tstdef.h>
+
+char const *name = "torture_su_port";
+
+int N0 = SU_HAVE_MBOX, N = 128, I = 128 + 1;
+
+int test_sup_indices(su_port_t const *port)
+{
+ int i, n;
+ int *indices = port->sup_indices;
+ int *reverses = port->sup_reverses;
+ int N = port->sup_size_waits;
+
+ if (indices == NULL)
+ return N == 0 && port->sup_n_waits == 0;
+
+ for (i = 0, n = 0; i < N; i++) {
+ if (reverses[i] > 0) {
+ if (indices[reverses[i]] != i)
+ return 0;
+ n++;
+ }
+ }
+
+ if (n != port->sup_n_waits)
+ return 0;
+
+ n = 0;
+
+ for (i = 1; i <= N; i++) {
+ if (indices[i] >= 0) {
+ if (reverses[indices[i]] != i)
+ return 0;
+ n++;
+ }
+ }
+
+ if (n != port->sup_n_waits)
+ return 0;
+
+ for (i = indices[0]; -i <= N; i = indices[-i]) {
+ if (i >= 0)
+ return 0;
+ n++;
+ }
+
+ return n == port->sup_size_waits;
+}
+
+struct su_root_magic_s
+{
+ int error, *sockets, *regs, *wakeups;
+};
+
+static int callback(su_root_magic_t *magic,
+ su_wait_t *w,
+ su_wakeup_arg_t *arg)
+{
+ intptr_t i = (intptr_t)arg;
+
+ assert(magic);
+
+ if (i <= 0 || i > I)
+ return ++magic->error;
+
+ su_wait_events(w, magic->sockets[i]);
+
+ magic->wakeups[i]++;
+
+#if HAVE_POLL
+ if (w->fd != magic->sockets[i])
+ return ++magic->error;
+#endif
+
+ return 0;
+}
+
+int test_wakeup(su_port_t *port, su_root_magic_t *magic)
+{
+ int i;
+
+ for (i = N0; i < N; i++) {
+ su_sockaddr_t su[1]; socklen_t sulen = sizeof su;
+ int n, woken = magic->wakeups[i];
+ char buf[1];
+ if (magic->regs[i] == 0)
+ continue;
+
+ if (getsockname(magic->sockets[i], &su->su_sa, &sulen) < 0)
+ su_perror("getsockname"), exit(1);
+ if (su_sendto(magic->sockets[1], "X", 1, 0, su, sulen) < 0)
+ su_perror("su_sendto"), exit(1);
+ n = su_port_wait_events(port, 100);
+ if (n != 1)
+ return 1;
+ if (magic->error)
+ return 2;
+ if (magic->wakeups[i] != woken + 1)
+ return 3;
+ if (recv(magic->sockets[i], buf, 1, 0) != 1)
+ return 4;
+ }
+
+ return 0;
+}
+
+int test_register(void)
+{
+ su_port_t *port;
+ su_sockaddr_t su[1];
+ intptr_t i;
+ int sockets[256] = { 0 };
+ int reg[256] = { 0 };
+ int wakeups[256] = { 0 };
+ int prioritized;
+ su_wait_t wait[256];
+ su_root_magic_t magic[1] = {{ 0 }};
+ su_root_t root[1] = {{ sizeof root }};
+
+ BEGIN();
+
+ root->sur_magic = magic;
+
+ memset(su, 0, sizeof su);
+ su->su_len = sizeof su->su_sin;
+ su->su_family = AF_INET;
+ su->su_sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */
+
+ memset(wait, 0, sizeof wait);
+
+ memset(magic->sockets = sockets, -1, sizeof sockets);
+ memset(magic->regs = reg, 0, sizeof reg);
+ memset(magic->wakeups = wakeups, 0, sizeof wakeups);
+
+ su_root_size_hint = 16;
+
+ TEST_1(port = su_port_create());
+ TEST(su_port_threadsafe(port), 0);
+ SU_PORT_INCREF(port, __func__);
+
+ TEST_1(test_sup_indices(port));
+
+ for (i = N0; i < N; i++) {
+ sockets[i] = su_socket(AF_INET, SOCK_DGRAM, 0); TEST_1(sockets[i] != -1);
+
+ if (bind(sockets[i], &su->su_sa, sizeof su->su_sin) != 0)
+ perror("bind"), assert(0);
+
+ TEST(su_wait_create(wait + i, sockets[i], SU_WAIT_IN), 0);
+
+ reg[i] = su_port_register(port, root, wait + i, callback, (void*)i, 0);
+
+ TEST_1(reg[i] > 0);
+ }
+
+ TEST(port->sup_indices[0], -I);
+ TEST_1(test_sup_indices(port));
+ TEST(test_wakeup(port, magic), 0);
+
+ for (i = 1; i < N; i += 2) {
+ TEST(su_port_deregister(port, reg[i]), reg[i]);
+ TEST_1(test_sup_indices(port));
+ }
+
+ TEST_1(test_sup_indices(port));
+
+ prioritized = 0;
+
+ for (i = N - 1; i >= N0; i -= 2) {
+ TEST(su_wait_create(wait + i, sockets[i], SU_WAIT_IN), 0);
+ reg[i] = su_port_register(port, root, wait + i, callback, (void *)i, 1);
+ TEST_1(reg[i] > 0);
+ prioritized++; /* Count number of prioritized registrations */
+#if HAVE_EPOLL
+ /* With epoll we do not bother to prioritize the wait list */
+ if (port->sup_epoll != -1) {
+ int N = port->sup_n_waits;
+ TEST_M(wait + i, port->sup_waits + N - 1, sizeof wait[0]);
+ }
+ else
+#endif
+ TEST_M(wait + i, port->sup_waits, sizeof wait[0]);
+ }
+
+ TEST(port->sup_indices[0], -I);
+
+#if 0
+#if HAVE_EPOLL
+ /* With epoll we do not bother to prioritize the wait list */
+ if (port->sup_epoll != -1) {
+ TEST_M(wait + 15, port->sup_waits + 8, sizeof wait[0]);
+ TEST_M(wait + 13, port->sup_waits + 9, sizeof wait[0]);
+ TEST_M(wait + 11, port->sup_waits + 10, sizeof wait[0]);
+ TEST_M(wait + 9, port->sup_waits + 11, sizeof wait[0]);
+ TEST_M(wait + 7, port->sup_waits + 12, sizeof wait[0]);
+ TEST_M(wait + 5, port->sup_waits + 13, sizeof wait[0]);
+ TEST_M(wait + 3, port->sup_waits + 14, sizeof wait[0]);
+ TEST_M(wait + 1, port->sup_waits + 15, sizeof wait[0]);
+ }
+ else
+#endif
+ {
+ TEST_M(wait + 15, port->sup_waits + 7, sizeof wait[0]);
+ TEST_M(wait + 13, port->sup_waits + 6, sizeof wait[0]);
+ TEST_M(wait + 11, port->sup_waits + 5, sizeof wait[0]);
+ TEST_M(wait + 9, port->sup_waits + 4, sizeof wait[0]);
+ TEST_M(wait + 7, port->sup_waits + 3, sizeof wait[0]);
+ TEST_M(wait + 5, port->sup_waits + 2, sizeof wait[0]);
+ TEST_M(wait + 3, port->sup_waits + 1, sizeof wait[0]);
+ TEST_M(wait + 1, port->sup_waits + 0, sizeof wait[0]);
+ }
+#endif
+
+ TEST_1(test_sup_indices(port));
+ TEST(test_wakeup(port, magic), 0);
+
+ for (i = 1; i <= 8; i++) {
+ TEST(su_port_deregister(port, reg[i]), reg[i]); reg[i] = 0;
+ if (i % 2 == (N - 1) % 2)
+ prioritized--; /* Count number of prioritized registrations */
+ }
+
+#if HAVE_EPOLL
+ /* With epoll we do not bother to prioritize the wait list */
+ if (port->sup_epoll == -1)
+#endif
+ TEST(port->sup_pri_offset, prioritized);
+
+ TEST_1(test_sup_indices(port));
+
+ TEST(su_port_deregister(port, 0), -1);
+ TEST(su_port_deregister(port, -1), -1);
+ TEST(su_port_deregister(port, 130), -1);
+
+ TEST_1(test_sup_indices(port));
+
+ for (i = 1; i <= 8; i++) {
+ TEST(su_port_deregister(port, reg[i]), -1);
+ }
+
+ TEST_VOID(su_port_decref(port, 1, __func__));
+
+ END();
+}
+
+void usage(void)
+{
+ fprintf(stderr,
+ "usage: %s [-v]\n",
+ name);
+}
+
+int main(int argc, char *argv[])
+{
+ int retval = 0;
+ int i;
+
+#if SU_HAVE_WINSOCK
+ if (N > SU_WAIT_MAX)
+ N = SU_WAIT_MAX;
+ if (I - 1 >= SU_WAIT_MAX)
+ I = (unsigned)SU_WAIT_MAX + 1;
+#endif
+
+ for (i = 1; argv[i]; i++) {
+ if (strcmp(argv[i], "-v") == 0)
+ tstflags |= tst_verbatim;
+ else
+ usage();
+ }
+
+ su_init();
+
+ retval |= test_register(); fflush(stdout);
+
+ su_deinit();
+
+ return retval;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_root.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_root.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,362 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_root_ex
+ *
+ * @file torture_su_root.c
+ *
+ * Test su_root_register functionality.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * Copyright (c) 2002 Nokia Research Center. All rights reserved.
+ *
+ * @date Created: Wed Jun 12 15:18:11 2002 ppessi
+ */
+
+#include "config.h"
+
+char const *name = "su_root_test";
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define TSTFLAGS rt->rt_flags
+#include <sofia-sip/tstdef.h>
+
+typedef struct root_test_s root_test_t;
+typedef struct test_ep_s test_ep_t;
+
+#define SU_ROOT_MAGIC_T root_test_t
+#define SU_WAKEUP_ARG_T test_ep_t
+
+#include <sofia-sip/su_wait.h>
+#include <sofia-sip/su_alloc.h>
+
+typedef struct test_ep_s {
+ int i;
+ int s;
+ su_wait_t wait[1];
+ int registered;
+ socklen_t addrlen;
+ su_sockaddr_t addr[1];
+} test_ep_at[1];
+
+struct root_test_s {
+ su_home_t rt_home[1];
+ int rt_flags;
+
+ su_root_t *rt_root;
+ short rt_family;
+ int rt_status;
+ int rt_received;
+ int rt_wakeup;
+
+ su_clone_r rt_clone;
+
+ unsigned rt_fail_init:1;
+ unsigned rt_fail_deinit:1;
+ unsigned rt_success_init:1;
+ unsigned rt_success_deinit:1;
+
+ test_ep_at rt_ep[5];
+};
+
+/** Test root initialization */
+int init_test(root_test_t *rt)
+{
+ su_sockaddr_t su[1] = {{ 0 }};
+ int i;
+
+ BEGIN();
+
+ su_init();
+
+ su->su_family = rt->rt_family;
+
+ TEST_1(rt->rt_root = su_root_create(rt));
+
+ for (i = 0; i < 5; i++) {
+ test_ep_t *ep = rt->rt_ep[i];
+ ep->i = i;
+ ep->addrlen = su_sockaddr_size(su);
+ TEST_1((ep->s = su_socket(su->su_family, SOCK_DGRAM, 0)) != -1);
+ TEST_1(bind(ep->s, &su->su_sa, ep->addrlen) != -1);
+ TEST_1(su_wait_create(ep->wait, ep->s, SU_WAIT_IN|SU_WAIT_ERR) != -1);
+ TEST_1(getsockname(ep->s, &ep->addr->su_sa, &ep->addrlen) != -1);
+ if (SU_HAS_INADDR_ANY(ep->addr)) {
+ inet_pton(su->su_family,
+ su->su_family == AF_INET ? "127.0.0.1" : "::1",
+ SU_ADDR(ep->addr));
+ }
+ }
+
+ END();
+}
+
+static int deinit_test(root_test_t *rt)
+{
+ BEGIN();
+
+ TEST_VOID(su_root_destroy(rt->rt_root)); rt->rt_root = NULL;
+ TEST_VOID(su_root_destroy(NULL));
+
+ su_deinit();
+
+ END();
+}
+
+int wakeup(root_test_t *rt,
+ su_wait_t *w,
+ test_ep_t *ep)
+{
+ char buffer[64];
+ int n, error;
+
+ su_wait_events(w, ep->s);
+
+ n = recv(ep->s, buffer, sizeof(buffer), 0);
+ error = su_errno();
+
+ if (n < 0)
+ fprintf(stderr, "%s: %s\n", "recv", su_strerror(error));
+
+ TEST_1(n > 0);
+
+ rt->rt_received = ep->i;
+
+ return 0;
+}
+
+static int wakeup0(root_test_t *rt, su_wait_t *w, test_ep_t *ep)
+{
+ rt->rt_wakeup = 0;
+ return wakeup(rt, w, ep);
+}
+static int wakeup1(root_test_t *rt, su_wait_t *w, test_ep_t *ep)
+{
+ rt->rt_wakeup = 1;
+ return wakeup(rt, w, ep);
+}
+static int wakeup2(root_test_t *rt, su_wait_t *w, test_ep_t *ep)
+{
+ rt->rt_wakeup = 2;
+ return wakeup(rt, w, ep);
+}
+static int wakeup3(root_test_t *rt, su_wait_t *w, test_ep_t *ep)
+{
+ rt->rt_wakeup = 3;
+ return wakeup(rt, w, ep);
+}
+static int wakeup4(root_test_t *rt, su_wait_t *w, test_ep_t *ep)
+{
+ rt->rt_wakeup = 4;
+ return wakeup(rt, w, ep);
+}
+
+static
+su_wakeup_f wakeups[5] = { wakeup0, wakeup1, wakeup2, wakeup3, wakeup4 };
+
+
+static
+void test_run(root_test_t *rt)
+{
+ rt->rt_received = -1;
+
+ while (rt->rt_received == -1) {
+ su_root_step(rt->rt_root, 200);
+ }
+}
+
+static int register_test(root_test_t *rt)
+{
+ int i;
+ int s;
+ char *msg = "foo";
+
+ BEGIN();
+
+ TEST_1((s = su_socket(rt->rt_family, SOCK_DGRAM, 0)) != -1);
+
+ for (i = 0; i < 5; i++) {
+ rt->rt_ep[i]->registered =
+ su_root_register(rt->rt_root, rt->rt_ep[i]->wait,
+ wakeups[i], rt->rt_ep[i], 0);
+ TEST(rt->rt_ep[i]->registered, i + 1 + SU_HAVE_PTHREADS);
+ }
+
+ for (i = 0; i < 5; i++) {
+ test_ep_t *ep = rt->rt_ep[i];
+ TEST_SIZE(su_sendto(s, msg, sizeof(msg), 0, ep->addr, ep->addrlen),
+ sizeof(msg));
+ test_run(rt);
+ TEST(rt->rt_received, i);
+ TEST(rt->rt_wakeup, i);
+ }
+
+ for (i = 0; i < 5; i++) {
+ TEST(su_root_unregister(rt->rt_root, rt->rt_ep[i]->wait,
+ wakeups[i], rt->rt_ep[i]),
+ rt->rt_ep[i]->registered);
+ }
+
+
+ for (i = 0; i < 5; i++) {
+ rt->rt_ep[i]->registered =
+ su_root_register(rt->rt_root, rt->rt_ep[i]->wait,
+ wakeups[i], rt->rt_ep[i], 1);
+ TEST_1(rt->rt_ep[i]->registered > 0);
+ }
+
+ for (i = 0; i < 5; i++) {
+ test_ep_t *ep = rt->rt_ep[i];
+ TEST_SIZE(su_sendto(s, msg, sizeof(msg), 0, ep->addr, ep->addrlen),
+ sizeof(msg));
+ test_run(rt);
+ TEST(rt->rt_received, i);
+ TEST(rt->rt_wakeup, i);
+ }
+
+ for (i = 0; i < 5; i++) {
+ TEST(su_root_deregister(rt->rt_root, rt->rt_ep[i]->registered),
+ rt->rt_ep[i]->registered);
+ }
+
+ for (i = 0; i < 5; i++) {
+ test_ep_t *ep = rt->rt_ep[i];
+ TEST_1(su_wait_create(ep->wait, ep->s, SU_WAIT_IN|SU_WAIT_ERR) != -1);
+ ep->registered =
+ su_root_register(rt->rt_root, ep->wait,
+ wakeups[i], ep, 1);
+ TEST_1(ep->registered > 0);
+ }
+
+ for (i = 0; i < 5; i++) {
+ test_ep_t *ep = rt->rt_ep[i];
+ TEST_SIZE(su_sendto(s, msg, sizeof(msg), 0, ep->addr, ep->addrlen),
+ sizeof(msg));
+ test_run(rt);
+ TEST(rt->rt_received, i);
+ TEST(rt->rt_wakeup, i);
+ }
+
+ for (i = 0; i < 5; i++) {
+ TEST(su_root_unregister(rt->rt_root, rt->rt_ep[i]->wait,
+ wakeups[i], rt->rt_ep[i]),
+ rt->rt_ep[i]->registered);
+ }
+
+ END();
+}
+
+int fail_init(su_root_t *root, root_test_t *rt)
+{
+ rt->rt_fail_init = 1;
+ return -1;
+}
+
+void fail_deinit(su_root_t *root, root_test_t *rt)
+{
+ rt->rt_fail_deinit = 1;
+}
+
+int success_init(su_root_t *root, root_test_t *rt)
+{
+ rt->rt_success_init = 1;
+ return 0;
+}
+
+void success_deinit(su_root_t *root, root_test_t *rt)
+{
+ rt->rt_success_deinit = 1;
+}
+
+static int clone_test(root_test_t rt[1])
+{
+ BEGIN();
+
+ rt->rt_fail_init = 0;
+ rt->rt_fail_deinit = 0;
+ rt->rt_success_init = 0;
+ rt->rt_success_deinit = 0;
+
+ TEST(su_clone_start(rt->rt_root,
+ rt->rt_clone,
+ rt,
+ fail_init,
+ fail_deinit), SU_FAILURE);
+ TEST_1(rt->rt_fail_init);
+ TEST_1(rt->rt_fail_deinit);
+
+ TEST(su_clone_start(rt->rt_root,
+ rt->rt_clone,
+ rt,
+ success_init,
+ success_deinit), SU_SUCCESS);
+ TEST_1(rt->rt_success_init);
+ TEST_1(!rt->rt_success_deinit);
+
+ TEST_VOID(su_clone_wait(rt->rt_root, rt->rt_clone));
+
+ TEST_1(rt->rt_success_deinit);
+
+ END();
+}
+
+void usage(void)
+{
+ fprintf(stderr,
+ "usage: %s [-v]\n",
+ name);
+}
+
+int main(int argc, char *argv[])
+{
+ root_test_t rt[1] = {{{ SU_HOME_INIT(rt) }}};
+ int retval = 0;
+ int i;
+
+ rt->rt_family = AF_INET;
+
+ for (i = 1; argv[i]; i++) {
+ if (strcmp(argv[i], "-v") == 0)
+ rt->rt_flags |= tst_verbatim;
+#if SU_HAVE_IN6
+ else if (strcmp(argv[i], "-6") == 0)
+ rt->rt_family = AF_INET6;
+#endif
+ else
+ usage();
+ }
+
+ retval |= init_test(rt);
+ retval |= register_test(rt);
+ retval |= clone_test(rt);
+ su_root_threading(rt->rt_root, 0);
+ retval |= clone_test(rt);
+ retval |= deinit_test(rt);
+
+ return retval;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_root_osx.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_root_osx.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,364 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_root_ex
+ *
+ * @file torture_su_root_osx.c
+ *
+ * Test su_root_register functionality.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ *
+ * Copyright (c) 2006 Nokia Research Center. All rights reserved.
+ *
+ * @date Created: Mon Oct 9 13:25:10 EEST 2006 mela
+ */
+
+#include "config.h"
+
+char const *name = "torture_su_root_osx";
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define TSTFLAGS rt->rt_flags
+#include <sofia-sip/tstdef.h>
+
+typedef struct root_test_s root_test_t;
+typedef struct test_ep_s test_ep_t;
+
+#define SU_ROOT_MAGIC_T root_test_t
+#define SU_WAKEUP_ARG_T test_ep_t
+
+#include <sofia-sip/su_osx_runloop.h>
+#include <sofia-sip/su_wait.h>
+#include <sofia-sip/su_alloc.h>
+
+typedef struct test_ep_s {
+ int i;
+ int s;
+ su_wait_t wait[1];
+ int registered;
+ socklen_t addrlen;
+ su_sockaddr_t addr[1];
+} test_ep_at[1];
+
+struct root_test_s {
+ su_home_t rt_home[1];
+ int rt_flags;
+
+ su_root_t *rt_root;
+ short rt_family;
+ int rt_status;
+ int rt_received;
+ int rt_wakeup;
+
+ su_clone_r rt_clone;
+
+ unsigned rt_fail_init:1;
+ unsigned rt_fail_deinit:1;
+ unsigned rt_success_init:1;
+ unsigned rt_success_deinit:1;
+
+ test_ep_at rt_ep[5];
+};
+
+/** Test root initialization */
+int init_test(root_test_t *rt)
+{
+ su_sockaddr_t su[1] = {{ 0 }};
+ int i;
+
+ BEGIN();
+
+ su_init();
+
+ su->su_family = rt->rt_family;
+
+ TEST_1(rt->rt_root = su_root_osx_runloop_create(rt));
+
+ for (i = 0; i < 5; i++) {
+ test_ep_t *ep = rt->rt_ep[i];
+ ep->i = i;
+ ep->addrlen = su_sockaddr_size(su);
+ TEST_1((ep->s = su_socket(su->su_family, SOCK_DGRAM, 0)) != -1);
+ TEST_1(bind(ep->s, &su->su_sa, ep->addrlen) != -1);
+ TEST_1(su_wait_create(ep->wait, ep->s, SU_WAIT_IN|SU_WAIT_ERR) != -1);
+ TEST_1(getsockname(ep->s, &ep->addr->su_sa, &ep->addrlen) != -1);
+ if (SU_HAS_INADDR_ANY(ep->addr)) {
+ inet_pton(su->su_family,
+ su->su_family == AF_INET ? "127.0.0.1" : "::1",
+ SU_ADDR(ep->addr));
+ }
+ }
+
+ END();
+}
+
+static int deinit_test(root_test_t *rt)
+{
+ BEGIN();
+
+ TEST_VOID(su_root_destroy(rt->rt_root)); rt->rt_root = NULL;
+ TEST_VOID(su_root_destroy(NULL));
+
+ su_deinit();
+
+ END();
+}
+
+int wakeup(root_test_t *rt,
+ su_wait_t *w,
+ test_ep_t *ep)
+{
+ char buffer[64];
+ int n, error;
+
+ su_wait_events(w, ep->s);
+
+ n = recv(ep->s, buffer, sizeof(buffer), 0);
+ error = su_errno();
+
+ if (n < 0)
+ fprintf(stderr, "%s: %s\n", "recv", su_strerror(error));
+
+ TEST_1(n > 0);
+
+ rt->rt_received = ep->i;
+
+ return 0;
+}
+
+static int wakeup0(root_test_t *rt, su_wait_t *w, test_ep_t *ep)
+{
+ rt->rt_wakeup = 0;
+ return wakeup(rt, w, ep);
+}
+static int wakeup1(root_test_t *rt, su_wait_t *w, test_ep_t *ep)
+{
+ rt->rt_wakeup = 1;
+ return wakeup(rt, w, ep);
+}
+static int wakeup2(root_test_t *rt, su_wait_t *w, test_ep_t *ep)
+{
+ rt->rt_wakeup = 2;
+ return wakeup(rt, w, ep);
+}
+static int wakeup3(root_test_t *rt, su_wait_t *w, test_ep_t *ep)
+{
+ rt->rt_wakeup = 3;
+ return wakeup(rt, w, ep);
+}
+static int wakeup4(root_test_t *rt, su_wait_t *w, test_ep_t *ep)
+{
+ rt->rt_wakeup = 4;
+ return wakeup(rt, w, ep);
+}
+
+static
+su_wakeup_f wakeups[5] = { wakeup0, wakeup1, wakeup2, wakeup3, wakeup4 };
+
+
+static
+void test_run(root_test_t *rt)
+{
+ rt->rt_received = -1;
+
+ while (rt->rt_received == -1) {
+ su_root_step(rt->rt_root, 200);
+ }
+}
+
+static int register_test(root_test_t *rt)
+{
+ int i;
+ int s;
+ char msg[3] = "foo";
+
+ BEGIN();
+
+ TEST_1((s = su_socket(rt->rt_family, SOCK_DGRAM, 0)) != -1);
+
+ for (i = 0; i < 5; i++) {
+ rt->rt_ep[i]->registered =
+ su_root_register(rt->rt_root, rt->rt_ep[i]->wait,
+ wakeups[i], rt->rt_ep[i], 0);
+ TEST(rt->rt_ep[i]->registered, i + 1 + SU_HAVE_PTHREADS);
+ }
+
+ for (i = 0; i < 5; i++) {
+ test_ep_t *ep = rt->rt_ep[i];
+ TEST(su_sendto(s, msg, sizeof(msg), 0, ep->addr, ep->addrlen),
+ sizeof(msg));
+ test_run(rt);
+ TEST(rt->rt_received, i);
+ TEST(rt->rt_wakeup, i);
+ }
+
+ for (i = 0; i < 5; i++) {
+ TEST(su_root_unregister(rt->rt_root, rt->rt_ep[i]->wait,
+ wakeups[i], rt->rt_ep[i]),
+ rt->rt_ep[i]->registered);
+ }
+
+
+ for (i = 0; i < 5; i++) {
+ rt->rt_ep[i]->registered =
+ su_root_register(rt->rt_root, rt->rt_ep[i]->wait,
+ wakeups[i], rt->rt_ep[i], 1);
+ TEST_1(rt->rt_ep[i]->registered > 0);
+ }
+
+ for (i = 0; i < 5; i++) {
+ test_ep_t *ep = rt->rt_ep[i];
+ TEST(su_sendto(s, msg, sizeof(msg), 0, ep->addr, ep->addrlen),
+ sizeof(msg));
+ test_run(rt);
+ TEST(rt->rt_received, i);
+ TEST(rt->rt_wakeup, i);
+ }
+
+ for (i = 0; i < 5; i++) {
+ TEST(su_root_deregister(rt->rt_root, rt->rt_ep[i]->registered),
+ rt->rt_ep[i]->registered);
+ }
+
+ for (i = 0; i < 5; i++) {
+ test_ep_t *ep = rt->rt_ep[i];
+ TEST_1(su_wait_create(ep->wait, ep->s, SU_WAIT_IN|SU_WAIT_ERR) != -1);
+ ep->registered =
+ su_root_register(rt->rt_root, ep->wait,
+ wakeups[i], ep, 1);
+ TEST_1(ep->registered > 0);
+ }
+
+ for (i = 0; i < 5; i++) {
+ test_ep_t *ep = rt->rt_ep[i];
+ TEST(su_sendto(s, msg, sizeof(msg), 0, ep->addr, ep->addrlen),
+ sizeof(msg));
+ test_run(rt);
+ TEST(rt->rt_received, i);
+ TEST(rt->rt_wakeup, i);
+ }
+
+ for (i = 0; i < 5; i++) {
+ TEST(su_root_unregister(rt->rt_root, rt->rt_ep[i]->wait,
+ wakeups[i], rt->rt_ep[i]),
+ rt->rt_ep[i]->registered);
+ }
+
+ END();
+}
+
+int fail_init(su_root_t *root, root_test_t *rt)
+{
+ rt->rt_fail_init = 1;
+ return -1;
+}
+
+void fail_deinit(su_root_t *root, root_test_t *rt)
+{
+ rt->rt_fail_deinit = 1;
+}
+
+int success_init(su_root_t *root, root_test_t *rt)
+{
+ rt->rt_success_init = 1;
+ return 0;
+}
+
+void success_deinit(su_root_t *root, root_test_t *rt)
+{
+ rt->rt_success_deinit = 1;
+}
+
+static int clone_test(root_test_t rt[1])
+{
+ BEGIN();
+
+ rt->rt_fail_init = 0;
+ rt->rt_fail_deinit = 0;
+ rt->rt_success_init = 0;
+ rt->rt_success_deinit = 0;
+
+ TEST(su_clone_start(rt->rt_root,
+ rt->rt_clone,
+ rt,
+ fail_init,
+ fail_deinit), SU_FAILURE);
+ TEST_1(rt->rt_fail_init);
+ TEST_1(rt->rt_fail_deinit);
+
+ TEST(su_clone_start(rt->rt_root,
+ rt->rt_clone,
+ rt,
+ success_init,
+ success_deinit), SU_SUCCESS);
+ TEST_1(rt->rt_success_init);
+ TEST_1(!rt->rt_success_deinit);
+
+ TEST_VOID(su_clone_wait(rt->rt_root, rt->rt_clone));
+
+ TEST_1(rt->rt_success_deinit);
+
+ END();
+}
+
+void usage(void)
+{
+ fprintf(stderr,
+ "usage: %s [-v]\n",
+ name);
+}
+
+int main(int argc, char *argv[])
+{
+ root_test_t rt[1] = {{{ SU_HOME_INIT(rt) }}};
+ int retval = 0;
+ int i;
+
+ rt->rt_family = AF_INET;
+
+ for (i = 1; argv[i]; i++) {
+ if (strcmp(argv[i], "-v") == 0)
+ rt->rt_flags |= tst_verbatim;
+#if SU_HAVE_IN6
+ else if (strcmp(argv[i], "-6") == 0)
+ rt->rt_family = AF_INET6;
+#endif
+ else
+ usage();
+ }
+
+ retval |= init_test(rt);
+ retval |= register_test(rt);
+ retval |= clone_test(rt);
+ su_root_threading(rt->rt_root, 0);
+ retval |= clone_test(rt);
+ retval |= deinit_test(rt);
+
+ return retval;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_tag.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_tag.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,654 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@SU_TAG
+ *
+ * @file torture_su_tag.c
+ *
+ * Testing functions for su_tag module.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Mar 6 18:33:42 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <sofia-sip/su_tag.h>
+#include <sofia-sip/su_tag_io.h>
+#include <sofia-sip/su_tag_class.h>
+#include <sofia-sip/su_tagarg.h>
+
+#ifndef WIN32
+#define DEVNULL "/dev/null"
+#else
+#define DEVNULL "nul"
+#endif
+
+int tstflags = 0;
+
+#define TSTFLAGS tstflags
+
+#include <sofia-sip/tstdef.h>
+
+#define TAG_A(s) tag_a, tag_str_v((s))
+#define TAG_A_REF(s) tag_a_ref, tag_str_vr(&(s))
+#define TAG_B(s) tag_b, tag_str_v((s))
+#define TAG_B_REF(s) tag_b_ref, tag_str_vr(&(s))
+
+#define TAG_I(i) tag_i, tag_int_v((i))
+#define TAG_I_REF(i) tag_i_ref, tag_int_vr(&(i))
+#define TAG_J(i) tag_j, tag_int_v((i))
+#define TAG_J_REF(i) tag_j_ref, tag_int_vr(&(i))
+#define TAG_K(i) tag_k, tag_int_v((i))
+#define TAG_K_REF(i) tag_k_ref, tag_int_vr(&(i))
+
+#define TAG_ANY_PQ() tag_any_pq, (tag_value_t)0
+
+#define TAG_P(i) tag_p, tag_bool_v((i))
+#define TAG_P_REF(i) tag_p_ref, tag_bool_vr(&(i))
+#define TAG_Q(i) tag_q, tag_bool_v((i))
+#define TAG_Q_REF(i) tag_q_ref, tag_bool_vr(&(i))
+
+char const *name = "su_tag_test";
+
+#if HAVE_WIN32
+typedef struct tag_type_s tag_typedef_win_t[1];
+
+tag_typedef_win_t tag_a, tag_a_ref, tag_b, tag_b_ref;
+tag_typedef_win_t tag_i, tag_i_ref, tag_j, tag_j_ref;
+tag_typedef_win_t tag_k, tag_k_ref, tag_n, tag_n_ref;
+tag_typedef_win_t tag_any_pq;
+tag_typedef_win_t tag_p, tag_p_ref, tag_q, tag_q_ref;
+
+#else
+tag_typedef_t tag_a = STRTAG_TYPEDEF(a);
+tag_typedef_t tag_a_ref = REFTAG_TYPEDEF(tag_a);
+
+tag_typedef_t tag_b = STRTAG_TYPEDEF(b);
+tag_typedef_t tag_b_ref = REFTAG_TYPEDEF(tag_b);
+
+tag_typedef_t tag_i = INTTAG_TYPEDEF(i);
+tag_typedef_t tag_i_ref = REFTAG_TYPEDEF(tag_i);
+
+tag_typedef_t tag_j = INTTAG_TYPEDEF(j);
+tag_typedef_t tag_j_ref = REFTAG_TYPEDEF(tag_j);
+
+tag_typedef_t tag_k = INTTAG_TYPEDEF(k);
+tag_typedef_t tag_k_ref = REFTAG_TYPEDEF(tag_k);
+
+tag_typedef_t tag_n = INTTAG_TYPEDEF(n);
+tag_typedef_t tag_n_ref = REFTAG_TYPEDEF(tag_n);
+
+#undef TAG_NAMESPACE
+#define TAG_NAMESPACE "pq"
+
+tag_typedef_t tag_any_pq = NSTAG_TYPEDEF(*);
+
+tag_typedef_t tag_p = BOOLTAG_TYPEDEF(p);
+tag_typedef_t tag_p_ref = REFTAG_TYPEDEF(tag_p);
+
+tag_typedef_t tag_q = BOOLTAG_TYPEDEF(q);
+tag_typedef_t tag_q_ref = REFTAG_TYPEDEF(tag_q);
+
+#endif
+
+static void init_tags(void)
+{
+#if HAVE_WIN32
+ /* Automatic initialization with pointers from DLL does not work in WIN32 */
+
+ tag_typedef_t _tag_a = STRTAG_TYPEDEF(a);
+ tag_typedef_t _tag_a_ref = REFTAG_TYPEDEF(tag_a);
+
+ tag_typedef_t _tag_b = STRTAG_TYPEDEF(b);
+ tag_typedef_t _tag_b_ref = REFTAG_TYPEDEF(tag_b);
+
+ tag_typedef_t _tag_i = INTTAG_TYPEDEF(i);
+ tag_typedef_t _tag_i_ref = REFTAG_TYPEDEF(tag_i);
+
+ tag_typedef_t _tag_j = INTTAG_TYPEDEF(j);
+ tag_typedef_t _tag_j_ref = REFTAG_TYPEDEF(tag_j);
+
+ tag_typedef_t _tag_k = INTTAG_TYPEDEF(k);
+ tag_typedef_t _tag_k_ref = REFTAG_TYPEDEF(tag_k);
+
+ tag_typedef_t _tag_n = INTTAG_TYPEDEF(n);
+ tag_typedef_t _tag_n_ref = REFTAG_TYPEDEF(tag_n);
+
+#undef TAG_NAMESPACE
+#define TAG_NAMESPACE "pq"
+
+ tag_typedef_t _tag_any_pq = NSTAG_TYPEDEF(*);
+
+ tag_typedef_t _tag_p = BOOLTAG_TYPEDEF(p);
+ tag_typedef_t _tag_p_ref = REFTAG_TYPEDEF(tag_p);
+
+ tag_typedef_t _tag_q = BOOLTAG_TYPEDEF(q);
+ tag_typedef_t _tag_q_ref = REFTAG_TYPEDEF(tag_q);
+
+ *(struct tag_type_s *)tag_a = *_tag_a;
+ *(struct tag_type_s *)tag_a_ref = *_tag_a_ref;
+ *(struct tag_type_s *)tag_b = *_tag_b;
+ *(struct tag_type_s *)tag_b_ref = *_tag_b_ref;
+ *(struct tag_type_s *)tag_i = *_tag_i;
+ *(struct tag_type_s *)tag_i_ref = *_tag_i_ref;
+ *(struct tag_type_s *)tag_j = *_tag_j;
+ *(struct tag_type_s *)tag_j_ref = *_tag_j_ref;
+ *(struct tag_type_s *)tag_k = *_tag_k;
+ *(struct tag_type_s *)tag_k_ref = *_tag_k_ref;
+ *(struct tag_type_s *)tag_n = *_tag_n;
+ *(struct tag_type_s *)tag_n_ref = *_tag_n_ref;
+ *(struct tag_type_s *)tag_any_pq = *_tag_any_pq;
+ *(struct tag_type_s *)tag_p = *_tag_p;
+ *(struct tag_type_s *)tag_p_ref = *_tag_p_ref;
+ *(struct tag_type_s *)tag_q = *_tag_q;
+ *(struct tag_type_s *)tag_q_ref = *_tag_q_ref;
+#endif
+}
+
+static int test_assumptions(void)
+{
+ tagi_t tags[2], *tagi;
+
+ BEGIN();
+
+ TEST_1(sizeof (tag_value_t) >= sizeof (void *));
+
+ /* First some pointer arithmetics - this is always true, right? */
+ tagi = tags;
+ TEST_P(tagi + 1, tags + 1);
+ tagi = (tagi_t *)(sizeof(tagi_t) + (char *)tagi);
+ TEST_P(tagi, tags + 1);
+
+ END();
+}
+
+#if SU_HAVE_TAGSTACK
+
+/* Automake thing:
+
+###
+### Test if we have stack suitable for handling tags directly
+###
+AC_TRY_RUN( [
+#if HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+#if HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#include <stdarg.h>
+
+typedef void *tp;
+typedef intptr_t tv;
+
+int test1(tv l, tv h, ...)
+{
+ va_list ap;
+ tv i, *p = &l;
+
+ va_start(ap, h);
+
+ if (*p++ != l || *p++ != h) return 1;
+
+ for (i = l; i <= h; i++) {
+ if (*p++ != i)
+ return 1;
+ }
+
+ for (i = l; i <= h; i++) {
+ if (va_arg(ap, tv) != i)
+ return 1;
+ }
+
+ va_end(ap);
+
+ return 0;
+}
+
+int main(int avc, char *av[])
+{
+ return test1((tv)1, (tv)10,
+ (tv)1, (tv)2, (tv)3, (tv)4, (tv)5,
+ (tv)6, (tv)7, (tv)8, (tv)9, (tv)10);
+}
+],
+SAC_SU_DEFINE(SU_HAVE_TAGSTACK, 1, [
+Define this as 1 if your compiler puts the variable argument list nicely in memory]),
+)
+
+*/
+
+static int test_stackargs(int l, ...)
+{
+ va_list ap;
+ int i, *p;
+
+ BEGIN();
+
+ va_start(ap, l);
+
+ p = &l;
+
+ for (i = l; i <= 10; i++) {
+ TEST(*p++, i);
+ }
+
+ for (i = l + 1; i <= 10; i++) {
+ TEST(va_arg(ap, int), i);
+ }
+
+ va_end(ap);
+
+ END();
+}
+#else
+static int test_stackargs(int l, ...) { return 0; }
+#endif
+
+/** Test tl_list, tl_llist and tl_dup */
+static int test_dup(void)
+{
+ tagi_t const rest[] = {{ TAG_A("Foo") }, { TAG_NULL() }};
+ tagi_t *lst, *dup;
+
+ BEGIN();
+
+ lst = tl_list(TAG_A("Moro"),
+ TAG_A("Vaan"),
+ TAG_I(1),
+ TAG_SKIP(2),
+ TAG_NEXT(rest));
+
+ TEST_P(lst[0].t_tag, tag_a);
+ TEST_P(lst[1].t_tag, tag_a);
+ TEST_P(lst[2].t_tag, tag_i);
+ TEST_P(lst[3].t_tag, tag_skip);
+ TEST_P(lst[4].t_tag, tag_next);
+
+ TEST_SIZE(tl_len(lst), 5 * sizeof(tagi_t));
+ TEST_SIZE(tl_xtra(lst, 0), strlen("Moro" "Vaan" "Foo") + 3);
+
+ dup = tl_adup(NULL, lst);
+
+ TEST_1(dup != NULL);
+ TEST_SIZE(tl_len(dup), 5 * sizeof(tagi_t));
+ TEST_SIZE(tl_xtra(dup, 0), strlen("Moro" "Vaan" "Foo") + 3);
+
+ su_free(NULL, dup);
+
+ dup = tl_llist(TAG_B("Moi"), TAG_NEXT(lst));
+
+ TEST_P(dup[0].t_tag, tag_b);
+ TEST_P(dup[1].t_tag, tag_a);
+ TEST_P(dup[2].t_tag, tag_a);
+ TEST_P(dup[3].t_tag, tag_i);
+ TEST_P(dup[4].t_tag, tag_a);
+ TEST_P(dup[5].t_tag, NULL);
+
+ su_free(NULL, dup);
+
+ dup = tl_llist(TAG_NEXT(NULL));
+ TEST_P(dup[0].t_tag, 0);
+ su_free(NULL, dup);
+
+ dup = tl_llist(TAG_END());
+ TEST_P(dup[0].t_tag, 0);
+ su_free(NULL, dup);
+
+ dup = tl_llist(TAG_SKIP(1), TAG_NEXT(lst + 4));
+ TEST_P(dup[0].t_tag, tag_a);
+ TEST_P(dup[1].t_tag, 0);
+ su_free(NULL, dup);
+
+ tl_vfree(lst);
+
+ END();
+}
+
+/* filtering function */
+int filter(tagi_t const *filter, tagi_t const *t)
+{
+ if (!t)
+ return 0;
+
+ /* Accept even TAG_I() */
+ if (t->t_tag == tag_i)
+ return (t->t_value & 1) == 0;
+
+ /* TAG_Q(true) */
+ if (t->t_tag == tag_q)
+ return t->t_value != 0;
+
+ /* TAG_P(false) */
+ if (t->t_tag == tag_p)
+ return t->t_value == 0;
+
+ if (t->t_tag == tag_a) {
+ char const *s = (char *)t->t_value;
+ if (s && 'A' <= *s && *s <= 'Z')
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Test tl_afilter() */
+static int test_filters(void)
+{
+ tagi_t *lst, *filter1, *filter2, *filter3, *filter4, *filter5, *filter6;
+ tagi_t *b, *b1, *b2, *b3, *b4;
+
+ tagi_t *nsfilter, *b5;
+ su_home_t *home;
+
+ BEGIN();
+
+ home = su_home_new(sizeof *home); TEST_1(home);
+
+ lst = tl_list(TAG_A("Moro"),
+ TAG_I(2),
+ TAG_Q(3),
+ TAG_SKIP(2),
+ TAG_A("vaan"),
+ TAG_I(1),
+ TAG_P(2),
+ TAG_NULL());
+
+ filter1 = tl_list(TAG_A(""), TAG_NULL());
+ filter2 = tl_list(TAG_I(0), TAG_NULL());
+ filter3 = tl_list(TAG_A(""), TAG_I(0), TAG_NULL());
+ filter4 = tl_list(TAG_ANY(), TAG_NULL());
+ filter5 = tl_list(TAG_FILTER(filter), TAG_NULL());
+ filter6 = tl_list(TAG_NULL());
+
+ TEST0(lst && filter1 && filter2 && filter3 && filter4 && filter5);
+
+ b1 = tl_afilter(NULL, filter1, lst);
+
+ TEST_SIZE(tl_len(b1), 3 * sizeof(tagi_t));
+ TEST_SIZE(tl_xtra(b1, 0), strlen("Moro" "vaan") + 2);
+
+ b2 = tl_afilter(NULL, filter2, lst);
+
+ TEST_SIZE(tl_len(b2), 3 * sizeof(tagi_t));
+ TEST_SIZE(tl_xtra(b2, 0), 0);
+
+ b3 = tl_afilter(NULL, filter3, lst);
+
+ TEST_SIZE(tl_len(b3), 5 * sizeof(tagi_t));
+ TEST_SIZE(tl_xtra(b3, 0), strlen("Moro" "vaan") + 2);
+
+ b4 = tl_afilter(NULL, filter4, lst);
+
+ TEST_SIZE(tl_len(b4), 7 * sizeof(tagi_t));
+ TEST_SIZE(tl_xtra(b4, 0), strlen("Moro" "vaan") + 2);
+
+ su_free(NULL, b1); su_free(NULL, b2); su_free(NULL, b3); su_free(NULL, b4);
+
+ nsfilter = tl_list(TAG_ANY_PQ(), TAG_END());
+
+ b5 = tl_afilter(NULL, nsfilter, lst);
+ TEST_SIZE(tl_len(b5), 3 * sizeof(tagi_t));
+ TEST_SIZE(tl_xtra(b5, 0), 0);
+
+ TEST_P(b5[0].t_tag, tag_q);
+ TEST_P(b5[1].t_tag, tag_p);
+
+ b = tl_afilter(home, filter5, lst); TEST_1(b);
+ TEST_P(b[0].t_tag, tag_a);
+ TEST_P(b[1].t_tag, tag_i);
+ TEST_P(b[2].t_tag, tag_q);
+ TEST_P(b[3].t_tag, 0);
+
+ b = tl_afilter(home, filter6, lst); TEST_1(b);
+ TEST_P(b[0].t_tag, 0);
+
+ tl_vfree(filter1); tl_vfree(filter2); tl_vfree(filter3);
+ tl_vfree(filter4); tl_vfree(filter5); tl_vfree(filter6);
+
+ tl_vfree(lst);
+
+ su_home_unref(home);
+
+ END();
+}
+
+/* Test tl_print */
+static int test_print(void)
+{
+ BEGIN();
+
+ tagi_t *lst;
+ FILE *out;
+
+ lst = tl_list(TAG_A("Moro"),
+ TAG_I(2),
+ TAG_J(3),
+ TAG_K(5),
+ TAG_SKIP(2),
+ TAG_A("Vaan"),
+ TAG_B("b"),
+ TAG_I(1),
+ TAG_NULL());
+
+ if (tstflags & tst_verbatim)
+ out = stdout;
+ else
+ out = fopen(DEVNULL, "w");
+
+ if (out) {
+ tl_print(out, "test_print: ", lst);
+
+ if ((tstflags & tst_verbatim) == 0)
+ fclose(out);
+ }
+
+ END();
+}
+
+static int test_tagargs2(tag_type_t tag, tag_value_t value, ...)
+{
+ ta_list ta;
+ tagi_t const *t;
+
+ BEGIN();
+
+ ta_start(ta, tag, value);
+
+ t = ta_args(ta);
+ TEST_P(t->t_tag, tag_a);
+ TEST_S((char *)t->t_value, "a");
+
+ t = tl_next(t);
+ TEST_P(t->t_tag, tag_b);
+ TEST_S((char *)t->t_value, "b");
+
+ ta_end(ta);
+
+ END();
+}
+
+/* Test tagargs) */
+static int test_tagargs(void)
+{
+ return test_tagargs2(TAG_A("a"),
+ TAG_B("b"),
+ TAG_I(1),
+ TAG_J(2),
+ TAG_K(3),
+ TAG_P(0),
+ TAG_Q(-1),
+ TAG_END());
+}
+
+/* Test tl_tgets() and tl_gets() */
+static int test_gets(void)
+{
+ tagi_t *lst, *t;
+ char const *a = "B", *b = "A";
+ int i = 1, j = 0, k = 0, p = -1;
+
+ BEGIN();
+
+ lst = tl_list(TAG_A("Moro"),
+ TAG_I(2),
+ TAG_J(3),
+ TAG_K(5),
+ TAG_P(3),
+ TAG_SKIP(2),
+ TAG_A("Vaan"),
+ TAG_B("b"),
+ TAG_I(1),
+ TAG_NULL());
+
+ TEST_1(lst);
+
+ TEST_1(t = tl_find(lst, tag_i)); TEST(t->t_value, 2);
+ TEST_1(t = tl_find_last(lst, tag_i)); TEST(t->t_value, 1);
+
+ TEST(tl_gets(lst,
+ TAG_A_REF(a),
+ TAG_B_REF(b),
+ TAG_I_REF(i),
+ TAG_J_REF(j),
+ TAG_K_REF(k),
+ TAG_P_REF(p),
+ TAG_END()),
+ 6);
+
+ /* tl_gets() semantics have changed */
+#if 0
+ TEST_S(a, "Moro");
+ TEST(i, 2);
+#else
+ TEST_S(a, "Vaan");
+ TEST(i, 1);
+#endif
+ TEST(j, 3);
+ TEST(k, 5);
+ TEST(p, 1);
+ TEST_S(b, "b");
+
+ lst = tl_list(TAG_A_REF(a),
+ TAG_I_REF(i),
+ TAG_NULL());
+
+ TEST(tl_tgets(lst, TAG_A("Foo"), TAG_I(-1), TAG_END()), 2);
+
+ TEST_S(a, "Foo");
+ TEST(i, -1);
+
+ END();
+}
+
+static int test_scan(void)
+{
+ tag_value_t v = 0;
+
+ BEGIN();
+
+ TEST(t_scan(tag_a, NULL, NULL, &v), -1); /* Invalid case */
+
+ TEST(t_scan(tag_a, NULL, "foo", &v), 1);
+ TEST_S((char *)v, "foo");
+ su_free(NULL, (void *)v);
+
+ TEST(t_scan(tag_i, NULL, "", &v), -1); /* Invalid case */
+ TEST(t_scan(tag_i, NULL, "kukkuu-reset", &v), -1); /* Invalid case */
+
+ TEST(t_scan(tag_i, NULL, "-1234", &v), 1);
+ TEST(v, -1234);
+
+ TEST(t_scan(tag_n, NULL, "", &v), -1); /* Invalid case */
+
+ TEST(t_scan(tag_n, NULL, "3243432", &v), 1);
+ TEST(v, 3243432);
+
+ TEST(t_scan(tag_p, NULL, "kukkuu-reset", &v), -1); /* Invalid case */
+ TEST(t_scan(tag_p, NULL, "", &v), -1); /* Invalid case */
+
+ TEST(t_scan(tag_p, NULL, "true", &v), 1);
+ TEST(v, 1);
+
+ TEST(t_scan(tag_p, NULL, "true ", &v), 1);
+ TEST(v, 1);
+
+ TEST(t_scan(tag_p, NULL, " 134 ", &v), 1);
+ TEST(v, 1);
+
+ TEST(t_scan(tag_p, NULL, "false \n\t", &v), 1);
+ TEST(v, 0);
+
+ TEST(t_scan(tag_p, NULL, " 000.000 ", &v), 1);
+ TEST(v, 0);
+
+ TEST(t_scan(tag_null, NULL, "NULL", &v), -2);
+ TEST(t_scan(tag_skip, NULL, "SKIP", &v), -2);
+ TEST(t_scan(tag_any, NULL, "any", &v), -2);
+
+ TEST(t_scan(NULL, NULL, "-1234", &v), -1);
+ TEST(t_scan(tag_a, NULL, NULL, &v), -1);
+ TEST(t_scan(tag_a, NULL, "-1234", NULL), -1);
+
+ END();
+}
+
+void usage(void)
+{
+ fprintf(stderr,
+ "usage: %s [-v]\n",
+ name);
+}
+
+int main(int argc, char *argv[])
+{
+ int retval = 0;
+ int i;
+
+ init_tags();
+
+ for (i = 1; argv[i]; i++) {
+ if (strcmp(argv[i], "-v") == 0)
+ tstflags |= tst_verbatim;
+ else
+ usage();
+ }
+
+ retval |= test_assumptions();
+ retval |= test_stackargs(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
+ retval |= test_dup();
+ retval |= test_filters();
+ retval |= test_print();
+ retval |= test_tagargs();
+ retval |= test_gets();
+ retval |= test_scan();
+
+ return retval;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_time.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_time.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,218 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005,2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_time
+ *
+ * @IFILE torture_su_time.c
+ *
+ * Tests for su_time functions.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Kai Vehmanen <first.surname at nokia.com>
+ *
+ * @date Created: Fri May 10 16:08:18 2002 ppessi
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#include <sofia-sip/su_time.h>
+
+#define TSTFLAGS flags
+
+#include <sofia-sip/tstdef.h>
+
+char const *name = "torture_su_time.c";
+
+static int test1(int flags);
+static int test2(int flags);
+static int test3(int flags);
+
+void usage(void)
+{
+ fprintf(stderr,
+ "usage: %s [-v]\n",
+ name);
+}
+
+char *lastpart(char *path)
+{
+ if (strchr(path, '/'))
+ return strrchr(path, '/') + 1;
+ else
+ return path;
+}
+
+int main(int argc, char *argv[])
+{
+ int flags = 0;
+ int retval = 0;
+ int i;
+
+ name = lastpart(argv[0]); /* Set our name */
+
+ for (i = 1; argv[i]; i++) {
+ if (strcmp(argv[i], "-v") == 0)
+ flags |= tst_verbatim;
+ else
+ usage();
+ }
+
+ retval |= test1(flags); fflush(stdout);
+ retval |= test2(flags); fflush(stdout);
+ retval |= test3(flags); fflush(stdout);
+
+ return retval;
+}
+
+su_time_t tv0;
+
+void su_time(su_time_t *tv)
+{
+ *tv = tv0;
+}
+
+int test1(int flags)
+{
+ uint32_t ntp_hi, ntp_lo, ntp_mw;
+ su_time_t now;
+ su_ntp_t ntp, ntp0, ntp1;
+
+ BEGIN();
+
+ ntp_hi = 2208988800UL;
+ ntp_lo = ((su_ntp_t)500000 << 32) / 1000000;
+ ntp_mw = (ntp_hi << 16) | (ntp_lo >> 16);
+
+ tv0.tv_sec = ntp_hi;
+ tv0.tv_usec = 500000UL;
+ ntp0 = (((su_ntp_t)2208988800UL) << 32) + ntp_lo;
+ ntp1 = (((su_ntp_t)2208988800UL) << 32);
+
+ now = su_now();
+
+ TEST(now.tv_sec, 2208988800UL);
+ TEST(now.tv_usec, 500000);
+
+ ntp = su_ntp_now();
+ TEST64(ntp, ntp0);
+ TEST64(su_ntp_hi(ntp), ntp_hi);
+ TEST64(su_ntp_lo(ntp), ntp_lo);
+ TEST64(su_ntp_mw(ntp), ntp_mw);
+ TEST(su_ntp_fraq(tv0), ntp_mw);
+
+ tv0.tv_usec = 0;
+ ntp = su_ntp_now();
+ TEST64(ntp, ntp1);
+ TEST64(su_ntp_hi(ntp), ntp_hi);
+ TEST64(su_ntp_lo(ntp), 0);
+ TEST64(su_ntp_mw(ntp), (ntp_hi & 0xffff) << 16);
+ TEST(su_ntp_fraq(tv0), su_ntp_mw(ntp));
+
+ END();
+}
+
+#include <sofia-sip/su_uniqueid.h>
+#include <sofia-sip/su.h> /* htonl() and guys */
+
+int test2(int flags)
+{
+ char buf[64];
+ su_guid_t g1[1], g2[2];
+ uint64_t tl;
+ uint16_t seq1, seq2;
+ const uint64_t granularity = 10000000U;
+ const uint64_t ntp_epoch =
+ (uint64_t)(141427) * (24 * 60 * 60L) * granularity;
+ isize_t i;
+
+ BEGIN();
+
+ tv0.tv_sec = 268435455;
+ tv0.tv_usec = 98765;
+
+ tl = tv0.tv_sec * granularity + tv0.tv_usec * (granularity / 1000000);
+ tl += ntp_epoch;
+
+ su_guid_generate(g1);
+ seq1 = ((g1->s.clock_seq_hi_and_reserved & 0x3f) << 8) + g1->s.clock_seq_low;
+ TEST(g1->s.time_low, htonl(tl & 0xffffFFFFU));
+ TEST(g1->s.time_mid, htons((tl >> 32) & 0xffffU));
+ TEST(g1->s.time_high_and_version, htons(((tl >> 48) & 0xfffU) | 0x1000));
+ TEST(g1->s.clock_seq_hi_and_reserved & 0xc0, 0x80);
+
+ TEST(i = su_guid_sprintf(buf, sizeof(buf), g1), su_guid_strlen);
+ TEST_SIZE(strlen(buf), i);
+
+ tv0.tv_usec++;
+ su_guid_generate(g1);
+ seq2 = ((g1->s.clock_seq_hi_and_reserved & 0x3f) << 8) + g1->s.clock_seq_low;
+ TEST(seq1, seq2);
+
+ su_guid_generate(g2);
+ seq2 = ((g2->s.clock_seq_hi_and_reserved & 0x3f) << 8) + g2->s.clock_seq_low;
+ TEST(g2->s.time_low, g1->s.time_low);
+ TEST(g2->s.time_mid, g1->s.time_mid);
+ TEST(g2->s.time_high_and_version, g1->s.time_high_and_version);
+ TEST((seq1 + 1) % 16384, seq2);
+
+ for (i = 0; i < 32000; i++) {
+ su_guid_generate(g2);
+ seq2 = ((g2->s.clock_seq_hi_and_reserved & 0x3f) << 8)
+ + g2->s.clock_seq_low;
+ TEST((seq1 + i + 2) % 16384, seq2);
+ }
+
+ END();
+}
+
+int test3(int flags)
+{
+ su_time_t a = { ULONG_MAX , ULONG_MAX };
+ su_time_t b = { 0 , 0 };
+ su_time_t c = { ULONG_MAX , ULONG_MAX - 1 };
+
+ BEGIN();
+
+ TEST_1(su_time_cmp(a, b) > 0);
+ TEST_1(su_time_cmp(a, a) == 0);
+ TEST_1(su_time_cmp(b, a) < 0);
+ TEST_1(su_time_cmp(a, c) > 0);
+ TEST_1(su_time_cmp(c, c) == 0);
+ TEST_1(su_time_cmp(c, a) < 0);
+
+ TEST_1(SU_TIME_CMP(a, b) > 0);
+ TEST_1(SU_TIME_CMP(a, a) == 0);
+ TEST_1(SU_TIME_CMP(b, a) < 0);
+ TEST_1(SU_TIME_CMP(a, c) > 0);
+ TEST_1(SU_TIME_CMP(c, c) == 0);
+ TEST_1(SU_TIME_CMP(c, a) < 0);
+
+ END();
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_timer.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su_timer.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,261 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@ingroup su_root_ex
+ * @CFILE torture_su_timer.c
+ *
+ * @brief Test program for su timers
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @internal
+ *
+ * @date Created: Fri Oct 19 08:53:55 2001 pessi
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <signal.h>
+
+#include <assert.h>
+
+struct tester;
+
+#define SU_ROOT_MAGIC_T struct tester
+#define SU_INTERNAL_P su_root_t *
+#define SU_TIMER_ARG_T struct timing
+
+#include "sofia-sip/su.h"
+#include "sofia-sip/su_wait.h"
+#include "sofia-sip/su_log.h"
+
+struct timing
+{
+ int t_run;
+ int t_times;
+ su_time_t t_prev;
+};
+
+struct tester
+{
+ su_root_t *root;
+ su_timer_t *t, *t1;
+ unsigned times;
+ void *sentinel;
+};
+
+void
+print_stamp(struct tester *x, su_timer_t *t, struct timing *ti)
+{
+ su_time_t now = su_now(), prev = ti->t_prev;
+
+ ti->t_prev = now;
+
+ if (!ti->t_run)
+ su_timer_set(t, print_stamp, ti);
+
+ printf("timer interval %f\n", 1000 * su_time_diff(now, prev));
+
+ if (++ti->t_times >= 10)
+ su_timer_reset(t);
+}
+
+void
+print_X(struct tester *x, su_timer_t *t1, struct timing *ti)
+{
+ su_timer_set(t1, print_X, ti);
+ putchar('X'); fflush(stdout);
+}
+
+su_msg_r intr_msg = SU_MSG_R_INIT;
+
+static RETSIGTYPE intr_handler(int signum)
+{
+ su_msg_send(intr_msg);
+}
+
+static void test_break(struct tester *tester, su_msg_r msg, su_msg_arg_t *arg)
+{
+ su_root_break(tester->root);
+}
+
+void
+end_test(struct tester *tester, su_timer_t *t, struct timing *ti)
+{
+ su_timer_destroy(t);
+ su_timer_reset(tester->t);
+ su_timer_reset(tester->t1);
+ su_root_break(tester->root);
+}
+
+void
+increment(struct tester *tester, su_timer_t *t, struct timing *ti)
+{
+ tester->times++;
+
+ if ((void *)ti == (void*)tester->sentinel)
+ su_root_break(tester->root);
+}
+
+void
+usage(char const *name)
+{
+ fprintf(stderr, "usage: %s [-1r] [-Nnum] [interval]\n", name);
+ exit(1);
+}
+
+/*
+ * test su_timer functionality:
+ *
+ * Create a timer, executing print_stamp() in every 20 ms
+ */
+int main(int argc, char *argv[])
+{
+ su_root_t *root;
+ su_timer_t *t, *t1, *t_end;
+ su_timer_t **timers;
+ su_duration_t interval = 60;
+ char *argv0 = argv[0];
+ char *s;
+ int use_t1 = 0;
+ su_time_t now, started;
+ intptr_t i, N = 500;
+
+ struct timing timing[1] = {{ 0 }};
+ struct tester tester[1] = {{ 0 }};
+
+ while (argv[1] && argv[1][0] == '-') {
+ char *o = argv[1] + 1;
+ while (*o) {
+ if (*o == '1')
+ o++, use_t1 = 1;
+ else if (*o == 'r')
+ o++, timing->t_run = 1;
+ else if (*o == 'N') {
+ if (o[1])
+ N = strtoul(o + 1, &o, 0);
+ else if (argv[2])
+ N = strtoul(argv++[2], &o, 0);
+ break;
+ }
+ else
+ break;
+
+ }
+ if (*o)
+ usage(argv0);
+ argv++;
+ }
+
+ if (argv[1]) {
+ interval = strtoul(argv[1], &s, 10);
+
+ if (interval == 0 || s == argv[1])
+ usage(argv0);
+ }
+
+ su_init(); atexit(su_deinit);
+
+ tester->root = root = su_root_create(tester);
+
+ su_msg_create(intr_msg,
+ su_root_task(root),
+ su_root_task(root),
+ test_break, 0);
+
+ signal(SIGINT, intr_handler);
+#if HAVE_SIGPIPE
+ signal(SIGPIPE, intr_handler);
+ signal(SIGQUIT, intr_handler);
+ signal(SIGHUP, intr_handler);
+#endif
+
+ t = su_timer_create(su_root_task(root), interval);
+ t1 = su_timer_create(su_root_task(root), 1);
+ t_end = su_timer_create(su_root_task(root), 20 * interval);
+
+ if (t == NULL || t1 == NULL || t_end == NULL)
+ su_perror("su_timer_create"), exit(1);
+
+ tester->t = t, tester->t1 = t1;
+
+ timing->t_prev = su_now();
+
+ if (timing->t_run)
+ su_timer_run(t, print_stamp, timing);
+ else
+ su_timer_set(t, print_stamp, timing);
+
+ if (use_t1)
+ su_timer_set(t1, print_X, NULL);
+
+ su_timer_set(t_end, end_test, NULL);
+
+ su_root_run(root);
+
+ su_msg_destroy(intr_msg);
+
+ su_timer_destroy(t);
+ su_timer_destroy(t1);
+
+ if (timing->t_times != 10) {
+ fprintf(stderr, "%s: t expired %d times (expecting 10)\n",
+ argv0, timing->t_times);
+ return 1;
+ }
+
+ /* Insert timers in order */
+ timers = calloc(N, sizeof *timers);
+ if (!timers) { perror("calloc"); exit(1); }
+
+ now = started = su_now();
+
+ for (i = 0; i < N; i++) {
+ t = su_timer_create(su_root_task(root), 1000);
+ if (!t) { perror("su_timer_create"); exit(1); }
+ if (++now.tv_usec == 0) ++now.tv_sec;
+ su_timer_set_at(t, increment, (void *)i, now);
+ timers[i] = t;
+ }
+
+ tester->sentinel = (void*)(i - 1);
+
+ su_root_run(root);
+
+ printf("Processing %u timers took %f millisec (%f expected)\n",
+ (unsigned)i, su_time_diff(su_now(), started) * 1000, (double)i / 1000);
+
+ for (i = 0; i < N; i++) {
+ su_timer_destroy(timers[i]);
+ }
+
+ su_root_destroy(root);
+
+ su_deinit();
+
+ return 0;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/ChangeLog Thu Dec 21 01:30:28 2006
@@ -0,0 +1,45 @@
+2006-10-19 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * tport.c (tport_is_shutdown, tport_is_closed): Added to
+ public API.
+
+2006-01-15 Martti Mela <martti.mela at nokia.com>
+
+ * tport.c: integrated initial new STUN support.
+
+2005-11-08 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Renamed tport_test.c as test_tport.c.
+
+2005-10-27 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Added tls_version[] to tport/tport_tls.[hc].
+
+ M ./libsofia-sip-ua/tport/tport_tls.c -2 +4
+ M ./libsofia-sip-ua/tport/tport_tls.h -3 +2
+
+2005-10-24 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * tport.c (tport_bind_server): Avoid segfault
+ if init for a NAT traversal mechanism has failed.
+
+2005-10-18 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Feature #1326002.
+
+ * Added stun_test(), but not running it.
+
+ M ./libsofia-sip-ua/tport/tport_test.c +32
+
+ * Passing tags to stun_engine_tcreate().
+
+ M ./libsofia-sip-ua/tport/tport.c -17 +14
+
+2005-09-08 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * tport_test.c: Fixed error when building without
+ SSL support.
+
+2005-07-18 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * Initial import of the module to Sofia-SIP tree.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/Doxyfile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/Doxyfile Thu Dec 21 01:30:28 2006
@@ -0,0 +1,16 @@
+PROJECT_NAME = "tport"
+OUTPUT_DIRECTORY = ../docs/html/tport
+
+INPUT = tport.docs sofia-sip .
+
+ at INCLUDE = ../docs/Doxyfile.conf
+
+TAGFILES += \
+ ../docs/su.doxytags=../su \
+ ../docs/msg.doxytags=../msg
+
+GENERATE_TAGFILE = ../docs/tport.doxytags
+
+EXCLUDE_PATTERNS += test_*.[hc] torture_*.[hc]
+
+ALIASES +=
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/Makefile.am Thu Dec 21 01:30:28 2006
@@ -0,0 +1,81 @@
+#
+# Makefile.am @template@ for tport module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+INCLUDES = -I$(srcdir)/../bnf -I../bnf \
+ -I$(srcdir)/../stun -I../stun \
+ -I$(srcdir)/../ipt -I../ipt \
+ -I$(srcdir)/../msg -I../msg \
+ -I$(srcdir)/../http -I../http \
+ -I$(srcdir)/../url -I../url \
+ -I$(srcdir)/../su -I../su
+
+# ----------------------------------------------------------------------
+# Build targets
+
+noinst_LTLIBRARIES = libtport.la
+
+bin_PROGRAMS =
+
+check_PROGRAMS = test_tport
+
+TESTS = test_tport
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+
+nobase_include_sofia_HEADERS = \
+ sofia-sip/tport.h sofia-sip/tport_tag.h \
+ sofia-sip/tport_plugins.h
+
+TLS_SRC = tport_type_tls.c tport_tls.c tport_tls.h
+
+if HAVE_TLS
+USE_TLS_SRC = $(TLS_SRC)
+endif
+
+libtport_la_SOURCES = tport.c tport_logging.c \
+ tport_stub_stun.c tport_stub_sigcomp.c \
+ tport_type_udp.c tport_type_tcp.c tport_type_sctp.c \
+ tport_type_connect.c tport_type_stun.c \
+ tport_internal.h \
+ tport_tag.c tport_tag_ref.c $(USE_TLS_SRC)
+
+# to make sure all files end up in the dist package
+EXTRA_libtport_la_SOURCES = $(TLS_SRC)
+
+# Disable for now
+EXTRA_libtport_la_SOURCES += tport_sigcomp.c tport_threadpool.c
+
+BUILT_SOURCES = tport_tag_ref.c
+
+COVERAGE_INPUT = $(libtport_la_SOURCES) $(include_sofia_HEADERS)
+
+LDADD = libtport.la \
+ ../stun/libstun.la \
+ ../sresolv/libsresolv.la \
+ ../ipt/libipt.la \
+ ../http/libhttp.la \
+ ../msg/libtest_msg.a ../msg/libmsg.la \
+ ../url/liburl.la \
+ ../bnf/libbnf.la \
+ ../su/libsu.la
+
+test_tport_LDFLAGS = -static
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+
+EXTRA_DIST = Doxyfile tport.docs \
+ certificates.html agent.pem cafile.pem
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+
+include ../sofia.am
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/Makefile.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1,786 @@
+# 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.
+
+ at SET_MAKE@
+
+#
+# Makefile.am @template@ for tport module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+# common Makefile targets for libsofia-sip-ua modules
+# ---------------------------------------------------
+
+
+
+SOURCES = $(libtport_la_SOURCES) $(EXTRA_libtport_la_SOURCES) test_tport.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@
+bin_PROGRAMS =
+check_PROGRAMS = test_tport$(EXEEXT)
+DIST_COMMON = $(nobase_include_sofia_HEADERS) $(srcdir)/../sofia.am \
+ $(srcdir)/Makefile.am $(srcdir)/Makefile.in ChangeLog
+subdir = libsofia-sip-ua/tport
+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 =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libtport_la_LIBADD =
+am__libtport_la_SOURCES_DIST = tport.c tport_logging.c \
+ tport_stub_stun.c tport_stub_sigcomp.c tport_type_udp.c \
+ tport_type_tcp.c tport_type_sctp.c tport_type_connect.c \
+ tport_type_stun.c tport_internal.h tport_tag.c tport_tag_ref.c \
+ tport_type_tls.c tport_tls.c tport_tls.h
+am__objects_1 = tport_type_tls.lo tport_tls.lo
+ at HAVE_TLS_TRUE@am__objects_2 = $(am__objects_1)
+am_libtport_la_OBJECTS = tport.lo tport_logging.lo tport_stub_stun.lo \
+ tport_stub_sigcomp.lo tport_type_udp.lo tport_type_tcp.lo \
+ tport_type_sctp.lo tport_type_connect.lo tport_type_stun.lo \
+ tport_tag.lo tport_tag_ref.lo $(am__objects_2)
+libtport_la_OBJECTS = $(am_libtport_la_OBJECTS)
+am__installdirs = "$(DESTDIR)$(bindir)" \
+ "$(DESTDIR)$(include_sofiadir)"
+binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+PROGRAMS = $(bin_PROGRAMS)
+test_tport_SOURCES = test_tport.c
+test_tport_OBJECTS = test_tport.$(OBJEXT)
+test_tport_LDADD = $(LDADD)
+test_tport_DEPENDENCIES = libtport.la ../stun/libstun.la \
+ ../sresolv/libsresolv.la ../ipt/libipt.la ../http/libhttp.la \
+ ../msg/libtest_msg.a ../msg/libmsg.la ../url/liburl.la \
+ ../bnf/libbnf.la ../su/libsu.la
+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 = $(libtport_la_SOURCES) $(EXTRA_libtport_la_SOURCES) \
+ test_tport.c
+DIST_SOURCES = $(am__libtport_la_SOURCES_DIST) \
+ $(EXTRA_libtport_la_SOURCES) test_tport.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)/../bnf -I../bnf \
+ -I$(srcdir)/../stun -I../stun \
+ -I$(srcdir)/../ipt -I../ipt \
+ -I$(srcdir)/../msg -I../msg \
+ -I$(srcdir)/../http -I../http \
+ -I$(srcdir)/../url -I../url \
+ -I$(srcdir)/../su -I../su
+
+
+# ----------------------------------------------------------------------
+# Build targets
+noinst_LTLIBRARIES = libtport.la
+TESTS = test_tport
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+nobase_include_sofia_HEADERS = \
+ sofia-sip/tport.h sofia-sip/tport_tag.h \
+ sofia-sip/tport_plugins.h
+
+TLS_SRC = tport_type_tls.c tport_tls.c tport_tls.h
+ at HAVE_TLS_TRUE@USE_TLS_SRC = $(TLS_SRC)
+libtport_la_SOURCES = tport.c tport_logging.c \
+ tport_stub_stun.c tport_stub_sigcomp.c \
+ tport_type_udp.c tport_type_tcp.c tport_type_sctp.c \
+ tport_type_connect.c tport_type_stun.c \
+ tport_internal.h \
+ tport_tag.c tport_tag_ref.c $(USE_TLS_SRC)
+
+
+# to make sure all files end up in the dist package
+
+# Disable for now
+EXTRA_libtport_la_SOURCES = $(TLS_SRC) tport_sigcomp.c \
+ tport_threadpool.c
+BUILT_SOURCES = tport_tag_ref.c
+COVERAGE_INPUT = $(libtport_la_SOURCES) $(include_sofia_HEADERS)
+LDADD = libtport.la \
+ ../stun/libstun.la \
+ ../sresolv/libsresolv.la \
+ ../ipt/libipt.la \
+ ../http/libhttp.la \
+ ../msg/libtest_msg.a ../msg/libmsg.la \
+ ../url/liburl.la \
+ ../bnf/libbnf.la \
+ ../su/libsu.la
+
+test_tport_LDFLAGS = -static
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+EXTRA_DIST = Doxyfile tport.docs \
+ certificates.html agent.pem cafile.pem
+
+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
+
+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/tport/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu libsofia-sip-ua/tport/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-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
+libtport.la: $(libtport_la_OBJECTS) $(libtport_la_DEPENDENCIES)
+ $(LINK) $(libtport_la_LDFLAGS) $(libtport_la_OBJECTS) $(libtport_la_LIBADD) $(LIBS)
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)"
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ if test -f $$p \
+ || test -f $$p1 \
+ ; then \
+ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \
+ else :; fi; \
+ done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \
+ rm -f "$(DESTDIR)$(bindir)/$$f"; \
+ done
+
+clean-binPROGRAMS:
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f $$p $$f"; \
+ rm -f $$p $$f ; \
+ done
+
+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
+test_tport$(EXEEXT): $(test_tport_OBJECTS) $(test_tport_DEPENDENCIES)
+ @rm -f test_tport$(EXEEXT)
+ $(LINK) $(test_tport_LDFLAGS) $(test_tport_OBJECTS) $(test_tport_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_tport.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tport.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tport_logging.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tport_sigcomp.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tport_stub_sigcomp.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tport_stub_stun.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tport_tag.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tport_tag_ref.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tport_threadpool.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tport_tls.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tport_type_connect.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tport_type_sctp.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tport_type_stun.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tport_type_tcp.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tport_type_tls.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tport_type_udp.Plo at am__quote@
+
+.c.o:
+ at am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+ at am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ at am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at 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 $(LTLIBRARIES) $(PROGRAMS) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(bindir)" "$(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-binPROGRAMS clean-checkPROGRAMS clean-generic \
+ clean-libtool 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-nobase_include_sofiaHEADERS
+
+install-exec-am: install-binPROGRAMS
+
+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-binPROGRAMS uninstall-info-am \
+ uninstall-nobase_include_sofiaHEADERS
+
+.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \
+ clean-binPROGRAMS clean-checkPROGRAMS clean-generic \
+ clean-libtool 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-binPROGRAMS install-data \
+ install-data-am 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-binPROGRAMS \
+ 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) $<
+
+ at ENABLE_COVERAGE_TRUE@coverage:
+ at 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)
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+# 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:
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/agent.pem
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/agent.pem Thu Dec 21 01:30:28 2006
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIDPjCCAqegAwIBAgIHJQIBAZACBjANBgkqhkiG9w0BAQUFADBwMQswCQYDVQQG
+EwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTERMA8GA1UEBxMIU2FuIEpvc2UxDjAM
+BgNVBAoTBXNpcGl0MSkwJwYDVQQLEyBTaXBpdCBUZXN0IENlcnRpZmljYXRlIEF1
+dGhvcml0eTAeFw0wMzEyMDMxODMwMjJaFw0wNjEyMDIxODMwMjJaMGUxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMREwDwYDVQQHEwhTYW4gSm9zZTEO
+MAwGA1UEChMFc2lwaXQxHjAcBgNVBAMTFXBla2thLm5va2lhLnNpcGl0Lm5ldDCB
+nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAsdJn/O6JoIC1I2iXOVJLQypmt9sN
+HmvB84853Qx9KS+xqP3U2nqNMnDQby6ZmTsRHNGAK5QuGugU11wocmYNP0/TQFaz
+KNLhNt0pMBOfpAV9vG6pCSkocObsUo2XFULPTEB/SzGcvE1G1em3XmwRfPA178y9
+L2+sVNT5Vtt5KfMCAwEAAaOB7DCB6TAgBgNVHREEGTAXghVwZWtrYS5ub2tpYS5z
+aXBpdC5uZXQwCQYDVR0TBAIwADAdBgNVHQ4EFgQU1OjdL9cdA0NNbxPDQ9xZUZG6
+NnIwgZoGA1UdIwSBkjCBj4AUa0YXFOqUdiWAVG4TVNqh41QUobahdKRyMHAxCzAJ
+BgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMREwDwYDVQQHEwhTYW4gSm9z
+ZTEOMAwGA1UEChMFc2lwaXQxKTAnBgNVBAsTIFNpcGl0IFRlc3QgQ2VydGlmaWNh
+dGUgQXV0aG9yaXR5ggEAMA0GCSqGSIb3DQEBBQUAA4GBADCO35LJqgiK5OUR+DuT
+N4CfUhsn9T5kDSf2rikna4ZFbuS7smc/oVu4g26HHjt6DKs4UEx9OmyXFslSENZ+
+tFNeVClpHJrPsNwjk/uyjhfeW1NezhXMIi6q8DYcwE5I7r+Uz2XST+jWCTb4obPY
+10ysI7e7/rgCoITe+qO2U35D
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQCx0mf87omggLUjaJc5UktDKma32w0ea8HzjzndDH0pL7Go/dTa
+eo0ycNBvLpmZOxEc0YArlC4a6BTXXChyZg0/T9NAVrMo0uE23SkwE5+kBX28bqkJ
+KShw5uxSjZcVQs9MQH9LMZy8TUbV6bdebBF88DXvzL0vb6xU1PlW23kp8wIDAQAB
+AoGAVtICT64vqBvvVPB2FVimwo5rRI1BJH88XSyq9dBpM7jDp1z3lgyL7/rA6ef4
+uqXqPwXS7HQW5rA1rMikPuawxE5UG31OG3U0+H/OGl0xwAq57mEtRDR8464jSUPY
+l9bzkRpjnEgdUtkLnogm8F4mALexdc3KxIgg3uo/OOg0N5ECQQDZon1JBNEYWxEF
+GBNbEvQthPy7rRLmxontgcsfhRvm5lSbuC+VP1uRHibwwIrXOUZD8uuEVdVZNzfV
+bGPdh70HAkEA0Ss6HyAWczRBzrvC8eVvPmkI9XihdLqUFLTDL0R1sMCISwW/FEeH
+X9yFqOY+y6EJAitzhxtol+0k+UsIJl5ctQJAXU0L6QHnokloQobPxXuasukQcGUC
+dW0oNGowapLmI1cbbqbHv3QqDUyf5Rambx5ewUKjNViW3miNxzFwnshSgQJAINuQ
+gskwnaJM4CPgqM0o333yeVUcz9BraKFItAkmD8D+6AIcFRxzaJykpnac0LIYTy3y
+NPwaPxtynnKp8hUKrQJBAM1i5051UzJVFuRedwtPdGDrfkNwoJm27fwWozSQcBC6
+G5VnTrQ6V8VCJglNzVhy9b2WqlqfWV3D5BCgxyuH984=
+-----END RSA PRIVATE KEY-----
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/cafile.pem
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/cafile.pem Thu Dec 21 01:30:28 2006
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDJDCCAo2gAwIBAgIBADANBgkqhkiG9w0BAQUFADBwMQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTERMA8GA1UEBxMIU2FuIEpvc2UxDjAMBgNVBAoT
+BXNpcGl0MSkwJwYDVQQLEyBTaXBpdCBUZXN0IENlcnRpZmljYXRlIEF1dGhvcml0
+eTAeFw0wMzA3MTgxMjIxNTJaFw0xMzA3MTUxMjIxNTJaMHAxCzAJBgNVBAYTAlVT
+MRMwEQYDVQQIEwpDYWxpZm9ybmlhMREwDwYDVQQHEwhTYW4gSm9zZTEOMAwGA1UE
+ChMFc2lwaXQxKTAnBgNVBAsTIFNpcGl0IFRlc3QgQ2VydGlmaWNhdGUgQXV0aG9y
+aXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDIh6DkcUDLDyK9BEUxkud
++nJ4xrCVGKfgjHm6XaSuHiEtnfELHM+9WymzkBNzZpJu30yzsxwfKoIKugdNUrD4
+N3viCicwcN35LgP/KnbN34cavXHr4ZlqxH+OdKB3hQTpQa38A7YXdaoz6goW2ft5
+Mi74z03GNKP/G9BoKOGd5QIDAQABo4HNMIHKMB0GA1UdDgQWBBRrRhcU6pR2JYBU
+bhNU2qHjVBShtjCBmgYDVR0jBIGSMIGPgBRrRhcU6pR2JYBUbhNU2qHjVBShtqF0
+pHIwcDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExETAPBgNVBAcT
+CFNhbiBKb3NlMQ4wDAYDVQQKEwVzaXBpdDEpMCcGA1UECxMgU2lwaXQgVGVzdCBD
+ZXJ0aWZpY2F0ZSBBdXRob3JpdHmCAQAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0B
+AQUFAAOBgQCWbRvv1ZGTRXxbH8/EqkdSCzSoUPrs+rQqR0xdQac9wNY/nlZbkR3O
+qAezG6Sfmklvf+DOg5RxQq/+Y6I03LRepc7KeVDpaplMFGnpfKsibETMipwzayNQ
+QgUf4cKBiF+65Ue7hZuDJa2EMv8qW4twEhGDYclpFU9YozyS1OhvUg==
+-----END CERTIFICATE-----
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/certificates.html
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/certificates.html Thu Dec 21 01:30:28 2006
@@ -0,0 +1,61 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+
+<html>
+<head>
+<title>Generating SSL/TLS certificates for SIP agents and proxies</title>
+</head>
+<body>
+<h1>Generating SSL/TLS certificates for SIP agents and proxies</h1>
+<h2>Prerequisites</h2>
+The openssl v0.96 or higher must be installed to create the certificates.
+
+<h2>To generate the random seed file</h2>
+<strong><pre>$ tport_rand tls_seed.dat
+</pre>
+</strong>
+
+<h2>To generate the root authority certificate</h2>
+<strong><pre>
+$ make_root_cert.pl \
+ -cn <root common name>\
+ -dns <comma separated list of root dns names>\
+ [-prefix <prefix for the generated files> (default root)]\
+ [-rand <random seed file> (default tls_seed.dat)]</pre></strong>
+
+This command will generate files <strong><prefix>key.pem</strong> (root private key),
+<strong><prefix>cert.pem</strong> (root certificate) and <strong><prefix>.pem</strong> (combination
+of the key and the certificate). The latter file will be used to sign the node certificates.
+
+<h2>To generate a certificate for a single node (user agent or proxy)</h2>
+<strong><pre>
+$ make_node_cert.pl \
+ -cn <node common name>\
+ -dns <comma separated list of node dns names>\
+ [-ca <cafile> (default root.pem)]\
+ [-prefix <prefix for the generated files> (default agent)]\
+ [-rand <random seed file> (default tls_seed.dat)]
+</pre></strong>
+This command will generate files <strong><prefix>key.pem </strong> (node private key),
+<strong><prefix>cert.pem</strong> (node certificate) and <strong><prefix>.pem</strong> (combination
+of the key and the certificate). The certificate has been signed with ca certificate
+contained in <strong><cafile></strong>.
+
+<h2>Installing the certificates to the nodes</h2>
+
+<ol>
+
+<li>Copy the root certificate file (<strong>rootcert.pem</strong> by default - <strong>not root.pem or rootkey.pem!</strong>),
+the combined node certificate+key file (<strong>agent.pem</strong>) and <strong>tls_seed.dat</strong> to the tls configuration
+directory (default <strong>$HOME/.sip/auth</strong>)</li>
+
+<li>Rename <strong>rootcert.pem</strong> as <strong>cafile.pem</strong></li>
+</ol>
+<p>
+<strong>Note that files agent.pem and tls_seed.dat must be kept secret to
+ensure secure connection</strong>
+</p>
+
+</ol>
+</body>
+</html>
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/make_node_cert.pl
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/make_node_cert.pl Thu Dec 21 01:30:28 2006
@@ -0,0 +1,59 @@
+#!/usr/bin/perl
+
+use strict;
+use Getopt::Long;
+use File::Temp;
+
+my $cn;
+my @dns = ();
+my $cafile = "root.pem";
+my $prefix = "agent";
+my $rand = "tls_seed.dat";
+my $help = 0;
+
+GetOptions('help' => \$help,
+ 'cn=s' => \$cn,
+ 'dns=s' => \@dns,
+ 'ca=s' => \$cafile,
+ 'prefix=s' => \$prefix,
+ 'rand=s' => \$rand);
+
+ at dns = split(/,/,join(',', at dns));
+
+if ($help || !$cn || !@dns) {
+ print "Usage: make_node_cert -cn <common name>\n".
+ " -dns <comma separated list of dns names>\n".
+ " [-ca cafile (default root.pem)]\n".
+ " [-prefix prefix (default agent)]\n".
+ " [-rand <random seed file>]\n";
+ exit 0;
+}
+
+$_ = "DNS:$_" for @dns;
+
+my $dnsstring = join(',', @dns);
+
+my ($fh, $filename) = File::Temp::tempfile(UNLINK => 1);
+
+print $fh <<"EOF";
+[ req ]
+default_bits = 1024
+prompt = no
+distinguished_name = req_dn
+
+[ req_dn ]
+commonName = $cn
+
+[ ext ]
+basicConstraints=CA:FALSE
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid,issuer:always
+subjectAltName=$dnsstring
+keyUsage=digitalSignature:TRUE,keyEncipherment:TRUE
+EOF
+
+system("openssl req -newkey rsa -nodes -keyout ${prefix}key.pem -sha1 -out ${prefix}req.pem -config $filename -rand $rand");
+
+system("openssl x509 -req -in ${prefix}req.pem -sha1 -extensions ext -CA $cafile -CAkey $cafile -out ${prefix}cert.pem -CAcreateserial -extfile $filename");
+
+system("cat ${prefix}cert.pem ${prefix}key.pem >${prefix}.pem");
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/make_root_cert.pl
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/make_root_cert.pl Thu Dec 21 01:30:28 2006
@@ -0,0 +1,56 @@
+#!/usr/bin/perl
+
+use strict;
+use Getopt::Long;
+use File::Temp;
+
+my $cn;
+my @dns = ();
+my $prefix = "root";
+my $rand = "tls_seed.dat";
+my $help = 0;
+
+GetOptions('help' => \$help,
+ 'cn=s' => \$cn,
+ 'dns=s' => \@dns,
+ 'prefix=s' => \$prefix,
+ 'rand=s' => \$rand);
+
+ at dns = split(/,/,join(',', at dns));
+
+if ($help || !$cn || !@dns) {
+ print "Usage: make_root_cert -cn <common name>\n".
+ " -dns <comma separated list of dns names>\n".
+ " [-prefix <name prefix>]\n".
+ " [-rand <random seed file>\n]";
+ exit 0;
+}
+
+$_ = "DNS:$_" for @dns;
+
+my $dnsstring = join(',', @dns);
+
+my ($fh, $filename) = File::Temp::tempfile(UNLINK => 1);
+
+print $fh <<"EOF";
+[ req ]
+default_bits = 1024
+prompt = no
+distinguished_name = req_dn
+
+[ req_dn ]
+commonName = $cn
+
+[ ext ]
+basicConstraints = CA:TRUE
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid:always,issuer:always
+subjectAltName=$dnsstring
+EOF
+
+system("openssl req -newkey rsa -nodes -keyout ${prefix}key.pem -sha1 -out ${prefix}req.pem -config $filename -rand $rand");
+
+system("openssl x509 -req -in ${prefix}req.pem -sha1 -extensions ext -signkey ${prefix}key.pem -out ${prefix}cert.pem -extfile $filename");
+
+system("cat ${prefix}cert.pem ${prefix}key.pem >${prefix}.pem");
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/make_test_certs.sh
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/make_test_certs.sh Thu Dec 21 01:30:28 2006
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+basedir=`dirname $0`
+
+mkdir -p test/server
+mkdir -p test/client
+
+./tport_rand tls_seed.dat
+
+cp tls_seed.dat test/server
+cp tls_seed.dat test/client
+
+./make_root_cert.pl -cn test_root -dns test_root.sip.nokia.com
+cp rootcert.pem test/client/cafile.pem
+cp rootcert.pem test/server/cafile.pem
+
+./make_node_cert.pl -cn test_client -dns test_client.sip.nokia.com
+cp agent.pem test/client
+
+./make_node_cert.pl -cn test_server -dns test_server.sip.nokia.com
+cp agent.pem test/server
+
+rm agent*.pem
+rm root*.pem
+rm tls_seed.dat
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,421 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef TPORT_H
+/** Defined when <sofia-sip/tport.h> has been included. */
+#define TPORT_H
+/**@file sofia-sip/tport.h
+ * @brief Transport interface
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Jun 29 15:58:06 2000 ppessi
+ */
+
+#ifndef SU_H
+#include <sofia-sip/su.h>
+#endif
+#ifndef SU_WAIT_H
+#include <sofia-sip/su_wait.h>
+#endif
+#ifndef MSG_H
+#include <sofia-sip/msg.h>
+#endif
+#ifndef URL_H
+#include <sofia-sip/url.h>
+#endif
+#ifndef TPORT_TAG_H
+#include <sofia-sip/tport_tag.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+struct tport_s;
+#ifndef TPORT_T
+#define TPORT_T struct tport_s
+typedef TPORT_T tport_t;
+#endif
+
+#ifndef TP_STACK_T
+#ifndef TP_AGENT_T
+#define TP_STACK_T struct tp_stack_s
+#else
+#define TP_STACK_T TP_AGENT_T
+#endif
+#endif
+/** Type of stack object */
+typedef TP_STACK_T tp_stack_t;
+
+#ifndef TP_MAGIC_T
+/** Type of transport-protocol-specific context. @sa @ref tp_magic */
+#define TP_MAGIC_T struct tp_magic_s
+#endif
+/** Type of transport-protocol-specific context object. */
+typedef TP_MAGIC_T tp_magic_t;
+
+#ifndef TP_CLIENT_T
+#define TP_CLIENT_T struct tp_client_s
+#endif
+/** Transaction object given as a reference to the transport.
+ *
+ * This type is used when transport reports errors with pending requests.
+ */
+typedef TP_CLIENT_T tp_client_t;
+
+struct sigcomp_compartment;
+struct sigcomp_udvm;
+
+/** Interface towards stack. */
+typedef struct {
+ int tpac_size;
+
+ /** Function used to pass a received message to the protocol stack */
+ void (*tpac_recv)(tp_stack_t *, tport_t *, msg_t *msg, tp_magic_t *magic,
+ su_time_t received);
+
+ /** Function used to indicate an error to the protocol stack */
+ void (*tpac_error)(tp_stack_t *, tport_t *,
+ int errcode, char const *remote);
+
+ /** Ask stack to allocate a message. */
+ msg_t *(*tpac_alloc)(tp_stack_t *, int flags,
+ char const [], usize_t,
+ tport_t const *, tp_client_t *);
+
+ /** Indicate stack that address has changed */
+ void (*tpac_address)(tp_stack_t *, tport_t *);
+
+} tport_stack_class_t;
+
+/* Compatibility */
+typedef tport_stack_class_t tp_stack_class_t;
+
+/** Callback to report error by pending requests. */
+typedef void tport_pending_error_f(tp_stack_t *, tp_client_t *,
+ tport_t *, msg_t *msg, int error);
+
+enum {
+ /** Maximum number of messages in send queue. */
+ TPORT_QUEUESIZE = 64
+};
+
+
+/* AI extension flags - these must not overlap with existing AI flags. */
+
+/** Message is to be sent/received compressed */
+#define TP_AI_COMPRESSED 0x01000
+/** Message is to be sent/received on secure connection */
+#define TP_AI_SECURE 0x02000
+
+/** Halfclose (shutdown(c, 1)) connection after sending message */
+#define TP_AI_SHUTDOWN 0x04000
+/** Close connection (shutdown(c, 2)) after sending message */
+#define TP_AI_CLOSE 0x08000
+
+/** Address was inaddr_any */
+#define TP_AI_ANY 0x80000
+
+#define TP_AI_MASK 0xff000
+
+/** Maximum size of a @e host:port string, including final NUL. */
+#define TPORT_HOSTPORTSIZE (55)
+
+/** Transport name.
+ *
+ * This structure represents the address of the transport in textual format.
+ * For primary transports, the transport name contains the local address,
+ * for secondary transports, the peer address.
+ *
+ * The tpn_ident specifies the transport identifier used to make difference
+ * between connectivity domains.
+ */
+typedef struct {
+ char const *tpn_proto; /**< Protocol name ("udp", "tcp", etc.) */
+ char const *tpn_canon; /**< Node DNS name (if known). */
+ char const *tpn_host; /**< Node address in textual format */
+ char const *tpn_port; /**< Port number in textual format. */
+ char const *tpn_comp; /**< Compression algorithm (NULL if none) */
+ char const *tpn_ident; /**< Transport identifier (NULL if none) */
+} tp_name_t;
+
+#define TPN_FORMAT "%s/%s:%s%s%s%s%s"
+
+#define TPN_ARGS(n) \
+ (n)->tpn_proto, (n)->tpn_host, (n)->tpn_port, \
+ (n)->tpn_comp ? ";comp=" : "", (n)->tpn_comp ? (n)->tpn_comp : "", \
+ (n)->tpn_ident ? "/" : "", (n)->tpn_ident ? (n)->tpn_ident : ""
+
+/** Create first primary transport. */
+TPORT_DLL tport_t *tport_tcreate(tp_stack_t *stack,
+ tport_stack_class_t const *tpac,
+ su_root_t *root,
+ tag_type_t tag, tag_value_t value, ...);
+
+/** Bind transports to network. */
+TPORT_DLL int tport_tbind(tport_t *self,
+ tp_name_t const *tpn,
+ char const * const transports[],
+ tag_type_t tag, tag_value_t value, ...);
+
+/** Get transport parameters. */
+TPORT_DLL int tport_get_params(tport_t const *, tag_type_t tag, tag_value_t value, ...);
+
+/** Set transport parameters. */
+TPORT_DLL int tport_set_params(tport_t *self, tag_type_t tag, tag_value_t value, ...);
+
+/** Destroy transport(s). */
+TPORT_DLL void tport_destroy(tport_t *tport);
+
+/** Shutdown a transport connection. */
+TPORT_DLL int tport_shutdown(tport_t *tport, int how);
+
+/** Create a new reference to a transport object. */
+TPORT_DLL tport_t *tport_ref(tport_t *tp);
+
+/** Destroy reference to a transport object. */
+TPORT_DLL void tport_unref(tport_t *tp);
+
+/** Create a new transport reference. @deprecated Use tport_ref(). */
+TPORT_DLL tport_t *tport_incref(tport_t *tp);
+
+/** Destroy a transport reference. @deprecated Use tport_unref(). */
+TPORT_DLL void tport_decref(tport_t **tp);
+
+/** Send a message using transport. */
+TPORT_DLL tport_t *tport_tsend(tport_t *, msg_t *, tp_name_t const *,
+ tag_type_t, tag_value_t, ...);
+
+/** Queue a message to transport. */
+TPORT_DLL int tport_tqueue(tport_t *, msg_t *, tag_type_t, tag_value_t, ...);
+
+/** Return number of queued messages. */
+TPORT_DLL isize_t tport_queuelen(tport_t const *self);
+
+/** Send a queued message (and queue another, if required). */
+TPORT_DLL int tport_tqsend(tport_t *, msg_t *, msg_t *,
+ tag_type_t, tag_value_t, ...);
+
+/** Stop reading from socket until tport_continue() is called. */
+TPORT_DLL int tport_stall(tport_t *self);
+
+/** Continue reading from socket. */
+TPORT_DLL int tport_continue(tport_t *self);
+
+/** Mark message as waiting for a response. */
+TPORT_DLL int tport_pend(tport_t *self, msg_t *msg,
+ tport_pending_error_f *callback, tp_client_t *client);
+
+/** Do not wait for response anymore. */
+TPORT_DLL int tport_release(tport_t *self, int pendd,
+ msg_t *msg, msg_t *reply, tp_client_t *client,
+ int still_pending);
+
+/** Return true if transport is master. */
+TPORT_DLL int tport_is_master(tport_t const *self);
+
+/** Return true if transport is primary. */
+TPORT_DLL int tport_is_primary(tport_t const *self);
+
+/** Return nonzero if transport is public. */
+TPORT_DLL int tport_is_public(tport_t const *self);
+
+/** Return true if transport is secondary. */
+TPORT_DLL int tport_is_secondary(tport_t const *self);
+
+/** Return true if transport is reliable, false otherwise */
+TPORT_DLL int tport_is_reliable(tport_t const *tport);
+
+/** Return true if transport is a stream (no message boundaries). */
+TPORT_DLL int tport_is_stream(tport_t const *tport);
+
+/** Return true if transport is dgram-based. */
+TPORT_DLL int tport_is_dgram(tport_t const *tport);
+
+/** Return true if transport supports IPv4 */
+TPORT_DLL int tport_has_ip4(tport_t const *tport);
+
+/** Return true if transport supports IPv6 */
+TPORT_DLL int tport_has_ip6(tport_t const *tport);
+
+/** Test if transport is udp. */
+TPORT_DLL int tport_is_udp(tport_t const *self);
+
+/** Test if transport is tcp. */
+TPORT_DLL int tport_is_tcp(tport_t const *self);
+
+/** Test if transport has TLS. */
+TPORT_DLL int tport_has_tls(tport_t const *tport);
+
+/** Return true if transport is being updated. */
+TPORT_DLL int tport_is_updating(tport_t const *self);
+
+/** Test if transport has been closed (added to @VERSION_1_12_4 ) */
+TPORT_DLL int tport_is_closed(tport_t const *self);
+
+/** Test if transport has been shut down (added to @VERSION_1_12_4 ) */
+TPORT_DLL int tport_is_shutdown(tport_t const *self);
+
+/** Test if transport is connected. @NEW_1_12_5 */
+TPORT_DLL int tport_is_connected(tport_t const *self);
+
+/** Set transport magic. */
+TPORT_DLL void tport_set_magic(tport_t *self, tp_magic_t *magic);
+
+/** Get transport magic. */
+TPORT_DLL tp_magic_t *tport_magic(tport_t const *tport);
+
+/** Get transport name. */
+TPORT_DLL tp_name_t const *tport_name(tport_t const *tport);
+
+/** Get transport address list. */
+TPORT_DLL su_addrinfo_t const *tport_get_address(tport_t const *tport);
+
+/** Get transport ident. */
+TPORT_DLL char const *tport_ident(tport_t const *self);
+
+/** Get primary transport (or self, if already parent) */
+TPORT_DLL tport_t *tport_parent(tport_t const *self);
+
+/** Flush idle connections */
+TPORT_DLL int tport_flush(tport_t *);
+
+/** Get primary transports */
+TPORT_DLL tport_t *tport_primaries(tport_t const *tport);
+
+/** Get next transport */
+TPORT_DLL tport_t *tport_next(tport_t const *tport);
+
+/** Get secondary transports. */
+TPORT_DLL tport_t *tport_secondary(tport_t const *tport);
+
+/** Get a protocol corresponding to the protocol name. */
+TPORT_DLL tport_t *tport_by_protocol(tport_t const *self, char const *proto);
+
+/** Get transport by interface identifier and protocol name. */
+TPORT_DLL tport_t *tport_primary_by_name(tport_t const *self, tp_name_t const *tpn);
+
+/** Get a transport corresponding to the name */
+TPORT_DLL tport_t *tport_by_name(tport_t const *self, tp_name_t const *);
+
+/** Create a transport name corresponding to the URL. */
+TPORT_DLL int tport_name_by_url(su_home_t *, tp_name_t *,
+ url_string_t const *us);
+
+/** Return source transport object for delivered message */
+TPORT_DLL tport_t *tport_delivered_by(tport_t const *tp, msg_t const *msg);
+
+/** Return source transport name for delivered message */
+TPORT_DLL int tport_delivered_from(tport_t *tp, msg_t const *msg,
+ tp_name_t name[1]);
+
+/** Check if transport named is already resolved */
+TPORT_DLL int tport_name_is_resolved(tp_name_t const *);
+
+/** Duplicate a transport name. */
+TPORT_DLL int tport_name_dup(su_home_t *,
+ tp_name_t *dst, tp_name_t const *src);
+
+/** Convert a socket address to a transport name. */
+TPORT_DLL int tport_convert_addr(su_home_t *home,
+ tp_name_t *tpn,
+ char const *protoname,
+ char const *canon,
+ su_sockaddr_t const *su);
+
+/** Print host and port separated with ':' to a string. */
+TPORT_DLL char *tport_hostport(char buf[], isize_t bufsize,
+ su_sockaddr_t const *su, int with_port);
+
+/** Initialize STUN keepalives. */
+TPORT_DLL int tport_keepalive(tport_t *tp, su_addrinfo_t const *ai,
+ tag_type_t tag, tag_value_t value, ...);
+
+/* ---------------------------------------------------------------------- */
+/* SigComp-related functions */
+
+#ifndef TPORT_COMPRESSOR
+#define TPORT_COMPRESSOR struct tport_compressor
+#endif
+
+typedef TPORT_COMPRESSOR tport_compressor_t;
+
+TPORT_DLL int tport_can_send_sigcomp(tport_t const *self);
+TPORT_DLL int tport_can_recv_sigcomp(tport_t const *self);
+
+TPORT_DLL int tport_has_compression(tport_t const *self, char const *comp);
+TPORT_DLL int tport_set_compression(tport_t *self, char const *comp);
+
+/** Set SigComp option. */
+TPORT_DLL
+int tport_sigcomp_option(tport_t const *self,
+ struct sigcomp_compartment *cc,
+ char const *option);
+
+/** Obtain a SigComp compartment with given name. */
+TPORT_DLL struct sigcomp_compartment *
+tport_sigcomp_compartment(tport_t *self,
+ char const *name, isize_t namelen,
+ int create_if_needed);
+
+TPORT_DLL struct sigcomp_compartment *
+tport_compartment_incref(struct sigcomp_compartment *cc);
+
+TPORT_DLL void
+tport_compartment_decref(struct sigcomp_compartment **pointer_to_cc);
+
+/** Assign a SigComp compartment to a connection-oriented tport. */
+TPORT_DLL int
+tport_sigcomp_assign(tport_t *self, struct sigcomp_compartment *);
+
+/** Test if a SigComp compartment is assigned to a tport. */
+TPORT_DLL int tport_has_sigcomp_assigned(tport_t const *self);
+
+/** Accept SigComp message */
+TPORT_DLL int
+tport_sigcomp_accept(tport_t *self,
+ struct sigcomp_compartment *cc,
+ msg_t *msg);
+
+/** Get compressor context with which the request was delivered */
+TPORT_DLL int
+tport_delivered_with_comp(tport_t *tp, msg_t const *msg,
+ tport_compressor_t **return_compressor);
+
+/** Shutdown SigComp compartment */
+TPORT_DLL int
+tport_sigcomp_close(tport_t *self,
+ struct sigcomp_compartment *cc,
+ int how);
+
+/** Set SigComp compartment lifetime. */
+TPORT_DLL int
+tport_sigcomp_lifetime(tport_t *self,
+ struct sigcomp_compartment *,
+ unsigned lifetime_in_ms,
+ int only_expand);
+
+
+SOFIA_END_DECLS
+
+#endif /* TPORT_H */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport_plugins.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport_plugins.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,171 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef TPORT_PLUGINS_H
+/** Defined when <sofia-sip/tport_plugins.h> has been included. */
+#define TPORT_PLUGINS_H
+
+/**@file sofia-sip/tport_plugins.h
+ * @brief Transport plugin interface
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Fri Mar 31 12:22:22 EEST 2006 ppessi
+ */
+
+/* -- STUN Plugin ------------------------------------------------------- */
+
+#ifndef TPORT_STUN_SERVER_T
+#define TPORT_STUN_SERVER_T struct tport_stun_server_s
+#endif
+/** Safe type for tport server object */
+typedef TPORT_STUN_SERVER_T tport_stun_server_t;
+
+typedef struct {
+ int vst_size;
+ tport_stun_server_t *(*vst_create)(su_root_t *root, tagi_t const *tags);
+ void (*vst_destroy)(tport_stun_server_t *);
+ int (*vst_add_socket)(tport_stun_server_t *, su_socket_t socket);
+ int (*vst_remove_socket)(tport_stun_server_t *, su_socket_t socket);
+ void (*vst_request)(tport_stun_server_t *server, su_socket_t socket,
+ void *msg, ssize_t msglen,
+ void *addr, socklen_t addrlen);
+} tport_stun_server_vtable_t;
+
+SOFIAPUBFUN int tport_plug_in_stun_server(tport_stun_server_vtable_t const *);
+
+
+/* -- SigComp Plugin ---------------------------------------------------- */
+
+/* We already use these SigComp types in applications */
+
+struct sigcomp_udvm;
+struct sigcomp_compartment;
+
+typedef struct tport_comp_vtable_s tport_comp_vtable_t;
+
+struct tport_comp_vtable_s {
+ /* NOTE: this will change! Unstable! Do not use! */
+ int vsc_size;
+
+ char const *vsc_compname;
+ size_t vsc_sizeof_context;
+
+ int (*vsc_init_comp)(tp_stack_t *,
+ tport_t *,
+ tport_compressor_t *,
+ char const *comp_name,
+ tagi_t const *tags);
+
+ void (*vsc_deinit_comp)(tp_stack_t *,
+ tport_t *,
+ tport_compressor_t *);
+
+ char const *(*vsc_comp_name)(tport_compressor_t const *master_sc,
+ char const *compression,
+ tagi_t const *tags);
+
+ /* Mapping of public tport API */
+
+ int (*vsc_can_send_comp)(tport_compressor_t const *);
+ int (*vsc_can_recv_comp)(tport_compressor_t const *);
+
+ int (*vsc_set_comp_name)(tport_t const *self,
+ tport_compressor_t const *return_sc,
+ char const *comp);
+
+ int (*vsc_sigcomp_option)(tport_t const *self,
+ struct sigcomp_compartment *cc,
+ char const *option);
+
+ struct sigcomp_compartment *
+ (*vsc_sigcomp_compartment)(tport_t *self,
+ char const *name, int namelen,
+ int create_if_needed);
+
+ struct sigcomp_compartment *
+ (*vsc_compartment_incref)(struct sigcomp_compartment *cc);
+
+ void (*vsc_compartment_decref)(struct sigcomp_compartment **pointer_to_cc);
+
+ int (*vsc_set_compartment)(tport_t *self,
+ tport_compressor_t *,
+ struct sigcomp_compartment *);
+
+ struct sigcomp_compartment *
+ (*vsc_get_compartment)(tport_t const *self,
+ tport_compressor_t const *);
+
+ int (*vsc_has_sigcomp_assigned)(tport_compressor_t const *comp);
+
+ int (*vsc_sigcomp_accept)(tport_t *self,
+ tport_compressor_t const *comp,
+ struct sigcomp_compartment *cc,
+ msg_t *msg);
+
+ int (*vsc_delivered_using_udvm)(tport_t *tp,
+ msg_t const *msg,
+ struct sigcomp_udvm **return_pointer_to_udvm,
+ int remove);
+
+ int (*vsc_sigcomp_close)(tport_t *self,
+ struct sigcomp_compartment *cc,
+ int how);
+
+ int (*vsc_sigcomp_lifetime)(tport_t *self,
+ struct sigcomp_compartment *,
+ unsigned lifetime_in_ms,
+ int only_expand);
+
+ /* Internal API */
+
+ struct sigcomp_udvm **(*vsc_get_udvm_slot)(tport_t *self);
+
+ struct sigcomp_compartment *
+ (*vsc_sigcomp_assign_if_needed)(tport_t *self,
+ struct sigcomp_compartment *cc);
+
+ void (*vsc_accept_incomplete)(tport_t const *self,
+ tport_compressor_t *sc,
+ msg_t *msg);
+
+ int (*vsc_recv_comp)(tport_t const *self,
+ tport_compressor_t *sc,
+ msg_t **in_out_msg,
+ su_sockaddr_t *from,
+ socklen_t fromlen);
+
+ ssize_t (*vsc_send_comp)(tport_t const *self,
+ msg_t *msg,
+ msg_iovec_t iov[],
+ size_t iovused,
+ struct sigcomp_compartment *cc,
+ tport_compressor_t *sc);
+
+
+};
+
+SOFIAPUBFUN int tport_plug_in_comp(tport_comp_vtable_t const *);
+
+#endif /* !defined(TPORT_PLUGINS_H) */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport_tag.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport_tag.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,270 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef TPORT_TAG_H
+/** Defined when <sofia-sip/tport_tag.h> has been included. */
+#define TPORT_TAG_H
+
+/**@file sofia-sip/tport_tag.h
+ * @brief Tags for tport module.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Sat Oct 12 18:39:48 2002 ppessi
+ */
+
+#ifndef SU_TAG_H
+#include <sofia-sip/su_tag.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** List of all tport tags. */
+TPORT_DLL extern tagi_t tport_tag_list[];
+
+/** Filter list matching any tport tag. */
+TPORT_DLL extern tagi_t tport_tags[];
+
+/** Filter tag matching any tport tag. */
+#define TPTAG_ANY() tptag_any, ((tag_value_t)0)
+TPORT_DLL extern tag_typedef_t tptag_any;
+
+TPORT_DLL extern tag_typedef_t tptag_ident;
+/** Ident transport connection (true by default). */
+#define TPTAG_IDENT(x) tptag_ident, tag_str_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_ident_ref;
+#define TPTAG_IDENT_REF(x) tptag_ident_ref, tag_str_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_reuse;
+/** Allow reusing transport connection (true by default). */
+#define TPTAG_REUSE(x) tptag_reuse, tag_bool_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_reuse_ref;
+#define TPTAG_REUSE_REF(x) tptag_reuse_ref, tag_bool_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_fresh;
+/** Create new connection (but allow reusing new one). */
+#define TPTAG_FRESH(x) tptag_fresh, tag_bool_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_fresh_ref;
+#define TPTAG_FRESH_REF(x) tptag_fresh_ref, tag_bool_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_server;
+/** Bind server sockets (true by default, disable with TPTAG_SERVER(0)). */
+#define TPTAG_SERVER(x) tptag_server, tag_bool_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_server_ref;
+#define TPTAG_SERVER_REF(x) tptag_server_ref, tag_bool_vr(&(x))
+
+/** Define how the public transport connects to Internet.
+ *
+ * @sa TPTAG_PUBLIC(), tport_is_public().
+ */
+typedef enum tport_via {
+ tport_type_local = 0,
+ tport_type_server = 0,
+ tport_type_client = 1,
+ tport_type_stun = 2,
+ tport_type_upnp = 3,
+ tport_type_connect = 4,
+ tport_type_socks = 5,
+} tport_pri_type_t;
+
+TPORT_DLL extern tag_typedef_t tptag_public;
+/** Use a transport reaching to public Internet. */
+#define TPTAG_PUBLIC(x) tptag_public, tag_int_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_public_ref;
+#define TPTAG_PUBLIC_REF(x) tptag_public_ref, tag_int_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_mtu;
+/** Specify MTU. */
+#define TPTAG_MTU(x) tptag_mtu, tag_usize_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_mtu_ref;
+#define TPTAG_MTU_REF(x) tptag_mtu_ref, tag_usize_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_connect;
+/** Specify that tport must always use connections. */
+#define TPTAG_CONNECT(x) tptag_connect, tag_bool_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_connect_ref;
+#define TPTAG_CONNECT_REF(x) tptag_connect_ref, tag_bool_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_queuesize;
+/** Specify the number of messages that can be queued per connection. */
+#define TPTAG_QUEUESIZE(x) tptag_queuesize, tag_uint_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_queuesize_ref;
+#define TPTAG_QUEUESIZE_REF(x) tptag_queuesize_ref, tag_uint_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_sdwn_error;
+/** If true, half close of a connection by remote is considered as an error. */
+#define TPTAG_SDWN_ERROR(x) tptag_sdwn_error, tag_bool_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_sdwn_error_ref;
+#define TPTAG_SDWN_ERROR_REF(x) tptag_sdwn_error_ref, tag_bool_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_sdwn_after;
+/** Half-close (shutdown(c, 1) after sending the message. */
+#define TPTAG_SDWN_AFTER(x) tptag_sdwn_after, tag_bool_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_sdwn_after_ref;
+#define TPTAG_SDWN_AFTER_REF(x) tptag_sdwn_after_ref, tag_bool_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_close_after;
+/** Close of a connection after sending the message. */
+#define TPTAG_CLOSE_AFTER(x) tptag_close_after, tag_bool_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_close_after_ref;
+#define TPTAG_CLOSE_AFTER_REF(x) tptag_close_after_ref, tag_bool_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_idle;
+/** How long transports may be idle (value in milliseconds).
+ * If 0, zap immediately,
+ * if UINT_MAX, leave them there (default value for now).
+ */
+#define TPTAG_IDLE(x) tptag_idle, tag_uint_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_idle_ref;
+#define TPTAG_IDLE_REF(x) tptag_idle_ref, tag_uint_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_timeout;
+/**Timeout for incomplete incoming message (value in milliseconds).
+ *
+ * If UINT_MAX, leave the incomplete messages there for ever.
+ * Default value for now is UINT_MAX.
+ */
+#define TPTAG_TIMEOUT(x) tptag_timeout, tag_uint_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_timeout_ref;
+#define TPTAG_TIMEOUT_REF(x) tptag_timeout_ref, tag_uint_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_sigcomp_lifetime;
+/**Default SigComp lifetime.
+ *
+ * If UINT_MAX, keep SigComp compartments around for ever.
+ *
+ * @note Experimental.
+ */
+#define TPTAG_SIGCOMP_LIFETIME(x) tptag_sigcomp_lifetime, tag_uint_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_sigcomp_lifetime_ref;
+#define TPTAG_SIGCOMP_LIFETIME_REF(x) \
+tptag_sigcomp_lifetime_ref, tag_uint_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_compartment;
+/** Pointer to SigComp compartment. */
+#define TPTAG_COMPARTMENT(x) tptag_compartment, tag_ptr_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_compartment_ref;
+#define TPTAG_COMPARTMENT_REF(x) \
+ tptag_compartment_ref, tag_ptr_vr(&(x), x)
+
+TPORT_DLL extern tag_typedef_t tptag_certificate;
+/** Path to the public key certificate directory.
+ */
+#define TPTAG_CERTIFICATE(x) tptag_certificate, tag_str_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_certificate_ref;
+#define TPTAG_CERTIFICATE_REF(x) tptag_certificate_ref, tag_str_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_tls_version;
+/** Sets the TLS version (version 0 implies SSL2/SSL3).
+ */
+#define TPTAG_TLS_VERSION(x) tptag_tls_version, tag_uint_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_tls_version_ref;
+#define TPTAG_TLS_VERSION_REF(x) tptag_tls_version_ref, tag_uint_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_trusted;
+/** Mark transport as trusted. */
+#define TPTAG_TRUSTED(x) tptag_trusted, tag_bool_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_trusted_ref;
+#define TPTAG_TRUSTED_REF(x) tptag_trusted_ref, tag_bool_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_debug_drop;
+/** Sets the drop propability for (0..1000) incoming/outgoing packets. */
+#define TPTAG_DEBUG_DROP(x) tptag_debug_drop, tag_uint_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_debug_drop_ref;
+#define TPTAG_DEBUG_DROP_REF(x) tptag_debug_drop_ref, tag_uint_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_udp_rmem;
+/** Sets the maximum receive buffer in bytes for primary UDP socket. */
+#define TPTAG_UDP_RMEM(x) tptag_udp_rmem, tag_uint_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_udp_rmem_ref;
+#define TPTAG_UDP_RMEM_REF(x) tptag_udp_rmem_ref, tag_uint_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_udp_wmem;
+/** Sets the maximum send buffer in bytes for primary UDP socket. */
+#define TPTAG_UDP_WMEM(x) tptag_udp_wmem, tag_uint_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_udp_wmem_ref;
+#define TPTAG_UDP_WMEM_REF(x) tptag_udp_wmem_ref, tag_uint_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_thrpsize;
+/** Determines the number of threads in the pool receiving, uncompressing,
+ * parsing, compressing, and sending messages.
+ */
+#define TPTAG_THRPSIZE(x) tptag_thrpsize, tag_uint_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_thrpsize_ref;
+#define TPTAG_THRPSIZE_REF(x) tptag_thrpsize_ref, tag_uint_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_thrprqsize;
+/** Length of per-thread receive queue (as messages)
+ */
+#define TPTAG_THRPRQSIZE(x) tptag_thrprqsize, tag_uint_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_thrprqsize_ref;
+#define TPTAG_THRPRQSIZE_REF(x) tptag_thrprqsize_ref, tag_uint_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_http_connect;
+/** Specify that tport can use HTTP connect method. */
+#define TPTAG_HTTP_CONNECT(x) tptag_http_connect, tag_str_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_http_connect_ref;
+#define TPTAG_HTTP_CONNECT_REF(x) tptag_http_connect_ref, tag_str_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_stun_server;
+/** Enable STUN server. */
+#define TPTAG_STUN_SERVER(x) tptag_stun_server, tag_bool_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_stun_server_ref;
+#define TPTAG_STUN_SERVER_REF(x) tptag_stun_server_ref, tag_bool_vr(&(x))
+
+TPORT_DLL extern tag_typedef_t tptag_tos;
+/** Sets the IP TOS for the socket. */
+#define TPTAG_TOS(x) tptag_tos, tag_int_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_tos_ref;
+#define TPTAG_TOS_REF(x) tptag_tos_ref, tag_int_vr(&(x))
+
+SOFIA_END_DECLS
+
+#endif /* !defined TPORT_TAG_H */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/test_tport.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/test_tport.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1402 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE tport_test.c
+ *
+ * Test functions for transports
+ *
+ * @internal
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Apr 3 11:25:13 2002 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <stdio.h>
+#include <assert.h>
+
+typedef struct tp_test_s tp_test_t;
+
+#define TP_STACK_T tp_test_t
+
+#include <sofia-sip/su_wait.h>
+#include <sofia-sip/su_md5.h>
+
+#include "test_class.h"
+#include "test_protos.h"
+#include "sofia-sip/msg.h"
+#include "sofia-sip/msg_mclass.h"
+#include "sofia-sip/msg_addr.h"
+
+#if HAVE_SIGCOMP
+#include <sigcomp.h>
+#endif
+
+#include <sofia-sip/base64.h>
+
+#include <sofia-sip/su_log.h>
+
+#include "sofia-sip/tport.h"
+
+struct tp_test_s {
+ su_home_t tt_home[1];
+ int tt_flags;
+ su_root_t *tt_root;
+ msg_mclass_t *tt_mclass;
+ tport_t *tt_srv_tports;
+ tport_t *tt_tports;
+
+ tport_t *tt_rtport;
+
+ tp_name_t tt_udp_name[1];
+ tp_name_t tt_udp_comp[1];
+
+ tp_name_t tt_tcp_name[1];
+ tp_name_t tt_tcp_comp[1];
+
+ tp_name_t tt_sctp_name[1];
+ tp_name_t tt_sctp_comp[1];
+
+ tp_name_t tt_tls_name[1];
+ tp_name_t tt_tls_comp[1];
+
+#if HAVE_SIGCOMP
+ struct sigcomp_state_handler *state_handler;
+ struct sigcomp_algorithm const *algorithm;
+ struct sigcomp_compartment *master_cc;
+
+#define IF_SIGCOMP_TPTAG_COMPARTMENT(cc) TAG_IF(cc, TPTAG_COMPARTMENT(cc)),
+#else
+#define IF_SIGCOMP_TPTAG_COMPARTMENT(cc)
+#endif
+
+ int tt_status;
+ int tt_received;
+ msg_t *tt_rmsg;
+ uint8_t tt_digest[SU_MD5_DIGEST_SIZE];
+};
+
+int tstflags;
+#define TSTFLAGS tstflags
+
+#include <sofia-sip/tstdef.h>
+
+char const name[] = "tport_test";
+
+SOFIAPUBVAR su_log_t tport_log[];
+
+void usage(void)
+{
+ fprintf(stderr, "usage: %s [-v]\n", name);
+}
+
+static int name_test(tp_test_t *tt)
+{
+ tp_name_t tpn[1];
+
+ su_home_t home[1] = { SU_HOME_INIT(home) };
+
+ su_sockaddr_t su[1];
+
+ BEGIN();
+
+ memset(su, 0, sizeof su);
+
+ su->su_port = htons(5060);
+ su->su_family = AF_INET;
+
+ TEST(tport_convert_addr(home, tpn, "tcp", "localhost", su), 0);
+
+ su->su_family = AF_INET;
+
+ TEST(tport_convert_addr(home, tpn, "tcp", "localhost", su), 0);
+
+#if SU_HAVE_IN6
+ su->su_family = AF_INET6;
+ TEST(tport_convert_addr(home, tpn, "tcp", "localhost", su), 0);
+#endif
+
+ END();
+}
+
+/* Count number of transports in chain */
+static
+int count_tports(tport_t *tp)
+{
+ int n = 0;
+
+ for (tp = tport_primaries(tp); tp; tp = tport_next(tp))
+ n++;
+
+ return n;
+}
+
+static int check_msg(tp_test_t *tt, msg_t *msg, char const *ident)
+{
+ msg_test_t *tst;
+ msg_payload_t *pl;
+ usize_t i, len;
+
+ BEGIN();
+
+ TEST_1(tst = msg_test_public(msg));
+ TEST_1(pl = tst->msg_payload);
+
+ if (ident) {
+ if (!tst->msg_content_location ||
+ strcmp(ident, tst->msg_content_location->g_string))
+ return 1;
+ }
+
+ len = pl->pl_len;
+
+ for (i = 0; i < len; i++) {
+ if (pl->pl_data[i] != (char) (i % 240))
+ break;
+ }
+
+ if (pl)
+ return i != len;
+
+ END();
+}
+
+static int test_create_md5(tp_test_t *tt, msg_t *msg)
+{
+ msg_test_t *tst;
+ msg_payload_t *pl;
+ su_md5_t md5[1];
+
+ BEGIN();
+
+ TEST_1(tst = msg_test_public(msg));
+ TEST_1(pl = tst->msg_payload);
+
+ su_md5_init(md5);
+ su_md5_update(md5, pl->pl_data, pl->pl_len);
+ su_md5_digest(md5, tt->tt_digest);
+
+ END();
+}
+
+static int test_check_md5(tp_test_t *tt, msg_t *msg)
+{
+ msg_test_t *tst;
+ msg_payload_t *pl;
+ su_md5_t md5[1];
+ uint8_t digest[SU_MD5_DIGEST_SIZE];
+
+ BEGIN();
+
+ TEST_1(tst = msg_test_public(msg));
+ TEST_1(pl = tst->msg_payload);
+
+ su_md5_init(md5);
+ su_md5_update(md5, pl->pl_data, pl->pl_len);
+ su_md5_digest(md5, digest);
+
+ TEST(memcmp(digest, tt->tt_digest, sizeof digest), 0);
+
+ END();
+}
+
+static int test_msg_md5(tp_test_t *tt, msg_t *msg)
+{
+ msg_test_t *tst;
+
+ BEGIN();
+
+ TEST_1(tst = msg_test_public(msg));
+
+ if (tst->msg_content_md5) {
+ su_md5_t md5sum[1];
+ uint8_t digest[SU_MD5_DIGEST_SIZE];
+ char b64[BASE64_SIZE(SU_MD5_DIGEST_SIZE) + 1];
+
+ msg_payload_t *pl =tst->msg_payload;
+
+ su_md5_init(md5sum);
+ su_md5_update(md5sum, pl->pl_data, pl->pl_len);
+ su_md5_digest(md5sum, digest);
+
+ base64_e(b64, sizeof(b64), digest, sizeof(digest));
+
+ if (strcmp(b64, tst->msg_content_md5->g_string)) {
+ ;
+ }
+
+ TEST_S(b64, tst->msg_content_md5->g_string);
+ } else {
+ TEST_1(tst->msg_content_md5);
+ }
+
+ END();
+}
+
+#define TPORT_TEST_VERSION MSG_TEST_VERSION_CURRENT
+
+static int new_test_msg(tp_test_t *tt, msg_t **retval,
+ char const *ident,
+ int N, int len)
+{
+ msg_t *msg;
+ msg_test_t *tst;
+ su_home_t *home;
+ msg_request_t *rq;
+ msg_unknown_t *u;
+ msg_content_location_t *cl;
+ msg_content_md5_t *md5;
+ msg_content_length_t *l;
+ msg_separator_t *sep;
+ msg_payload_t payload[1];
+ msg_header_t *h;
+ int i;
+
+ su_md5_t md5sum[1];
+ uint8_t digest[SU_MD5_DIGEST_SIZE];
+ char b64[BASE64_SIZE(SU_MD5_DIGEST_SIZE) + 1];
+
+ BEGIN();
+
+ TEST_1(msg = msg_create(tt->tt_mclass, 0));
+ TEST_1(tst = msg_test_public(msg));
+ TEST_1(home = msg_home(msg));
+
+ TEST_SIZE(msg_maxsize(msg, 1024 + N * len), 0);
+
+ TEST_1(rq = msg_request_make(home, "DO im:foo at faa " TPORT_TEST_VERSION));
+ TEST(msg_header_insert(msg, (void *)tst, (msg_header_t *)rq), 0);
+
+ TEST_1(u = msg_unknown_make(home, "Foo: faa"));
+ TEST(msg_header_insert(msg, (void *)tst, (msg_header_t *)u), 0);
+
+ TEST_1(u = msg_unknown_make(home, "Foo: faa"));
+ TEST(msg_header_insert(msg, (void *)tst, (msg_header_t *)u), 0);
+
+ if (ident) {
+ TEST_1(cl = msg_content_location_make(home, ident));
+ TEST(msg_header_insert(msg, (void *)tst, (msg_header_t *)cl), 0);
+ }
+
+ msg_payload_init(payload);
+
+ payload->pl_len = len;
+ TEST_1(payload->pl_data = su_zalloc(home, payload->pl_len));
+
+ for (i = 0; i < len; i++) {
+ payload->pl_data[i] = (char) (i % 240);
+ }
+
+ su_md5_init(md5sum);
+
+ for (i = 0; i < N; i++) {
+ h = msg_header_dup(home, (msg_header_t*)payload);
+ TEST_1(h);
+ TEST(msg_header_insert(msg, (void *)tst, h), 0);
+ su_md5_update(md5sum, payload->pl_data, payload->pl_len);
+ }
+
+ TEST_1(l = msg_content_length_format(home, MOD_ZU, (size_t)(N * payload->pl_len)));
+ TEST(msg_header_insert(msg, (void *)tst, (msg_header_t *)l), 0);
+
+ su_md5_digest(md5sum, digest);
+
+ base64_e(b64, sizeof(b64), digest, sizeof(digest));
+
+ TEST_1(md5 = msg_content_md5_make(home, b64));
+ TEST(msg_header_insert(msg, (void *)tst, (msg_header_t *)md5), 0);
+
+ TEST_1(sep = msg_separator_create(home));
+ TEST(msg_header_insert(msg, (void *)tst, (msg_header_t *)sep), 0);
+
+ TEST(msg_serialize(msg, (void *)tst), 0);
+
+ *retval = msg;
+
+ END();
+}
+
+static
+struct sigcomp_compartment *
+test_sigcomp_compartment(tp_test_t *tt, tport_t *tp, tp_name_t const *tpn);
+
+static void tp_test_recv(tp_test_t *tt,
+ tport_t *tp,
+ msg_t *msg,
+ tp_magic_t *magic,
+ su_time_t now)
+{
+ tp_name_t frm[1];
+
+ if (tport_delivered_from(tp, msg, frm) != -1 && frm->tpn_comp) {
+ struct sigcomp_compartment *cc = test_sigcomp_compartment(tt, tp, frm);
+
+ tport_sigcomp_accept(tp, cc, msg);
+ }
+
+ tt->tt_status = 1;
+ tt->tt_received++;
+
+ if (test_msg_md5(tt, msg))
+ msg_destroy(msg);
+ else if (tt->tt_rmsg)
+ msg_destroy(msg);
+ else {
+ tt->tt_rmsg = msg;
+ tt->tt_rtport = tp;
+ }
+}
+
+static void tp_test_error(tp_test_t *tt,
+ tport_t *tp,
+ int errcode,
+ char const *remote)
+{
+ tt->tt_status = -1;
+ fprintf(stderr, "tp_test_error(%p): error %d (%s) from %s\n",
+ tp, errcode, su_strerror(errcode),
+ remote ? remote : "<unknown destination>");
+}
+
+msg_t *tp_test_msg(tp_test_t *tt, int flags,
+ char const data[], usize_t size,
+ tport_t const *tp,
+ tp_client_t *tpc)
+{
+ msg_t *msg = msg_create(tt->tt_mclass, flags);
+
+ msg_maxsize(msg, 2 * 1024 * 1024);
+
+ return msg;
+}
+
+
+static
+struct sigcomp_compartment *
+test_sigcomp_compartment(tp_test_t *tt,
+ tport_t *tp,
+ tp_name_t const *tpn)
+{
+ struct sigcomp_compartment *cc = NULL;
+#if HAVE_SIGCOMP
+ char name[256];
+ int namesize;
+
+ namesize = snprintf(name, sizeof name, "TEST_%s/%s:%s",
+ tpn->tpn_proto,
+ tpn->tpn_host,
+ tpn->tpn_port);
+
+ if (namesize <= 0 || namesize >= sizeof name)
+ return NULL;
+
+ cc = sigcomp_compartment_access(tt->state_handler,
+ 0, name, namesize, NULL, 0);
+
+ if (cc == NULL) {
+ cc = sigcomp_compartment_create(tt->algorithm, tt->state_handler,
+ 0, name, namesize, NULL, 0);
+
+ sigcomp_compartment_option(cc, "dms=32768");
+ }
+#endif
+
+ return cc;
+}
+
+/* Accept/reject early SigComp message */
+int test_sigcomp_accept(tp_stack_t *tt, tport_t *tp, msg_t *msg)
+{
+ struct sigcomp_compartment *cc = NULL;
+
+ cc = test_sigcomp_compartment(tt, tp, tport_name(tp));
+
+ if (cc)
+ tport_sigcomp_assign(tp, cc);
+
+ return tport_sigcomp_accept(tp, cc, msg);
+}
+
+
+tp_stack_class_t const tp_test_class[1] =
+ {{
+ /* tpac_size */ sizeof(tp_test_class),
+ /* tpac_recv */ tp_test_recv,
+ /* tpac_error */ tp_test_error,
+ /* tpac_alloc */ tp_test_msg,
+ }};
+
+static int init_test(tp_test_t *tt)
+{
+ tp_name_t myname[1] = {{ "*", "*", "*", "*", "sigcomp" }};
+#if HAVE_NETINET_SCTP_H
+ char const * transports[] = { "udp", "tcp", "sctp", NULL };
+#else
+ char const * transports[] = { "udp", "tcp", NULL };
+#endif
+ tp_name_t const *tpn;
+ tport_t *tp;
+ unsigned idle;
+
+ BEGIN();
+
+ int mask = AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST;
+
+#ifdef AI_ALL
+ mask |= AI_ALL;
+#endif
+#ifdef AI_V4MAPPED_CFG
+ mask |= AI_V4MAPPED_CFG;
+#endif
+#ifdef AI_ADDRCONFIG
+ mask |= AI_ADDRCONFIG;
+#endif
+#ifdef AI_V4MAPPED
+ mask |= AI_V4MAPPED;
+#endif
+
+ /* Test that we have no common flags with underlying getaddrinfo() */
+ TEST(mask & TP_AI_MASK, 0);
+
+ TEST_1(tt->tt_root = su_root_create(NULL));
+
+ myname->tpn_host = "127.0.0.1";
+ myname->tpn_ident = "client";
+
+ /* Create message class */
+ TEST_1(tt->tt_mclass = msg_mclass_clone(msg_test_mclass, 0, 0));
+
+ /* Try to insert Content-Length header (expecting failure) */
+ TEST(msg_mclass_insert(tt->tt_mclass, msg_content_length_href), -1);
+
+#if HAVE_SIGCOMP
+ TEST_1(tt->state_handler = sigcomp_state_handler_create());
+ TEST_1(tt->algorithm =
+ sigcomp_algorithm_by_name(getenv("SIGCOMP_ALGORITHM")));
+ TEST_1(tt->master_cc =
+ sigcomp_compartment_create(tt->algorithm, tt->state_handler,
+ 0, "", 0, NULL, 0));
+ TEST(sigcomp_compartment_option(tt->master_cc, "stateless"), 1);
+#endif
+
+ /* Create client transport */
+ TEST_1(tt->tt_tports =
+ tport_tcreate(tt, tp_test_class, tt->tt_root,
+ IF_SIGCOMP_TPTAG_COMPARTMENT(tt->master_cc)
+ TAG_END()));
+
+ /* Bind client transports */
+ TEST(tport_tbind(tt->tt_tports, myname, transports,
+ TPTAG_SERVER(0), TAG_END()),
+ 0);
+
+ if (getenv("TPORT_TEST_HOST"))
+ myname->tpn_host = getenv("TPORT_TEST_HOST");
+ else
+ myname->tpn_host = "*";
+
+ if (getenv("TPORT_TEST_PORT"))
+ myname->tpn_port = getenv("TPORT_TEST_PORT");
+
+ myname->tpn_ident = "server";
+
+ /* Create server transport */
+ TEST_1(tt->tt_srv_tports =
+ tport_tcreate(tt, tp_test_class, tt->tt_root,
+ IF_SIGCOMP_TPTAG_COMPARTMENT(tt->master_cc)
+ TAG_END()));
+
+ /* Bind server transports */
+ TEST(tport_tbind(tt->tt_srv_tports, myname, transports,
+ TPTAG_SERVER(1),
+ TAG_END()),
+ 0);
+
+ TEST(tport_get_params(tt->tt_srv_tports,
+ TPTAG_IDLE_REF(idle),
+ TAG_END()), 1);
+
+ for (tp = tport_primaries(tt->tt_srv_tports); tp; tp = tport_next(tp))
+ TEST_S(tport_name(tp)->tpn_ident, "server");
+
+ {
+ su_sockaddr_t su[1];
+ socklen_t sulen;
+ int s;
+ int i, before, after;
+ char port[8];
+
+ tp_name_t rname[1];
+
+ *rname = *myname;
+
+ memset(su, 0, sulen = sizeof(su->su_sin));
+ s = su_socket(su->su_family = AF_INET, SOCK_STREAM, 0); TEST_1(s != -1);
+ TEST_1(bind(s, &su->su_sa, sulen) != -1);
+ TEST_1(listen(s, 5) != -1);
+ TEST_1(getsockname(s, &su->su_sa, &sulen) != -1);
+
+ sprintf(port, "%u", ntohs(su->su_port));
+
+ rname->tpn_port = port;
+ rname->tpn_ident = "failure";
+
+ before = count_tports(tt->tt_srv_tports);
+
+ /* Bind server transports to an reserved port */
+ TEST(tport_tbind(tt->tt_srv_tports, rname, transports,
+ TPTAG_SERVER(1),
+ TAG_END()),
+ -1);
+
+ after = count_tports(tt->tt_srv_tports);
+
+ TEST(before, after);
+
+ for (tp = tport_primaries(tt->tt_srv_tports); tp; tp = tport_next(tp))
+ TEST_S(tport_name(tp)->tpn_ident, "server");
+
+ rname->tpn_port = "*";
+ rname->tpn_ident = "server2";
+
+ /* Bind server transports to another port */
+ TEST(tport_tbind(tt->tt_srv_tports, rname, transports,
+ TPTAG_SERVER(1),
+ TAG_END()),
+ 0);
+
+ tp = tport_primaries(tt->tt_srv_tports);
+
+ for (i = 0; i++ < before; tp = tport_next(tp))
+ TEST_S(tport_name(tp)->tpn_ident, "server");
+
+ for (; tp; tp = tport_next(tp))
+ TEST_S(tport_name(tp)->tpn_ident, "server2");
+ }
+
+#if HAVE_TLS
+ {
+ tp_name_t tlsname[1] = {{ "tls", "*", "*", "*", NULL }};
+ char const * transports[] = { "tls", NULL };
+
+ char const *srcdir = getenv("srcdir");
+
+ if (srcdir == NULL)
+ srcdir = ".";
+
+ tlsname->tpn_host = myname->tpn_host;
+ tlsname->tpn_ident = "server";
+
+ /* Bind client transports */
+ TEST(tport_tbind(tt->tt_tports, tlsname, transports,
+ TPTAG_SERVER(0),
+ TPTAG_CERTIFICATE(srcdir),
+ TAG_END()),
+ 0);
+
+ /* Bind tls server transport */
+ TEST(tport_tbind(tt->tt_srv_tports, tlsname, transports,
+ TPTAG_SERVER(1),
+ TPTAG_CERTIFICATE(srcdir),
+ TAG_END()),
+ 0);
+ }
+#endif
+
+ for (tp = tport_primaries(tt->tt_srv_tports); tp; tp = tport_next(tp)) {
+ TEST_1(tpn = tport_name(tp));
+
+ if (1 || tt->tt_flags & tst_verbatim) {
+ char const *host = tpn->tpn_host != tpn->tpn_canon ? tpn->tpn_host : "";
+ printf("bound transport to %s/%s:%s%s%s%s%s\n",
+ tpn->tpn_proto, tpn->tpn_canon, tpn->tpn_port,
+ host[0] ? ";maddr=" : "", host,
+ tpn->tpn_comp ? ";comp=" : "",
+ tpn->tpn_comp ? tpn->tpn_comp : "");
+ }
+
+ /* Ignore server2 tports for now */
+ if (strcmp(tpn->tpn_ident, "server"))
+ continue;
+
+ if (strcmp(tpn->tpn_proto, "udp") == 0) {
+ *tt->tt_udp_name = *tpn;
+ tt->tt_udp_name->tpn_comp = NULL;
+ tt->tt_udp_name->tpn_ident = NULL;
+ *tt->tt_udp_comp = *tpn;
+ tt->tt_udp_comp->tpn_ident = NULL;
+ }
+ else if (strcmp(tpn->tpn_proto, "tcp") == 0) {
+ *tt->tt_tcp_name = *tpn;
+ tt->tt_tcp_name->tpn_comp = NULL;
+ tt->tt_tcp_name->tpn_ident = NULL;
+ *tt->tt_tcp_comp = *tpn;
+ tt->tt_tcp_comp->tpn_ident = NULL;
+ }
+ else if (strcmp(tpn->tpn_proto, "sctp") == 0) {
+ *tt->tt_sctp_name = *tpn;
+ tt->tt_sctp_name->tpn_ident = NULL;
+ }
+ else if (strcmp(tpn->tpn_proto, "tls") == 0) {
+ *tt->tt_tls_name = *tpn;
+ tt->tt_tls_name->tpn_ident = NULL;
+ }
+ }
+
+ END();
+}
+
+char const payload[] =
+"Some data\n"
+"More data\n";
+
+#include <time.h>
+
+int
+tport_test_run(tp_test_t *tt, unsigned timeout)
+{
+ time_t now = time(NULL);
+
+ tt->tt_status = 0;
+
+ msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
+ tt->tt_rtport = NULL;
+
+ while (!tt->tt_status) {
+ if (tt->tt_flags & tst_verbatim) {
+ fputs(".", stdout); fflush(stdout);
+ }
+ su_root_step(tt->tt_root, 500L);
+
+ if (!getenv("TPORT_TEST_DEBUG") &&
+ time(NULL) > (time_t)(now + timeout))
+ return 0;
+ }
+
+ return tt->tt_status;
+}
+
+static int udp_test(tp_test_t *tt)
+{
+ tport_t *tp;
+ msg_t *msg;
+ msg_test_t *tst;
+ su_home_t *home;
+ msg_request_t *rq;
+ msg_unknown_t *u;
+ msg_content_length_t *l;
+ msg_content_md5_t *md5;
+ msg_separator_t *sep;
+ msg_payload_t *pl;
+
+ BEGIN();
+
+ TEST_1(msg = msg_create(tt->tt_mclass, 0));
+ TEST_1(tst = msg_test_public(msg));
+ TEST_1(home = msg_home(msg));
+
+ TEST_1(rq = msg_request_make(home, "DO im:foo at faa " TPORT_TEST_VERSION));
+ TEST(msg_header_insert(msg, (void *)tst, (msg_header_t *)rq), 0);
+
+ TEST_1(u = msg_unknown_make(home, "Foo: faa"));
+ TEST(msg_header_insert(msg, (void *)tst, (msg_header_t *)u), 0);
+
+ TEST_1(pl = msg_payload_make(home, payload));
+ TEST(msg_header_insert(msg, (void *)tst, (msg_header_t *)pl), 0);
+
+ TEST_1(l = msg_content_length_format(home, MOD_ZU, (size_t)pl->pl_len));
+ TEST(msg_header_insert(msg, (void *)tst, (msg_header_t *)l), 0);
+
+ TEST_1(md5 = msg_content_md5_make(home, "R6nitdrtJFpxYzrPaSXfrA=="));
+ TEST(msg_header_insert(msg, (void *)tst, (msg_header_t *)md5), 0);
+
+ TEST_1(sep = msg_separator_create(home));
+ TEST(msg_header_insert(msg, (void *)tst, (msg_header_t *)sep), 0);
+
+ TEST(msg_serialize(msg, (void *)tst), 0);
+
+ TEST_1(tp = tport_tsend(tt->tt_tports, msg, tt->tt_udp_name, TAG_END()));
+
+ TEST_S(tport_name(tp)->tpn_ident, "client");
+
+ TEST(tport_test_run(tt, 5), 1);
+
+ msg_destroy(msg);
+
+#if 0
+ tp_name_t tpn[1] = {{ NULL }};
+
+ TEST_1(msg = tt->tt_rmsg); tt->tt_rmsg = NULL;
+
+ TEST_1(home = msg_home(msg));
+
+ TEST_1(tport_convert_addr(home, tpn, "udp", NULL, msg_addr(msg)) == 0);
+
+ tpn->tpn_comp = tport_name(tt->tt_rtport)->tpn_comp;
+
+ /* reply */
+ TEST_1(tport_tsend(tt->tt_rtport, msg, tpn, TAG_END()) != NULL);
+
+ msg_destroy(msg);
+
+ TEST(tport_test_run(tt, 5), 1);
+
+ msg_destroy(msg);
+#endif
+
+ msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
+
+ END();
+}
+
+static int tcp_test(tp_test_t *tt)
+{
+ msg_t *msg = NULL;
+ int i;
+ tport_t *tp, *tp0;
+ char ident[16];
+
+ BEGIN();
+
+ /* Create a large message, just to force queueing in sending end */
+ TEST(new_test_msg(tt, &msg, "tcp-0", 1, 16 * 64 * 1024), 0);
+ test_create_md5(tt, msg);
+ TEST_1(tp = tport_tsend(tt->tt_tports, msg, tt->tt_tcp_name, TAG_END()));
+ TEST_S(tport_name(tp)->tpn_ident, "client");
+ tp0 = tport_incref(tp);
+ msg_destroy(msg);
+
+ /* Fill up the queue */
+ for (i = 1; i < TPORT_QUEUESIZE; i++) {
+ snprintf(ident, sizeof ident, "tcp-%u", i);
+
+ TEST(new_test_msg(tt, &msg, ident, 1, 64 * 1024), 0);
+ TEST_1(tp = tport_tsend(tt->tt_tports, msg, tt->tt_tcp_name, TAG_END()));
+ TEST_S(tport_name(tp)->tpn_ident, "client");
+ TEST_P(tport_incref(tp), tp0); tport_decref(&tp);
+ msg_destroy(msg);
+ }
+
+ /* This overflows the queue */
+ TEST(new_test_msg(tt, &msg, "tcp-overflow", 1, 1024), 0);
+ TEST_1(!tport_tsend(tt->tt_tports, msg, tt->tt_tcp_name, TAG_END()));
+ msg_destroy(msg);
+
+ tt->tt_received = 0;
+
+ TEST(tport_test_run(tt, 60), 1);
+ TEST_1(!check_msg(tt, tt->tt_rmsg, "tcp-0"));
+ test_check_md5(tt, tt->tt_rmsg);
+ msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
+
+ if (tt->tt_received < TPORT_QUEUESIZE) { /* We have not received it all */
+ snprintf(ident, sizeof ident, "tcp-%u", tt->tt_received);
+ TEST(tport_test_run(tt, 5), 1);
+ TEST_1(!check_msg(tt, tt->tt_rmsg, ident));
+ msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
+ }
+
+ /* This uses a new connection */
+ TEST_1(!new_test_msg(tt, &msg, "tcp-no-reuse", 1, 1024));
+ TEST_1(tp = tport_tsend(tt->tt_tports, msg, tt->tt_tcp_name,
+ TPTAG_REUSE(0), TAG_END()));
+ TEST_S(tport_name(tp)->tpn_ident, "client");
+ TEST_1(tport_incref(tp) != tp0); tport_decref(&tp);
+ msg_destroy(msg);
+
+ /* This uses the old connection */
+ TEST_1(!new_test_msg(tt, &msg, "tcp-reuse", 1, 1024));
+ TEST_1(tp = tport_tsend(tt->tt_tports, msg, tt->tt_tcp_name,
+ TPTAG_REUSE(1), TAG_END()));
+ TEST_S(tport_name(tp)->tpn_ident, "client");
+ TEST_1(tport_incref(tp) == tp0); tport_decref(&tp);
+ msg_destroy(msg);
+
+ /* Receive every message from queue */
+ while (tt->tt_received < TPORT_QUEUESIZE + 2) {
+ TEST(tport_test_run(tt, 5), 1);
+ /* Validate message */
+ TEST_1(!check_msg(tt, tt->tt_rmsg, NULL));
+ msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
+ }
+
+ /* Try to send a single message */
+ TEST_1(!new_test_msg(tt, &msg, "tcp-last", 1, 1024));
+ TEST_1(tp = tport_tsend(tt->tt_tports, msg, tt->tt_tcp_name, TAG_END()));
+ TEST_S(tport_name(tp)->tpn_ident, "client");
+ TEST_P(tport_incref(tp), tp0); tport_decref(&tp);
+ msg_destroy(msg);
+
+ TEST(tport_test_run(tt, 5), 1);
+
+ TEST_1(!check_msg(tt, tt->tt_rmsg, "tcp-last"));
+ msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
+
+ tport_decref(&tp0);
+
+ END();
+}
+
+static int reuse_test(tp_test_t *tt)
+{
+ msg_t *msg = NULL;
+ int i, reuse = -1;
+ tport_t *tp, *tp0, *tp1;
+ tp_name_t tpn[1];
+
+ BEGIN();
+
+ /* Flush existing connections */
+ *tpn = *tt->tt_tcp_name;
+ tpn->tpn_port = "*";
+ TEST_1(tp = tport_by_name(tt->tt_tports, tpn));
+ TEST_1(tport_is_primary(tp));
+ TEST(tport_flush(tp), 0);
+
+ for (i = 0; i < 10; i++)
+ su_root_step(tt->tt_root, 10L);
+
+ TEST(tport_set_params(tp, TPTAG_REUSE(0), TAG_END()), 1);
+
+ /* Send two messages */
+ TEST(new_test_msg(tt, &msg, "reuse-1", 1, 1024), 0);
+ TEST_1(tp = tport_tsend(tt->tt_tports, msg, tt->tt_tcp_name, TAG_END()));
+ TEST_S(tport_name(tp)->tpn_ident, "client");
+ TEST_1(tp0 = tport_incref(tp));
+ TEST(tport_get_params(tp, TPTAG_REUSE_REF(reuse), TAG_END()), 1);
+ TEST(reuse, 0);
+ msg_destroy(msg), msg = NULL;
+
+ TEST(new_test_msg(tt, &msg, "reuse-2", 1, 1024), 0);
+ TEST_1(tp = tport_tsend(tt->tt_tports, msg, tt->tt_tcp_name, TAG_END()));
+ TEST_S(tport_name(tp)->tpn_ident, "client");
+ TEST_1(tp1 = tport_incref(tp)); TEST_1(tp0 != tp1);
+ TEST(tport_get_params(tp, TPTAG_REUSE_REF(reuse), TAG_END()), 1);
+ TEST(reuse, 0);
+ msg_destroy(msg), msg = NULL;
+
+ /* Receive every message from queue */
+ for (tt->tt_received = 0;
+ tt->tt_received < 2;) {
+ TEST(tport_test_run(tt, 5), 1);
+ msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
+ }
+
+ /* Enable reuse on single connection */
+ TEST(tport_set_params(tp1, TPTAG_REUSE(1), TAG_END()), 1);
+ TEST(new_test_msg(tt, &msg, "reuse-3", 1, 1024), 0);
+ TEST_1(tp = tport_tsend(tt->tt_tports, msg, tt->tt_tcp_name,
+ TPTAG_REUSE(1),
+ TAG_END()));
+ TEST_S(tport_name(tp)->tpn_ident, "client");
+ TEST_1(tp1 == tp);
+ TEST(tport_get_params(tp, TPTAG_REUSE_REF(reuse), TAG_END()), 1);
+ TEST(reuse, 1);
+ msg_destroy(msg), msg = NULL;
+
+ TEST(tport_test_run(tt, 5), 1);
+ msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
+
+ TEST_1(tp = tport_by_name(tt->tt_tports, tpn));
+ TEST_1(tport_is_primary(tp));
+ TEST(tport_set_params(tp, TPTAG_REUSE(1), TAG_END()), 1);
+
+ /* Send a single message with different connection */
+ TEST_1(!new_test_msg(tt, &msg, "fresh-1", 1, 1024));
+ TEST_1(tp = tport_tsend(tt->tt_tports, msg, tt->tt_tcp_name,
+ TPTAG_FRESH(1),
+ TPTAG_REUSE(1),
+ TAG_END()));
+ TEST_S(tport_name(tp)->tpn_ident, "client");
+ TEST_1(tport_incref(tp) != tp1); tport_decref(&tp);
+ msg_destroy(msg);
+
+ TEST(tport_test_run(tt, 5), 1);
+
+ TEST_1(!check_msg(tt, tt->tt_rmsg, "fresh-1"));
+ msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
+
+ TEST_1(tport_shutdown(tp0, 2) >= 0);
+ TEST_1(tport_shutdown(tp1, 2) >= 0);
+ TEST_1(tport_shutdown(tp0, 1) >= 0);
+
+ TEST(tport_shutdown(NULL, 0), -1);
+
+ tport_decref(&tp0);
+ tport_decref(&tp1);
+
+ END();
+}
+
+static int sctp_test(tp_test_t *tt)
+{
+ BEGIN();
+
+ msg_t *msg = NULL;
+ int i, n;
+ tport_t *tp;
+ char buffer[32];
+
+ if (!tt->tt_sctp_name->tpn_proto)
+ return 0;
+
+ /* Just a small and nice message first */
+ TEST_1(!new_test_msg(tt, &msg, "sctp-small", 1, 1024));
+ test_create_md5(tt, msg);
+ TEST_1(tp = tport_tsend(tt->tt_tports, msg, tt->tt_sctp_name, TAG_END()));
+ TEST_S(tport_name(tp)->tpn_ident, "client");
+ msg_destroy(msg);
+
+ TEST(tport_test_run(tt, 5), 1);
+
+ TEST_1(!check_msg(tt, tt->tt_rmsg, NULL));
+ test_check_md5(tt, tt->tt_rmsg);
+ msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
+
+ if (1)
+ return 0; /* SCTP does not work reliably. Really. */
+
+ /* Create large messages, just to force queueing in sending end */
+ for (n = 0; !tport_queuelen(tp); n++) {
+ snprintf(buffer, sizeof buffer, "cid:sctp-%u", n);
+ TEST_1(!new_test_msg(tt, &msg, buffer, 1, 32000));
+ test_create_md5(tt, msg);
+ TEST_1(tport_tsend(tp, msg, tt->tt_sctp_name, TAG_END()));
+ TEST_S(tport_name(tp)->tpn_ident, "client");
+ msg_destroy(msg);
+ }
+
+ /* Fill up the queue */
+ for (i = 1; i < TPORT_QUEUESIZE; i++) {
+ snprintf(buffer, sizeof buffer, "cid:sctp-%u", n + i);
+ TEST_1(!new_test_msg(tt, &msg, buffer, 1, 1024));
+ TEST_1(tport_tsend(tp, msg, tt->tt_sctp_name, TAG_END()));
+ msg_destroy(msg);
+ }
+
+ /* This overflows the queue */
+ snprintf(buffer, sizeof buffer, "cid:sctp-%u", n + i);
+ TEST_1(!new_test_msg(tt, &msg, buffer, 1, 1024));
+ TEST_1(!tport_tsend(tt->tt_tports, msg, tt->tt_sctp_name, TAG_END()));
+ msg_destroy(msg);
+
+ TEST(tport_test_run(tt, 5), 1);
+
+ TEST_1(!check_msg(tt, tt->tt_rmsg, NULL));
+ test_check_md5(tt, tt->tt_rmsg);
+ msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
+
+ /* This uses a new connection */
+ TEST_1(!new_test_msg(tt, &msg, "cid-sctp-new", 1, 1024));
+ TEST_1(tport_tsend(tt->tt_tports, msg, tt->tt_sctp_name,
+ TPTAG_REUSE(0), TAG_END()));
+ msg_destroy(msg);
+
+ /* Receive every message from queue */
+ for (tt->tt_received = 0; tt->tt_received < TPORT_QUEUESIZE + n;) {
+ TEST(tport_test_run(tt, 10), 1);
+ /* Validate message */
+ TEST_1(!check_msg(tt, tt->tt_rmsg, NULL));
+ msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
+ }
+
+ /* Try to send a single message */
+ TEST_1(!new_test_msg(tt, &msg, "cid:sctp-final", 1, 1024));
+ TEST_1(tport_tsend(tt->tt_tports, msg, tt->tt_sctp_name, TAG_END()));
+ msg_destroy(msg);
+
+ TEST(tport_test_run(tt, 10), 1);
+
+ TEST_1(!check_msg(tt, tt->tt_rmsg, NULL));
+ msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
+
+ END();
+}
+
+static int tls_test(tp_test_t *tt)
+{
+ BEGIN();
+
+#if HAVE_TLS
+ tp_name_t const *dst = tt->tt_tls_name;
+ msg_t *msg = NULL;
+ int i;
+ char ident[16];
+
+ TEST_S(dst->tpn_proto, "tls");
+
+ tt->tt_received = 0;
+
+ /* Create a large message, just to force queueing in sending end */
+ TEST_1(!new_test_msg(tt, &msg, "tls-0", 16, 64 * 1024));
+ test_create_md5(tt, msg);
+ TEST_1(tport_tsend(tt->tt_tports, msg, dst, TAG_END()));
+ msg_destroy(msg);
+
+ /* Fill up the queue */
+ for (i = 1; i < TPORT_QUEUESIZE; i++) {
+ snprintf(ident, sizeof ident, "tls-%u", i);
+
+ TEST_1(!new_test_msg(tt, &msg, ident, 2, 512));
+ TEST_1(tport_tsend(tt->tt_tports, msg, dst, TAG_END()));
+ msg_destroy(msg);
+ }
+
+ /* This overflows the queue */
+ TEST_1(!new_test_msg(tt, &msg, "tls-overflow", 1, 1024));
+ TEST_1(!tport_tsend(tt->tt_tports, msg, dst, TAG_END()));
+ msg_destroy(msg);
+
+ TEST(tport_test_run(tt, 60), 1);
+
+ msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
+
+ /* This uses a new connection */
+ TEST_1(!new_test_msg(tt, &msg, "tls-no-reuse", 1, 1024));
+ TEST_1(tport_tsend(tt->tt_tports, msg, dst,
+ TPTAG_REUSE(0), TAG_END()));
+ msg_destroy(msg);
+
+ /* Receive every message from queue */
+ while (tt->tt_received < TPORT_QUEUESIZE + 1) {
+ TEST(tport_test_run(tt, 5), 1);
+ /* Validate message */
+ msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
+ }
+
+ /* Try to send a single message */
+ TEST_1(!new_test_msg(tt, &msg, "tls-last", 1, 1024));
+ TEST_1(tport_tsend(tt->tt_tports, msg, dst, TAG_END()));
+ msg_destroy(msg);
+
+ TEST(tport_test_run(tt, 5), 1);
+
+ TEST_1(!check_msg(tt, tt->tt_rmsg, "tls-last"));
+ msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
+
+#endif
+
+ END();
+}
+
+static int sigcomp_test(tp_test_t *tt)
+{
+ BEGIN();
+
+#if HAVE_SIGCOMP
+ su_home_t *home;
+ tp_name_t tpn[1] = {{ NULL }};
+ struct sigcomp_compartment *cc;
+
+ if (tt->tt_udp_comp->tpn_comp) {
+ msg_t *msg = NULL;
+
+ TEST_1(cc = test_sigcomp_compartment(tt, tt->tt_tports, tt->tt_udp_comp));
+
+ TEST_1(!new_test_msg(tt, &msg, "udp-sigcomp", 1, 1200));
+ test_create_md5(tt, msg);
+ TEST_1(tport_tsend(tt->tt_tports,
+ msg,
+ tt->tt_udp_comp,
+ TPTAG_COMPARTMENT(cc),
+ TAG_END()));
+ msg_destroy(msg);
+
+ TEST(tport_test_run(tt, 5), 1);
+
+ TEST_1(!check_msg(tt, tt->tt_rmsg, NULL));
+
+ test_check_md5(tt, tt->tt_rmsg);
+
+ TEST_1(msg = tt->tt_rmsg); tt->tt_rmsg = NULL;
+
+ TEST_1(home = msg_home(msg));
+
+ TEST_1(tport_convert_addr(home, tpn, "udp", NULL, msg_addr(msg)) == 0);
+
+ tpn->tpn_comp = tport_name(tt->tt_rtport)->tpn_comp;
+
+ /* reply */
+ TEST_1(cc = test_sigcomp_compartment(tt, tt->tt_tports, tpn));
+ TEST_1(tport_tsend(tt->tt_rtport, msg, tpn,
+ TPTAG_COMPARTMENT(cc),
+ TAG_END()) != NULL);
+
+ msg_destroy(msg);
+
+ TEST(tport_test_run(tt, 5), 1);
+
+ TEST_1(!check_msg(tt, tt->tt_rmsg, NULL));
+ test_check_md5(tt, tt->tt_rmsg);
+ msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
+ }
+
+ if (tt->tt_tcp_comp->tpn_comp) {
+ tport_t *tp;
+ msg_t *msg = NULL;
+
+ *tpn = *tt->tt_tcp_comp;
+
+ TEST_1(!new_test_msg(tt, &msg, "tcp-sigcomp", 1, 1500));
+ test_create_md5(tt, msg);
+
+ tport_log->log_level = 9;
+
+ TEST_1(cc = test_sigcomp_compartment(tt, tt->tt_tports, tpn));
+ TEST_1(tp = tport_tsend(tt->tt_tports,
+ msg,
+ tpn,
+ TPTAG_COMPARTMENT(cc),
+ TAG_END()));
+ TEST_1(tport_incref(tp)); tport_decref(&tp);
+ msg_destroy(msg);
+
+ TEST(tport_test_run(tt, 5), 1);
+
+ TEST_1(!check_msg(tt, tt->tt_rmsg, "tcp-sigcomp"));
+ test_check_md5(tt, tt->tt_rmsg);
+ msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
+
+ TEST_1(!new_test_msg(tt, &msg, "tcp-sigcomp-2", 1, 3000));
+ test_create_md5(tt, msg);
+ TEST_1(tp = tport_tsend(tt->tt_tports,
+ msg,
+ tt->tt_tcp_comp,
+ TPTAG_COMPARTMENT(cc),
+ TAG_END()));
+ TEST_1(tport_incref(tp)); tport_decref(&tp);
+ msg_destroy(msg);
+
+ TEST(tport_test_run(tt, 5), 1);
+
+ TEST_1(!check_msg(tt, tt->tt_rmsg, "tcp-sigcomp-2"));
+ test_check_md5(tt, tt->tt_rmsg);
+
+ msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
+
+ TEST_1(!new_test_msg(tt, &msg, "tcp-sigcomp-3", 1, 45500));
+ test_create_md5(tt, msg);
+ TEST_1(tp = tport_tsend(tt->tt_tports,
+ msg,
+ tt->tt_tcp_comp,
+ TPTAG_COMPARTMENT(cc),
+ TAG_END()));
+ TEST_1(tport_incref(tp));
+ msg_destroy(msg);
+
+ TEST(tport_test_run(tt, 5), 1);
+
+ tport_decref(&tp);
+ TEST_1(!check_msg(tt, tt->tt_rmsg, "tcp-sigcomp-3"));
+ test_check_md5(tt, tt->tt_rmsg);
+ msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
+
+ {
+ tp_name_t tpn[1];
+ tport_t *ctp, *rtp;
+
+ *tpn = *tt->tt_tcp_comp; tpn->tpn_comp = NULL;
+
+ TEST_1(!new_test_msg(tt, &msg, "tcp-sigcomp-4", 1, 1000));
+ test_create_md5(tt, msg);
+ TEST_1(tp = tport_tsend(tt->tt_tports,
+ msg,
+ tpn,
+ TPTAG_COMPARTMENT(cc),
+ TPTAG_FRESH(1),
+ TAG_END()));
+ TEST_1(ctp = tport_incref(tp));
+ msg_destroy(msg);
+
+ TEST(tport_test_run(tt, 5), 1);
+
+ TEST_1(!check_msg(tt, tt->tt_rmsg, "tcp-sigcomp-4"));
+ test_check_md5(tt, tt->tt_rmsg);
+ TEST_1((msg_addrinfo(tt->tt_rmsg)->ai_flags & TP_AI_COMPRESSED) == 0);
+ msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
+ TEST_1(rtp = tport_incref(tt->tt_rtport));
+
+ TEST_1(!new_test_msg(tt, &msg, "tcp-sigcomp-5", 1, 1000));
+ test_create_md5(tt, msg);
+ {
+ /* Mess with internal data structures in order to
+ force tport to use SigComp on this connection */
+ tp_name_t *tpn = (tp_name_t *)tport_name(rtp);
+ tpn->tpn_comp = "sigcomp";
+ }
+ TEST_1(tp = tport_tsend(rtp,
+ msg,
+ tt->tt_tcp_comp,
+ TPTAG_COMPARTMENT(cc),
+ TAG_END()));
+ TEST_1(tport_incref(tp));
+ msg_destroy(msg);
+
+ TEST(tp, rtp);
+
+ TEST(tport_test_run(tt, 5), 1);
+
+ tport_decref(&tp);
+ TEST_1(!check_msg(tt, tt->tt_rmsg, "tcp-sigcomp-5"));
+ test_check_md5(tt, tt->tt_rmsg);
+ TEST_1((msg_addrinfo(tt->tt_rmsg)->ai_flags & TP_AI_COMPRESSED) != 0);
+ msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
+ TEST(ctp, tt->tt_rtport);
+ tport_decref(&ctp);
+ }
+ }
+#endif
+
+ END();
+}
+
+#if HAVE_SOFIA_STUN
+
+#include <sofia-sip/stun_tag.h>
+
+static int stun_test(tp_test_t *tt)
+{
+ BEGIN();
+
+ tport_t *mr;
+ tp_name_t tpn[1] = {{ "*", "*", "*", "*", NULL }};
+#if HAVE_NETINET_SCTP_H
+ char const * transports[] = { "udp", "tcp", "sctp", NULL };
+#else
+ char const * transports[] = { "udp", "tcp", NULL };
+#endif
+
+ TEST_1(mr = tport_tcreate(tt, tp_test_class, tt->tt_root, TAG_END()));
+
+ TEST(tport_tbind(tt->tt_tports, tpn, transports, TPTAG_SERVER(1),
+ STUNTAG_SERVER("999.999.999.999"),
+ TAG_END()), -1);
+
+ tport_destroy(mr);
+
+ END();
+}
+#else
+static int stun_test(tp_test_t *tt)
+{
+ return 0;
+}
+#endif
+
+static int deinit_test(tp_test_t *tt)
+{
+ BEGIN();
+
+ /* Destroy client transports */
+ tport_destroy(tt->tt_tports), tt->tt_tports = NULL;
+
+ /* Destroy server transports */
+ tport_destroy(tt->tt_srv_tports), tt->tt_srv_tports = NULL;
+
+#if HAVE_SIGCOMP
+ sigcomp_state_handler_free(tt->state_handler); tt->state_handler = NULL;
+#endif
+
+ END();
+}
+
+/* Test tport_tags filter */
+static int filter_test(tp_test_t *tt)
+{
+ tagi_t *lst, *result;
+
+ su_home_t home[1] = { SU_HOME_INIT(home) };
+
+ BEGIN();
+
+ lst = tl_list(TSTTAG_HEADER_STR("X: Y"),
+ TAG_SKIP(2),
+ TPTAG_IDENT("foo"),
+ TSTTAG_HEADER_STR("X: Y"),
+ TPTAG_IDENT("bar"),
+ TAG_NULL());
+
+ TEST_1(lst);
+
+ result = tl_afilter(home, tport_tags, lst);
+
+ TEST_1(result);
+ TEST_P(result[0].t_tag, tptag_ident);
+ TEST_P(result[1].t_tag, tptag_ident);
+
+ free(lst);
+ su_home_deinit(home);
+
+ END();
+}
+
+int main(int argc, char *argv[])
+{
+ int flags = 0; /* XXX */
+ int retval = 0;
+ int i;
+ tp_test_t tt[1] = {{{ SU_HOME_INIT(tt) }}};
+
+ for (i = 1; argv[i]; i++) {
+ if (strcmp(argv[i], "-v") == 0)
+ tstflags |= tst_verbatim;
+ else
+ usage();
+ }
+
+ /* Use log */
+ if (flags & tst_verbatim)
+ tport_log->log_default = 9;
+ else
+ tport_log->log_default = 1;
+
+ su_init();
+
+ retval |= name_test(tt); fflush(stdout);
+ retval |= filter_test(tt); fflush(stdout);
+
+ retval |= init_test(tt); fflush(stdout);
+ if (retval == 0) {
+ retval |= sigcomp_test(tt); fflush(stdout);
+ retval |= sctp_test(tt); fflush(stdout);
+ retval |= udp_test(tt); fflush(stdout);
+ retval |= tcp_test(tt); fflush(stdout);
+ retval |= reuse_test(tt); fflush(stdout);
+ retval |= tls_test(tt); fflush(stdout);
+ if (0) /* Not yet working... */
+ retval |= stun_test(tt); fflush(stdout);
+ retval |= deinit_test(tt); fflush(stdout);
+ }
+
+ su_deinit();
+
+ return retval;
+}
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tls_test_client.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tls_test_client.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,167 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#include "ssl.h"
+#include "tls.h"
+
+void write_file(FILE *fp, int size);
+
+int tls_setblocking(int s, int blocking)
+{
+ unsigned mode = fcntl(s, F_GETFL, 0);
+
+ if (mode < 0)
+ return -1;
+
+ if (blocking)
+ mode &= ~(O_NDELAY | O_NONBLOCK);
+ else
+ mode |= O_NDELAY | O_NONBLOCK;
+
+ return fcntl(s, F_SETFL, mode);
+}
+
+void tls_write_buffer(TLS_CONTEXT ctx, unsigned char *buf, int size)
+{
+ int ret, err;
+ int pos = 0;
+
+ while (pos < size) {
+ int bytes = pos + 30000 < size ? 30000 : size - pos;
+
+ printf("writing %d bytes\n", bytes);
+
+ ret = tls_write(ctx, buf + pos, bytes);
+ err = tls_get_error(ctx, ret);
+
+ switch(err) {
+ case SSL_ERROR_NONE:
+ pos += ret;
+ printf("%d bytes written\n", ret);
+ break;
+
+ case SSL_ERROR_WANT_WRITE:
+ printf("want write\n");
+ break;
+
+ case SSL_ERROR_WANT_READ:
+ printf("want read\n");
+ break;
+
+ default:
+ printf("TLS error code %d\n", err);
+ }
+ }
+}
+
+int main (int argc, char *argv[])
+{
+ int i, pid;
+ FILE *fp;
+ struct stat stats;
+
+ if (argc != 2) {
+ printf("Usage: tls_test_client <file>\n");
+ }
+
+ for (i = 0; i < 10; i++) {
+ pid = fork();
+ if (pid == 0)
+ break;
+ }
+
+ fp = fopen(argv[1], "r");
+
+ if (fp == NULL) {
+ perror("fopen");
+ exit(1);
+ }
+
+ if (fstat(fileno(fp), &stats) < 0) {
+ perror("fstat");
+ exit(1);
+ }
+
+ for (i = 0; i < 20; i++)
+ write_file(fp, stats.st_size);
+
+ return 0;
+}
+
+void write_file(FILE *fp, int size)
+{
+ TLS_ISSUES tls_issues = {0};
+ TLS_CONTEXT ctx;
+ int sock, posFile = 0;
+
+ printf("tls_client connecting\n");
+
+ sock = init_tls_client(tls_issues, &ctx);
+
+ printf("tls_client initialized\n");
+
+ if (sock < 0)
+ exit (1);
+
+ tls_setblocking(sock, 0);
+
+ rewind(fp);
+
+ while (posFile < size) {
+ int posBuffer = 0;
+ char buf[150000];
+
+ while (posBuffer < sizeof(buf)) {
+ int bytes;
+
+ bytes = read(fileno(fp), buf + posBuffer, sizeof(buf));
+
+ if (bytes == 0)
+ break;
+
+ if (bytes < 0) {
+ perror("read");
+ }
+
+ else {
+ printf("writing %d buffer\n", bytes);
+ tls_write_buffer(ctx, buf, bytes);
+ printf("wrote %d buffer\n", bytes);
+ posBuffer += bytes;
+ posFile += bytes;
+ }
+
+ if (posFile >= size)
+ break;
+ }
+ }
+
+ printf("wrote total %d bytes\n", posFile);
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tls_test_server.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tls_test_server.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,264 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "ssl.h"
+#include "tls.h"
+
+typedef int (*IO_HANDLER)(int i);
+
+typedef struct __tls_mngr {
+ int sock;
+ TLS_CONTEXT ctx;
+ IO_HANDLER handler;
+} TLS_MNGR;
+
+static TLS_MNGR tls_mngr[100] = {{0}};
+static int mngr_size = 0;
+static int width = 0;
+static char *file_prefix = "";
+static fd_set regifds;
+static int master_socket = 0;
+
+void init_event_mngr (void)
+{
+ mngr_size = 0;
+ FD_ZERO (®ifds);
+}
+
+int tls_setblocking(int s, int blocking)
+{
+ unsigned mode = fcntl(s, F_GETFL, 0);
+
+ if (mode < 0)
+ return -1;
+
+ if (blocking)
+ mode &= ~(O_NDELAY | O_NONBLOCK);
+ else
+ mode |= O_NDELAY | O_NONBLOCK;
+
+ return fcntl(s, F_SETFL, mode);
+}
+
+void regi_sock (int sock, TLS_CONTEXT ctx, IO_HANDLER handler)
+{
+ FD_SET (sock, ®ifds);
+
+ if (sock + 1 > width)
+ width = sock + 1;
+
+ tls_mngr[mngr_size].sock = sock;
+ tls_mngr[mngr_size].ctx = ctx;
+ tls_mngr[mngr_size].handler = handler;
+ mngr_size++;
+
+ tls_setblocking(sock, 0);
+
+ printf("socket %d registered, ctx = %p, mngr_size = %d, width = %d\n",
+ sock, ctx, mngr_size, width);
+}
+
+int get_width (void)
+{
+ int i;
+ int lwidth = 1;
+
+ for (i = 0; i < mngr_size; i++) {
+ if (tls_mngr[i].sock + 1 > lwidth)
+ lwidth = tls_mngr[i].sock + 1;
+ }
+
+ return lwidth;
+}
+
+int tls_read_buffer(TLS_MNGR mngr, char *buf, int size)
+{
+ int bytes = 0;
+ TLS_CONTEXT ctx = mngr.ctx;
+
+ do {
+ int ret = tls_read(ctx, buf + bytes, size - bytes);
+ int err = tls_get_error(ctx, ret);
+
+ printf("tls_read returned %d\n", ret);
+
+ switch (err) {
+ case SSL_ERROR_NONE:
+ bytes += ret;
+ break;
+
+ case SSL_ERROR_WANT_READ:
+ printf("ssl error want read\n");
+ return bytes;
+ break;
+
+ case SSL_ERROR_WANT_WRITE:
+ break;
+
+ case SSL_ERROR_ZERO_RETURN:
+ printf("shutdown\n");
+ tls_shutdown(ctx);
+ return bytes;
+
+ case SSL_ERROR_SYSCALL:
+ perror("tls_syscall");
+ tls_shutdown(ctx);
+ FD_CLR(mngr.sock, ®ifds);
+ return bytes;
+
+ default:
+ printf("TLS error code %d\n", err);
+ return bytes;
+ }
+
+ if (tls_pending(ctx)) {
+ printf("read pending\n");
+ }
+
+ } while (tls_pending(ctx));
+
+ printf("normal read %d bytes\n", bytes);
+ return bytes;
+}
+
+int tls_slave_handler(int i)
+{
+ unsigned char buf[50000];
+ char fname[100];
+ FILE *fp;
+
+ int bytes = tls_read_buffer(tls_mngr[i], buf, sizeof(buf));
+
+ printf("buffer read %d bytes\n", bytes);
+
+ if (bytes > 0) {
+ sprintf(fname, "%s%02d.txt", file_prefix, i);
+ fp = fopen(fname, "a");
+
+ if (fp == NULL)
+ perror("tls_slave_handler fopen");
+
+ else {
+ int ret = fwrite(buf, sizeof(char), bytes, fp);
+
+ if (ret != bytes)
+ perror("tls_slave_handler write");
+
+ fclose(fp);
+ }
+ }
+
+ return 0;
+}
+
+int tls_master_handler(int i)
+{
+ TLS_CONTEXT ctx_slave;
+ TLS_ISSUES tls_issues = {0};
+ int sock;
+
+ printf("tls_master_handler\n");
+
+ tls_issues.master_socket = master_socket;
+
+ sock = init_tls_slave(tls_issues, tls_mngr[i].ctx, &ctx_slave);
+
+ if (sock < 0) {
+ perror("init_tls_slave");
+ return -1;
+ }
+
+ regi_sock(sock, ctx_slave, tls_slave_handler);
+
+ return 0;
+}
+
+int event_mngr ()
+{
+ struct timeval tv;
+ int retv;
+ int i;
+ fd_set readfds;
+
+ tv.tv_sec = 5;
+ tv.tv_usec = 0;
+
+ readfds = regifds;
+
+ retv = select(width, &readfds, NULL, NULL, &tv);
+ printf("select returned %d\n", retv);
+
+ if (retv > 0) {
+ for (i=0; i < mngr_size; i++) {
+ if (FD_ISSET(tls_mngr[i].sock, &readfds)) {
+ tls_mngr[i].handler(i);
+ }
+ }
+ }
+
+ if (retv < 0)
+ perror("select");
+
+ return retv;
+}
+
+int main (int argc, char *argv[])
+{
+ TLS_ISSUES tls_issues = {0};
+ TLS_CONTEXT ctx;
+ fd_set readfds;
+
+ if (argc != 2) {
+ printf("Usage: tls_test_server <file prefix>\n");
+ exit(0);
+ }
+
+ file_prefix = strdup(argv[1]);
+
+ init_event_mngr();
+
+ if (init_tls_master(&master_socket,
+ tls_issues,
+ &ctx) < 0) {
+ printf("init_tls_master failed\n");
+ exit (1);
+ }
+
+ regi_sock(master_socket, ctx, tls_master_handler);
+
+ for (;;) {
+ readfds = regifds;
+ event_mngr();
+ usleep(100000L);
+ }
+
+ return 0;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,4530 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE tport.c Transport interface implementation.
+ *
+ * See tport.docs for more detailed description of tport interface.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Ismo Puustinen <Ismo.H.Puustinen at nokia.com>
+ * @author Tat Chan <Tat.Chan at nokia.com>
+ * @author Kai Vehmanen <kai.vehmanen at nokia.com>
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ *
+ * @date Created: Thu Jul 20 12:54:32 2000 ppessi
+ */
+
+#include "config.h"
+
+#include <sofia-sip/string0.h>
+#include <sofia-sip/su.h>
+#include <sofia-sip/su_errno.h>
+#include <sofia-sip/su_alloc.h>
+#include <sofia-sip/su_tagarg.h>
+#include <sofia-sip/su_localinfo.h>
+
+typedef struct tport_nat_s tport_nat_t;
+
+#define SU_WAKEUP_ARG_T struct tport_s
+#define SU_TIMER_ARG_T struct tport_master
+#define SU_MSG_ARG_T union tport_su_msg_arg
+
+#include <sofia-sip/su_wait.h>
+
+#include <sofia-sip/msg.h>
+#include <sofia-sip/msg_addr.h>
+#include <sofia-sip/hostdomain.h>
+
+#include <stdlib.h>
+#include <time.h>
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+
+#ifndef IPPROTO_SCTP
+#define IPPROTO_SCTP (132)
+#endif
+
+#include "sofia-sip/tport.h"
+#include "sofia-sip/su_uniqueid.h"
+#include <sofia-sip/rbtree.h>
+
+#include "tport_internal.h"
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+static char const __func__[] = "tport";
+#endif
+
+#define STACK_RECV(tp, msg, now) \
+ (tp)->tp_master->mr_tpac->tpac_recv((tp)->tp_master->mr_stack, (tp), \
+ (msg), (tp)->tp_magic, (now))
+
+#define STACK_ERROR(tp, errcode, dstname) \
+ (tp)->tp_master->mr_tpac->tpac_error((tp)->tp_master->mr_stack, (tp), \
+ (errcode), (dstname))
+
+#define STACK_ADDRESS(tp) \
+ (tp)->tp_master->mr_tpac->tpac_address((tp)->tp_master->mr_stack, (tp))
+
+#define TP_STACK tp_master->mr_stack
+
+/* Define macros for rbtree implementation */
+#define TP_LEFT(tp) ((tp)->tp_left)
+#define TP_RIGHT(tp) ((tp)->tp_right)
+#define TP_PARENT(tp) ((tp)->tp_dad)
+#define TP_SET_RED(tp) ((tp)->tp_black = 0)
+#define TP_SET_BLACK(tp) ((tp)->tp_black = 1)
+#define TP_IS_RED(tp) ((tp) && (tp)->tp_black == 0)
+#define TP_IS_BLACK(tp) (!(tp) || (tp)->tp_black == 1)
+#define TP_COPY_COLOR(dst, src) ((dst)->tp_black = (src)->tp_black)
+#define TP_INSERT(tp) ((void)0)
+#define TP_REMOVE(tp) ((tp)->tp_left = (tp)->tp_right = (tp)->tp_dad = NULL)
+
+static inline int tp_cmp(tport_t const *a, tport_t const *b)
+{
+ if (a == b)
+ return 0;
+
+ if (a->tp_addrlen != b->tp_addrlen)
+ return (int)(a->tp_addrlen - b->tp_addrlen);
+
+ return memcmp(a->tp_addr, b->tp_addr, a->tp_addrlen);
+}
+
+static inline int tprb_is_inserted(tport_t const *a)
+{
+ return a->tp_dad != 0 || a->tp_left != 0 || a->tp_right != 0;
+}
+
+RBTREE_PROTOS(static inline, tprb, tport_t);
+
+RBTREE_BODIES(static inline, tprb, tport_t,
+ TP_LEFT, TP_RIGHT, TP_PARENT,
+ TP_IS_RED, TP_SET_RED, TP_IS_BLACK, TP_SET_BLACK, TP_COPY_COLOR,
+ tp_cmp, TP_INSERT, TP_REMOVE);
+
+enum {
+ /** Default per-thread read queue length */
+ THRP_PENDING = 8
+};
+
+struct tport_pending_s {
+ /* tport_pending_t *p_left, *p_right, *p_parent; */
+ void *p_client;
+ tport_pending_error_f *p_callback;
+ msg_t *p_msg;
+ unsigned short p_reported;
+ unsigned short p_on_success;
+};
+
+/** Return true if transport is master. */
+int tport_is_master(tport_t const *self)
+{
+ return
+ self &&
+ self->tp_master->mr_master == self;
+}
+
+/** Return true if transport is primary. */
+int tport_is_primary(tport_t const *self)
+{
+ return
+ self &&
+ self->tp_pri->pri_primary == self;
+}
+
+/** Return true if transport is secondary. */
+int tport_is_secondary(tport_t const *self)
+{
+ return
+ self &&
+ self->tp_master->mr_master != self &&
+ self->tp_pri->pri_primary != self;
+}
+
+/** Test if transport has been registered */
+int tport_is_registered(tport_t const *self)
+{
+ return self->tp_index != 0;
+}
+
+/** Test if transport is stream. */
+int tport_is_stream(tport_t const *self)
+{
+ return self->tp_addrinfo->ai_socktype == SOCK_STREAM;
+}
+
+/** Test if transport is dgram. */
+int tport_is_dgram(tport_t const *self)
+{
+ return self->tp_addrinfo->ai_socktype == SOCK_DGRAM;
+}
+
+/** Test if transport is udp. */
+int tport_is_udp(tport_t const *self)
+{
+ return self->tp_addrinfo->ai_protocol == IPPROTO_UDP;
+}
+
+/** Test if transport is tcp. */
+int tport_is_tcp(tport_t const *self)
+{
+ return self->tp_addrinfo->ai_protocol == IPPROTO_TCP;
+}
+
+/** Return 1 if transport is reliable, 0 otherwise.
+ *
+ * (Note that this is part of external API).
+ */
+int tport_is_reliable(tport_t const *self)
+{
+ return self != NULL &&
+ (self->tp_addrinfo->ai_socktype == SOCK_STREAM ||
+ self->tp_addrinfo->ai_socktype == SOCK_SEQPACKET);
+}
+
+/** Return 0 if self is local, nonzero otherwise.
+ *
+ * The return valu is the
+ *
+ * @sa TPTAG_PUBLIC(), enum #tport_via.
+ */
+int tport_is_public(tport_t const *self)
+{
+ return self->tp_pri->pri_public;
+}
+
+/** Return true if transport supports IPv4 */
+int tport_has_ip4(tport_t const *self)
+{
+ return self &&
+ (self->tp_addrinfo->ai_family == 0 ||
+ self->tp_addrinfo->ai_family == AF_INET);
+}
+
+
+#if SU_HAVE_IN6
+/** Return true if transport supports IPv6 */
+int tport_has_ip6(tport_t const *self)
+{
+ return self &&
+ (self->tp_addrinfo->ai_family == 0 ||
+ self->tp_addrinfo->ai_family == AF_INET6);
+}
+#endif
+
+/** Return true if transport supports TLS. */
+int tport_has_tls(tport_t const *self)
+{
+ return self && self->tp_pri->pri_has_tls;
+
+}
+
+/** Return true if transport is being updated. */
+int tport_is_updating(tport_t const *self)
+{
+ tport_primary_t *pri;
+
+ if (tport_is_master(self)) {
+ for (pri = self->tp_master->mr_primaries; pri; pri = pri->pri_next)
+ if (pri->pri_updating)
+ return 1;
+ }
+ else if (tport_is_primary(self)) {
+ return self->tp_pri->pri_updating;
+ }
+
+ return 0;
+}
+
+/** Test if transport has been closed.
+ *
+ * @since New in @VERSION_1_12_4
+ */
+inline int tport_is_closed(tport_t const *self)
+{
+ return self->tp_closed;
+}
+
+/** Test if transport has been shut down.
+ *
+ * @since New in @VERSION_1_12_4
+ */
+inline int tport_is_shutdown(tport_t const *self)
+{
+ return self->tp_closed || self->tp_send_close || self->tp_recv_close;
+}
+
+/** Test if transport is bound */
+static inline int tport_is_bound(tport_t const *self)
+{
+ return self->tp_protoname != NULL;
+}
+
+/** Test if transport connection has been established. @NEW_1_12_5 */
+inline int tport_is_connected(tport_t const *self)
+{
+ return self->tp_is_connected;
+}
+
+/** MTU for transport */
+static inline unsigned tport_mtu(tport_t const *self)
+{
+ return self->tp_params->tpp_mtu;
+}
+
+static inline
+int tport_has_sigcomp(tport_t const *self)
+{
+ return self->tp_name->tpn_comp != NULL;
+}
+
+/** Set IP TOS for socket */
+void tport_set_tos(su_socket_t socket, su_addrinfo_t *ai, int tos)
+{
+ if (tos >= 0 &&
+ ai->ai_family == AF_INET &&
+ setsockopt(socket, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0) {
+ SU_DEBUG_3(("tport: setsockopt(IP_TOS): %s\n",
+ su_strerror(su_errno())));
+ }
+}
+
+static
+tport_t *tport_connect(tport_primary_t *pri, su_addrinfo_t *ai,
+ tp_name_t const *tpn);
+
+static int bind6only_check(tport_master_t *mr);
+
+static
+int tport_server_addrinfo(tport_master_t *mr,
+ char const *canon,
+ int family,
+ char const *host,
+ char const *service,
+ char const *protocol,
+ char const * const transports[],
+ su_addrinfo_t **res);
+
+static int tport_get_local_addrinfo(tport_master_t *mr,
+ char const *port,
+ su_addrinfo_t const *hints,
+ su_addrinfo_t **return_ai);
+
+int tport_getaddrinfo(char const *node, char const *service,
+ su_addrinfo_t const *hints,
+ su_addrinfo_t **res);
+
+static void tport_freeaddrinfo(su_addrinfo_t *ai);
+
+static
+int tport_addrinfo_copy(su_addrinfo_t *dst, void *addr, socklen_t addrlen,
+ su_addrinfo_t const *src);
+
+static int
+ tport_bind_client(tport_master_t *self, tp_name_t const *tpn,
+ char const * const transports[], enum tport_via public,
+ tagi_t *tags),
+ tport_bind_server(tport_master_t *, tp_name_t const *tpn,
+ char const * const transports[], enum tport_via public,
+ tagi_t *tags),
+
+ tport_setname(tport_t *, char const *, su_addrinfo_t const *, char const *),
+ tport_wakeup_pri(su_root_magic_t *m, su_wait_t *w, tport_t *self),
+ tport_wakeup(su_root_magic_t *m, su_wait_t *w, tport_t *self),
+ tport_base_wakeup(tport_t *self, int events),
+ tport_connected(su_root_magic_t *m, su_wait_t *w, tport_t *self),
+ tport_resolve(tport_t *self, msg_t *msg, tp_name_t const *tpn),
+ tport_send_error(tport_t *, msg_t *, tp_name_t const *),
+ tport_queue(tport_t *self, msg_t *msg),
+ tport_queue_rest(tport_t *self, msg_t *msg, msg_iovec_t iov[], size_t iovused),
+ tport_pending_error(tport_t *self, su_sockaddr_t const *dst, int error),
+ tport_pending_errmsg(tport_t *self, msg_t *msg, int error);
+
+static ssize_t tport_vsend(tport_t *self, msg_t *msg, tp_name_t const *tpn,
+ msg_iovec_t iov[], size_t iovused,
+ struct sigcomp_compartment *cc);
+
+tport_t *tport_by_addrinfo(tport_primary_t const *pri,
+ su_addrinfo_t const *ai,
+ tp_name_t const *tpn);
+
+void tport_peer_address(tport_t *self, msg_t *msg);
+static unsigned long tport_now(void);
+
+static void tport_tick(su_root_magic_t *, su_timer_t *, tport_master_t *mr);
+
+static void tport_parse(tport_t *self, int complete, su_time_t now);
+
+static tport_primary_t *tport_alloc_primary(tport_master_t *mr,
+ tport_vtable_t const *vtable,
+ tp_name_t tpn[1],
+ su_addrinfo_t *ai,
+ tagi_t const *tags,
+ char const **return_culprit);
+
+static tport_primary_t *tport_listen(tport_master_t *mr,
+ tport_vtable_t const *vtable,
+ tp_name_t tpn[1],
+ su_addrinfo_t *ai,
+ tagi_t *tags);
+static void tport_zap_primary(tport_primary_t *);
+
+static char *localipname(int pf, char *buf, size_t bufsiz);
+static int getprotohints(su_addrinfo_t *hints,
+ char const *proto, int flags);
+static void tport_send_queue(tport_t *self);
+
+
+/* Stack class used when transports are being destroyed */
+static
+void tport_destroy_recv(tp_stack_t *stack, tport_t *tp,
+ msg_t *msg, tp_magic_t *magic,
+ su_time_t received)
+{
+ msg_destroy(msg);
+}
+
+static
+void tport_destroy_error(tp_stack_t *stack, tport_t *tp,
+ int errcode, char const *remote)
+{
+}
+
+static
+msg_t *tport_destroy_alloc(tp_stack_t *stack, int flags,
+ char const data[], usize_t len,
+ tport_t const *tp,
+ tp_client_t *tpc)
+{
+ return NULL;
+}
+
+/** Name for "any" transport. @internal */
+static char const tpn_any[] = "*";
+
+/** Create the master transport. */
+tport_t *tport_tcreate(tp_stack_t *stack,
+ tp_stack_class_t const *tpac,
+ su_root_t *root,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ tport_master_t *mr;
+ tp_name_t *tpn;
+ tport_params_t *tpp;
+ unsigned tick;
+ ta_list ta;
+
+ if (!stack || !tpac || !root) {
+ su_seterrno(EINVAL);
+ return NULL;
+ }
+
+ mr = su_home_clone(NULL, sizeof *mr);
+ if (!mr)
+ return NULL;
+
+ SU_DEBUG_7(("%s(): %p\n", "tport_create", mr));
+
+ mr->mr_stack = stack;
+ mr->mr_tpac = tpac;
+ mr->mr_root = root;
+
+ mr->mr_master->tp_master = mr;
+ mr->mr_master->tp_params = tpp = mr->mr_params;
+
+ mr->mr_master->tp_reusable = 1;
+ tpp->tpp_mtu = UINT_MAX;
+ tpp->tpp_thrprqsize = THRP_PENDING;
+ tpp->tpp_qsize = TPORT_QUEUESIZE;
+ tpp->tpp_sdwn_error = 1;
+ tpp->tpp_idle = UINT_MAX;
+ tpp->tpp_timeout = UINT_MAX;
+ tpp->tpp_sigcomp_lifetime = UINT_MAX;
+ tpp->tpp_stun_server = 1;
+ tpp->tpp_tos = -1; /* set invalid, valid values are 0-255 */
+
+ tpn = mr->mr_master->tp_name;
+ tpn->tpn_proto = "*";
+ tpn->tpn_host = "*";
+ tpn->tpn_canon = "*";
+ tpn->tpn_port = "*";
+
+ ta_start(ta, tag, value);
+
+ tport_set_params(mr->mr_master, ta_tags(ta));
+ tport_open_log(mr, ta_args(ta));
+
+ tick = 5000; /* For testing, usually 30000 is enough */
+ if (tpp->tpp_idle < 4 * tick)
+ tick = tpp->tpp_idle / 4;
+ if (tpp->tpp_timeout < 4 * tick)
+ tick = tpp->tpp_timeout / 4;
+ if (tick < 200)
+ tick = 200;
+
+ tport_init_stun_server(mr, ta_args(ta));
+
+ mr->mr_timer = su_timer_create(su_root_task(root), tick);
+ su_timer_set(mr->mr_timer, tport_tick, mr);
+
+ ta_end(ta);
+
+ return mr->mr_master;
+}
+
+/** Destroy the master transport. */
+void tport_destroy(tport_t *self)
+{
+ tport_master_t *mr;
+
+ static tp_stack_class_t tport_destroy_tpac[1] =
+ {{
+ sizeof tport_destroy_tpac,
+ /* tpac_recv */ tport_destroy_recv,
+ /* tpac_error */ tport_destroy_error,
+ /* tpac_alloc */ tport_destroy_alloc,
+ /* tpac_address */ NULL
+ }};
+
+ SU_DEBUG_7(("%s(%p)\n", __func__, self));
+
+ if (self == NULL)
+ return;
+
+ assert(tport_is_master(self));
+ if (!tport_is_master(self))
+ return;
+
+ mr = (tport_master_t *)self;
+ mr->mr_tpac = tport_destroy_tpac;
+
+ while (mr->mr_primaries)
+ tport_zap_primary(mr->mr_primaries);
+
+ tport_deinit_stun_server(mr);
+
+ if (mr->mr_dump_file)
+ fclose(mr->mr_dump_file), mr->mr_dump_file = NULL;
+
+ if (mr->mr_timer)
+ su_timer_destroy(mr->mr_timer), mr->mr_timer = NULL;
+
+ su_home_zap(mr->mr_home);
+}
+
+
+/** Allocate a primary transport */
+static
+tport_primary_t *tport_alloc_primary(tport_master_t *mr,
+ tport_vtable_t const *vtable,
+ tp_name_t tpn[1],
+ su_addrinfo_t *ai,
+ tagi_t const *tags,
+ char const **return_culprit)
+{
+ tport_primary_t *pri, **next;
+ tport_t *tp;
+ int save_errno;
+
+ for (next = &mr->mr_primaries; *next; next = &(*next)->pri_next)
+ ;
+
+ assert(vtable->vtp_pri_size >= sizeof *pri);
+
+ if ((pri = su_home_clone(mr->mr_home, vtable->vtp_pri_size))) {
+ tport_t *tp = pri->pri_primary;
+ pri->pri_vtable = vtable;
+ pri->pri_public = vtable->vtp_public;
+
+ tp->tp_master = mr;
+ tp->tp_pri = pri;
+ tp->tp_socket = INVALID_SOCKET;
+
+ tp->tp_magic = mr->mr_master->tp_magic;
+
+ tp->tp_params = pri->pri_params;
+ memcpy(tp->tp_params, mr->mr_params, sizeof (*tp->tp_params));
+ tp->tp_reusable = mr->mr_master->tp_reusable;
+
+ if (!pri->pri_public)
+ tp->tp_addrinfo->ai_addr = &tp->tp_addr->su_sa;
+
+ SU_DEBUG_5(("%s(%p): new primary tport %p\n", __func__, mr, pri));
+ }
+
+ *next = pri;
+ tp = pri->pri_primary;
+
+ if (!tp)
+ *return_culprit = "alloc";
+ else if (tport_set_params(tp, TAG_NEXT(tags)) < 0)
+ *return_culprit = "tport_set_params";
+ else if (vtable->vtp_init_primary &&
+ vtable->vtp_init_primary(pri, tpn, ai, tags, return_culprit) < 0)
+ ;
+ else if (tport_setname(tp, vtable->vtp_name, ai, tpn->tpn_canon) == -1)
+ *return_culprit = "tport_setname";
+ else if (tpn->tpn_ident &&
+ !(tp->tp_name->tpn_ident = su_strdup(tp->tp_home, tpn->tpn_ident)))
+ *return_culprit = "alloc ident";
+ else
+ return pri; /* Success */
+
+ save_errno = su_errno();
+ tport_zap_primary(pri);
+ su_seterrno(save_errno);
+
+ return NULL;
+}
+
+
+/** Destroy a primary transport and its secondary transports. @internal */
+static
+void tport_zap_primary(tport_primary_t *pri)
+{
+ tport_primary_t **prip;
+
+ if (pri == NULL)
+ return;
+
+ assert(tport_is_primary(pri->pri_primary));
+
+ if (pri->pri_vtable->vtp_deinit_primary)
+ pri->pri_vtable->vtp_deinit_primary(pri);
+
+ while (pri->pri_secondary)
+ tport_zap_secondary(pri->pri_secondary);
+
+ /* We have just a single-linked list for primary transports */
+ for (prip = &pri->pri_master->mr_primaries;
+ *prip != pri;
+ prip = &(*prip)->pri_next)
+ assert(*prip);
+
+ *prip = pri->pri_next;
+
+ tport_zap_secondary(pri->pri_primary);
+}
+
+/**Create a primary transport object with socket.
+ *
+ * Creates a primary transport object with a server socket, and then
+ * registers the socket with suitable events to the root.
+ *
+ * @param dad parent (master or primary) transport object
+ * @param ai pointer to addrinfo structure
+ * @param canon canonical name of node
+ * @param protoname name of the protocol
+ */
+static
+tport_primary_t *tport_listen(tport_master_t *mr,
+ tport_vtable_t const *vtable,
+ tp_name_t tpn[1],
+ su_addrinfo_t *ai,
+ tagi_t *tags)
+{
+ tport_primary_t *pri = NULL;
+
+ int err;
+ int errlevel = 3;
+ char buf[TPORT_HOSTPORTSIZE];
+
+ char const *protoname = vtable->vtp_name;
+ char const *culprit = "unknown";
+
+ su_sockaddr_t *su = (void *)ai->ai_addr;
+
+ /* Log an error, return error */
+#define TPORT_LISTEN_ERROR(errno, what) \
+ ((void)(err = errno, \
+ ((err == EADDRINUSE || err == EAFNOSUPPORT || \
+ err == ESOCKTNOSUPPORT || err == EPROTONOSUPPORT || \
+ err == ENOPROTOOPT ? 7 : 3) < SU_LOG_LEVEL ? \
+ su_llog(tport_log, errlevel, \
+ "%s(%p): %s(pf=%d %s/%s): %s\n", \
+ __func__, pri ? (void *)pri : (void *)mr, what, \
+ ai->ai_family, protoname, \
+ tport_hostport(buf, sizeof(buf), su, 2), \
+ su_strerror(err)) : (void)0), \
+ tport_zap_primary(pri), \
+ su_seterrno(err)), \
+ (void *)NULL)
+
+ /* Create a primary transport object for another transport. */
+ pri = tport_alloc_primary(mr, vtable, tpn, ai, tags, &culprit);
+ if (pri == NULL)
+ return TPORT_LISTEN_ERROR(errno, culprit);
+
+ if (pri->pri_primary->tp_socket != INVALID_SOCKET) {
+ int index = 0;
+ tport_t *tp = pri->pri_primary;
+ su_wait_t wait[1] = { SU_WAIT_INIT };
+
+ if (su_wait_create(wait, tp->tp_socket, tp->tp_events) == -1)
+ return TPORT_LISTEN_ERROR(su_errno(), "su_wait_create");
+
+ /* Register receiving or accepting function with events specified above */
+ index = su_root_register(mr->mr_root, wait, tport_wakeup_pri, tp, 0);
+ if (index == -1) {
+ su_wait_destroy(wait);
+ return TPORT_LISTEN_ERROR(su_errno(), "su_root_register");
+ }
+
+ tp->tp_index = index;
+ }
+
+ pri->pri_primary->tp_has_connection = 0;
+
+ SU_DEBUG_5(("%s(%p): %s " TPN_FORMAT "\n",
+ __func__, pri, "listening at",
+ TPN_ARGS(pri->pri_primary->tp_name)));
+
+ return pri;
+}
+
+int tport_bind_socket(int socket,
+ su_addrinfo_t *ai,
+ char const **return_culprit)
+{
+ su_sockaddr_t *su = (su_sockaddr_t *)ai->ai_addr;
+ socklen_t sulen = (socklen_t)(ai->ai_addrlen);
+
+ if (bind(socket, ai->ai_addr, sulen) == -1) {
+ return *return_culprit = "bind", -1;
+ }
+
+ if (getsockname(socket, &su->su_sa, &sulen) == SOCKET_ERROR) {
+ return *return_culprit = "getsockname", -1;
+ }
+
+ ai->ai_addrlen = sulen;
+
+#if defined (__linux__) && defined (SU_HAVE_IN6)
+ if (ai->ai_family == AF_INET6) {
+ if (!SU_SOCKADDR_INADDR_ANY(su) &&
+ (IN6_IS_ADDR_V4MAPPED(&su->su_sin6.sin6_addr) ||
+ IN6_IS_ADDR_V4COMPAT(&su->su_sin6.sin6_addr))) {
+ su_sockaddr_t su0[1];
+
+ memcpy(su0, su, sizeof su0);
+
+ memset(su, 0, ai->ai_addrlen = sizeof su->su_sin);
+ su->su_family = ai->ai_family = AF_INET;
+ su->su_port = su0->su_port;
+
+#ifndef IN6_V4MAPPED_TO_INADDR
+#define IN6_V4MAPPED_TO_INADDR(in6, in4) \
+ memcpy((in4), 12 + (uint8_t *)(in6), sizeof(struct in_addr))
+#endif
+ IN6_V4MAPPED_TO_INADDR(&su0->su_sin6.sin6_addr, &su->su_sin.sin_addr);
+ }
+ }
+#endif
+
+ return 0;
+}
+
+
+/** Indicate stack that a transport has been updated */
+void tport_has_been_updated(tport_t *self)
+{
+ self->tp_pri->pri_updating = 0;
+
+ if (self->tp_master->mr_tpac->tpac_address)
+ self->tp_master->mr_tpac->tpac_address(self->tp_master->mr_stack, self);
+}
+
+
+static
+int tport_set_events(tport_t *self, int set, int clear)
+{
+ int events;
+
+ if (self == NULL)
+ return -1;
+
+ events = (self->tp_events | set) & ~clear;
+ self->tp_events = events;
+
+ if (self->tp_pri->pri_vtable->vtp_set_events)
+ return self->tp_pri->pri_vtable->vtp_set_events(self);
+
+ SU_DEBUG_7(("tport_set_events(%p): events%s%s%s\n", self,
+ (events & SU_WAIT_IN) ? " IN" : "",
+ (events & SU_WAIT_OUT) ? " OUT" : "",
+ SU_WAIT_CONNECT != SU_WAIT_OUT &&
+ (events & SU_WAIT_CONNECT) ? " CONNECT" : ""));
+
+ return
+ su_root_eventmask(self->tp_master->mr_root,
+ self->tp_index,
+ self->tp_socket,
+ self->tp_events = events);
+}
+
+/**Allocate a secondary transport. @internal
+ *
+ * The function tport_alloc_secondary() creates a secondary transport
+ * object. The new transport initally shares parameters structure with the
+ * original transport.
+ *
+ * @param pri primary transport
+ * @param socket socket for transport
+ * @parma accepted true if the socket was accepted from server socket
+ *
+ * @return
+ * Pointer to the newly created transport, or NULL upon an error.
+ *
+ * @note The socket is always closed upon error.
+ */
+tport_t *tport_alloc_secondary(tport_primary_t *pri,
+ int socket,
+ int accepted,
+ char const **return_reason)
+{
+ tport_master_t *mr = pri->pri_master;
+ tport_t *self;
+
+ self = su_home_clone(mr->mr_home, pri->pri_vtable->vtp_secondary_size);
+
+ if (self) {
+ SU_DEBUG_7(("%s(%p): new secondary tport %p\n", __func__, pri, self));
+
+ self->tp_refs = -1; /* Freshly allocated */
+ self->tp_master = mr;
+ self->tp_pri = pri;
+ self->tp_params = pri->pri_params;
+ self->tp_accepted = accepted != 0;
+ self->tp_reusable = pri->pri_primary->tp_reusable;
+
+ self->tp_magic = pri->pri_primary->tp_magic;
+
+ self->tp_addrinfo->ai_addr = (void *)self->tp_addr;
+
+ self->tp_socket = socket;
+
+ if (pri->pri_vtable->vtp_init_secondary &&
+ pri->pri_vtable->vtp_init_secondary(self, socket, accepted,
+ return_reason) < 0) {
+ if (pri->pri_vtable->vtp_deinit_secondary)
+ pri->pri_vtable->vtp_deinit_secondary(self);
+ su_home_zap(self->tp_home);
+ return NULL;
+ }
+
+ /* Set IP TOS if it is set in primary */
+ tport_set_tos(socket,
+ pri->pri_primary->tp_addrinfo,
+ pri->pri_params->tpp_tos);
+ }
+ else {
+ su_close(socket);
+ *return_reason = "malloc";
+ }
+
+ return self;
+}
+
+
+/** Create a connected transport object with socket.
+ *
+ * The function tport_connect() creates a secondary transport with a
+ * connected socket. It registers the socket with suitable events to the
+ * root.
+ *
+ * @param pri primary transport object
+ * @param ai pointer to addrinfo structure
+ * @param tpn canonical name of node
+ */
+static
+tport_t *tport_connect(tport_primary_t *pri,
+ su_addrinfo_t *ai,
+ tp_name_t const *tpn)
+{
+ if (ai == NULL || ai->ai_addrlen > sizeof (pri->pri_primary->tp_addr))
+ return NULL;
+
+ if (pri->pri_vtable->vtp_connect)
+ return pri->pri_vtable->vtp_connect(pri, ai, tpn);
+ else
+ return tport_base_connect(pri, ai, ai, tpn);
+}
+
+/**Create a connected transport object with socket.
+ *
+ * The function tport_connect() creates a secondary transport with a
+ * connected socket. It registers the socket with suitable events to the
+ * root.
+ *
+ * @param pri primary transport object
+ * @param ai pointer to addrinfo structure describing socket
+ * @param real_ai pointer to addrinfo structure describing real target
+ * @param tpn canonical name of node
+ */
+tport_t *tport_base_connect(tport_primary_t *pri,
+ su_addrinfo_t *ai,
+ su_addrinfo_t *real_ai,
+ tp_name_t const *tpn)
+{
+ tport_master_t *mr = pri->pri_master;
+ tport_t *self = NULL;
+
+ su_socket_t s, server_socket;
+ su_wait_t wait[1] = { SU_WAIT_INIT };
+ su_wakeup_f wakeup = tport_wakeup;
+ int index = 0;
+ int events = SU_WAIT_IN | SU_WAIT_ERR;
+
+ int err;
+ unsigned errlevel = 3;
+ char buf[TPORT_HOSTPORTSIZE];
+ char const *what;
+
+ /* Log an error, return error */
+#define TPORT_CONNECT_ERROR(errno, what) \
+ return \
+ ((void)(err = errno, \
+ su_wait_destroy(wait), \
+ (SU_LOG_LEVEL >= errlevel ? \
+ su_llog(tport_log, errlevel, \
+ "%s(%p): %s(pf=%d %s/%s): %s\n", \
+ __func__, pri, #what, ai->ai_family, \
+ tpn->tpn_proto, \
+ tport_hostport(buf, sizeof(buf), \
+ (void *)ai->ai_addr, 2), \
+ su_strerror(err)) : (void)0), \
+ tport_zap_secondary(self), \
+ su_seterrno(err)), \
+ (void *)NULL)
+
+ s = su_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+ if (s == INVALID_SOCKET)
+ TPORT_CONNECT_ERROR(su_errno(), "socket");
+
+ what = "tport_alloc_secondary";
+ if ((self = tport_alloc_secondary(pri, s, 0, &what)) == NULL)
+ TPORT_CONNECT_ERROR(errno, what);
+
+ self->tp_conn_orient = 1;
+
+ if ((server_socket = pri->pri_primary->tp_socket) != INVALID_SOCKET) {
+ su_sockaddr_t susa;
+ socklen_t susalen = sizeof(susa);
+
+ /* Bind this socket to same IP address as the primary server socket */
+ if (getsockname(server_socket, &susa.su_sa, &susalen) < 0) {
+ SU_DEBUG_3(("tport_connect: getsockname(): %s\n",
+ su_strerror(su_errno())));
+ }
+ else {
+ susa.su_port = 0;
+ if (bind(s, &susa.su_sa, susalen) < 0) {
+ SU_DEBUG_3(("tport_connect: bind(local-ip): %s\n",
+ su_strerror(su_errno())));
+ }
+ }
+ }
+
+ /* Set sockname for the tport */
+ if (tport_setname(self, tpn->tpn_proto, real_ai, tpn->tpn_canon) == -1)
+ TPORT_CONNECT_ERROR(su_errno(), tport_setname);
+
+ if (connect(s, ai->ai_addr, (socklen_t)(ai->ai_addrlen)) == SOCKET_ERROR) {
+ err = su_errno();
+ if (!su_is_blocking(err))
+ TPORT_CONNECT_ERROR(err, connect);
+ events = SU_WAIT_CONNECT | SU_WAIT_ERR;
+ wakeup = tport_connected;
+ what = "connecting";
+ }
+ else {
+ what = "connected";
+ self->tp_is_connected = 1;
+ }
+
+ if (su_wait_create(wait, s, self->tp_events = events) == -1)
+ TPORT_CONNECT_ERROR(su_errno(), su_wait_create);
+
+ /* Register receiving function with events specified above */
+ if ((index = su_root_register(mr->mr_root, wait, wakeup, self, 0)) == -1)
+ TPORT_CONNECT_ERROR(su_errno(), su_root_register);
+
+ self->tp_index = index;
+
+ if (ai == real_ai) {
+ SU_DEBUG_5(("%s(%p): %s to " TPN_FORMAT "\n",
+ __func__, self, what, TPN_ARGS(self->tp_name)));
+ }
+ else {
+ SU_DEBUG_5(("%s(%p): %s via %s to " TPN_FORMAT "\n",
+ __func__, self, what,
+ tport_hostport(buf, sizeof(buf), (void *)ai->ai_addr, 2),
+ TPN_ARGS(self->tp_name)));
+ }
+
+ tprb_append(&pri->pri_secondary, self);
+
+ return self;
+}
+
+/** Destroy a secondary transport. @internal */
+void tport_zap_secondary(tport_t *self)
+{
+ tport_master_t *mr;
+
+ if (self == NULL)
+ return;
+
+ /* Remove from rbtree */
+ tprb_remove(&self->tp_pri->pri_secondary, self);
+
+ /* Do not deinit primary as secondary! */
+ if (tport_is_secondary(self) &&
+ self->tp_pri->pri_vtable->vtp_deinit_secondary)
+ self->tp_pri->pri_vtable->vtp_deinit_secondary(self);
+
+ if (self->tp_msg) {
+ msg_destroy(self->tp_msg), self->tp_msg = NULL;
+ SU_DEBUG_3(("%s(%p): zapped partially received message\n",
+ __func__, self));
+ }
+
+ if (self->tp_queue && self->tp_queue[self->tp_qhead]) {
+ size_t n = 0, i, N = self->tp_params->tpp_qsize;
+ for (i = self->tp_qhead; self->tp_queue[i]; i = (i + 1) % N) {
+ msg_destroy(self->tp_queue[i]), self->tp_queue[i] = NULL;
+ n++;
+ }
+ SU_DEBUG_3(("%s(%p): zapped %lu queued messages\n",
+ __func__, self, (LU)n));
+ }
+
+ if (self->tp_pused) {
+ SU_DEBUG_3(("%s(%p): zapped with pending requests\n", __func__, self));
+ }
+
+ mr = self->tp_master;
+
+ tport_stun_server_remove_socket(self);
+
+ if (self->tp_index)
+ su_root_deregister(mr->mr_root, self->tp_index);
+ self->tp_index = 0;
+ if (self->tp_socket != INVALID_SOCKET)
+ su_close(self->tp_socket);
+ self->tp_socket = INVALID_SOCKET;
+
+ su_home_zap(self->tp_home);
+}
+
+/** Create a new reference to a transport object. */
+tport_t *tport_ref(tport_t *tp)
+{
+ if (tp) {
+ if (tp->tp_refs >= 0)
+ tp->tp_refs++;
+ else if (tp->tp_refs == -1)
+ tp->tp_refs = 1;
+ }
+ return tp;
+}
+
+/** Destroy reference to a transport object. */
+void tport_unref(tport_t *tp)
+{
+ if (tp && tp->tp_refs > 0)
+ if (--tp->tp_refs == 0 && tp->tp_params->tpp_idle == 0)
+ if (!tport_is_closed(tp))
+ tport_close(tp);
+}
+
+/** Create a new reference to transport object. */
+tport_t *tport_incref(tport_t *tp)
+{
+ return tport_ref(tp);
+}
+
+/** Destroy a transport reference. */
+void tport_decref(tport_t **ttp)
+{
+ assert(ttp);
+
+ if (*ttp) {
+ tport_unref(*ttp);
+ *ttp = NULL;
+ }
+}
+
+/** Get transport parameters.
+ *
+ * @param self pointer to a transport object
+ * @param tag,value,... list of tags
+ */
+int tport_get_params(tport_t const *self,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ ta_list ta;
+ int n;
+ tport_params_t const *tpp;
+ tport_primary_t const *pri = self->tp_pri;
+ int connect;
+
+ if (self == NULL)
+ return su_seterrno(EINVAL);
+
+ tpp = self->tp_params;
+ ta_start(ta, tag, value);
+
+ connect = tpp->tpp_conn_orient
+ /* Only dgram primary is *not* connection-oriented */
+ || !tport_is_primary(self) || !tport_is_dgram(self);
+
+ n = tl_tgets(ta_args(ta),
+ TPTAG_MTU(tpp->tpp_mtu),
+ TPTAG_REUSE(self->tp_reusable),
+ TPTAG_CONNECT(connect),
+ TPTAG_QUEUESIZE(tpp->tpp_qsize),
+ TPTAG_IDLE(tpp->tpp_idle),
+ TPTAG_TIMEOUT(tpp->tpp_timeout),
+ TPTAG_SDWN_ERROR(tpp->tpp_sdwn_error),
+ TPTAG_DEBUG_DROP(tpp->tpp_drop),
+ TPTAG_THRPSIZE(tpp->tpp_thrpsize),
+ TPTAG_THRPRQSIZE(tpp->tpp_thrprqsize),
+ TAG_IF(pri, TPTAG_PUBLIC(pri ? pri->pri_public : 0)),
+ TPTAG_TOS(tpp->tpp_tos),
+ TAG_END());
+
+ ta_end(ta);
+
+ return n;
+}
+
+/** Set transport parameters.
+ *
+ * @param self pointer to a transport object
+ * @param tag,value,... list of tags
+ */
+int tport_set_params(tport_t *self,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ ta_list ta;
+ int n;
+ tport_params_t tpp[1], *tpp0;
+
+ int connect, sdwn_error, reusable, stun_server;
+
+ struct sigcomp_compartment *cc = NONE;
+
+ if (self == NULL)
+ return su_seterrno(EINVAL);
+
+ memcpy(tpp, tpp0 = self->tp_params, sizeof *tpp);
+
+ connect = tpp->tpp_conn_orient;
+ sdwn_error = tpp->tpp_sdwn_error;
+ reusable = self->tp_reusable;
+ stun_server = tpp->tpp_stun_server;
+
+ ta_start(ta, tag, value);
+
+ n = tl_gets(ta_args(ta),
+ TPTAG_MTU_REF(tpp->tpp_mtu),
+ TAG_IF(!self->tp_queue, TPTAG_QUEUESIZE_REF(tpp->tpp_qsize)),
+ TPTAG_IDLE_REF(tpp->tpp_idle),
+ TPTAG_TIMEOUT_REF(tpp->tpp_timeout),
+ TPTAG_DEBUG_DROP_REF(tpp->tpp_drop),
+ TPTAG_THRPSIZE_REF(tpp->tpp_thrpsize),
+ TPTAG_THRPRQSIZE_REF(tpp->tpp_thrprqsize),
+ TPTAG_SIGCOMP_LIFETIME_REF(tpp->tpp_sigcomp_lifetime),
+ TPTAG_CONNECT_REF(connect),
+ TPTAG_SDWN_ERROR_REF(sdwn_error),
+ TPTAG_REUSE_REF(reusable),
+ TPTAG_COMPARTMENT_REF(cc),
+ TPTAG_STUN_SERVER_REF(stun_server),
+ TPTAG_TOS_REF(tpp->tpp_tos),
+ TAG_END());
+
+ ta_end(ta);
+
+ if (n == 0)
+ return 0;
+
+ if (tpp->tpp_idle > 0 && tpp->tpp_idle < 2000)
+ tpp->tpp_idle = 2000;
+ if (tpp->tpp_timeout < 1000)
+ tpp->tpp_timeout = 1000;
+ if (tpp->tpp_drop > 1000)
+ tpp->tpp_drop = 1000;
+ if (tpp->tpp_thrprqsize > 0)
+ tpp->tpp_thrprqsize = tpp0->tpp_thrprqsize;
+ if (tpp->tpp_sigcomp_lifetime != 0 && tpp->tpp_sigcomp_lifetime < 30)
+ tpp->tpp_sigcomp_lifetime = 30;
+ if (tpp->tpp_qsize >= 1000)
+ tpp->tpp_qsize = 1000;
+
+ /* Currently only primary UDP transport can *not* be connection oriented */
+ tpp->tpp_conn_orient = connect;
+ tpp->tpp_sdwn_error = sdwn_error;
+ self->tp_reusable = reusable;
+ tpp->tpp_stun_server = stun_server;
+
+ if (tport_is_secondary(self) &&
+ self->tp_params == self->tp_pri->pri_primary->tp_params) {
+ tpp0 = su_zalloc(self->tp_home, sizeof *tpp0); if (!tpp0) return -1;
+ }
+
+ memcpy(tpp0, tpp, sizeof *tpp);
+
+ return n;
+}
+
+extern tport_vtable_t const tport_udp_vtable;
+extern tport_vtable_t const tport_tcp_vtable;
+extern tport_vtable_t const tport_tls_vtable;
+extern tport_vtable_t const tport_sctp_vtable;
+extern tport_vtable_t const tport_udp_client_vtable;
+extern tport_vtable_t const tport_tcp_client_vtable;
+extern tport_vtable_t const tport_sctp_client_vtable;
+extern tport_vtable_t const tport_tls_client_vtable;
+extern tport_vtable_t const tport_http_connect_vtable;
+extern tport_vtable_t const tport_threadpool_vtable;
+
+#define TPORT_NUMBER_OF_TYPES 64
+
+tport_vtable_t const *tport_vtables[TPORT_NUMBER_OF_TYPES + 1] =
+{
+ &tport_http_connect_vtable,
+#if HAVE_TLS
+ &tport_tls_client_vtable,
+ &tport_tls_vtable,
+#endif
+#if HAVE_SCTP /* SCTP is broken */
+ &tport_sctp_client_vtable,
+ &tport_sctp_vtable,
+#endif
+ &tport_tcp_client_vtable,
+ &tport_tcp_vtable,
+ &tport_udp_client_vtable,
+ &tport_udp_vtable,
+#if 0
+ &tport_threadpool_vtable,
+#endif
+#if HAVE_SOFIA_STUN
+ &tport_stun_vtable,
+#endif
+};
+
+/** Register new transport vtable */
+int tport_register_type(tport_vtable_t const *vtp)
+{
+ int i;
+
+ for (i = TPORT_NUMBER_OF_TYPES; i >= 0; i--) {
+ if (tport_vtables[i] == NULL) {
+ tport_vtables[i] = vtp;
+ return 0;
+ }
+ }
+
+ su_seterrno(ENOMEM);
+ return -1;
+}
+
+/**Get a vtable for given protocol */
+tport_vtable_t const *tport_vtable_by_name(char const *protoname,
+ enum tport_via public)
+{
+ int i;
+
+ for (i = TPORT_NUMBER_OF_TYPES; i >= 0; i--) {
+ tport_vtable_t const *vtable = tport_vtables[i];
+
+ if (vtable == NULL)
+ continue;
+ if (vtable->vtp_public != public)
+ continue;
+ if (strcasecmp(vtable->vtp_name, protoname))
+ continue;
+
+ assert(vtable->vtp_pri_size >= sizeof (tport_primary_t));
+ assert(vtable->vtp_secondary_size >= sizeof (tport_t));
+
+ return vtable;
+ }
+
+ return NULL;
+}
+
+#if 0
+tport_set_f const *tport_set_methods[TPORT_NUMBER_OF_TYPES + 1] =
+ {
+ tport_server_bind_set,
+ tport_client_bind_set,
+ tport_threadpool_set,
+ tport_http_connect_set,
+#if HAVE_TLS
+ tport_tls_set,
+#endif
+ NULL
+ };
+
+int tport_bind_set(tport_master_t *mr,
+ tp_name_t const *tpn,
+ char const * const transports[],
+ tagi_t const *taglist,
+ tport_set_t **return_set,
+ int set_size)
+{
+ int i;
+
+ for (i = TPORT_NUMBER_OF_TYPES; i >= 0; i--) {
+ tport_set_f const *perhaps = tport_vtables[i];
+ int result;
+
+ if (perhaps == NULL)
+ continue;
+
+ result = perhaps(mr, tpn, transports, taglist, return_set, set_size);
+ if (result != 0)
+ return result;
+ }
+
+ return 0;
+}
+#endif
+
+/** Bind transport objects.
+ *
+ * @param self pointer to a transport object
+ * @param tpn desired transport address
+ * @param transports list of protocol names supported by stack
+ * @param tag,value,... tagged argument list
+ */
+int tport_tbind(tport_t *self,
+ tp_name_t const *tpn,
+ char const * const transports[],
+ tag_type_t tag, tag_value_t value, ...)
+{
+ ta_list ta;
+ int server = 1, retval, public = 0;
+ tp_name_t mytpn[1];
+ tport_master_t *mr;
+ char const *http_connect = NULL;
+
+ if (self == NULL || tport_is_secondary(self) ||
+ tpn == NULL || transports == NULL) {
+ su_seterrno(EINVAL);
+ return -1;
+ }
+
+ *mytpn = *tpn;
+
+ if (mytpn->tpn_ident == NULL)
+ mytpn->tpn_ident = self->tp_ident;
+
+ ta_start(ta, tag, value);
+
+ tl_gets(ta_args(ta),
+ TPTAG_SERVER_REF(server),
+ TPTAG_PUBLIC_REF(public),
+ TPTAG_IDENT_REF(mytpn->tpn_ident),
+ TPTAG_HTTP_CONNECT_REF(http_connect),
+ TAG_END());
+
+ mr = self->tp_master; assert(mr);
+
+ if (http_connect && public == 0)
+ public = tport_type_connect;
+
+ if (public && public != tport_type_stun)
+ server = 0;
+
+ if (server)
+ retval = tport_bind_server(mr, mytpn, transports, public, ta_args(ta));
+ else
+ retval = tport_bind_client(mr, mytpn, transports, public, ta_args(ta));
+
+ ta_end(ta);
+
+ return retval;
+}
+
+
+/** Bind primary transport objects used by a client-only application.
+ * @internal
+ */
+int tport_bind_client(tport_master_t *mr,
+ tp_name_t const *tpn,
+ char const * const transports[],
+ enum tport_via public,
+ tagi_t *tags)
+{
+ int i;
+ tport_primary_t *pri = NULL, **tbf;
+ tp_name_t tpn0[1] = {{ "*", "*", "*", "*", NULL, NULL }};
+ char const *why = "unknown";
+
+ tport_vtable_t const *vtable;
+
+ if (public == tport_type_local)
+ public = tport_type_client;
+
+ SU_DEBUG_5(("%s(%p) to " TPN_FORMAT "\n", __func__, mr, TPN_ARGS(tpn)));
+
+ memset(tpn0, 0, sizeof(tpn0));
+
+ for (tbf = &mr->mr_primaries; *tbf; tbf = &(*tbf)->pri_next)
+ ;
+
+ for (i = 0; transports[i]; i++) {
+ su_addrinfo_t hints[1];
+ char const *proto = transports[i];
+
+ if (strcmp(proto, tpn->tpn_proto) != 0 &&
+ strcmp(tpn->tpn_proto, tpn_any) != 0)
+ continue;
+
+ vtable = tport_vtable_by_name(proto, public);
+ if (!vtable)
+ continue;
+
+ /* Resolve protocol, skip unknown transport protocols */
+ if (getprotohints(hints, proto, AI_PASSIVE) < 0)
+ continue;
+
+ tpn0->tpn_proto = proto;
+ tpn0->tpn_comp = tpn->tpn_comp;
+ tpn0->tpn_ident = tpn->tpn_ident;
+
+ hints->ai_canonname = "*";
+
+ if (!(pri = tport_alloc_primary(mr, vtable, tpn0, hints, tags, &why)))
+ break;
+
+ pri->pri_public = tport_type_client; /* XXX */
+ }
+
+ if (!pri) {
+ SU_DEBUG_3(("tport_alloc_primary: %s failed\n", why));
+ tport_zap_primary(*tbf);
+ }
+
+ return pri ? 0 : -1;
+}
+
+/** Bind primary transport objects used by a server application. */
+int tport_bind_server(tport_master_t *mr,
+ tp_name_t const *tpn,
+ char const * const transports[],
+ enum tport_via public,
+ tagi_t *tags)
+{
+ char hostname[256];
+ char const *canon = NULL, *host, *service;
+ int error = 0, not_supported, family = 0;
+ tport_primary_t *pri = NULL, **tbf;
+ su_addrinfo_t *ai, *res = NULL;
+ unsigned port, port0, port1, old;
+ unsigned short step = 0;
+
+ bind6only_check(mr);
+
+ SU_DEBUG_5(("%s(%p) to " TPN_FORMAT "\n", __func__, mr, TPN_ARGS(tpn)));
+
+ if (tpn->tpn_host == NULL || strcmp(tpn->tpn_host, tpn_any) == 0) {
+ /* Use a local IP address */
+ host = NULL;
+ }
+#ifdef SU_HAVE_IN6
+ else if (tpn->tpn_host && tpn->tpn_host[0] == '[') {
+ /* Remove [] around IPv6 addresses. */
+ host = strcpy(hostname, tpn->tpn_host + 1);
+ hostname[strlen(hostname) - 1] = '\0';
+ }
+#endif
+ else
+ host = tpn->tpn_host;
+
+ if (tpn->tpn_port != NULL && strlen(tpn->tpn_port) > 0 &&
+ strcmp(tpn->tpn_port, tpn_any) != 0)
+ service = tpn->tpn_port;
+ else
+ service = "";
+
+ if (host && (strcmp(host, "0.0.0.0") == 0 || strcmp(host, "0") == 0))
+ host = NULL, family = AF_INET;
+#if SU_HAVE_IN6
+ else if (host && strcmp(host, "::") == 0)
+ host = NULL, family = AF_INET6;
+#endif
+
+ if (tpn->tpn_canon && strcmp(tpn->tpn_canon, tpn_any) &&
+ (host || tpn->tpn_canon != tpn->tpn_host))
+ canon = tpn->tpn_canon;
+
+ if (tport_server_addrinfo(mr, canon, family,
+ host, service, tpn->tpn_proto,
+ transports, &res) < 0)
+ return -1;
+
+ for (tbf = &mr->mr_primaries; *tbf; tbf = &(*tbf)->pri_next)
+ ;
+
+ port = port0 = port1 = ntohs(((su_sockaddr_t *)res->ai_addr)->su_port);
+ error = EPROTONOSUPPORT;
+
+ /*
+ * Loop until we can bind all the transports requested
+ * by the transport user to the same port.
+ */
+ for (;;) {
+ for (ai = res; ai; ai = ai->ai_next) {
+ tp_name_t tpname[1];
+ su_addrinfo_t ainfo[1];
+ su_sockaddr_t su[1];
+ tport_vtable_t const *vtable;
+
+ vtable = tport_vtable_by_name(ai->ai_canonname, public);
+ if (!vtable)
+ continue;
+
+ tport_addrinfo_copy(ainfo, su, sizeof su, ai);
+ ainfo->ai_canonname = (char *)canon;
+ su->su_port = htons(port);
+
+ memcpy(tpname, tpn, sizeof tpname);
+ tpname->tpn_canon = canon;
+ tpname->tpn_host = host;
+
+ SU_DEBUG_9(("%s(%p): calling tport_listen for %s\n",
+ __func__, mr, ai->ai_canonname));
+
+ pri = tport_listen(mr, vtable, tpname, ainfo, tags);
+ if (!pri) {
+ switch (error = su_errno()) {
+ case EADDRNOTAVAIL: /* Not our address */
+ case ENOPROTOOPT: /* Protocol not supported */
+ case ESOCKTNOSUPPORT: /* Socket type not supported */
+ continue;
+ default:
+ break;
+ }
+ break;
+ }
+
+ not_supported = 0;
+
+ if (port0 == 0 && port == 0) {
+ port = port1 = ntohs(su->su_port);
+ assert(public != tport_type_server || port != 0);
+ }
+ }
+
+ if (ai == NULL)
+ break;
+
+ while (*tbf)
+ tport_zap_primary(*tbf);
+
+ if (error != EADDRINUSE || port0 != 0 || port == 0)
+ break;
+
+ while (step == 0) {
+ /* step should be relative prime to 65536 - 1024 */
+ /* 65536 - 1024 = 7 * 3 * 3 * 1024 */
+ step = su_randint(1, 65535 - 1024 - 1) | 1;
+ if (step % 3 == 0)
+ step = (step + 2) % (65536 - 1024);
+ if (step % 7 == 0)
+ step = (step + 2) % (65536 - 1024);
+ }
+ old = port; port += step; if (port >= 65536) port -= (65536 - 1024);
+
+ if (port == port1) /* All ports in use! */
+ break;
+
+ SU_DEBUG_3(("%s(%p): cannot bind all transports to port %u, trying %u\n",
+ __func__, mr, old, port));
+ }
+
+ tport_freeaddrinfo(res);
+
+ if (!*tbf) {
+ su_seterrno(error);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/** Check if we can bind to IPv6 separately from IPv4 bind */
+static
+int bind6only_check(tport_master_t *mr)
+{
+ int retval = 0;
+#if SU_HAVE_IN6
+ su_sockaddr_t su[1], su4[1];
+ socklen_t sulen, su4len;
+ int s6, s4;
+
+ if (mr->mr_boundserver)
+ return 0;
+
+ s4 = su_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ s6 = su_socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+
+ memset(su, 0, sizeof *su);
+ su->su_len = sulen = (sizeof su->su_sin6);
+ su->su_family = AF_INET6;
+
+ memset(su4, 0, sizeof *su4);
+ su4->su_len = su4len = (sizeof su->su_sin);
+ su4->su_family = AF_INET;
+
+ if (bind(s6, &su->su_sa, sulen) < 0)
+ ;
+ else if (getsockname(s6, &su->su_sa, &sulen) < 0)
+ ;
+ else if ((su4->su_port = su->su_port) != 0 &&
+ bind(s4, &su4->su_sa, su4len) == 0)
+ retval = 1;
+
+ su_close(s6), su_close(s4);
+
+ mr->mr_bindv6only = retval;
+ mr->mr_boundserver = 1;
+#endif
+
+ return retval;
+}
+
+/* Number of supported transports */
+#define TPORT_N (8)
+
+/** Return list of addrinfo structures matching to
+ * canon/host/service/protocol
+ */
+static
+int tport_server_addrinfo(tport_master_t *mr,
+ char const *canon,
+ int family,
+ char const *host,
+ char const *service,
+ char const *protocol,
+ char const * const transports[],
+ su_addrinfo_t **return_addrinfo)
+{
+ int i, N;
+ su_addrinfo_t hints[TPORT_N + 1];
+
+ *return_addrinfo = NULL;
+
+ /*
+ * Resolve all the transports requested by the protocol
+ */
+ for (i = 0, N = 0; transports[i] && N < TPORT_N; i++) {
+ su_addrinfo_t *ai = &hints[N];
+
+ if (strcasecmp(transports[i], protocol) != 0 &&
+ strcmp(protocol, tpn_any) != 0)
+ continue;
+
+ /* Resolve protocol, skip unknown transport protocols. */
+ if (getprotohints(ai, transports[i], AI_PASSIVE) < 0)
+ continue;
+
+ ai->ai_family = family;
+ ai->ai_next = &hints[++N];
+ }
+
+ if (N == 0)
+ return su_seterrno(EPROTONOSUPPORT);
+ if (transports[i] /* Too many protocols */)
+ return su_seterrno(ENOMEM);
+
+ hints[N - 1].ai_next = NULL;
+
+ if (host) {
+ int error = tport_getaddrinfo(host, service, hints, return_addrinfo);
+ if (error || !*return_addrinfo) {
+ SU_DEBUG_3(("%s(%p): su_getaddrinfo(%s, %s) for %s: %s\n",
+ __func__, mr, host ? host : "\"\"", service, protocol,
+ su_gai_strerror(error)));
+ return su_seterrno(error != EAI_MEMORY ? ENOENT : ENOMEM);
+ }
+ return 0;
+ }
+
+ return tport_get_local_addrinfo(mr, service, hints, return_addrinfo);
+}
+
+/** Convert localinfo into addrinfo */
+static
+int
+tport_get_local_addrinfo(tport_master_t *mr,
+ char const *port,
+ su_addrinfo_t const *hints,
+ su_addrinfo_t **return_ai)
+{
+ int error, family;
+ su_localinfo_t lihints[1] = {{ 0 }};
+ su_localinfo_t *li, *li_result;
+ su_addrinfo_t const *h;
+ su_addrinfo_t *ai, **prev;
+ su_sockaddr_t *su;
+ unsigned long lport = 0;
+ char *rest;
+
+ prev = return_ai, *prev = NULL;
+
+ if (port) {
+ lport = strtoul(port, &rest, 10);
+ if (lport >= 65536) {
+ su_seterrno(EINVAL);
+ return -1;
+ }
+ }
+
+ family = hints->ai_family;
+
+ for (h = hints->ai_next; h && family; h = h->ai_next)
+ if (h->ai_family != family)
+ family = 0;
+
+ lihints->li_flags = 0;
+ lihints->li_family = family;
+ lihints->li_scope = LI_SCOPE_GLOBAL | LI_SCOPE_SITE | LI_SCOPE_HOST;
+
+ error = su_getlocalinfo(lihints, &li_result);
+ if (error) {
+#if SU_HAVE_IN6
+ SU_DEBUG_3(("%s(%p): su_getlocalinfo() for %s address: %s\n",
+ __func__, mr,
+ family == AF_INET6 ? "ip6"
+ : family == AF_INET ? "ip4" : "ip",
+ su_gli_strerror(error)));
+#else
+ SU_DEBUG_3(("%s(%p): su_getlocalinfo() for %s address: %s\n",
+ __func__, mr,
+ family == AF_INET ? "ip4" : "ip",
+ su_gli_strerror(error)));
+#endif
+ su_seterrno(ENOENT);
+ return -1;
+ }
+
+ for (li = li_result; li; li = li->li_next) {
+ for (h = hints; h; h = h->ai_next) {
+ if (h->ai_family && h->ai_family != li->li_family)
+ continue;
+
+ ai = calloc(1, sizeof *ai + li->li_addrlen);
+ if (ai == NULL)
+ break;
+
+ *prev = ai, prev = &ai->ai_next;
+
+ ai->ai_flags = AI_PASSIVE | TP_AI_ANY;
+ ai->ai_family = li->li_family;
+ ai->ai_socktype = h->ai_socktype;
+ ai->ai_protocol = h->ai_protocol;
+ ai->ai_canonname = h->ai_canonname;
+ ai->ai_addr = memcpy(ai + 1, li->li_addr,
+ ai->ai_addrlen = li->li_addrlen);
+ su = (void *)ai->ai_addr;
+ su->su_port = htons(lport);
+ }
+ }
+
+ su_freelocalinfo(li_result);
+
+ if (li) {
+ tport_freeaddrinfo(*return_ai);
+ su_seterrno(ENOMEM);
+ return -1;
+ }
+
+ if (*return_ai == NULL) {
+ su_seterrno(ENOENT);
+ return -1;
+ }
+
+ return 0;
+}
+
+static inline su_addrinfo_t *get_next_addrinfo(su_addrinfo_t **all);
+
+/** Translate address and service.
+ *
+ * This is a getaddrinfo() supporting multiple hints in a list.
+ */
+int tport_getaddrinfo(char const *node, char const *service,
+ su_addrinfo_t const *hints,
+ su_addrinfo_t **res)
+{
+ su_addrinfo_t const *h0;
+ su_addrinfo_t *tbf, **prev;
+ int error = EAI_SOCKTYPE;
+ int i, N;
+ su_addrinfo_t *all[TPORT_N + 1]; /* Lists for all supported transports */
+ su_addrinfo_t *results[TPORT_N + 1];
+ void *addr;
+ int addrlen;
+
+ *res = NULL;
+
+ for (N = 0, h0 = hints; h0; h0 = h0->ai_next) {
+ su_addrinfo_t h[1];
+
+ *h = *h0, h->ai_next = NULL, h->ai_canonname = NULL;
+
+ error = su_getaddrinfo(node, service, h, &all[N]);
+ results[N] = all[N];
+ if (error == EAI_SOCKTYPE) {
+ SU_DEBUG_7(("%s(): su_getaddrinfo(%s, %s) for %s: %s\n",
+ __func__, node ? node : "\"\"", service,
+ h0->ai_canonname, su_gai_strerror(error)));
+ continue;
+ }
+
+ if (error || !all[N])
+ break;
+ N++;
+ }
+
+ if (h0)
+ for (i = 0; i < N; i++)
+ su_freeaddrinfo(all[i]);
+ if (error)
+ return error;
+
+ /* Combine all the valid addrinfo structures to a single list */
+ prev = &tbf, tbf = NULL;
+
+ for (;;) {
+ su_addrinfo_t *ai = NULL, *ai0;
+
+ for (i = 0, h0 = hints; i < N; i++, h0 = h0->ai_next) {
+ if ((ai = get_next_addrinfo(&results[i])))
+ break;
+ }
+ if (i == N)
+ break;
+
+ assert(ai);
+ addr = SU_ADDR((su_sockaddr_t *)ai->ai_addr);
+ addrlen = SU_ADDRLEN((su_sockaddr_t *)ai->ai_addr);
+
+ /* Copy all the addrinfo structures with same address to the list */
+ for (; i < N; i++, h0 = h0->ai_next) {
+ while ((ai0 = get_next_addrinfo(&results[i]))) {
+ void *a = SU_ADDR((su_sockaddr_t *)ai0->ai_addr);
+
+ if (memcmp(addr, a, addrlen)) /* Different address */
+ break;
+
+ results[i] = ai0->ai_next;
+
+ ai = calloc(1, sizeof *ai + ai0->ai_addrlen);
+ if (ai == NULL)
+ goto error;
+ *prev = memcpy(ai, ai0, sizeof *ai); prev = &ai->ai_next; *prev = NULL;
+ ai->ai_addr = memcpy(ai + 1, ai0->ai_addr, ai0->ai_addrlen);
+ ai->ai_canonname = h0->ai_canonname;
+ }
+ }
+ }
+
+ for (i = 0; i < N; i++)
+ su_freeaddrinfo(all[i]);
+
+ *res = tbf;
+ return 0;
+
+ error:
+ for (i = 0; i < N; i++)
+ su_freeaddrinfo(all[i]);
+ tport_freeaddrinfo(tbf);
+ return EAI_MEMORY;
+}
+
+static inline
+su_addrinfo_t *get_next_addrinfo(su_addrinfo_t **all)
+{
+ su_addrinfo_t *ai;
+
+ while ((ai = *all)) {
+ if (ai->ai_family == AF_INET)
+ return ai;
+#if SU_HAVE_IN6
+ if (ai->ai_family == AF_INET6)
+ return ai;
+#endif
+ *all = ai->ai_next;
+ }
+ return ai;
+}
+
+static
+void tport_freeaddrinfo(su_addrinfo_t *ai)
+{
+ su_addrinfo_t *ai_next;
+
+ while (ai) {
+ ai_next = ai->ai_next;
+ free(ai);
+ ai = ai_next;
+ }
+}
+
+static
+int tport_addrinfo_copy(su_addrinfo_t *dst, void *addr, socklen_t addrlen,
+ su_addrinfo_t const *src)
+{
+ if (addrlen < src->ai_addrlen)
+ return -1;
+
+ memcpy(dst, src, sizeof *dst);
+
+ if (src->ai_addrlen < addrlen)
+ memset(addr, 0, addrlen);
+
+ dst->ai_addr = memcpy(addr, src->ai_addr, src->ai_addrlen);
+ dst->ai_next = NULL;
+
+ return 0;
+}
+
+/** Close a transport.
+ *
+ * The function tport_close() closes a socket associated with a transport
+ * object.
+ */
+void tport_close(tport_t *self)
+{
+ SU_DEBUG_5(("%s(%p): " TPN_FORMAT "\n", "tport_close", self,
+ TPN_ARGS(self->tp_name)));
+
+ self->tp_closed = 1;
+ self->tp_send_close = 3;
+ self->tp_recv_close = 3;
+
+ if (self->tp_params->tpp_sdwn_error && self->tp_pused)
+ tport_error_report(self, -1, NULL);
+
+ if (self->tp_pri->pri_vtable->vtp_shutdown)
+ self->tp_pri->pri_vtable->vtp_shutdown(self, 2);
+ else if (self->tp_socket != -1)
+ shutdown(self->tp_socket, 2);
+
+ if (self->tp_index)
+ su_root_deregister(self->tp_master->mr_root, self->tp_index);
+ self->tp_index = 0;
+#if SU_HAVE_BSDSOCK
+ if (self->tp_socket != -1)
+ su_close(self->tp_socket);
+ self->tp_socket = -1;
+#endif
+
+ /* Zap the queued messages */
+ if (self->tp_queue) {
+ unsigned short i, N = self->tp_params->tpp_qsize;
+ for (i = 0; i < N; i++) {
+ if (self->tp_queue[i])
+ msg_ref_destroy(self->tp_queue[i]), self->tp_queue[i] = NULL;
+ }
+ }
+
+ self->tp_index = 0;
+ self->tp_events = 0;
+}
+
+/** Shutdown a transport.
+ *
+ * The tport_shutdown() shuts down a full-duplex transport connection
+ * partially or completely. If @a how is 0, the further incoming data is
+ * shut down. If @a how is 1, further outgoing data is shut down. If @a how
+ * is 2, both incoming and outgoing traffic is shut down.
+ *
+ */
+int tport_shutdown(tport_t *self, int how)
+{
+ if (!tport_is_secondary(self))
+ return -1;
+
+ SU_DEBUG_7(("%s(%p, %d)\n", "tport_shutdown", self, how));
+
+ if (!tport_is_tcp(self) ||
+ how < 0 ||
+ (how == 0 && self->tp_send_close) ||
+ (how == 1 && self->tp_recv_close > 1) ||
+ how >= 2) {
+ tport_close(self);
+ return 1;
+ }
+
+ if (self->tp_pri->pri_vtable->vtp_shutdown)
+ self->tp_pri->pri_vtable->vtp_shutdown(self, how);
+ else
+ shutdown(self->tp_socket, how);
+
+ if (how == 0) {
+ self->tp_recv_close = 2;
+ tport_set_events(self, 0, SU_WAIT_IN);
+ if (self->tp_params->tpp_sdwn_error && self->tp_pused)
+ tport_error_report(self, -1, NULL);
+ }
+ else if (how == 1) {
+ self->tp_send_close = 2;
+ tport_set_events(self, 0, SU_WAIT_OUT);
+ if (self->tp_queue && self->tp_queue[self->tp_qhead]) {
+ unsigned short i, N = self->tp_params->tpp_qsize;
+ for (i = 0; i < N; i++) {
+ if (self->tp_queue[i]) {
+ tport_pending_errmsg(self, self->tp_queue[i], EPIPE);
+ msg_ref_destroy(self->tp_queue[i]), self->tp_queue[i] = NULL;
+ }
+ }
+ }
+ }
+
+
+ return 0;
+}
+
+static inline
+unsigned long tport_now(void)
+{
+ return su_now().tv_sec;
+}
+
+/** Transport timer function. */
+static
+void tport_tick(su_root_magic_t *magic, su_timer_t *t, tport_master_t *mr)
+{
+ tport_primary_t *dad;
+ tport_t *tp, *tp_next;
+ su_time_t now = su_now();
+ int ts = (int)su_time_ms(now);
+
+ /* Go through all primary transports */
+ for (dad = mr->mr_primaries; dad; dad = dad->pri_next) {
+ if (dad->pri_primary->tp_addrinfo->ai_protocol == IPPROTO_SCTP) {
+ /* Go through all SCTP connections */
+
+ tp = dad->pri_secondary;
+
+ for (tp = tprb_first(tp); tp; tp = tp_next) {
+ tp_next = tprb_succ(tp);
+ if (tp->tp_queue && tp->tp_queue[tp->tp_qhead]) {
+ SU_DEBUG_9(("tport_tick(%p) - trying to send to %s/%s:%s\n",
+ tp, tp->tp_protoname, tp->tp_host, tp->tp_port));
+ tport_send_queue(tp);
+ }
+ }
+ }
+
+ /* Go through all secondary transports with incomplete messages */
+ for (tp = tprb_first(dad->pri_secondary); tp; tp = tp_next) {
+ msg_t *msg = tp->tp_msg;
+ int closed;
+
+ if (msg &&
+ tp->tp_params->tpp_timeout < INT_MAX &&
+ (int)tp->tp_params->tpp_timeout < ts - (int)tp->tp_time &&
+ !msg_is_streaming(msg)) {
+ SU_DEBUG_5(("tport_tick(%p): incomplete message idle for %d ms\n",
+ tp, ts - (int)tp->tp_time));
+ msg_set_streaming(msg, 0);
+ msg_set_flags(msg, MSG_FLG_ERROR | MSG_FLG_TRUNC | MSG_FLG_TIMEOUT);
+ tport_deliver(tp, msg, NULL, NULL, now);
+ tp->tp_msg = NULL;
+ }
+
+ tp_next = tprb_succ(tp);
+
+ if (tp->tp_refs)
+ continue;
+
+ closed = tport_is_closed(tp);
+
+ if (!closed &&
+ !(tp->tp_params->tpp_idle > 0
+ && (int)tp->tp_params->tpp_idle < ts - (int)tp->tp_time)) {
+ continue;
+ }
+
+ if (closed) {
+ SU_DEBUG_5(("tport_tick(%p): closed, zapping\n", tp));
+ } else {
+ SU_DEBUG_5(("tport_tick(%p): unused for %d ms, closing and zapping\n",
+ tp, ts - (int)tp->tp_time));
+ if (!tport_is_closed(tp))
+ tport_close(tp);
+ }
+
+ tport_zap_secondary(tp);
+ }
+ }
+
+ su_timer_set(t, tport_tick, mr);
+}
+
+/** Flush idle connections. */
+int tport_flush(tport_t *tp)
+{
+ tport_t *tp_next;
+
+ if (tp == NULL)
+ return -1;
+
+ /* Go through all secondary transports, zap idle ones */
+ for (tp = tprb_first(tp->tp_pri->pri_secondary); tp; tp = tp_next) {
+ tp_next = tprb_succ(tp);
+
+ if (tp->tp_refs != 0)
+ continue;
+
+ SU_DEBUG_1(("tport_flush(%p): %szapping\n",
+ tp, tport_is_closed(tp) ? "" : "closing and "));
+ if (!tport_is_closed(tp))
+ tport_close(tp);
+ tport_zap_secondary(tp);
+ }
+
+ return 0;
+}
+
+/**Convert sockaddr_t to a transport name.
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error
+ */
+int tport_convert_addr(su_home_t *home,
+ tp_name_t *tpn,
+ char const *protoname,
+ char const *canon,
+ su_sockaddr_t const *su)
+{
+ tp_name_t name[1] = {{ NULL }};
+ char const *host;
+ char buf[TPORT_HOSTPORTSIZE];
+ char port[8];
+ size_t canonlen = canon ? strlen(canon) : 0;
+
+ if (su == NULL)
+ host = "*";
+ else if (!SU_SOCKADDR_INADDR_ANY(su))
+ host = tport_hostport(buf, sizeof(buf), su, 0);
+ else if (canonlen && su->su_family == AF_INET &&
+ strspn(canon, "0123456789.") == canonlen)
+ host = canon;
+#if SU_HAVE_IN6
+ else if (canonlen && su->su_family == AF_INET6 &&
+ strspn(canon, "0123456789abcdefABCDEF:.") == canonlen)
+ host = canon;
+#endif
+ else
+ host = localipname(su->su_family, buf, sizeof(buf));
+
+ if (host == NULL)
+ return -1;
+
+ if (su == NULL)
+ strcpy(port, "*");
+ else
+ snprintf(port, sizeof(port), "%u", ntohs(su->su_port));
+
+ name->tpn_proto = protoname;
+ name->tpn_host = host;
+ name->tpn_canon = canon ? canon : host;
+ name->tpn_port = port;
+
+ return tport_name_dup(home, tpn, name);
+}
+
+/** Set transport object name. @internal
+ */
+static
+int tport_setname(tport_t *self,
+ char const *protoname,
+ su_addrinfo_t const *ai,
+ char const *canon)
+{
+ su_addrinfo_t *selfai = self->tp_addrinfo;
+
+ if (tport_convert_addr(self->tp_home, self->tp_name,
+ protoname, canon,
+ (su_sockaddr_t *)ai->ai_addr) < 0)
+ return -1;
+
+ if (tport_is_secondary(self))
+ self->tp_ident = self->tp_pri->pri_primary->tp_ident;
+
+ selfai->ai_flags = ai->ai_flags & TP_AI_MASK;
+
+ selfai->ai_family = ai->ai_family;
+ selfai->ai_socktype = ai->ai_socktype;
+ selfai->ai_protocol = ai->ai_protocol;
+ selfai->ai_canonname = (char *)self->tp_name->tpn_canon;
+
+ if (ai->ai_addr) {
+ assert(ai->ai_family), assert(ai->ai_socktype), assert(ai->ai_protocol);
+ memcpy(self->tp_addr, ai->ai_addr, selfai->ai_addrlen = ai->ai_addrlen);
+ }
+
+ return 0;
+}
+
+/**Resolve protocol name.
+ *
+ * Convert a protocol name to IP protocol number and socket type used by
+ * su_getaddrinfo().
+ *
+ * @param hints hints with the protocol number and socktype [OUT]
+ * @param proto protocol name [IN]
+ * @param flags hint flags
+ */
+static
+int getprotohints(su_addrinfo_t *hints,
+ char const *proto,
+ int flags)
+{
+ memset(hints, 0, sizeof *hints);
+
+ hints->ai_flags = flags;
+ hints->ai_canonname = (char *)proto;
+
+#if HAVE_TLS
+ if (strcasecmp(proto, "tls") == 0)
+ proto = "tcp";
+#endif
+
+#if HAVE_SCTP
+ if (strcasecmp(proto, "sctp") == 0) {
+ hints->ai_protocol = IPPROTO_SCTP;
+ hints->ai_socktype = SOCK_STREAM;
+ return 0;
+ }
+#endif
+
+ if (strcasecmp(proto, "udp") == 0) {
+ hints->ai_protocol = IPPROTO_UDP;
+ hints->ai_socktype = SOCK_DGRAM;
+ return 0;
+ }
+
+ if (strcasecmp(proto, "tcp") == 0) {
+ hints->ai_protocol = IPPROTO_TCP;
+ hints->ai_socktype = SOCK_STREAM;
+ return 0;
+ }
+
+ return -1;
+}
+
+/** Get local IP.
+ *
+ * Get primary local IP address in URI format (IPv6 address will be
+ * []-quoted).
+ */
+static
+char *localipname(int pf, char *buf, size_t bufsiz)
+{
+ su_localinfo_t *li = NULL, hints[1] = {{ LI_NUMERIC | LI_CANONNAME }};
+ size_t n;
+ int error;
+
+ hints->li_family = pf;
+
+#if SU_HAVE_IN6
+ if (pf == AF_INET6) {
+ /* Link-local addresses are not usable on IPv6 */
+ hints->li_scope = LI_SCOPE_GLOBAL | LI_SCOPE_SITE /* | LI_SCOPE_HOST */;
+ }
+#endif
+
+ if ((error = su_getlocalinfo(hints, &li))) {
+#if SU_HAVE_IN6
+ if (error == ELI_NOADDRESS && pf == AF_INET6) {
+ hints->li_family = AF_INET;
+ error = su_getlocalinfo(hints, &li);
+ if (error == ELI_NOADDRESS) {
+ hints->li_family = AF_INET6; hints->li_scope |= LI_SCOPE_HOST;
+ error = su_getlocalinfo(hints, &li);
+ }
+ if (error == ELI_NOADDRESS) {
+ hints->li_family = AF_INET;
+ error = su_getlocalinfo(hints, &li);
+ }
+ }
+#endif
+ if (error) {
+ SU_DEBUG_1(("tport: su_getlocalinfo: %s\n", su_gli_strerror(error)));
+ return NULL;
+ }
+ }
+
+ assert(li); assert(li->li_canonname);
+
+ n = strlen(li->li_canonname);
+
+ if (li->li_family == AF_INET) {
+ if (n >= bufsiz)
+ return NULL;
+
+ memcpy(buf, li->li_canonname, n + 1);
+ }
+ else {
+ if (n + 2 >= bufsiz)
+ return NULL;
+
+ memcpy(buf + 1, li->li_canonname, n);
+ buf[0] = '['; buf[++n] = ']'; buf[++n] = '\0';
+ }
+
+ su_freelocalinfo(li);
+
+ return buf;
+}
+
+/** Process errors from transport. */
+void tport_error_report(tport_t *self, int errcode,
+ su_sockaddr_t const *addr)
+{
+ char const *errmsg;
+
+ if (errcode == 0)
+ return;
+ else if (errcode > 0)
+ errmsg = su_strerror(errcode);
+ else
+ errcode = 0, errmsg = "stream closed";
+
+ if (addr && addr->su_family == AF_UNSPEC)
+ addr = NULL;
+
+ /* Mark this connection as unusable */
+ if (errcode > 0 && tport_has_connection(self))
+ self->tp_reusable = 0;
+
+ if (addr == NULL && tport_is_connection_oriented(self))
+ addr = self->tp_addr;
+
+ /* Report error */
+ if (addr && tport_pending_error(self, addr, errcode))
+ ;
+ else if (self->tp_master->mr_tpac->tpac_error) {
+ char *dstname = NULL;
+ char hp[TPORT_HOSTPORTSIZE];
+
+ if (addr)
+ dstname = tport_hostport(hp, sizeof hp, addr, 1);
+
+ STACK_ERROR(self, errcode, dstname);
+ }
+ else {
+ if (tport_is_primary(self))
+ SU_DEBUG_3(("%s(%p): %s (with %s)\n", __func__, self,
+ errmsg, self->tp_protoname));
+ else
+ SU_DEBUG_3(("%s(%p): %s (with %s/%s:%s)\n", __func__, self,
+ errmsg, self->tp_protoname, self->tp_host, self->tp_port));
+ }
+
+ /* Close connection */
+ if (!self->tp_closed && errcode > 0 && tport_has_connection(self))
+ tport_close(self);
+}
+
+/** Accept a new connection.
+ *
+ * The function tport_accept() accepts a new connection and creates a
+ * secondary transport object for the new socket.
+ */
+int tport_accept(tport_primary_t *pri, int events)
+{
+ tport_t *self;
+ su_addrinfo_t ai[1];
+ su_sockaddr_t su[1];
+ socklen_t sulen = sizeof su;
+ su_socket_t s = INVALID_SOCKET, l = pri->pri_primary->tp_socket;
+ char const *reason = "accept";
+
+ if (events & SU_WAIT_ERR)
+ tport_error_event(pri->pri_primary);
+
+ if (!(events & SU_WAIT_ACCEPT))
+ return 0;
+
+ memcpy(ai, pri->pri_primary->tp_addrinfo, sizeof ai);
+ ai->ai_canonname = NULL;
+
+ s = accept(l, &su->su_sa, &sulen);
+
+ if (s < 0) {
+ tport_error_report(pri->pri_primary, su_errno(), NULL);
+ return 0;
+ }
+
+ ai->ai_addr = &su->su_sa, ai->ai_addrlen = sulen;
+
+ /* Alloc a new transport object, then register socket events with it */
+ self = tport_alloc_secondary(pri, s, 1, &reason);
+
+ if (self) {
+ int i;
+ su_root_t *root = self->tp_master->mr_root;
+ su_wakeup_f wakeup = tport_wakeup;
+ int events = SU_WAIT_IN|SU_WAIT_ERR|SU_WAIT_HUP;
+ su_wait_t wait[1] = { SU_WAIT_INIT };
+
+ SU_CANONIZE_SOCKADDR(su);
+
+ if (/* Create wait object with appropriate events. */
+ su_wait_create(wait, s, events) != -1
+ /* Register socket to root */
+ &&
+ (i = su_root_register(root, wait, wakeup, self, 0)) != -1) {
+
+ self->tp_index = i;
+ self->tp_conn_orient = 1;
+ self->tp_is_connected = 1;
+ self->tp_events = events;
+
+ if (tport_setname(self, pri->pri_protoname, ai, NULL) != -1) {
+ SU_DEBUG_5(("%s(%p): new connection from " TPN_FORMAT "\n",
+ __func__, self, TPN_ARGS(self->tp_name)));
+
+ tprb_append(&pri->pri_secondary, self);
+
+ /* Return succesfully */
+ return 0;
+ }
+ }
+ else
+ su_wait_destroy(wait);
+
+ /* Failure: shutdown socket, */
+ tport_close(self);
+ tport_zap_secondary(self);
+ }
+
+ /* XXX - report error ? */
+
+ return 0;
+}
+
+/** Allocate a new message object */
+msg_t *tport_msg_alloc(tport_t const *self, usize_t size)
+{
+ if (self) {
+ tport_master_t *mr = self->tp_master;
+ msg_t *msg = mr->mr_tpac->tpac_alloc(mr->mr_stack, mr->mr_log,
+ NULL, size, self, NULL);
+ if (msg) {
+ su_addrinfo_t *mai = msg_addrinfo(msg);
+ su_addrinfo_t const *tai = self->tp_addrinfo;
+
+ mai->ai_family = tai->ai_family;
+ mai->ai_protocol = tai->ai_protocol;
+ mai->ai_socktype = tai->ai_socktype;
+ }
+
+ return msg;
+ }
+ else {
+ return NULL;
+ }
+}
+
+/** Process events for socket waiting to be connected
+ */
+static int tport_connected(su_root_magic_t *magic, su_wait_t *w, tport_t *self)
+{
+ int events = su_wait_events(w, self->tp_socket);
+ tport_master_t *mr = self->tp_master;
+ su_wait_t wait[1] = { SU_WAIT_INIT };
+
+ int error;
+
+ SU_DEBUG_7(("tport_connected(%p): events%s%s\n", self,
+ events & SU_WAIT_CONNECT ? " CONNECTED" : "",
+ events & SU_WAIT_ERR ? " ERR" : ""));
+
+#if HAVE_POLL
+ assert(w->fd == self->tp_socket);
+#endif
+
+ if (events & SU_WAIT_ERR)
+ tport_error_event(self);
+
+ if (!(events & SU_WAIT_CONNECT) || self->tp_closed) {
+ return 0;
+ }
+
+ error = su_soerror(self->tp_socket);
+ if (error) {
+ tport_error_report(self, error, NULL);
+ return 0;
+ }
+
+ self->tp_is_connected = 1;
+
+ su_root_deregister(mr->mr_root, self->tp_index);
+ self->tp_index = -1;
+ self->tp_events = SU_WAIT_IN | SU_WAIT_ERR;
+ if (su_wait_create(wait, self->tp_socket, self->tp_events) == -1 ||
+ (self->tp_index = su_root_register(mr->mr_root,
+ wait, tport_wakeup, self, 0))
+ == -1) {
+ tport_close(self);
+ }
+ else if (self->tp_queue && self->tp_queue[self->tp_qhead]) {
+ tport_send_event(self);
+ }
+
+ return 0;
+}
+
+/** Process events for primary socket */
+static int tport_wakeup_pri(su_root_magic_t *m, su_wait_t *w, tport_t *self)
+{
+ tport_primary_t *pri = self->tp_pri;
+ int events = su_wait_events(w, self->tp_socket);
+
+#if HAVE_POLL
+ assert(w->fd == self->tp_socket);
+#endif
+
+ SU_DEBUG_7(("%s(%p): events%s%s%s%s%s%s\n",
+ "tport_wakeup_pri", self,
+ events & SU_WAIT_IN ? " IN" : "",
+ SU_WAIT_ACCEPT != SU_WAIT_IN &&
+ (events & SU_WAIT_ACCEPT) ? " ACCEPT" : "",
+ events & SU_WAIT_OUT ? " OUT" : "",
+ events & SU_WAIT_HUP ? " HUP" : "",
+ events & SU_WAIT_ERR ? " ERR" : "",
+ self->tp_closed ? " (closed)" : ""));
+
+
+ if (pri->pri_vtable->vtp_wakeup_pri)
+ return pri->pri_vtable->vtp_wakeup_pri(pri, events);
+ else
+ return tport_base_wakeup(self, events);
+}
+
+/** Process events for connected socket */
+static int tport_wakeup(su_root_magic_t *magic, su_wait_t *w, tport_t *self)
+{
+ int events = su_wait_events(w, self->tp_socket);
+
+#if HAVE_POLL
+ assert(w->fd == self->tp_socket);
+#endif
+
+ SU_DEBUG_7(("%s(%p): events%s%s%s%s%s\n",
+ "tport_wakeup", self,
+ events & SU_WAIT_IN ? " IN" : "",
+ events & SU_WAIT_OUT ? " OUT" : "",
+ events & SU_WAIT_HUP ? " HUP" : "",
+ events & SU_WAIT_ERR ? " ERR" : "",
+ self->tp_closed ? " (closed)" : ""));
+
+ if (self->tp_pri->pri_vtable->vtp_wakeup)
+ return self->tp_pri->pri_vtable->vtp_wakeup(self, events);
+ else
+ return tport_base_wakeup(self, events);
+}
+
+static int tport_base_wakeup(tport_t *self, int events)
+{
+ int error = 0;
+
+ if (events & SU_WAIT_ERR)
+ error = tport_error_event(self);
+
+ if ((events & SU_WAIT_OUT) && !self->tp_closed)
+ tport_send_event(self);
+
+ if ((events & SU_WAIT_IN) && !self->tp_closed)
+ tport_recv_event(self);
+
+ if ((events & SU_WAIT_HUP) && !self->tp_closed)
+ tport_hup_event(self);
+
+ if (error)
+ tport_error_report(self, error, NULL);
+
+ return 0;
+}
+
+/** Stop reading from socket until tport_continue() is called. */
+int tport_stall(tport_t *self)
+{
+ return tport_set_events(self, 0, SU_WAIT_IN);
+}
+
+/** Continue reading from socket. */
+int tport_continue(tport_t *self)
+{
+ if (self == NULL || self->tp_recv_close)
+ return -1;
+ return tport_set_events(self, SU_WAIT_IN, 0);
+}
+
+/** Process "hangup" event.
+ *
+ */
+void tport_hup_event(tport_t *self)
+{
+ SU_DEBUG_7(("%s(%p)\n", __func__, self));
+
+ if (self->tp_msg) {
+ su_time_t now = su_now();
+ msg_recv_commit(self->tp_msg, 0, 1);
+ tport_parse(self, 1, now);
+ }
+
+ /* End of stream */
+ tport_shutdown(self, 0);
+}
+
+/** Receive data available on the socket.
+ *
+ * @retval -1 error
+ * @retval 0 end-of-stream
+ * @retval 1 normal receive
+ * @retval 2 incomplete recv, recv again
+ * @retval 3 STUN keepalive, ignore
+ */
+static inline
+int tport_recv_data(tport_t *self)
+{
+ return self->tp_pri->pri_vtable->vtp_recv(self);
+}
+
+/** Process "ready to receive" event.
+ *
+ */
+void tport_recv_event(tport_t *self)
+{
+ su_time_t now;
+ int again;
+
+ SU_DEBUG_7(("%s(%p)\n", "tport_recv_event", self));
+
+ do {
+ now = su_now();
+
+ /* Receive data from socket */
+ again = tport_recv_data(self);
+
+ self->tp_time = su_time_ms(now);
+
+ if (again == 3) /* STUN keepalive */
+ return;
+
+ if (again < 0) {
+ int error = su_errno();
+
+ if (!su_is_blocking(error)) {
+ tport_error_report(self, error, NULL);
+ /* Failure: shutdown socket */
+ if (tport_has_connection(self))
+ tport_close(self);
+ return;
+ }
+ else {
+ SU_DEBUG_3(("%s: recvfrom(): %s (%d)\n", __func__,
+ su_strerror(EAGAIN), EAGAIN));
+ }
+ }
+
+ if (again >= 0)
+ tport_parse(self, !again, now);
+ }
+ while (again > 1);
+
+ if (again == 0 && !tport_is_dgram(self)) {
+ /* End of stream */
+ if (!self->tp_closed) {
+ /* Don't shutdown completely if there are queued messages */
+ tport_shutdown(self, self->tp_queue && self->tp_queue[self->tp_qhead] ? 0 : 2);
+ }
+ }
+}
+
+/*
+ * Parse the data and feed complete messages to the stack
+ */
+static void tport_parse(tport_t *self, int complete, su_time_t now)
+{
+ msg_t *msg, *next = NULL;
+ int n, streaming, stall = 0;
+
+ for (msg = self->tp_msg; msg; msg = next) {
+ n = msg_extract(msg); /* Parse message */
+
+ streaming = 0;
+
+ if (n == 0) {
+ if (complete)
+ msg_mark_as_complete(msg, MSG_FLG_ERROR), n = -1;
+ else if (!(streaming = msg_is_streaming(msg))) {
+ tport_sigcomp_accept_incomplete(self, msg);
+ break;
+ }
+ }
+
+ if (msg_get_flags(msg, MSG_FLG_TOOLARGE))
+ SU_DEBUG_3(("%s(%p): too large message from " TPN_FORMAT "\n",
+ __func__, self, TPN_ARGS(self->tp_name)));
+
+ /* Do not try to read anymore from this connection? */
+ if (tport_is_stream(self) &&
+ msg_get_flags(msg, MSG_FLG_TOOLARGE | MSG_FLG_ERROR))
+ self->tp_recv_close = stall = 1;
+
+ if (n == -1)
+ next = NULL;
+ else if (streaming)
+ msg_ref_create(msg); /* Keep a reference */
+ else if (tport_is_stream(self))
+ next = msg_next(msg);
+ else
+ next = NULL;
+
+ tport_deliver(self, msg, next, self->tp_comp, now);
+
+ if (streaming && next == NULL)
+ break;
+ }
+
+ if (stall)
+ tport_stall(self);
+
+ if (self->tp_rlogged != msg)
+ self->tp_rlogged = NULL;
+
+ self->tp_msg = msg;
+}
+
+/** Deliver message to the protocol stack */
+void tport_deliver(tport_t *self,
+ msg_t *msg,
+ msg_t *next,
+ tport_compressor_t *sc,
+ su_time_t now)
+{
+ tport_t *ref;
+ int error;
+ struct tport_delivery *d;
+
+ assert(msg);
+
+ d = self->tp_master->mr_delivery;
+
+ d->d_tport = self;
+ d->d_msg = msg;
+ *d->d_from = *self->tp_name;
+
+ if (tport_is_primary(self)) {
+ char ipaddr[SU_ADDRSIZE + 2];
+ su_sockaddr_t const *su = msg_addr(msg);
+
+#if SU_HAVE_IN6
+ if (su->su_family == AF_INET6) {
+ ipaddr[0] = '[';
+ inet_ntop(su->su_family, SU_ADDR(su), ipaddr + 1, sizeof(ipaddr) - 1);
+ strcat(ipaddr, "]");
+ }
+ else {
+ inet_ntop(su->su_family, SU_ADDR(su), ipaddr, sizeof(ipaddr));
+ }
+#else
+ inet_ntop(su->su_family, SU_ADDR(su), ipaddr, sizeof(ipaddr));
+#endif
+
+ d->d_from->tpn_canon = ipaddr;
+ d->d_from->tpn_host = ipaddr;
+ }
+
+ d->d_comp = sc;
+ if (!sc)
+ d->d_from->tpn_comp = NULL;
+
+ error = msg_has_error(msg);
+
+ if (error && !*msg_chain_head(msg)) {
+ /* This is badly damaged packet */
+ }
+ else if (self->tp_master->mr_log && msg != self->tp_rlogged) {
+ char const *via = "recv";
+ tport_log_msg(self, msg, via, "from", now);
+ self->tp_rlogged = msg;
+ }
+
+ SU_DEBUG_7(("%s(%p): %smsg %p ("MOD_ZU" bytes)"
+ " from " TPN_FORMAT " next=%p\n",
+ __func__, self, error ? "bad " : "",
+ msg, (size_t)msg_size(msg),
+ TPN_ARGS(d->d_from), next));
+
+ ref = tport_incref(self);
+
+ if (self->tp_pri->pri_vtable->vtp_deliver) {
+ self->tp_pri->pri_vtable->vtp_deliver(self, msg, now);
+ }
+ else
+ tport_base_deliver(self, msg, now);
+
+ tport_decref(&ref);
+
+ d->d_msg = NULL;
+}
+
+/** Pass message to the protocol stack */
+void
+tport_base_deliver(tport_t *self, msg_t *msg, su_time_t now)
+{
+ STACK_RECV(self, msg, now);
+}
+
+/** Return source transport object for delivered message */
+tport_t *tport_delivered_by(tport_t const *tp, msg_t const *msg)
+{
+ if (tp && msg && msg == tp->tp_master->mr_delivery->d_msg)
+ return tp->tp_master->mr_delivery->d_tport;
+ else
+ return NULL;
+}
+
+
+/** Return source transport name for delivered message */
+int tport_delivered_from(tport_t *tp, msg_t const *msg, tp_name_t name[1])
+{
+ if (name == NULL)
+ return -1;
+
+ if (tp == NULL || msg == NULL || msg != tp->tp_master->mr_delivery->d_msg) {
+ memset(name, 0, sizeof *name);
+ return -1;
+ }
+ else {
+ *name = *tp->tp_master->mr_delivery->d_from;
+ return 0;
+ }
+}
+
+/** Return UDVM used to decompress the message. */
+int
+tport_delivered_with_comp(tport_t *tp, msg_t const *msg,
+ tport_compressor_t **return_compressor)
+{
+ if (tp == NULL || msg == NULL || msg != tp->tp_master->mr_delivery->d_msg)
+ return -1;
+
+ if (return_compressor)
+ *return_compressor = tp->tp_master->mr_delivery->d_comp;
+
+ return 0;
+}
+
+/** Allocate message for N bytes,
+ * return message buffer as a iovec
+ */
+ssize_t tport_recv_iovec(tport_t const *self,
+ msg_t **in_out_msg,
+ msg_iovec_t iovec[msg_n_fragments],
+ size_t N,
+ int exact)
+{
+ msg_t *msg = *in_out_msg;
+ ssize_t i, veclen;
+ int fresh;
+
+ if (N == 0)
+ return 0;
+
+ fresh = !msg;
+
+ /*
+ * Allocate a new message if needed
+ */
+ if (!msg) {
+ if (!(*in_out_msg = msg = tport_msg_alloc(self, N))) {
+ SU_DEBUG_7(("%s(%p): cannot allocate msg for "MOD_ZU" bytes "
+ "from (%s/%s:%s)\n",
+ __func__, self, N,
+ self->tp_protoname, self->tp_host, self->tp_port));
+ return -1;
+ }
+ }
+
+ /*
+ * Get enough buffer space for the incoming data
+ */
+ veclen = msg_recv_iovec(msg, iovec, msg_n_fragments, N, exact);
+ if (veclen < 0) {
+ int err = su_errno();
+ if (fresh && err == ENOBUFS && msg_get_flags(msg, MSG_FLG_TOOLARGE))
+ veclen = msg_recv_iovec(msg, iovec, msg_n_fragments, 4096, 1);
+ }
+ if (veclen < 0) {
+ int err = su_errno();
+ SU_DEBUG_7(("%s(%p): cannot get msg %p buffer for "MOD_ZU" bytes "
+ "from (%s/%s:%s): %s\n",
+ __func__, self, msg, N,
+ self->tp_protoname, self->tp_host, self->tp_port,
+ su_strerror(err)));
+ su_seterrno(err);
+ return veclen;
+ }
+
+ assert(veclen <= msg_n_fragments);
+
+ SU_DEBUG_7(("%s(%p) msg %p from (%s/%s:%s) has "MOD_ZU" bytes, "
+ "veclen = "MOD_ZD"\n",
+ __func__, self,
+ msg, self->tp_protoname, self->tp_host, self->tp_port,
+ N, veclen));
+
+ for (i = 0; veclen > 1 && i < veclen; i++) {
+ SU_DEBUG_7(("\tiovec[%lu] = %lu bytes\n", (LU)i, (LU)iovec[i].mv_len));
+ }
+
+ return veclen;
+}
+
+int tport_recv_error_report(tport_t *self)
+{
+ if (su_is_blocking(su_errno()))
+ return 1;
+
+ /* Report error */
+ tport_error_report(self, su_errno(), NULL);
+
+ return -1;
+}
+
+/** Send a message.
+ *
+ * The function tport_tsend() sends a message using the transport @a self.
+ *
+ * @TAGS
+ * TPTAG_MTU(), TPTAG_REUSE(), TPTAG_CLOSE_AFTER(), TPTAG_SDWN_AFTER(),
+ */
+tport_t *tport_tsend(tport_t *self,
+ msg_t *msg,
+ tp_name_t const *_tpn,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ ta_list ta;
+ tagi_t const *t;
+ int reuse, sdwn_after, close_after, resolved = 0, fresh;
+ unsigned mtu;
+ su_addrinfo_t *ai;
+ tport_primary_t *primary;
+ tp_name_t tpn[1];
+ struct sigcomp_compartment *cc;
+
+ assert(self);
+
+ if (!self || !msg || !_tpn) {
+ msg_set_errno(msg, EINVAL);
+ return NULL;
+ }
+
+ *tpn = *_tpn;
+
+ SU_DEBUG_7(("tport_tsend(%p) tpn = " TPN_FORMAT "\n", self, TPN_ARGS(tpn)));
+
+ if (tport_is_master(self)) {
+ primary = (tport_primary_t *)tport_primary_by_name(self, tpn);
+ if (!primary) {
+ msg_set_errno(msg, EPROTONOSUPPORT);
+ return NULL;
+ }
+ }
+ else {
+ primary = self->tp_pri;
+ }
+
+ ta_start(ta, tag, value);
+
+ reuse = primary->pri_primary->tp_reusable && self->tp_reusable;
+ fresh = 0;
+ sdwn_after = 0;
+ close_after = 0;
+ mtu = 0;
+ cc = NULL;
+
+ /* tl_gets() is a bit too slow here... */
+ for (t = ta_args(ta); t; t = tl_next(t)) {
+ tag_type_t tt = t->t_tag;
+
+ if (tptag_reuse == tt)
+ reuse = t->t_value != 0;
+ else if (tptag_mtu == tt)
+ mtu = t->t_value;
+ else if (tptag_sdwn_after == tt)
+ sdwn_after = t->t_value != 0;
+ else if (tptag_close_after == tt)
+ close_after = t->t_value != 0;
+ else if (tptag_fresh == tt)
+ fresh = t->t_value != 0;
+ else if (tptag_compartment == tt)
+ cc = (struct sigcomp_compartment *)t->t_value;
+ }
+
+ ta_end(ta);
+
+ fresh = fresh || !reuse;
+
+ ai = msg_addrinfo(msg);
+
+ ai->ai_flags = 0;
+
+ tpn->tpn_comp = tport_canonize_comp(tpn->tpn_comp);
+ if (tpn->tpn_comp) {
+ ai->ai_flags |= TP_AI_COMPRESSED;
+ SU_DEBUG_9(("%s: compressed msg(%p) with %s\n",
+ __func__, msg, tpn->tpn_comp));
+ }
+
+ if (!tpn->tpn_comp || cc == NONE)
+ cc = NULL;
+
+ if (sdwn_after)
+ ai->ai_flags |= TP_AI_SHUTDOWN;
+ if (close_after)
+ ai->ai_flags |= TP_AI_CLOSE;
+
+ if (fresh) {
+ /* Select a primary protocol, make a fresh connection */
+ self = primary->pri_primary;
+ }
+ else {
+ if (tport_is_secondary(self) &&
+ tport_is_registered(self) &&
+ self->tp_reusable &&
+ !self->tp_closed &&
+ !self->tp_send_close) {
+ self = self;
+ }
+ /*
+ * Try to find an already open connection to the destination,
+ * or get a primary protocol
+ */
+ else {
+ /* If primary, resolve the destination address, store it in the msg */
+ if (tport_resolve(primary->pri_primary, msg, tpn) < 0) {
+ return NULL;
+ }
+ resolved = 1;
+
+ self = tport_by_addrinfo(primary, msg_addrinfo(msg), tpn);
+
+ if (!self)
+ self = primary->pri_primary;
+ }
+ }
+
+ if (tport_is_primary(self)) {
+ /* If primary, resolve the destination address, store it in the msg */
+ if (!resolved && tport_resolve(self, msg, tpn) < 0) {
+ return NULL;
+ }
+
+ if (tport_is_connection_oriented(self)
+ || self->tp_params->tpp_conn_orient) {
+#if 0 && HAVE_UPNP /* We do not want to use UPnP with secondary transports! */
+ if (upnp_register_upnp_client(1) != 0) {
+ upnp_check_for_nat();
+ }
+#endif
+
+ tpn->tpn_proto = self->tp_protoname;
+
+ if (!cc)
+ tpn->tpn_comp = NULL;
+
+ /* Create a secondary transport which is connected to the destination */
+ self = tport_connect(primary, msg_addrinfo(msg), tpn);
+
+#if 0 && HAVE_UPNP /* We do not want to use UPnP with secondary transports! */
+ upnp_deregister_upnp_client(0, 0);
+#endif
+
+ if (!self) {
+ msg_set_errno(msg, su_errno());
+ SU_DEBUG_9(("tport_socket failed in tsend\n"));
+ return NULL;
+ }
+
+ if (cc)
+ tport_sigcomp_assign(self, cc);
+ }
+ }
+ else if (tport_is_secondary(self)) {
+ cc = tport_sigcomp_assign_if_needed(self, cc);
+ }
+
+ if (cc == NULL)
+ tpn->tpn_comp = NULL;
+
+ if (tport_is_secondary(self)) {
+ /* Set the peer address to msg */
+ tport_peer_address(self, msg);
+ if (sdwn_after || close_after)
+ self->tp_reusable = 0;
+ }
+
+ if (self->tp_pri->pri_vtable->vtp_prepare
+ ? self->tp_pri->pri_vtable->vtp_prepare(self, msg, tpn, cc, mtu) < 0
+ : tport_prepare_and_send(self, msg, tpn, cc, mtu) < 0)
+ return NULL;
+ else
+ return self;
+}
+
+int tport_prepare_and_send(tport_t *self, msg_t *msg,
+ tp_name_t const *tpn,
+ struct sigcomp_compartment *cc,
+ unsigned mtu)
+{
+ /* Prepare message for sending - i.e., encode it */
+ if (msg_prepare(msg) < 0) {
+ msg_set_errno(msg, errno);
+ return -1;
+ }
+
+ if (msg_size(msg) > (mtu ? mtu : tport_mtu(self))) {
+ msg_set_errno(msg, EMSGSIZE);
+ return -1;
+ }
+
+ /*
+ * If there is already an queued message,
+ * put this message straight in the queue
+ */
+ if ((self->tp_queue && self->tp_queue[self->tp_qhead]) ||
+ /* ...or we are connecting */
+ (self->tp_events & (SU_WAIT_CONNECT | SU_WAIT_OUT))) {
+ if (tport_queue(self, msg) < 0) {
+ SU_DEBUG_9(("tport_queue failed in tsend\n"));
+ return -1;
+ }
+ return 0;
+ }
+
+ return tport_send_msg(self, msg, tpn, cc);
+}
+
+
+/** Send a message.
+ *
+ * @retval 0 when succesful
+ * @retval -1 upon an error
+ */
+int tport_send_msg(tport_t *self, msg_t *msg,
+ tp_name_t const *tpn,
+ struct sigcomp_compartment *cc)
+{
+ msg_iovec_t *iov, auto_iov[40];
+ size_t iovlen, iovused, i, total;
+ size_t n;
+ ssize_t nerror;
+ int sdwn_after, close_after;
+ su_time_t now;
+ su_addrinfo_t *ai;
+
+ assert(self->tp_queue == NULL ||
+ self->tp_queue[self->tp_qhead] == NULL ||
+ self->tp_queue[self->tp_qhead] == msg);
+
+ if (self->tp_iov)
+ /* Use the heap-allocated I/O vector */
+ iov = self->tp_iov, iovlen = self->tp_iovlen;
+ else
+ /* Use the stack I/O vector */
+ iov = auto_iov, iovlen = sizeof(auto_iov)/sizeof(auto_iov[0]);
+
+ /* Get a iovec for message contents */
+ for (;;) {
+ iovused = msg_iovec(msg, iov, iovlen);
+ if (iovused <= iovlen)
+ break;
+
+ iov = su_realloc(self->tp_home, self->tp_iov, sizeof(*iov) * iovused);
+
+ if (iov == NULL) {
+ msg_set_errno(msg, errno);
+ return -1;
+ }
+
+ self->tp_iov = iov, self->tp_iovlen = iovlen = iovused;
+ }
+
+ assert(iovused > 0);
+
+ self->tp_time = su_time_ms(now = su_now());
+
+ nerror = tport_vsend(self, msg, tpn, iov, iovused, cc);
+ SU_DEBUG_9(("tport_vsend returned "MOD_ZD"\n", nerror));
+
+ if (nerror == -1)
+ return -1;
+
+ n = (size_t)nerror;
+
+ self->tp_unsent = NULL, self->tp_unsentlen = 0;
+
+ if (n > 0 && self->tp_master->mr_log && self->tp_slogged != msg) {
+ tport_log_msg(self, msg, "send", "to", now);
+ self->tp_slogged = msg;
+ }
+
+ for (i = 0, total = 0; i < iovused; i++) {
+ if (total + (size_t)iov[i].mv_len > n) {
+ if (tport_is_connection_oriented(self)) {
+ iov[i].mv_len -= (su_ioveclen_t)(n - total);
+ iov[i].mv_base = (char *)iov[i].mv_base + (n - total);
+ if (tport_queue_rest(self, msg, &iov[i], iovused - i) >= 0)
+ return 0;
+ }
+ else {
+ char const *comp = tpn->tpn_comp;
+
+ SU_DEBUG_1(("tport(%p): send truncated for %s/%s:%s%s%s\n",
+ self, tpn->tpn_proto, tpn->tpn_host, tpn->tpn_port,
+ comp ? ";comp=" : "", comp ? comp : ""));
+
+ su_seterrno(EIO);
+ }
+
+ return -1;
+ }
+ total += iov[i].mv_len;
+ }
+
+ /* We have sent a complete message */
+
+ self->tp_slogged = NULL;
+
+ ai = msg_addrinfo(msg); assert(ai);
+ close_after = (ai->ai_flags & TP_AI_CLOSE) == TP_AI_CLOSE;
+ sdwn_after = (ai->ai_flags & TP_AI_SHUTDOWN) == TP_AI_SHUTDOWN ||
+ self->tp_send_close;
+
+ if (close_after || sdwn_after)
+ tport_shutdown(self, close_after ? 2 : 1);
+
+ return 0;
+}
+
+static
+ssize_t tport_vsend(tport_t *self,
+ msg_t *msg,
+ tp_name_t const *tpn,
+ msg_iovec_t iov[],
+ size_t iovused,
+ struct sigcomp_compartment *cc)
+{
+ ssize_t n;
+ su_addrinfo_t *ai = msg_addrinfo(msg);
+
+ if (cc) {
+ n = tport_send_comp(self, msg, iov, iovused, cc, self->tp_comp);
+ }
+ else {
+ ai->ai_flags &= ~TP_AI_COMPRESSED;
+ n = self->tp_pri->pri_vtable->vtp_send(self, msg, iov, iovused);
+ }
+
+ if (n == 0)
+ return 0;
+
+ if (n == -1)
+ return tport_send_error(self, msg, tpn);
+
+ self->tp_stats.sent_bytes += n;
+
+ if (n > 0 && self->tp_master->mr_dump_file)
+ tport_dump_iovec(self, msg, n, iov, iovused, "sent", "to");
+
+ if (tport_log->log_level >= 7) {
+ size_t i, m = 0;
+
+ for (i = 0; i < iovused; i++)
+ m += iov[i].mv_len;
+
+ if (tpn == NULL || tport_is_connection_oriented(self))
+ tpn = self->tp_name;
+
+ SU_DEBUG_7(("tport_vsend(%p): "MOD_ZU" bytes of "MOD_ZU" to %s/%s:%s%s\n",
+ self, n, m, tpn->tpn_proto, tpn->tpn_host,
+ tpn->tpn_port,
+ (ai->ai_flags & TP_AI_COMPRESSED) ? ";comp=sigcomp" : ""));
+ }
+
+ return n;
+}
+
+static
+int tport_send_error(tport_t *self, msg_t *msg,
+ tp_name_t const *tpn)
+{
+ int error = su_errno();
+ su_addrinfo_t *ai = msg_addrinfo(msg);
+ char const *comp = (ai->ai_flags & TP_AI_COMPRESSED) ? ";comp=sigcomp" : "";
+
+ if (error == EPIPE) {
+ /*Xyzzy*/
+ }
+
+ if (su_is_blocking(error)) {
+ SU_DEBUG_5(("tport_vsend(%p): %s with (s=%d %s/%s:%s%s)\n",
+ self, "EAGAIN", (int)self->tp_socket,
+ tpn->tpn_proto, tpn->tpn_host, tpn->tpn_port, comp));
+ return 0;
+ }
+
+ msg_set_errno(msg, error);
+
+ if (self->tp_addrinfo->ai_family == AF_INET) {
+ SU_DEBUG_3(("tport_vsend(%p): %s with (s=%d %s/%s:%s%s)\n",
+ self, su_strerror(error), (int)self->tp_socket,
+ tpn->tpn_proto, tpn->tpn_host, tpn->tpn_port, comp));
+ }
+#if SU_HAVE_IN6
+ else if (self->tp_addrinfo->ai_family == AF_INET6) {
+ su_sockaddr_t const *su = (su_sockaddr_t const *)ai->ai_addr;
+ SU_DEBUG_3(("tport_vsend(%p): %s with "
+ "(s=%d, IP6=%s/%s:%s%s (scope=%i) addrlen=%u)\n",
+ self, su_strerror(error), (int)self->tp_socket,
+ tpn->tpn_proto, tpn->tpn_host, tpn->tpn_port, comp,
+ su->su_scope_id, (unsigned)ai->ai_addrlen));
+ }
+#endif
+ else {
+ SU_DEBUG_3(("\ttport_vsend(%p): %s with "
+ "(s=%d, AF=%u addrlen=%u)%s\n",
+ self, su_strerror(error),
+ (int)self->tp_socket, ai->ai_family, (unsigned)ai->ai_addrlen, comp));
+ }
+
+#if 0
+ int i;
+ for (i = 0; i < iovused; i++)
+ SU_DEBUG_7(("\t\tiov[%d] = { %d bytes @ %p }\n",
+ i, iov[i].siv_len, iov[i].siv_base));
+#endif
+
+ if (tport_is_connection_oriented(self)) {
+ tport_error_report(self, error, NULL);
+ if (tport_has_connection(self))
+ tport_close(self);
+ }
+
+ return -1;
+}
+
+
+static
+int tport_queue_rest(tport_t *self,
+ msg_t *msg,
+ msg_iovec_t iov[],
+ size_t iovused)
+{
+ size_t iovlen = self->tp_iovlen;
+
+ assert(tport_is_connection_oriented(self));
+ assert(self->tp_queue == NULL ||
+ self->tp_queue[self->tp_qhead] == NULL ||
+ self->tp_queue[self->tp_qhead] == msg);
+
+ if (tport_queue(self, msg) < 0)
+ return -1;
+
+ assert(self->tp_queue[self->tp_qhead] == msg);
+
+ if (self->tp_iov == NULL) {
+ if (iovlen < 40) iovlen = 40;
+ if (iovlen < iovused) iovlen = iovused;
+ self->tp_iov = su_alloc(self->tp_home, iovlen * sizeof(iov[0]));
+ self->tp_iovlen = iovlen;
+
+ if (!self->tp_iov) {
+ msg_set_errno(msg, errno);
+ return -1;
+ }
+
+ memcpy(self->tp_iov, iov, iovused * sizeof(iov[0]));
+
+ iov = self->tp_iov;
+ }
+
+ self->tp_unsent = iov;
+ self->tp_unsentlen = iovused;
+
+ /* the POLLOUT event is far too unreliable with SCTP */
+ if (self->tp_addrinfo->ai_protocol == IPPROTO_SCTP)
+ return 0;
+
+ /* Ask for a send event */
+ tport_set_events(self, SU_WAIT_OUT, 0);
+
+ return 0;
+}
+
+/** Queue a message to transport.
+ *
+ * The tport_tqueue() function queues a message in the send queue. It is
+ * used by an (server) application that is required to send (response)
+ * messages in certain order. For example, a HTTP server or proxy may
+ * receive multiple requests from a single TCP connection. The server is
+ * required to answer to the requests in same order as they are received.
+ * The responses are, however, sometimes generated asynchronously, that is,
+ * a response to a later request may be ready earlier. For that purpose, the
+ * HTTP protocol stack queues an empty response message immediately upon
+ * receiving a request. Other messages cannot be sent before the queued one.
+ *
+ * The function tport_tqsend() is used to send the completed response message.
+ *
+ * @param self pointer to transport object
+ * @param msg message to be inserted into queue
+ * @param tag,value,... tagged argument list
+ *
+ * @TAGS
+ * @par Currently none.
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error
+
+ * @ERRORS
+ * @ERROR EINVAL Invalid argument(s).
+ * @ERROR ENOMEM Memory was exhausted.
+ * @ERROR ENOBUFS The transport object queue was full.
+ *
+ * @deprecated Alternative interface will be provided in near future.
+ *
+ * @sa tport_tqsend()
+ */
+int tport_tqueue(tport_t *self, msg_t *msg,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ msg_unprepare(msg);
+
+ return tport_queue(self, msg);
+}
+
+/** Return number of queued messages. */
+isize_t tport_queuelen(tport_t const *self)
+{
+ isize_t retval = 0;
+
+ if (self && self->tp_queue) {
+ unsigned short i, N = self->tp_params->tpp_qsize;
+
+ for (i = self->tp_qhead; self->tp_queue[i]; i = (i + 1) % N)
+ retval++;
+ }
+
+ return retval;
+}
+
+static
+int tport_queue(tport_t *self, msg_t *msg)
+{
+ unsigned short qhead = self->tp_qhead;
+ unsigned short N = self->tp_params->tpp_qsize;
+
+ SU_DEBUG_7(("tport_queue(%p): queueing %p for %s/%s:%s\n",
+ self, msg, self->tp_protoname, self->tp_host, self->tp_port));
+
+ if (self->tp_queue == NULL) {
+ assert(N > 0);
+ assert(qhead == 0);
+ self->tp_queue = su_zalloc(self->tp_home, N * sizeof(msg));
+ if (!self->tp_queue) {
+ msg_set_errno(msg, errno);
+ return -1;
+ }
+ }
+
+ if (self->tp_queue[qhead] == msg)
+ return 0;
+
+ while (self->tp_queue[qhead]) {
+ qhead = (qhead + 1) % N;
+ if (qhead == self->tp_qhead) {
+ msg_set_errno(msg, ENOBUFS);
+ return -1;
+ }
+ }
+
+ self->tp_queue[qhead] = msg_ref_create(msg);
+
+ return 0;
+}
+
+/** Send a queued message (and queue another, if required).
+ *
+ * The function tport_tqsend() sends a message to the transport.
+ *
+ * @deprecated Alternative interface will be provided in near future.
+ */
+int tport_tqsend(tport_t *self, msg_t *msg, msg_t *next,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ unsigned short qhead;
+ ta_list ta;
+ int reuse, sdwn_after, close_after;
+ unsigned short N;
+ su_addrinfo_t *ai;
+
+ if (self == NULL)
+ return -1;
+
+ qhead = self->tp_qhead;
+ N = self->tp_params->tpp_qsize;
+ reuse = self->tp_reusable;
+ sdwn_after = 0;
+ close_after = 0;
+
+ ta_start(ta, tag, value);
+
+ tl_gets(ta_args(ta),
+ TPTAG_REUSE_REF(reuse),
+ TPTAG_SDWN_AFTER_REF(sdwn_after),
+ TPTAG_CLOSE_AFTER_REF(close_after),
+ TAG_END());
+
+ ta_end(ta);
+
+ /* If "next", make sure we can queue it */
+ if (next && self->tp_queue[qhead == 0 ? N - 1 : qhead - 1]) {
+ msg_set_errno(next, ENOBUFS);
+ return -1;
+ }
+
+ /* Prepare message for sending - i.e., encode it */
+ if (msg_prepare(msg) < 0) {
+ msg_set_errno(msg, errno);
+ return -1;
+ }
+
+ tport_peer_address(self, msg); /* Set addrinfo */
+ if (next == NULL) {
+ ai = msg_addrinfo(msg);
+
+ if (sdwn_after)
+ ai->ai_flags |= TP_AI_SHUTDOWN;
+ if (close_after)
+ ai->ai_flags |= TP_AI_CLOSE;
+
+ if (self->tp_queue[qhead] == msg)
+ tport_send_queue(self);
+ return 0;
+ }
+
+ ai = msg_addrinfo(next);
+
+ if (sdwn_after)
+ ai->ai_flags |= TP_AI_SHUTDOWN;
+ if (close_after)
+ ai->ai_flags |= TP_AI_CLOSE;
+
+ if (self->tp_queue[qhead] == msg) {
+ /* XXX - what about errors? */
+ tport_send_msg(self, msg, self->tp_name, NULL);
+ if (!self->tp_unsent) {
+ msg_destroy(self->tp_queue[qhead]);
+ if ((self->tp_queue[qhead] = msg_ref_create(next)))
+ msg_unprepare(next);
+ return 0;
+ }
+ }
+
+ while (self->tp_queue[qhead] && self->tp_queue[qhead] != msg) {
+ qhead = (qhead + 1) % N;
+ if (qhead == self->tp_qhead)
+ break;
+ }
+
+ if (self->tp_queue[qhead] != msg) {
+ msg_set_errno(next, EINVAL);
+ return -1;
+ }
+
+ msg = msg_ref_create(next);
+
+ do {
+ qhead = (qhead + 1) % N;
+ next = self->tp_queue[qhead]; self->tp_queue[qhead] = msg; msg = next;
+ /* Above we made sure that there is an empty slot */
+ assert(!next || qhead != self->tp_qhead);
+ } while (next);
+
+ return 0;
+}
+
+/** Send event.
+ *
+ * Process SU_WAIT_OUT event.
+ */
+void tport_send_event(tport_t *self)
+{
+ assert(tport_is_connection_oriented(self));
+
+ SU_DEBUG_7(("tport_send_event(%p) - ready to send to (%s/%s:%s)\n",
+ self, self->tp_protoname, self->tp_host, self->tp_port));
+ tport_send_queue(self);
+}
+
+/** Send queued messages */
+static
+void tport_send_queue(tport_t *self)
+{
+ msg_t *msg;
+ msg_iovec_t *iov;
+ size_t i, iovused, n, total;
+ unsigned short qhead = self->tp_qhead, N = self->tp_params->tpp_qsize;
+ su_time_t now;
+
+ assert(self->tp_queue && self->tp_queue[qhead]);
+
+ self->tp_time = su_time_ms(now = su_now());
+
+ msg = self->tp_queue[qhead];
+
+ iov = self->tp_unsent, self->tp_unsent = NULL;
+ iovused = self->tp_unsentlen, self->tp_unsentlen = 0;
+
+ if (iov && iovused) {
+ ssize_t e;
+ e = tport_vsend(self, msg, self->tp_name, iov, iovused, NULL);
+
+ if (e == -1) /* XXX */
+ return;
+
+ n = (size_t)e;
+
+ if (n > 0 && self->tp_master->mr_log && self->tp_slogged != msg) {
+ tport_log_msg(self, msg, "send", "to", now);
+ self->tp_slogged = msg;
+ }
+
+ for (i = 0, total = 0; i < iovused; i++) {
+ if (total + (size_t)iov[i].mv_len > n) {
+ iov[i].mv_len -= (su_ioveclen_t)(n - total);
+ iov[i].mv_base = (char *)iov[i].mv_base + (n - total);
+
+ self->tp_unsent = iov + i;
+ self->tp_unsentlen = iovused - i;
+
+ return;
+ }
+ total += iov[i].mv_len;
+ }
+ assert(total == n);
+
+ self->tp_queue[qhead] = NULL;
+ msg_destroy(msg);
+ self->tp_slogged = NULL;
+
+ qhead = (qhead + 1) % N;
+ }
+
+ while (msg_is_prepared(msg = self->tp_queue[self->tp_qhead = qhead])) {
+ /* XXX - what about errors? */
+ tport_send_msg(self, msg, self->tp_name, NULL);
+ if (self->tp_unsent)
+ return;
+
+ msg = self->tp_queue[qhead]; /* tport_send_msg() may flush queue! */
+ self->tp_queue[qhead] = NULL;
+ msg_destroy(msg);
+ qhead = (qhead + 1) % N;
+ }
+
+ /* No more send event(s)? */
+ tport_set_events(self, 0, SU_WAIT_OUT);
+}
+
+static int msg_select_addrinfo(msg_t *msg, su_addrinfo_t *res);
+
+static int
+tport_resolve(tport_t *self, msg_t *msg, tp_name_t const *tpn)
+{
+ int error;
+ char ipaddr[TPORT_HOSTPORTSIZE];
+ su_addrinfo_t *res, hints[1] = {{ 0 }};
+ char const *host;
+ su_sockaddr_t *su;
+
+ hints->ai_socktype = self->tp_addrinfo->ai_socktype;
+ hints->ai_protocol = self->tp_addrinfo->ai_protocol;
+
+ if (tpn->tpn_host[0] == '[') {
+ /* Remove [] around IPv6 address */
+ char *end;
+ hints->ai_flags |= AI_NUMERICHOST;
+ host = strncpy(ipaddr, tpn->tpn_host + 1, sizeof(ipaddr) - 1);
+ ipaddr[sizeof(ipaddr) - 1] = '\0';
+
+ if ((end = strchr(host, ']'))) {
+ *end = 0;
+ }
+ else {
+ SU_DEBUG_3(("tport_resolve: bad IPv6 address\n"));
+ msg_set_errno(msg, EINVAL);
+ return -1;
+ }
+ }
+ else
+ host = tpn->tpn_host;
+
+ if ((error = su_getaddrinfo(host, tpn->tpn_port, hints, &res))) {
+ SU_DEBUG_3(("tport_resolve: getaddrinfo(\"%s\":%s): %s\n",
+ tpn->tpn_host, tpn->tpn_port,
+ su_gai_strerror(error)));
+ msg_set_errno(msg, ENXIO);
+ return -1;
+ }
+
+ error = msg_select_addrinfo(msg, res);
+
+ su = (su_sockaddr_t *) msg_addrinfo(msg)->ai_addr;
+
+#if SU_HAVE_IN6
+ SU_DEBUG_9(("tport_resolve addrinfo = %s%s%s:%d\n",
+ su->su_family == AF_INET6 ? "[" : "",
+ inet_ntop(su->su_family, SU_ADDR(su), ipaddr, sizeof(ipaddr)),
+ su->su_family == AF_INET6 ? "]" : "",
+ htons(su->su_port)));
+#else
+ SU_DEBUG_9(("tport_resolve addrinfo = %s%s%s:%d\n",
+ "",
+ inet_ntop(su->su_family, SU_ADDR(su), ipaddr, sizeof(ipaddr)),
+ "",
+ htons(su->su_port)));
+#endif
+
+ su_freeaddrinfo(res);
+
+ return error;
+}
+
+static int
+msg_select_addrinfo(msg_t *msg, su_addrinfo_t *res)
+{
+ su_addrinfo_t *ai, *mai = msg_addrinfo(msg);
+ su_sockaddr_t *su = (su_sockaddr_t *)mai->ai_addr;
+
+ for (ai = res; ai; ai = ai->ai_next) {
+#if SU_HAVE_IN6
+ if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
+ continue;
+#else
+ if (ai->ai_family != AF_INET)
+ continue;
+#endif
+
+ if (ai->ai_addrlen > sizeof(su_sockaddr_t))
+ continue;
+ mai->ai_family = ai->ai_family;
+ mai->ai_socktype = ai->ai_socktype;
+ mai->ai_protocol = ai->ai_protocol;
+ if (ai->ai_addrlen < sizeof(su_sockaddr_t))
+ memset(su, 0, sizeof(su_sockaddr_t));
+ memcpy(su, ai->ai_addr, ai->ai_addrlen);
+ if (su_sockaddr_size(su))
+ mai->ai_addrlen = su_sockaddr_size(su);
+ else
+ mai->ai_addrlen = ai->ai_addrlen;
+ return 0;
+ }
+
+ msg_set_errno(msg, EAFNOSUPPORT);
+
+ return -1;
+}
+
+/** Copy peer address to msg */
+void
+tport_peer_address(tport_t *self, msg_t *msg)
+{
+ su_addrinfo_t *mai = msg_addrinfo(msg);
+ su_addrinfo_t const *tai = self->tp_addrinfo;
+ void *maddr = mai->ai_addr;
+ int flags = mai->ai_flags;
+
+ memcpy(mai, tai, sizeof *mai);
+ mai->ai_addr = memcpy(maddr, tai->ai_addr, tai->ai_addrlen);
+ mai->ai_flags = flags;
+}
+
+/** Process error event.
+ *
+ * Return events that can be processed afterwards.
+ */
+int tport_error_event(tport_t *self)
+{
+ int errcode;
+ su_sockaddr_t name[1] = {{ 0 }};
+
+ name->su_family = AF_UNSPEC; /* 0 */
+
+ if (tport_is_udp(self)) {
+ errcode = tport_udp_error(self, name);
+ }
+ else {
+ /* Process error event for basic transport. */
+ errcode = su_soerror(self->tp_socket);
+ }
+
+ if (errcode == 0 || errcode == EPIPE)
+ return errcode;
+
+ tport_error_report(self, errcode, name);
+
+ return 0;
+}
+
+/** Mark message as waiting for a response.
+ *
+ * @return Positive integer, or -1 upon an error.
+ */
+int tport_pend(tport_t *self,
+ msg_t *msg,
+ tport_pending_error_f *callback,
+ tp_client_t *client)
+{
+ tport_pending_t *pending;
+
+ if (self == NULL || msg == NULL || callback == NULL || client == NULL)
+ return -1;
+
+ SU_DEBUG_7(("tport_pend(%p): pending %p for %s/%s:%s (already %u)\n",
+ self, msg,
+ self->tp_protoname, self->tp_host, self->tp_port,
+ self->tp_pused));
+
+ if (self->tp_released == NULL) {
+ unsigned i, len = 8;
+ if (self->tp_plen)
+ len = 2 * self->tp_plen;
+ pending = su_realloc(self->tp_home,
+ self->tp_pending, len * sizeof(*pending));
+ if (!pending) {
+ msg_set_errno(msg, errno);
+ return -1;
+ }
+
+ memset(pending + self->tp_plen, 0, (len - self->tp_plen) * sizeof(*pending));
+
+ for (i = self->tp_plen; i + 1 < len; i++)
+ pending[i].p_client = pending + i + 1;
+
+ self->tp_released = pending + self->tp_plen;
+ self->tp_pending = pending;
+ self->tp_plen = len;
+ }
+
+ pending = self->tp_released;
+ self->tp_released = pending->p_client;
+
+ pending->p_callback = callback;
+ pending->p_client = client;
+ pending->p_msg = msg;
+ pending->p_reported = self->tp_reported;
+
+ self->tp_pused++;
+
+ return (pending - self->tp_pending) + 1;
+}
+
+/** Mark message as no more pending */
+int tport_release(tport_t *self,
+ int pendd,
+ msg_t *msg,
+ msg_t *reply,
+ tp_client_t *client,
+ int still_pending)
+{
+ tport_pending_t *pending;
+
+ if (self == NULL || msg == NULL || pendd <= 0 || pendd > (int)self->tp_plen)
+ return su_seterrno(EINVAL), -1;
+
+ pending = self->tp_pending + (pendd - 1);
+
+ if (pending->p_client != client ||
+ pending->p_msg != msg) {
+ SU_DEBUG_1(("tport_release(%p): %u %p by %p not pending\n", self,
+ pendd, msg, client));
+ return su_seterrno(EINVAL), -1;
+ }
+
+ SU_DEBUG_7(("tport_release(%p): %p by %p with %p%s\n",
+ self, msg, client, reply,
+ still_pending ? " (preliminary)" : ""));
+
+ /* sigcomp can here associate request (msg) with response (reply) */
+
+ if (still_pending)
+ return 0;
+
+ /* Just to make sure nobody uses stale data */
+ memset(pending, 0, sizeof(*pending));
+ pending->p_client = self->tp_released;
+ self->tp_released = pending;
+ self->tp_pused--;
+ return 0;
+}
+
+/** Report error to pending messages with destination */
+int
+tport_pending_error(tport_t *self, su_sockaddr_t const *dst, int error)
+{
+ unsigned i, reported, callbacks;
+ tport_pending_t *pending;
+ msg_t *msg;
+ su_addrinfo_t const *ai;
+
+ assert(self); assert(dst);
+
+ callbacks = 0;
+ reported = ++self->tp_reported;
+
+ if (self->tp_pused == 0)
+ return 0;
+
+ for (i = 0; i < self->tp_plen; i++) {
+ pending = self->tp_pending + i;
+
+ if (!pending->p_callback || !pending->p_msg)
+ continue;
+
+ if (pending->p_reported == reported)
+ continue;
+
+ msg = pending->p_msg;
+ ai = msg_addrinfo(msg);
+
+ if (su_cmp_sockaddr(dst, (su_sockaddr_t *)ai->ai_addr) != 0)
+ continue;
+
+ pending->p_reported = reported;
+
+ msg_set_errno(msg, error);
+
+ pending->p_callback(self->TP_STACK, pending->p_client, self, msg, error);
+
+ callbacks++;
+ }
+
+ return callbacks;
+}
+
+
+/** Report error via pending message */
+int
+tport_pending_errmsg(tport_t *self, msg_t *msg, int error)
+{
+ unsigned i, reported, callbacks;
+ tport_pending_t *pending;
+
+ assert(self); assert(msg);
+
+ callbacks = 0;
+ reported = ++self->tp_reported;
+
+ msg_set_errno(msg, error);
+
+ if (self->tp_pused == 0)
+ return 0;
+
+ for (i = 0; i < self->tp_plen; i++) {
+ pending = self->tp_pending + i;
+
+ if (!pending->p_client ||
+ pending->p_msg != msg ||
+ pending->p_reported == reported)
+ continue;
+
+ pending->p_reported = reported;
+
+ pending->p_callback(self->TP_STACK, pending->p_client, self, msg, error);
+
+ callbacks++;
+ }
+
+ return callbacks;
+}
+
+
+/** Set transport magic. */
+void tport_set_magic(tport_t *self, tp_magic_t *magic)
+{
+ self->tp_magic = magic;
+}
+
+/** Get transport magic. */
+tp_magic_t *tport_magic(tport_t const *self)
+{
+ return self ? self->tp_magic : NULL;
+}
+
+/** Get primary transport (or self, if primary) */
+tport_t *tport_parent(tport_t const *self)
+{
+ return self ? self->tp_pri->pri_primary : NULL;
+}
+
+/** Get list of primary transports */
+tport_t *tport_primaries(tport_t const *self)
+{
+ if (self)
+ return self->tp_master->mr_primaries->pri_primary;
+ else
+ return NULL;
+}
+
+/** Get next transport */
+tport_t *tport_next(tport_t const *self)
+{
+ if (self == NULL)
+ return NULL;
+ else if (tport_is_master(self))
+ return ((tport_master_t *)self)->mr_primaries->pri_primary;
+ else if (tport_is_primary(self))
+ return ((tport_primary_t *)self)->pri_next->pri_primary;
+ else
+ return tprb_succ(self);
+}
+
+/** Get secondary transports. */
+tport_t *tport_secondary(tport_t const *self)
+{
+ if (tport_is_primary(self))
+ return self->tp_pri->pri_secondary;
+ else
+ return NULL;
+}
+
+#if 0
+void tport_hints(tport_t const *self, su_addrinfo_t *hints)
+{
+ hints->ai_protocol = self->tp_addrinfo->ai_protocol;
+ hints->ai_socktype = self->tp_addrinfo->ai_socktype;
+}
+#endif
+
+/** Get transport address list. */
+su_addrinfo_t const *tport_get_address(tport_t const *self)
+{
+ return self ? self->tp_addrinfo : NULL;
+}
+
+/** Get transport name. */
+tp_name_t const *tport_name(tport_t const *self)
+{
+ return self->tp_name;
+}
+
+/** Get transport identifier. */
+char const *tport_ident(tport_t const *self)
+{
+ return self ? self->tp_ident : NULL;
+}
+
+/** Get transport by protocol name. */
+tport_t *tport_by_protocol(tport_t const *self, char const *proto)
+{
+ if (proto && strcmp(proto, tpn_any) != 0) {
+ for (; self; self = tport_next(self))
+ if (strcasecmp(proto, self->tp_protoname) == 0)
+ break;
+ }
+
+ return (tport_t *)self;
+}
+
+/** Get transport by protocol name. */
+tport_t *tport_primary_by_name(tport_t const *tp, tp_name_t const *tpn)
+{
+ char const *ident = tpn->tpn_ident;
+ char const *proto = tpn->tpn_proto;
+ char const *comp = tpn->tpn_comp;
+ int family = 0;
+
+ tport_primary_t const *self, *nocomp = NULL;
+
+ self = tp ? tp->tp_master->mr_primaries : NULL;
+
+ if (ident && strcmp(ident, tpn_any) == 0)
+ ident = NULL;
+
+ if (tpn->tpn_host == NULL)
+ family = 0;
+#if SU_HAVE_IN6
+ else if (host_is_ip6_address(tpn->tpn_host))
+ family = AF_INET6;
+#endif
+ else if (host_is_ip4_address(tpn->tpn_host))
+ family = AF_INET;
+ else
+ family = 0;
+
+ if (proto && strcmp(proto, tpn_any) == 0)
+ proto = NULL;
+
+ if (!ident && !proto && !family && !comp)
+ return (tport_t *)self; /* Anything goes */
+
+ comp = tport_canonize_comp(comp);
+
+ for (; self; self = self->pri_next) {
+ tp = self->pri_primary;
+
+ if (ident && strcmp(ident, tp->tp_ident))
+ continue;
+ if (family) {
+ if (family == AF_INET && !tport_has_ip4(tp))
+ continue;
+#if SU_HAVE_IN6
+ if (family == AF_INET6 && !tport_has_ip6(tp))
+ continue;
+#endif
+ }
+ if (proto && strcasecmp(proto, tp->tp_protoname))
+ continue;
+
+ if (comp && comp != tp->tp_name->tpn_comp) {
+ if (tp->tp_name->tpn_comp == NULL && nocomp == NULL)
+ nocomp = self;
+ continue;
+ }
+
+ break;
+ }
+
+ if (self)
+ return (tport_t *)self;
+ else
+ return (tport_t *)nocomp;
+}
+
+
+/** Get transport by name. */
+tport_t *tport_by_name(tport_t const *self, tp_name_t const *tpn)
+{
+ tport_t const *sub, *next;
+ char const *canon, *host, *port, *comp;
+#if SU_HAVE_IN6
+ char *end, ipaddr[TPORT_HOSTPORTSIZE];
+#endif
+
+ assert(self); assert(tpn);
+
+ assert(tpn->tpn_proto); assert(tpn->tpn_host); assert(tpn->tpn_port);
+ assert(tpn->tpn_canon);
+
+ if (!tport_is_primary(self))
+ self = tport_primary_by_name(self, tpn);
+
+ host = strcmp(tpn->tpn_host, tpn_any) ? tpn->tpn_host : NULL;
+ port = strcmp(tpn->tpn_port, tpn_any) ? tpn->tpn_port : NULL;
+ canon = tpn->tpn_canon;
+ comp = tport_canonize_comp(tpn->tpn_comp);
+
+ if (self && host && port) {
+ int resolved = 0, cmp;
+ socklen_t sulen;
+ su_sockaddr_t su[1];
+
+ sub = self->tp_pri->pri_secondary;
+
+ memset(su, 0, sizeof su);
+
+#if SU_HAVE_IN6
+ if (host_is_ip6_reference(host)) {
+ /* Remove [] around IPv6 address */
+ host = strncpy(ipaddr, host + 1, sizeof(ipaddr) - 1);
+ ipaddr[sizeof(ipaddr) - 1] = '\0';
+ if ((end = strchr(host, ']')))
+ *end = 0;
+ su->su_len = sulen = (socklen_t) sizeof (struct sockaddr_in6);
+ su->su_family = AF_INET6;
+ }
+ else if (host_is_ip_address(host)) {
+ su->su_len = sulen = (socklen_t) sizeof (struct sockaddr_in6);
+ su->su_family = AF_INET6;
+ }
+ else
+#endif
+ {
+ su->su_len = sulen = (socklen_t) sizeof (struct sockaddr_in);
+ su->su_family = AF_INET;
+ }
+
+ su->su_port = htons(strtoul(port, NULL, 10));
+
+ if (inet_pton(su->su_family, host, SU_ADDR(su)) > 0) {
+ resolved = 1;
+ next = NULL;
+
+ /* Depth-first search */
+ while (sub) {
+ cmp = (int)((size_t)sub->tp_addrlen - (size_t)sulen);
+
+ if (cmp == 0)
+ cmp = memcmp(sub->tp_addr, su, sulen);
+
+ if (cmp == 0) {
+ if (sub->tp_left) {
+ next = sub;
+ sub = sub->tp_left;
+ continue;
+ }
+ break;
+ }
+ else if (next) {
+ sub = next;
+ break;
+ }
+ else if (cmp > 0) {
+ sub = sub->tp_left;
+ continue;
+ }
+ else /* if (cmp < 0) */ {
+ sub = sub->tp_right;
+ continue;
+ }
+ }
+ }
+ else {
+ SU_DEBUG_7(("tport(%p): EXPENSIVE unresolved " TPN_FORMAT "\n",
+ self, TPN_ARGS(tpn)));
+
+ sub = tprb_first(sub);
+ }
+
+ for (; sub; sub = tprb_succ(sub)) {
+ if (!sub->tp_reusable)
+ continue;
+ if (!tport_is_registered(sub))
+ continue;
+ if (tport_is_shutdown(sub))
+ continue;
+
+ if (comp != sub->tp_name->tpn_comp)
+ continue;
+
+ if (resolved) {
+ if ((socklen_t)sub->tp_addrlen != sulen ||
+ memcmp(sub->tp_addr, su, sulen)) {
+ SU_DEBUG_7(("tport(%p): not found by name " TPN_FORMAT "\n",
+ self, TPN_ARGS(tpn)));
+ break;
+ }
+ SU_DEBUG_7(("tport(%p): found %p by name " TPN_FORMAT "\n",
+ self, sub, TPN_ARGS(tpn)));
+ }
+ else if ((strcasecmp(canon, sub->tp_canon) &&
+ strcasecmp(host, sub->tp_host)) ||
+ strcmp(port, sub->tp_port))
+ continue;
+
+ return (tport_t *)sub;
+ }
+ }
+
+ return (tport_t *)self;
+}
+
+/** Get transport from primary by addrinfo. */
+tport_t *tport_by_addrinfo(tport_primary_t const *pri,
+ su_addrinfo_t const *ai,
+ tp_name_t const *tpn)
+{
+ tport_t const *sub, *maybe;
+ struct sockaddr const *sa;
+ int cmp;
+ char const *comp;
+
+ assert(pri); assert(ai);
+
+ sa = ai->ai_addr;
+
+ sub = pri->pri_secondary, maybe = NULL;
+
+ comp = tport_canonize_comp(tpn->tpn_comp);
+
+ /* Find leftmost (prevmost) matching tport */
+ while (sub) {
+ cmp = (int)(sub->tp_addrlen - ai->ai_addrlen);
+ if (cmp == 0)
+ cmp = memcmp(sub->tp_addr, sa, ai->ai_addrlen);
+
+ if (cmp == 0) {
+ if (sub->tp_left) {
+ maybe = sub;
+ sub = sub->tp_left;
+ continue;
+ }
+ break;
+ }
+ else if (maybe) {
+ sub = maybe;
+ break;
+ }
+ else if (cmp > 0) {
+ sub = sub->tp_left;
+ continue;
+ }
+ else /* if (cmp < 0) */ {
+ sub = sub->tp_right;
+ continue;
+ }
+ }
+
+ for (; sub; sub = tprb_succ(sub)) {
+ if (!sub->tp_reusable)
+ continue;
+ if (!tport_is_registered(sub))
+ continue;
+ if (tport_is_shutdown(sub))
+ continue;
+
+ if (comp != sub->tp_name->tpn_comp)
+ continue;
+
+ if (sub->tp_addrlen != ai->ai_addrlen
+ || memcmp(sub->tp_addr, sa, ai->ai_addrlen)) {
+ sub = NULL;
+ break;
+ }
+ break;
+ }
+
+ if (sub)
+ SU_DEBUG_7(("%s(%p): found %p by name " TPN_FORMAT "\n",
+ __func__, pri, sub, TPN_ARGS(tpn)));
+ else
+ SU_DEBUG_7(("%s(%p): not found by name " TPN_FORMAT "\n",
+ __func__, pri, TPN_ARGS(tpn)));
+
+ return (tport_t *)sub;
+}
+
+
+/** Get transport name from URL. */
+int tport_name_by_url(su_home_t *home,
+ tp_name_t *tpn,
+ url_string_t const *us)
+{
+ size_t n;
+ url_t url[1];
+ char *b;
+
+ n = url_xtra(us->us_url);
+ b = su_alloc(home, n);
+
+ if (b == NULL || url_dup(b, n, url, us->us_url) < 0) {
+ su_free(home, b);
+ return -1;
+ }
+
+ tpn->tpn_proto = url_tport_default(url->url_type);
+ tpn->tpn_canon = url->url_host;
+ tpn->tpn_host = url->url_host;
+ tpn->tpn_port = url_port(url);
+
+ if (tpn->tpn_host == NULL || tpn->tpn_host[0] == '\0' ||
+ tpn->tpn_port == NULL || tpn->tpn_port[0] == '\0') {
+ su_free(home, b);
+ return -1;
+ }
+
+ if (url->url_params) {
+ for (b = (char *)url->url_params; b[0]; b += n) {
+ n = strcspn(b, ";");
+
+ if (n > 10 && strncasecmp(b, "transport=", 10) == 0)
+ tpn->tpn_proto = b + 10;
+ else if (n > 6 && strncasecmp(b, "maddr=", 6) == 0)
+ tpn->tpn_host = b + 6;
+
+ if (b[n])
+ b[n++] = '\0';
+ }
+ }
+
+ return 0;
+}
+
+/** Check if transport named is already resolved */
+int tport_name_is_resolved(tp_name_t const *tpn)
+{
+ size_t n;
+
+ if (!tpn->tpn_host)
+ return 0;
+
+ if (tpn->tpn_host[0] == '[')
+ return 1;
+
+ n = strspn(tpn->tpn_host, ".0123456789");
+
+ if (tpn->tpn_host[n] == '\0')
+ return 1;
+
+ if (strchr(tpn->tpn_host, ':')) {
+ n = strspn(tpn->tpn_host, ":0123456789abcdefABCDEF");
+
+ if (tpn->tpn_host[n] == '\0')
+ return 1;
+ }
+
+ return 0;
+}
+
+/** Duplicate name.
+ *
+ * The tport_name_dup() function copies strings belonging to the transport
+ * name. It returns the copied strings via the @a dst transport name
+ * structure. The memory block required for copies is allocated from the
+ * memory @a home. Please note that only one memory block is allocated, so
+ * the memory can be reclainmed only by deinitializing the memory home
+ * itself.
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error
+ */
+int tport_name_dup(su_home_t *home,
+ tp_name_t *dst,
+ tp_name_t const *src)
+{
+ size_t n_proto, n_host, n_port, n_canon, n_comp = 0;
+ char *s;
+
+ if (strcmp(src->tpn_proto, tpn_any))
+ n_proto = strlen(src->tpn_proto) + 1;
+ else
+ n_proto = 0;
+
+ n_host = strlen(src->tpn_host) + 1;
+
+ n_port = strlen(src->tpn_port) + 1;
+
+ if (src->tpn_comp != NULL)
+ n_comp = strlen(src->tpn_comp) + 1;
+
+ if (src->tpn_canon != src->tpn_host &&
+ strcmp(src->tpn_canon, src->tpn_host))
+ n_canon = strlen(src->tpn_canon) + 1;
+ else
+ n_canon = 0;
+
+ s = su_alloc(home, n_proto + n_canon + n_host + n_port + n_comp);
+
+ if (n_proto)
+ dst->tpn_proto = memcpy(s, src->tpn_proto, n_proto), s += n_proto;
+ else
+ dst->tpn_proto = tpn_any;
+
+ dst->tpn_host = memcpy(s, src->tpn_host, n_host), s += n_host;
+ dst->tpn_port = memcpy(s, src->tpn_port, n_port), s += n_port;
+
+ if (n_canon)
+ dst->tpn_canon = memcpy(s, src->tpn_canon, n_canon), s += n_canon;
+ else
+ dst->tpn_canon = dst->tpn_host;
+
+ if (n_comp)
+ dst->tpn_comp = memcpy(s, src->tpn_comp, n_comp), s += n_comp;
+ else
+ dst->tpn_comp = NULL;
+
+ return 0;
+}
+
+/** Convert a sockaddr structure into printable form. */
+char *tport_hostport(char buf[], isize_t bufsize,
+ su_sockaddr_t const *su,
+ int with_port_and_brackets)
+{
+ char *b = buf;
+ size_t n;
+
+#if SU_HAVE_IN6
+ if (with_port_and_brackets > 1 || su->su_family == AF_INET6) {
+ *b++ = '['; bufsize--;
+ }
+#endif
+
+ if (inet_ntop(su->su_family, SU_ADDR(su), b, bufsize) == NULL)
+ return NULL;
+ n = strlen(b);
+ if (bufsize < n + 2)
+ return NULL;
+
+ bufsize -= n; b += n;
+
+#if SU_HAVE_IN6
+ if (with_port_and_brackets > 1 || su->su_family == AF_INET6) {
+ *b++ = ']'; bufsize--;
+ }
+ if (with_port_and_brackets) {
+ unsigned short port = ntohs(su->su_port);
+ if (port != 0) {
+ n = snprintf(b, bufsize, ":%u", port);
+ if (n <= 0)
+ return NULL;
+ b += n;
+ if (bufsize > n)
+ bufsize -= n;
+ else
+ bufsize = 0;
+ }
+ }
+#endif
+
+ if (bufsize)
+ *b++ = 0;
+
+ return buf;
+}
+
+/* ---------------------------------------------------------------------- */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport.docs Thu Dec 21 01:30:28 2006
@@ -0,0 +1,193 @@
+/**@MODULEPAGE "tport" - Transport Module
+
+ at section tport_meta Module Information
+
+The @b tport module contains a generic transport interface used by SIP,
+RTSP, and HTTP protocols. It is an abstraction layer between a protocol
+stack and a transport protocol implementation. The interface is
+implemented via transport objects.
+
+ at CONTACT Pekka.Pessi at nokia.com
+
+ at LICENSE LGPL
+
+ at section tp_primary Master, Primary and Secondary Transport Objects
+
+A transport object can be used in three roles. Master transport object
+represents all available transport. It is used to store stack and root
+interface as well as common data such as SigComp state handler. The primary
+transport objects represent available transports. The secondary transports
+represent actual transport connections.
+
+A protocol stack first creates a @e master @e transport object and binds a
+number of primary transport objects (each representing a transport protocol
+such as UDP, TCP, TLS/TCP, SCTP, etc). The binding process creates a new
+primary transport object for each transport supported. If the protocol stack
+is used as a server, the binding process also creates the necessary server
+sockets and binds them to the specified server ports.
+
+Secondary transport objects are created for each transport-level
+connection. The @b tport module takes care of automatically creating them
+and discarding them when they are no more used. The secondary transport
+objects are required to transmit messages when a connection-oriented
+transport protocol is used.
+
+A secondary transport object can be created for two reasons. A server may
+accept a new connection from a client, or a client may connect to a
+server. When the connection belonging to a secondary transport has been
+established, the protocol stack can send or receive messages through it.
+
+ at section tp_init Initializing Transports
+
+When the primary transport object is created with tport_tcreate(), the
+protocol stack must pass a #tport_stack_class_t structure containing
+function pointers to the new transport object. These function pointers
+are used to
+
+-# create new message objects used to store received messages
+-# pass received messages to the protocol stack, and
+-# report transport errors to the protocol stack.
+
+The transport protocols are bound to the primary transport objects with
+the method tport_tbind(). The protocol stack gives the desired server
+transport name (transport name is a structure containing a text-formatted
+socket address along with transport name) along with the list of
+transport protocols supported by the stack. The function tport_tbind()
+can be called multiple times, if, for example, the server port(s) used by
+transport protocol differ (for example, default TCP port for SIP is 5060,
+and default TLS port is 5061).
+
+ at subsection tp_connect Connection-Oriented and Connection-Less Transports
+
+A secondary transport objects is created for each transport-level
+connection. The tport module takes care of automatically creating them,
+and discarding them when they are no more used. The secondary transport
+objects are required to transmit messages when a connection-oriented
+transport protocol is used.
+
+A secondary transport can be created for two reasons. A server may accept
+a new connection from a client, or a client may connect to a server. When
+the connection belonging to a secondary transport has been established,
+the protocol stack can send or receive messages through it.
+
+ at par Connection-Oriented and Connection-Less Transports
+
+A transport can be connection-oriented (TCP, SCTP) or connectionless
+(UDP). A connection-oriented transport needs a connection to be
+established before messages can be sent. It can also send messages only
+to a single destination. For a connectionless transport, a destination
+address must always be given.
+
+A connectionless transport can be used to send messages to several
+distinct destinations. The destination address must be given to the
+kernel whenever a message is sent using connectionless transport.
+
+Note that UDP can be used in connection-oriented manner (client does not
+use sendto(), but connect() and then send()), if tport_set_params() is
+called with TPTAG_CONNECT(1) argument.
+
+ at subsection tp_stream Stream and Datagram Transports
+
+A connection-oriented transport can also be stream-based (TCP, SCTP) or
+packet-based (UDP, SCTP). A stream-based transport protocol takes care of
+ordering the data within a stream, a data chunk sent earlier is always
+delivered before chunks sent after it. A packet-based transport delivers
+data chunks independent of each other and does not maintain the relative
+order, for instance, if a data chunk is lost by the network and then
+retransmitted, application can receive it later than a data chunk that
+was sent after lost one but did not need any retransmissions.
+
+ at subsection tp_magic Transport Magic
+
+Transport magic is a cookie, a piece of data specified by stack that can
+be associated with a transport (e.g., a Via header). The protocol stack
+can change the type of transport magic by defining the macro
+#TP_MAGIC_T before including <tport.h>.
+
+ at section tp_op Transport Operations
+
+ at subsection tp_send Sending Messages
+
+A message can be sent by the tport_tsend() method. The method can be
+called either from the primary or from the secondary transport. If a
+secondary transport is needed to send the message, it is created and
+connected automatically.
+
+The transport gets the data to be sent from the message object with
+msg_iovec() call. The transport tries to send all the data using one
+su_vsend() call. If the call would fail, for instance, because the send
+buffer is too short, the transport object would create a reference to the
+message and queue it in its own queue.
+
+ at subsection tp_recv Receiving Messages
+
+When a primary connectionless transport object or a secondary transport
+object receives new data, it allocates a new message object. The message
+object is created using the factory function tpac_alloc() provided by the
+protocl stack. The incoming data is passed to the message object, data is
+parsed and when a message is complete, it is passed to the application
+using the tpac_recv() function provided when the transport was created.
+
+ at subsection tp_refcnt Reference Counting
+
+In order to destroy unused connections, each secondary transport object
+needs to know if there is a reference to it from the stack. A protocol
+stack creates a reference to a transport when it receives an incoming
+request and needs to send the response using the same transport, or when
+it expects a reply from the server coming on the connection used to send
+the request.
+
+ at note While the reference counting has been implemented in the tport
+module, the transport objects are not destroyed by timers by default as
+all the protocol stacks do @b not properly handle the reference counting.
+Timers are activated when the tag TPTAG_IDLE() is used.
+
+ at subsection tp_pend Pending Requests
+
+The protocol stack can mark requests as @e pending using tport_pend()
+function. The tport_pend() function associates a request message with a
+callback and a handle to a client object. When a transport error occurs,
+it is reported to the client object using the associated callback
+function.
+
+When the stack receives a response to the request it has marked as
+pending, it calls tport_release(). The request can be still considered
+pending, if the response was a preliminary one. In this case, the @a
+still_pending argument is true. The function tport_release() is also
+called without response message, if the stack is no more interested in
+the response, for instance, after a timeout.
+
+ at subsection tp_queue Send Queue
+
+Each stream-based transport also supports send queue. The queue can be
+used either to queue messages during congestion, or to maintain the
+relative ordering of responses. Usually, queue is used implicitly for the
+first purpose, e.g., if a transport is busy sending a message it queues
+further messages when tport_tsend() is called.
+
+Explicit queueing is needed when the protocol (like HTTP/1.1) requires
+that the relative order of responses is maintained. When the protocol
+stack receives a request, it queues an empty response message to the
+transport with tport_tqueue(). Such an empty response is marked as
+incomplete, not ready to send. When application responds to the request
+via tport_tqsend(), the transport object marks the message ready to send
+and, if there are no other queued responses before it, sends it.
+
+ at section tp_debug Logging and Dumping Messages
+
+Seeing message contents and network events is extremely useful when
+debugging protocols. There are environment variables that are used to
+activate message logging within @b tport module.
+<dl compact>
+<dt>@b #TPORT_LOG
+ <dd>if set, tport module prints out the message contents
+ after parsing
+<dt>@b #TPORT_DUMP
+ <dd>contains dump file name - incoming data is written
+ dump file @e before parsing
+<dt>@b #TPORT_DEBUG
+ <dd>integer in range -1..9 controlling amount of
+ debugging printout from @b tport module. See also #tport_log.
+</dl>
+ */
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_internal.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_internal.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,529 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef TPORT_INTERNAL_H
+/** Defined when <tport_internal.h> has been included. */
+#define TPORT_INTERNAL_H
+
+/**@file tport_internal.h
+ * @brief Transport interface
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Jun 29 15:58:06 2000 ppessi
+ */
+
+#ifndef SU_H
+#include <sofia-sip/su.h>
+#endif
+
+#include <sofia-sip/su_uniqueid.h>
+
+#ifndef MSG_ADDR_H
+#include <sofia-sip/msg_addr.h>
+#endif
+#ifndef TPORT_H
+#include <sofia-sip/tport.h>
+#endif
+
+#if HAVE_SOFIA_STUN
+#include "sofia-sip/stun.h"
+#include "sofia-sip/stun_tag.h"
+#endif
+
+#include <sofia-sip/tport_plugins.h>
+
+#ifndef SU_DEBUG
+#define SU_DEBUG 3
+#endif
+#define SU_LOG tport_log
+
+#include <sofia-sip/su_debug.h>
+
+#if !defined(MSG_NOSIGNAL) || defined(__CYGWIN__)
+#undef MSG_NOSIGNAL
+#define MSG_NOSIGNAL (0)
+#endif
+
+#if !HAVE_MSG_TRUNC
+#define MSG_TRUNC (0)
+#endif
+
+#ifndef NONE
+#define NONE ((void *)-1)
+#endif
+
+SOFIA_BEGIN_DECLS
+
+typedef struct tport_master tport_master_t;
+typedef struct tport_pending_s tport_pending_t;
+typedef struct tport_primary tport_primary_t;
+typedef struct tport_vtable tport_vtable_t;
+
+struct sigcomp_state_handler;
+struct sigcomp_algorithm;
+struct sigcomp_udvm;
+struct sigcomp_magic;
+struct sigcomp_compartment;
+
+typedef long unsigned LU; /* for printf() and friends */
+
+/** Transport parameters */
+typedef struct {
+ usize_t tpp_mtu; /**< Maximum packet size */
+ unsigned tpp_idle; /**< Allowed connection idle time. */
+ unsigned tpp_timeout; /**< Allowed idle time for message. */
+ unsigned tpp_sigcomp_lifetime; /**< SigComp compartment lifetime */
+ unsigned tpp_thrpsize; /**< Size of thread pool */
+
+ unsigned tpp_thrprqsize; /**< Length of per-thread recv queue */
+ unsigned tpp_qsize; /**< Size of queue */
+
+ unsigned tpp_drop; /**< Packet drop probablity */
+ int tpp_tos; /**< IP TOS */
+
+ unsigned tpp_conn_orient:1; /**< Connection-orienteded */
+ unsigned tpp_sdwn_error:1; /**< If true, shutdown is error. */
+ unsigned tpp_stun_server:1; /**< If true, use stun server */
+
+ unsigned :0;
+
+} tport_params_t;
+
+
+/** Transport object.
+ *
+ * A transport object can be used in three roles, to represent transport
+ * list (aka master transport), to represent available transports (aka
+ * primary transport) and to represent actual transport connections (aka
+ * secondary transport).
+ */
+struct tport_s {
+ su_home_t tp_home[1]; /**< Memory home */
+
+ int tp_refs; /**< Number of references to tport */
+
+ unsigned tp_black:1; /**< Used by red-black-tree */
+
+ unsigned tp_accepted:1; /**< Originally server? */
+ unsigned tp_conn_orient:1; /**< Is connection-oriented */
+ unsigned tp_has_connection:1; /**< Has real connection */
+ unsigned tp_reusable:1; /**< Can this connection be reused */
+ unsigned tp_closed : 1; /**< This transport is closed */
+ /**< Remote end has sent FIN (2) or we should not just read */
+ unsigned tp_recv_close:2;
+ /** We will send FIN (1) or have sent FIN (2) */
+ unsigned tp_send_close:2;
+ unsigned tp_has_keepalive:1;
+ unsigned tp_has_stun_server:1;
+ unsigned tp_trunc:1;
+ unsigned tp_is_connected:1; /**< Connection is established */
+ unsigned:0;
+
+ tport_t *tp_left, *tp_right, *tp_dad; /**< Links in tport tree */
+
+ tport_master_t *tp_master; /**< Master transport */
+ tport_primary_t *tp_pri; /**< Primary transport */
+
+ tport_params_t *tp_params; /**< Transport parameters */
+
+ tp_magic_t *tp_magic; /**< Context provided by consumer */
+
+ msg_t const *tp_rlogged; /**< Last logged when receiving */
+ msg_t const *tp_slogged; /**< Last logged when sending */
+
+ unsigned tp_time; /**< When this transport was last used */
+
+ tp_name_t tp_name[1]; /**< Transport name.
+ *
+ * This is either our name (if primary)
+ * or peer name (if secondary).
+ */
+
+#define tp_protoname tp_name->tpn_proto
+#define tp_canon tp_name->tpn_canon
+#define tp_host tp_name->tpn_host
+#define tp_port tp_name->tpn_port
+#define tp_ident tp_name->tpn_ident
+
+ su_socket_t tp_socket; /**< Socket of this tport*/
+ int tp_index; /**< Root registration index */
+ int tp_events; /**< Subscribed events */
+
+ su_addrinfo_t tp_addrinfo[1]; /**< Peer/own address info */
+ su_sockaddr_t tp_addr[1]; /**< Peer/own address */
+#define tp_addrlen tp_addrinfo->ai_addrlen
+
+ /* ==== Receive queue ================================================== */
+
+ msg_t *tp_msg; /**< Message being received */
+
+ /* ==== Pending messages =============================================== */
+
+ tport_pending_t *tp_pending; /**< Pending requests */
+ tport_pending_t *tp_released; /**< Released pends */
+ unsigned tp_plen; /**< Size of tp_pending */
+ unsigned tp_pused; /**< Used pends */
+ unsigned short tp_reported; /**< Report counter */
+ unsigned short tp_pad;
+
+ /* ==== Send queue ===================================================== */
+
+ msg_t **tp_queue; /**< Messages being sent */
+ unsigned short tp_qhead; /**< Head of queue */
+
+ msg_iovec_t *tp_unsent; /**< Pointer to first unsent iovec */
+ size_t tp_unsentlen; /**< Number of unsent iovecs */
+
+ msg_iovec_t *tp_iov; /**< Iovecs allocated for sending */
+ size_t tp_iovlen; /**< Number of allocated iovecs */
+
+ /* ==== Extensions ===================================================== */
+
+ tport_compressor_t *tp_comp;
+
+ /* ==== Statistics ===================================================== */
+
+ struct {
+ uint64_t sent_bytes, sent_on_line, recv_bytes, recv_on_line;
+ uint64_t sent_msgs, recv_msgs;
+ } tp_stats;
+};
+
+/** Primary structure */
+struct tport_primary {
+ tport_t pri_primary[1]; /**< Transport part */
+#if DOXYGEN_ONLY
+ su_home_t pri_home[1];
+#else
+#define pri_home pri_primary->tp_home
+#define pri_master pri_primary->tp_master
+#define pri_protoname pri_primary->tp_name->tpn_proto
+#endif
+ tport_vtable_t const
+ *pri_vtable;
+ int pri_public; /**< Type of primary transport;
+ * tport_type_local,
+ * tport_type_stun, etc.
+ */
+
+ char pri_ident[16];
+ tport_primary_t *pri_next; /**< Next primary tport */
+
+ tport_t *pri_secondary; /**< Secondary tports */
+
+ unsigned pri_updating:1; /**< Currently updating address */
+ unsigned pri_natted:1; /**< Using natted address */
+ unsigned pri_has_tls:1; /**< Supports tls */
+ unsigned:0;
+
+ void *pri_stun_handle;
+
+ tport_params_t pri_params[1]; /**< Transport parameters */
+
+};
+
+/** Master structure */
+struct tport_master {
+ tport_t mr_master[1];
+#if DOXYGEN_ONLY
+ su_home_t mr_home[1];
+#else
+#define mr_home mr_master->tp_home
+#endif
+
+ int mr_stun_step_ready; /**< for stun's callback */
+
+ tp_stack_t *mr_stack; /**< Transport consumer */
+ tp_stack_class_t
+ const *mr_tpac; /**< Methods provided by stack */
+ int mr_log; /**< Do logging of parsed messages */
+ su_root_t *mr_root; /**< SU root pointer */
+
+ /**< Timer reclaiming unused connections and compartment */
+ su_timer_t *mr_timer;
+ /** File to dump received and sent data */
+ FILE *mr_dump_file;
+
+ tport_primary_t *mr_primaries; /**< List of primary contacts */
+
+ tport_params_t mr_params[1];
+
+ unsigned mr_boundserver:1; /**< Server has been bound */
+ unsigned mr_bindv6only:1; /**< We can bind separately to IPv6/4 */
+ unsigned :0;
+
+ /* Delivery context */
+ struct tport_delivery {
+ tport_t *d_tport;
+ msg_t *d_msg;
+ tp_name_t d_from[1];
+ tport_compressor_t *d_comp;
+ } mr_delivery[1];
+
+ tport_stun_server_t *mr_stun_server;
+
+#if 0
+ struct tport_nat_s {
+ int initialized;
+ int bound;
+ int stun_enabled;
+ char *external_ip_address;
+#if HAVE_UPNP || HAVE_SOFIA_STUN
+ int try_stun;
+#endif
+#if HAVE_UPNP
+#endif
+#if HAVE_SOFIA_STUN
+ tport_master_t *tport;
+ char *stun_server;
+ /* stun_socket_t *stun_socket; */
+ stun_handle_t *stun;
+ su_socket_t stun_socket;
+ su_sockaddr_t sockaddr;
+#endif
+ } mr_nat[1];
+#endif
+};
+
+/** Virtual funtion table for transports */
+struct tport_vtable
+{
+ char const *vtp_name;
+ enum tport_via vtp_public;
+
+ size_t vtp_pri_size; /* Size of primary tport */
+ int (*vtp_init_primary)(tport_primary_t *pri,
+ tp_name_t tpn[1],
+ su_addrinfo_t *ai, tagi_t const *,
+ char const **return_culprit);
+ void (*vtp_deinit_primary)(tport_primary_t *pri);
+ int (*vtp_wakeup_pri)(tport_primary_t *pri, int events);
+ tport_t *(*vtp_connect)(tport_primary_t *pri, su_addrinfo_t *ai,
+ tp_name_t const *tpn);
+
+ size_t vtp_secondary_size; /* Size of secondary tport */
+
+ int (*vtp_init_secondary)(tport_t *, int socket, int accepted,
+ char const **return_reason);
+ void (*vtp_deinit_secondary)(tport_t *);
+ void (*vtp_shutdown)(tport_t *, int how);
+ int (*vtp_set_events)(tport_t const *self);
+ int (*vtp_wakeup)(tport_t *self, int events);
+ int (*vtp_recv)(tport_t *self);
+ ssize_t (*vtp_send)(tport_t const *self, msg_t *msg,
+ msg_iovec_t iov[], size_t iovused);
+ void (*vtp_deliver)(tport_t *self, msg_t *msg, su_time_t now);
+ int (*vtp_prepare)(tport_t *self, msg_t *msg,
+ tp_name_t const *tpn,
+ struct sigcomp_compartment *cc,
+ unsigned mtu);
+ int (*vtp_keepalive)(tport_t *self, su_addrinfo_t const *ai,
+ tagi_t const *taglist);
+ int (*vtp_stun_response)(tport_t const *self,
+ void *msg, size_t msglen,
+ void *addr, socklen_t addrlen);
+};
+
+int tport_register_type(tport_vtable_t const *vtp);
+
+/** Test if transport is needs connect() before sending. */
+static inline int tport_is_connection_oriented(tport_t const *self)
+{
+ return self->tp_conn_orient;
+}
+
+/** Test if transport involves connection. @NEW_1_12_5 */
+static inline int tport_has_connection(tport_t const *self)
+{
+ return self->tp_has_connection;
+}
+
+void tport_has_been_updated(tport_t *tport);
+
+int tport_primary_compression(tport_primary_t *pri,
+ char const *compression,
+ tagi_t const *tl);
+
+void tport_set_tos(su_socket_t socket, su_addrinfo_t *ai, int tos);
+
+tport_t *tport_base_connect(tport_primary_t *pri,
+ su_addrinfo_t *ai,
+ su_addrinfo_t *name,
+ tp_name_t const *tpn);
+
+int tport_stream_init_primary(tport_primary_t *pri,
+ su_socket_t socket,
+ tp_name_t tpn[1],
+ su_addrinfo_t *ai,
+ tagi_t const *tags,
+ char const **return_reason);
+
+tport_t *tport_alloc_secondary(tport_primary_t *pri,
+ int socket,
+ int accepted,
+ char const **return_reason);
+
+int tport_accept(tport_primary_t *pri, int events);
+void tport_zap_secondary(tport_t *self);
+
+int tport_bind_socket(int socket,
+ su_addrinfo_t *ai,
+ char const **return_culprit);
+void tport_close(tport_t *self);
+
+
+int tport_error_event(tport_t *self);
+void tport_recv_event(tport_t *self);
+void tport_send_event(tport_t *self);
+void tport_hup_event(tport_t *self);
+
+ssize_t tport_recv_iovec(tport_t const *self,
+ msg_t **mmsg,
+ msg_iovec_t iovec[msg_n_fragments], size_t N,
+ int exact);
+
+msg_t *tport_msg_alloc(tport_t const *self, usize_t size);
+
+int tport_prepare_and_send(tport_t *self, msg_t *msg,
+ tp_name_t const *tpn,
+ struct sigcomp_compartment *cc,
+ unsigned mtu);
+int tport_send_msg(tport_t *self, msg_t *msg,
+ tp_name_t const *tpn,
+ struct sigcomp_compartment *cc);
+
+void tport_deliver(tport_t *self, msg_t *msg, msg_t *next,
+ tport_compressor_t *comp,
+ su_time_t now);
+void tport_base_deliver(tport_t *self, msg_t *msg, su_time_t now);
+
+int tport_recv_error_report(tport_t *self);
+void tport_error_report(tport_t *self, int errcode,
+ su_sockaddr_t const *addr);
+
+void tport_open_log(tport_master_t *mr, tagi_t *tags);
+void tport_log_msg(tport_t *tp, msg_t *msg, char const *what,
+ char const *via, su_time_t now);
+void tport_dump_iovec(tport_t const *self, msg_t *msg,
+ size_t n, su_iovec_t const iov[], size_t iovused,
+ char const *what, char const *how);
+
+extern tport_vtable_t const tport_udp_vtable;
+extern tport_vtable_t const tport_udp_client_vtable;
+
+int tport_udp_init_primary(tport_primary_t *,
+ tp_name_t tpn[1],
+ su_addrinfo_t *,
+ tagi_t const *,
+ char const **return_culprit);
+void tport_udp_deinit_primary(tport_primary_t *);
+int tport_recv_dgram(tport_t *self);
+ssize_t tport_send_dgram(tport_t const *self, msg_t *msg,
+ msg_iovec_t iov[], size_t iovused);
+int tport_udp_error(tport_t const *self, su_sockaddr_t name[1]);
+
+extern tport_vtable_t const tport_tcp_vtable;
+extern tport_vtable_t const tport_tcp_client_vtable;
+
+int tport_tcp_init_primary(tport_primary_t *,
+ tp_name_t tpn[1],
+ su_addrinfo_t *, tagi_t const *,
+ char const **return_culprit);
+int tport_tcp_init_client(tport_primary_t *,
+ tp_name_t tpn[1],
+ su_addrinfo_t *, tagi_t const *,
+ char const **return_culprit);
+int tport_tcp_init_secondary(tport_t *self, int socket, int accepted,
+ char const **return_reason);
+int tport_recv_stream(tport_t *self);
+ssize_t tport_send_stream(tport_t const *self, msg_t *msg,
+ msg_iovec_t iov[], size_t iovused);
+
+extern tport_vtable_t const tport_sctp_vtable;
+extern tport_vtable_t const tport_sctp_client_vtable;
+extern tport_vtable_t const tport_tls_vtable;
+extern tport_vtable_t const tport_tls_client_vtable;
+extern tport_vtable_t const tport_stun_vtable;
+extern tport_vtable_t const tport_http_connect_vtable;
+extern tport_vtable_t const tport_threadpool_vtable;
+
+typedef struct tport_descriptor_s {
+ char const *tpd_name;
+ tport_vtable_t *tpd_vtable;
+ su_addrinfo_t *tpd_hints;
+ int tpd_is_client_only;
+} tport_descriptor_t;
+
+typedef int const *(tport_set_f)(tport_master_t *mr,
+ tp_name_t const *tpn,
+ tagi_t const *taglist,
+ tport_descriptor_t **return_set,
+ int return_set_size);
+
+/* STUN plugin */
+
+int tport_init_stun_server(tport_master_t *mr, tagi_t const *tags);
+void tport_deinit_stun_server(tport_master_t *mr);
+int tport_recv_stun_dgram(tport_t const *self, msg_t **in_out_msg,
+ su_sockaddr_t *from, socklen_t fromlen);
+
+int tport_stun_server_add_socket(tport_t *tp);
+int tport_stun_server_remove_socket(tport_t *tp);
+
+/* ---------------------------------------------------------------------- */
+/* Compressor plugin */
+extern tport_comp_vtable_t const *tport_comp_vtable;
+
+char const *tport_canonize_comp(char const *comp);
+
+int tport_init_compressor(tport_t *,
+ char const *comp_name,
+ tagi_t const *tags);
+void tport_deinit_compressor(tport_t *);
+
+struct sigcomp_compartment *
+tport_sigcomp_assign_if_needed(tport_t *self,
+ struct sigcomp_compartment *cc);
+
+struct sigcomp_udvm **tport_get_udvm_slot(tport_t *self);
+
+void tport_sigcomp_accept_incomplete(tport_t *self, msg_t *msg);
+
+int tport_recv_comp_dgram(tport_t const *self,
+ tport_compressor_t *sc,
+ msg_t **in_out_msg,
+ su_sockaddr_t *from,
+ socklen_t fromlen);
+
+ssize_t tport_send_comp(tport_t const *self,
+ msg_t *msg,
+ msg_iovec_t iov[],
+ size_t iovused,
+ struct sigcomp_compartment *cc,
+ tport_compressor_t *sc);
+
+SOFIA_END_DECLS
+
+#endif /* TPORT_INTERNAL_H */
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_logging.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_logging.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,249 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE tport_logging.c Logging transported messages.
+ *
+ * See tport.docs for more detailed description of tport interface.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ *
+ * @date Created: Fri Mar 24 08:45:49 EET 2006 ppessi
+ */
+
+#include "config.h"
+
+#include "tport_internal.h"
+
+#include <sofia-sip/string0.h>
+#include <stdlib.h>
+#include <time.h>
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+
+/**@var TPORT_LOG
+ *
+ * Environment variable determining if parsed message contents are logged.
+ *
+ * If the TPORT_LOG environment variable is set, the tport module logs the
+ * contents of parsed messages. This eases debugging the signaling greatly.
+ *
+ * @sa TPORT_DUMP, TPORT_DEBUG, tport_log
+ */
+extern char const TPORT_LOG[]; /* dummy declaration for Doxygen */
+
+/**@var TPORT_DUMP
+ *
+ * Environment variable for transport data dump.
+ *
+ * The received and sent data is dumped to the file specified by TPORT_DUMP
+ * environment variable. This can be used to save message traces and help
+ * hairy debugging tasks.
+ *
+ * @sa TPORT_LOG, TPORT_DEBUG, tport_log
+ */
+extern char const TPORT_DUMP[]; /* dummy declaration for Doxygen */
+
+/**@var TPORT_DEBUG
+ *
+ * Environment variable determining the debug log level for @b tport module.
+ *
+ * The TPORT_DEBUG environment variable is used to determine the debug logging
+ * level for @b tport module. The default level is 3.
+ *
+ * @sa <su_debug.h>, tport_log, SOFIA_DEBUG
+ */
+extern char const TPORT_DEBUG[]; /* dummy declaration for Doxygen */
+
+/**Debug log for @b tport module.
+ *
+ * The tport_log is the log object used by @b tport module. The level of
+ * #tport_log is set using #TPORT_DEBUG environment variable.
+ */
+su_log_t tport_log[] = {
+ SU_LOG_INIT("tport", "TPORT_DEBUG", SU_DEBUG)
+};
+
+
+/** Initialize logging. */
+void tport_open_log(tport_master_t *mr, tagi_t *tags)
+{
+ char const *log;
+
+ mr->mr_log =
+ getenv("MSG_STREAM_LOG") != NULL ||
+ getenv("TPORT_LOG") != NULL
+ ? MSG_DO_EXTRACT_COPY : 0;
+
+ if ((log = getenv("TPORT_DUMP")) || (log = getenv("MSG_DUMP"))) {
+ time_t now;
+
+ if (strcmp(log, "-"))
+ mr->mr_dump_file = fopen(log, "ab"); /* XXX */
+ else
+ mr->mr_dump_file = stdout;
+
+ if (mr->mr_dump_file) {
+ time(&now);
+ fprintf(mr->mr_dump_file, "dump started at %s\n\n", ctime(&now));
+ }
+ }
+}
+
+/** Create log stamp */
+void tport_stamp(tport_t const *self, msg_t *msg,
+ char stamp[128], char const *what,
+ size_t n, char const *via,
+ su_time_t now)
+{
+ char label[24] = "";
+ char *comp = "";
+ char name[SU_ADDRSIZE] = "";
+ su_sockaddr_t const *su = msg_addr(msg);
+ unsigned short second, minute, hour;
+
+ second = (unsigned short)(now.tv_sec % 60);
+ minute = (unsigned short)((now.tv_sec / 60) % 60);
+ hour = (unsigned short)((now.tv_sec / 3600) % 24);
+
+#if SU_HAVE_IN6
+ if (su->su_family == AF_INET6) {
+ if (su->su_sin6.sin6_flowinfo)
+ snprintf(label, sizeof(label), "/%u", ntohl(su->su_sin6.sin6_flowinfo));
+ }
+#endif
+
+ if (msg_addrinfo(msg)->ai_flags & TP_AI_COMPRESSED)
+ comp = ";comp=sigcomp";
+
+ inet_ntop(su->su_family, SU_ADDR(su), name, sizeof(name));
+
+ snprintf(stamp, 128,
+ "%s "MOD_ZU" bytes %s %s/[%s]:%u%s%s at %02u:%02u:%02u.%06lu:\n",
+ what, (size_t)n, via, self->tp_name->tpn_proto,
+ name, ntohs(su->su_port), label[0] ? label : "", comp,
+ hour, minute, second, now.tv_usec);
+}
+
+/** Dump the data from the iovec */
+void tport_dump_iovec(tport_t const *self, msg_t *msg,
+ size_t n, su_iovec_t const iov[], size_t iovused,
+ char const *what, char const *how)
+{
+ tport_master_t *mr = self->tp_master;
+ char stamp[128];
+ size_t i;
+
+ if (!mr->mr_dump_file)
+ return;
+
+ tport_stamp(self, msg, stamp, what, n, how, su_now());
+ fputs(stamp, mr->mr_dump_file);
+
+ for (i = 0; i < iovused && n > 0; i++) {
+ size_t len = iov[i].mv_len;
+ if (len > n)
+ len = n;
+ if (fwrite(iov[i].mv_base, len, 1, mr->mr_dump_file) != len)
+ break;
+ n -= len;
+ }
+
+ fputs("\v\n", mr->mr_dump_file);
+ fflush(mr->mr_dump_file);
+}
+
+/** Log the message. */
+void tport_log_msg(tport_t *self, msg_t *msg,
+ char const *what, char const *via,
+ su_time_t now)
+{
+ char stamp[128];
+ msg_iovec_t iov[80];
+ size_t i, iovlen = msg_iovec(msg, iov, 80);
+ size_t linelen = 0, n, logged = 0, truncated = 0;
+ int skip_lf = 0;
+
+#define MSG_SEPARATOR \
+ "------------------------------------------------------------------------\n"
+#define MAX_LINELEN 2047
+
+ for (i = n = 0; i < iovlen && i < 80; i++)
+ n += iov[i].mv_len;
+
+ tport_stamp(self, msg, stamp, what, n, via, now);
+ su_log(stamp);
+ su_log(" " MSG_SEPARATOR);
+
+ for (i = 0; truncated == 0 && i < iovlen && i < 80; i++) {
+ char *s = iov[i].mv_base, *end = s + iov[i].mv_len;
+
+ if (skip_lf && s < end && s[0] == '\n') { s++; logged++; skip_lf = 0; }
+
+ while (s < end) {
+ if (s[0] == '\0') {
+ truncated = logged;
+ break;
+ }
+
+ n = strncspn(s, end - s, "\r\n");
+
+ if (linelen + n > MAX_LINELEN) {
+ n = MAX_LINELEN - n - linelen;
+ truncated = logged + n;
+ }
+
+ su_log("%s%.*s", linelen > n ? "" : " ", (int)n, s);
+ s += n, linelen += n, logged += n;
+
+ if (truncated)
+ break;
+ if (s == end)
+ continue;
+
+ linelen = 0;
+ su_log("\n");
+
+ /* Skip eol */
+ if (s[0] == '\r') {
+ s++, logged++;
+ if (s == end) {
+ skip_lf = 1;
+ continue;
+ }
+ }
+ if (s[0] == '\n')
+ s++, logged++;
+ }
+ }
+
+ su_log("%s " MSG_SEPARATOR, linelen > 0 ? "\n" : "");
+
+ if (!truncated && i == 80)
+ truncated = logged;
+
+ if (truncated)
+ su_log(" *** message truncated at "MOD_ZU" ***\n", truncated);
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_rand.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_rand.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,46 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <openssl/rand.h>
+
+int main(int argc, char **argv)
+{
+ int nb;
+
+ if (argc != 2) {
+ printf("Usage: tport_rand <output seed file>\n");
+ exit(0);
+ }
+
+ printf("Please move mouse for until the application stops\n");
+
+ RAND_load_file("/dev/random", 1024);
+ RAND_write_file(argv[1]);
+
+ nb = RAND_load_file(argv[1], -1);
+
+ printf("Wrote %d bytes to the seed file\n", nb);
+
+ return 0;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_sigcomp.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_sigcomp.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,885 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE tport_sigcomp.c Transport using SigComp.
+ *
+ * Incomplete.
+ *
+ * See tport.docs for more detailed description of tport interface.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ *
+ * @date Created: Fri Mar 24 08:45:49 EET 2006 ppessi
+ */
+
+#include "config.h"
+
+#include "tport.h"
+
+#include <sofia-sip/string0.h>
+#include <stdlib.h>
+#include <time.h>
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+
+#include <sigcomp.h>
+
+/* ---------------------------------------------------------------------- */
+/* SigComp */
+
+typedef struct tport_sigcomp_handler tport_sigcomp_handler_t;
+
+/** Per end-point SigComp data */
+struct tport_compressor {
+ struct sigcomp_state_handler *msc_state_handler;
+ struct sigcomp_compartment *msc_compartment;
+};
+
+/** Per-socket SigComp data */
+struct tport_comp {
+ struct sigcomp_udvm *sc_udvm;
+ struct sigcomp_compartment *sc_cc;
+ struct sigcomp_compressor *sc_compressor;
+ struct sigcomp_buffer *sc_output;
+ unsigned sc_compressed;
+
+ struct sigcomp_buffer *sc_input;
+ unsigned sc_copied;
+
+ enum {
+ format_is_unknown,
+ format_is_sigcomp,
+ format_is_noncomp
+ } sc_infmt, sc_outfmt;
+};
+
+
+tport_compressor_t *vsc_master_init_sigcomp(tport_t *mr,
+ char const *algorithm)
+{
+ tport_compressor_t *retval = NLL;
+ stuct sigcomp_state_handler *sh = NULL;
+ struct sigcomp_algorithm *a = NULL;
+ struct sigcomp_compartment *cc = NULL;
+
+ if (algorithm == NULL)
+ algorithm = getenv("SIGCOMP_ALGORITHM");
+
+ retval = su_zalloc((su_home_t *)mr, sizeof *retval);
+ if (retval == NULL)
+ return retval;
+
+ sh = sigcomp_state_handler_create();
+
+ if (sh == NULL) {
+ SU_DEBUG_1(("tport: initializing SigComp state handler: %s\n",
+ strerror(errno)));
+ vsc_master_deinit_sigcomp(mr, retval), retval = NULL;
+ return retval;
+ }
+ retval->msc_state_handler = sh;
+
+ a = sigcomp_algorithm_by_name(algorithm);
+ cc = sigcomp_compartment_create(a, sh, 0, "", 0, NULL, 0);
+
+ if (cc == NULL) {
+ SU_DEBUG_1(("tport: initializing SigComp master compartment: %s\n",
+ strerror(errno)));
+ vsc_master_deinit_sigcomp(mr, retval), retval = NULL;
+ return retval;
+ }
+
+ self->msc_compartment = cc;
+
+ return retval;
+}
+
+ if (self->sa_compartment) {
+ agent_sigcomp_options(self, self->sa_compartment);
+ sigcomp_compartment_option(self->sa_compartment, "stateless");
+ }
+ else
+
+ if (mr->mr_compartment)
+ sigcomp_compartment_unref(mt->mr_compartment);
+ mr->mr_compartment = sigcomp_compartment_ref(cc);
+
+ return cc;
+}
+
+
+void vsc_master_deinit_sigcomp(tport_master_t *mr)
+{
+ tport_sigcomp_vtable_t const *vsc = tport_sigcomp_vtable;
+
+ if (mr->mr_compartment)
+ sigcomp_compartment_unref(mr->mr_compartment), mr->mr_compartment = NULL;
+
+}
+
+char const *vsc_comp_name(tport_sigcomp_t const *master_sc,
+ char const *proposed_name,
+ tagi_t const *tags)
+{
+ if (master_sc == NULL ||
+ master_sc->sc_cc == NULL ||
+ compression == NULL ||
+ strcasecmp(compression, tport_sigcomp_name))
+ return NULL;
+
+ return tport_sigcomp_name;
+}
+
+/** Check if transport can receive compressed messages */
+int vsc_can_recv_sigcomp(tport_sigcomp_t const *sc)
+{
+ return sc && sc->sc_infmt != format_is_noncomp;
+}
+
+/** Check if transport can send compressed messages */
+int vsc_can_send_sigcomp(tport_sigcomp_t const *sc)
+{
+ return sc && sc->sc_outfmt != format_is_noncomp;
+}
+
+/** Set/reset compression */
+int vsc_set_compression(tport_t *self,
+ tport_sigcomp_t *sc,
+ char const *comp)
+{
+ if (self == NULL)
+ ;
+ else if (comp == NULL) {
+ if (sc == NULL || sc->sc_outfmt != format_is_sigcomp) {
+ self->tp_name->tpn_comp = NULL;
+ return 0;
+ }
+ }
+ else {
+ comp = tport_canonize_comp(comp);
+
+ if (comp && sc && sc->sc_outfmt != format_is_noncomp) {
+ self->tp_name->tpn_comp = comp;
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+
+/** Assign a SigComp compartment (to a possibly connected tport). */
+int tport_sigcomp_assign(tport_t *self, struct sigcomp_compartment *cc)
+{
+ if (tport_is_connection_oriented(self) &&
+ tport_is_secondary(self) &&
+ self->tp_socket != INVALID_SOCKET) {
+
+ if (self->tp_sigcomp->sc_cc) {
+ if (cc == self->tp_sigcomp->sc_cc)
+ return 0;
+
+ /* Remove old assignment */
+ sigcomp_compartment_unref(self->tp_sigcomp->sc_cc);
+ }
+
+ self->tp_sigcomp->sc_cc = sigcomp_compartment_ref(cc);
+
+ return 0;
+ }
+
+ return su_seterrno(EINVAL);
+}
+
+
+void vsc_sigcomp_shutdown(tport_t *self, int how)
+{
+ if (self->tp_socket != -1)
+ shutdown(self->tp_socket, how - 1);
+
+ if (how >= 2 && self->tp_sigcomp->sc_cc) {
+ sigcomp_compartment_unref(self->tp_sigcomp->sc_cc);
+ self->tp_sigcomp->sc_cc = NULL;
+ }
+}
+
+static int vsc_recv_sigcomp_r(tport_t*, msg_t**, struct sigcomp_udvm*, int);
+static struct sigcomp_compartment *vsc_primary_compartment(tport_master_t *);
+
+
+static int tport_sigcomp_init_secondary()
+{
+ if (accept) {
+ if (!pri->pri_primary->tp_name->tpn_comp)
+ self->tp_sigcomp->sc_infmt = format_is_noncomp;
+ }
+ else {
+ /* XXX - no tpn here */
+ if (tpn->tpn_comp == pri->pri_primary->tp_name->tpn_comp)
+ self->tp_name->tpn_comp = pri->pri_primary->tp_name->tpn_comp;
+ if (!pri->pri_primary->tp_name->tpn_comp)
+ self->tp_sigcomp->sc_infmt = format_is_noncomp;
+ }
+}
+
+static int tport_sigcomp_deinit_secondary(tport_t *self)
+{
+ if (self->tp_sigcomp) {
+ tport_sigcomp_t *sc = self->tp_sigcomp;
+
+ if (sc->sc_udvm)
+ sigcomp_udvm_free(sc->sc_udvm), sc->sc_udvm = NULL;
+ if (sc->sc_compressor)
+ sigcomp_compressor_free(sc->sc_compressor), sc->sc_compressor = NULL;
+ }
+}
+
+#if 0
+#if HAVE_SIGCOMP
+ if (tport_can_recv_sigcomp(self))
+ return tport_recv_sigcomp_stream(self);
+#endif
+#endif
+
+/** Try to receive stream data using SigComp. */
+static int tport_recv_sigcomp_stream(tport_t *self)
+{
+ struct sigcomp_udvm *udvm;
+ int retval;
+
+ SU_DEBUG_7(("%s(%p)\n", __func__, self));
+
+ /* Peek for first byte in stream,
+ determine if this is a compressed stream or not */
+ if (self->tp_sigcomp->sc_infmt == format_is_unknown) {
+ unsigned char sample;
+ int n;
+
+ n = recv(self->tp_socket, &sample, 1, MSG_PEEK);
+ if (n < 0)
+ return n;
+
+ if (n == 0) {
+ recv(self->tp_socket, &sample, 1, 0);
+ return 0; /* E-o-S from first message */
+ }
+
+ if ((sample & 0xf8) != 0xf8) {
+ /* Not SigComp, receive as usual */
+ if (tport_is_primary(self)) {
+ SU_DEBUG_1(("%s(%p): receive semantics not implemented\n",
+ __func__, self));
+ su_seterrno(EINVAL); /* Internal error */
+ return -1;
+ }
+
+ /* Do not try to receive with sigcomp from this socket */
+ self->tp_sigcomp->sc_infmt = format_is_noncomp;
+
+ return tport_recv_stream(self);
+ }
+
+ /* SigComp, receive using UDVM */
+ self->tp_sigcomp->sc_infmt = format_is_sigcomp;
+
+ /* Initialize UDVM */
+ self->tp_sigcomp->sc_udvm = tport_init_udvm(self);
+ if (!self->tp_sigcomp->sc_udvm) {
+ int save = su_errno();
+ recv(self->tp_socket, &sample, 1, 0); /* remove msg from socket */
+ return su_seterrno(save);
+ }
+ }
+
+ udvm = self->tp_sigcomp->sc_udvm; assert(udvm);
+
+ retval = tport_recv_sigcomp_r(self, &self->tp_msg, udvm, N);
+
+ if (retval < 0)
+ sigcomp_udvm_reject(udvm);
+
+ return retval;
+}
+
+/** Receive data available on the socket.
+ *
+ * @retval -1 error
+ * @retval 0 end-of-stream
+ * @retval 1 normal receive
+ * @retval 2 incomplete recv, recv again
+ */
+static int tport_recv_sigcomp_r(tport_t *self,
+ msg_t **mmsg,
+ struct sigcomp_udvm *udvm,
+ int N)
+{
+ msg_t *msg;
+ size_t n, m, i;
+ int eos, complete;
+ ssize_t veclen;
+ msg_iovec_t iovec[msg_n_fragments] = {{ 0 }};
+ su_sockaddr_t su[1];
+ socklen_t su_size = sizeof(su);
+ struct sigcomp_buffer *input, *output;
+ void *data;
+ size_t dlen;
+
+ SU_DEBUG_7(("%s(%p)\n", __func__, self));
+
+ assert(udvm);
+
+ if (sigcomp_udvm_has_input(udvm)) {
+ input = sigcomp_udvm_input_buffer(udvm, n = N = 0); assert(input);
+ }
+ else {
+ if (N == 0) {
+ assert(self->tp_addrinfo->ai_socktype != SOCK_DGRAM);
+ if (self->tp_addrinfo->ai_socktype == SOCK_DGRAM) {
+ recv(self->tp_socket, (void *)su, 1, 0);
+ return 1;
+ }
+ }
+
+ input = sigcomp_udvm_input_buffer(udvm, N); assert(input);
+ if (input == NULL)
+ return su_seterrno(EIO);
+
+ data = input->b_data + input->b_avail;
+ dlen = input->b_size - input->b_avail;
+
+ if (tport_is_stream(self)) {
+ n = recv(self->tp_socket, data, dlen, 0);
+ }
+ else if (dlen >= N) {
+ n = recvfrom(self->tp_socket, data, dlen, 0, &su->su_sa, &su_size);
+ SU_CANONIZE_SOCKADDR(su);
+ }
+ else {
+ recvfrom(self->tp_socket, data, dlen, 0, &su->su_sa, &su_size);
+ SU_CANONIZE_SOCKADDR(su);
+ su_seterrno(EMSGSIZE); /* Protocol error */
+ return -1;
+ }
+
+ if (n == (unsigned)-1) {
+ char const *pn = self->tp_protoname;
+ int err = su_errno();
+
+ if (su_is_blocking(err)) {
+ SU_DEBUG_7(("%s(%p): recv from %s: EAGAIN\n", __func__, self, pn));
+ return 1;
+ }
+
+ SU_DEBUG_1(("%s(%p): recv from %s: %s (%d)\n", __func__, self, pn,
+ su_strerror(err), err));
+ return -1;
+ }
+
+ /* XXX - in case of stream, use message buffers for output? */
+
+ input->b_avail += n;
+ input->b_complete = (n == 0) || !tport_is_stream(self);
+ }
+
+ for (complete = eos = 0; !complete;) {
+ output = sigcomp_udvm_output_buffer(udvm, 16384);
+
+ if (sigcomp_udvm_decompress(udvm, output, input) < 0) {
+ int error = sigcomp_udvm_errno(udvm);
+
+ SU_DEBUG_3(("%s: UDVM error %d: %s\n", __func__,
+ error, sigcomp_udvm_strerror(udvm)));
+
+ su_seterrno(EREMOTEIO);
+
+ return -1;
+ }
+
+ data = output->b_data + output->b_used;
+ dlen = output->b_avail - output->b_used;
+ complete = output->b_complete;
+ eos = complete && input->b_complete;
+
+ veclen = tport_recv_iovec(self, mmsg, iovec, dlen, eos);
+
+ if (dlen ? veclen <= 0 : veclen < 0) {
+ return -1;
+ }
+
+ for (i = 0, n = 0; i < veclen; i++) {
+ m = iovec[i].mv_len; assert(dlen >= n + m);
+ memcpy(iovec[i].mv_base, data + n, m);
+ n += m;
+ }
+ assert(dlen == n);
+
+ msg = *mmsg;
+
+ if (msg) {
+ /* Message address */
+ if (self->tp_addrinfo->ai_socktype == SOCK_STREAM)
+ msg_set_address(msg, self->tp_addr, self->tp_addrlen);
+ else
+ msg_set_address(msg, su, su_size);
+
+ SU_DEBUG_5(("%s(%p): sigcomp recv = %u => %u %s\n", __func__, self,
+ N, dlen, eos ? " (complete)" : ""));
+
+ msg_mark_as_compressed(msg);
+
+ /* Write the received data to the message dump file */
+ if (self->tp_master->mr_dump_file && !self->tp_pri->pri_threadpool)
+ tport_dump_iovec(self, msg, n, iovec, veclen, "recv", "from");
+
+ msg_recv_commit(msg, dlen, eos); /* Mark buffer as used */
+ }
+ else {
+ SU_DEBUG_5(("%s(%p): sigcomp recv = %u => %u %s\n", __func__, self,
+ N, dlen, eos ? " (complete)" : ""));
+ if (complete || !tport_is_stream(self)) {
+ sigcomp_udvm_reject(udvm); /* Reject empty message */
+ }
+ }
+
+ if (self->tp_addrinfo->ai_socktype == SOCK_STREAM) {
+ if (eos)
+ return 0;
+
+ if (output->b_complete)
+ return n < N || sigcomp_udvm_has_pending_data(udvm) ? 2 : 1;
+
+ if (!sigcomp_udvm_has_input(udvm))
+ return 1;
+ }
+ }
+
+ return eos ? 0 : 2;
+}
+
+static
+int vsc_send_sigcomp(tport_t const *self,
+ msg_t *msg,
+ msg_iovec_t iov[],
+ int iovused,
+ struct sigcomp_compartment *cc,
+ tport_sigcomp_t *sc)
+{
+ struct sigcomp_compressor *c = sc->sc_compressor;
+ struct sigcomp_buffer *input = sc->sc_input;
+ struct sigcomp_buffer *output = sc->sc_output;
+ msg_iovec_t ciov[1];
+
+ int i, n, m, k, stream = tport_is_stream(self);
+ char const *ccname;
+ int ccnamelen;
+
+ su_addrinfo_t *ai = msg_addrinfo(msg);
+
+ int compress = (cc || (cc = sc->sc_cc)) && ai->ai_flags & TP_AI_COMPRESSED;
+
+ if (!compress) {
+ if (stream)
+ sc->sc_outfmt = format_is_noncomp;
+ ai->ai_flags &= ~TP_AI_COMPRESSED;
+ return self->tp_pri->pri_vtable->vtp_send(self, msg, iov, iovused, NULL);
+ }
+
+ if (stream)
+ sc->sc_outfmt = format_is_sigcomp;
+
+ assert(cc);
+
+ if (c == NULL) {
+ assert(input == NULL);
+ if (stream)
+ c = sigcomp_compressor_create_for_stream(cc);
+ else
+ c = sigcomp_compressor_create(cc);
+ sc->sc_compressor = c;
+ }
+
+ ccname = sigcomp_compartment_name(cc, &ccnamelen);
+
+ if (sc->sc_compressed != 0) {
+ input = NONE;
+ }
+ else if (input == NULL) {
+ int input_size = -1;
+
+ if (tport_is_udp(self)) {
+ input_size = 0;
+
+ for (i = 0; i < iovused; i++)
+ input_size += iov[i].siv_len;
+ }
+
+ sc->sc_input = input = sigcomp_compressor_input_buffer(c, input_size);
+
+ assert(input->b_avail == 0 && input->b_used == 0);
+ }
+ else if (!input->b_complete) {
+ int input_size = 0;
+
+ for (i = 0; i < iovused; i++)
+ input_size += iov[i].siv_len;
+
+ if (input_size > input->b_size - input->b_avail)
+ sigcomp_buffer_align_available(input, 0);
+ }
+
+ if (output == NULL)
+ sc->sc_output = output = sigcomp_compressor_output_buffer(c, NULL);
+
+ if (!c || !input || !output) {
+ SU_DEBUG_3(("%s(%p): %s (%u)%s%s%s\n",
+ __func__, self, strerror(errno), errno,
+ c ? "" : " (comp)",
+ input ? "" : " (input)",
+ output ? "" : " (output)"));
+ sigcomp_compressor_free(c);
+ sc->sc_compressor = NULL;
+ sc->sc_output = NULL; sc->sc_input = NULL;
+ sc->sc_compressed = 0; sc->sc_copied = 0;
+ return -1;
+ }
+
+ if (sc->sc_compressed == 0) {
+ k = sc->sc_copied;
+
+ if (!input->b_complete) {
+ int m = sc->sc_copied;
+
+ for (i = 0, n = 0; i < iovused; i++) {
+ char *b = iov[i].siv_base;
+ int l = iov[i].siv_len;
+
+ if (m >= l) {
+ m -= l;
+ continue;
+ }
+
+ b += m; l -= m;
+
+ if (input->b_size == input->b_avail)
+ break;
+
+ if (l > input->b_size - input->b_avail)
+ l = input->b_size - input->b_avail;
+
+ memcpy(input->b_data + input->b_avail, b, l);
+ input->b_avail += l; n += l; sc->sc_copied += l;
+
+ if (l != iov[i].siv_len)
+ break;
+ }
+ input->b_complete = i == iovused;
+ assert(stream || input->b_complete); (void)stream;
+ }
+
+ m = output->b_avail - output->b_used;
+
+ n = sigcomp_compressor_compress(c, output, input);
+
+ if (n < 0) {
+ SU_DEBUG_3(("%s(%p): %s (%u)\n", __func__, self,
+ sigcomp_compressor_strerror(c),
+ sigcomp_compressor_errno(c)));
+ sigcomp_compressor_free(c);
+ sc->sc_compressor = NULL;
+ sc->sc_output = NULL; sc->sc_input = NULL;
+ sc->sc_compressed = 0;
+ return -1;
+ }
+
+ assert(input->b_complete || sc->sc_copied - k > 0);
+
+ SU_DEBUG_5(("%s: input %u (%u new) compressed %u to %u with '%.*s'\n",
+ __func__, sc->sc_copied, k, n,
+ (output->b_avail - output->b_used) - m,
+ ccnamelen, ccname));
+
+ sc->sc_compressed = n;
+
+ assert(stream || output->b_complete);
+ }
+ else {
+ assert(tport_is_connection_oriented(self));
+ n = sc->sc_compressed;
+ }
+
+ assert(input && cc && c && output);
+
+ ciov->siv_base = output->b_data + output->b_used;
+ ciov->siv_len = output->b_avail - output->b_used;
+
+ m = self->tp_pri->pri_vtable->vtp_send(self, msg, ciov, 1);
+
+ if (m == -1) {
+ int error = su_errno();
+
+ if (su_is_blocking(error)) {
+ sigcomp_compressor_free(c);
+ sc->sc_compressor = NULL;
+ sc->sc_output = NULL; sc->sc_input = NULL;
+ sc->sc_compressed = 0; sc->sc_copied = 0;
+ su_seterrno(error);
+ }
+
+ return -1;
+ }
+
+ output->b_used += m;
+
+ if (output->b_used < output->b_avail)
+ return 0;
+
+ if (output->b_complete) {
+ sigcomp_compressor_accept(c, cc), sc->sc_output = output = NULL;
+ }
+
+ if (input != NONE && input->b_avail == input->b_used && input->b_complete)
+ sigcomp_buffer_reset(input, -1), sc->sc_input = input = NULL;
+
+ if (!input && !output) {
+ sigcomp_compressor_free(c);
+ sc->sc_compressor = NULL;
+ }
+
+ assert(sc->sc_compressed >= n); assert(sc->sc_copied >= n);
+
+ sc->sc_compressed -= n;
+ sc->sc_copied -= n;
+
+ return n;
+}
+
+/** Initialize UDVM */
+static
+struct sigcomp_udvm *tport_init_udvm(tport_t *self)
+{
+ struct sigcomp_compartment *cc;
+ struct sigcomp_udvm *udvm;
+
+ if (self->tp_sigcomp->sc_udvm)
+ return self->tp_sigcomp->sc_udvm;
+
+ cc = tport_primary_compartment(self->tp_master);
+
+ if (!cc)
+ return NULL;
+
+ if (self->tp_addrinfo->ai_socktype == SOCK_STREAM)
+ udvm = sigcomp_udvm_create_for_stream(cc);
+ else
+ udvm = sigcomp_udvm_create_for_compartment(cc);
+
+ return udvm;
+}
+
+
+/** Get primary compartment */
+static
+struct sigcomp_compartment *
+tport_primary_compartment(tport_master_t *mr)
+{
+ return mr->mr_compartment;
+}
+
+/** Test if tport has a SigComp compartment is assigned to it. */
+int vsc_has_sigcomp_assigned(tport_sigcomp_t const *sc)
+{
+ return sc && sc->sc_udvm != NULL;
+}
+
+static
+void vsc_try_accept_sigcomp(tport_t *self, msg_t *msg)
+{
+ struct sigcomp_udvm *udvm;
+
+ udvm = self->tp_sigcomp->sc_udvm;
+ if (udvm && sigcomp_udvm_is_complete(udvm)) {
+ if (self->tp_master->mr_tpac->tpac_sigcomp_accept &&
+ self->tp_sigcomp->sc_cc == NULL) {
+ tport_t *ref;
+ struct tport_delivery *d;
+
+ d = self->tp_master->mr_delivery;
+
+ d->d_tport = self;
+ d->d_msg = msg;
+ d->d_udvm = &self->tp_sigcomp->sc_udvm;
+ *d->d_from = *self->tp_name;
+
+ ref = tport_incref(self);
+ STACK_SIGCOMP_ACCEPT(self, msg);
+ /* Reject by default */
+ if (self->tp_sigcomp->sc_udvm)
+ sigcomp_udvm_accept(self->tp_sigcomp->sc_udvm, NULL);
+ tport_decref(&ref);
+
+ d->d_msg = NULL;
+ }
+ else {
+ if (tport_log->log_level >= 5) {
+ char const *name;
+ int namelen;
+
+ name = sigcomp_compartment_name(self->tp_sigcomp->sc_cc, &namelen);
+ SU_DEBUG_5(("tport(%p): msg %p SigComp implicit accept '%.*s'\n",
+ self, msg, namelen, name));
+ }
+ sigcomp_udvm_accept(udvm, self->tp_sigcomp->sc_cc);
+ }
+ }
+}
+
+
+/** Accept a SigComp message */
+int
+tport_sigcomp_accept(tport_t *self,
+ struct sigcomp_compartment *cc,
+ msg_t *msg)
+{
+ struct sigcomp_udvm *udvm;
+
+ if (self == NULL || msg != self->tp_master->mr_delivery->d_msg)
+ return su_seterrno(EINVAL);
+
+ if (!self->tp_master->mr_delivery->d_udvm || cc == NONE)
+ return 0;
+
+ udvm = *self->tp_master->mr_delivery->d_udvm;
+
+ if (udvm) {
+ if (tport_log->log_level >= 5) {
+ char const *name;
+ int namelen;
+
+ if (cc) {
+ name = sigcomp_compartment_name(cc, &namelen);
+ SU_DEBUG_5(("tport(%p): msg %p SigComp accept '%.*s'\n",
+ self, msg, namelen, name));
+ }
+ else {
+ SU_DEBUG_5(("tport(%p): msg %p SigComp reject\n", self, msg));
+ }
+ }
+ sigcomp_udvm_accept(udvm, cc);
+ }
+
+ self->tp_master->mr_delivery->d_udvm = NULL;
+
+ return 0;
+}
+
+
+/** Pass message to the protocol stack */
+void
+tport_sigcomp_deliver(tport_t *self, msg_t *msg, su_time_t now)
+{
+ /* XXX - no d */
+
+ STACK_RECV(self, msg, now);
+
+ if (d->d_udvm && *d->d_udvm)
+ sigcomp_udvm_accept(*d->d_udvm, NULL); /* reject */
+}
+
+
+#if HAVE_SIGCOMP && 0
+
+static inline
+int msg_is_compressed(msg_t *msg)
+{
+ return msg &&
+ (msg_addrinfo(msg)->ai_flags & TP_AI_COMPRESSED) == TP_AI_COMPRESSED;
+}
+
+static inline
+void msg_mark_as_compressed(msg_t *msg)
+{
+ if (msg)
+ msg_addrinfo(msg)->ai_flags |= TP_AI_COMPRESSED;
+}
+
+
+struct sigcomp_udvm **tport_get_udvm_slot(tport_t *self)
+{
+ tport_sigcomp_vtable_t const *vsc = tport_sigcomp_vtable;
+
+ if (vsc)
+
+#if HAVE_SIGCOMP
+ return &self->tp_sigcomp->sc_udvm;
+#else
+ return NULL;
+#endif
+}
+
+struct sigcomp_compartment *
+tport_sigcomp_assign_if_needed(tport_t *self,
+ struct sigcomp_compartment *cc)
+{
+ if (self->tp_name->tpn_comp) {
+ if (cc)
+ tport_sigcomp_assign(self, cc);
+ else if (self->tp_sigcomp->sc_cc)
+ cc = self->tp_sigcomp->sc_cc;
+ else
+ /* Use default compartment */
+ cc = self->tp_master->mr_compartment;
+ }
+ else
+ cc = NULL;
+
+ return cc;
+}
+
+/** Receive data from datagram using SigComp. */
+int tport_recv_sigcomp_dgram(tport_t *self, int N)
+{
+ char dummy[1];
+ int error = EBADMSG;
+#if HAVE_SIGCOMP
+ struct sigcomp_udvm *udvm;
+
+ if (self->tp_sigcomp->sc_udvm == 0)
+ self->tp_sigcomp->sc_udvm = tport_init_udvm(self);
+
+ udvm = self->tp_sigcomp->sc_udvm;
+
+ if (udvm) {
+ retval = tport_recv_sigcomp_r(self, &self->tp_msg, udvm, N);
+ if (retval < 0)
+ sigcomp_udvm_reject(udvm);
+ return retval;
+ }
+ error = su_errno();
+#endif
+ recv(self->tp_socket, dummy, 1, 0); /* remove msg from socket */
+ /* XXX - send NACK ? */
+ return su_seterrno(error);
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_stub_sigcomp.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_stub_sigcomp.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,290 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE tport_stub_sigcomp.c Stub interface for SigComp
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Fri Mar 31 12:31:36 EEST 2006
+ */
+
+#include "config.h"
+
+#include "tport_internal.h"
+
+tport_comp_vtable_t const *tport_comp_vtable = NULL;
+
+int tport_plug_in_compress(tport_comp_vtable_t const *vsc)
+{
+ return -1;
+}
+
+char const tport_sigcomp_name[] = "sigcomp";
+
+/** Canonize compression string */
+char const *tport_canonize_comp(char const *comp)
+{
+ if (tport_comp_vtable && comp && strcasecmp(comp, tport_sigcomp_name) == 0)
+ return tport_sigcomp_name;
+ return NULL;
+}
+
+int tport_init_compressor(tport_t *tp,
+ char const *comp_name,
+ tagi_t const *tags)
+{
+ tport_comp_vtable_t const *vsc = tport_comp_vtable;
+ tport_master_t *mr = tp ? tp->tp_master : NULL;
+ tport_compressor_t *tcc;
+
+ if (vsc == NULL)
+ return -1;
+ if (mr == NULL)
+ return -1;
+
+ if (tp->tp_comp)
+ return 0;
+
+ comp_name = tport_canonize_comp(comp_name);
+ if (comp_name == NULL)
+ return 0;
+
+ tcc = su_zalloc(tp->tp_home, vsc->vsc_sizeof_context);
+
+ if (tcc == NULL)
+ return -1;
+
+ if (vsc->vsc_init_comp(mr->mr_stack, tp, tcc, comp_name, tags) < 0) {
+ vsc->vsc_deinit_comp(mr->mr_stack, tp, tcc);
+ return -1;
+ }
+
+ tp->tp_comp = tcc;
+
+ return 0;
+}
+
+void tport_deinit_compressor(tport_t *tp)
+{
+ tport_comp_vtable_t const *vsc = tport_comp_vtable;
+ tport_master_t *mr = tp ? tp->tp_master : NULL;
+
+ if (vsc && mr && tp->tp_comp) {
+ vsc->vsc_deinit_comp(mr->mr_stack, tp, tp->tp_comp);
+ su_free(tp->tp_home, tp->tp_comp), tp->tp_comp = NULL;
+ }
+}
+
+
+char const *tport_comp_name(tport_primary_t *pri,
+ char const *name,
+ tagi_t const *tags)
+{
+ tport_comp_vtable_t const *vsc = tport_comp_vtable;
+ tport_compressor_t const *comp = pri->pri_master->mr_master->tp_comp;
+
+ if (vsc)
+ return vsc->vsc_comp_name(comp, name, tags);
+
+ return NULL;
+}
+
+
+/** Check if transport can receive compressed messages */
+int tport_can_recv_sigcomp(tport_t const *self)
+{
+ tport_comp_vtable_t const *vsc = tport_comp_vtable;
+
+ if (vsc)
+ return vsc->vsc_can_recv_comp(self->tp_comp);
+
+ return 0;
+}
+
+/** Check if transport can send compressed messages */
+int tport_can_send_sigcomp(tport_t const *self)
+{
+ tport_comp_vtable_t const *vsc = tport_comp_vtable;
+
+ if (vsc)
+ return vsc->vsc_can_send_comp(self->tp_comp);
+
+ return 0;
+}
+
+/** Check if transport supports named compression */
+int tport_has_compression(tport_t const *self, char const *comp)
+{
+ return
+ self && comp &&
+ self->tp_name->tpn_comp == tport_canonize_comp(comp);
+}
+
+int tport_set_compression(tport_t *self, char const *comp)
+{
+ tport_comp_vtable_t const *vsc = tport_comp_vtable;
+
+ if (vsc)
+ return vsc->vsc_set_comp_name(self, self->tp_comp, comp);
+
+ return (self == NULL || comp) ? -1 : 0;
+}
+
+/** Set options to SigComp */
+int tport_sigcomp_option(tport_t const *self,
+ struct sigcomp_compartment *cc,
+ char const *option)
+{
+ tport_comp_vtable_t const *vsc = tport_comp_vtable;
+
+ if (vsc)
+ return vsc->vsc_sigcomp_option(self, cc, option);
+
+ return -1;
+}
+
+
+/** Assign a SigComp compartment (to a possibly connected tport).
+ *
+ * @related tport_s
+ */
+int tport_sigcomp_assign(tport_t *self, struct sigcomp_compartment *cc)
+{
+ tport_comp_vtable_t const *vsc = tport_comp_vtable;
+
+ if (!vsc)
+ return 0;
+
+ if (tport_is_connection_oriented(self) &&
+ tport_is_secondary(self) &&
+ self->tp_socket != INVALID_SOCKET) {
+ return vsc->vsc_set_compartment(self, self->tp_comp, cc);
+ }
+
+ return 0;
+}
+
+struct sigcomp_compartment *
+tport_sigcomp_assign_if_needed(tport_t *self,
+ struct sigcomp_compartment *cc)
+{
+ tport_comp_vtable_t const *vsc = tport_comp_vtable;
+
+ if (!vsc)
+ return NULL;
+
+ if (!self->tp_name->tpn_comp)
+ return NULL;
+
+ if (cc) {
+ tport_sigcomp_assign(self, cc);
+ return cc;
+ }
+
+ return vsc->vsc_get_compartment(self, self->tp_comp);
+}
+
+
+/** Test if tport has a SigComp compartment assigned to it. */
+int tport_has_sigcomp_assigned(tport_t const *self)
+{
+ tport_comp_vtable_t const *vsc = tport_comp_vtable;
+
+ if (vsc && self)
+ return vsc->vsc_has_sigcomp_assigned(self->tp_comp);
+
+ return 0;
+}
+
+int
+tport_sigcomp_accept(tport_t *self,
+ struct sigcomp_compartment *cc,
+ msg_t *msg)
+{
+ tport_comp_vtable_t const *vsc = tport_comp_vtable;
+
+ if (self == NULL)
+ return su_seterrno(EFAULT);
+
+ if (vsc)
+ return vsc->vsc_sigcomp_accept(self, self->tp_comp, cc, msg);
+
+ return 0;
+}
+
+/* Internal API */
+
+/** This function is called when the application message is still incomplete
+ but a complete SigComp message could have been received */
+void tport_sigcomp_accept_incomplete(tport_t *self, msg_t *msg)
+{
+ tport_comp_vtable_t const *vsc = tport_comp_vtable;
+
+ if (vsc && self->tp_comp)
+ vsc->vsc_accept_incomplete(self, self->tp_comp, msg);
+}
+
+struct sigcomp_udvm **tport_get_udvm_slot(tport_t *self)
+{
+ tport_comp_vtable_t const *vsc = tport_comp_vtable;
+
+ if (vsc && self)
+ return vsc->vsc_get_udvm_slot(self);
+
+ return NULL;
+}
+
+/** Receive data from datagram using SigComp. */
+int tport_recv_comp_dgram(tport_t const *self,
+ tport_compressor_t *sc,
+ msg_t **in_out_msg,
+ su_sockaddr_t *from,
+ socklen_t fromlen)
+{
+ tport_comp_vtable_t const *vsc = tport_comp_vtable;
+
+ if (vsc)
+ return vsc->vsc_recv_comp(self, sc, in_out_msg, from, fromlen);
+
+ msg_destroy(*in_out_msg), *in_out_msg = NULL;
+
+ return su_seterrno(EBADMSG);
+}
+
+
+ssize_t tport_send_comp(tport_t const *self,
+ msg_t *msg,
+ msg_iovec_t iov[],
+ size_t iovused,
+ struct sigcomp_compartment *cc,
+ tport_compressor_t *comp)
+{
+ tport_comp_vtable_t const *vsc = tport_comp_vtable;
+
+ if (vsc)
+ vsc->vsc_send_comp(self, msg, iov, iovused, cc, comp);
+
+ msg_addrinfo(msg)->ai_flags &= ~TP_AI_COMPRESSED;
+ return self->tp_pri->pri_vtable->vtp_send(self, msg, iov, iovused);
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_stub_stun.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_stub_stun.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,294 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE tport_stub_stun.c Stub interface for STUN
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Fri Mar 31 12:31:36 EEST 2006
+ */
+
+#include "config.h"
+
+#include <sofia-sip/stun.h>
+#include <sofia-sip/su_tagarg.h>
+
+#define TPORT_STUN_SERVER_T stun_mini_t
+#include "tport_internal.h"
+#include "sofia-sip/msg_buffer.h"
+#include "sofia-sip/msg_addr.h"
+
+#include <assert.h>
+
+/* ---------------------------------------------------------------------- */
+/* Plugin pointer */
+
+tport_stun_server_vtable_t const *tport_stun_server_vtable = NULL;
+
+
+static
+tport_stun_server_t *vst_create(su_root_t *root, tagi_t const *tags)
+{
+ return stun_mini_create();
+}
+
+static
+tport_stun_server_vtable_t const stun_mini_vtable =
+ {
+ sizeof stun_mini_vtable,
+ vst_create,
+ stun_mini_destroy,
+ stun_mini_add_socket,
+ stun_mini_remove_socket,
+ stun_mini_request
+ };
+
+/** Initialize stun server */
+int tport_init_stun_server(tport_master_t *mr, tagi_t const *tags)
+{
+ tport_stun_server_vtable_t const *vst = tport_stun_server_vtable;
+
+ if (vst == NULL)
+ /* Nobody has plugged better server in, use miniserver */
+ tport_stun_server_vtable = vst = &stun_mini_vtable;
+
+ if (!vst)
+ return 0;
+
+ if (mr->mr_params->tpp_stun_server)
+ mr->mr_stun_server = vst->vst_create(mr->mr_root, tags);
+ mr->mr_master->tp_has_stun_server = mr->mr_stun_server != NULL;
+ return 0;
+}
+
+/** Deinit stun server */
+void tport_deinit_stun_server(tport_master_t *mr)
+{
+ tport_stun_server_vtable_t const *vst = tport_stun_server_vtable;
+
+ if (mr->mr_stun_server) {
+ assert(vst);
+ vst->vst_destroy(mr->mr_stun_server), mr->mr_stun_server = NULL;
+ }
+}
+
+int tport_stun_server_add_socket(tport_t *tp)
+{
+ tport_stun_server_t *stun_server = tp->tp_master->mr_stun_server;
+
+ if (tport_stun_server_vtable &&
+ stun_server &&
+ tp->tp_params->tpp_stun_server) {
+ if (tport_stun_server_vtable->vst_add_socket(stun_server,
+ tp->tp_socket) == 0)
+ tp->tp_has_stun_server = 1;
+ }
+ return 0;
+}
+
+int tport_stun_server_remove_socket(tport_t *tp)
+{
+ tport_stun_server_t *stun_server = tp->tp_master->mr_stun_server;
+
+ if (tport_stun_server_vtable &&
+ stun_server &&
+ tp->tp_has_stun_server) {
+ tport_stun_server_vtable->vst_remove_socket(stun_server, tp->tp_socket);
+ tp->tp_has_stun_server = 0;
+ }
+ return 0;
+}
+
+/**Process stun messagee.
+ *
+ * @retval -1 error
+ * @retval 3 stun message received, ignore
+ */
+int tport_recv_stun_dgram(tport_t const *self,
+ msg_t **in_out_msg,
+ su_sockaddr_t *from,
+ socklen_t fromlen)
+{
+ int retval = -1;
+ msg_t *msg;
+ uint8_t *request;
+ size_t n;
+
+ assert(in_out_msg); assert(*in_out_msg);
+
+ msg = *in_out_msg;
+
+ request = msg_buf_committed_data(msg);
+ n = msg_buf_committed(msg);
+
+ if (n < 20 || request == NULL) {
+ su_seterrno(EBADMSG);
+ retval = -1;
+ }
+ else if (request[0] == 1) {
+ /* This is a response. */
+ if (self->tp_pri->pri_vtable->vtp_stun_response) {
+ if (self->tp_pri->pri_vtable->vtp_stun_response(self, request, n,
+ from, fromlen) < 0)
+ retval = -1;
+ }
+ else
+ SU_DEBUG_7(("tport(%p): recv_stun_dgram(): "
+ "ignoring request with "MOD_ZU" bytes\n", self, n));
+ }
+ else if (request[0] == 0 && self->tp_master->mr_stun_server) {
+ tport_stun_server_vtable_t const *vst = tport_stun_server_vtable;
+ vst->vst_request(self->tp_master->mr_stun_server,
+ self->tp_socket, request, n,
+ (void *)from, fromlen);
+ }
+ else if (request[0] == 0) {
+ /* Respond to stun request with a simple error message. */
+ int const status = 600;
+ char const *error = "Not Implemented";
+ size_t unpadded = strlen(error);
+ uint16_t elen;
+ uint8_t dgram[128];
+
+ if (unpadded > sizeof(dgram) - 28)
+ unpadded = sizeof(dgram) - 28;
+
+ elen = (uint16_t)unpadded;
+ elen = (elen + 3) & -4; /* Round up to 4 */
+
+ SU_DEBUG_7(("tport(%p): recv_stun_dgram(): "
+ "responding %u %s\n", self, status, error));
+ /*
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | STUN Message Type | Message Length |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ Transaction ID
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+#define set16(b, offset, value) \
+ (((b)[(offset) + 0] = ((value) >> 8) & 255), \
+ ((b)[(offset) + 1] = (value) & 255))
+
+ /* Respond to request */
+ dgram[0] = 1; /* Mark as response */
+ dgram[1] = request[1] | 0x10; /* Mark as error response */
+ set16(dgram, 2, elen + 4 + 4);
+
+ /* TransactionID is there at bytes 4..19 */
+ memcpy(dgram + 4, request + 4, 16);
+
+ /*
+ TLV At 20:
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Type | Length |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ set16(dgram, 20, 0x0009); /* ERROR-CODE */
+ set16(dgram, 22, elen + 4);
+ /*
+ ERROR-CODE at 24:
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | 0 |Class| Number |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Reason Phrase (variable) ..
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ dgram[24] = 0, dgram[25] = 0;
+ dgram[26] = status / 100, dgram[27] = status % 100;
+ memcpy(dgram + 28, error, unpadded);
+ memset(dgram + 28 + unpadded, 0, elen - unpadded);
+
+ sendto(self->tp_socket, (void *)dgram, 28 + elen, 0,
+ (void *)from, fromlen);
+#undef set16
+ }
+ else {
+ SU_DEBUG_0(("tport(%p): recv_stun_dgram(): internal error\n", self));
+ su_seterrno(EBADMSG);
+ retval = -1;
+ }
+
+ *in_out_msg = NULL, msg_destroy(msg);
+
+ return retval;
+}
+
+
+/** Activate (STUN) keepalive for transport */
+int tport_keepalive(tport_t *tp, su_addrinfo_t const *ai,
+ tag_type_t tag, tag_value_t value, ...)
+{
+ if (tp && tp->tp_pri && tp->tp_pri->pri_vtable->vtp_keepalive) {
+ int retval;
+ ta_list ta;
+ ta_start(ta, tag, value);
+ retval = tp->tp_pri->pri_vtable->vtp_keepalive(tp, ai, ta_args(ta));
+ ta_end(ta);
+ return retval;
+ }
+ return -1;
+}
+
+/* ---------------------------------------------------------------------- */
+/* Plugin interface */
+
+/** Plug in stun server.
+ *
+ * @note This function @b must be called before any transport is initialized.
+ */
+int tport_plug_in_stun_server(tport_stun_server_vtable_t const *vtable)
+{
+ if (!vtable)
+ return 0;
+
+ if (vtable->vst_size <= (int)sizeof *vtable)
+ return su_seterrno(EINVAL);
+
+ if (!vtable->vst_create ||
+ !vtable->vst_destroy ||
+ !vtable->vst_add_socket ||
+ !vtable->vst_remove_socket ||
+ !vtable->vst_request)
+ return su_seterrno(EFAULT);
+
+ if (tport_stun_server_vtable)
+ return su_seterrno(EEXIST);
+
+ tport_stun_server_vtable = vtable;
+
+ return 0;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_tag.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_tag.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,80 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE tport_tag.c
+ * @brief Tags for transport module
+ *
+ * @note This file is used to automatically generate
+ * tport_tag_ref.c and tport_tag_dll.c
+ *
+ * Copyright (c) 2002 Nokia Research Center. All rights reserved.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Jun 6 00:38:07 2002 ppessi
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <assert.h>
+
+#define TAG_NAMESPACE "tp"
+
+#include "sofia-sip/tport.h"
+#include <sofia-sip/su_tag_class.h>
+
+/* ==== Globals ========================================================== */
+
+/** Filter for tport tags. */
+tagi_t tport_tags[] = { { tptag_any, 0 }, { TAG_END() } };
+
+tag_typedef_t tptag_any = NSTAG_TYPEDEF(*);
+
+tag_typedef_t tptag_ident = CSTRTAG_TYPEDEF(ident);
+tag_typedef_t tptag_reuse = BOOLTAG_TYPEDEF(reuse);
+tag_typedef_t tptag_fresh = BOOLTAG_TYPEDEF(fresh);
+tag_typedef_t tptag_server = BOOLTAG_TYPEDEF(server);
+tag_typedef_t tptag_public = INTTAG_TYPEDEF(public);
+tag_typedef_t tptag_mtu = USIZETAG_TYPEDEF(mtu);
+tag_typedef_t tptag_connect = BOOLTAG_TYPEDEF(connect);
+tag_typedef_t tptag_sdwn_error = BOOLTAG_TYPEDEF(sdwn_error);
+tag_typedef_t tptag_sdwn_after = BOOLTAG_TYPEDEF(sdwn_after);
+tag_typedef_t tptag_close_after = BOOLTAG_TYPEDEF(sdwn_after);
+tag_typedef_t tptag_idle = UINTTAG_TYPEDEF(idle);
+tag_typedef_t tptag_timeout = UINTTAG_TYPEDEF(timeout);
+tag_typedef_t tptag_sigcomp_lifetime = UINTTAG_TYPEDEF(sigcomp_lifetime);
+tag_typedef_t tptag_certificate = STRTAG_TYPEDEF(certificate);
+tag_typedef_t tptag_compartment = PTRTAG_TYPEDEF(compartment);
+
+tag_typedef_t tptag_tls_version = UINTTAG_TYPEDEF(tls_version);
+tag_typedef_t tptag_queuesize = UINTTAG_TYPEDEF(queuesize);
+tag_typedef_t tptag_debug_drop = UINTTAG_TYPEDEF(debug_drop);
+tag_typedef_t tptag_udp_rmem = UINTTAG_TYPEDEF(udp_rmem);
+tag_typedef_t tptag_udp_wmem = UINTTAG_TYPEDEF(udp_wmem);
+tag_typedef_t tptag_thrpsize = UINTTAG_TYPEDEF(thrpsize);
+tag_typedef_t tptag_thrprqsize = UINTTAG_TYPEDEF(thrprqsize);
+tag_typedef_t tptag_http_connect = STRTAG_TYPEDEF(http_connect);
+tag_typedef_t tptag_stun_server = BOOLTAG_TYPEDEF(stun_server);
+tag_typedef_t tptag_tos = INTTAG_TYPEDEF(tos);
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_threadpool.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_threadpool.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,812 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE tport_threadpool.c Multithreading transport
+ *
+ * See tport.docs for more detailed description of tport interface.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ *
+ * @date Created: Fri Mar 24 08:45:49 EET 2006 ppessi
+ */
+
+#include "config.h"
+
+#undef HAVE_SIGCOMP
+
+#define SU_ROOT_MAGIC_T struct tport_threadpool
+#define SU_WAKEUP_ARG_T struct tport_s
+#define SU_MSG_ARG_T union tport_su_msg_arg
+
+#include "tport_internal.h"
+
+#include <stdlib.h>
+#include <time.h>
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+static char const __func__[] = "tport_threadpool";
+#endif
+
+/* ==== Thread pools =================================================== */
+
+typedef struct threadpool threadpool_t;
+
+typedef struct {
+ tport_primary_t tptp_primary;
+ threadpool_t *tptp_pool; /**< Worker threads */
+ unsigned tptp_poolsize;
+} tport_threadpool_t;
+
+struct threadpool
+{
+ /* Shared */
+ su_clone_r thrp_clone;
+ tport_threadpool_t *thrp_tport;
+
+ int thrp_killing; /* Threadpool is being killed */
+
+ /* Private variables */
+ su_root_t *thrp_root;
+ int thrp_reg;
+ struct sigcomp_compartment *thrp_compartment;
+ su_msg_r thrp_rmsg;
+
+ /* Slave thread counters */
+ int thrp_r_sent;
+ int thrp_s_recv;
+
+ unsigned thrp_rcvd_msgs;
+ unsigned thrp_rcvd_bytes;
+
+ /* Master thread counters */
+ int thrp_s_sent;
+ int thrp_r_recv;
+
+ int thrp_yield;
+};
+
+typedef struct
+{
+ threadpool_t *tpd_thrp;
+ int tpd_errorcode;
+ msg_t *tpd_msg;
+ su_time_t tpd_when;
+ unsigned tpd_mtu;
+#if HAVE_SIGCOMP
+ struct sigcomp_compartment *tpd_cc;
+#endif
+ struct sigcomp_udvm *tpd_udvm;
+ socklen_t tpd_namelen;
+ su_sockaddr_t tpd_name[1];
+} thrp_udp_deliver_t;
+
+union tport_su_msg_arg
+{
+ threadpool_t *thrp;
+ thrp_udp_deliver_t thrp_udp_deliver[1];
+};
+
+int tport_threadpool_init_primary(tport_primary_t *,
+ tp_name_t tpn[1],
+ su_addrinfo_t *,
+ tagi_t const *,
+ char const **return_culprit);
+static void tport_threadpool_deinit_primary(tport_primary_t *pri);
+
+static int tport_thread_send(tport_t *tp,
+ msg_t *msg,
+ tp_name_t const *tpn,
+ struct sigcomp_compartment *cc,
+ unsigned mtu);
+
+tport_vtable_t const tport_threadpool_vtable =
+{
+ "udp", tport_type_local,
+ sizeof (tport_threadpool_t),
+ tport_threadpool_init_primary,
+ tport_threadpool_deinit_primary,
+ NULL,
+ NULL,
+ 0, /* No secondary transports! */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ tport_recv_dgram,
+ tport_send_dgram,
+ NULL,
+ tport_thread_send
+};
+
+static int thrp_udp_init(su_root_t *, threadpool_t *);
+static void thrp_udp_deinit(su_root_t *, threadpool_t *);
+static int thrp_udp_event(threadpool_t *thrp,
+ su_wait_t *w,
+ tport_t *_tp);
+static int thrp_udp_recv_deliver(threadpool_t *thrp,
+ tport_t const *tp,
+ thrp_udp_deliver_t *tpd,
+ int events);
+static int thrp_udp_recv(threadpool_t *thrp, thrp_udp_deliver_t *tpd);
+#if HAVE_SIGCOMP
+static int thrp_udvm_decompress(threadpool_t *thrp,
+ thrp_udp_deliver_t *tpd);
+#endif
+static void thrp_udp_deliver(threadpool_t *thrp,
+ su_msg_r msg,
+ union tport_su_msg_arg *arg);
+static void thrp_udp_deliver_report(threadpool_t *thrp,
+ su_msg_r m,
+ union tport_su_msg_arg *arg);
+static void thrp_udp_send(threadpool_t *thrp,
+ su_msg_r msg,
+ union tport_su_msg_arg *arg);
+static void thrp_udp_send_report(threadpool_t *thrp,
+ su_msg_r msg,
+ union tport_su_msg_arg *arg);
+
+
+/** Launch threads in the tport pool. */
+int tport_threadpool_init_primary(tport_primary_t *pri,
+ tp_name_t tpn[1],
+ su_addrinfo_t *ai,
+ tagi_t const *tags,
+ char const **return_culprit)
+{
+ tport_threadpool_t *tptp = (tport_threadpool_t *)pri;
+ tport_t *tp = pri->pri_primary;
+ threadpool_t *thrp;
+ int i, N = tp->tp_params->tpp_thrpsize;
+
+ assert(ai->ai_socktype == SOCK_DGRAM);
+
+ if (tport_udp_init_primary(pri, tpn, ai, tags, return_culprit) < 0)
+ return -1;
+
+ if (N == 0)
+ return 0;
+
+ thrp = su_zalloc(tp->tp_home, (sizeof *thrp) * N);
+ if (!thrp)
+ return -1;
+
+ su_setblocking(tp->tp_socket, 0);
+
+ tptp->tptp_pool = thrp;
+ tptp->tptp_poolsize = N;
+
+ for (i = 0; i < N; i++) {
+#if HAVE_SIGCOMP
+ if (tport_has_sigcomp(tp))
+ thrp[i].thrp_compartment = tport_primary_compartment(tp->tp_master);
+#endif
+ thrp[i].thrp_tport = tptp;
+ if (su_clone_start(pri->pri_master->mr_root,
+ thrp[i].thrp_clone,
+ thrp + i,
+ thrp_udp_init,
+ thrp_udp_deinit) < 0)
+ goto error;
+ }
+
+ tp->tp_events = 0;
+
+ return 0;
+
+ error:
+ assert(!"tport_launch_threadpool");
+ return -1;
+}
+
+/** Kill threads in the tport pool.
+ *
+ * @note Executed by stack thread only.
+ */
+static
+void tport_threadpool_deinit_primary(tport_primary_t *pri)
+{
+ tport_threadpool_t *tptp = (tport_threadpool_t *)pri;
+ threadpool_t *thrp = tptp->tptp_pool;
+ int i, N = pri->tptp_poolsize;
+
+ if (!thrp)
+ return;
+
+ /* Prevent application from using these. */
+ for (i = 0; i < N; i++)
+ thrp[i].thrp_killing = 1;
+
+ /* Stop every task in the threadpool. */
+ for (i = 0; i < N; i++)
+ su_clone_wait(pri->pri_master->mr_root, thrp[i].thrp_clone);
+
+ su_free(pri->pri_home, tptp), tptp->tptp_pool = NULL;
+ tptp->tptp_poolsize = 0;
+
+ SU_DEBUG_3(("%s(%p): zapped threadpool\n", __func__, pri));
+}
+
+static int thrp_udp_init(su_root_t *root, threadpool_t *thrp)
+{
+ tport_t *tp = thrp->thrp_tport->tptp_primary->pri_primary;
+ su_wait_t wait[1];
+
+ assert(tp);
+
+ thrp->thrp_root = root;
+
+ if (su_wait_create(wait, tp->tp_socket, SU_WAIT_IN | SU_WAIT_ERR) < 0)
+ return -1;
+
+ thrp->thrp_reg = su_root_register(root, wait, thrp_udp_event, tp, 0);
+
+ if (thrp->thrp_reg == -1)
+ return -1;
+
+ return 0;
+}
+
+static void thrp_udp_deinit(su_root_t *root, threadpool_t *thrp)
+{
+ if (thrp->thrp_reg)
+ su_root_deregister(root, thrp->thrp_reg), thrp->thrp_reg = 0;
+ su_msg_destroy(thrp->thrp_rmsg);
+}
+
+static inline void
+thrp_yield(threadpool_t *thrp)
+{
+ tport_t *tp = thrp->thrp_tport->tptp_primary->pri_primary;
+ su_root_eventmask(thrp->thrp_root, thrp->thrp_reg, tp->tp_socket, 0);
+ thrp->thrp_yield = 1;
+}
+
+static inline void
+thrp_gain(threadpool_t *thrp)
+{
+ tport_t *tp = thrp->thrp_tport->tptp_primary->pri_primary;
+ int events = SU_WAIT_IN | SU_WAIT_ERR;
+ su_root_eventmask(thrp->thrp_root, thrp->thrp_reg, tp->tp_socket, events);
+ thrp->thrp_yield = 0;
+}
+
+static int thrp_udp_event(threadpool_t *thrp,
+ su_wait_t *w,
+ tport_t *tp)
+{
+#if HAVE_POLL
+ assert(w->fd == tp->tp_socket);
+#endif
+
+ for (;;) {
+ thrp_udp_deliver_t *tpd;
+ int events;
+
+ if (!*thrp->thrp_rmsg) {
+ if (su_msg_create(thrp->thrp_rmsg,
+ su_root_parent(thrp->thrp_root),
+ su_root_task(thrp->thrp_root),
+ thrp_udp_deliver,
+ sizeof (*tpd)) == -1) {
+ SU_DEBUG_1(("thrp_udp_event(%p): su_msg_create(): %s\n", thrp,
+ strerror(errno)));
+ return 0;
+ }
+ }
+
+ tpd = su_msg_data(thrp->thrp_rmsg)->thrp_udp_deliver; assert(tpd);
+ tpd->tpd_thrp = thrp;
+
+ events = su_wait_events(w, tp->tp_socket);
+ if (!events)
+ return 0;
+
+ thrp_udp_recv_deliver(thrp, tp, tpd, events);
+
+ if (*thrp->thrp_rmsg) {
+ SU_DEBUG_7(("thrp_udp_event(%p): no msg sent\n", thrp));
+ tpd = su_msg_data(thrp->thrp_rmsg)->thrp_udp_deliver;
+ memset(tpd, 0, sizeof *tpd);
+ return 0;
+ }
+
+ if (thrp->thrp_yield || (thrp->thrp_s_sent - thrp->thrp_s_recv) > 0)
+ return 0;
+
+ su_wait(w, 1, 0);
+ }
+}
+
+static int thrp_udp_recv_deliver(threadpool_t *thrp,
+ tport_t const *tp,
+ thrp_udp_deliver_t *tpd,
+ int events)
+{
+ unsigned qlen = thrp->thrp_r_sent - thrp->thrp_r_recv;
+
+ SU_DEBUG_7(("thrp_udp_event(%p): events%s%s%s%s for %p\n", thrp,
+ events & SU_WAIT_IN ? " IN" : "",
+ events & SU_WAIT_HUP ? " HUP" : "",
+ events & SU_WAIT_OUT ? " OUT" : "",
+ events & SU_WAIT_ERR ? " ERR" : "",
+ tpd));
+
+ if (events & SU_WAIT_ERR) {
+ tpd->tpd_errorcode = tport_udp_error(tp, tpd->tpd_name);
+ if (tpd->tpd_errorcode) {
+ if (thrp->thrp_yield)
+ su_msg_report(thrp->thrp_rmsg, thrp_udp_deliver_report);
+ tpd->tpd_when = su_now();
+ su_msg_send(thrp->thrp_rmsg);
+ thrp->thrp_r_sent++;
+ return 0;
+ }
+ }
+
+ if (events & SU_WAIT_IN) {
+ if (thrp_udp_recv(thrp, tpd) < 0) {
+ tpd->tpd_errorcode = su_errno();
+ assert(tpd->tpd_errorcode);
+ if (su_is_blocking(tpd->tpd_errorcode))
+ return 0;
+ }
+ else if (tpd->tpd_msg) {
+ int n = msg_extract(tpd->tpd_msg); (void)n;
+
+ thrp->thrp_rcvd_msgs++;
+ thrp->thrp_rcvd_bytes += msg_size(tpd->tpd_msg);
+ }
+
+#if HAVE_SIGCOMP
+ if (tpd->tpd_udvm && !tpd->tpd_msg)
+ sigcomp_udvm_free(tpd->tpd_udvm), tpd->tpd_udvm = NULL;
+#endif
+
+ assert(!tpd->tpd_msg || !tpd->tpd_errorcode);
+
+ if (tpd->tpd_msg || tpd->tpd_errorcode) {
+ if (qlen >= tp->tp_params->tpp_thrprqsize) {
+ SU_DEBUG_7(("tport recv queue %i: %u\n",
+ (int)(thrp - tp->tp_pri->tptp_pool), qlen));
+ thrp_yield(thrp);
+ }
+
+ if (qlen >= tp->tp_params->tpp_thrprqsize / 2)
+ su_msg_report(thrp->thrp_rmsg, thrp_udp_deliver_report);
+ tpd->tpd_when = su_now();
+ su_msg_send(thrp->thrp_rmsg);
+ thrp->thrp_r_sent++;
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+#include <pthread.h>
+
+/** Mutex for reading from socket */
+static pthread_mutex_t mutex[1] = { PTHREAD_MUTEX_INITIALIZER };
+
+/** Receive a UDP packet by threadpool. */
+static
+int thrp_udp_recv(threadpool_t *thrp, thrp_udp_deliver_t *tpd)
+{
+ tport_t const *tp = thrp->thrp_tport->pri_primary;
+ unsigned char sample[2];
+ int N;
+ int s = tp->tp_socket;
+
+ pthread_mutex_lock(mutex);
+
+ /* Simulate packet loss */
+ if (tp->tp_params->tpp_drop &&
+ su_randint(0, 1000) < tp->tp_params->tpp_drop) {
+ recv(s, sample, 1, 0);
+ pthread_mutex_unlock(mutex);
+ SU_DEBUG_3(("tport(%p): simulated packet loss!\n", tp));
+ return 0;
+ }
+
+ /* Peek for first two bytes in message:
+ determine if this is stun, sigcomp or sip
+ */
+ N = recv(s, sample, sizeof sample, MSG_PEEK | MSG_TRUNC);
+
+ if (N < 0) {
+ if (su_is_blocking(su_errno()))
+ N = 0;
+ }
+ else if (N <= 1) {
+ SU_DEBUG_1(("%s(%p): runt of %u bytes\n", "thrp_udp_recv", thrp, N));
+ recv(s, sample, sizeof sample, 0);
+ N = 0;
+ }
+#if !HAVE_MSG_TRUNC
+ else if ((N = su_getmsgsize(tp->tp_socket)) < 0)
+ ;
+#endif
+ else if ((sample[0] & 0xf8) == 0xf8) {
+#if HAVE_SIGCOMP
+ if (thrp->thrp_compartment) {
+ struct sigcomp_buffer *input;
+ void *data;
+ int dlen;
+
+ tpd->tpd_udvm =
+ sigcomp_udvm_create_for_compartment(thrp->thrp_compartment);
+ input = sigcomp_udvm_input_buffer(tpd->tpd_udvm, N); assert(input);
+
+ data = input->b_data + input->b_avail;
+ dlen = input->b_size - input->b_avail;
+
+ if (dlen < N)
+ dlen = 0;
+
+ tpd->tpd_namelen = sizeof(tpd->tpd_name);
+
+ dlen = recvfrom(tp->tp_socket, data, dlen, 0,
+ &tpd->tpd_name->su_sa, &tpd->tpd_namelen);
+
+ SU_CANONIZE_SOCKADDR(tpd->tpd_name);
+
+ if (dlen < N) {
+ su_seterrno(EMSGSIZE); /* Protocol error */
+ N = -1;
+ } else if (dlen == -1)
+ N = -1;
+ else {
+ input->b_avail += dlen;
+ input->b_complete = 1;
+
+ pthread_mutex_unlock(mutex);
+
+ N = thrp_udvm_decompress(thrp, tpd);
+
+ if (N == -1)
+ /* Do not report decompression errors as ICMP errors */
+ memset(tpd->tpd_name, 0, tpd->tpd_namelen);
+
+ return N;
+ }
+ pthread_mutex_unlock(mutex);
+ return N;
+ }
+#endif
+ recv(s, sample, 1, 0);
+ pthread_mutex_unlock(mutex);
+ /* XXX - send NACK ? */
+ su_seterrno(EBADMSG);
+ N = -1;
+ }
+ else {
+ /* receive as usual */
+ N = tport_recv_dgram_r(tp, &tpd->tpd_msg, N);
+ }
+
+ pthread_mutex_unlock(mutex);
+
+ return N;
+}
+
+#if HAVE_SIGCOMP
+static
+int thrp_udvm_decompress(threadpool_t *thrp, thrp_udp_deliver_t *tpd)
+{
+ struct sigcomp_udvm *udvm = tpd->tpd_udvm;
+ struct sigcomp_buffer *output;
+ msg_iovec_t iovec[msg_n_fragments] = {{ 0 }};
+ su_addrinfo_t *ai;
+ tport_t *tp = thrp->thrp_tport->pri_primary;
+ size_t n, m, i, dlen;
+ int eos;
+ void *data;
+ ssize_t veclen;
+
+ output = sigcomp_udvm_output_buffer(udvm, -1);
+
+ if (sigcomp_udvm_decompress(udvm, output, NULL) < 0) {
+ int error = sigcomp_udvm_errno(udvm);
+ SU_DEBUG_3(("%s: UDVM error %d: %s\n", __func__,
+ error, sigcomp_udvm_strerror(udvm)));
+ su_seterrno(EREMOTEIO);
+ return -1;
+ }
+
+ data = output->b_data + output->b_used;
+ dlen = output->b_avail - output->b_used;
+ /* XXX - if a message is larger than default output size... */
+ eos = output->b_complete; assert(output->b_complete);
+
+ veclen = tport_recv_iovec(tp, &tpd->tpd_msg, iovec, dlen, eos);
+
+ if (veclen <= 0) {
+ n = -1;
+ } else {
+ for (i = 0, n = 0; i < veclen; i++) {
+ m = iovec[i].mv_len; assert(dlen >= n + m);
+ memcpy(iovec[i].mv_base, data + n, m);
+ n += m;
+ }
+ assert(dlen == n);
+
+ msg_recv_commit(tpd->tpd_msg, dlen, eos); /* Mark buffer as used */
+
+ /* Message address */
+ ai = msg_addrinfo(tpd->tpd_msg);
+ ai->ai_flags |= TP_AI_COMPRESSED;
+ ai->ai_family = tpd->tpd_name->su_sa.sa_family;
+ ai->ai_socktype = SOCK_DGRAM;
+ ai->ai_protocol = IPPROTO_UDP;
+ memcpy(ai->ai_addr, tpd->tpd_name, ai->ai_addrlen = tpd->tpd_namelen);
+
+ SU_DEBUG_9(("%s(%p): sigcomp msg sz = %d\n", __func__, tp, n));
+ }
+
+ return n;
+}
+#endif
+
+/** Deliver message from threadpool to the stack
+ *
+ * @note Executed by stack thread only.
+ */
+static
+void thrp_udp_deliver(su_root_magic_t *magic,
+ su_msg_r m,
+ union tport_su_msg_arg *arg)
+{
+ thrp_udp_deliver_t *tpd = arg->thrp_udp_deliver;
+ threadpool_t *thrp = tpd->tpd_thrp;
+ tport_t *tp = thrp->thrp_tport->pri_primary;
+ su_time_t now = su_now();
+
+ assert(magic != thrp);
+
+ thrp->thrp_r_recv++;
+
+ if (thrp->thrp_killing) {
+#if HAVE_SIGCOMP
+ sigcomp_udvm_free(tpd->tpd_udvm), tpd->tpd_udvm = NULL;
+#endif
+ msg_destroy(tpd->tpd_msg);
+ return;
+ }
+
+ SU_DEBUG_7(("thrp_udp_deliver(%p): got %p delay %f\n",
+ thrp, tpd, 1000 * su_time_diff(now, tpd->tpd_when)));
+
+ if (tpd->tpd_errorcode)
+ tport_error_report(tp, tpd->tpd_errorcode, tpd->tpd_name);
+ else if (tpd->tpd_msg) {
+ tport_deliver(tp, tpd->tpd_msg, NULL, &tpd->tpd_udvm, tpd->tpd_when);
+ tp->tp_rlogged = NULL;
+ }
+
+#if HAVE_SIGCOMP
+ if (tpd->tpd_udvm) {
+ sigcomp_udvm_free(tpd->tpd_udvm), tpd->tpd_udvm = NULL;
+ }
+#endif
+}
+
+static
+void thrp_udp_deliver_report(threadpool_t *thrp,
+ su_msg_r m,
+ union tport_su_msg_arg *arg)
+{
+ if (thrp->thrp_yield) {
+ int qlen = thrp->thrp_r_sent - thrp->thrp_r_recv;
+ int qsize = thrp->thrp_tport->pri_params->tpp_thrprqsize;
+ if (qlen == 0 || qlen < qsize / 2)
+ thrp_gain(thrp);
+ }
+}
+
+/** Send a message to network using threadpool.
+ *
+ * @note Executed by stack thread only.
+ */
+static
+int tport_thread_send(tport_t *tp,
+ msg_t *msg,
+ tp_name_t const *tpn,
+ struct sigcomp_compartment *cc,
+ unsigned mtu)
+{
+
+ threadpool_t *thrp = tp->tp_pri->tptp_pool;
+ thrp_udp_deliver_t *tpd;
+ int i, N = tp->tp_pri->tptp_poolsize;
+ su_msg_r m;
+ unsigned totalqlen = 0;
+ unsigned qlen;
+
+ if (!tp->tp_pri->tptp_pool)
+ return tport_prepare_and_send(tp, msg, tpn, cc, mtu);
+
+ SU_DEBUG_9(("tport_thread_send()\n"));
+
+ if (thrp->thrp_killing)
+ return (su_seterrno(ECHILD)), -1;
+
+ qlen = totalqlen = thrp->thrp_s_sent - thrp->thrp_s_recv;
+
+ /* Select thread with shortest queue */
+ for (i = 1; i < N; i++) {
+ threadpool_t *other = tp->tp_pri->tptp_pool + i;
+ unsigned len = other->thrp_s_sent - other->thrp_s_recv;
+
+ if (len < qlen ||
+ (len == qlen && (other->thrp_s_sent - thrp->thrp_s_sent) < 0))
+ thrp = other, qlen = len;
+
+ totalqlen += len;
+ }
+
+ if (totalqlen >= N * tp->tp_params->tpp_qsize)
+ SU_DEBUG_3(("tport send queue: %u (shortest %u)\n", totalqlen, qlen));
+
+ if (su_msg_create(m,
+ su_clone_task(thrp->thrp_clone),
+ su_root_task(tp->tp_master->mr_root),
+ thrp_udp_send,
+ sizeof (*tpd)) != su_success) {
+ SU_DEBUG_1(("thrp_udp_event(%p): su_msg_create(): %s\n", thrp,
+ strerror(errno)));
+ return -1;
+ }
+
+ tpd = su_msg_data(m)->thrp_udp_deliver;
+ tpd->tpd_thrp = thrp;
+ tpd->tpd_when = su_now();
+ tpd->tpd_mtu = mtu;
+ tpd->tpd_msg = msg_ref_create(msg);
+
+#if HAVE_SIGCOMP
+ tpd->tpd_cc = cc;
+#endif
+
+ su_msg_report(m, thrp_udp_send_report);
+
+ if (su_msg_send(m) == su_success) {
+ thrp->thrp_s_sent++;
+ return 0;
+ }
+
+ msg_ref_destroy(msg);
+ return -1;
+}
+
+/** thrp_udp_send() is run by threadpool to send the message. */
+static
+void thrp_udp_send(threadpool_t *thrp,
+ su_msg_r m,
+ union tport_su_msg_arg *arg)
+{
+ thrp_udp_deliver_t *tpd = arg->thrp_udp_deliver;
+ tport_t *tp = thrp->thrp_tport->pri_primary;
+ msg_t *msg = tpd->tpd_msg;
+ msg_iovec_t *iov, auto_iov[40], *iov0 = NULL;
+ int iovlen, iovused, n;
+
+ assert(thrp == tpd->tpd_thrp);
+
+ thrp->thrp_s_recv++;
+
+ {
+ double delay = 1000 * su_time_diff(su_now(), tpd->tpd_when);
+ if (delay > 100)
+ SU_DEBUG_3(("thrp_udp_deliver(%p): got %p delay %f\n", thrp, tpd, delay));
+ else
+ SU_DEBUG_7(("thrp_udp_deliver(%p): got %p delay %f\n", thrp, tpd, delay));
+ }
+
+ if (!msg) {
+ tpd->tpd_errorcode = EINVAL;
+ return;
+ }
+
+ /* Prepare message for sending - i.e., encode it */
+ if (msg_prepare(msg) < 0) {
+ tpd->tpd_errorcode = errno;
+ return;
+ }
+
+ if (tpd->tpd_mtu != 0 && msg_size(msg) > tpd->tpd_mtu) {
+ tpd->tpd_errorcode = EMSGSIZE;
+ return;
+ }
+
+ /* Use initially the I/O vector from stack */
+ iov = auto_iov, iovlen = sizeof(auto_iov)/sizeof(auto_iov[0]);
+
+ /* Get a iovec for message contents */
+ for (;;) {
+ iovused = msg_iovec(msg, iov, iovlen);
+ if (iovused <= iovlen)
+ break;
+
+ iov = iov0 = realloc(iov0, sizeof(*iov) * iovused);
+ iovlen = iovused;
+
+ if (iov0 == NULL) {
+ tpd->tpd_errorcode = errno;
+ return;
+ }
+ }
+
+ assert(iovused > 0);
+
+ tpd->tpd_when = su_now();
+
+ if (0)
+ ;
+#if HAVE_SIGCOMP
+ else if (tpd->tpd_cc) {
+ tport_sigcomp_t sc[1] = {{ NULL }};
+
+ n = tport_sigcomp_vsend(tp, msg, iov, iovused, tpd->tpd_cc, sc);
+ }
+#endif
+ else
+ n = tport_send_dgram(tp, msg, iov, iovused);
+
+ if (n == -1)
+ tpd->tpd_errorcode = su_errno();
+
+ if (iov0)
+ free(iov0);
+}
+
+static
+void thrp_udp_send_report(su_root_magic_t *magic,
+ su_msg_r msg,
+ union tport_su_msg_arg *arg)
+{
+ thrp_udp_deliver_t *tpd = arg->thrp_udp_deliver;
+ threadpool_t *thrp = tpd->tpd_thrp;
+ tport_t *tp = thrp->thrp_tport->pri_primary;
+
+ assert(magic != thrp);
+
+ SU_DEBUG_7(("thrp_udp_send_report(%p): got %p delay %f\n",
+ thrp, tpd, 1000 * su_time_diff(su_now(), tpd->tpd_when)));
+
+ if (tp->tp_master->mr_log)
+ tport_log_msg(tp, tpd->tpd_msg, "sent", "to", tpd->tpd_when);
+
+ if (tpd->tpd_errorcode)
+ tport_error_report(tp, tpd->tpd_errorcode, msg_addr(tpd->tpd_msg));
+
+ msg_ref_destroy(tpd->tpd_msg);
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_tls.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_tls.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,763 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE tport_tls.c
+ * @brief TLS interface
+ *
+ * @author Mikko Haataja <ext-Mikko.A.Haataja at nokia.com>
+ * @author Pekka Pessi <ext-Pekka.Pessi at nokia.com>
+ *
+ * Copyright 2001, 2002 Nokia Research Center. All rights reserved.
+ *
+ */
+
+#include "config.h"
+
+#define OPENSSL_NO_KRB5 oh-no
+
+#include <openssl/lhash.h>
+#include <openssl/bn.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/pem.h>
+#include <openssl/rand.h>
+#include <openssl/bio.h>
+#include <openssl/opensslv.h>
+
+#include <sofia-sip/su_types.h>
+#include <sofia-sip/su.h>
+#include <sofia-sip/su_wait.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+
+#include "tport_tls.h"
+
+char const tls_version[] = OPENSSL_VERSION_TEXT;
+
+enum { tls_master, tls_slave };
+
+struct tls_s {
+ SSL_CTX *ctx;
+ SSL *con;
+ BIO *bio_con;
+ BIO *bio_err;
+ int type;
+ int verified;
+
+ /* Receiving */
+ int read_events;
+ void *read_buffer;
+ size_t read_buffer_len;
+
+ /* Sending */
+ int write_events;
+ void *write_buffer;
+ size_t write_buffer_len;
+
+ /* Host names */
+ char *hosts[TLS_MAX_HOSTS + 1];
+};
+
+enum { tls_buffer_size = 16384 };
+
+static
+tls_t *tls_create(int type)
+{
+ tls_t *tls = calloc(1, sizeof(*tls));
+
+ if (tls)
+ tls->type = type;
+
+ return tls;
+}
+
+static
+void tls_set_default(tls_issues_t *i)
+{
+ i->verify_depth = i->verify_depth == 0 ? 2 : i->verify_depth;
+ i->cert = i->cert ? i->cert : "agent.pem";
+ i->key = i->key ? i->key : i->cert;
+ i->randFile = i->randFile ? i->randFile : "tls_seed.dat";
+ i->CAfile = i->CAfile ? i->CAfile : "cafile.pem";
+ i->cipher = i->cipher ? i->cipher : "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH";
+ /* Default SIP cipher */
+ /* "RSA-WITH-AES-128-CBC-SHA"; */
+ /* RFC-2543-compatibility ciphersuite */
+ /* TLS_RSA_WITH_3DES_EDE_CBC_SHA; */
+}
+
+static
+int tls_verify_cb(int ok, X509_STORE_CTX *store)
+{
+ char data[256];
+
+ X509 *cert = X509_STORE_CTX_get_current_cert(store);
+ int depth = X509_STORE_CTX_get_error_depth(store);
+ int err = X509_STORE_CTX_get_error(store);
+
+#if nomore
+ 509_NAME_oneline(X509_get_subject_name(cert), data, 256);
+ fprintf(stderr,"depth=%d %s\n",depth,data);
+#endif
+
+ if (!ok)
+ {
+ fprintf(stderr, "-Error with certificate at depth: %i\n", depth);
+ X509_NAME_oneline(X509_get_issuer_name(cert), data, 256);
+ fprintf(stderr, " issuer = %s\n", data);
+ X509_NAME_oneline(X509_get_subject_name(cert), data, 256);
+ fprintf(stderr, " subject = %s\n", data);
+ fprintf(stderr, " err %i:%s\n", err, X509_verify_cert_error_string(err));
+ }
+
+ return 1; /* Always return "ok" */
+}
+
+static
+int tls_init_context(tls_t *tls, tls_issues_t const *ti)
+{
+ static int initialized = 0;
+
+ if (!initialized) {
+ initialized = 1;
+ SSL_library_init();
+ SSL_load_error_strings();
+
+ if (ti->randFile &&
+ !RAND_load_file(ti->randFile, 1024 * 1024)) {
+ if (ti->configured > 1) {
+ BIO_printf(tls->bio_err, "%s: cannot open randFile %s\n",
+ "tls_init_context", ti->randFile);
+ ERR_print_errors(tls->bio_err);
+ }
+ /* errno = EIO; */
+ /* return -1; */
+ }
+ }
+
+ /* Avoid possible SIGPIPE when sending close_notify */
+ signal(SIGPIPE, SIG_IGN);
+
+ if (tls->bio_err == NULL)
+ tls->bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
+
+ if (tls->ctx == NULL) {
+ SSL_METHOD *meth;
+
+ /* meth = SSLv3_method(); */
+ /* meth = SSLv23_method(); */
+
+ if (ti->version)
+ meth = TLSv1_method();
+ else
+ meth = SSLv23_method();
+
+ tls->ctx = SSL_CTX_new(meth);
+ }
+
+ if (tls->ctx == NULL) {
+ ERR_print_errors(tls->bio_err);
+ errno = EIO;
+ return -1;
+ }
+
+ if (!SSL_CTX_use_certificate_file(tls->ctx,
+ ti->cert,
+ SSL_FILETYPE_PEM)) {
+ if (ti->configured > 0) {
+ BIO_printf(tls->bio_err, "%s: invalid certificate: %s\n",
+ "tls_init_context", ti->cert);
+ ERR_print_errors(tls->bio_err);
+#if require_client_certificate
+ errno = EIO;
+ return -1;
+#endif
+ }
+ }
+
+ if (!SSL_CTX_use_PrivateKey_file(tls->ctx,
+ ti->key,
+ SSL_FILETYPE_PEM)) {
+ if (ti->configured > 0) {
+ ERR_print_errors(tls->bio_err);
+#if require_client_certificate
+ errno = EIO;
+ return -1;
+#endif
+ }
+ }
+
+ if (!SSL_CTX_check_private_key(tls->ctx)) {
+ if (ti->configured > 0) {
+ BIO_printf(tls->bio_err,
+ "Private key does not match the certificate public key\n");
+ }
+#if require_client_certificate
+ errno = EIO;
+ return -1;
+#endif
+ }
+
+ if (!SSL_CTX_load_verify_locations(tls->ctx,
+ ti->CAfile,
+ ti->CApath)) {
+ if (ti->configured > 0)
+ ERR_print_errors(tls->bio_err);
+ errno = EIO;
+ return -1;
+ }
+
+ SSL_CTX_set_verify_depth(tls->ctx, ti->verify_depth);
+
+ SSL_CTX_set_verify(tls->ctx,
+ getenv("SSL_VERIFY_PEER") ? SSL_VERIFY_PEER : SSL_VERIFY_NONE
+ /* SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT */,
+ tls_verify_cb);
+
+ if (!SSL_CTX_set_cipher_list(tls->ctx, ti->cipher)) {
+ BIO_printf(tls->bio_err,"error setting cipher list\n");
+ ERR_print_errors(tls->bio_err);
+ errno = EIO;
+ return -1;
+ }
+
+ return 0;
+}
+
+void tls_free(tls_t *tls)
+{
+ int k;
+
+ if (!tls)
+ return;
+
+ if (tls->read_buffer)
+ free(tls->read_buffer), tls->read_buffer = NULL;
+
+ if (tls->con != NULL)
+ SSL_shutdown(tls->con);
+
+ if (tls->ctx != NULL && tls->type != tls_slave)
+ SSL_CTX_free(tls->ctx);
+
+ if (tls->bio_con != NULL)
+ BIO_free(tls->bio_con);
+
+ if (tls->bio_err != NULL && tls->type != tls_slave)
+ BIO_free(tls->bio_err);
+
+ for (k = 0; k < TLS_MAX_HOSTS; k++)
+ free(tls->hosts[k]), tls->hosts[k] = NULL;
+
+ free(tls);
+}
+
+int tls_get_socket(tls_t *tls)
+{
+ int sock = -1;
+
+ if (tls != NULL && tls->bio_con != NULL)
+ BIO_get_fd(tls->bio_con, &sock);
+
+ return sock;
+}
+
+tls_t *tls_init_master(tls_issues_t *ti)
+{
+ /* Default id in case RAND fails */
+ unsigned char sessionId[32] = "sofia/tls";
+ tls_t *tls;
+
+ signal(SIGPIPE, SIG_IGN); /* Ignore spurios SIGPIPE from OpenSSL */
+
+ tls_set_default(ti);
+
+ if (!(tls = tls_create(tls_master)))
+ return NULL;
+
+ if (tls_init_context(tls, ti) < 0) {
+ int err = errno;
+ tls_free(tls);
+ errno = err;
+ return NULL;
+ }
+
+ RAND_pseudo_bytes(sessionId, sizeof(sessionId));
+
+ SSL_CTX_set_session_id_context(tls->ctx,
+ (void*) sessionId,
+ sizeof(sessionId));
+
+ if (ti->CAfile != NULL)
+ SSL_CTX_set_client_CA_list(tls->ctx,
+ SSL_load_client_CA_file(ti->CAfile));
+
+#if 0
+ if (sock != -1) {
+ tls->bio_con = BIO_new_socket(sock, BIO_NOCLOSE);
+
+ if (tls->bio_con == NULL) {
+ BIO_printf(tls->bio_err, "tls_init_master: BIO_new_socket failed\n");
+ ERR_print_errors(tls->bio_err);
+ tls_free(tls);
+ errno = EIO;
+ return NULL;
+ }
+ }
+#endif
+
+ return tls;
+}
+
+#if 0
+#include <poll.h>
+
+static
+int tls_accept(tls_t *tls)
+{
+ int ret = SSL_accept(tls->con);
+ int verify_result;
+
+ if (ret <= 0) {
+ int err = SSL_get_error(tls->con, ret);
+ switch(err) {
+ case SSL_ERROR_WANT_READ:
+ return errno = EAGAIN, tls->read_events = SU_WAIT_IN, 0;
+ case SSL_ERROR_WANT_WRITE:
+ return errno = EAGAIN, tls->read_events = SU_WAIT_OUT, 0;
+
+ default:
+ BIO_printf(tls->bio_err, "SSL_connect failed: %d %s\n",
+ err,
+ ERR_error_string(err, NULL));
+ ERR_print_errors(tls->bio_err);
+ return -1;
+ }
+ }
+
+ verify_result = SSL_get_verify_result(tls->con);
+
+ if (verify_result != X509_V_OK) {
+ BIO_printf(tls->bio_err,
+ "Client certificate doesn't verify: %s\n",
+ X509_verify_cert_error_string(verify_result));
+#if 0
+ tls_free(tls);
+ return NULL;
+#endif
+ }
+
+ if (SSL_get_peer_certificate(tls->con) == NULL) {
+ BIO_printf(tls->bio_err, "Client didn't send certificate\n");
+#if 0
+ tls_free(tls);
+ return NULL;
+#endif
+ }
+
+ return 1;
+}
+#endif
+
+tls_t *tls_clone(tls_t *master, int sock, int accept)
+{
+ tls_t *tls = tls_create(tls_slave);
+
+ if (tls) {
+ tls->ctx = master->ctx;
+ tls->bio_err = master->bio_err;
+
+ if (!(tls->read_buffer = malloc(tls_buffer_size)))
+ free(tls), tls = NULL;
+ }
+ if (!tls)
+ return tls;
+
+ assert(sock != -1);
+
+ tls->bio_con = BIO_new_socket(sock, BIO_NOCLOSE);
+ tls->con = SSL_new(tls->ctx);
+
+ if (tls->con == NULL) {
+ BIO_printf(tls->bio_err, "tls_clone: SSL_new failed\n");
+ ERR_print_errors(tls->bio_err);
+ tls_free(tls);
+ errno = EIO;
+ return NULL;
+ }
+
+ SSL_set_bio(tls->con, tls->bio_con, tls->bio_con);
+ if (accept)
+ SSL_set_accept_state(tls->con);
+ else
+ SSL_set_connect_state(tls->con);
+ SSL_set_mode(tls->con, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+
+ tls_read(tls); /* XXX - works only with non-blocking sockets */
+
+ return tls;
+}
+
+tls_t *tls_init_slave(tls_t *master, int sock)
+{
+ int accept;
+ return tls_clone(master, sock, accept = 1);
+}
+
+tls_t *tls_init_client(tls_t *master, int sock)
+{
+ int accept;
+ return tls_clone(master, sock, accept = 0);
+}
+
+static char *tls_strdup(char const *s)
+{
+ if (s) {
+ size_t len = strlen(s) + 1;
+ char *d = malloc(len);
+ if (d)
+ memcpy(d, s, len);
+ return d;
+ }
+ return NULL;
+}
+
+static
+int tls_post_connection_check(tls_t *tls)
+{
+ X509 *cert;
+ int extcount;
+ int k, i, j, error;
+
+ if (!tls) return -1;
+
+ cert = SSL_get_peer_certificate(tls->con);
+ if (!cert)
+ return X509_V_OK;
+
+ extcount = X509_get_ext_count(cert);
+
+ for (k = 0; k < TLS_MAX_HOSTS && tls->hosts[k]; k++)
+ ;
+
+ /* Find matching subjectAltName.DNS */
+ for (i = 0; i < extcount; i++) {
+ X509_EXTENSION *ext;
+ char const *name;
+ X509V3_EXT_METHOD *vp;
+ STACK_OF(CONF_VALUE) *values;
+ CONF_VALUE *value;
+ void *d2i;
+
+ ext = X509_get_ext(cert, i);
+ name = OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(ext)));
+
+ if (strcmp(name, "subjectAltName") != 0)
+ continue;
+
+ vp = X509V3_EXT_get(ext); if (!vp) continue;
+ d2i = X509V3_EXT_d2i(ext);
+ values = vp->i2v(vp, d2i, NULL);
+
+ for (j = 0; j < sk_CONF_VALUE_num(values); j++) {
+ value = sk_CONF_VALUE_value(values, j);
+ if (strcmp(value->name, "DNS") == 0) {
+ if (k < TLS_MAX_HOSTS) {
+ tls->hosts[k] = tls_strdup(value->value);
+ k += tls->hosts[k] != NULL;
+ }
+ }
+ else if (strcmp(value->name, "URI") == 0) {
+ char const *uri = strchr(value->value, ':');
+ if (uri ++ && k < TLS_MAX_HOSTS) {
+ tls->hosts[k] = tls_strdup(uri);
+ k += tls->hosts[k] != NULL;
+ }
+ }
+ }
+ }
+
+ if (k < TLS_MAX_HOSTS) {
+ X509_NAME *subject;
+ char name[256];
+
+ subject = X509_get_subject_name(cert);
+ if (subject) {
+ if (X509_NAME_get_text_by_NID(subject, NID_commonName,
+ name, sizeof name) > 0) {
+ name[(sizeof name) - 1] = '\0';
+
+ for (i = 0; tls->hosts[i]; i++)
+ if (strcasecmp(tls->hosts[i], name) == 0)
+ break;
+
+ if (i == k)
+ tls->hosts[k++] = tls_strdup(name);
+ }
+ }
+ }
+
+ X509_free(cert);
+
+ error = SSL_get_verify_result(tls->con);
+
+ if (error == X509_V_OK)
+ tls->verified = 1;
+
+ return error;
+}
+
+int tls_check_hosts(tls_t *tls, char const *hosts[TLS_MAX_HOSTS])
+{
+ int i, j;
+
+ if (tls == NULL) { errno = EINVAL; return -1; }
+ if (!tls->verified) { errno = EAGAIN; return -1; }
+
+ if (!hosts)
+ return 0;
+
+ for (i = 0; hosts[i]; i++) {
+ for (j = 0; tls->hosts[j]; j++) {
+ if (strcasecmp(hosts[i], tls->hosts[j]) == 0)
+ break;
+ }
+ if (tls->hosts[j] == NULL) {
+ errno = EACCES;
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static
+int tls_error(tls_t *tls, int ret, char const *who, char const *operation,
+ void *buf, int size)
+{
+ char errorbuf[128];
+ int events = 0;
+ int err = SSL_get_error(tls->con, ret);
+
+ switch (err) {
+ case SSL_ERROR_WANT_WRITE:
+ events = SU_WAIT_OUT;
+ break;
+
+ case SSL_ERROR_WANT_READ:
+ events = SU_WAIT_IN;
+ break;
+
+ case SSL_ERROR_ZERO_RETURN:
+ return 0;
+
+ case SSL_ERROR_SYSCALL:
+ return -1;
+
+ default:
+ BIO_printf(tls->bio_err, "%s: %s failed (%d): %s\n",
+ who, operation, err, ERR_error_string(err, errorbuf));
+ ERR_print_errors(tls->bio_err);
+ errno = EIO;
+ return -1;
+ }
+
+ if (buf) {
+ tls->write_events = events;
+ tls->write_buffer = buf, tls->write_buffer_len = size;
+ }
+ else {
+ tls->read_events = events;
+ }
+
+ errno = EAGAIN;
+ return -1;
+}
+
+ssize_t tls_read(tls_t *tls)
+{
+ ssize_t ret;
+
+ if (tls == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (0)
+ fprintf(stderr, "tls_read(%p) called on %s (events %u)\n", tls,
+ tls->type == tls_slave ? "server" : "client",
+ tls->read_events);
+
+ if (tls->read_buffer_len)
+ return (ssize_t)tls->read_buffer_len;
+
+ tls->read_events = SU_WAIT_IN;
+
+ ret = SSL_read(tls->con, tls->read_buffer, tls_buffer_size);
+ if (ret <= 0)
+ return tls_error(tls, ret, "tls_read", "SSL_read", NULL, 0);
+
+ if (!tls->verified) {
+ int err = tls_post_connection_check(tls);
+
+ if (err != X509_V_OK &&
+ err != SSL_ERROR_SYSCALL &&
+ err != SSL_ERROR_WANT_WRITE &&
+ err != SSL_ERROR_WANT_READ) {
+ BIO_printf(tls->bio_err,
+ "%s: server certificate doesn't verify\n",
+ "tls_read");
+ }
+ }
+
+ return (ssize_t)(tls->read_buffer_len = ret);
+}
+
+void *tls_read_buffer(tls_t *tls, size_t N)
+{
+ assert(N == tls->read_buffer_len);
+ tls->read_buffer_len = 0;
+ return tls->read_buffer;
+}
+
+int tls_pending(tls_t const *tls)
+{
+ return tls && tls->con && SSL_pending(tls->con);
+}
+
+int tls_want_read(tls_t *tls, int events)
+{
+ if (tls && (events & tls->read_events)) {
+ int ret = tls_read(tls);
+
+ if (ret >= 0)
+ return 1;
+ else if (errno == EAGAIN)
+ return 0;
+ else
+ return -1;
+ }
+
+ return 0;
+}
+
+ssize_t tls_write(tls_t *tls, void *buf, size_t size)
+{
+ ssize_t ret;
+
+ if (0)
+ fprintf(stderr, "tls_write(%p, %p, "MOD_ZU") called on %s\n",
+ tls, buf, size,
+ tls && tls->type == tls_slave ? "server" : "client");
+
+ if (tls == NULL || buf == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (tls->write_buffer) {
+ assert(buf == tls->write_buffer);
+ assert(size >= tls->write_buffer_len);
+ assert(tls->write_events == 0);
+
+ if (tls->write_events ||
+ buf != tls->write_buffer ||
+ size < tls->write_buffer_len) {
+ errno = EIO;
+ return -1;
+ }
+
+ ret = tls->write_buffer_len;
+
+ tls->write_buffer = NULL;
+ tls->write_buffer_len = 0;
+
+ return ret;
+ }
+
+ if (size == 0)
+ return 0;
+
+ tls->write_events = 0;
+
+ if (!tls->verified) {
+ if (tls_post_connection_check(tls) != X509_V_OK) {
+ BIO_printf(tls->bio_err,
+ "tls_read: server certificate doesn't verify\n");
+ }
+ }
+
+ ret = SSL_write(tls->con, buf, size);
+ if (ret < 0)
+ return tls_error(tls, ret, "tls_write", "SSL_write", buf, size);
+
+ return ret;
+}
+
+int tls_want_write(tls_t *tls, int events)
+{
+ if (tls && (events & tls->write_events)) {
+ int ret;
+ void *buf = tls->write_buffer;
+ size_t size = tls->write_buffer_len;
+
+ tls->write_events = 0;
+
+ /* remove buf */
+ tls->write_buffer = NULL;
+ tls->write_buffer_len = 0;
+
+ ret = tls_write(tls, buf, size);
+
+ if (ret >= 0)
+ /* Restore buf */
+ return tls->write_buffer = buf, tls->write_buffer_len = ret;
+ else if (errno == EAGAIN)
+ return 0;
+ else
+ return -1;
+ }
+ return 0;
+}
+
+int tls_events(tls_t const *tls, int mask)
+{
+
+ if (!tls)
+ return mask;
+
+ if (tls->type == tls_master)
+ return mask;
+
+ return
+ (mask & ~(SU_WAIT_IN|SU_WAIT_OUT)) |
+ ((mask & SU_WAIT_IN) ? tls->read_events : 0) |
+ ((mask & SU_WAIT_OUT) ? tls->write_events : 0);
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_tls.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_tls.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,82 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef TPORT_TLS_H
+/** Defined when <tport_tls.h> has been included. */
+#define TPORT_TLS_H
+/**@IFILE tport_tls.h
+ * @brief TLS interface
+ *
+ * @author Mikko Haataja <ext-Mikko.A.Haataja at nokia.com>
+ *
+ * Copyright 2001, 2002 Nokia Research Center. All rights reserved.
+ */
+
+#ifndef SU_TYPES_H
+#include <sofia-sip/su_types.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+#define TLS_MAX_HOSTS (16)
+
+typedef struct tls_s tls_t;
+
+extern char const tls_version[];
+
+typedef struct tls_issues_s {
+ int verify_depth; /* if 0, then do nothing */
+ int configured; /* If non-zero, complain about certificate errors */
+ char *cert; /* CERT file name. File format is PEM */
+ char *key; /* Private key file. PEM format */
+ char *randFile; /* Seed file for the PRNG (default: tls_seed.dat) */
+ char *CAfile; /* PEM file of CA's */
+ char *CApath; /* PEM file path of CA's */
+ char *cipher; /* Should be one of the above defined ciphers *
+ * or NULL (default: "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH
+ */
+ int version; /* For tls1, version is 1. When ssl3/ssl2 is
+ * used, it is 0. */
+} tls_issues_t;
+
+tls_t *tls_init_master(tls_issues_t *tls_issues);
+tls_t *tls_init_slave(tls_t *tls_master, int sock);
+tls_t *tls_init_client(tls_t *tls_master, int sock);
+void tls_free(tls_t *tls);
+int tls_get_socket(tls_t *tls);
+ssize_t tls_read(tls_t *tls);
+void *tls_read_buffer(tls_t *tls, size_t N);
+int tls_want_read(tls_t *tls, int events);
+int tls_pending(tls_t const *tls);
+
+ssize_t tls_write(tls_t *tls, void *buf, size_t size);
+int tls_want_write(tls_t *tls, int events);
+
+int tls_check_hosts(tls_t *tls, char const *hosts[TLS_MAX_HOSTS]);
+
+int tls_events(tls_t const *tls, int flags);
+
+SOFIA_END_DECLS
+
+#endif
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_tls_test.sh
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_tls_test.sh Thu Dec 21 01:30:28 2006
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+echo Starting TLS Test Server
+./tport_test_server &
+sleep 1
+./tport_test_client
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_connect.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_connect.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,237 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE tport_type_connect.c Transport using HTTP CONNECT.
+ *
+ * See tport.docs for more detailed description of tport interface.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ *
+ * @date Created: Fri Mar 24 08:45:49 EET 2006 ppessi
+ */
+
+#include "config.h"
+
+#include "tport_internal.h"
+
+#include <stdlib.h>
+#include <time.h>
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+
+/* ---------------------------------------------------------------------- */
+/* TCP using HTTP CONNECT */
+
+#include <sofia-sip/http.h>
+#include <sofia-sip/http_header.h>
+
+static int tport_http_connect_init_primary(tport_primary_t *,
+ tp_name_t tpn[1],
+ su_addrinfo_t *,
+ tagi_t const *,
+ char const **return_culprit);
+
+static void tport_http_connect_deinit_primary(tport_primary_t *);
+
+static tport_t *tport_http_connect(tport_primary_t *pri, su_addrinfo_t *ai,
+ tp_name_t const *tpn);
+
+static void tport_http_deliver(tport_t *self, msg_t *msg, su_time_t now);
+
+typedef struct
+{
+ tport_primary_t thc_primary[1];
+ su_addrinfo_t *thc_proxy;
+} tport_http_connect_t;
+
+typedef struct
+{
+ tport_t thci_tport[1];
+ msg_t *thci_response;
+ msg_t *thci_stackmsg;
+} tport_http_connect_instance_t;
+
+tport_vtable_t const tport_http_connect_vtable =
+{
+ "TCP", tport_type_connect,
+ sizeof (tport_http_connect_t),
+ tport_http_connect_init_primary,
+ tport_http_connect_deinit_primary,
+ NULL,
+ tport_http_connect,
+ sizeof (tport_http_connect_instance_t),
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ tport_recv_stream,
+ tport_send_stream,
+ tport_http_deliver,
+};
+
+static int tport_http_connect_init_primary(tport_primary_t *pri,
+ tp_name_t tpn[1],
+ su_addrinfo_t *ai,
+ tagi_t const *tags,
+ char const **return_culprit)
+{
+ tport_http_connect_t *thc = (tport_http_connect_t *)pri;
+ char const *http_connect = NULL;
+ url_t *http_proxy;
+ int error;
+ char const *host, *port;
+ su_addrinfo_t hints[1];
+
+ tl_gets(tags,
+ TPTAG_HTTP_CONNECT_REF(http_connect),
+ TAG_END());
+ if (!http_connect)
+ return *return_culprit = "missing proxy url", -1;
+
+ http_proxy = url_hdup(pri->pri_home, URL_STRING_MAKE(http_connect)->us_url);
+ if (!http_proxy || !http_proxy->url_host)
+ return *return_culprit = "invalid proxy url", -1;
+
+ host = http_proxy->url_host;
+ port = http_proxy->url_port;
+ if (!port || !port[0])
+ port = "8080";
+
+ memcpy(hints, ai, sizeof hints);
+
+ hints->ai_flags = 0;
+ hints->ai_addr = NULL;
+ hints->ai_addrlen = 0;
+ hints->ai_next = NULL;
+ hints->ai_canonname = NULL;
+
+ error = su_getaddrinfo(host, port, hints, &thc->thc_proxy);
+ if (error)
+ return *return_culprit = "su_getaddrinfo", -1;
+
+ return tport_tcp_init_client(pri, tpn, ai, tags, return_culprit);
+}
+
+static void tport_http_connect_deinit_primary(tport_primary_t *pri)
+{
+ tport_http_connect_t *thc = (tport_http_connect_t *)pri;
+
+ su_freeaddrinfo(thc->thc_proxy), thc->thc_proxy = NULL;
+}
+
+static tport_t *tport_http_connect(tport_primary_t *pri, su_addrinfo_t *ai,
+ tp_name_t const *tpn)
+{
+ tport_http_connect_t *thc = (tport_http_connect_t *)pri;
+ tport_http_connect_instance_t *thci;
+ tport_master_t *mr = pri->pri_master;
+
+ msg_t *msg, *response;
+
+ char hostport[TPORT_HOSTPORTSIZE];
+
+ tport_t *tport;
+ http_request_t *rq;
+
+ msg = msg_create(http_default_mclass(), 0);
+
+ if (!msg)
+ return NULL;
+
+ tport_hostport(hostport, sizeof hostport, (void *)ai->ai_addr, 1);
+
+ rq = http_request_format(msg_home(msg), "CONNECT %s HTTP/1.1", hostport);
+
+ if (msg_header_insert(msg, NULL, (void *)rq) < 0
+ || msg_header_add_str(msg, NULL,
+ "User-Agent: Sofia-SIP/" VERSION "\n") < 0
+ || msg_header_add_str(msg, NULL, "Proxy-Connection: keepalive\n") < 0
+ || msg_header_add_make(msg, NULL, http_host_class, hostport) < 0
+ || msg_header_add_make(msg, NULL, http_separator_class, "\r\n") < 0
+ || msg_serialize(msg, NULL) < 0
+ || msg_prepare(msg) < 0)
+ return (void)msg_destroy(msg), NULL;
+
+ /*
+ * Create a response message that ignores the body
+ * if there is no Content-Length
+ */
+ response = msg_create(http_default_mclass(), mr->mr_log | MSG_FLG_MAILBOX);
+
+ tport = tport_base_connect(pri, thc->thc_proxy, ai, tpn);
+ if (!tport) {
+ msg_destroy(msg); msg_destroy(response);
+ return tport;
+ }
+
+ thci = (tport_http_connect_instance_t*)tport;
+
+ thci->thci_response = response;
+ tport->tp_msg = response;
+ msg_set_next(response, thci->thci_stackmsg = tport_msg_alloc(tport, 512));
+
+ if (tport_send_msg(tport, msg, tpn, NULL) < 0) {
+ SU_DEBUG_9(("tport_send_msg failed in tpot_http_connect\n"));
+ msg_destroy(msg);
+ tport_zap_secondary(tport);
+ return NULL;
+ }
+
+ return tport;
+}
+
+#include <sofia-sip/msg_buffer.h>
+
+static void tport_http_deliver(tport_t *self, msg_t *msg, su_time_t now)
+{
+ tport_http_connect_instance_t *thci = (tport_http_connect_instance_t*)self;
+
+ if (msg && thci->thci_response == msg) {
+ tport_http_connect_t *thc = (tport_http_connect_t *)self->tp_pri;
+ http_t *http = http_object(msg);
+
+ if (http && http->http_status) {
+ SU_DEBUG_0(("tport_http_connect: %u %s\n",
+ http->http_status->st_status,
+ http->http_status->st_phrase));
+ if (http->http_status->st_status < 300) {
+ msg_buf_move(thci->thci_stackmsg, msg);
+ thci->thci_response = NULL;
+ thci->thci_stackmsg = NULL;
+ return;
+ }
+ }
+
+ msg_destroy(msg);
+ thci->thci_response = NULL;
+ tport_error_report(self, EPROTO, (void *)thc->thc_proxy->ai_addr);
+ tport_close(self);
+ return;
+ }
+
+ tport_base_deliver(self, msg, now);
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_sctp.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_sctp.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,262 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE tport_type_sctp.c Transport using SCTP.
+ *
+ * See tport.docs for more detailed description of tport interface.
+ *
+ * @RFC4168.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ *
+ * @date Created: Fri Mar 24 08:45:49 EET 2006 ppessi
+ * @date Original Created: Thu Jul 20 12:54:32 2000 ppessi
+ */
+
+#include "config.h"
+
+#if HAVE_SCTP
+
+#include "tport_internal.h"
+
+#if HAVE_NETINET_SCTP_H
+#include <netinet/sctp.h>
+#undef HAVE_SCTP
+#define HAVE_SCTP 1
+#endif
+
+#include <stdlib.h>
+#include <time.h>
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+
+/* ---------------------------------------------------------------------- */
+/* SCTP */
+
+#undef MAX_STREAMS
+#define MAX_STREAMS MAX_STREAMS
+
+enum { MAX_STREAMS = 1 };
+typedef struct tport_sctp_t
+{
+ tport_t sctp_base[1];
+
+ msg_t *sctp_recv[MAX_STREAMS];
+ struct sctp_send {
+ msg_t *ss_msg;
+ msg_iovec_t *ss_unsent; /**< Pointer to first unsent iovec */
+ unsigned ss_unsentlen; /**< Number of unsent iovecs */
+ msg_iovec_t *ss_iov; /**< Iovecs allocated for sending */
+ unsigned ss_iovlen; /**< Number of allocated iovecs */
+ } sctp_send[MAX_STREAMS];
+} tport_sctp_t;
+
+#define TP_SCTP_MSG_MAX (65536)
+
+static int tport_sctp_init_primary(tport_primary_t *,
+ tp_name_t tpn[1],
+ su_addrinfo_t *, tagi_t const *,
+ char const **return_culprit);
+static int tport_sctp_init_client(tport_primary_t *,
+ tp_name_t tpn[1],
+ su_addrinfo_t *, tagi_t const *,
+ char const **return_culprit);
+static int tport_sctp_init_secondary(tport_t *self, int socket, int accepted,
+ char const **return_reason);
+static int tport_sctp_init_socket(tport_primary_t *pri,
+ int socket,
+ char const **return_reason);
+static int tport_recv_sctp(tport_t *self);
+static int tport_send_sctp(tport_t const *self, msg_t *msg,
+ msg_iovec_t iov[], int iovused);
+
+tport_vtable_t const tport_sctp_client_vtable =
+{
+ "sctp", tport_type_client,
+ sizeof (tport_primary_t),
+ tport_sctp_init_client,
+ NULL,
+ tport_accept,
+ NULL,
+ sizeof (tport_t),
+ tport_sctp_init_secondary,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ tport_recv_sctp,
+ tport_send_sctp,
+};
+
+#undef NEXT_VTABLE
+#define NEXT_VTABLE &tport_sctp_client_vtable
+
+tport_vtable_t const tport_sctp_vtable =
+{
+ "sctp", tport_type_local,
+ sizeof (tport_primary_t),
+ tport_sctp_init_primary,
+ NULL,
+ tport_accept,
+ NULL,
+ sizeof (tport_t),
+ tport_sctp_init_secondary,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ tport_recv_sctp,
+ tport_send_sctp,
+};
+
+#undef NEXT_VTABLE
+#define NEXT_VTABLE &tport_sctp_vtable
+
+static int tport_sctp_init_primary(tport_primary_t *pri,
+ tp_name_t tpn[1],
+ su_addrinfo_t *ai,
+ tagi_t const *tags,
+ char const **return_culprit)
+{
+ int socket;
+
+ if (pri->pri_params->tpp_mtu > TP_SCTP_MSG_MAX)
+ pri->pri_params->tpp_mtu = TP_SCTP_MSG_MAX;
+
+ socket = su_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+
+ if (socket == INVALID_SOCKET)
+ return *return_culprit = "socket", -1;
+
+ if (tport_sctp_init_socket(pri, socket, return_culprit) < 0)
+ return -1;
+
+ return tport_stream_init_primary(pri, socket, tpn, ai, tags, return_culprit);
+}
+
+static int tport_sctp_init_client(tport_primary_t *pri,
+ tp_name_t tpn[1],
+ su_addrinfo_t *ai,
+ tagi_t const *tags,
+ char const **return_culprit)
+{
+ if (pri->pri_params->tpp_mtu > TP_SCTP_MSG_MAX)
+ pri->pri_params->tpp_mtu = TP_SCTP_MSG_MAX;
+
+ return tport_tcp_init_client(pri, tpn, ai, tags, return_culprit);
+}
+
+static int tport_sctp_init_secondary(tport_t *self, int socket, int accepted,
+ char const **return_reason)
+{
+ self->tp_has_connection = 1;
+
+ if (su_setblocking(socket, 0) < 0)
+ return *return_reason = "su_setblocking", -1;
+
+ if (accepted) {
+ /* Accepted socket inherit the init information from listen socket */
+ return 0;
+ }
+ else {
+ return tport_sctp_init_socket(self->tp_pri, socket, return_reason);
+ }
+}
+
+/** Initialize a SCTP socket */
+static int tport_sctp_init_socket(tport_primary_t *pri,
+ int socket,
+ char const **return_reason)
+{
+ struct sctp_initmsg initmsg = { 0 };
+
+ initmsg.sinit_num_ostreams = MAX_STREAMS;
+ initmsg.sinit_max_instreams = MAX_STREAMS;
+
+ if (setsockopt(socket, SOL_SCTP, SCTP_INITMSG, &initmsg, sizeof initmsg) < 0)
+ return *return_reason = "SCTP_INITMSG", -1;
+
+ return 0;
+}
+
+/** Receive data available on the socket.
+ *
+ * @retval -1 error
+ * @retval 0 end-of-stream
+ * @retval 1 normal receive
+ * @retval 2 incomplete recv, recv again
+ */
+static
+int tport_recv_sctp(tport_t *self)
+{
+ msg_t *msg;
+ ssize_t N, veclen;
+ msg_iovec_t iovec[2] = {{ 0 }};
+
+ char sctp_buf[TP_SCTP_MSG_MAX];
+
+ iovec[0].mv_base = sctp_buf;
+ iovec[0].mv_len = sizeof(sctp_buf);
+
+ N = su_vrecv(self->tp_socket, iovec, 1, 0, NULL, NULL);
+ if (N == SOCKET_ERROR) {
+ return su_is_blocking(su_errno()) ? 1 : -1;
+ }
+
+ if (N == 0) {
+ if (self->tp_msg)
+ msg_recv_commit(self->tp_msg, 0, 1);
+ return 0; /* End of stream */
+ }
+
+ veclen = tport_recv_iovec(self, &self->tp_msg, iovec, N, 0);
+ if (veclen < 0)
+ return -1;
+
+ assert(veclen == 1); assert(iovec[0].mv_len == N);
+ msg = self->tp_msg;
+
+ msg_set_address(msg, self->tp_addr, self->tp_addrlen);
+
+ memcpy(iovec[0].mv_base, sctp_buf, iovec[0].mv_len);
+
+ if (self->tp_master->mr_dump_file)
+ tport_dump_iovec(self, msg, N, iovec, veclen, "recv", "from");
+
+ msg_recv_commit(msg, N, 0); /* Mark buffer as used */
+
+ return 2;
+}
+
+static int tport_send_sctp(tport_t const *self, msg_t *msg,
+ msg_iovec_t iov[], int iovused)
+{
+
+
+ return su_vsend(self->tp_socket, iov, iovused, MSG_NOSIGNAL, NULL, 0);
+}
+
+#endif
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_stun.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_stun.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,236 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE tport_type_stun.c Transport using stun.
+ *
+ * See tport.docs for more detailed description of tport interface.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ *
+ * @date Created: Fri Mar 24 08:45:49 EET 2006 ppessi
+ */
+
+#include "config.h"
+
+#define STUN_DISCOVERY_MAGIC_T struct tport_primary
+
+#include "tport_internal.h"
+
+#include <stdlib.h>
+#include <time.h>
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+
+/* ---------------------------------------------------------------------- */
+/* STUN */
+
+#include <sofia-sip/stun.h>
+
+static int tport_udp_init_stun(tport_primary_t *,
+ tp_name_t tpn[1],
+ su_addrinfo_t *,
+ tagi_t const *,
+ char const **return_culprit);
+
+static void tport_udp_deinit_stun(tport_primary_t *pri);
+
+static
+void tport_stun_bind_cb(tport_primary_t *pri,
+ stun_handle_t *sh,
+ stun_discovery_t *sd,
+ stun_action_t action,
+ stun_state_t event);
+static
+void tport_stun_bind_done(tport_primary_t *pri,
+ stun_handle_t *sh,
+ stun_discovery_t *sd);
+static
+int tport_stun_keepalive(tport_t *tp, su_addrinfo_t const *ai,
+ tagi_t const *taglist);
+
+static int tport_stun_response(tport_t const *self,
+ void *dgram, size_t n,
+ void *from, socklen_t fromlen);
+
+tport_vtable_t const tport_stun_vtable =
+{
+ "UDP", tport_type_stun,
+ sizeof (tport_primary_t),
+ tport_udp_init_stun,
+ tport_udp_deinit_stun,
+ NULL,
+ NULL,
+ sizeof (tport_t),
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ tport_recv_dgram,
+ tport_send_dgram,
+ NULL,
+ NULL,
+ tport_stun_keepalive,
+ tport_stun_response
+};
+
+static int tport_udp_init_stun(tport_primary_t *pri,
+ tp_name_t tpn[1],
+ su_addrinfo_t *ai,
+ tagi_t const *tags,
+ char const **return_culprit)
+{
+ stun_handle_t *sh;
+
+#if 0
+ if (!stun_is_requested(TAG_NEXT(tags)))
+ return -1;
+#endif
+
+ sh = stun_handle_init(pri->pri_master->mr_root, TAG_NEXT(tags));
+ if (!sh)
+ return *return_culprit = "stun_handle_init", -1;
+
+ pri->pri_stun_handle = sh;
+ tpn->tpn_canon = NULL;
+
+ if (tport_udp_init_primary(pri, tpn, ai, tags, return_culprit) < 0)
+ return -1;
+
+#if 0
+ if (stun_obtain_shared_secret(sh, tport_stun_tls_cb, pri,
+ TAG_NEXT(tags)) < 0) {
+ return *return_culprit = "stun_request_shared_secret()", -1;
+ }
+#endif
+
+ if (stun_bind(sh, tport_stun_bind_cb, pri,
+ STUNTAG_SOCKET(pri->pri_primary->tp_socket),
+ STUNTAG_REGISTER_EVENTS(0),
+ TAG_NULL()) < 0) {
+ return *return_culprit = "stun_bind()", -1;
+ }
+
+ pri->pri_updating = 1;
+
+ return 0;
+}
+
+
+static void tport_udp_deinit_stun(tport_primary_t *pri)
+{
+ if (pri->pri_stun_handle)
+ stun_handle_destroy(pri->pri_stun_handle);
+ pri->pri_stun_handle = NULL;
+}
+
+
+static int tport_stun_response(tport_t const *self,
+ void *dgram, size_t n,
+ void *from, socklen_t fromlen)
+{
+ stun_process_message(self->tp_pri->pri_stun_handle, self->tp_socket,
+ from, fromlen, (void *)dgram, n);
+
+ return 3;
+}
+
+
+/**Callback for STUN bind */
+static
+void tport_stun_bind_cb(tport_primary_t *pri,
+ stun_handle_t *sh,
+ stun_discovery_t *sd,
+ stun_action_t action,
+ stun_state_t event)
+{
+ tport_master_t *mr;
+ SU_DEBUG_3(("%s: %s\n", __func__, stun_str_state(event)));
+
+ mr = pri->pri_master;
+
+ if (event == stun_discovery_done) {
+ tport_stun_bind_done(pri, sh, sd);
+ }
+}
+
+
+static
+void tport_stun_bind_done(tport_primary_t *pri,
+ stun_handle_t *sh,
+ stun_discovery_t *sd)
+{
+ tport_t *self = pri->pri_primary;
+ su_socket_t socket;
+ su_sockaddr_t *su = self->tp_addr;
+ su_addrinfo_t *ai = self->tp_addrinfo;
+
+ socket = stun_discovery_get_socket(sd);
+ assert(pri->pri_primary->tp_socket == socket);
+
+ if (stun_discovery_get_address(sd, su, &ai->ai_addrlen) == 0) {
+ char ipname[SU_ADDRSIZE + 2] = { 0 };
+ ai->ai_addr = (void *)su;
+
+ SU_DEBUG_5(("%s: stun_bind() ok: local address NATed as %s:%u\n",
+ __func__,
+ inet_ntop(su->su_family, SU_ADDR(su), ipname, sizeof(ipname)),
+ (unsigned) ntohs(su->su_port)));
+ }
+
+ /* Send message to calling application indicating
+ * there's a new public address available
+ */
+ tport_has_been_updated(self);
+
+ return;
+}
+
+/** Initialize STUN keepalives.
+ *
+ *@retval 0
+ */
+static
+int tport_stun_keepalive(tport_t *tp, su_addrinfo_t const *ai,
+ tagi_t const *taglist)
+{
+ tport_primary_t *pri = tp->tp_pri;
+ int err;
+
+ err = stun_keepalive(pri->pri_stun_handle,
+ (su_sockaddr_t *)ai->ai_addr,
+ STUNTAG_SOCKET(tp->tp_socket),
+ STUNTAG_TIMEOUT(10000),
+ TAG_NEXT(taglist));
+
+ if (err < 0)
+ return -1;
+
+ tp->tp_has_keepalive = 1;
+
+ return 0;
+}
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_tcp.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_tcp.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,271 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE tport_type_tcp.c TCP Transport
+ *
+ * See tport.docs for more detailed description of tport interface.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ *
+ * @date Created: Fri Mar 24 08:45:49 EET 2006 ppessi
+ */
+
+#include "config.h"
+
+#include "tport_internal.h"
+
+#if HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#endif
+
+#ifndef SOL_TCP
+#define SOL_TCP IPPROTO_TCP
+#endif
+
+#include <stdlib.h>
+#include <time.h>
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+
+#if HAVE_FUNC
+#elif HAVE_FUNCTION
+#define __func__ __FUNCTION__
+#else
+char const __func__[] = "tport_type_tcp";
+#endif
+
+/* ---------------------------------------------------------------------- */
+/* TCP */
+
+tport_vtable_t const tport_tcp_vtable =
+{
+ "tcp", tport_type_local,
+ sizeof (tport_primary_t),
+ tport_tcp_init_primary,
+ NULL,
+ tport_accept,
+ NULL,
+ sizeof (tport_t),
+ tport_tcp_init_secondary,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ tport_recv_stream,
+ tport_send_stream,
+};
+
+tport_vtable_t const tport_tcp_client_vtable =
+{
+ "tcp", tport_type_client,
+ sizeof (tport_primary_t),
+ tport_tcp_init_client,
+ NULL,
+ tport_accept,
+ NULL,
+ sizeof (tport_t),
+ tport_tcp_init_secondary,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ tport_recv_stream,
+ tport_send_stream,
+};
+
+static int tport_tcp_setsndbuf(int socket, int atleast);
+
+int tport_tcp_init_primary(tport_primary_t *pri,
+ tp_name_t tpn[1],
+ su_addrinfo_t *ai,
+ tagi_t const *tags,
+ char const **return_culprit)
+{
+ int socket;
+
+ socket = su_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+
+ if (socket == INVALID_SOCKET)
+ return *return_culprit = "socket", -1;
+
+ tport_tcp_setsndbuf(socket, 64 * 1024);
+
+ return tport_stream_init_primary(pri, socket, tpn, ai, tags, return_culprit);
+}
+
+int tport_stream_init_primary(tport_primary_t *pri,
+ su_socket_t socket,
+ tp_name_t tpn[1],
+ su_addrinfo_t *ai,
+ tagi_t const *tags,
+ char const **return_culprit)
+{
+ pri->pri_primary->tp_socket = socket;
+
+ /* Set IP TOS if set */
+ tport_set_tos(socket, ai, pri->pri_params->tpp_tos);
+
+#if defined(__linux__)
+ /* Linux does not allow reusing TCP port while this one is open,
+ so we can safely call su_setreuseaddr() before bind(). */
+ su_setreuseaddr(socket, 1);
+#endif
+
+ if (tport_bind_socket(socket, ai, return_culprit) == -1)
+ return -1;
+
+ if (listen(socket, pri->pri_params->tpp_qsize) == SOCKET_ERROR)
+ return *return_culprit = "listen", -1;
+
+#if !defined(__linux__)
+ /* Allow reusing TCP sockets
+ *
+ * On Solaris & BSD, call setreuseaddr() after bind in order to avoid
+ * binding to a port owned by an existing server.
+ */
+ su_setreuseaddr(socket, 1);
+#endif
+
+ pri->pri_primary->tp_events = SU_WAIT_ACCEPT;
+ pri->pri_primary->tp_conn_orient = 1;
+
+ return 0;
+}
+
+int tport_tcp_init_client(tport_primary_t *pri,
+ tp_name_t tpn[1],
+ su_addrinfo_t *ai,
+ tagi_t const *tags,
+ char const **return_culprit)
+{
+ pri->pri_primary->tp_conn_orient = 1;
+
+ return 0;
+}
+
+int tport_tcp_init_secondary(tport_t *self, int socket, int accepted,
+ char const **return_reason)
+{
+ int one = 1;
+
+ self->tp_has_connection = 1;
+
+ if (setsockopt(socket, SOL_TCP, TCP_NODELAY, (void *)&one, sizeof one) == -1)
+ return *return_reason = "TCP_NODELAY", -1;
+ if (su_setblocking(socket, 0) < 0)
+ return *return_reason = "su_setblocking", -1;
+
+ if (!accepted)
+ tport_tcp_setsndbuf(socket, 64 * 1024);
+
+ return 0;
+}
+
+static int tport_tcp_setsndbuf(int socket, int atleast)
+{
+#if SU_HAVE_WINSOCK2
+ /* Set send buffer size to something reasonable on windows */
+ int size = 0;
+ socklen_t sizelen = sizeof size;
+
+ if (getsockopt(socket, SOL_SOCKET, SO_SNDBUF, (void *)&size, &sizelen) < 0)
+ return -1;
+
+ if (sizelen != sizeof size)
+ return su_seterrno(EINVAL);
+
+ if (size >= atleast)
+ return 0; /* OK */
+
+ return setsockopt(socket, SOL_SOCKET, SO_SNDBUF,
+ (void *)&atleast, sizeof atleast);
+#else
+ return 0;
+#endif
+}
+
+/** Receive from stream.
+ *
+ * @retval -1 error
+ * @retval 0 end-of-stream
+ * @retval 1 normal receive
+ * @retval 2 incomplete recv, recv again
+ *
+ */
+int tport_recv_stream(tport_t *self)
+{
+ msg_t *msg;
+ ssize_t n, N, veclen;
+ int err;
+ msg_iovec_t iovec[msg_n_fragments] = {{ 0 }};
+
+ N = su_getmsgsize(self->tp_socket);
+ if (N == 0) {
+ if (self->tp_msg)
+ msg_recv_commit(self->tp_msg, 0, 1);
+ return 0; /* End of stream */
+ }
+ if (N == -1) {
+ err = su_errno();
+ SU_DEBUG_1(("%s(%p): su_getmsgsize(): %s (%d)\n", __func__, self,
+ su_strerror(err), err));
+ return -1;
+ }
+
+ veclen = tport_recv_iovec(self, &self->tp_msg, iovec, N, 0);
+ if (veclen == -1)
+ return -1;
+
+ msg = self->tp_msg;
+
+ msg_set_address(msg, self->tp_addr, (socklen_t)(self->tp_addrlen));
+
+ n = su_vrecv(self->tp_socket, iovec, veclen, 0, NULL, NULL);
+ if (n == SOCKET_ERROR)
+ return tport_recv_error_report(self);
+
+ assert(n <= N);
+
+ /* Write the received data to the message dump file */
+ if (self->tp_master->mr_dump_file)
+ tport_dump_iovec(self, msg, n, iovec, veclen, "recv", "from");
+
+ /* Mark buffer as used */
+ msg_recv_commit(msg, n, 0);
+
+ return 1;
+}
+
+ssize_t tport_send_stream(tport_t const *self, msg_t *msg,
+ msg_iovec_t iov[],
+ size_t iovused)
+{
+#if __sun__ /* XXX - there must be a better way... */
+ if (iovused > 16)
+ iovused = 16;
+#endif
+ return su_vsend(self->tp_socket, iov, iovused, MSG_NOSIGNAL, NULL, 0);
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_tls.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_tls.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,490 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE tport_type_tls.c TLS over TCP Transport
+ *
+ * See tport.docs for more detailed description of tport interface.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Ismo Puustinen <Ismo.H.Puustinen at nokia.com>
+ * @author Tat Chan <Tat.Chan at nokia.com>
+ * @author Kai Vehmanen <kai.vehmanen at nokia.com>
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ *
+ * @date Split here: Fri Mar 24 08:45:49 EET 2006 ppessi
+ * @date Originally Created: Thu Jul 20 12:54:32 2000 ppessi
+ */
+
+#include "config.h"
+
+#include "tport_internal.h"
+
+#include <stdlib.h>
+#include <time.h>
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+
+/* ---------------------------------------------------------------------- */
+/* TLS */
+
+#include <tport_tls.h>
+
+static int tport_tls_init_primary(tport_primary_t *,
+ tp_name_t tpn[1],
+ su_addrinfo_t *, tagi_t const *,
+ char const **return_culprit);
+static int tport_tls_init_client(tport_primary_t *,
+ tp_name_t tpn[1],
+ su_addrinfo_t *, tagi_t const *,
+ char const **return_culprit);
+static int tport_tls_init_master(tport_primary_t *pri,
+ tp_name_t tpn[1],
+ su_addrinfo_t *ai,
+ tagi_t const *tags,
+ char const **return_culprit);
+static void tport_tls_deinit_primary(tport_primary_t *pri);
+static int tport_tls_init_secondary(tport_t *self, int socket, int accepted,
+ char const **return_reason);
+static void tport_tls_deinit_secondary(tport_t *self);
+static void tport_tls_shutdown(tport_t *self, int how);
+static int tport_tls_set_events(tport_t const *self);
+static int tport_tls_events(tport_t *self, int events);
+static int tport_tls_recv(tport_t *self);
+static ssize_t tport_tls_send(tport_t const *self, msg_t *msg,
+ msg_iovec_t iov[], size_t iovused);
+
+typedef struct
+{
+ tport_primary_t tlspri_pri[1];
+ tls_t *tlspri_master;
+} tport_tls_primary_t;
+
+typedef struct
+{
+ tport_t tlstp_tp[1];
+ tls_t *tlstp_context;
+ char *tlstp_buffer; /**< 2k Buffer */
+} tport_tls_t;
+
+tport_vtable_t const tport_tls_vtable =
+{
+ "tls", tport_type_local,
+ sizeof (tport_tls_primary_t),
+ tport_tls_init_primary,
+ tport_tls_deinit_primary,
+ tport_accept,
+ NULL,
+ sizeof (tport_tls_t),
+ tport_tls_init_secondary,
+ tport_tls_deinit_secondary,
+ tport_tls_shutdown,
+ tport_tls_set_events,
+ tport_tls_events,
+ tport_tls_recv,
+ tport_tls_send,
+};
+
+tport_vtable_t const tport_tls_client_vtable =
+{
+ "tls", tport_type_client,
+ sizeof (tport_tls_primary_t),
+ tport_tls_init_client,
+ tport_tls_deinit_primary,
+ tport_accept,
+ NULL,
+ sizeof (tport_tls_t),
+ tport_tls_init_secondary,
+ tport_tls_deinit_secondary,
+ tport_tls_shutdown,
+ tport_tls_set_events,
+ tport_tls_events,
+ tport_tls_recv,
+ tport_tls_send,
+};
+
+static int tport_tls_init_primary(tport_primary_t *pri,
+ tp_name_t tpn[1],
+ su_addrinfo_t *ai,
+ tagi_t const *tags,
+ char const **return_culprit)
+{
+ if (tport_tls_init_master(pri, tpn, ai, tags, return_culprit) < 0)
+ return -1;
+
+ return tport_tcp_init_primary(pri, tpn, ai, tags, return_culprit);
+}
+
+static int tport_tls_init_client(tport_primary_t *pri,
+ tp_name_t tpn[1],
+ su_addrinfo_t *ai,
+ tagi_t const *tags,
+ char const **return_culprit)
+{
+ tport_tls_init_master(pri, tpn, ai, tags, return_culprit);
+
+ return tport_tcp_init_client(pri, tpn, ai, tags, return_culprit);
+}
+
+static int tport_tls_init_master(tport_primary_t *pri,
+ tp_name_t tpn[1],
+ su_addrinfo_t *ai,
+ tagi_t const *tags,
+ char const **return_culprit)
+{
+ tport_tls_primary_t *tlspri = (tport_tls_primary_t *)pri;
+ char *homedir;
+ char *tbf = NULL;
+ char const *path = NULL;
+ unsigned tls_version = 1;
+ su_home_t autohome[SU_HOME_AUTO_SIZE(1024)];
+ tls_issues_t ti = {0};
+
+ su_home_auto(autohome, sizeof autohome);
+
+ if (getenv("TPORT_SSL"))
+ tls_version = 0;
+
+ tl_gets(tags,
+ TPTAG_CERTIFICATE_REF(path),
+ TPTAG_TLS_VERSION_REF(tls_version),
+ TAG_END());
+
+ if (!path) {
+ homedir = getenv("HOME");
+ if (!homedir)
+ homedir = "";
+ path = tbf = su_sprintf(autohome, "%s/.sip/auth", homedir);
+ }
+
+ if (path) {
+ ti.verify_depth = 2;
+ ti.configured = path != tbf;
+ ti.randFile = su_sprintf(autohome, "%s/%s", path, "tls_seed.dat");
+ ti.key = su_sprintf(autohome, "%s/%s", path, "agent.pem");
+ ti.cert = ti.key;
+ ti.CAfile = su_sprintf(autohome, "%s/%s", path, "cafile.pem");
+ ti.version = tls_version;
+
+ SU_DEBUG_9(("%s(%p): tls key = %s\n", __func__, pri, ti.key));
+
+ if (ti.key && ti.CAfile && ti.randFile) {
+ tlspri->tlspri_master = tls_init_master(&ti);
+ }
+ }
+
+ su_home_zap(autohome);
+
+ if (!tlspri->tlspri_master) {
+ if (!path || ti.configured) {
+ SU_DEBUG_1(("tls_init_master: %s\n", strerror(errno)));
+ }
+ else {
+ SU_DEBUG_5(("tls_init_master: %s\n", strerror(errno)));
+ }
+ return *return_culprit = "tls_init_master", -1;
+ }
+
+ pri->pri_has_tls = 1;
+
+ return 0;
+}
+
+static void tport_tls_deinit_primary(tport_primary_t *pri)
+{
+ tport_tls_primary_t *tlspri = (tport_tls_primary_t *)pri;
+ tls_free(tlspri->tlspri_master), tlspri->tlspri_master = NULL;
+}
+
+static int tport_tls_init_secondary(tport_t *self, int socket, int accepted,
+ char const **return_reason)
+{
+ tport_tls_primary_t *tlspri = (tport_tls_primary_t *)self->tp_pri;
+ tport_tls_t *tlstp = (tport_tls_t *)self;
+
+ tls_t *master = tlspri->tlspri_master;
+
+ if (tport_tcp_init_secondary(self, socket, accepted, return_reason) < 0)
+ return -1;
+
+ if (accepted) {
+ tlstp->tlstp_context = tls_init_slave(master, socket);
+ if (!tlstp->tlstp_context)
+ return *return_reason = "tls_init_slave", -1;
+ }
+
+ return 0;
+}
+
+static void tport_tls_deinit_secondary(tport_t *self)
+{
+ tport_tls_t *tlstp = (tport_tls_t *)self;
+
+ /* XXX - PPe: does the tls_shutdown zap everything but socket? */
+ if (tlstp->tlstp_context != NULL)
+ tls_free(tlstp->tlstp_context);
+ tlstp->tlstp_context = NULL;
+
+ su_free(self->tp_home, tlstp->tlstp_buffer);
+ tlstp->tlstp_buffer = NULL;
+}
+
+static void tport_tls_shutdown(tport_t *self, int how)
+{
+ tport_tls_t *tlstp = (tport_tls_t *)self;
+
+ /* XXX - send alert */
+ (void)tlstp;
+
+ shutdown(self->tp_socket, how);
+
+ if (how >= 2)
+ tport_tls_deinit_secondary(self);
+}
+
+
+static
+int tport_tls_set_events(tport_t const *self)
+{
+ tport_tls_t *tlstp = (tport_tls_t *)self;
+ int mask = tls_events(tlstp->tlstp_context, self->tp_events);
+
+ SU_DEBUG_7(("%s(%p): logical events%s%s real%s%s\n",
+ "tport_tls_set_events", self,
+ (self->tp_events & SU_WAIT_IN) ? " IN" : "",
+ (self->tp_events & SU_WAIT_OUT) ? " OUT" : "",
+ (mask & SU_WAIT_IN) ? " IN" : "",
+ (mask & SU_WAIT_OUT) ? " OUT" : ""));
+
+ return
+ su_root_eventmask(self->tp_master->mr_root,
+ self->tp_index,
+ self->tp_socket,
+ mask);
+}
+
+/** Handle poll events for tls */
+int tport_tls_events(tport_t *self, int events)
+{
+ tport_tls_t *tlstp = (tport_tls_t *)self;
+ int old_mask = tls_events(tlstp->tlstp_context, self->tp_events), mask;
+ int ret, error = 0;
+
+ if (events & SU_WAIT_ERR)
+ error = tport_error_event(self);
+
+ if ((self->tp_events & SU_WAIT_OUT) && !self->tp_closed) {
+ ret = tls_want_write(tlstp->tlstp_context, events);
+ if (ret > 0)
+ tport_send_event(self);
+ else if (ret < 0)
+ tport_error_report(self, errno, NULL);
+ }
+
+ if ((self->tp_events & SU_WAIT_IN) && !self->tp_closed) {
+ ret = tls_want_read(tlstp->tlstp_context, events);
+ if (ret > 0)
+ tport_recv_event(self);
+ else if (ret < 0)
+ tport_error_report(self, errno, NULL);
+ }
+
+ if ((events & SU_WAIT_HUP) && !self->tp_closed)
+ tport_hup_event(self);
+
+ if (error && !self->tp_closed)
+ tport_error_report(self, error, NULL);
+
+ if (self->tp_closed)
+ return 0;
+
+ events = self->tp_events;
+ mask = tls_events(tlstp->tlstp_context, events);
+ if ((old_mask ^ mask) == 0)
+ return 0;
+
+ SU_DEBUG_7(("%s(%p): logical events%s%s real%s%s\n",
+ "tport_tls_events", self,
+ (events & SU_WAIT_IN) ? " IN" : "",
+ (events & SU_WAIT_OUT) ? " OUT" : "",
+ (mask & SU_WAIT_IN) ? " IN" : "",
+ (mask & SU_WAIT_OUT) ? " OUT" : ""));
+
+ su_root_eventmask(self->tp_master->mr_root,
+ self->tp_index,
+ self->tp_socket,
+ mask);
+
+ return 0;
+}
+
+/** Receive data from TLS.
+ *
+ * @retval -1 error
+ * @retval 0 end-of-stream
+ * @retval 1 normal receive
+ * @retval 2 incomplete recv, recv again
+ *
+ */
+static
+int tport_tls_recv(tport_t *self)
+{
+ tport_tls_t *tlstp = (tport_tls_t *)self;
+ msg_t *msg;
+ ssize_t n, N, veclen, i, m;
+ msg_iovec_t iovec[msg_n_fragments] = {{ 0 }};
+ char *tls_buf;
+
+ N = tls_read(tlstp->tlstp_context);
+
+ SU_DEBUG_7(("%s(%p): tls_read() returned "MOD_ZD"\n", __func__, self, N));
+
+ if (N == 0) /* End-of-stream */
+ return 0;
+ else if (N == -1) {
+ if (su_is_blocking(su_errno())) {
+ tport_tls_set_events(self);
+ return 1;
+ }
+ return -1;
+ }
+
+ veclen = tport_recv_iovec(self, &self->tp_msg, iovec, N, 0);
+ if (veclen < 0)
+ return -1;
+
+ msg = self->tp_msg;
+
+ tls_buf = tls_read_buffer(tlstp->tlstp_context, N);
+
+ msg_set_address(msg, self->tp_addr, self->tp_addrlen);
+
+ for (i = 0, n = 0; i < veclen; i++) {
+ m = iovec[i].mv_len; assert(N >= n + m);
+ memcpy(iovec[i].mv_base, tls_buf + n, m);
+ n += m;
+ }
+
+ assert(N == n);
+
+ /* Write the received data to the message dump file */
+ if (self->tp_master->mr_dump_file)
+ tport_dump_iovec(self, msg, n, iovec, veclen, "recv", "from");
+
+ /* Mark buffer as used */
+ msg_recv_commit(msg, N, 0);
+
+ return tls_pending(tlstp->tlstp_context) ? 2 : 1;
+}
+
+static
+ssize_t tport_tls_send(tport_t const *self,
+ msg_t *msg,
+ msg_iovec_t iov[],
+ size_t iovlen)
+{
+ tport_tls_primary_t *tlspri = (tport_tls_primary_t *)self->tp_pri;
+ tport_tls_t *tlstp = (tport_tls_t *)self;
+ enum { TLSBUFSIZE = 2048 };
+ size_t i, j, n, m, size = 0;
+ ssize_t nerror;
+ int oldmask, mask;
+
+ if (tlstp->tlstp_context == NULL) {
+ tls_t *master = tlspri->tlspri_master;
+ tlstp->tlstp_context = tls_init_client(master, self->tp_socket);
+ if (!tlstp->tlstp_context)
+ return -1;
+ }
+
+ oldmask = tls_events(tlstp->tlstp_context, self->tp_events);
+
+#if 0
+ if (!tlstp->tlstp_buffer)
+ tlstp->tlstp_buffer = su_alloc(self->tp_home, TLSBUFSIZE);
+#endif
+
+ for (i = 0; i < iovlen; i = j) {
+#if 0
+ nerror = tls_write(tlstp->tlstp_context,
+ iov[i].siv_base,
+ m = iov[i].siv_len);
+ j = i + 1;
+#else
+ char *buf = tlstp->tlstp_buffer;
+ unsigned tlsbufsize = TLSBUFSIZE;
+
+ if (i + 1 == iovlen)
+ buf = NULL; /* Don't bother copying single chunk */
+
+ if (buf &&
+ (char *)iov[i].siv_base - buf < TLSBUFSIZE &&
+ (char *)iov[i].siv_base - buf >= 0) {
+ tlsbufsize = buf + TLSBUFSIZE - (char *)iov[i].siv_base;
+ assert(tlsbufsize <= TLSBUFSIZE);
+ }
+
+ for (j = i, m = 0; buf && j < iovlen; j++) {
+ if (m + iov[j].siv_len > tlsbufsize)
+ break;
+ if (buf + m != iov[j].siv_base)
+ memcpy(buf + m, iov[j].siv_base, iov[j].siv_len);
+ m += iov[j].siv_len; iov[j].siv_len = 0;
+ }
+
+ if (j == i)
+ buf = iov[i].siv_base, m = iov[i].siv_len, j++;
+ else
+ iov[j].siv_base = buf, iov[j].siv_len = m;
+
+ nerror = tls_write(tlstp->tlstp_context, buf, m);
+#endif
+
+ SU_DEBUG_9(("tport_tls_writevec: vec %p %p %lu ("MOD_ZD")\n",
+ tlstp->tlstp_context, iov[i].siv_base, (LU)iov[i].siv_len,
+ nerror));
+
+ if (nerror == -1) {
+ int err = su_errno();
+ if (su_is_blocking(err))
+ break;
+ SU_DEBUG_3(("tls_write: %s\n", strerror(err)));
+ return -1;
+ }
+
+ n = (size_t)nerror;
+ size += n;
+
+ /* Return if the write buffer is full for now */
+ if (n != m)
+ break;
+ }
+
+ mask = tls_events(tlstp->tlstp_context, self->tp_events);
+
+ if (oldmask != mask)
+ tport_tls_set_events(self);
+
+ return size;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_udp.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_udp.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,435 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE tport_type_udp.c UDP Transport
+ *
+ * See tport.docs for more detailed description of tport interface.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Martti Mela <Martti.Mela at nokia.com>
+ *
+ * @date Created: Fri Mar 24 08:45:49 EET 2006 ppessi
+ */
+
+#include "config.h"
+
+#include "tport_internal.h"
+
+#if HAVE_IP_RECVERR || HAVE_IPV6_RECVERR
+#include <linux/types.h>
+#include <linux/errqueue.h>
+#include <sys/uio.h>
+#endif
+
+#include <stdlib.h>
+#include <time.h>
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+
+/* ---------------------------------------------------------------------- */
+/* UDP */
+
+static
+int tport_udp_init_client(tport_primary_t *pri,
+ tp_name_t tpn[1],
+ su_addrinfo_t *ai,
+ tagi_t const *tags,
+ char const **return_culprit);
+
+tport_vtable_t const tport_udp_client_vtable =
+{
+ "udp", tport_type_client,
+ sizeof (tport_primary_t),
+ tport_udp_init_client,
+ NULL,
+ NULL,
+ NULL,
+ sizeof (tport_t),
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ tport_recv_dgram,
+ tport_send_dgram,
+};
+
+tport_vtable_t const tport_udp_vtable =
+{
+ "udp", tport_type_local,
+ sizeof (tport_primary_t),
+ tport_udp_init_primary,
+ NULL,
+ NULL,
+ NULL,
+ sizeof (tport_t),
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ tport_recv_dgram,
+ tport_send_dgram,
+};
+
+static void tport_check_trunc(tport_t *tp, su_addrinfo_t *ai);
+
+int tport_udp_init_primary(tport_primary_t *pri,
+ tp_name_t tpn[1],
+ su_addrinfo_t *ai,
+ tagi_t const *tags,
+ char const **return_culprit)
+{
+ unsigned rmem = 0, wmem = 0;
+ int events = SU_WAIT_IN;
+ int s;
+
+ s = su_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+ if (s == INVALID_SOCKET)
+ return *return_culprit = "socket", -1;
+
+ pri->pri_primary->tp_socket = s;
+
+ if (tport_bind_socket(s, ai, return_culprit) < 0)
+ return -1;
+
+ tport_set_tos(s, ai, pri->pri_params->tpp_tos);
+
+#if HAVE_IP_RECVERR
+ if (ai->ai_family == AF_INET || ai->ai_family == AF_INET6) {
+ int const one = 1;
+ if (setsockopt(s, SOL_IP, IP_RECVERR, &one, sizeof(one)) < 0) {
+ if (ai->ai_family == AF_INET)
+ SU_DEBUG_3(("setsockopt(IPVRECVERR): %s\n", su_strerror(su_errno())));
+ }
+ events |= SU_WAIT_ERR;
+ }
+#endif
+#if HAVE_IPV6_RECVERR
+ if (ai->ai_family == AF_INET6) {
+ int const one = 1;
+ if (setsockopt(s, SOL_IPV6, IPV6_RECVERR, &one, sizeof(one)) < 0)
+ SU_DEBUG_3(("setsockopt(IPV6_RECVERR): %s\n", su_strerror(su_errno())));
+ events |= SU_WAIT_ERR;
+ }
+#endif
+
+ tl_gets(tags,
+ TPTAG_UDP_RMEM_REF(rmem),
+ TPTAG_UDP_WMEM_REF(wmem),
+ TAG_END());
+
+ if (rmem != 0 &&
+ setsockopt(s, SOL_SOCKET, SO_RCVBUF, (void *)&rmem, sizeof rmem) < 0) {
+ SU_DEBUG_3(("setsockopt(SO_RCVBUF): %s\n",
+ su_strerror(su_errno())));
+ }
+
+ if (wmem != 0 &&
+ setsockopt(s, SOL_SOCKET, SO_SNDBUF, (void *)&wmem, sizeof wmem) < 0) {
+ SU_DEBUG_3(("setsockopt(SO_SNDBUF): %s\n",
+ su_strerror(su_errno())));
+ }
+
+ pri->pri_primary->tp_events = events;
+
+ tport_init_compressor(pri->pri_primary, tpn->tpn_comp, tags);
+
+ tport_check_trunc(pri->pri_primary, ai);
+
+ tport_stun_server_add_socket(pri->pri_primary);
+
+ return 0;
+}
+
+static
+int tport_udp_init_client(tport_primary_t *pri,
+ tp_name_t tpn[1],
+ su_addrinfo_t *ai,
+ tagi_t const *tags,
+ char const **return_culprit)
+{
+ pri->pri_primary->tp_conn_orient = 1;
+ return 0;
+}
+
+/** Runtime test making sure MSG_TRUNC work as expected */
+static void tport_check_trunc(tport_t *tp, su_addrinfo_t *ai)
+{
+#if HAVE_MSG_TRUNC
+ ssize_t n;
+ char buffer[2];
+ su_sockaddr_t su[1];
+ socklen_t sulen = sizeof su;
+
+ n = su_sendto(tp->tp_socket,
+ "TEST", 4, 0,
+ (void *)ai->ai_addr, ai->ai_addrlen);
+
+ for (;;) {
+ n = su_recvfrom(tp->tp_socket, buffer, sizeof buffer, MSG_TRUNC,
+ (void *)&su, &sulen);
+
+ if (n > (ssize_t)sizeof buffer) {
+ tp->tp_trunc = 1;
+ return;
+ }
+
+ /* XXX - check that su and tp->tp_addrinfo->ai_addr match */
+
+ return;
+ }
+#endif
+}
+
+/** Receive datagram.
+ *
+ * @retval -1 error
+ * @retval 0 end-of-stream
+ * @retval 1 normal receive (should never happen)
+ * @retval 2 incomplete recv, call me again (should never happen)
+ * @retval 3 STUN keepalive, ignore
+ */
+int tport_recv_dgram(tport_t *self)
+{
+ msg_t *msg;
+ ssize_t n, veclen;
+ su_addrinfo_t *ai;
+ su_sockaddr_t *from;
+ socklen_t fromlen;
+ msg_iovec_t iovec[msg_n_fragments] = {{ 0 }};
+ uint8_t sample[1];
+
+ /* Simulate packet loss */
+ if (self->tp_params->tpp_drop &&
+ (unsigned)su_randint(0, 1000) < self->tp_params->tpp_drop) {
+ su_recv(self->tp_socket, sample, 1, 0);
+ SU_DEBUG_3(("tport(%p): simulated packet loss!\n", self));
+ return 0;
+ }
+
+ assert(self->tp_msg == NULL);
+
+ veclen = tport_recv_iovec(self, &self->tp_msg, iovec, 65536, 1);
+ if (veclen < 0)
+ return -1;
+
+ msg = self->tp_msg;
+
+ ai = msg_addrinfo(msg);
+ from = (su_sockaddr_t *)ai->ai_addr, fromlen = (socklen_t)(ai->ai_addrlen);
+
+ n = su_vrecv(self->tp_socket, iovec, veclen, 0, from, &fromlen);
+
+ ai->ai_addrlen = fromlen;
+
+ if (n == SOCKET_ERROR) {
+ int error = su_errno();
+ msg_destroy(msg); self->tp_msg = NULL;
+ su_seterrno(error);
+
+ if (su_is_blocking(error))
+ return 0;
+ else
+ return -1;
+ }
+ else if (n <= 1) {
+ SU_DEBUG_1(("%s(%p): runt of "MOD_ZD" bytes\n", "tport_recv_dgram", self, n));
+ msg_destroy(msg), self->tp_msg = NULL;
+ return 0;
+ }
+
+ SU_CANONIZE_SOCKADDR(from);
+
+ if (self->tp_master->mr_dump_file)
+ tport_dump_iovec(self, msg, n, iovec, veclen, "recv", "from");
+
+ *sample = *((uint8_t *)iovec[0].mv_base);
+
+ /* Commit received data into buffer. This may relocate iovec contents */
+ msg_recv_commit(msg, n, 1);
+
+ if ((sample[0] & 0xf8) == 0xf8)
+ /* SigComp */
+ return tport_recv_comp_dgram(self, self->tp_comp, &self->tp_msg,
+ from, fromlen);
+ else if (sample[0] == 0 || sample[0] == 1)
+ /* STUN request or response */
+ return tport_recv_stun_dgram(self, &self->tp_msg, from, fromlen);
+ else
+ return 0;
+}
+
+/** Send using su_vsend(). Map IPv4 addresses as IPv6 addresses, if needed. */
+ssize_t tport_send_dgram(tport_t const *self, msg_t *msg,
+ msg_iovec_t iov[],
+ size_t iovused)
+{
+ su_sockaddr_t su[1];
+ socklen_t sulen = sizeof su;
+
+ if (tport_is_connection_oriented(self))
+ return su_vsend(self->tp_socket, iov, iovused, MSG_NOSIGNAL, NULL, 0);
+
+ msg_get_address(msg, su, &sulen);
+
+#if SU_HAVE_IN6 && defined(IN6_INADDR_TO_V4MAPPED)
+ if (su->su_family == AF_INET && self->tp_addrinfo->ai_family == AF_INET6) {
+ su_sockaddr_t su0[1];
+
+ memset(su0, 0, sizeof su0);
+
+ su0->su_family = self->tp_addrinfo->ai_family;
+ su0->su_port = su->su_port;
+
+ IN6_INADDR_TO_V4MAPPED(&su->su_sin.sin_addr, &su0->su_sin6.sin6_addr);
+
+ memcpy(su, su0, sulen = sizeof(su0->su_sin6));
+ }
+#endif
+
+ su_soerror(self->tp_socket); /* XXX - we *still* have a race condition */
+
+ return su_vsend(self->tp_socket, iov, iovused, MSG_NOSIGNAL, su, sulen);
+}
+
+
+#if !HAVE_IP_RECVERR && !HAVE_IPV6_RECVERR
+
+/** Process UDP error event. */
+int tport_udp_error(tport_t const *self, su_sockaddr_t name[1])
+{
+ if (tport_is_connection_oriented(self))
+ name[0] = self->tp_addr[0];
+ return su_soerror(self->tp_socket);
+}
+
+#else
+
+/** Process UDP error event. */
+int tport_udp_error(tport_t const *self, su_sockaddr_t name[1])
+{
+ struct cmsghdr *c;
+ struct sock_extended_err *ee;
+ su_sockaddr_t *from;
+ char control[512];
+ char errmsg[64 + 768];
+ struct iovec iov[1];
+ struct msghdr msg[1] = {{ 0 }};
+ int n;
+
+ msg->msg_name = name, msg->msg_namelen = sizeof(*name);
+ msg->msg_iov = iov, msg->msg_iovlen = 1;
+ iov->iov_base = errmsg, iov->iov_len = sizeof(errmsg);
+ msg->msg_control = control, msg->msg_controllen = sizeof(control);
+
+ n = recvmsg(self->tp_socket, msg, MSG_ERRQUEUE);
+
+ if (n < 0) {
+ int err = su_errno();
+ if (!su_is_blocking(err))
+ SU_DEBUG_1(("%s: recvmsg: %s\n", __func__, su_strerror(err)));
+ return 0;
+ }
+
+ if ((msg->msg_flags & MSG_ERRQUEUE) != MSG_ERRQUEUE) {
+ SU_DEBUG_1(("%s: recvmsg: no errqueue\n", __func__));
+ return 0;
+ }
+
+ if (msg->msg_flags & MSG_CTRUNC) {
+ SU_DEBUG_1(("%s: extended error was truncated\n", __func__));
+ return 0;
+ }
+
+ if (msg->msg_flags & MSG_TRUNC) {
+ /* ICMP message may contain original message... */
+ SU_DEBUG_3(("%s: icmp(6) message was truncated (at %d)\n", __func__, n));
+ }
+
+ /* Go through the ancillary data */
+ for (c = CMSG_FIRSTHDR(msg); c; c = CMSG_NXTHDR(msg, c)) {
+ if (0
+#if HAVE_IP_RECVERR
+ || (c->cmsg_level == SOL_IP && c->cmsg_type == IP_RECVERR)
+#endif
+#if HAVE_IPV6_RECVERR
+ || (c->cmsg_level == SOL_IPV6 && c->cmsg_type == IPV6_RECVERR)
+#endif
+ ) {
+ char info[128];
+ char const *origin;
+
+ ee = (struct sock_extended_err *)CMSG_DATA(c);
+ from = (su_sockaddr_t *)SO_EE_OFFENDER(ee);
+ info[0] = '\0';
+
+ switch (ee->ee_origin) {
+ case SO_EE_ORIGIN_LOCAL:
+ origin = "local";
+ break;
+ case SO_EE_ORIGIN_ICMP:
+ origin = "icmp";
+ snprintf(info, sizeof(info), " type=%u code=%u",
+ ee->ee_type, ee->ee_code);
+ break;
+ case SO_EE_ORIGIN_ICMP6:
+ origin = "icmp6";
+ snprintf(info, sizeof(info), " type=%u code=%u",
+ ee->ee_type, ee->ee_code);
+ break;
+ case SO_EE_ORIGIN_NONE:
+ origin = "none";
+ break;
+ default:
+ origin = "unknown";
+ break;
+ }
+
+ if (ee->ee_info)
+ snprintf(info + strlen(info), sizeof(info) - strlen(info),
+ " info=%08x", ee->ee_info);
+
+ SU_DEBUG_3(("%s: %s (%d) [%s%s]\n",
+ __func__, su_strerror(ee->ee_errno), ee->ee_errno,
+ origin, info));
+ if (from->su_family != AF_UNSPEC)
+ SU_DEBUG_3(("\treported by [%s]:%u\n",
+ inet_ntop(from->su_family, SU_ADDR(from),
+ info, sizeof(info)),
+ ntohs(from->su_port)));
+
+ if (msg->msg_namelen == 0)
+ name->su_family = AF_UNSPEC;
+
+ SU_CANONIZE_SOCKADDR(name);
+
+ return ee->ee_errno;
+ }
+ }
+
+ return 0;
+}
+#endif
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/ChangeLog Thu Dec 21 01:30:28 2006
@@ -0,0 +1,3 @@
+2005-07-18 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * Initial import of the module to Sofia-SIP tree.
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/Doxyfile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/Doxyfile Thu Dec 21 01:30:28 2006
@@ -0,0 +1,12 @@
+PROJECT_NAME = "url"
+OUTPUT_DIRECTORY = ../docs/html/url
+
+INPUT = url.docs sofia-sip .
+
+ at INCLUDE = ../docs/Doxyfile.conf
+
+TAGFILES += ../docs/su.doxytags=../su
+
+GENERATE_TAGFILE = ../docs/url.doxytags
+
+PREDEFINED += "URL_DLL"
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/Makefile.am Thu Dec 21 01:30:28 2006
@@ -0,0 +1,57 @@
+#
+# Makefile.am for url module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+INCLUDES = -I$(srcdir)/../bnf -I../bnf \
+ -I$(srcdir)/../ipt -I../ipt \
+ -I$(srcdir)/../su -I../su
+
+# ----------------------------------------------------------------------
+# Build targets
+
+noinst_LTLIBRARIES = liburl.la
+
+check_PROGRAMS = torture_url test_urlmap
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+
+BUILT_SOURCES = url_tag_ref.c
+
+nobase_include_sofia_HEADERS = \
+ sofia-sip/url.h sofia-sip/url_tag.h \
+ sofia-sip/url_tag_class.h
+
+liburl_la_SOURCES = url.c url_tag.c url_tag_ref.c
+
+COVERAGE_INPUT = $(liburl_la_SOURCES) $(include_sofia_HEADERS)
+
+LDADD = liburl.la \
+ ../bnf/libbnf.la \
+ ../su/libsu.la
+
+test_urlmap_SOURCES = urlmap.c urlmap.h
+test_urlmap_CFLAGS = $(CFLAGS) -DTEST_URLMAP=1
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+
+EXTRA_DIST = Doxyfile url.docs $(BUILT_SOURCES)
+
+# ----------------------------------------------------------------------
+# Tests
+
+TESTS = torture_url test_urlmap
+
+# ----------------------------------------------------------------------
+# Sofia specific rules
+
+include ../sofia.am
+
+TAG_DLL_FLAGS = DLLREF=1
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/Makefile.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1,726 @@
+# 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.
+
+ at SET_MAKE@
+
+#
+# Makefile.am for url module
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# ----------------------------------------------------------------------
+# Header paths
+
+# common Makefile targets for libsofia-sip-ua modules
+# ---------------------------------------------------
+
+
+SOURCES = $(liburl_la_SOURCES) $(test_urlmap_SOURCES) torture_url.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 = torture_url$(EXEEXT) test_urlmap$(EXEEXT)
+DIST_COMMON = $(nobase_include_sofia_HEADERS) $(srcdir)/../sofia.am \
+ $(srcdir)/Makefile.am $(srcdir)/Makefile.in ChangeLog
+subdir = libsofia-sip-ua/url
+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 =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+liburl_la_LIBADD =
+am_liburl_la_OBJECTS = url.lo url_tag.lo url_tag_ref.lo
+liburl_la_OBJECTS = $(am_liburl_la_OBJECTS)
+am_test_urlmap_OBJECTS = test_urlmap-urlmap.$(OBJEXT)
+test_urlmap_OBJECTS = $(am_test_urlmap_OBJECTS)
+test_urlmap_LDADD = $(LDADD)
+test_urlmap_DEPENDENCIES = liburl.la ../bnf/libbnf.la ../su/libsu.la
+torture_url_SOURCES = torture_url.c
+torture_url_OBJECTS = torture_url.$(OBJEXT)
+torture_url_LDADD = $(LDADD)
+torture_url_DEPENDENCIES = liburl.la ../bnf/libbnf.la ../su/libsu.la
+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 = $(liburl_la_SOURCES) $(test_urlmap_SOURCES) torture_url.c
+DIST_SOURCES = $(liburl_la_SOURCES) $(test_urlmap_SOURCES) \
+ torture_url.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|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(include_sofiadir)"
+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)/../bnf -I../bnf \
+ -I$(srcdir)/../ipt -I../ipt \
+ -I$(srcdir)/../su -I../su
+
+
+# ----------------------------------------------------------------------
+# Build targets
+noinst_LTLIBRARIES = liburl.la
+
+# ----------------------------------------------------------------------
+# Rules for building the targets
+BUILT_SOURCES = url_tag_ref.c
+nobase_include_sofia_HEADERS = \
+ sofia-sip/url.h sofia-sip/url_tag.h \
+ sofia-sip/url_tag_class.h
+
+liburl_la_SOURCES = url.c url_tag.c url_tag_ref.c
+COVERAGE_INPUT = $(liburl_la_SOURCES) $(include_sofia_HEADERS)
+LDADD = liburl.la \
+ ../bnf/libbnf.la \
+ ../su/libsu.la
+
+test_urlmap_SOURCES = urlmap.c urlmap.h
+test_urlmap_CFLAGS = $(CFLAGS) -DTEST_URLMAP=1
+
+# ----------------------------------------------------------------------
+# Install and distribution rules
+EXTRA_DIST = Doxyfile url.docs $(BUILT_SOURCES)
+
+# ----------------------------------------------------------------------
+# Tests
+TESTS = torture_url test_urlmap
+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
+TAG_DLL_FLAGS = DLLREF=1
+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/url/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu libsofia-sip-ua/url/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-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
+liburl.la: $(liburl_la_OBJECTS) $(liburl_la_DEPENDENCIES)
+ $(LINK) $(liburl_la_LDFLAGS) $(liburl_la_OBJECTS) $(liburl_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
+test_urlmap$(EXEEXT): $(test_urlmap_OBJECTS) $(test_urlmap_DEPENDENCIES)
+ @rm -f test_urlmap$(EXEEXT)
+ $(LINK) $(test_urlmap_LDFLAGS) $(test_urlmap_OBJECTS) $(test_urlmap_LDADD) $(LIBS)
+torture_url$(EXEEXT): $(torture_url_OBJECTS) $(torture_url_DEPENDENCIES)
+ @rm -f torture_url$(EXEEXT)
+ $(LINK) $(torture_url_LDFLAGS) $(torture_url_OBJECTS) $(torture_url_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_urlmap-urlmap.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/torture_url.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/url.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/url_tag.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/url_tag_ref.Plo at am__quote@
+
+.c.o:
+ at am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+ at am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ at am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+test_urlmap-urlmap.o: urlmap.c
+ at am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_urlmap_CFLAGS) $(CFLAGS) -MT test_urlmap-urlmap.o -MD -MP -MF "$(DEPDIR)/test_urlmap-urlmap.Tpo" -c -o test_urlmap-urlmap.o `test -f 'urlmap.c' || echo '$(srcdir)/'`urlmap.c; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/test_urlmap-urlmap.Tpo" "$(DEPDIR)/test_urlmap-urlmap.Po"; else rm -f "$(DEPDIR)/test_urlmap-urlmap.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='urlmap.c' object='test_urlmap-urlmap.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_urlmap_CFLAGS) $(CFLAGS) -c -o test_urlmap-urlmap.o `test -f 'urlmap.c' || echo '$(srcdir)/'`urlmap.c
+
+test_urlmap-urlmap.obj: urlmap.c
+ at am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_urlmap_CFLAGS) $(CFLAGS) -MT test_urlmap-urlmap.obj -MD -MP -MF "$(DEPDIR)/test_urlmap-urlmap.Tpo" -c -o test_urlmap-urlmap.obj `if test -f 'urlmap.c'; then $(CYGPATH_W) 'urlmap.c'; else $(CYGPATH_W) '$(srcdir)/urlmap.c'; fi`; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/test_urlmap-urlmap.Tpo" "$(DEPDIR)/test_urlmap-urlmap.Po"; else rm -f "$(DEPDIR)/test_urlmap-urlmap.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='urlmap.c' object='test_urlmap-urlmap.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_urlmap_CFLAGS) $(CFLAGS) -c -o test_urlmap-urlmap.obj `if test -f 'urlmap.c'; then $(CYGPATH_W) 'urlmap.c'; else $(CYGPATH_W) '$(srcdir)/urlmap.c'; fi`
+
+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 $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(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-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-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-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-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-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-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) $<
+
+ at ENABLE_COVERAGE_TRUE@coverage:
+ at 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)
+# 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:
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/sofia-sip/url.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/sofia-sip/url.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,315 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@file sofia-sip/url.h
+ *
+ * URL struct and helper functions.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Jun 8 19:28:55 2000 ppessi
+ */
+
+#ifndef URL_H_TYPES
+#define URL_H_TYPES
+
+/** Recognized URL schemes (value of url_t.url_type). */
+enum url_type_e {
+ url_invalid = -2, /**< Invalid url. */
+ url_unknown = -1, /**< Unknown scheme. */
+ url_any = 0, /**< @c "*" */
+ url_sip, /**< @c "sip:" */
+ url_sips, /**< @c "sips:" */
+ url_tel, /**< @c "tel:" */
+ url_fax, /**< @c "fax:" */
+ url_modem, /**< @c "modem:" */
+ url_http, /**< @c "http:" */
+ url_https, /**< @c "https:" */
+ url_ftp, /**< @c "ftp:" */
+ url_file, /**< @c "file:" */
+ url_rtsp, /**< @c "rtsp:" */
+ url_rtspu, /**< @c "rtspu:" */
+ url_mailto, /**< @c "mailto:" */
+ url_im, /**< @c "im:" (simple instant messaging) */
+ url_pres, /**< @c "pres:" (simple presence) */
+ url_cid, /**< @c "cid:" (Content-ID) */
+ url_msrp, /**< @c "msrp:" (message session relay) */
+ url_msrps, /**< @c "msrps:" (new in @VERSION_1_12_2) */
+ url_wv, /**< @c "wv:" (Wireless village) */
+ _url_none
+};
+
+/** URL structure.
+ *
+ * This structure is used to present a parsed URL.
+ */
+typedef struct {
+ char url_pad[sizeof(void *) - 2];
+ /**< Zero pad for URL_STRING_P(). */
+ signed char url_type; /**< URL type (url_type_e). */
+ char url_root; /**< Nonzero if root "//" */
+ char const *url_scheme; /**< URL type as string. */
+ char const *url_user; /**< User part */
+ char const *url_password; /**< Password */
+ char const *url_host; /**< Host part */
+ char const *url_port; /**< Port */
+ char const *url_path; /**< Path part, starts with "/" */
+ char const *url_params; /**< Parameters (separated by ;) */
+ char const *url_headers; /**< Headers (separated by ? and &) */
+ char const *url_fragment; /**< Fragment (separated by #) */
+} url_t;
+
+enum {
+ /** Maximum size of a URL. */
+ URL_MAXLEN = 65536
+};
+
+/** Type to present either a parsed URL or string.
+ *
+ * The union type url_string_t is used to pass a parsed URL or string as a
+ * parameter. The URL_STRING_P() checks if a passed pointer points to a
+ * string or a parsed URL. Testing requires that the first character of the
+ * string is nonzero. Use URL_STRING_MAKE() to properly cast a string
+ * pointer as a pointer to url_string_t.
+ */
+typedef union {
+ char us_str[URL_MAXLEN]; /**< URL as a string. */
+ url_t us_url[1]; /**< Parsed URL. */
+} url_string_t;
+
+#endif
+
+#ifndef URL_H
+/** Defined when <sofia-sip/url.h> has been included. */
+#define URL_H
+
+#ifndef SU_ALLOC_H
+#include <sofia-sip/su_alloc.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** Convert a string to a url struct. */
+SOFIAPUBFUN url_t *url_make(su_home_t *h, char const *str);
+
+/** Convert a string formatting result to a url struct. */
+SOFIAPUBFUN url_t *url_format(su_home_t *h, char const *fmt, ...);
+
+/** Convert #url_t to a string allocated from @a home */
+SOFIAPUBFUN char *url_as_string(su_home_t *home, url_t const *url);
+
+/** Duplicate the url to memory allocated via home */
+SOFIAPUBFUN url_t *url_hdup(su_home_t *h, url_t const *src);
+
+/** Sanitize a URL. */
+SOFIAPUBFUN int url_sanitize(url_t *u);
+
+/** Get URL scheme by type. */
+SOFIAPUBFUN char const *url_scheme(enum url_type_e type);
+
+/* ---------------------------------------------------------------------- */
+/* URL comparison */
+
+/** Compare two URLs lazily. */
+SOFIAPUBFUN int url_cmp(url_t const *a, url_t const *b);
+
+/** Compare two URLs conservatively. */
+SOFIAPUBFUN int url_cmp_all(url_t const *a, url_t const *b);
+
+/* ---------------------------------------------------------------------- */
+/* Parameter handling */
+
+/** Search for a parameter. */
+SOFIAPUBFUN isize_t url_param(char const *params, char const *tag,
+ char value[], isize_t vlen);
+
+/** Check for a parameter. */
+SOFIAPUBFUN int url_has_param(url_t const *url, char const *name);
+
+/** Check for a presence of a parameter in string. */
+SOFIAPUBFUN isize_t url_have_param(char const *params, char const *tag);
+
+/** Add a parameter. */
+SOFIAPUBFUN int url_param_add(su_home_t *h, url_t *url, char const *param);
+
+/** Strip transport-specific stuff away from URI. */
+SOFIAPUBFUN int url_strip_transport(url_t *u);
+
+/** Strip parameter away from URI. */
+SOFIAPUBFUN char *url_strip_param_string(char *params, char const *name);
+
+/** Test if url has any transport-specific stuff. */
+SOFIAPUBFUN int url_have_transport(url_t const *u);
+
+/* ---------------------------------------------------------------------- */
+/* Query handling */
+
+/** Convert a URL query to a header string. */
+SOFIAPUBFUN char *url_query_as_header_string(su_home_t *home,
+ char const *query);
+
+/* ---------------------------------------------------------------------- */
+/* Handling url-escque strings */
+
+/** Test if string contains url-reserved characters. */
+SOFIAPUBFUN int url_reserved_p(char const *s);
+
+/** Escape a string. */
+SOFIAPUBFUN char *url_escape(char *d, char const *s, char const reserved[]);
+
+/** Calculate length of string when escaped. */
+SOFIAPUBFUN isize_t url_esclen(char const *s, char const reserved[]);
+
+/** Unescape characters from string */
+SOFIAPUBFUN size_t url_unescape_to(char *d, char const *s, size_t n);
+
+/** Unescape a string */
+SOFIAPUBFUN char *url_unescape(char *d, char const *s);
+
+#define URL_RESERVED_CHARS ";/?:@&=+$,"
+
+/* ---------------------------------------------------------------------- */
+/* Initializing */
+
+/** Initializer for an #url_t structure. @HI
+ *
+ * The macro URL_INIT_AS() is used to initialize a #url_t structure with a
+ * known url type:
+ * @code
+ * url_t urls[2] = { URL_INIT_AS(sip), URL_INIT_AS(http) };
+ * @endcode
+ */
+#define URL_INIT_AS(type) \
+ { "\0\0", url_##type, 0, url_##type != url_any ? #type : "*" }
+
+/** Init a url structure as given type */
+SOFIAPUBFUN void url_init(url_t *url, enum url_type_e type);
+
+/* ---------------------------------------------------------------------- */
+/* Resolving helpers */
+
+/** Return default port number corresponding to the url type. */
+SOFIAPUBFUN char const *url_port_default(enum url_type_e url_type);
+
+/** Return default transport name corresponding to the url type */
+SOFIAPUBFUN char const *url_tport_default(enum url_type_e url_type);
+
+/** Return the URL port string, using default port if not present. */
+SOFIAPUBFUN char const *url_port(url_t const *u);
+
+/** Return the URL port string, using default port if none present. */
+#define URL_PORT(u) \
+ ((u) && (u)->url_port ? (u)->url_port : \
+ url_port_default((u) ? (u)->url_type : url_any))
+
+/* ---------------------------------------------------------------------- */
+/* url_string_t handling */
+
+/** Test if a pointer to #url_string_t is a string
+ * (not a pointer to a #url_t structure). */
+#define URL_STRING_P(u) ((u) && *((url_string_t*)(u))->us_str != 0)
+
+/** Test if a pointer to #url_string_t is a string
+ * (not a pointer to a #url_t structure). */
+#define URL_IS_STRING(u) ((u) && *((url_string_t*)(u))->us_str != 0)
+
+/** Test if a pointer to #url_string_t is a string
+ * (not a pointer to a #url_t structure). */
+SOFIAPUBFUN int url_string_p(url_string_t const * url);
+
+/** Test if a pointer to #url_string_t is a string
+ * (not a pointer to a #url_t structure). */
+SOFIAPUBFUN int url_is_string(url_string_t const * url);
+
+/** Cast a string to a #url_string_t. @HI */
+#define URL_STRING_MAKE(s) \
+ ((url_string_t *)((s) && *((char *)(s)) ? (s) : NULL))
+
+/* ---------------------------------------------------------------------- */
+/* Printing URL */
+
+/** Format string used when printing url with printf(). @HI */
+#define URL_PRINT_FORMAT "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
+#define URL_FORMAT_STRING URL_PRINT_FORMAT
+
+/** Argument list used when printing url with printf(). @HI */
+#define URL_PRINT_ARGS(u) \
+ (u)->url_scheme ? (u)->url_scheme : "", \
+ (u)->url_type != url_any && (u)->url_scheme && (u)->url_scheme[0] \
+ ? ":" : "", \
+ (u)->url_root && ((u)->url_host || (u)->url_user) ? "//" : "", \
+ (u)->url_user ? (u)->url_user : "", \
+ (u)->url_user && (u)->url_password ? ":" : "", \
+ (u)->url_user && (u)->url_password ? (u)->url_password : "", \
+ (u)->url_user && (u)->url_host ? "@" : "", \
+ (u)->url_host ? (u)->url_host : "", \
+ (u)->url_host && (u)->url_port ? ":" : "", \
+ (u)->url_host && (u)->url_port ? (u)->url_port : "", \
+ (u)->url_root && (u)->url_path ? "/" : "", \
+ (u)->url_path ? (u)->url_path : "", \
+ (u)->url_params ? ";" : "", (u)->url_params ? (u)->url_params : "", \
+ (u)->url_headers ? "?" : "", (u)->url_headers ? (u)->url_headers : "", \
+ (u)->url_fragment ? "#" : "", (u)->url_fragment ? (u)->url_fragment : ""
+
+/* ---------------------------------------------------------------------- */
+/* URL digests */
+
+struct su_md5_t;
+
+/** Update MD5 sum with URL contents. */
+SOFIAPUBFUN void url_update(struct su_md5_t *md5, url_t const *url);
+
+/** Calculate a digest from URL contents. */
+SOFIAPUBFUN void url_digest(void *hash, int hsize,
+ url_t const *, char const *key);
+
+/* ---------------------------------------------------------------------- */
+/* Parsing and manipulating URLs */
+
+/** Decode a URL. */
+SOFIAPUBFUN int url_d(url_t *url, char *s);
+
+/** Calculate the encoding length of URL. */
+SOFIAPUBFUN isize_t url_len(url_t const * url);
+
+/** Encode a URL. */
+SOFIAPUBFUN issize_t url_e(char buffer[], isize_t n, url_t const *url);
+
+/** Encode a URL: use @a buf up to @a end. @HI */
+#define URL_E(buf, end, url) \
+ (buf) += url_e((buf), (buf) < (end) ? (end) - (buf) : 0, (url))
+
+/** Calculate the size of srings attached to the url. */
+SOFIAPUBFUN isize_t url_xtra(url_t const * url);
+
+/** Duplicate the url in the provided memory area. */
+SOFIAPUBFUN issize_t url_dup(char *, isize_t , url_t *dst, url_t const *src);
+
+/** Duplicate the url: use @a buf up to @a end. @HI */
+#define URL_DUP(buf, end, dst, src) \
+ (buf) += url_dup((buf), (isize_t)((buf) < (end) ? (end) - (buf) : 0), (dst), (src))
+
+SOFIA_END_DECLS
+#endif
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/sofia-sip/url_tag.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/sofia-sip/url_tag.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,74 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef URL_TAG_H
+/** Defined when <sofia-sip/url_tag.h> has been included. */
+#define URL_TAG_H
+/**@file url_tag.h
+ * @brief Tags for URLs
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Feb 21 11:01:45 2001 ppessi
+ */
+
+#ifndef SU_TAG_H
+#include <sofia-sip/su_tag.h>
+#endif
+
+#ifndef URL_H
+#define URL_H
+#include <sofia-sip/url.h> /* Include only types */
+#undef URL_H
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** Filter tag matching any url tag. */
+#define URLTAG_ANY() urltag_any, ((tag_value_t)0)
+SOFIAPUBVAR tag_typedef_t urltag_any;
+
+SOFIAPUBVAR tag_typedef_t urltag_url;
+
+/** Tag list item for an URL. */
+#define URLTAG_URL(u) urltag_url, urltag_url_v(u)
+
+SOFIAPUBVAR tag_typedef_t urltag_url_ref;
+
+#define URLTAG_URL_REF(u) urltag_url_ref, urltag_url_vr(&(u))
+
+#if SU_HAVE_INLINE
+su_inline
+tag_value_t urltag_url_v(void const *v) { return (tag_value_t)v; }
+su_inline
+tag_value_t urltag_url_vr(url_string_t const **vp) { return(tag_value_t)vp; }
+#else
+#define urltag_url_v(v) (tag_value_t)(v)
+#define urltag_url_vr(vr) (tag_value_t)(vr)
+#endif
+
+
+SOFIA_END_DECLS
+#endif
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/sofia-sip/url_tag_class.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/sofia-sip/url_tag_class.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,56 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef URL_TAG_CLASS_H
+/**Defined when <sofia-sip/url_tag_class.h> has been included. */
+#define URL_TAG_CLASS_H
+/**@file url_tag_class.h
+ * @brief Tag classes for URLs
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Feb 21 11:01:45 2001 ppessi
+ */
+
+#ifndef SU_TAG_H
+#include <sofia-sip/su_tag.h>
+#endif
+#ifndef SU_TAG_CLASS_H
+#include <sofia-sip/su_tag_class.h>
+#endif
+#ifndef SU_TAG_CLASS_H
+#include <sofia-sip/su_tag_class.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+SOFIAPUBVAR tag_class_t url_tag_class[1];
+
+#define URLTAG_TYPEDEF(t) TAG_TYPEDEF(t, url)
+
+SOFIA_END_DECLS
+
+#endif
+
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/torture_url.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/torture_url.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1061 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE torture_url.c Test functions for url parser
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Aug 21 15:18:26 2001 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include "sofia-sip/url.h"
+#include "sofia-sip/url_tag.h"
+
+static int tstflags = 0;
+
+#define TSTFLAGS tstflags
+
+#include <sofia-sip/tstdef.h>
+
+char const name[] = "torture_url";
+
+void usage(void)
+{
+ fprintf(stderr, "usage: %s [-v]\n", name);
+}
+
+unsigned char hash1[16], hash2[16];
+
+/* test unquoting and canonizing */
+int test_quote(void)
+{
+ su_home_t home[1] = { SU_HOME_INIT(home) };
+ url_t *u;
+ char s[] = "%73ip:q%74est%01:%01%02%00 at host%2enokia.com;%70aram=%01%02";
+ char c[] = "sip:qtest%01:%01%02%00 at host.nokia.com;param=%01%02";
+ char *d;
+
+#define RESERVED ";/?:@&=+$,"
+#define DELIMS "<>#%\""
+#define UNWISE "{}|\\^[]`"
+#define EXCLUDED RESERVED DELIMS UNWISE
+
+ char escaped[1 + 3 * 23 + 1];
+
+#define UNRESERVED "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
+ "abcdefghijklmnopqrstuvwxyz" \
+ "0123456789" \
+ "-_.!~*'()"
+
+ char unreserved[26 + 26 + 10 + 9 + 1];
+
+ BEGIN();
+
+ d = url_as_string(home, (url_t *)"sip:joe at example.com");
+ TEST_S(d, "sip:joe at example.com");
+
+ TEST(strlen(EXCLUDED), 23);
+ TEST(strlen(UNRESERVED), 71);
+
+ TEST_1(!url_reserved_p("foo"));
+ TEST_1(!url_reserved_p(""));
+ TEST_1(url_reserved_p("foobar:bar"));
+
+ TEST_SIZE(url_esclen("a" EXCLUDED, ""),
+ 1 + strlen(RESERVED) + 3 * strlen(DELIMS UNWISE));
+ TEST_SIZE(url_esclen("a" EXCLUDED, DELIMS UNWISE),
+ 1 + strlen(RESERVED) + 3 * strlen(DELIMS UNWISE));
+ TEST_SIZE(url_esclen("a" EXCLUDED, EXCLUDED), 1 + 3 * strlen(EXCLUDED));
+ TEST_SIZE(url_esclen("a" EXCLUDED, NULL), 1 + 3 * strlen(EXCLUDED));
+
+ TEST_S(url_escape(escaped, "a" EXCLUDED, NULL),
+ "a%3B%2F%3F%3A%40%26%3D%2B%24%2C"
+ "%3C%3E%23%25%22"
+ "%7B%7D%7C%5C%5E%5B%5D%60");
+ TEST_S(url_unescape(escaped, escaped), "a" EXCLUDED);
+
+ TEST_SIZE(url_esclen(UNRESERVED, NULL), strlen(UNRESERVED));
+ TEST_S(url_escape(unreserved, UNRESERVED, NULL), UNRESERVED);
+ TEST_S(url_unescape(unreserved, UNRESERVED), UNRESERVED);
+
+ d = "%73ip:%55@%68";
+ u = url_hdup(home, (url_t *)d); TEST_1(u);
+ url_digest(hash1, sizeof(hash1), u, NULL);
+ url_digest(hash2, sizeof(hash2), (url_t const *)d, NULL);
+ TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);
+
+ d = "sip:u at h";
+ u = url_hdup(home, (url_t *)d); TEST_1(u);
+ url_digest(hash1, sizeof(hash1), u, NULL);
+ TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);
+ url_digest(hash2, sizeof(hash2), (url_t const *)d, NULL);
+ TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);
+
+ u = url_hdup(home, (url_t *)s); TEST_1(u);
+ d = url_as_string(home, u); TEST_1(d);
+ TEST_S(d, c);
+
+ d = "sip:&=+$,;?/:&=+$, at host:56001;param=+$,/:@&;another=@"
+ "?header=" RESERVED "&%3b%2f%3f%3a%40%26%3d%2b%24%2c";
+ u = url_hdup(home, (url_t *)d); TEST_1(u);
+ TEST_S(u->url_headers, "header=" RESERVED "&%3B%2F%3F%3A%40%26%3D%2B%24%2C");
+ url_digest(hash1, sizeof(hash1), u, NULL);
+ url_digest(hash2, sizeof(hash2), (url_t const *)d, NULL);
+ TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);
+
+ u = url_hdup(home, (url_t *)s); TEST_1(u);
+ d = url_as_string(home, u); TEST_1(d);
+ TEST_S(d, c);
+
+ d = "http://&=+$,;:&=+$,;@host:8080/foo;param=+$,/:@&;another=@?query=" RESERVED;
+ u = url_hdup(home, (url_t *)d); TEST_1(u);
+ url_digest(hash1, sizeof(hash1), u, NULL);
+ url_digest(hash2, sizeof(hash2), (url_t const *)d, NULL);
+ TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);
+
+ u = url_hdup(home, (url_t *)s); TEST_1(u);
+ d = url_as_string(home, u); TEST_1(d);
+ TEST_S(d, c);
+
+ url_digest(hash1, sizeof(hash1), u, NULL);
+ url_digest(hash2, sizeof(hash2), (url_t const *)s, NULL);
+ TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);
+
+ url_digest(hash2, sizeof(hash2), (url_t const *)c, NULL);
+ TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);
+
+ END();
+}
+
+
+int test_any(void)
+{
+ /* Test any (*) urls */
+ url_t any[1] = { URL_INIT_AS(any) };
+ su_home_t home[1] = { SU_HOME_INIT(home) };
+ url_t *u, url[1];
+ char *tst;
+
+ BEGIN();
+
+ TEST_S(url_scheme(url_any), "*");
+ TEST_S(url_scheme(url_mailto), "mailto");
+ TEST_S(url_scheme(url_im), "im");
+ TEST_S(url_scheme(url_cid), "cid");
+ TEST_S(url_scheme(url_msrp), "msrp");
+ TEST_S(url_scheme(url_msrps), "msrps");
+
+ TEST_1(tst = su_strdup(home, "*"));
+ TEST(url_d(url, tst), 0);
+ TEST(url_cmp(any, url), 0);
+ TEST(url->url_type, url_any);
+ TEST_1(u = url_hdup(home, url));
+ TEST(u->url_type, url_any);
+ TEST(url_cmp(any, u), 0);
+
+ url_digest(hash1, sizeof(hash1), url, NULL);
+ url_digest(hash2, sizeof(hash2), (url_t *)"*", NULL);
+ TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);
+
+ {
+ char buf[6];
+
+ TEST_1(u = url_hdup(home, (void *)"error"));
+ TEST_SIZE(url_xtra(u), 6);
+ TEST_SIZE(url_dup(buf, 6, url, u), 6);
+ TEST_S(buf, "error");
+ }
+
+ {
+ TEST_1(u = url_hdup(home, (void *)"scheme:test"));
+ TEST(u->url_type, url_unknown);
+ }
+
+ {
+ TEST_1(u = url_hdup(home, (void *)"*;param=foo?query=bar"));
+ TEST(u->url_type, url_unknown);
+ TEST_S(u->url_host, "*");
+ TEST_S(u->url_params, "param=foo");
+ TEST_S(u->url_headers, "query=bar");
+ }
+
+ {
+ TEST_1(u = url_hdup(home, (void *)"#foo"));
+ TEST(u->url_type, url_unknown);
+ TEST_S(u->url_fragment, "foo");
+ }
+
+ su_home_deinit(home);
+
+ END();
+}
+
+int test_sip(void)
+{
+ /* sip urls */
+ su_home_t home[1] = { SU_HOME_INIT(home) };
+ url_t sip[1] = { URL_INIT_AS(sip) };
+ url_t *u, url[1];
+ char *tst, *s;
+ char sipurl0[] =
+ "sip:pekka%2Epessi at nokia%2Ecom;method=%4D%45%53%53%41%47%45"
+ "?body=CANNED%20MSG";
+ char sipurl[] =
+ "sip:user:pass at host:32;param=1"
+ "?From=foo at bar&To=bar at baz#unf";
+ char sip2url[] =
+ "sip:user/path;tel-param:pass at host:32;param=1"
+ "?From=foo at bar&To=bar at baz#unf";
+ char sip2[sizeof(sipurl) + 32];
+ char sipsurl[] =
+ "sips:user:pass at host:32;param=1"
+ "?From=foo at bar&To=bar at baz#unf";
+ size_t i, j;
+ url_t *a, *b;
+
+ BEGIN();
+
+ TEST_S(url_scheme(url_sip), "sip");
+ TEST_S(url_scheme(url_sips), "sips");
+
+ memset(url, 255, sizeof url);
+
+ TEST(url_d(url, sipurl0), 0);
+
+ TEST(url->url_type, url_sip);
+ TEST(url->url_root, 0);
+ TEST_S(url->url_scheme, "sip");
+ TEST_S(url->url_user, "pekka.pessi");
+ TEST_P(url->url_password, NULL);
+ TEST_S(url->url_host, "nokia.com");
+ TEST_P(url->url_port, NULL);
+ TEST_P(url->url_path, NULL);
+ TEST_S(url->url_params, "method=MESSAGE");
+ TEST_S(url->url_headers, "body=CANNED%20MSG");
+ TEST_P(url->url_fragment, NULL);
+
+ TEST_S(url_query_as_header_string(home, url->url_headers),
+ "\n\nCANNED MSG");
+
+ sip->url_user = "user";
+ sip->url_password = "pass";
+ sip->url_host = "host";
+ sip->url_port = "32";
+ sip->url_params = "param=1";
+ sip->url_headers = "From=foo at bar&To=bar at baz";
+ sip->url_fragment = "unf";
+
+ memset(url, 255, sizeof url);
+
+ TEST_1(tst = su_strdup(home, sipurl));
+ TEST_1(url_d(url, tst) == 0);
+ TEST_1(url_cmp(sip, url) == 0);
+ TEST(url->url_type, url_sip);
+ TEST_1(u = url_hdup(home, url));
+ TEST(u->url_type, url_sip);
+ TEST_1(url_cmp(sip, u) == 0);
+ TEST(url_e(sip2, sizeof(sip2), u), strlen(sipurl));
+ TEST_1(strcmp(sip2, sipurl) == 0);
+ TEST_SIZE(snprintf(sip2, sizeof(sip2), URL_PRINT_FORMAT,
+ URL_PRINT_ARGS(sip)), strlen(sipurl));
+ TEST_1(strcmp(sip2, sipurl) == 0);
+
+ url_digest(hash1, sizeof(hash1), url, NULL);
+ url_digest(hash2, sizeof(hash2), (url_t const *)sipurl, NULL);
+ TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);
+
+ TEST_1(tst = su_strdup(home, sip2url));
+ TEST_1(url_d(url, tst) == 0);
+ TEST_S(url->url_user, "user/path;tel-param");
+
+ TEST_S(url_query_as_header_string(home, url->url_headers),
+ "From:foo at bar\nTo:bar at baz");
+
+ url_digest(hash1, sizeof(hash1), url, NULL);
+ url_digest(hash2, sizeof(hash2), (url_t *)sip2url, NULL);
+ TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);
+
+ sip->url_type = url_sips; sip->url_scheme = "sips";
+
+ TEST_1(tst = su_strdup(home, sipsurl));
+ TEST_1(url_d(url, tst) == 0);
+ TEST_1(url_cmp(sip, url) == 0);
+ TEST(url->url_type, url_sips);
+
+ /* Test url_dup() */
+ for (i = 0; i <= sizeof(sipsurl); i++) {
+ char buf[sizeof(sipsurl) + 1];
+ url_t dst[1];
+
+ buf[i] = '\377';
+ TEST_SIZE(url_dup(buf, i, dst, url), sizeof(sipsurl) - 1 - strlen("sips"));
+ TEST(buf[i], '\377');
+ }
+
+ url_digest(hash1, sizeof(hash1), url, NULL);
+ url_digest(hash2, sizeof(hash2), (url_t *)sipsurl, NULL);
+ TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);
+
+ u = url_hdup(home, (url_t*)"SIP:test at 127.0.0.1:55"); TEST_1(u);
+ TEST(u->url_type, url_sip);
+
+ TEST_P(url_hdup(home, (url_t*)"sip:test at 127.0.0.1::55"), NULL);
+ TEST_P(url_hdup(home, (url_t*)"sip:test at 127.0.0.1:55:"), NULL);
+ TEST_P(url_hdup(home, (url_t*)"sip:test at 127.0.0.1:sip"), NULL);
+
+ for (i = 32; i <= 256; i++) {
+ char pu[512];
+ char param[512];
+
+ for (j = 0; j < i; j++)
+ param[j] = 'x';
+ param[j] = '\0';
+ memcpy(param, "x=", 2);
+
+ snprintf(pu, sizeof(pu), "sip:test at host;%s", param);
+ u = url_hdup(home, (url_t*)pu); TEST_1(u);
+ s = url_as_string(home, u);
+ TEST_S(pu, s);
+ }
+
+ s = su_strdup(home, "ttl;transport=tcp;ttl=15;ttl=;method=INVITE;ttl");
+ TEST_1(s);
+ s = url_strip_param_string(s, "ttl");
+ TEST_S(s, "transport=tcp;method=INVITE");
+
+ u = url_hdup(home, (void*)"sip:u:p at host:5060;maddr=127.0.0.1;transport=tcp");
+ TEST_1(u);
+ TEST_1(url_have_transport(u));
+ TEST_1(url_strip_transport(u));
+ TEST_P(u->url_params, NULL);
+ TEST_1(!url_have_transport(u));
+
+ u = url_hdup(home, (void*)"sip:u:p at host:5060;user=phone;ttl=1;isfocus");
+ TEST_1(u);
+ TEST_1(url_have_transport(u));
+ TEST_1(url_strip_transport(u));
+ TEST_S(u->url_params, "user=phone;isfocus");
+ TEST_1(!url_have_transport(u));
+
+ u = url_hdup(home, (void*)"sip:u:p at host:5060;maddr=127.0.0.1;user=phone");
+ TEST_1(u);
+ TEST_1(url_have_transport(u));
+ TEST_1(url_strip_transport(u));
+ TEST_S(u->url_params, "user=phone");
+ TEST_1(!url_have_transport(u));
+
+ u = url_hdup(home, (void*)"sip:u:p at host:5060;user=phone;transport=tcp");
+ TEST_1(u);
+ TEST_1(url_have_transport(u));
+ TEST_1(url_strip_transport(u));
+ TEST_S(u->url_params, "user=phone");
+ TEST_1(!url_have_transport(u));
+
+ u = url_hdup(home, (void*)"sip:u:p at host;user=phone;;");
+ TEST_1(u);
+ /* We don't have transport params */
+ TEST_1(!url_have_transport(u));
+ /* ...but we still strip empty params */
+ TEST_1(url_strip_transport(u));
+ TEST_S(u->url_params, "user=phone");
+ TEST_1(!url_have_transport(u));
+
+ u = url_hdup(home, (void*)"sip:u:p at host:5060;ttl=1;isfocus;transport=udp;");
+ TEST_1(u);
+ TEST_1(url_have_transport(u));
+ TEST_1(url_strip_transport(u));
+ TEST_S(u->url_params, "isfocus");
+ TEST_1(!url_have_transport(u));
+
+ a = url_hdup(home, (void *)"sip:172.21.55.55:5060");
+ b = url_hdup(home, (void *)"sip:172.21.55.55");
+ TEST_1(a); TEST_1(b);
+ TEST_1(url_cmp(a, b) == 0);
+ TEST(url_cmp_all(a, b), 0);
+
+ a = url_hdup(home, (void *)"sips:172.21.55.55:5060");
+ b = url_hdup(home, (void *)"sips:172.21.55.55");
+ TEST_1(a); TEST_1(b);
+ TEST_1(url_cmp(a, b) != 0);
+ TEST_1(url_cmp_all(a, b) < 0);
+
+ a = url_hdup(home, (void *)"sips:172.21.55.55:5061");
+ b = url_hdup(home, (void *)"sips:172.21.55.55");
+ TEST_1(a); TEST_1(b);
+ TEST_1(url_cmp(a, b) == 0);
+ TEST(url_cmp_all(a, b), 0);
+
+ a = url_hdup(home, (void *)"sip:my.domain:5060");
+ b = url_hdup(home, (void *)"sip:my.domain");
+ TEST_1(a); TEST_1(b);
+ TEST_1(url_cmp(a, b) > 0);
+ TEST_1(url_cmp_all(a, b) > 0);
+
+ a = url_hdup(home, (void *)"sips:my.domain:5061");
+ b = url_hdup(home, (void *)"sips:my.domain");
+ TEST_1(a); TEST_1(b);
+ TEST_1(url_cmp(a, b) > 0);
+ TEST_1(url_cmp_all(a, b) > 0);
+
+ a = url_hdup(home, (void *)"sip:my.domain");
+ b = url_hdup(home, (void *)"SIP:MY.DOMAIN");
+ TEST_1(a); TEST_1(b);
+ TEST_1(url_cmp(a, b) == 0);
+ TEST_1(url_cmp_all(a, b) == 0);
+
+ su_home_deinit(home);
+
+ END();
+}
+
+int test_wv(void)
+{
+ /* wv urls */
+ su_home_t home[1] = { SU_HOME_INIT(home) };
+ url_t wv[1] = { URL_INIT_AS(wv) };
+ url_t *u, url[1];
+ char *tst;
+ char wvurl[] = "wv:+12345678 at imps.com";
+ char wv2[sizeof(wvurl) + 32];
+
+ BEGIN();
+
+ TEST_S(url_scheme(url_wv), "wv");
+
+ wv->url_user = "+12345678";
+ wv->url_host = "imps.com";
+
+ TEST_1(tst = su_strdup(home, wvurl));
+ TEST_1(url_d(url, tst) == 0);
+ TEST_1(url_cmp(wv, url) == 0);
+ TEST_1(url_cmp(url_hdup(home, (void *)"wv:+12345678 at imps.com"), url) == 0);
+ TEST(url->url_type, url_wv);
+ TEST_1(u = url_hdup(home, url));
+ TEST(u->url_type, url_wv);
+ TEST_1(url_cmp(wv, u) == 0);
+ TEST_SIZE(url_e(wv2, sizeof(wv2), u), strlen(wvurl));
+ TEST_1(strcmp(wv2, wvurl) == 0);
+ TEST_SIZE(snprintf(wv2, sizeof(wv2), URL_PRINT_FORMAT,
+ URL_PRINT_ARGS(wv)), strlen(wvurl));
+ TEST_1(strcmp(wv2, wvurl) == 0);
+
+ url_digest(hash1, sizeof(hash1), url, NULL);
+ url_digest(hash2, sizeof(hash2), (url_t *)wvurl, NULL);
+ TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);
+
+ TEST_1(u = url_hdup(home, (void*)"wv:/managers at imps.com"));
+ TEST_S(u->url_user, "/managers");
+
+ su_home_deinit(home);
+
+ END();
+}
+
+
+int test_tel(void)
+{
+ /* tel urls: RFC 3906 */
+ su_home_t home[1] = { SU_HOME_INIT(home) };
+ url_t tel[1] = { URL_INIT_AS(tel) };
+ url_t *u, url[1];
+ char *tst;
+ char telurl[] =
+ "tel:+12345678"
+ ";param=1;param=2"
+ "?From=foo at bar&To=bar at baz#unf";
+ char tel2[sizeof(telurl) + 32];
+ url_t *a, *b;
+
+ BEGIN();
+
+ TEST_S(url_scheme(url_tel), "tel");
+
+ tel->url_user = "+12345678";
+ tel->url_params = "param=1;param=2";
+ tel->url_headers = "From=foo at bar&To=bar at baz";
+ tel->url_fragment = "unf";
+
+ TEST_1(tst = su_strdup(home, telurl));
+ TEST_1(url_d(url, tst) == 0);
+ TEST_1(url_cmp(tel, url) == 0);
+ TEST_1(url_cmp(url_hdup(home, (url_t const *)"tel:+12345678"
+ ";param=1;param=2"
+ "?From=foo at bar&To=bar at baz#unf"), url) == 0);
+ TEST(url->url_type, url_tel);
+ TEST_1(u = url_hdup(home, url));
+ TEST(u->url_type, url_tel);
+ TEST_1(url_cmp(tel, u) == 0);
+ TEST_SIZE(url_e(tel2, sizeof(tel2), u), strlen(telurl));
+ TEST_1(strcmp(tel2, telurl) == 0);
+ TEST_SIZE(snprintf(tel2, sizeof(tel2), URL_PRINT_FORMAT,
+ URL_PRINT_ARGS(tel)), strlen(telurl));
+ TEST_1(strcmp(tel2, telurl) == 0);
+
+ url_digest(hash1, sizeof(hash1), url, NULL);
+ url_digest(hash2, sizeof(hash2), (url_t *)telurl, NULL);
+ TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);
+
+ a = url_hdup(home, (void *)"tel:+1.245.62357");
+ b = url_hdup(home, (void *)"tel:+(1).245.62357");
+ TEST_1(a); TEST_1(b);
+ TEST_1(url_cmp(a, b) == 0);
+ TEST_1(url_cmp_all(a, b) == 0);
+
+ su_home_deinit(home);
+
+ END();
+}
+
+int test_fax(void)
+{
+ /* fax urls */
+ su_home_t home[1] = { SU_HOME_INIT(home) };
+ url_t fax[1] = { URL_INIT_AS(fax) };
+ url_t *u, url[1];
+ char *tst;
+ char faxurl[] =
+ "fax:+12345678"
+ ";param=1;param=2"
+ "?From=foo at bar&To=bar at baz#unf";
+ char fax2[sizeof(faxurl) + 32];
+
+ BEGIN();
+
+ TEST_S(url_scheme(url_fax), "fax");
+
+ fax->url_user = "+12345678";
+ fax->url_params = "param=1;param=2";
+ fax->url_headers = "From=foo at bar&To=bar at baz";
+ fax->url_fragment = "unf";
+
+ TEST_1(tst = su_strdup(home, faxurl));
+ TEST_1(url_d(url, tst) == 0);
+ TEST_1(url_cmp(fax, url) == 0);
+ TEST(url->url_type, url_fax);
+ TEST_1(u = url_hdup(home, url));
+ TEST(u->url_type, url_fax);
+ TEST_1(url_cmp(fax, u) == 0);
+ TEST_SIZE(url_e(fax2, sizeof(fax2), u), strlen(faxurl));
+ TEST_1(strcmp(fax2, faxurl) == 0);
+ TEST_SIZE(snprintf(fax2, sizeof(fax2), URL_PRINT_FORMAT,
+ URL_PRINT_ARGS(fax)), strlen(faxurl));
+ TEST_1(strcmp(fax2, faxurl) == 0);
+
+
+ url_digest(hash1, sizeof(hash1), url, NULL);
+ url_digest(hash2, sizeof(hash2), (url_t *)faxurl, NULL);
+ TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);
+
+ su_home_deinit(home);
+
+ END();
+}
+
+int test_modem(void)
+{
+ /* modem urls */
+ su_home_t home[1] = { SU_HOME_INIT(home) };
+ url_t modem[1] = { URL_INIT_AS(modem) };
+ url_t *u, url[1];
+ char *tst;
+ char modemurl[] =
+ "modem:+12345678"
+ ";param=1;param=2"
+ "?From=foo at bar&To=bar at baz#unf";
+ char modem2[sizeof(modemurl) + 32];
+
+ BEGIN();
+
+ TEST_S(url_scheme(url_modem), "modem");
+
+ modem->url_user = "+12345678";
+ modem->url_params = "param=1;param=2";
+ modem->url_headers = "From=foo at bar&To=bar at baz";
+ modem->url_fragment = "unf";
+
+ TEST_1(tst = su_strdup(home, modemurl));
+ TEST_1(url_d(url, tst) == 0);
+ TEST_1(url_cmp(modem, url) == 0);
+ TEST(url->url_type, url_modem);
+ TEST_1(u = url_hdup(home, url));
+ TEST(u->url_type, url_modem);
+ TEST_1(url_cmp(modem, u) == 0);
+ TEST_SIZE(url_e(modem2, sizeof(modem2), u), strlen(modemurl));
+ TEST_1(strcmp(modem2, modemurl) == 0);
+ TEST_SIZE(snprintf(modem2, sizeof(modem2), URL_PRINT_FORMAT,
+ URL_PRINT_ARGS(modem)), strlen(modemurl));
+ TEST_1(strcmp(modem2, modemurl) == 0);
+
+ url_digest(hash1, sizeof(hash1), url, NULL);
+ url_digest(hash2, sizeof(hash2), (url_t *)modemurl, NULL);
+ TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);
+
+ su_home_deinit(home);
+
+ END();
+}
+
+int test_file(void)
+{
+ /* Test a url with path like file:/foo/bar */
+ char fileurl[] = "file:/foo/bar";
+ url_t file[1] = { URL_INIT_AS(file) };
+ su_home_t home[1] = { SU_HOME_INIT(home) };
+ char *tst;
+ url_t *u, url[1];
+ char buf1[sizeof(fileurl) + 32];
+ char buf2[sizeof(fileurl) + 32];
+
+ BEGIN();
+
+ TEST_S(url_scheme(url_file), "file");
+
+ TEST_1(tst = su_strdup(home, fileurl));
+ TEST(url_d(url, tst), 0);
+ file->url_root = '/';
+ file->url_path = "foo/bar";
+ TEST(url_cmp(file, url), 0);
+ TEST(url->url_type, url_file);
+ TEST_1(u = url_hdup(home, url));
+ TEST(u->url_type, url_file);
+ TEST(url_cmp(file, u), 0);
+ TEST_SIZE(url_e(buf1, sizeof(buf1), u), strlen(fileurl));
+ TEST_S(buf1, fileurl);
+ TEST_SIZE(snprintf(buf2, sizeof(buf2), URL_PRINT_FORMAT, URL_PRINT_ARGS(u)),
+ strlen(fileurl));
+ TEST_S(buf2, fileurl);
+
+ url_digest(hash1, sizeof(hash1), url, NULL);
+ url_digest(hash2, sizeof(hash2), (url_t *)fileurl, NULL);
+ TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);
+
+ su_home_deinit(home);
+
+ END();
+}
+
+int test_ldap(void)
+{
+ /* Test a LDAP url */
+ char ldapurl[] = "ldap://cn=Manager,o=nokia:secret@localhost:389/ou=devices,o=nokia";
+ url_t ldap[1] = { URL_INIT_AS(file) };
+ su_home_t home[1] = { SU_HOME_INIT(home) };
+ char *tst;
+ url_t *u, url[1];
+ char buf1[sizeof(ldapurl) + 32];
+ char buf2[sizeof(ldapurl) + 32];
+
+ BEGIN();
+
+ ldap->url_type = url_unknown;
+ ldap->url_scheme = "ldap";
+
+ /* TEST_S(url_scheme(url_ldap), "ldap"); */
+
+ TEST_1(tst = su_strdup(home, ldapurl));
+ TEST(url_d(url, tst), 0);
+
+ TEST_S(url->url_user, "cn=Manager,o=nokia:secret");
+ /* TEST_S(url->url_password, "secret"); */
+ TEST_S(url->url_host, "localhost");
+ TEST_S(url->url_port, "389");
+ TEST_S(url->url_path, "ou=devices,o=nokia");
+
+ ldap->url_user = "cn=Manager,o=nokia";
+ ldap->url_password = "secret";
+ ldap->url_user = "cn=Manager,o=nokia:secret", ldap->url_password = NULL;
+ ldap->url_host = "localhost";
+ ldap->url_port = "389";
+ ldap->url_path = "ou=devices,o=nokia";
+
+ TEST(url_cmp(ldap, url), 0);
+ TEST(url->url_type, url_unknown);
+ TEST_S(url->url_scheme, "ldap");
+ TEST_1(u = url_hdup(home, url));
+ TEST(u->url_type, url_unknown);
+ TEST_S(u->url_scheme, "ldap");
+ TEST(url_cmp(ldap, u), 0);
+ TEST_SIZE(url_e(buf1, sizeof(buf1), u), strlen(ldapurl));
+ TEST_S(buf1, ldapurl);
+ TEST_SIZE(snprintf(buf2, sizeof(buf2), URL_PRINT_FORMAT, URL_PRINT_ARGS(u)),
+ strlen(ldapurl));
+ TEST_S(buf2, ldapurl);
+
+ url_digest(hash1, sizeof(hash1), url, NULL);
+ url_digest(hash2, sizeof(hash2), (url_t *)ldapurl, NULL);
+ TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);
+
+ su_home_deinit(home);
+
+ END();
+}
+
+int test_rtsp(void)
+{
+ /* RTSP urls */
+ su_home_t home[1] = { SU_HOME_INIT(home) };
+ url_t rtsp[1] = { URL_INIT_AS(rtsp) };
+ url_t *u, url[1];
+ char *tst;
+ char rtspurl[] = "rtsp://example.com:42/barfoo.rm";
+ char rtspuurl[] = "rtspu://example.com:42/barfoo.rm";
+ char rtsp2[sizeof(rtspurl) + 32];
+
+ BEGIN();
+
+ TEST_S(url_scheme(url_rtsp), "rtsp");
+ TEST_S(url_scheme(url_rtspu), "rtspu");
+
+ rtsp->url_root = 1;
+ rtsp->url_host = "example.com";
+ rtsp->url_port = "42";
+ rtsp->url_path = "barfoo.rm";
+
+ TEST_1(tst = su_strdup(home, rtspurl));
+ TEST_1(url_d(url, tst) == 0);
+ TEST_1(url_cmp(rtsp, url) == 0);
+ TEST(url->url_type, url_rtsp);
+ TEST_1(u = url_hdup(home, url));
+ TEST(u->url_type, url_rtsp);
+ TEST_1(url_cmp(rtsp, u) == 0);
+ TEST(url_e(rtsp2, sizeof(rtsp2), u), strlen(rtspurl));
+ TEST_1(strcmp(rtsp2, rtspurl) == 0);
+ TEST_SIZE(snprintf(rtsp2, sizeof(rtsp2), URL_PRINT_FORMAT,
+ URL_PRINT_ARGS(rtsp)), strlen(rtspurl));
+ TEST_1(strcmp(rtsp2, rtspurl) == 0);
+
+ url_digest(hash1, sizeof(hash1), url, NULL);
+ url_digest(hash2, sizeof(hash2), (url_t *)rtspurl, NULL);
+ TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);
+
+ su_home_deinit(home);
+ rtsp->url_type = url_rtspu, rtsp->url_scheme = "rtspu";
+
+ TEST_1(tst = su_strdup(home, rtspuurl));
+ TEST_1(url_d(url, tst) == 0);
+ TEST_1(url_cmp(rtsp, url) == 0);
+ TEST(url->url_type, url_rtspu);
+
+ url_digest(hash1, sizeof(hash1), url, NULL);
+ url_digest(hash2, sizeof(hash2), (url_t *)rtspuurl, NULL);
+ TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);
+
+ su_home_deinit(home);
+
+ END();
+}
+
+int test_http(void)
+{
+ /* http urls */
+ su_home_t home[1] = { SU_HOME_INIT(home) };
+ url_t http[1] = { URL_INIT_AS(http) };
+ url_t *u, url[1];
+ char *tst;
+ char httpurl[] =
+ "http://user:pass@host:32/foo;param=1/bar;param=3"
+ "?From=foo at bar&To=bar at baz#unf";
+ char http2[sizeof(httpurl) + 32];
+
+ char queryonly[] =
+ "http://some.host?query";
+
+ BEGIN();
+
+ TEST_S(url_scheme(url_http), "http");
+ TEST_S(url_scheme(url_https), "https");
+
+ http->url_root = '/';
+ http->url_user = "user";
+ http->url_password = "pass";
+ http->url_host = "host";
+ http->url_port = "32";
+ http->url_path = "foo;param=1/bar;param=3";
+ http->url_headers = "From=foo at bar&To=bar at baz";
+ http->url_fragment = "unf";
+
+ TEST_1(tst = su_strdup(home, httpurl));
+ TEST_1(url_d(url, tst) == 0);
+ TEST_1(url_cmp(http, url) == 0);
+ TEST(url->url_type, url_http);
+ TEST_1(u = url_hdup(home, url));
+ TEST(u->url_type, url_http);
+ TEST_1(url_cmp(http, u) == 0);
+ TEST_SIZE(url_e(http2, sizeof(http2), u), strlen(httpurl));
+ TEST_1(strcmp(http2, httpurl) == 0);
+ TEST_SIZE(snprintf(http2, sizeof(http2), URL_PRINT_FORMAT,
+ URL_PRINT_ARGS(http)), strlen(httpurl));
+ TEST_1(strcmp(http2, httpurl) == 0);
+
+ url_digest(hash1, sizeof(hash1), http, NULL);
+ url_digest(hash2, sizeof(hash2), (url_t *)httpurl, NULL);
+ TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);
+
+ memset(url, 0, sizeof url);
+ TEST_1(tst = su_strdup(home, queryonly));
+ TEST(url_d(url, tst), 0);
+ TEST_S(url->url_host, "some.host");
+ TEST_S(url->url_headers, "query");
+ TEST_S(url->url_params, NULL);
+
+ su_home_deinit(home);
+
+ END();
+}
+
+int test_sanitizing(void)
+{
+ url_t url[1];
+ char www[] = "www.hut.fi";
+ char ftp[] = "ftp.hut.fi";
+ char www2[] = "iptel.hut.fi/humppa";
+ char sip[] = "test.host";
+ char buf[64];
+
+ BEGIN();
+
+ TEST_1(url_d(url, www) == 0);
+ TEST_1(url_sanitize(url) == 0);
+ TEST(url->url_type, url_http);
+ snprintf(buf, sizeof(buf), URL_PRINT_FORMAT, URL_PRINT_ARGS(url));
+ TEST_S(buf, "http://www.hut.fi");
+
+ TEST_1(url_d(url, ftp) == 0);
+ TEST_1(url_sanitize(url) == 0);
+ TEST(url->url_type, url_ftp);
+ snprintf(buf, sizeof(buf), URL_PRINT_FORMAT, URL_PRINT_ARGS(url));
+ TEST_S(buf, "ftp://ftp.hut.fi");
+
+ TEST_1(url_d(url, www2) == 0);
+ TEST_1(url_sanitize(url) == 0);
+ TEST(url->url_type, url_http);
+ snprintf(buf, sizeof(buf), URL_PRINT_FORMAT, URL_PRINT_ARGS(url));
+ TEST_S(buf, "http://iptel.hut.fi/humppa");
+
+ TEST_1(url_d(url, sip) == 0);
+ TEST_1(url_sanitize(url) == 0);
+ TEST(url->url_type, url_sip);
+ snprintf(buf, sizeof(buf), URL_PRINT_FORMAT, URL_PRINT_ARGS(url));
+ TEST_S(buf, "sip:test.host");
+
+ END();
+}
+
+
+int test_tags(void)
+{
+ url_t u0[1];
+ url_t *u1 = NULL;
+ url_t const *u2 = (void *)-1;
+ url_t const u3[1] = { URL_INIT_AS(sip) };
+ char c0[] = "http://www.nokia.com";
+ char const *c1 = "http://goodfeel.nokia.com";
+ char *c2 = "http://forum.nokia.com";
+ char const c3[] = "http://www.research.nokia.com";
+ url_string_t *us0 = NULL;
+
+ tagi_t *lst, *dup;
+
+ tag_value_t value;
+ char *s;
+ su_home_t home[1] = { SU_HOME_INIT(home) };
+
+ BEGIN();
+
+ TEST(t_scan(urltag_url, home, c0, &value), 0);
+ TEST_S(s = url_as_string(home, (url_t *)value), c0);
+
+ TEST(t_scan(urltag_url, home, c3, &value), 0);
+ TEST_S(s = url_as_string(home, (url_t *)value), c3);
+
+ TEST_1(url_d(u0, c0) == 0);
+
+ lst = tl_list(URLTAG_URL(u0),
+ URLTAG_URL(u1),
+ URLTAG_URL(u2),
+ URLTAG_URL(u3),
+ URLTAG_URL(c0),
+ URLTAG_URL(c1),
+ URLTAG_URL(c2),
+ URLTAG_URL(c3),
+ URLTAG_URL(us0),
+ TAG_NULL());
+
+ TEST_1(lst);
+
+ dup = tl_adup(home, lst);
+
+ tl_vfree(lst);
+
+ su_free(home, dup);
+
+ su_home_deinit(home);
+
+ END();
+}
+
+#include <sofia-sip/su_tag_class.h>
+
+int test_tag_filter(void)
+{
+ BEGIN();
+
+#undef TAG_NAMESPACE
+#define TAG_NAMESPACE "test"
+ tag_typedef_t tag_a = STRTAG_TYPEDEF(a);
+#define TAG_A(s) tag_a, tag_str_v((s))
+ tag_typedef_t tag_b = STRTAG_TYPEDEF(b);
+#define TAG_B(s) tag_b, tag_str_v((s))
+
+ tagi_t filter[2] = {{ URLTAG_ANY() }, { TAG_END() }};
+
+ tagi_t *lst, *result;
+
+ lst = tl_list(TAG_A("X"),
+ TAG_SKIP(2),
+ URLTAG_URL((void *)"urn:foo"),
+ TAG_B("Y"),
+ URLTAG_URL((void *)"urn:bar"),
+ TAG_NULL());
+
+ TEST_1(lst);
+
+ result = tl_afilter(NULL, filter, lst);
+
+ TEST_1(result);
+ TEST_P(result[0].t_tag, urltag_url);
+ TEST_P(result[1].t_tag, urltag_url);
+
+ tl_vfree(lst);
+ free(result);
+
+ END();
+}
+
+#if 0
+/* This is just a spike. How we can get
+ * register_printf_function('U', printf_url, printf_url_info)
+ * run while initializing?
+ */
+#include <printf.h>
+
+int printf_url(FILE *fp,
+ const struct printf_info *info,
+ const void * const *args)
+{
+ url_t const *url = *(url_t **)args[0];
+
+ return fprintf(fp, URL_PRINT_FORMAT, URL_PRINT_ARGS(url));
+}
+
+/* This is the appropriate argument information function for `printf_url'. */
+int printf_url_info(const struct printf_info *info,
+ size_t n, int *argtypes)
+{
+ if (n > 0) {
+ argtypes[0] = PA_POINTER;
+ return 1;
+ }
+ return 0;
+}
+#endif
+
+int test_print(void)
+{
+#if 0
+ url_t u0[1];
+ url_t *u1 = NULL;
+ url_t const *u2 = (void *)-1;
+ url_t const u3[1] = { URL_INIT_AS(sip) };
+ char c0[] = "http://www.nokia.com/";
+ char c1[] = "http://goodfeel.nokia.com/test";
+ char c2[] = "/test2/";
+ char c3[] = "///file/";
+
+ tagi_t *lst;
+
+ BEGIN();
+
+ TEST(register_printf_function('U', printf_url, printf_url_info), 0);
+
+ TEST(url_d(u0, c0), 0);
+ printf("URL is %U\n", u0);
+
+ TEST(url_d(u0, c1), 0);
+ printf("URL is %U\n", u0);
+
+ TEST(url_d(u0, c2), 0);
+ printf("URL is %U\n", u0);
+
+ TEST(url_d(u0, c3), 0);
+ printf("URL is %U\n", u0);
+#else
+ BEGIN();
+#endif
+
+ END();
+}
+
+
+
+int main(int argc, char *argv[])
+{
+ int retval = 0;
+ int i;
+
+ for (i = 1; argv[i]; i++) {
+ if (strcmp(argv[i], "-v") == 0)
+ tstflags |= tst_verbatim;
+ else
+ usage();
+ }
+
+ retval |= test_quote(); fflush(stdout);
+ retval |= test_any(); fflush(stdout);
+ retval |= test_sip(); fflush(stdout);
+ retval |= test_wv(); fflush(stdout);
+ retval |= test_tel(); fflush(stdout);
+ retval |= test_fax(); fflush(stdout);
+ retval |= test_modem(); fflush(stdout);
+ retval |= test_file(); fflush(stdout);
+ retval |= test_ldap(); fflush(stdout);
+ retval |= test_rtsp(); fflush(stdout);
+ retval |= test_http(); fflush(stdout);
+ retval |= test_sanitizing(); fflush(stdout);
+ retval |= test_tags(); fflush(stdout);
+ retval |= test_print(); fflush(stdout);
+ retval |= test_tag_filter(); fflush(stdout);
+
+ return retval;
+}
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/url.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/url.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,2088 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE url.c
+ *
+ * Implementation of basic URL parsing and handling.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Jun 29 22:44:37 2000 ppessi
+ */
+
+#include "config.h"
+
+#include <sofia-sip/su_alloc.h>
+#include <sofia-sip/bnf.h>
+#include <sofia-sip/hostdomain.h>
+#include <sofia-sip/url.h>
+
+#include <sofia-sip/string0.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <ctype.h>
+#include <limits.h>
+
+/**@def URL_PRINT_FORMAT
+ * Format string used when printing url with printf().
+ *
+ * The macro URL_PRINT_FORMAT is used in format string of printf() or
+ * similar printing functions. A URL can be printed like this:
+ * @code
+ * printf("%s received URL " URL_PRINT_FORMAT "\n",
+ * my_name, URL_PRINT_ARGS(url));
+ * @endcode
+ */
+
+/** @def URL_PRINT_ARGS(u)
+ * Argument list used when printing url with printf().
+ *
+ * The macro URL_PRINT_ARGS() is used to create a stdarg list for printf()
+ * or similar printing functions. Using it, a URL can be printed like this:
+ *
+ * @code
+ * printf("%s received URL " URL_PRINT_FORMAT "\n",
+ * my_name, URL_PRINT_ARGS(url));
+ * @endcode
+ */
+
+#define RESERVED ";/?:@&=+$,"
+#define DELIMS "<>#%\""
+#define UNWISE "{}|\\^[]`"
+
+#define EXCLUDED RESERVED DELIMS UNWISE
+
+#define UNRESERVED "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
+ "abcdefghijklmnopqrstuvwxyz" \
+ "0123456789" \
+ "-_.!~*'()"
+
+#define IS_EXCLUDED(u, m32, m64, m96) \
+ (u <= ' ' \
+ || u >= '\177' \
+ || (u < 64 ? (m32 & (1 << (63 - u))) \
+ : (u < 96 ? (m64 & (1 << (95 - u))) \
+ : /*u < 128*/ (m96 & (1 << (127 - u))))) != 0)
+
+#define MASKS_WITH_RESERVED(reserved, m32, m64, m96) \
+ if (reserved == NULL) { \
+ m32 = 0xbe19003f, m64 = 0x8000001e, m96 = 0x8000001d; \
+ } else do { \
+ m32 = 0xb400000a, m64 = 0x0000001e, m96 = 0x8000001d; \
+ \
+ for (;reserved[0]; reserved++) { \
+ unsigned r = reserved[0]; \
+ RESERVE(r, m32, m64, m96); \
+ } \
+ } while (0)
+
+#define RESERVE(reserved, m32, m64, m96) \
+ if (r < 32) \
+ ; \
+ else if (r < 64) \
+ m32 |= 1U << (63 - r); \
+ else if (r < 96) \
+ m64 |= 1U << (95 - r); \
+ else if (r < 128) \
+ m96 |= 1U << (127 - r)
+
+#define MASKS_WITH_ALLOWED(allowed, mask32, mask64, mask96) \
+ do { \
+ if (allowed) { \
+ for (;allowed[0]; allowed++) { \
+ unsigned a = allowed[0]; \
+ ALLOW(a, mask32, mask64, mask96); \
+ } \
+ } \
+ } while (0)
+
+#define ALLOW(a, mask32, mask64, mask96) \
+ if (a < 32) \
+ ; \
+ else if (a < 64) \
+ mask32 &= ~(1U << (63 - a)); \
+ else if (a < 96) \
+ mask64 &= ~(1U << (95 - a)); \
+ else if (a < 128) \
+ mask96 &= ~(1U << (127 - a))
+
+
+#define RMASK1 0xbe19003f
+#define RMASK2 0x8000001e
+#define RMASK3 0x8000001d
+
+#define RESERVED_MASK 0xbe19003f, 0x8000001e, 0x8000001d
+#define URIC_MASK 0xb400000a, 0x0000001e, 0x8000001d
+
+#define IS_EXCLUDED_MASK(u, m) IS_EXCLUDED(u, m)
+
+/* Internal prototypes */
+static char *url_canonize(char *d, char const *s, size_t n,
+ char const allowed[]);
+static char *url_canonize2(char *d, char const *s, size_t n,
+ unsigned m32, unsigned m64, unsigned m96);
+static int url_tel_cmp_numbers(char const *A, char const *B);
+
+/**Test if string contains excluded or url-reserved characters.
+ *
+ *
+ *
+ * @param s string to be searched
+ *
+ * @retval 0 if no reserved characters were found.
+ * @retval l if a reserved character was found.
+ */
+int url_reserved_p(char const *s)
+{
+ if (s)
+ while (*s) {
+ unsigned char u = *s++;
+
+ if (IS_EXCLUDED(u, RMASK1, RMASK2, RMASK3))
+ return 1;
+ }
+
+ return 0;
+}
+
+/** Calculate length of string when escaped with %-notation.
+ *
+ * Calculate the length of string @a s when the excluded or reserved
+ * characters in it have been escaped.
+ *
+ * @param s String with reserved URL characters. [IN
+ * @param reserved Optional array of reserved characters [IN]
+ *
+ * @return
+ * The number of characters in corresponding but escaped string.
+ *
+ * You can handle a part of URL with reserved characters like this:
+ * @code
+ * if (url_reserved_p(s)) {
+ * n = malloc(url_esclen(s, NULL) + 1);
+ * if (n) url_escape(n, s);
+ * } else {
+ * n = malloc(strlen(s) + 1);
+ * if (n) strcpy(n, s);
+ * }
+ * @endcode
+ */
+isize_t url_esclen(char const *s, char const reserved[])
+{
+ size_t n;
+ unsigned mask32, mask64, mask96;
+
+ MASKS_WITH_RESERVED(reserved, mask32, mask64, mask96);
+
+ for (n = 0; s && *s; n++) {
+ unsigned char u = *s++;
+
+ if (IS_EXCLUDED(u, mask32, mask64, mask96))
+ n += 2;
+ }
+
+ return (isize_t)n;
+}
+
+/** Escape a string.
+ *
+ * The function url_escape() copies the string pointed by @a s to the array
+ * pointed by @a d, @b excluding the terminating \\0 character. All reserved
+ * characters in @a s are copied in hexadecimal format, for instance, @c
+ * "$%#" is copied as @c "%24%25%23". The destination array @a d must be
+ * large enough to receive the escaped copy.
+ *
+ * @param d Destination buffer [OUT]
+ * @param s String to be copied [IN]
+ * @param reserved Array of reserved characters [IN]
+ *
+ * @return Pointer to the destination array.
+ */
+char *url_escape(char *d, char const *s, char const reserved[])
+{
+ char *retval = d;
+ unsigned mask32, mask64, mask96;
+
+ MASKS_WITH_RESERVED(reserved, mask32, mask64, mask96);
+
+ while (s && *s) {
+ unsigned char u = *s++;
+
+ if (IS_EXCLUDED(u, mask32, mask64, mask96)) {
+# define URL_HEXIFY(u) ((u) + '0' + ((u) >= 10 ? 'A' - '0' - 10 : 0))
+
+ *d++ = '%';
+ *d++ = URL_HEXIFY(u >> 4);
+ *d++ = URL_HEXIFY(u & 15);
+
+# undef URL_HEXIFY
+ }
+ else {
+ *d++ = u;
+ }
+ }
+
+ *d = '\0';
+
+ return retval;
+}
+
+
+/**Unescape url-escaped string fragment.
+ *
+ * Unescape @a n characters from string @a s to the buffer @a d, including
+ * the terminating \\0 character. All %-escaped triplets in @a s are
+ * unescaped, for instance, @c "%40%25%23" is copied as @c "@%#". The
+ * destination array @a d must be large enough to receive the escaped copy
+ * (@a n bytes is always enough).
+ *
+ * @param d destination buffer
+ * @param s string to be unescaped
+ * @param n maximum number of characters to unescape
+ *
+ * @return Length of unescaped string
+ *
+ * @NEW_1_12_4.
+ */
+size_t url_unescape_to(char *d, char const *s, size_t n)
+{
+ size_t i = 0, j = 0;
+
+ if (s == NULL)
+ return 0;
+
+ i = j = strncspn(s, n, "%");
+
+ if (d && d != s)
+ memmove(d, s, i);
+
+ for (; i < n;) {
+ char c = s[i++];
+
+ if (c == '\0')
+ break;
+
+ if (c == '%' && i + 1 < n && IS_HEX(s[i]) && IS_HEX(s[i + 1])) {
+#define UNHEX(a) (a - (a >= 'a' ? 'a' - 10 : (a >= 'A' ? 'A' - 10 : '0')))
+ c = (UNHEX(s[i]) << 4) | UNHEX(s[i + 1]);
+#undef UNHEX
+ i += 2;
+ }
+
+ if (d)
+ d[j] = c;
+ j++;
+ }
+
+ return j;
+}
+
+/**Unescape url-escaped string.
+ *
+ * Unescape string @a s to the buffer @a d, including the terminating \\0
+ * character. All %-escaped triplets in @a s are unescaped, for instance, @c
+ * "%40%25%23" is copied as @c "@%#". The destination array @a d must be
+ * large enough to receive the escaped copy.
+ *
+ * @param d destination buffer
+ * @param s string to be copied
+ *
+ * @return Pointer to the destination buffer.
+ */
+char *url_unescape(char *d, char const *s)
+{
+ size_t n = url_unescape_to(d, s, SIZE_MAX);
+ if (d)
+ d[n] = '\0';
+ return d;
+}
+
+/** Canonize a URL component */
+static
+char *url_canonize(char *d, char const *s, size_t n, char const allowed[])
+{
+ unsigned mask32 = 0xbe19003f, mask64 = 0x8000001e, mask96 = 0x8000001d;
+
+ MASKS_WITH_ALLOWED(allowed, mask32, mask64, mask96);
+
+ return url_canonize2(d, s, n, mask32, mask64, mask96);
+}
+
+/** Canonize a URL component (with precomputed mask) */
+static
+char *url_canonize2(char *d, char const * const s, size_t n,
+ unsigned m32, unsigned m64, unsigned m96)
+{
+ size_t i = 0;
+
+ if (d == s)
+ for (;s[i] && i < n; d++, i++)
+ if (s[i] == '%')
+ break;
+
+ for (;s[i] && i < n; d++, i++) {
+ unsigned char c = s[i], h1, h2;
+
+ if (c != '%') {
+ if (IS_EXCLUDED(c, m32, m64, m96))
+ return NULL;
+ *d = c;
+ continue;
+ }
+
+ h1 = s[i + 1], h2 = s[i + 2];
+
+ if (!IS_HEX(h1) || !IS_HEX(h2)) {
+ *d = '\0';
+ return NULL;
+ }
+
+#define UNHEX(a) (a - (a >= 'a' ? 'a' - 10 : (a >= 'A' ? 'A' - 10 : '0')))
+ c = (UNHEX(h1) << 4) | UNHEX(h2);
+
+ if (!IS_EXCLUDED(c, m32, m64, m96)) {
+ /* Convert hex to normal character */
+ *d = c, i += 2;
+ continue;
+ }
+
+ /* Convert hex to uppercase */
+ if (h1 >= 'a' /* && h1 <= 'f' */)
+ h1 = h1 - 'a' + 'A';
+ if (h2 >= 'a' /* && h2 <= 'f' */)
+ h2 = h2 - 'a' + 'A';
+
+ d[0] = '%', d[1] = h1, d[2] = h2;
+
+ d +=2, i += 2;
+#undef UNHEX
+ }
+
+ *d = '\0';
+
+ return d;
+}
+
+
+/** Canonize a URL component (with precomputed mask).
+ *
+ * This version does not flag error if *s contains character that should
+ * be escaped.
+ */
+static
+char *url_canonize3(char *d, char const * const s, size_t n,
+ unsigned m32, unsigned m64, unsigned m96)
+{
+ size_t i = 0;
+
+ if (d == s)
+ for (;s[i] && i < n; d++, i++)
+ if (s[i] == '%')
+ break;
+
+ for (;s[i] && i < n; d++, i++) {
+ unsigned char c = s[i], h1, h2;
+
+ if (c != '%') {
+ *d = c;
+ continue;
+ }
+
+ h1 = s[i + 1], h2 = s[i + 2];
+
+ if (!IS_HEX(h1) || !IS_HEX(h2)) {
+ *d = '\0';
+ return NULL;
+ }
+
+#define UNHEX(a) (a - (a >= 'a' ? 'a' - 10 : (a >= 'A' ? 'A' - 10 : '0')))
+ c = (UNHEX(h1) << 4) | UNHEX(h2);
+
+ if (!IS_EXCLUDED(c, m32, m64, m96)) {
+ *d = c, i += 2;
+ continue;
+ }
+
+ /* Convert hex to uppercase */
+ if (h1 >= 'a' /* && h1 <= 'f' */)
+ h1 = h1 - 'a' + 'A';
+ if (h2 >= 'a' /* && h2 <= 'f' */)
+ h2 = h2 - 'a' + 'A';
+
+ d[0] = '%', d[1] = h1, d[2] = h2;
+
+ d +=2, i += 2;
+#undef UNHEX
+ }
+
+ *d = '\0';
+
+ return d;
+}
+
+
+/** Get URL scheme. */
+char const* url_scheme(enum url_type_e url_type)
+{
+ switch (url_type) {
+ case url_any: return "*";
+ case url_sip: return "sip";
+ case url_sips: return "sips";
+ case url_tel: return "tel";
+ case url_fax: return "fax";
+ case url_modem: return "modem";
+ case url_http: return "http";
+ case url_https: return "https";
+ case url_ftp: return "ftp";
+ case url_file: return "file";
+ case url_rtsp: return "rtsp";
+ case url_rtspu: return "rtspu";
+ case url_mailto: return "mailto";
+ case url_im: return "im";
+ case url_pres: return "pres";
+ case url_cid: return "cid";
+ case url_msrp: return "msrp";
+ case url_msrps: return "msrps";
+ case url_wv: return "wv";
+ default:
+ assert(url_type == url_unknown);
+ return NULL;
+ }
+}
+
+static inline
+int url_type_is_opaque(enum url_type_e url_type)
+{
+ return
+ url_type == url_invalid ||
+ url_type == url_tel ||
+ url_type == url_modem ||
+ url_type == url_fax ||
+ url_type == url_cid;
+}
+
+/** Init an url as given type */
+void url_init(url_t *url, enum url_type_e type)
+{
+ memset(url, 0, sizeof(*url));
+ url->url_type = type;
+ if (type > url_unknown) {
+ char const *scheme = url_scheme(url->url_type);
+ if (scheme)
+ url->url_scheme = scheme;
+ }
+}
+
+/** Get url type */
+static inline
+enum url_type_e url_get_type(char const *scheme, size_t len)
+{
+#define test_scheme(s) \
+ if (len == strlen(#s) && !strncasecmp(scheme, #s, len)) return url_##s
+
+ switch (scheme[0]) {
+ case '*': if (strcmp(scheme, "*") == 0) return url_any;
+ case 'c': case 'C':
+ test_scheme(cid); break;
+ case 'f': case 'F':
+ test_scheme(ftp); test_scheme(file); test_scheme(fax); break;
+ case 'h': case 'H':
+ test_scheme(http); test_scheme(https); break;
+ case 'i': case 'I':
+ test_scheme(im); break;
+ case 'm': case 'M':
+ test_scheme(mailto); test_scheme(modem);
+ test_scheme(msrp); test_scheme(msrps); break;
+ case 'p': case 'P':
+ test_scheme(pres); break;
+ case 'r': case 'R':
+ test_scheme(rtsp); test_scheme(rtspu); break;
+ case 's': case 'S':
+ test_scheme(sip); test_scheme(sips); break;
+ case 't': case 'T':
+ test_scheme(tel); break;
+ case 'w': case 'W':
+ test_scheme(wv); break;
+
+
+ default: break;
+ }
+
+#undef test_scheme
+
+ if (len != span_unreserved(scheme))
+ return url_invalid;
+ else
+ return url_unknown;
+}
+
+/**
+ * Decode a URL.
+ *
+ * This function decodes a (SIP) URL string to a url_t structure.
+ *
+ * @param url structure to store the parsing result
+ * @param s NUL-terminated string to be parsed
+ *
+ * @note The parsed string @a s will be modified when parsing it.
+ *
+ * @retval 0 if successful,
+ * @retval -1 otherwise.
+ */
+static
+int _url_d(url_t *url, char *s)
+{
+ size_t n;
+ char *s0, rest_c, *host;
+ int net_path = 1;
+
+ memset(url, 0, sizeof(*url));
+
+ if (strcmp(s, "*") == 0) {
+ url->url_type = url_any;
+ url->url_scheme = "*";
+ return 0;
+ }
+
+ s0 = s;
+
+ n = strcspn(s, ":/?#");
+
+ if (n && s[n] == ':') {
+ char *scheme;
+ url->url_scheme = scheme = s; s[n] = '\0'; s = s + n + 1;
+
+ if (!(scheme = url_canonize(scheme, scheme, SIZE_MAX, "+")))
+ return -1;
+
+ n = scheme - url->url_scheme;
+
+ url->url_type = url_get_type(url->url_scheme, n);
+
+ net_path = !url_type_is_opaque(url->url_type);
+ }
+ else {
+ url->url_type = url_unknown;
+ }
+
+ host = s;
+
+ if (url->url_type == url_sip || url->url_type == url_sips) {
+ /* SIP URL may have /; in user part */
+ n = strcspn(s, "@#"); /* Opaque part */
+ if (s[n] != '@')
+ n = 0;
+ n += strcspn(s + n, "/;?#");
+ }
+ else if (url->url_type == url_wv) {
+ /* WV URL may have / in user part */
+ n = strcspn(s, "@#?;");
+ if (s[n] == '@')
+ n += strcspn(s + n, ";?#");
+ }
+ else if (url->url_type == url_invalid) {
+ n = strcspn(s, "#");
+ }
+ else if (net_path && host[0] == '/') {
+ url->url_root = host[0]; /* Absolute path */
+
+ if (host[1] == '/') { /* We have host-part */
+ host += 2; s += 2;
+ }
+ else
+ host = NULL;
+ n = strcspn(s, "/;?#"); /* Find path, query and/or fragment */
+ }
+ else {
+ n = strcspn(s, "/;?#"); /* Find params, query and/or fragment */
+ }
+
+ rest_c = s[n]; s[n] = 0; s = rest_c ? s + n + 1 : NULL;
+
+ if (host) {
+ char *atsign, *port;
+
+ if (!net_path) {
+ url->url_user = host;
+ host = NULL;
+ }
+ else if ((atsign = strchr(host, '@'))) {
+ char *user;
+
+ url->url_user = user = host;
+
+ if (atsign)
+ *atsign++ = '\0';
+ host = atsign;
+
+ if (url->url_type != url_unknown) {
+ char *colon = strchr(user, ':');
+ if (colon)
+ *colon++ = '\0';
+ url->url_password = colon;
+ }
+ }
+
+ if ((url->url_host = host)) {
+ /* IPv6 (and in some cases, IPv4) addresses are quoted with [] */
+ if (host[0] == '[') {
+ port = strchr(host, ']');
+ if (!port)
+ return -1;
+ port = strchr(port + 1, ':');
+ }
+ else
+ port = strchr(host, ':');
+
+ if (port) {
+ *port++ = '\0';
+ url->url_port = port;
+ switch (url->url_type) {
+ case url_any:
+ case url_sip:
+ case url_sips:
+ case url_http:
+ case url_https:
+ case url_ftp:
+ case url_file:
+ case url_rtsp:
+ case url_rtspu:
+
+ if (!url_canonize2(port, port, SIZE_MAX, RESERVED_MASK))
+ return -1;
+
+ /* Check that port is really numeric or wildcard */
+ /* Port can be *digit, empty string or "*" */
+ while (*port >= '0' && *port <= '9')
+ port++;
+ if (port != url->url_port
+ ? port[0] != '\0'
+ : port[0] != '\0'
+ && (port[0] != '*' || port[1] != '\0'))
+ return -1;
+ }
+ }
+ }
+ }
+
+ if (rest_c == '/') {
+ url->url_path = s; n = strcspn(s, "?#");
+ rest_c = s[n]; s[n] = 0; s = rest_c ? s + n + 1 : NULL;
+ }
+ if (rest_c == ';') {
+ url->url_params = s; n = strcspn(s, "?#");
+ rest_c = s[n]; s[n] = 0; s = rest_c ? s + n + 1 : NULL;
+ }
+ if (rest_c == '?') {
+ url->url_headers = s; n = strcspn(s, "#");
+ rest_c = s[n]; s[n] = 0; s = rest_c ? s + n + 1 : NULL;
+ }
+ if (rest_c == '#') {
+ url->url_fragment = s;
+ rest_c = '\0';
+ }
+ if (rest_c)
+ return -1;
+
+ return 0;
+}
+
+/* Unreserved things */
+
+/**
+ * Decode a URL.
+ *
+ * This function decodes a URL string to a url_t structure.
+ *
+ * @param url structure to store the parsing result
+ * @param s NUL-terminated string to be parsed
+ *
+ * @note The parsed string @a s will be modified when parsing it.
+ *
+ * @retval 0 if successful,
+ * @retval -1 otherwise.
+ */
+int url_d(url_t *url, char *s)
+{
+ if (url == NULL || _url_d(url, s) < 0)
+ return -1;
+
+ /* Canonize URL */
+ /* scheme is canonized by _url_d() */
+ if (url->url_type == url_sip || url->url_type == url_sips) {
+
+# define SIP_USER_UNRESERVED "&=+$,;?/"
+ s = (char *)url->url_user;
+ if (s && !url_canonize(s, s, SIZE_MAX, SIP_USER_UNRESERVED))
+ return -1;
+
+# define SIP_PASS_UNRESERVED "&=+$,"
+ s = (char *)url->url_password;
+ if (s && !url_canonize(s, s, SIZE_MAX, SIP_PASS_UNRESERVED))
+ return -1;
+
+ } else {
+
+# define USER_UNRESERVED "&=+$,;"
+ s = (char *)url->url_user;
+ if (s && !url_canonize(s, s, SIZE_MAX, USER_UNRESERVED))
+ return -1;
+
+# define PASS_UNRESERVED "&=+$,;:"
+ s = (char *)url->url_password;
+ if (s && !url_canonize(s, s, SIZE_MAX, PASS_UNRESERVED))
+ return -1;
+ }
+
+ s = (char *)url->url_host;
+ if (s && !url_canonize2(s, s, SIZE_MAX, RESERVED_MASK))
+ return -1;
+
+ /* port is canonized by _url_d() */
+
+ /* Allow all URI characters but ? and ; */
+# define PATH_UNRESERVED "/:@&=+$,"
+ s = (char *)url->url_path;
+ if (s && !url_canonize(s, s, SIZE_MAX, PATH_UNRESERVED))
+ return -1;
+
+ /* Allow all URI characters but ? */
+# define PARAMS_UNRESERVED ";" PATH_UNRESERVED
+ s = (char *)url->url_params;
+ if (s && !url_canonize(s, s, SIZE_MAX, PARAMS_UNRESERVED))
+ return -1;
+
+ /* Unhex alphanumeric and unreserved URI characters */
+ s = (char *)url->url_headers;
+ if (s && !url_canonize3(s, s, SIZE_MAX, RESERVED_MASK))
+ return -1;
+
+ /* Allow all URI characters (including reserved ones) */
+ s = (char *)url->url_fragment;
+ if (s && !url_canonize2(s, s, SIZE_MAX, URIC_MASK))
+ return -1;
+
+ return 0;
+}
+
+/** Encode an URL.
+ *
+ * The function url_e() combines a URL from substrings in url_t structure
+ * according the @ref url_syntax "URL syntax" presented above. The encoded
+ * @a url is stored in a @a buffer of @a n bytes.
+ *
+ * @param buffer memory area to store the encoded @a url.
+ * @param n size of @a buffer.
+ * @param url URL to be encoded.
+ *
+ * @return
+ * Return the number of bytes in the encoding.
+ *
+ * @note The function follows the convention set by C99 snprintf(). Even if
+ * the result does not fit into the @a buffer and it is truncated, the
+ * function returns the number of bytes in an untruncated encoding.
+ */
+issize_t url_e(char buffer[], isize_t n, url_t const *url)
+{
+ size_t i;
+ char *b = buffer;
+ size_t m = n;
+ int do_copy = n > 0;
+
+ if (url == NULL)
+ return -1;
+
+ if (URL_STRING_P(url)) {
+ char const *u = (char *)url;
+ i = strlen(u);
+ if (!buffer)
+ return i;
+
+ if (i >= n) {
+ memcpy(buffer, u, n - 2);
+ buffer[n - 1] = '\0';
+ } else {
+ memcpy(buffer, u, i + 1);
+ }
+
+ return i;
+ }
+
+
+ if (url->url_type == url_any) {
+ if (b && m > 0) {
+ if (m > 1) strcpy(b, "*"); else b[0] = '\0';
+ }
+ return 1;
+ }
+
+ if (url->url_scheme && url->url_scheme[0]) {
+ i = strlen(url->url_scheme) + 1;
+ if (do_copy && (do_copy = i <= n)) {
+ memcpy(b, url->url_scheme, i - 1);
+ b[i - 1] = ':';
+ }
+ b += i; n -= i;
+ }
+
+ if (url->url_root && (url->url_host || url->url_user)) {
+ if (do_copy && (do_copy = 2 <= n))
+ memcpy(b, "//", 2);
+ b += 2; n -= 2;
+ }
+
+ if (url->url_user) {
+ i = strlen(url->url_user);
+ if (do_copy && (do_copy = i <= n))
+ memcpy(b, url->url_user, i);
+ b += i; n -= i;
+
+ if (url->url_password) {
+ if (do_copy && (do_copy = 1 <= n))
+ *b = ':';
+ b++; n--;
+ i = strlen(url->url_password);
+ if (do_copy && (do_copy = i <= n))
+ memcpy(b, url->url_password, i);
+ b += i; n -= i;
+ }
+
+ if (url->url_host) {
+ if (do_copy && (do_copy = 1 <= n))
+ *b = '@';
+ b++; n--;
+ }
+ }
+
+ if (url->url_host) {
+ i = strlen(url->url_host);
+ if (do_copy && (do_copy = i <= n))
+ memcpy(b, url->url_host, i);
+ b += i; n -= i;
+
+ if (url->url_port) {
+ i = strlen(url->url_port) + 1;
+ if (do_copy && (do_copy = i <= n)) {
+ b[0] = ':';
+ memcpy(b + 1, url->url_port, i - 1);
+ }
+ b += i; n -= i;
+ }
+ }
+
+ if (url->url_path) {
+ if (url->url_root) {
+ if (do_copy && (do_copy = 1 <= n))
+ b[0] = '/';
+ b++, n--;
+ }
+ i = strlen(url->url_path);
+ if (do_copy && (do_copy = i < n))
+ memcpy(b, url->url_path, i);
+ b += i; n -= i;
+ }
+
+ {
+ static char const sep[] = ";?#";
+ char const *pp[3];
+ size_t j;
+
+ pp[0] = url->url_params;
+ pp[1] = url->url_headers;
+ pp[2] = url->url_fragment;
+
+ for (j = 0; j < 3; j++) {
+ char const *p = pp[j];
+ if (!p) continue;
+ i = strlen(p) + 1;
+ if (do_copy && (do_copy = i <= n)) {
+ *b = sep[j];
+ memcpy(b + 1, p, i - 1);
+ }
+ b += i; n -= i;
+ }
+ }
+
+ if (do_copy && (do_copy = 1 <= n))
+ *b = '\0';
+ else if (buffer && m > 0)
+ buffer[m - 1] = '\0';
+
+ assert((size_t)(b - buffer) == (size_t)(m - n));
+
+ /* This follows the snprintf(C99) return value,
+ * Number of characters written (excluding NUL)
+ */
+ return b - buffer;
+}
+
+
+/** Calculate the lengh of URL when encoded.
+ *
+ */
+isize_t url_len(url_t const * url)
+{
+ size_t rv = 0;
+
+ if (url->url_scheme) rv += strlen(url->url_scheme) + 1; /* plus ':' */
+ if (url->url_user) {
+ rv += strlen(url->url_user);
+ if (url->url_password)
+ rv += strlen(url->url_password) + 1; /* plus ':' */
+ rv += url->url_host != NULL; /* plus '@' */
+ }
+ if (url->url_host) rv += strlen(url->url_host);
+ if (url->url_port) rv += strlen(url->url_port) + 1; /* plus ':' */
+ if (url->url_path) rv += strlen(url->url_path) + 1; /* plus initial / */
+ if (url->url_params) rv += strlen(url->url_params) + 1; /* plus initial ; */
+ if (url->url_headers) rv += strlen(url->url_headers) + 1; /* plus '?' */
+ if (url->url_fragment) rv += strlen(url->url_fragment) + 1; /* plus '#' */
+
+ return rv;
+}
+
+/**@def URL_E(buf, end, url)
+ * Encode an URL: use @a buf up to @a end.
+ * @hideinitializer
+ */
+
+/**
+ * Calculate the size of strings associated with a #url_t sructure.
+ *
+ * @param url pointer to a #url_t structure or string
+ * @return Number of bytes for URL
+ */
+isize_t url_xtra(url_t const *url)
+{
+ size_t xtra;
+
+ if (URL_STRING_P(url)) {
+ xtra = strlen((char const *)url) + 1;
+ }
+ else {
+ size_t len_scheme, len_user, len_password,
+ len_host, len_port, len_path, len_params,
+ len_headers, len_fragment;
+
+ len_scheme = (url->url_type <= url_unknown && url->url_scheme) ?
+ strlen(url->url_scheme) + 1 : 0;
+ len_user = url->url_user ? strlen(url->url_user) + 1 : 0;
+ len_password = url->url_password ? strlen(url->url_password) + 1 : 0;
+ len_host = url->url_host ? strlen(url->url_host) + 1 : 0;
+ len_port = url->url_port ? strlen(url->url_port) + 1 : 0;
+ len_path = url->url_path ? strlen(url->url_path) + 1 : 0;
+ len_params = url->url_params ? strlen(url->url_params) + 1 : 0;
+ len_headers = url->url_headers ? strlen(url->url_headers) + 1 : 0;
+ len_fragment = url->url_fragment ? strlen(url->url_fragment) + 1 : 0;
+
+ xtra =
+ len_scheme + len_user + len_password + len_host + len_port +
+ len_path + len_params + len_headers + len_fragment;
+ }
+
+ return xtra;
+}
+
+static inline
+char *copy(char *buf, char *end, char const *src)
+{
+#if HAVE_MEMCCPY
+ char *b = memccpy(buf, src, '\0', end - buf);
+ if (b)
+ return b;
+ else
+ return end + strlen(src + (end - buf)) + 1;
+#else
+ for (; buf < end && (*buf = *src); buf++, src++)
+ ;
+
+ if (buf >= end)
+ while (*src++)
+ buf++;
+
+ return buf + 1;
+#endif
+}
+
+/**
+ * Duplicate the url.
+ *
+ * The function url_dup() copies the url structure @a src and the strings
+ * attached to it to @a url. The non-constant strings in @a src are copied
+ * to @a buf. If the size of duplicated strings exceed @a bufsize, the
+ * corresponding string fields in @a url are set to NULL.
+ *
+ * The calling function can calculate the size of buffer required by calling
+ * url_dup() with zero as @a bufsize and NULL as @a dst.
+
+ * @param buf Buffer for non-constant strings copied from @a src.
+ * @param bufsize Size of @a buf.
+ * @param dst Destination URL structure.
+ * @param src Source URL structure.
+ *
+ * @return Number of characters required for
+ * duplicating the strings in @a str, or -1 if an error
+ * occurred.
+ */
+issize_t url_dup(char *buf, isize_t bufsize, url_t *dst, url_t const *src)
+{
+ if (!src && !dst)
+ return -1;
+ else if (URL_STRING_P(src)) {
+ size_t n = strlen((char *)src) + 1;
+ if (n > bufsize || dst == NULL)
+ return n;
+
+ strcpy(buf, (char *)src);
+ memset(dst, 0, sizeof(*dst));
+ if (url_d(dst, buf) < 0)
+ return -1;
+
+ return n;
+ }
+ else {
+ char *b = buf;
+ char *end = b + bufsize;
+ char const **dstp;
+ char const * const *srcp;
+ url_t dst0[1];
+
+ if (dst == NULL)
+ dst = dst0;
+
+ memset(dst, 0, sizeof(*dst));
+
+ if (!src)
+ return 0;
+
+ memset(dst->url_pad, 0, sizeof dst->url_pad);
+ dst->url_type = src->url_type;
+ dst->url_root = src->url_root;
+
+ dstp = &dst->url_scheme;
+ srcp = &src->url_scheme;
+
+ if (dst->url_type > url_unknown)
+ *dstp = url_scheme(dst->url_type);
+
+ if (*dstp != NULL)
+ dstp++, srcp++; /* Skip scheme if it is constant */
+
+ if (dst != dst0 && buf != NULL && bufsize != 0)
+ for (; srcp <= &src->url_fragment; srcp++, dstp++)
+ if (*srcp) {
+ char *next = copy(b, end, *srcp);
+
+ if (next > end)
+ break;
+
+ *dstp = b, b = next;
+ }
+
+ for (; srcp <= &src->url_fragment; srcp++)
+ if (*srcp) {
+ b += strlen(*srcp) + 1;
+ }
+
+ return b - buf;
+ }
+}
+
+/**@def URL_DUP(buf, end, dst, src)
+ * Duplicate the url: use @a buf up to @a end. @HI
+ *
+ * The macro URL_DUP() duplicates the url. The non-constant strings in @a
+ * src are copied to @a buf. However, no strings are copied past @a end.
+ * In other words, the size of buffer is @a end - @a buf.
+ *
+ * The macro updates the buffer pointer @a buf, so that it points to the
+ * first unused byte in the buffer. The buffer pointer @a buf is updated,
+ * even if the buffer is too small for the duplicated strings.
+ *
+ * @param buf Buffer for non-constant strings copied from @a src.
+ * @param end End of @a buf.
+ * @param dst Destination URL structure.
+ * @param src Source URL structure.
+ *
+ * @return
+ * The macro URL_DUP() returns pointer to first unused byte in the
+ * buffer @a buf.
+ */
+
+/** Duplicate the url to memory allocated via home.
+ *
+ * The function url_hdup() duplicates (deep copies) an #url_t structure.
+ * Alternatively, it can be passed a string; string is then copied and
+ * parsed to the #url_t structure.
+ *
+ * The function url_hdup() allocates the destination structure from @a home
+ * as a single memory block. It is possible to free the copied url structure
+ * and all the associated strings using a single call to su_free().
+ *
+ * @param home memory home used to allocate new url object
+ * @param src pointer to URL (or string)
+ *
+ * @return
+ * The function url_hdup() returns a pointer to the newly allocated #url_t
+ * structure, or NULL upon an error.
+ */
+url_t *url_hdup(su_home_t *home, url_t const *src)
+{
+ if (src) {
+ size_t len = sizeof(*src) + url_xtra(src);
+ url_t *dst = su_alloc(home, len);
+ if (dst) {
+ ssize_t actual;
+ actual = url_dup((char *)(dst + 1), len - sizeof(*src), dst, src);
+ if (actual < 0)
+ su_free(home, dst), dst = NULL;
+ else
+ assert(len == sizeof(*src) + actual);
+ }
+ return dst;
+ }
+ else
+ return NULL;
+}
+
+
+/** Convert an string to an url */
+url_t *url_make(su_home_t *h, char const *str)
+{
+ return url_hdup(h, URL_STRING_MAKE(str)->us_url);
+}
+
+/** Print an URL */
+url_t *url_format(su_home_t *h, char const *fmt, ...)
+{
+ url_t *url;
+ char *us;
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ us = su_vsprintf(h, fmt, ap);
+
+ va_end(ap);
+
+ if (us == NULL)
+ return NULL;
+
+ url = url_hdup(h, URL_STRING_MAKE(us)->us_url);
+
+ su_free(h, us);
+
+ return url;
+}
+
+
+/** Convert @a url to a string allocated from @a home.
+ *
+ * @param home memory home to allocate the new string
+ * @param url url to convert to string
+ *
+ * The @a url can be a string, too.
+ *
+ * @return Newly allocated conversion result, or NULL upon an error.
+ */
+char *url_as_string(su_home_t *home, url_t const *url)
+{
+ if (url) {
+ int len = url_e(NULL, 0, url);
+ char *b = su_alloc(home, len + 1);
+ url_e(b, len + 1, url);
+ return b;
+ } else {
+ return NULL;
+ }
+}
+
+
+/** Test if param @a tag matches to parameter string @a p.
+ */
+#define URL_PARAM_MATCH(p, tag) \
+ (strncasecmp(p, tag, strlen(tag)) == 0 && \
+ (p[strlen(tag)] == '\0' || p[strlen(tag)] == ';' || p[strlen(tag)] == '='))
+
+/**
+ * Search for a parameter.
+ *
+ * This function searches for a parameter from a parameter list.
+ *
+ * If you want to test if there is parameter @b user=phone,
+ * call this function like
+ * @code if (url_param(url->url_param, "user=phone", NULL, 0))
+ * @endcode
+ *
+ * @param params URL parameter string (excluding first semicolon)
+ * @param tag parameter name
+ * @param value string to which the parameter value is copied
+ * @param vlen length of string reserved for value
+ *
+ * @retval positive length of parameter value (including final NUL) if found
+ * @retval zero if not found.
+ */
+isize_t url_param(char const *params,
+ char const *tag,
+ char value[], isize_t vlen)
+{
+ size_t n, tlen, flen;
+ char *p;
+
+ if (!params)
+ return 0;
+
+ tlen = strlen(tag);
+ if (tlen && tag[tlen - 1] == '=')
+ tlen--;
+
+ for (p = (char *)params; *p; p += n + 1) {
+ n = strcspn(p, ";");
+ if (n < tlen) {
+ if (p[n]) continue; else break;
+ }
+ if (strncasecmp(p, tag, tlen) == 0) {
+ if (n == tlen) {
+ if (vlen > 0)
+ value[0] = '\0';
+ return 1;
+ }
+ if (p[tlen] != '=')
+ continue;
+ flen = n - tlen - 1;
+ if (flen >= (size_t)vlen)
+ return flen + 1;
+ memcpy(value, p + tlen + 1, flen);
+ value[flen] = '\0';
+ return flen + 1;
+ }
+ if (!p[n])
+ break;
+ }
+
+ return 0;
+}
+
+/** Check for a parameter.
+ *
+ * @deprecated
+ * Bad grammar. Use url_has_param().
+ */
+isize_t url_have_param(char const *params, char const *tag)
+{
+ return url_param(params, tag, NULL, 0);
+}
+
+/** Check for a parameter. */
+int url_has_param(url_t const *url, char const *tag)
+{
+ return url && url->url_params && url_param(url->url_params, tag, NULL, 0);
+}
+
+/** Add an parameter. */
+int url_param_add(su_home_t *h, url_t *url, char const *param)
+{
+ /* XXX - should remove existing parameters with same name? */
+ size_t n = url->url_params ? strlen(url->url_params) + 1: 0;
+ size_t nn = strlen(param) + 1;
+ char *s = su_alloc(h, n + nn);
+
+ if (!s)
+ return -1;
+
+ if (url->url_params)
+ strcpy(s, url->url_params)[n - 1] = ';';
+ strcpy(s + n, param);
+ url->url_params = s;
+
+ return 0;
+}
+
+/** Remove a named parameter from url_param string.
+ *
+ * Remove a named parameter and its possible value from the URL parameter
+ * string (url_s##url_param).
+ *
+ * @return Pointer to modified string, or NULL if nothing is left in there.
+ */
+char *url_strip_param_string(char *params, char const *name)
+{
+ if (params && name) {
+ size_t i, n = strlen(name), remove, rest;
+
+ for (i = 0; params[i];) {
+ if (strncasecmp(params + i, name, n) ||
+ (params[i + n] != '=' && params[i + n] != ';' && params[i + n])) {
+ i = i + strcspn(params + i, ";");
+ if (!params[i++])
+ break;
+ continue;
+ }
+ remove = n + strcspn(params + i + n, ";");
+ if (params[i + remove] == ';')
+ remove++;
+
+ if (i == 0) {
+ params += remove;
+ continue;
+ }
+
+ rest = strlen(params + i + remove);
+ if (!rest) {
+ if (i == 0)
+ return NULL; /* removed everything */
+ params[i - 1] = '\0';
+ break;
+ }
+ memmove(params + i, params + i + remove, rest + 1);
+ }
+
+ if (!params[0])
+ return NULL;
+ }
+
+ return params;
+}
+
+int url_string_p(url_string_t const *url)
+{
+ return URL_STRING_P(url);
+}
+
+int url_is_string(url_string_t const *url)
+{
+ return URL_IS_STRING(url);
+}
+
+/** Strip transport-specific stuff. */
+static
+int url_strip_transport2(url_t *url, int modify)
+{
+ char *p, *d;
+ size_t n;
+ int semi;
+
+ if (url->url_type != url_sip && url->url_type != url_sips)
+ return 0;
+
+ if (url->url_port != NULL) {
+ if (!modify)
+ return 1;
+ url->url_port = NULL;
+ }
+
+ if (!url->url_params)
+ return 0;
+
+ for (d = p = (char *)url->url_params; *p; p += n + semi) {
+ n = strcspn(p, ";");
+ semi = (p[n] != '\0');
+
+ if (modify && n == 0)
+ continue;
+ if (URL_PARAM_MATCH(p, "method"))
+ continue;
+ if (URL_PARAM_MATCH(p, "maddr"))
+ continue;
+ if (URL_PARAM_MATCH(p, "ttl"))
+ continue;
+ if (URL_PARAM_MATCH(p, "transport"))
+ continue;
+
+ if (p != d) {
+ if (d != url->url_params)
+ d++;
+ if (p != d) {
+ if (!modify)
+ return 1;
+ memmove(d, p, n + 1);
+ }
+ }
+ d += n;
+ }
+
+ if (d == p)
+ return 0;
+ else if (d + 1 == p) /* empty param */
+ return 0;
+ else if (!modify)
+ return 1;
+
+ if (d != url->url_params)
+ *d = '\0';
+ else
+ url->url_params = NULL;
+
+ return 1;
+}
+
+/** Strip transport-specific stuff.
+ *
+ * The function url_strip_transport() removes transport-specific parameters
+ * from a SIP or SIPS URI. These parameters include:
+ * - the port number
+ * - "maddr=" parameter
+ * - "transport=" parameter
+ * - "ttl=" parameter
+ * - "method=" parameter
+ *
+ * @note
+ * The @a url must be a pointer to a URL structure. It is stripped in-place.
+ *
+ * @note
+ * If the parameter string contains empty parameters, they are stripped, too.
+ *
+ * @return
+ * The function url_strip_transport() returns @e true, if the URL was
+ * modified, @e false otherwise.
+ */
+int url_strip_transport(url_t *url)
+{
+ return url_strip_transport2(url, 1);
+}
+
+/** Check for transport-specific stuff.
+ *
+ * The function url_have_transport() tests if there are transport-specific
+ * parameters in a SIP or SIPS URI. These parameters include:
+ * - the port number
+ * - "maddr=" parameters
+ * - "transport=" parameters
+ *
+ * @note
+ * The @a url must be a pointer to a URL structure.
+ *
+ * @return The function url_have_transport() returns @e true, if the URL
+ * contains transport parameters, @e false otherwise.
+ */
+int url_have_transport(url_t const *url)
+{
+ return url_strip_transport2((url_t *)url, 0);
+}
+
+/**Lazily compare two URLs.
+ *
+ * Compare essential parts of URLs: schema, host, port, and username.
+ *
+ * any_url compares 0 with any other URL.
+ *
+ * pres: and im: URIs compares 0 with SIP URIs.
+ *
+ * @note
+ * The @a a and @a b must be pointers to URL structures.
+ *
+ * @note Currently, the url parameters are not compared. This is because the
+ * url_cmp() is used to sort URLs: taking parameters into account makes that
+ * impossible.
+ */
+int url_cmp(url_t const *a, url_t const *b)
+{
+ int rv;
+ int url_type;
+
+ if ((a && a->url_type == url_any) || (b && b->url_type == url_any))
+ return 0;
+
+ if (!a || !b)
+ return (a != NULL) - (b != NULL);
+
+ if ((rv = a->url_type - b->url_type)) {
+#if 0
+ /* presence and instant messaging URLs match magically with SIP */
+ enum url_type_e a_type = a->url_type;
+ enum url_type_e b_type = b->url_type;
+
+ if (a_type == url_im || a_type == url_pres)
+ a_type = url_sip;
+
+ if (b_type == url_im || b_type == url_pres)
+ b_type = url_sip;
+
+ if (a_type != b_type)
+#endif
+ return rv;
+ }
+
+ url_type = a->url_type; /* Or b->url_type, they are equal! */
+
+ if (url_type <= url_unknown &&
+ ((rv = !a->url_scheme - !b->url_scheme) ||
+ (a->url_scheme && b->url_scheme &&
+ (rv = strcasecmp(a->url_scheme, b->url_scheme)))))
+ return rv;
+
+ if ((rv = host_cmp(a->url_host, b->url_host)))
+ return rv;
+
+ if (a->url_port != b->url_port) {
+ char const *a_port;
+ char const *b_port;
+
+ if (url_type != url_sip && url_type != url_sips)
+ a_port = b_port = url_port_default(url_type);
+ else if (host_is_ip_address(a->url_host))
+ a_port = b_port = url_port_default(url_type);
+ else
+ a_port = b_port = "";
+
+ if (a->url_port) a_port = a->url_port;
+ if (b->url_port) b_port = b->url_port;
+
+ if ((rv = strcmp(a_port, b_port)))
+ return rv;
+ }
+
+ if (a->url_user != b->url_user) {
+ if (a->url_user == NULL) return -1;
+ if (b->url_user == NULL) return +1;
+ switch (url_type) {
+ case url_tel: case url_modem: case url_fax:
+ rv = url_tel_cmp_numbers(a->url_user, b->url_user);
+ break;
+ default:
+ rv = strcmp(a->url_user, b->url_user);
+ break;
+ }
+ if (rv)
+ return rv;
+ }
+
+#if 0
+ if (a->url_path != b->url_path) {
+ if (a->url_path == NULL) return -1;
+ if (b->url_path == NULL) return +1;
+ if ((rv = strcmp(a->url_path, b->url_path)))
+ return rv;
+ }
+#endif
+
+ return 0;
+}
+
+static
+int url_tel_cmp_numbers(char const *A, char const *B)
+{
+ char a, b;
+ int rv;
+
+ while (*A && *B) {
+ #define UNHEX(a) (a - (a >= 'a' ? 'a' - 10 : (a >= 'A' ? 'A' - 10 : '0')))
+ /* Skip visual-separators */
+ do {
+ a = *A++;
+ if (a == '%' && IS_HEX(A[0]) && IS_HEX(A[1]))
+ a = (UNHEX(A[0]) << 4) | UNHEX(A[1]), A +=2;
+ } while (a == ' ' || a == '-' || a == '.' || a == '(' || a == ')');
+
+ if (isupper(a))
+ a = tolower(a);
+
+ do {
+ b = *B++;
+ if (b == '%' && IS_HEX(B[0]) && IS_HEX(B[1]))
+ b = (UNHEX(B[0]) << 4) | UNHEX(B[1]), B +=2;
+ } while (b == ' ' || b == '-' || b == '.' || b == '(' || b == ')');
+
+ if (isupper(b))
+ b = tolower(b);
+
+ if ((rv = a - b))
+ return rv;
+ }
+
+ return (int)*A - (int)*B;
+}
+
+/**Conservative comparison of urls.
+ *
+ * Compare all parts of URLs.
+ *
+ * @note
+ * The @a a and @a b must be pointers to URL structures.
+ *
+ */
+int url_cmp_all(url_t const *a, url_t const *b)
+{
+ int rv, url_type;
+
+ if (!a || !b)
+ return (a != NULL) - (b != NULL);
+
+ if ((rv = a->url_type - b->url_type))
+ return rv;
+
+ url_type = a->url_type; /* Or b->url_type, they are equal! */
+
+ if (url_type <= url_unknown &&
+ ((rv = !a->url_scheme - !b->url_scheme) ||
+ (a->url_scheme && b->url_scheme &&
+ (rv = strcasecmp(a->url_scheme, b->url_scheme)))))
+ return rv;
+
+ if ((rv = a->url_root - b->url_root))
+ return rv;
+
+ if ((rv = host_cmp(a->url_host, b->url_host)))
+ return rv;
+
+ if (a->url_port != b->url_port) {
+ char const *a_port;
+ char const *b_port;
+
+ if (url_type != url_sip && url_type != url_sips)
+ a_port = b_port = url_port_default(url_type);
+ else if (host_is_ip_address(a->url_host))
+ a_port = b_port = url_port_default(url_type);
+ else
+ a_port = b_port = "";
+
+ if (a->url_port) a_port = a->url_port;
+ if (b->url_port) b_port = b->url_port;
+
+ if ((rv = strcmp(a_port, b_port)))
+ return rv;
+ }
+
+ if (a->url_user != b->url_user) {
+ if (a->url_user == NULL) return -1;
+ if (b->url_user == NULL) return +1;
+
+ switch (url_type) {
+ case url_tel: case url_modem: case url_fax:
+ rv = url_tel_cmp_numbers(a->url_user, b->url_user);
+ break;
+ default:
+ rv = strcmp(a->url_user, b->url_user);
+ break;
+ }
+ if (rv)
+ return rv;
+ }
+
+ if (a->url_path != b->url_path) {
+ if (a->url_path == NULL) return -1;
+ if (b->url_path == NULL) return +1;
+ if ((rv = strcmp(a->url_path, b->url_path)))
+ return rv;
+ }
+
+ if (a->url_params != b->url_params) {
+ if (a->url_params == NULL) return -1;
+ if (b->url_params == NULL) return +1;
+ if ((rv = strcmp(a->url_params, b->url_params)))
+ return rv;
+ }
+
+ if (a->url_headers != b->url_headers) {
+ if (a->url_headers == NULL) return -1;
+ if (b->url_headers == NULL) return +1;
+ if ((rv = strcmp(a->url_headers, b->url_headers)))
+ return rv;
+ }
+
+ if (a->url_headers != b->url_headers) {
+ if (a->url_headers == NULL) return -1;
+ if (b->url_headers == NULL) return +1;
+ if ((rv = strcmp(a->url_headers, b->url_headers)))
+ return rv;
+ }
+
+ if (a->url_fragment != b->url_fragment) {
+ if (a->url_fragment == NULL) return -1;
+ if (b->url_fragment == NULL) return +1;
+ if ((rv = strcmp(a->url_fragment, b->url_fragment)))
+ return rv;
+ }
+
+ return 0;
+}
+
+/** Return default port number corresponding to the url type */
+char const *url_port_default(enum url_type_e url_type)
+{
+ switch (url_type) {
+ case url_sip: /* "sip:" */
+ return "5060";
+ case url_sips: /* "sips:" */
+ return "5061";
+ case url_http: /* "http:" */
+ return "80";
+ case url_https: /* "https:" */
+ return "443";
+ case url_ftp: /* "ftp:" */
+ case url_file: /* "file:" */
+ return "21";
+ case url_rtsp: /* "rtsp:" */
+ case url_rtspu: /* "rtspu:" */
+ return "554";
+ case url_mailto: /* "mailto:" */
+ return "25";
+
+ case url_any: /* "*" */
+ return "*";
+
+ case url_msrp:
+ case url_msrps:
+ return "9999"; /* XXXX */
+
+ case url_tel:
+ case url_fax:
+ case url_modem:
+ case url_im:
+ case url_pres:
+ case url_cid:
+ case url_wv:
+
+ default: /* Unknown scheme */
+ return "";
+ }
+}
+
+/** Return default transport name corresponding to the url type */
+char const *url_tport_default(enum url_type_e url_type)
+{
+ switch (url_type) {
+ case url_sip:
+ return "*";
+ case url_sips:
+ return "tls";
+ case url_http:
+ return "tcp";
+ case url_https:
+ return "tls";
+ case url_ftp:
+ case url_file:
+ return "tcp";
+ case url_rtsp:
+ return "tcp";
+ case url_rtspu:
+ return "udp";
+ case url_mailto:
+ return "tcp";
+ case url_msrp:
+ return "tcp";
+ case url_msrps:
+ return "tls";
+
+ case url_any: /* "*" */
+ case url_tel:
+ case url_fax:
+ case url_modem:
+ case url_im:
+ case url_pres:
+ case url_cid:
+ case url_wv:
+
+ default: /* Unknown scheme */
+ return "*";
+ }
+}
+
+
+/** Return the URL port string */
+char const *url_port(url_t const *u)
+{
+ if (!u)
+ return "";
+ else if (u->url_port && u->url_port[0])
+ return u->url_port;
+
+ if (u->url_type == url_sips || u->url_type == url_sip)
+ if (!host_is_ip_address(u->url_host))
+ return "";
+
+ return url_port_default(u->url_type);
+}
+
+/** Sanitize URL.
+ *
+ * The function url_sanitize() adds a scheme to an incomplete URL. It
+ * modifies its parameter structure @a url. Currently, the function follows
+ * simple heuristics:
+ *
+ * - URL with host name starting with @c ftp. is an FTP URL
+ * - URL with host name starting with @c www. is an HTTP URL
+ * - URL with host and path, e.g., @c host/foo;bar, is an HTTP URL
+ * - URL with host name, no path is a SIP URL.
+ *
+ * @param url pointer to URL struct to be sanitized (IN/OUT)
+ *
+ * @return
+ * The function url_sanitize() returns 0 if it considers URL to be
+ * sane, and -1 otherwise.
+ */
+int url_sanitize(url_t *url)
+{
+ if (!url)
+ return -1;
+ else if (url->url_scheme != NULL)
+ /* xyzzy */;
+ else if (url->url_host == NULL)
+ return -1;
+ else if (strncasecmp(url->url_host, "ftp.", strlen("ftp.")) == 0)
+ url->url_type = url_ftp, url->url_scheme = "ftp", url->url_root = '/';
+ else if (strncasecmp(url->url_host, "www.", strlen("www.")) == 0
+ || url->url_path)
+ url->url_type = url_http, url->url_scheme = "http", url->url_root = '/';
+ else
+ url->url_type = url_sip, url->url_scheme = "sip";
+
+ return 0;
+}
+
+#include <sofia-sip/su_md5.h>
+
+static
+void canon_update(su_md5_t *md5, char const *s, size_t n, char const *allow)
+{
+ size_t i, j;
+
+ for (i = 0, j = 0; i < n && s[i]; i++) {
+ char c;
+
+ if (s[i] == '%' && i + 2 < n && IS_HEX(s[i+1]) && IS_HEX(s[i+2])) {
+#define UNHEX(a) (a - (a >= 'a' ? 'a' - 10 : (a >= 'A' ? 'A' - 10 : '0')))
+ c = (UNHEX(s[i+1]) << 4) | UNHEX(s[i+2]);
+#undef UNHEX
+ if (c != '%' && c > ' ' && c < '\177' &&
+ (!strchr(EXCLUDED, c) || strchr(allow, c))) {
+ if (i != j)
+ su_md5_iupdate(md5, s + j, i - j);
+ su_md5_iupdate(md5, &c, 1);
+ j = i + 3;
+ }
+ i += 2;
+ }
+ }
+
+ if (i != j)
+ su_md5_iupdate(md5, s + j, i - j);
+}
+
+/** Update MD5 sum with url-string contents */
+static
+void url_string_update(su_md5_t *md5, char const *s)
+{
+ size_t n;
+ int hostpart = 1;
+ enum url_type_e type = url_any;
+ char const *at, *colon;
+ char schema[48];
+
+ if (s == NULL || strlen(s) == 0 || strcmp(s, "*") == 0) {
+ su_md5_update(md5, "*\0\0*", 4);
+ return;
+ }
+
+ n = strcspn(s, ":/?#");
+ if (n >= sizeof schema) {
+ su_md5_update(md5, ":", 1);
+ }
+ else if (n && s[n] == ':' ) {
+ at = url_canonize(schema, s, n, "+");
+
+ type = url_get_type(schema, at - schema);
+ su_md5_iupdate(md5, schema, at - schema);
+
+ hostpart = !url_type_is_opaque(type);
+ s += n + 1;
+ }
+ else {
+ su_md5_update(md5, "", 1);
+ }
+
+ if (type == url_sip || type == url_sips) {
+ n = strcspn(s, "@#"); /* Opaque part */
+ if (s[n] != '@')
+ n = 0;
+ n += strcspn(s + n, "/;?#");
+ }
+ else if (type == url_wv) { /* WV URL may have / in user part */
+ n = strcspn(s, "@#?;");
+ if (s[n] == '@')
+ n += strcspn(s + n, ";?#");
+ }
+ else if (!hostpart || s[0] != '/') {
+ n = strcspn(s, "/;?#"); /* Opaque part */
+ }
+ else if (s[1] == '/') {
+ s += 2;
+ n = strcspn(s, "/;?#"); /* Until host, path, query or fragment */
+ }
+ else {
+ /* foo:/bar */
+ su_md5_update(md5, "\0\0", 2); /* user, host */
+ su_md5_striupdate(md5, url_port_default(type));
+ return;
+ }
+
+ if (!hostpart) {
+ char const *colon = memchr(s, ':', n);
+
+ if (colon) n = colon - s;
+ canon_update(md5, s, n, ""); /* user */
+ su_md5_update(md5, "\0", 1); /* host, no port */
+ su_md5_striupdate(md5, url_port_default(type));
+ return;
+ }
+
+ at = memchr(s, '@', n);
+
+ if (at) {
+ char const *allow =
+ (type == url_sip || type == url_sips)
+ ? SIP_USER_UNRESERVED
+ : USER_UNRESERVED;
+
+ colon = type == url_unknown ? NULL : memchr(s, ':', at - s);
+
+ /* Updated only user part */
+ if (colon)
+ canon_update(md5, s, colon - s, allow);
+ else
+ canon_update(md5, s, at - s, allow);
+ n = n - (at + 1 - s);
+ s = at + 1;
+ }
+ else
+ su_md5_iupdate(md5, "", 1); /* user */
+
+ colon = memchr(s, ':', n); /* XXX - IPv6! */
+ if (colon) {
+ canon_update(md5, s, colon - s, ""); /* host */
+ canon_update(md5, colon + 1, (s + n) - (colon + 1), "");
+ }
+ else {
+ canon_update(md5, s, n, ""); /* host */
+ su_md5_strupdate(md5, url_port_default(type)); /* port */
+ }
+
+ /* ignore parameters/path/headers.... */
+}
+
+
+/** Update md5 digest with contents of URL.
+ *
+ */
+void url_update(su_md5_t *md5, url_t const *url)
+{
+ if (url_string_p((url_string_t *)url)) {
+ url_string_update(md5, (char const *)url);
+ }
+ else {
+ SU_MD5_STRI0UPDATE(md5, url->url_scheme);
+ SU_MD5_STRI0UPDATE(md5, url->url_user);
+ SU_MD5_STRI0UPDATE(md5, url->url_host);
+ su_md5_striupdate(md5, URL_PORT(url));
+ /* XXX - parameters/path.... */
+ /* SU_MD5_STRI0UPDATE(md5, url->url_path); */
+ }
+}
+
+/** Calculate a digest from URL contents. */
+void url_digest(void *hash, int hsize, url_t const *url, char const *key)
+{
+ su_md5_t md5[1];
+ uint8_t digest[SU_MD5_DIGEST_SIZE];
+
+ su_md5_init(md5);
+ if (key) su_md5_strupdate(md5, key);
+ url_update(md5, url);
+ su_md5_digest(md5, digest);
+
+ if (hsize > SU_MD5_DIGEST_SIZE) {
+ memset((char *)hash + SU_MD5_DIGEST_SIZE, 0, hsize - SU_MD5_DIGEST_SIZE);
+ hsize = SU_MD5_DIGEST_SIZE;
+ }
+
+ memcpy(hash, digest, hsize);
+}
+
+/** Convert a URL query to a header string.
+ *
+ * URL query is converted by replacing each "=" in header name "=" value
+ * pair with semicolon (":"), and the "&" separating header-name-value pairs
+ * with line feed ("\n"). The "body" pseudoheader is moved last in the
+ * string. The %-escaping is removed. Note that if the @a query contains %00,
+ * the resulting string will be truncated.
+ *
+ * @param home memory home used to alloate string (if NULL, malloc() it)
+ * @param query query part from SIP URL
+ *
+ * The result string is allocated from @a home, and it can be used as
+ * argument to msg_header_parse_str(), msg_header_add_str() or
+ * SIPTAG_HEADER_STR().
+ *
+ * @sa msg_header_add_str(), SIPTAG_HEADER_STR(),
+ * sip_headers_as_url_query(), sip_url_query_as_taglist(),
+ * @RFC3261 section 19.1.1 "Headers", #url_t, url_s#url_headers,
+ * url_unescape(), url_unescape_to()
+ *
+ * @since New in @VERSION_1_12_4.
+ */
+char *url_query_as_header_string(su_home_t *home,
+ char const *query)
+{
+ size_t i, j, n, b_start = 0, b_len = 0;
+ char *s = su_strdup(home, query);
+
+ if (!s)
+ return NULL;
+
+ for (i = 0, j = 0; s[i];) {
+ n = strcspn(s + i, "=");
+ if (!s[i + n])
+ break;
+ if (n == 4 && strncasecmp(s + i, "body", 4) == 0) {
+ if (b_start)
+ break;
+ b_start = i + n + 1, b_len = strcspn(s + b_start, "&");
+ i = b_start + b_len + 1;
+ continue;
+ }
+ if (i != j)
+ memmove(s + j, s + i, n);
+ s[j + n] = ':';
+ i += n + 1, j += n + 1;
+ n = strcspn(s + i, "&");
+ j += url_unescape_to(s + j, s + i, n);
+ i += n;
+ if (s[i]) {
+ s[j++] = '\n', i++;
+ }
+ }
+
+ if (s[i])
+ return (void)su_free(home, s), NULL;
+
+ if (b_start) {
+ s[j++] = '\n', s[j++] = '\n';
+ j += url_unescape_to(s + j, query + b_start, b_len);
+ }
+ s[j] = '\0'; assert(j <= i);
+
+ return s;
+}
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/url.docs
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/url.docs Thu Dec 21 01:30:28 2006
@@ -0,0 +1,189 @@
+/**@MODULEPAGE "url" - URL Module
+
+ at section url_meta Module Meta Information
+
+The Sofia @b url module contains macros and functions for using URL
+datatype #url_t, parsing and printing URLs.
+
+ at CONTACT Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ at STATUS @SofiaSIP Core library
+
+ at LICENSE LGPL
+
+ at section url_syntax Using URL Library
+
+The URL library provides URL datatype and helper functions related to it.
+There is URL parser, which separates the URL components to the #url_t
+structure.
+
+ at note
+Please note that we use terms URL and URI interchangeable.
+
+The formal URI syntax is defined in the
+<a href="http://www.ietf.org/rfc/rfc2396.txt">RFC2396</a>.
+
+The URLs consist of a subset of printable ASCII (ECMA-5) characters. The
+subset excludes space and characters commonly used as @e delimiters in
+text-based protocols, such as <b> < > # \% </b>and<b> " </b> (double
+quote), and so called @e unwise characters whose positions are reserved for
+national extensions in ECMA-5. In US-ASCII, those characters are:
+<code><b>
+{ } | \ ^ [ ] `
+</b></code>
+
+There are also nine characters that can have special syntactic meaning in
+some parts of the URI. These @e reserved characters are used to separate
+syntactical parts of the URLs from each other. The reserved characters are
+as follows: <b> : @ / ; ? & = + </b>and<b> $</b>.
+
+The URL library understands two alternative URL syntaxes. First, the
+basic syntax used by, e.g., @b ftp:, @b http: and @b rtsp: URLs:
+
+<i>scheme</i> ":" ["//" [ <i>user</i> [":" <i>password</i> ] "@"]
+<i>host</i> [":" <i>port</i> ] ]
+ ["/" <i>path</i> ] ["?" <i>query</i> ] ["#" <i>fragment</i> ]
+
+Alternatively, the syntax used by @b mailto:, @b sip:, @b im:, @b tel,
+and @b pres: URLs:
+
+<i>scheme</i> ":" [ [ <i>user</i> [":" <i>password</i> ] "@"]
+<i>host</i> [":" <i>port</i> ] ] [";" <i>params</i> ] ["?" <i>query</i> ]
+["#" <i>fragment</i> ]
+
+Note that also "*" is considered to be a valid URL (with type #url_any).
+
+For example: \n
+ at code
+http://example.org:7100/cgi-bin/query?key=90786
+ftp://user:pass\@ftp.example.com/pub/
+sip:user:pass\@example.com;user=ip
+tel:+358718008000
+ at endcode
+
+ at subsection url_parsing Converting a String to #url_t
+
+The function url_make() converts a string to a freshly allocated #url_t
+structure. The URL components are split into parts as shown above.
+The hex encoding using \% is removed if the encoded character can
+syntactically be part of the field. For instance, "%41" is decoded as
+"A" in the user part, but "%40" (@) is left as is. (This is called
+canonization of the URL fields.)
+
+The function url_format() is provided for generating the URL with
+printf()-like formatting.
+
+For example, when we make the url from the string below
+ at code
+sip:joe%2Euser at example%2Ecom;method=%4D%45%53%53%41%47%45?body=CANNED%20MSG
+ at endcode
+the components are NUL-terminated, canonized and assigned to the structure
+as follows:
+ at code
+ url_type = url_sip
+ url_root = 0
+ url_scheme = "sip"
+ url_user = "joe.user"
+ url_password = NULL
+ url_host = "example.com"
+ url_port = NULL
+ url_path = NULL
+ url_params = "method=MESSAGE"
+ url_headers = "body=CANNED%20MSG"
+ url_fragment = NULL
+ at endcode
+
+You can use the function url_param() and url_have_param() to access
+particular parameters from @ref url_t::url_params "url->url_params" string.
+
+ at subsection url_parsing Converting a #url_t structure to string
+
+The function url_as_string() converts contents of #url_t structure to a
+newly allocated string.
+
+ at subsection url_reference Functions and Macros in URL Module
+
+The include file <url.h> contains the types, function and macros of URL
+module. The functions and macros are listed here for the reference, too.
+The most important functions and macros for manipulating URLs are here:
+ at code
+url_t *url_make(su_home_t *h, char const *str);
+url_t *url_format(su_home_t *h, char const *fmt, ...);
+char *url_as_string(su_home_t *home, url_t const *url);
+url_t *url_hdup(su_home_t *h, url_t const *src);
+int url_sanitize(url_t *u);
+char const *url_scheme(enum url_type_e type);
+
+#define URL_INIT_AS(type)
+void url_init(url_t *url, enum url_type_e type);
+
+int url_cmp(url_t const *a, url_t const *b);
+int url_cmp_all(url_t const *a, url_t const *b);
+
+isize_t url_param(char const *params, char const *tag,
+ char value[], isize_t vlen);
+int url_has_param(url_t const *url, char const *name);
+isize_t url_have_param(char const *params, char const *tag);
+int url_param_add(su_home_t *h, url_t *url, char const *param);
+ at endcode
+
+There are functions for handling %-encoding used in URLs:
+ at code
+int url_reserved_p(char const *s);
+char *url_escape(char *d, char const *s, char const reserved[]);
+int url_esclen(char const *s, char const reserved[]);
+char *url_unescape(char *d, char const *s);
+ at endcode
+
+There are a few function and macros helping resolving URLs:
+ at code
+char const *url_port_default(enum url_type_e url_type);
+char const *url_tport_default(enum url_type_e url_type);
+char const *url_port(url_t const *u);
+#define URL_PORT(u)
+ at endcode
+
+In addition to the basic URL structure, #url_t, the library interface
+provides an union type #url_string_t for passing unparsed strings instead
+of parsed URLs as function arguments:
+ at code
+#define URL_STRING_P(u) ((u) && *((url_string_t*)(u))->us_str != 0)
+#define URL_IS_STRING(u) ((u) && *((url_string_t*)(u))->us_str != 0)
+int url_string_p(url_string_t const * url);
+int url_is_string(url_string_t const * url);
+#define URL_STRING_MAKE(s)
+ at endcode
+
+There are a macros for printf()-like formatting of URLs:
+ at code
+#define URL_PRINT_FORMAT
+#define URL_PRINT_ARGS(u)
+ at endcode
+
+These functions calculate MD5 digest of URL or contribute contents of the
+URL to MD5 sum:
+ at code
+void url_update(struct su_md5_t *md5, url_t const *url);
+void url_digest(void *hash, int hsize, url_t const *, char const *key);
+ at endcode
+
+SIP or SIPS URIs have some parameters that control transport of the request.
+In some cases, they should be detected and removed:
+ at code
+int url_have_transport(url_t const *u);
+int url_strip_transport(url_t *u);
+ at endcode
+
+Finally, there are functions used as building blocks for protocol parsers
+using URLs:
+ at code
+int url_d(url_t *url, char *s);
+isize_t url_len(url_t const * url);
+issize_t url_e(char buffer[], isize_t n, url_t const *url);
+#define URL_E(buf, end, url)
+isize_t url_xtra(url_t const * url);
+issize_t url_dup(char *, isize_t , url_t *dst, url_t const *src);
+#define URL_DUP(buf, end, dst, src)
+ at endcode
+
+*/
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/url_tag.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/url_tag.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,161 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE url_tag.c URL Tag classes
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Feb 21 10:15:20 2001 ppessi
+ */
+
+#include "config.h"
+
+#define TAG_NAMESPACE "url"
+
+#include <sofia-sip/su.h>
+
+#include <sofia-sip/url_tag.h>
+#include <sofia-sip/url_tag_class.h>
+#include <sofia-sip/su_tag_class.h>
+
+#include <sofia-sip/url.h>
+
+#include <string.h>
+
+tag_typedef_t urltag_any = NSTAG_TYPEDEF(*);
+
+tag_typedef_t urltag_url = URLTAG_TYPEDEF(url);
+
+int urltag_snprintf(tagi_t const *t, char b[], size_t size)
+{
+ url_string_t const *us = (url_string_t const *)t->t_value;
+
+ if (us == NULL)
+ return snprintf(b, size, "<null>");
+ if (URL_STRING_P(us))
+ return snprintf(b, size, "<%s>", us->us_str);
+ else
+ return snprintf(b, size, "<" URL_PRINT_FORMAT ">",
+ URL_PRINT_ARGS(us->us_url));
+}
+
+size_t urltag_xtra(tagi_t const *t, size_t offset)
+{
+ url_t const *url = (url_t const *)t->t_value;
+
+ if (url == NULL || url == (url_t *)-1)
+ return 0;
+ else if (URL_STRING_P(url))
+ return t_str_xtra(t, offset);
+ else
+ return SU_ALIGN(offset) + sizeof(*url) + url_xtra(url);
+}
+
+tagi_t *urltag_dup(tagi_t *dst, tagi_t const *src, void **bb)
+{
+ url_t const *url = (url_t const *)src->t_value;
+
+ if (url == NULL || url == (url_t *)-1) {
+ dst->t_tag = src->t_tag;
+ dst->t_value = src->t_value;
+ }
+ else if (URL_STRING_P(url)) {
+ return t_str_dup(dst, src, bb);
+ } else {
+ size_t xtra = url_xtra(url);
+ char *b = *bb;
+ url_t *d;
+
+ b += SU_ALIGN(b);
+ d = (url_t *)b;
+ url_dup(b + sizeof(*d), xtra, d, url);
+
+ dst->t_tag = src->t_tag;
+ dst->t_value = (tag_value_t)d;
+ *bb = b + sizeof(*d) + xtra;
+ }
+
+ return dst + 1;
+}
+
+#define IS_EXCLUDED(u) \
+ (u <= ' ' \
+ || u >= '\177' \
+ || (u < 64 ? (0xb400000aU & (1 << (63 - u))) \
+ : (u < 96 ? (0x0000001eU & (1 << (95 - u))) \
+ : /*u < 128*/ (0x8000001dU & (1 << (127 - u))))) != 0)
+
+/** Tag function used to convert a string to a URL tag value.
+ *
+ * @param tt tag type
+ * @param home memory home used to allocate new #url_t structure
+ * @param str string to convert
+ * @param return_value return-value parameter for converted url
+ *
+ * @retval 0 when successful
+ * @retval -1 upon an error
+ *
+ * @since New in @VERSION_1_12_2.
+ */
+int urltag_scan(tag_type_t tt, su_home_t *home,
+ char const *str,
+ tag_value_t *return_value)
+{
+ size_t len;
+ url_t *url;
+ char *s;
+
+ for (len = 0; !IS_EXCLUDED(str[len]); len++)
+ ;
+
+ url = su_alloc(home, (sizeof *url) + len + 1);
+ if (!url)
+ return -1;
+ s = memcpy((char *)(url + 1), str, len);
+ s[len] = 0;
+
+ if (url_d(url, s) < 0)
+ return (void)su_free(home, url), -1;
+
+ *return_value = (tag_value_t)url;
+
+ return 0;
+}
+
+tag_class_t url_tag_class[1] =
+ {{
+ sizeof(url_tag_class),
+ /* tc_next */ NULL,
+ /* tc_len */ NULL,
+ /* tc_move */ NULL,
+ /* tc_xtra */ urltag_xtra,
+ /* tc_dup */ urltag_dup,
+ /* tc_free */ NULL,
+ /* tc_find */ NULL,
+ /* tc_snprintf */ urltag_snprintf,
+ /* tc_filter */ NULL,
+ /* tc_ref_set */ t_ptr_ref_set,
+ /* tc_scan */ urltag_scan,
+ }};
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/urlmap.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/urlmap.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1167 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**
+ * @file urlmap.c
+ * @brief Mapping with hierarchical URLs.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Mar 10 17:05:23 2004 ppessi
+ *
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include "urlmap.h"
+
+/** Create map entry. */
+UrlMap *url_map_new(su_home_t *home,
+ url_string_t const *url,
+ unsigned size)
+{
+ UrlMap *um;
+ int xtra;
+ url_t *u;
+
+ xtra = url_xtra(url->us_url);
+ um = su_zalloc(home, size + xtra);
+ if (!um || url_dup((char *)um + size, xtra, um->um_url, url->us_url) < 0) {
+ su_free(home, um);
+ return NULL;
+ }
+
+ u = um->um_url;
+ if (!u->url_path)
+ u->url_path = "";
+
+ return um;
+}
+
+static
+void left_rotate(UrlMap **top, UrlMap *x)
+{
+ /* x c
+ * / \ / \
+ * Convert a c into x d
+ * / \ / \
+ * b d a b
+ */
+ UrlMap *c = x->um_right, *dad = x->um_dad; assert(c);
+
+ if ((x->um_right = c->um_left))
+ x->um_right->um_dad = x;
+
+ if (!(c->um_dad = dad))
+ *top = c;
+ else if (dad->um_left == x)
+ dad->um_left = c;
+ else
+ assert(dad->um_right == x), dad->um_right = c;
+
+ c->um_left = x;
+ x->um_dad = c;
+}
+
+static
+void right_rotate(UrlMap **top, UrlMap *x)
+{
+ /* x c
+ * / \ / \
+ * Convert c f into a x
+ * / \ / \
+ * a d d f
+ */
+ UrlMap *c = x->um_left, *dad = x->um_dad; assert(c);
+
+ if ((x->um_left = c->um_right))
+ x->um_left->um_dad = x;
+
+ if (!(c->um_dad = dad))
+ *top = c;
+ else if (dad->um_right == x)
+ dad->um_right = c;
+ else
+ assert(dad->um_left == x), dad->um_left = c;
+
+ c->um_right = x;
+ x->um_dad = c;
+}
+
+/** Balance Red-Black binary tree after inserting node @a um.
+ *
+ * The function red_black_balance_insert() balances a red-black tree after
+ * insertion.
+ */
+static
+void red_black_balance_insert(UrlMap **top, UrlMap *um)
+{
+ UrlMap *dad, *uncle, *granddad;
+
+ um->um_black = 0;
+
+ for (dad = um->um_dad; um != *top && !dad->um_black; dad = um->um_dad) {
+ /* Repeat until we are parent or we have a black dad */
+ granddad = dad->um_dad; assert(granddad);
+ if (dad == granddad->um_left) {
+ uncle = granddad->um_right;
+ if (uncle && !uncle->um_black) {
+ dad->um_black = 1;
+ uncle->um_black = 1;
+ granddad->um_black = 0;
+ um = granddad;
+ } else {
+ if (um == dad->um_right) {
+ left_rotate(top, um = dad);
+ dad = um->um_dad; assert(dad);
+ granddad = dad->um_dad; assert(granddad);
+ }
+ dad->um_black = 1;
+ granddad->um_black = 0;
+ right_rotate(top, granddad);
+ }
+ } else { assert(dad == granddad->um_right);
+ uncle = granddad->um_left;
+ if (uncle && !uncle->um_black) {
+ dad->um_black = 1;
+ uncle->um_black = 1;
+ granddad->um_black = 0;
+ um = granddad;
+ } else {
+ if (um == dad->um_left) {
+ right_rotate(top, um = dad);
+ dad = um->um_dad; assert(dad);
+ granddad = dad->um_dad; assert(granddad);
+ }
+ dad->um_black = 1;
+ granddad->um_black = 0;
+ left_rotate(top, granddad);
+ }
+ }
+ }
+
+ assert(*top);
+
+ (*top)->um_black = 1;
+}
+
+static
+void red_black_balance_delete(UrlMap **top, UrlMap *um)
+{
+ UrlMap *dad, *brother;
+
+ for (dad = um->um_dad; um != *top && !dad->um_black; dad = um->um_dad) {
+ if (um == dad->um_left) {
+ brother = dad->um_right;
+
+ if (!brother) {
+ um = dad;
+ continue;
+ }
+
+ assert(brother->um_black);
+ if ((!brother->um_left || brother->um_left->um_black) &&
+ (!brother->um_right || brother->um_right->um_black)) {
+ brother->um_black = 0;
+ um = dad;
+ continue;
+ }
+
+ if (!brother->um_right || brother->um_right->um_black) {
+ brother->um_left->um_black = 1;
+ brother->um_black = 0;
+ right_rotate(top, brother);
+ brother = dad->um_right;
+ }
+
+ brother->um_black = dad->um_black;
+ dad->um_black = 1;
+ if (brother->um_right)
+ brother->um_right->um_black = 1;
+ left_rotate(top, dad);
+ um = *top;
+ break;
+ } else {
+ assert(um == dad->um_right);
+ brother = dad->um_left;
+
+ if (!brother) {
+ um = dad;
+ continue;
+ }
+
+ assert(brother->um_black);
+
+ if ((!brother->um_left || brother->um_left->um_black) &&
+ (!brother->um_right || brother->um_right->um_black)) {
+ brother->um_black = 0;
+ um = dad;
+ continue;
+ }
+
+ if (!brother->um_left || brother->um_left->um_black) {
+ brother->um_right->um_black = 1;
+ brother->um_black = 0;
+ left_rotate(top, brother);
+ brother = dad->um_left;
+ }
+
+ brother->um_black = um->um_dad->um_black;
+ um->um_dad->um_black = 1;
+ if (brother->um_left)
+ brother->um_left->um_black = 1;
+ right_rotate(top, dad);
+ um = *top;
+ break;
+ }
+ }
+
+ um->um_black = 1;
+}
+
+/** Compare paths. */
+static inline
+int urlmap_pathcmp(url_t const *a, url_t const *b, int *return_hostmatch)
+{
+ int retval;
+
+ retval = url_cmp(a, b);
+
+ *return_hostmatch = !retval;
+
+ if (retval)
+ return retval;
+ else
+ return strcmp(a->url_path, b->url_path);
+}
+
+/** Insert URL into map. */
+int url_map_insert(UrlMap ** const tree,
+ UrlMap * const um,
+ UrlMap **return_old)
+{
+ UrlMap *old, *dad, **tslot;
+ url_t *u;
+ int cmp, hostmatch;
+
+ if (tree == NULL || um == NULL || um->um_inserted)
+ return (errno = EINVAL), -1;
+
+ u = um->um_url;
+
+ /* Insert into red-black binary tree */
+
+ tslot = tree;
+
+ for (old = *tree, dad = NULL; old; old = *tslot) {
+ cmp = urlmap_pathcmp(u, old->um_url, &hostmatch);
+ if (cmp < 0)
+ dad = old, tslot = &old->um_left;
+ else if (cmp > 0)
+ dad = old, tslot = &old->um_right;
+ else
+ break;
+ }
+
+ assert(old != um);
+
+ if (old) {
+ if ((um->um_left = old->um_left))
+ um->um_left->um_dad = um;
+ if ((um->um_right = old->um_right))
+ um->um_right->um_dad = um;
+
+ if (!(um->um_dad = old->um_dad))
+ *tree = um;
+ else if (um->um_dad->um_left == old)
+ um->um_dad->um_left = um;
+ else assert(um->um_dad->um_right == old),
+ um->um_dad->um_right = um;
+
+ um->um_black = old->um_black;
+
+ old->um_left = NULL;
+ old->um_right = NULL;
+ old->um_dad = NULL;
+ old->um_inserted = 0;
+ } else {
+ *tslot = um;
+ um->um_dad = dad;
+ if (tree != tslot) {
+ red_black_balance_insert(tree, um);
+ } else {
+ um->um_black = 1;
+ }
+ }
+
+ um->um_inserted = 1;
+
+ if (return_old)
+ *return_old = old;
+
+ return 0;
+}
+
+/** Find a URL */
+UrlMap *
+url_map_find(UrlMap *root,
+ url_string_t const *url,
+ int relative)
+{
+ UrlMap *um, *maybe = NULL;
+ url_t u[1];
+ void *tbf = NULL;
+ char *end;
+ int cmp, hostmatch;
+
+ if (root == NULL || url == NULL)
+ return NULL;
+
+ url = tbf = url_hdup(NULL, (url_t *)url);
+ if (!url)
+ return NULL;
+
+ *u = *url->us_url;
+ if (!u->url_path)
+ u->url_path = "";
+
+ for (um = root; um; um = cmp < 0 ? um->um_left : um->um_right) {
+ cmp = urlmap_pathcmp(u, um->um_url, &hostmatch);
+ if (cmp == 0)
+ break;
+ if (hostmatch && !maybe)
+ maybe = um;
+ }
+
+ while (!um && relative && u->url_path[0]) {
+ end = strrchr(u->url_path, '/');
+ end = end ? end + 1 : (char *)u->url_path;
+ if (*end)
+ *end = '\0';
+ for (um = maybe; um; um = cmp < 0 ? um->um_left : um->um_right) {
+ if ((cmp = urlmap_pathcmp(u, um->um_url, &hostmatch)) == 0)
+ break;
+ }
+ }
+
+ su_free(NULL, tbf);
+
+ return um;
+}
+
+/** Remove URL. */
+void url_map_remove(UrlMap **top, UrlMap *um)
+{
+ UrlMap *kid, *dad;
+ int need_to_balance;
+
+ if (top == NULL || um == NULL || !um->um_inserted)
+ return;
+
+ /* Make sure that node is in tree */
+ for (dad = um; dad; dad = dad->um_dad)
+ if (dad == *top)
+ break;
+
+ assert(dad);
+ if (!dad)
+ return;
+
+ /* Find a successor node with a free branch */
+ if (!um->um_left || !um->um_right)
+ dad = um;
+ else for (dad = um->um_right; dad->um_left; dad = dad->um_left)
+ ;
+ /* Dad has a free branch => kid is dad's only child */
+ kid = dad->um_left ? dad->um_left : dad->um_right;
+
+ /* Remove dad from tree */
+ if (!(dad->um_dad))
+ *top = kid;
+ else if (dad->um_dad->um_left == dad)
+ dad->um_dad->um_left = kid;
+ else assert(dad->um_dad->um_right == dad),
+ dad->um_dad->um_right = kid;
+ if (kid)
+ kid->um_dad = dad->um_dad;
+
+ need_to_balance = kid && dad->um_black;
+
+ /* Put dad in place of um */
+ if (um != dad) {
+ if (!(dad->um_dad = um->um_dad))
+ *top = dad;
+ else if (dad->um_dad->um_left == um)
+ dad->um_dad->um_left = dad;
+ else assert(dad->um_dad->um_right == um),
+ dad->um_dad->um_right = dad;
+
+ dad->um_black = um->um_black;
+
+ if ((dad->um_left = um->um_left))
+ dad->um_left->um_dad = dad;
+
+ if ((dad->um_right = um->um_right))
+ dad->um_right->um_dad = dad;
+ }
+
+ um->um_left = NULL;
+ um->um_right = NULL;
+ um->um_dad = NULL;
+ um->um_black = 0;
+ um->um_inserted = 0;
+
+ if (need_to_balance)
+ red_black_balance_delete(top, kid);
+}
+
+#if TEST_URLMAP
+/* Functions currently used only by test cases */
+
+/** Return inorder successor of node @a um. */
+UrlMap *url_map_succ(UrlMap *um)
+{
+ UrlMap *dad;
+
+ if (um->um_right) {
+ for (um = um->um_right; um->um_left; um = um->um_left)
+ ;
+ return um;
+ }
+
+ for (dad = um->um_dad; dad && um == dad->um_right; dad = um->um_dad)
+ um = dad;
+
+ return dad;
+}
+
+/** Return inorder precedessor of node @a um. */
+UrlMap *url_map_prec(UrlMap *um)
+{
+ UrlMap *dad;
+
+ if (um->um_left) {
+ for (um = um->um_left; um->um_right; um = um->um_right)
+ ;
+ return um;
+ }
+
+ for (dad = um->um_dad; dad && um == dad->um_left; dad = um->um_dad)
+ um = dad;
+
+ return dad;
+}
+
+/** Return first node in tree @a um. */
+UrlMap *url_map_first(UrlMap *um)
+{
+ while (um && um->um_left)
+ um = um->um_left;
+
+ return um;
+}
+
+/** Return last node in tree @a um. */
+UrlMap *url_map_last(UrlMap *um)
+{
+ while (um && um->um_right)
+ um = um->um_right;
+
+ return um;
+}
+
+/** Return height of the tree */
+int url_map_height(UrlMap const *tree)
+{
+ int left, right;
+
+ if (!tree)
+ return 0;
+
+ left = tree->um_left ? url_map_height(tree->um_left) : 0;
+ right = tree->um_right ? url_map_height(tree->um_right) : 0;
+
+ if (left > right)
+ return left + 1;
+ else
+ return right + 1;
+}
+
+/** Check consistency */
+static
+int redblack_check(UrlMap const *n)
+{
+ UrlMap const *l, *r;
+
+ if (!n)
+ return 1;
+
+ l = n->um_left, r = n->um_right;
+
+ if (n->um_black || ((!l || l->um_black) && (!r || r->um_black)))
+ return (!l || redblack_check(l)) && (!r || redblack_check(r));
+ else
+ return 0;
+}
+
+/* Testing functions */
+
+int tstflags;
+
+#define TSTFLAGS tstflags
+
+#include <stdio.h>
+#include <sofia-sip/tstdef.h>
+
+char const *name = "test_urlmap";
+
+int test_path(void)
+{
+ su_home_t *home;
+ UrlMap *tree = NULL, *o;
+ UrlMap *um, *um1, *um2, *um3;
+
+ BEGIN();
+
+ home = su_home_clone(NULL, sizeof(*home)); TEST_1(home);
+
+ um1 = url_map_new(home, (void*)"http://host/aa/", sizeof *um1);
+ TEST_1(um1);
+
+ um2 = url_map_new(home, (void*)"http://host/aa/bb/", sizeof *um1);
+ TEST_1(um2);
+
+ um3 = url_map_new(home, (void*)"http://host/aa/bb/cc/",
+ sizeof *um);
+ TEST_1(um3);
+
+ TEST_1(um1 != um2 && um1 != um3 && um2 != um3);
+
+ o = (void *)-1;
+ TEST(url_map_insert(&tree, um3, &o), 0);
+ TEST_P(o, NULL); o = (void *)-1;
+ TEST(url_map_insert(&tree, um2, &o), 0);
+ TEST_P(o, NULL); o = (void *)-1;
+ TEST(url_map_insert(&tree, um1, &o), 0);
+ TEST_P(o, NULL);
+
+ um = url_map_find(tree, (void*)"http://host/aa/bb/cc", 1); TEST_P(um, um2);
+ um = url_map_find(tree, (void*)"http://host/aa/bb/cc/oo", 1);
+ TEST_P(um, um3);
+ um = url_map_find(tree, (void*)"http://host/aa/bb", 1); TEST_P(um, um1);
+ um = url_map_find(tree, (void*)"http://host/aa/bb", 0); TEST_P(um, NULL);
+ um = url_map_find(tree, (void*)"http://host/aa/bb/", 1); TEST_P(um, um2);
+
+ su_home_check(home);
+ su_home_zap(home);
+
+ END();
+}
+
+int test_insert(void)
+{
+ su_home_t *home;
+ UrlMap *tree = NULL, *o, *old;
+ UrlMap *one, *three, *five, *six, *seven;
+
+ BEGIN();
+
+ home = su_home_clone(NULL, sizeof(*home)); TEST_1(home);
+ one = url_map_new(home, (void*)"/1", sizeof (UrlMap));
+ three = url_map_new(home, (void*)"/3", sizeof (UrlMap));
+ five = url_map_new(home, (void*)"/5", sizeof (UrlMap));
+ six = url_map_new(home, (void*)"/6", sizeof (UrlMap));
+ seven = url_map_new(home, (void*)"/7", sizeof (UrlMap));
+
+ TEST_1(one);
+ TEST_1(three);
+ TEST_1(five);
+ TEST_1(six);
+ TEST_1(seven);
+
+ /* Check single node */
+ TEST(url_map_insert(&tree, five, &o), 0); TEST_P(o, NULL);
+ TEST_P(tree, five);
+ TEST_P(five->um_left, NULL); TEST_P(five->um_right, NULL);
+ TEST_P(five->um_dad, NULL); TEST(five->um_black, 1);
+
+ /* Check after another node:
+ *
+ * 5b
+ * /
+ * 3r
+ */
+ TEST(url_map_insert(&tree, three, &o), 0); TEST_P(o, NULL);
+ TEST_P(tree->um_left, three); TEST(tree->um_black, 1);
+ TEST_P(three->um_left, NULL); TEST_P(three->um_right, NULL);
+ TEST_P(three->um_dad, tree); TEST(three->um_black, 0);
+
+ /* Check third node
+ * 5b
+ * / \
+ * 3r 7r
+ */
+ TEST(url_map_insert(&tree, seven, &o), 0); TEST_P(o, NULL);
+ TEST_P(tree->um_right, seven); TEST(tree->um_black, 1);
+ TEST_P(seven->um_left, NULL); TEST_P(seven->um_right, NULL);
+ TEST_P(seven->um_dad, tree); TEST(seven->um_black, 0);
+
+ /* Check after fourth node:
+ * 5b
+ * / \
+ * 3b 7b
+ * /
+ * 1r
+ */
+ TEST(url_map_insert(&tree, one, &o), 0); TEST_P(o, NULL);
+ TEST_P(tree->um_left->um_left, one);
+ TEST(tree->um_black, 1);
+ TEST(tree->um_left->um_black, 1); TEST(tree->um_right->um_black, 1);
+ TEST_P(one->um_left, NULL); TEST_P(one->um_right, NULL);
+ TEST_P(one->um_dad, tree->um_left); TEST(one->um_black, 0);
+
+ /* Checks that we got after fifth node:
+ * 5b
+ * / \
+ * 3b 7b
+ * / /
+ * 1r 6r
+ */
+ TEST(url_map_insert(&tree, six, &o), 0); TEST_P(o, NULL);
+ TEST_P(tree, five); TEST(five->um_black, 1);
+ TEST_P(tree->um_left, three); TEST(three->um_black, 1);
+ TEST_P(tree->um_left->um_left, one); TEST(one->um_black, 0);
+ TEST_P(tree->um_right, seven); TEST(seven->um_black, 1);
+ TEST_P(tree->um_right->um_left, six); TEST(six->um_black, 0);
+
+ /* Insert five second time */
+ old = five;
+ five = url_map_new(home, (void*)"/5", sizeof (UrlMap));
+ TEST(url_map_insert(&tree, five, &o), 0); TEST_P(o, old);
+ TEST_P(tree, five); TEST(five->um_black, 1);
+ TEST_P(tree->um_left, three); TEST(three->um_black, 1);
+ TEST_P(three->um_dad, five);
+ TEST_P(tree->um_left->um_left, one); TEST(one->um_black, 0);
+ TEST_P(tree->um_right, seven); TEST(seven->um_black, 1);
+ TEST_P(seven->um_dad, five);
+ TEST_P(tree->um_right->um_left, six); TEST(six->um_black, 0);
+
+ su_home_check(home);
+ su_home_zap(home);
+
+ END();
+}
+
+int test_rotate(void)
+{
+ su_home_t *home;
+ UrlMap *tree = NULL;
+ UrlMap *x, *y, *o;
+
+ BEGIN();
+
+ home = su_home_clone(NULL, sizeof(*home)); TEST_1(home);
+
+ x = url_map_new(home, (void*)"/x", sizeof *x);
+ y = url_map_new(home, (void*)"/y", sizeof *y);
+
+ TEST_1(x);
+ TEST_1(y);
+
+ /*
+ * x y x
+ * Checks that \ transforms to / and back to \
+ * y x y
+ */
+ TEST(url_map_insert(&tree, x, &o), 0); TEST_P(o, NULL);
+ TEST(url_map_insert(&tree, y, &o), 0); TEST_P(o, NULL);
+
+ TEST_P(tree, x); TEST_P(x->um_right, y);
+ left_rotate(&tree, x);
+ TEST_P(tree, y); TEST_P(y->um_left, x);
+ right_rotate(&tree, y);
+ TEST_P(tree, x); TEST_P(x->um_right, y);
+
+ su_home_check(home);
+ su_home_zap(home);
+
+ END();
+}
+
+/** ceil of log2 */
+static
+unsigned log2ceil(unsigned k)
+{
+ unsigned result = 0;
+
+#if 0
+ if (k > (1 << 32))
+ result += 32, k = (k >> 32) + ((k & ((1 << 32) - 1)) != 0);
+#endif
+ if (k > (1 << 16))
+ result += 16, k = (k >> 16) + ((k & ((1 << 16) - 1)) != 0);
+ if (k > (1 << 8))
+ result += 8, k = (k >> 8) + ((k & ((1 << 8) - 1)) != 0);
+ if (k > (1 << 4))
+ result += 4, k = (k >> 4) + ((k & 15) != 0);
+ if (k > (1 << 2))
+ result += 2, k = (k >> 2) + ((k & 3) != 0);
+ if (k > (1 << 1))
+ result += 1, k = (k >> 1) + (k & 1);
+ if (k > 1)
+ result += 1;
+
+ return result;
+}
+
+typedef struct {
+ UrlMap te_urlmap[1];
+ int te_value;
+ int te_inserted;
+} TEntry;
+
+int test_balance(void)
+{
+ su_home_t *home;
+ UrlMap *tree = NULL, *o = NULL;
+ url_t *u;
+ TEntry *te, **nodes;
+ char path[16];
+ int i, j;
+ int const N = 1000;
+
+ BEGIN();
+
+ home = su_home_clone(NULL, sizeof(*home)); TEST_1(home);
+ nodes = su_zalloc(home, (N + 2) * (sizeof *nodes)); TEST_1(nodes);
+ nodes++;
+
+ u = url_hdup(home, (url_t *)"http://host");
+ u->url_path = path;
+
+ for (i = 0; i < N; i++) {
+ snprintf(path, (sizeof path), "p%07u", i);
+ te = (TEntry *)url_map_new(home, (void *)u, sizeof *te);
+ te->te_value = i;
+ nodes[i] = te;
+ TEST(url_map_insert(&tree, te->te_urlmap, &o), 0);
+ TEST_P(o, NULL);
+ TEST_1(url_map_height(tree) <= 2 * log2ceil(i + 1 + 1));
+ TEST_1(redblack_check(tree));
+ }
+
+ for (i = 0; i < N; i++) {
+ snprintf(path, (sizeof path), "p%07u", i);
+ te = (TEntry *)url_map_find(tree, (void*)u, 1);
+ TEST_1(te); TEST(te->te_value, i);
+ }
+
+ snprintf(path, (sizeof path), "p%07u", 0);
+
+ te = (TEntry *)url_map_find(tree, (void*)u, 1);
+
+ for (i = 0; i < N; i++) {
+ TEST_1(te); TEST(te->te_value, i);
+ te = (TEntry *)url_map_succ(te->te_urlmap);
+ }
+ TEST_1(te == NULL);
+
+ for (i = 0; i < N; i++) {
+ TEST_P(url_map_succ(nodes[i]->te_urlmap), nodes[i + 1]->te_urlmap);
+ TEST_P(url_map_prec(nodes[i]->te_urlmap), nodes[i - 1]->te_urlmap);
+ }
+
+ for (i = 0; i < N; i++) {
+ snprintf(path, (sizeof path), "p%07u", i);
+ te = (TEntry *)url_map_find(tree, (void*)u, 1);
+ TEST_1(te); TEST(te->te_value, i);
+ url_map_remove(&tree, te->te_urlmap);
+ TEST_1(te->te_urlmap->um_dad == NULL &&
+ te->te_urlmap->um_left == NULL &&
+ te->te_urlmap->um_right == NULL);
+ TEST_1(url_map_height(tree) <= 2 * log2ceil(N - i + 1));
+ TEST_1(redblack_check(tree));
+ }
+
+ TEST_P(tree, NULL);
+
+ for (i = N - 1; i >= 0; i--) {
+ o = (void *)-1;
+ TEST(url_map_insert(&tree, nodes[i]->te_urlmap, &o), 0);
+ TEST_P(o, NULL);
+ TEST_1(url_map_height(tree) <= 2 * log2ceil(N - i + 1));
+ TEST_1(redblack_check(tree));
+ }
+
+ for (i = 0; i < N; i++) {
+ TEST_P(url_map_succ(nodes[i]->te_urlmap), nodes[i + 1]->te_urlmap);
+ TEST_P(url_map_prec(nodes[i]->te_urlmap), nodes[i - 1]->te_urlmap);
+ }
+
+ for (i = 0; i < N; i++) {
+ url_map_remove(&tree, nodes[i]->te_urlmap);
+ TEST_1(url_map_height(tree) <= 2 * log2ceil(N - i + 1));
+ TEST_1(redblack_check(tree));
+ }
+
+ TEST_P(tree, NULL);
+
+ for (i = 0; i < N; i++) {
+ int sn = (i * 57) % N;
+ o = (void *)-1;
+ TEST(nodes[sn]->te_inserted, 0);
+ TEST(url_map_insert(&tree, nodes[sn]->te_urlmap, &o), 0);
+ nodes[sn]->te_inserted = 1;
+ TEST_P(o, NULL);
+ TEST_1(url_map_height(tree) <= 2 * log2ceil(i + 1 + 1));
+ TEST_1(redblack_check(tree));
+ }
+
+ for (i = 0; i < N; i++) {
+ TEST(nodes[i]->te_inserted, 1);
+ TEST_P(url_map_succ(nodes[i]->te_urlmap), nodes[i + 1]->te_urlmap);
+ TEST_P(url_map_prec(nodes[i]->te_urlmap), nodes[i - 1]->te_urlmap);
+ }
+
+ for (i = 0; i < N; i++) {
+ int sn = (i * 23) % N; /* 23 is relative prime to N */
+ TEST(nodes[sn]->te_inserted, 1);
+ url_map_remove(&tree, nodes[sn]->te_urlmap);
+ nodes[sn]->te_inserted = 0;
+ TEST_1(url_map_height(tree) <= 2 * log2ceil(N - i + 1));
+ TEST_1(redblack_check(tree));
+ }
+
+ TEST_P(tree, NULL);
+
+ for (i = 0; i < N; i++) {
+ int sn = (i * 517) % N; /* relative prime to N */
+ o = (void *)-1;
+ TEST(nodes[sn]->te_inserted, 0);
+ TEST(url_map_insert(&tree, nodes[sn]->te_urlmap, &o), 0);
+ nodes[sn]->te_inserted = 1;
+ TEST_P(o, NULL);
+ TEST_1(url_map_height(tree) <= 2 * log2ceil(i + 1 + 1));
+ TEST_1(redblack_check(tree));
+ }
+
+ for (i = 0; i < N; i++) {
+ TEST(nodes[i]->te_inserted, 1);
+ TEST_P(url_map_succ(nodes[i]->te_urlmap), nodes[i + 1]->te_urlmap);
+ TEST_P(url_map_prec(nodes[i]->te_urlmap), nodes[i - 1]->te_urlmap);
+ }
+
+ for (i = 0; i < N; i++) {
+ int sn = (i * 497) % N; /* relative prime to N */
+ TEST(nodes[sn]->te_inserted, 1);
+ url_map_remove(&tree, nodes[sn]->te_urlmap);
+ nodes[sn]->te_inserted = 0;
+ TEST_1(url_map_height(tree) <= 2 * log2ceil(N - i + 1));
+ TEST_1(redblack_check(tree));
+ }
+
+ TEST_P(tree, NULL);
+
+ for (i = 0; i < N; i++) {
+ int sn = (i * 1957) % N; /* relative prime to N */
+ o = (void *)-1;
+ TEST(nodes[sn]->te_inserted, 0);
+ TEST(url_map_insert(&tree, nodes[sn]->te_urlmap, &o), 0);
+ nodes[sn]->te_inserted = 1;
+ TEST_P(o, NULL);
+ TEST_1(url_map_height(tree) <= 2 * log2ceil(i + 1 + 1));
+ TEST_1(redblack_check(tree));
+ }
+
+ for (i = 0; i < N; i++) {
+ TEST(nodes[i]->te_inserted, 1);
+ TEST_P(url_map_succ(nodes[i]->te_urlmap), nodes[i + 1]->te_urlmap);
+ TEST_P(url_map_prec(nodes[i]->te_urlmap), nodes[i - 1]->te_urlmap);
+ }
+
+ for (i = 0; i < N; i++) {
+ int sn = (i * 1519) % N; /* relative prime to N */
+ TEST(nodes[sn]->te_inserted, 1);
+ url_map_remove(&tree, nodes[sn]->te_urlmap);
+ nodes[sn]->te_inserted = 0;
+ TEST_1(url_map_height(tree) <= 2 * log2ceil(N - i + 1));
+ TEST_1(redblack_check(tree));
+ }
+
+ TEST_P(tree, NULL);
+
+ /* Insert small, big, small, big ... */
+
+ for (i = 0; i < N / 2; i++) {
+ int sn = N - i - 1;
+ TEST(nodes[i]->te_inserted, 0);
+ o = (void *)-1;
+ TEST(url_map_insert(&tree, nodes[i]->te_urlmap, &o), 0);
+ TEST_P(o, NULL);
+ nodes[i]->te_inserted = 1;
+
+ TEST(nodes[sn]->te_inserted, 0);
+ o = (void *)-1;
+ TEST(url_map_insert(&tree, nodes[sn]->te_urlmap, &o), 0);
+ TEST_P(o, NULL);
+ nodes[sn]->te_inserted = 1;
+ }
+
+ for (i = 0; i < N; i++) {
+ TEST(nodes[i]->te_inserted, 1);
+ TEST_P(url_map_succ(nodes[i]->te_urlmap), nodes[i + 1]->te_urlmap);
+ TEST_P(url_map_prec(nodes[i]->te_urlmap), nodes[i - 1]->te_urlmap);
+ }
+
+ for (i = 0; i < N; i++) {
+ te = (TEntry *)((i & 1) ? url_map_succ(tree) : url_map_prec(tree));
+ if (te == NULL)
+ te = (TEntry *)tree;
+ TEST(te->te_inserted, 1);
+ url_map_remove(&tree, te->te_urlmap);
+ te->te_inserted = 0;
+ TEST_1(url_map_height(tree) <= 2 * log2ceil(N - i + 1));
+ TEST_1(redblack_check(tree));
+ }
+
+ TEST_P(tree, NULL);
+
+ /* Insert small, big, small, big ... */
+
+ for (i = 0; i < N / 2; i++) {
+ int sn = N - i - 1;
+ TEST(nodes[i]->te_inserted, 0);
+ o = (void *)-1;
+ TEST(url_map_insert(&tree, nodes[i]->te_urlmap, &o), 0);
+ TEST_P(o, NULL);
+ nodes[i]->te_inserted = 1;
+
+ TEST(nodes[sn]->te_inserted, 0);
+ o = (void *)-1;
+ TEST(url_map_insert(&tree, nodes[sn]->te_urlmap, &o), 0);
+ TEST_P(o, NULL);
+ nodes[sn]->te_inserted = 1;
+ }
+
+ for (i = 0; i < N; i++) {
+ TEST(nodes[i]->te_inserted, 1);
+ TEST_P(url_map_succ(nodes[i]->te_urlmap), nodes[i + 1]->te_urlmap);
+ TEST_P(url_map_prec(nodes[i]->te_urlmap), nodes[i - 1]->te_urlmap);
+ }
+
+ /* Remove last, first, last, first, ... */
+ for (i = 0; i < N; i++) {
+ te = (TEntry *)((i & 1) ? url_map_first(tree) : url_map_last(tree));
+ TEST_1(te);
+ TEST(te->te_inserted, 1);
+ url_map_remove(&tree, te->te_urlmap);
+ te->te_inserted = 0;
+ TEST_1(url_map_height(tree) <= 2 * log2ceil(N - i + 1));
+ TEST_1(redblack_check(tree));
+ }
+
+ TEST_P(tree, NULL);
+
+ /* Insert small, big, small, big ... */
+
+ for (i = 0; i < N / 2; i++) {
+ int sn = N / 2 + i;
+ TEST(nodes[i]->te_inserted, 0);
+ o = (void *)-1;
+ TEST(url_map_insert(&tree, nodes[i]->te_urlmap, &o), 0);
+ TEST_P(o, NULL);
+ nodes[i]->te_inserted = 1;
+
+ TEST(nodes[sn]->te_inserted, 0);
+ o = (void *)-1;
+ TEST(url_map_insert(&tree, nodes[sn]->te_urlmap, &o), 0);
+ TEST_P(o, NULL);
+ nodes[sn]->te_inserted = 1;
+ }
+
+ for (i = 0; i < N; i++) {
+ TEST(nodes[i]->te_inserted, 1);
+ TEST_P(url_map_succ(nodes[i]->te_urlmap), nodes[i + 1]->te_urlmap);
+ TEST_P(url_map_prec(nodes[i]->te_urlmap), nodes[i - 1]->te_urlmap);
+ }
+
+ /* Remove last, first, last, first, ... */
+ for (i = 0; i < N; i++) {
+ te = (TEntry *)((i & 1) ? url_map_first(tree) : url_map_last(tree));
+ TEST_1(te);
+ TEST(te->te_inserted, 1);
+ url_map_remove(&tree, te->te_urlmap);
+ te->te_inserted = 0;
+ TEST_1(url_map_height(tree) <= 2 * log2ceil(N - i + 1));
+ TEST_1(redblack_check(tree));
+ }
+
+ TEST_P(tree, NULL);
+
+ /* Insert in perfect order ... */
+
+ for (j = N / 2; j > 0; j /= 2) {
+ for (i = N - j; i >= 0; i -= j) {
+ if (nodes[i]->te_inserted)
+ continue;
+ o = (void *)-1;
+ TEST(url_map_insert(&tree, nodes[i]->te_urlmap, &o), 0);
+ TEST_P(o, NULL);
+ nodes[i]->te_inserted = 1;
+ }
+ }
+
+ for (i = 0; i < N; i++) {
+ TEST(nodes[i]->te_inserted, 1);
+ TEST_P(url_map_succ(nodes[i]->te_urlmap), nodes[i + 1]->te_urlmap);
+ TEST_P(url_map_prec(nodes[i]->te_urlmap), nodes[i - 1]->te_urlmap);
+ }
+
+ /* Remove such nodes that insert red uncles into tree */
+ for (i = 0; i < N; i++) {
+ te = (TEntry *)url_map_last(tree);
+ for (o = te->te_urlmap; o; o = url_map_prec(o)) {
+ UrlMap *dad, *granddad, *uncle, *to_be_removed;
+ /* We must have a node with black dad, no brother, red granddad and uncle */
+ if (!(dad = o->um_dad) || !dad->um_black)
+ continue;
+ if (dad->um_left && dad->um_right)
+ continue;
+ if (!(granddad = dad->um_dad) || granddad->um_black)
+ continue;
+ if (granddad->um_left == dad)
+ uncle = granddad->um_right;
+ else
+ uncle = granddad->um_left;
+ if (!uncle || uncle->um_black)
+ continue;
+ to_be_removed = url_map_prec(o->um_dad);
+ if (to_be_removed == granddad || to_be_removed == uncle)
+ continue;
+ if (!to_be_removed->um_left || !to_be_removed->um_right)
+ continue;
+ te = (TEntry *)to_be_removed;
+ break;
+ }
+ TEST(te->te_inserted, 1);
+ url_map_remove(&tree, te->te_urlmap);
+ te->te_inserted = 0;
+ TEST_1(url_map_height(tree) <= 2 * log2ceil(N - i + 1));
+ TEST_1(redblack_check(tree));
+ }
+
+ TEST_P(tree, NULL);
+
+ su_home_check(home);
+ su_home_zap(home);
+
+ END();
+}
+
+int test_speed(void)
+{
+ su_home_t *home;
+ UrlMap *tree = NULL, *o = NULL;
+ url_t *u;
+ TEntry *te;
+ unsigned i;
+ char path[16];
+ int const N = 1000000;
+
+ BEGIN();
+
+ home = su_home_clone(NULL, sizeof(*home)); TEST_1(home);
+
+ u = url_hdup(home, (url_t *)"http://host");
+ u->url_path = path;
+
+ for (i = 0; i < N; i++) {
+ snprintf(path, (sizeof path), "p%07u", i);
+ te = (TEntry *)url_map_new(home, (void *)u, sizeof *te);
+ te->te_value = i;
+ TEST(url_map_insert(&tree, te->te_urlmap, &o), 0);
+ TEST_P(o, NULL);
+ }
+
+ TEST_1(url_map_height(tree) <= 2 * log2ceil(i + 1));
+
+ for (i = 0; i < N; i++) {
+ snprintf(path, (sizeof path), "p%07u", i);
+ te = (TEntry *)url_map_find(tree, (void*)u, 1);
+ TEST_1(te); TEST(te->te_value, i);
+ }
+
+ snprintf(path, (sizeof path), "p%07u", 0);
+
+ te = (TEntry *)url_map_find(tree, (void*)u, 1);
+
+ for (i = 0; i < N; i++) {
+ TEST_1(te); TEST(te->te_value, i);
+ te = (TEntry *)url_map_succ(te->te_urlmap);
+ }
+ TEST_1(te == NULL);
+
+ su_home_check(home);
+ su_home_zap(home);
+
+ END();
+}
+
+
+
+void usage(void)
+{
+ fprintf(stderr,
+ "usage: %s [-v]\n",
+ name);
+}
+
+int main(int argc, char *argv[])
+{
+ int retval = 0;
+ int i;
+
+ for (i = 1; argv[i]; i++) {
+ if (strcmp(argv[i], "-v") == 0)
+ tstflags |= tst_verbatim;
+ else
+ usage();
+ }
+
+ retval |= test_insert(); fflush(stdout);
+ retval |= test_rotate(); fflush(stdout);
+ retval |= test_path(); fflush(stdout);
+ retval |= test_balance(); fflush(stdout);
+
+ return retval;
+}
+
+#endif
+
Added: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/urlmap.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/urlmap.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,65 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef URLMAP_H
+/** Defined when <urlmap.h> has been included. */
+#define URLMAP_H
+
+/**
+ * @file urlmap.h
+ * @brief
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Wed Mar 10 17:06:20 2004 ppessi
+ */
+
+#ifndef URL_H
+#include <sofia-sip/url.h>
+#endif
+
+SOFIA_BEGIN_DECLS
+
+/** Mapping of URLs */
+typedef struct _UrlMap UrlMap;
+
+struct _UrlMap {
+ UrlMap *um_left, *um_right, *um_dad;
+ unsigned um_black:1;
+ unsigned um_inserted:1;
+ unsigned :0;
+ url_t um_url[1];
+};
+
+UrlMap *url_map_new(su_home_t *home, url_string_t const *url, unsigned size);
+
+int url_map_insert(UrlMap **tree, UrlMap * um, UrlMap **return_old);
+void url_map_remove(UrlMap **tree, UrlMap *ume);
+
+UrlMap *url_map_find(UrlMap *tree, url_string_t const *u, int relative);
+
+
+SOFIA_END_DECLS
+#endif /* !defined URLMAP_H */
+
Added: freeswitch/trunk/libs/sofia-sip/ltmain.sh
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/ltmain.sh Thu Dec 21 01:30:28 2006
@@ -0,0 +1,6425 @@
+# ltmain.sh - Provide generalized library-building support services.
+# NOTE: Changing this file will not affect anything until you rerun configure.
+#
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004
+# Free Software Foundation, Inc.
+# Originally by Gordon Matzigkeit <gord at gnu.ai.mit.edu>, 1996
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+basename="s,^.*/,,g"
+
+# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh
+# is ksh but when the shell is invoked as "sh" and the current value of
+# the _XPG environment variable is not equal to 1 (one), the special
+# positional parameter $0, within a function call, is the name of the
+# function.
+progpath="$0"
+
+# RH: define SED for historic ltconfig's generated by Libtool 1.3
+[ -z "$SED" ] && SED=sed
+
+# The name of this program:
+progname=`echo "$progpath" | $SED $basename`
+modename="$progname"
+
+# Global variables:
+EXIT_SUCCESS=0
+EXIT_FAILURE=1
+
+PROGRAM=ltmain.sh
+PACKAGE=libtool
+VERSION=1.5.6
+TIMESTAMP=" (1.1220.2.95 2004/04/11 05:50:42)"
+
+
+# Check that we have a working $echo.
+if test "X$1" = X--no-reexec; then
+ # Discard the --no-reexec flag, and continue.
+ shift
+elif test "X$1" = X--fallback-echo; then
+ # Avoid inline document here, it may be left over
+ :
+elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then
+ # Yippee, $echo works!
+ :
+else
+ # Restart under the correct shell, and then maybe $echo will work.
+ exec $SHELL "$progpath" --no-reexec ${1+"$@"}
+fi
+
+if test "X$1" = X--fallback-echo; then
+ # used as fallback echo
+ shift
+ cat <<EOF
+$*
+EOF
+ exit $EXIT_SUCCESS
+fi
+
+default_mode=
+help="Try \`$progname --help' for more information."
+magic="%%%MAGIC variable%%%"
+mkdir="mkdir"
+mv="mv -f"
+rm="rm -f"
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed="${SED}"' -e 1s/^X//'
+sed_quote_subst='s/\([\\`\\"$\\\\]\)/\\\1/g'
+# test EBCDIC or ASCII
+case `echo A|tr A '\301'` in
+ A) # EBCDIC based system
+ SP2NL="tr '\100' '\n'"
+ NL2SP="tr '\r\n' '\100\100'"
+ ;;
+ *) # Assume ASCII based system
+ SP2NL="tr '\040' '\012'"
+ NL2SP="tr '\015\012' '\040\040'"
+ ;;
+esac
+
+# NLS nuisances.
+# Only set LANG and LC_ALL to C if already set.
+# These must not be set unconditionally because not all systems understand
+# e.g. LANG=C (notably SCO).
+# We save the old values to restore during execute mode.
+if test "${LC_ALL+set}" = set; then
+ save_LC_ALL="$LC_ALL"; LC_ALL=C; export LC_ALL
+fi
+if test "${LANG+set}" = set; then
+ save_LANG="$LANG"; LANG=C; export LANG
+fi
+
+# Make sure IFS has a sensible default
+: ${IFS="
+"}
+
+if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then
+ $echo "$modename: not configured to build any kind of library" 1>&2
+ $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2
+ exit $EXIT_FAILURE
+fi
+
+# Global variables.
+mode=$default_mode
+nonopt=
+prev=
+prevopt=
+run=
+show="$echo"
+show_help=
+execute_dlfiles=
+lo2o="s/\\.lo\$/.${objext}/"
+o2lo="s/\\.${objext}\$/.lo/"
+
+#####################################
+# Shell function definitions:
+# This seems to be the best place for them
+
+# func_win32_libid arg
+# return the library type of file 'arg'
+#
+# Need a lot of goo to handle *both* DLLs and import libs
+# Has to be a shell function in order to 'eat' the argument
+# that is supplied when $file_magic_command is called.
+func_win32_libid () {
+ win32_libid_type="unknown"
+ win32_fileres=`file -L $1 2>/dev/null`
+ case $win32_fileres in
+ *ar\ archive\ import\ library*) # definitely import
+ win32_libid_type="x86 archive import"
+ ;;
+ *ar\ archive*) # could be an import, or static
+ if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | \
+ $EGREP -e 'file format pe-i386(.*architecture: i386)?' >/dev/null ; then
+ win32_nmres=`eval $NM -f posix -A $1 | \
+ sed -n -e '1,100{/ I /{x;/import/!{s/^/import/;h;p;};x;};}'`
+ if test "X$win32_nmres" = "Ximport" ; then
+ win32_libid_type="x86 archive import"
+ else
+ win32_libid_type="x86 archive static"
+ fi
+ fi
+ ;;
+ *DLL*)
+ win32_libid_type="x86 DLL"
+ ;;
+ *executable*) # but shell scripts are "executable" too...
+ case $win32_fileres in
+ *MS\ Windows\ PE\ Intel*)
+ win32_libid_type="x86 DLL"
+ ;;
+ esac
+ ;;
+ esac
+ $echo $win32_libid_type
+}
+
+
+# func_infer_tag arg
+# Infer tagged configuration to use if any are available and
+# if one wasn't chosen via the "--tag" command line option.
+# Only attempt this if the compiler in the base compile
+# command doesn't match the default compiler.
+# arg is usually of the form 'gcc ...'
+func_infer_tag () {
+ if test -n "$available_tags" && test -z "$tagname"; then
+ CC_quoted=
+ for arg in $CC; do
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ arg="\"$arg\""
+ ;;
+ esac
+ CC_quoted="$CC_quoted $arg"
+ done
+ case $@ in
+ # Blanks in the command may have been stripped by the calling shell,
+ # but not from the CC environment variable when configure was run.
+ " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$echo $CC_quoted` "* | "`$echo $CC_quoted` "*) ;;
+ # Blanks at the start of $base_compile will cause this to fail
+ # if we don't check for them as well.
+ *)
+ for z in $available_tags; do
+ if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then
+ # Evaluate the configuration.
+ eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`"
+ CC_quoted=
+ for arg in $CC; do
+ # Double-quote args containing other shell metacharacters.
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ arg="\"$arg\""
+ ;;
+ esac
+ CC_quoted="$CC_quoted $arg"
+ done
+ case "$@ " in
+ " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$echo $CC_quoted` "* | "`$echo $CC_quoted` "*)
+ # The compiler in the base compile command matches
+ # the one in the tagged configuration.
+ # Assume this is the tagged configuration we want.
+ tagname=$z
+ break
+ ;;
+ esac
+ fi
+ done
+ # If $tagname still isn't set, then no tagged configuration
+ # was found and let the user know that the "--tag" command
+ # line option must be used.
+ if test -z "$tagname"; then
+ $echo "$modename: unable to infer tagged configuration"
+ $echo "$modename: specify a tag with \`--tag'" 1>&2
+ exit $EXIT_FAILURE
+# else
+# $echo "$modename: using $tagname tagged configuration"
+ fi
+ ;;
+ esac
+ fi
+}
+# End of Shell function definitions
+#####################################
+
+# Darwin sucks
+eval std_shrext=\"$shrext_cmds\"
+
+# Parse our command line options once, thoroughly.
+while test "$#" -gt 0
+do
+ arg="$1"
+ shift
+
+ case $arg in
+ -*=*) optarg=`$echo "X$arg" | $Xsed -e 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) optarg= ;;
+ esac
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$prev"; then
+ case $prev in
+ execute_dlfiles)
+ execute_dlfiles="$execute_dlfiles $arg"
+ ;;
+ tag)
+ tagname="$arg"
+ preserve_args="${preserve_args}=$arg"
+
+ # Check whether tagname contains only valid characters
+ case $tagname in
+ *[!-_A-Za-z0-9,/]*)
+ $echo "$progname: invalid tag name: $tagname" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ esac
+
+ case $tagname in
+ CC)
+ # Don't test for the "default" C tag, as we know, it's there, but
+ # not specially marked.
+ ;;
+ *)
+ if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "$progpath" > /dev/null; then
+ taglist="$taglist $tagname"
+ # Evaluate the configuration.
+ eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$tagname'$/,/^# ### END LIBTOOL TAG CONFIG: '$tagname'$/p' < $progpath`"
+ else
+ $echo "$progname: ignoring unknown tag $tagname" 1>&2
+ fi
+ ;;
+ esac
+ ;;
+ *)
+ eval "$prev=\$arg"
+ ;;
+ esac
+
+ prev=
+ prevopt=
+ continue
+ fi
+
+ # Have we seen a non-optional argument yet?
+ case $arg in
+ --help)
+ show_help=yes
+ ;;
+
+ --version)
+ $echo "$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP"
+ $echo
+ $echo "Copyright (C) 2003 Free Software Foundation, Inc."
+ $echo "This is free software; see the source for copying conditions. There is NO"
+ $echo "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+ exit $EXIT_SUCCESS
+ ;;
+
+ --config)
+ ${SED} -e '1,/^# ### BEGIN LIBTOOL CONFIG/d' -e '/^# ### END LIBTOOL CONFIG/,$d' $progpath
+ # Now print the configurations for the tags.
+ for tagname in $taglist; do
+ ${SED} -n -e "/^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$/,/^# ### END LIBTOOL TAG CONFIG: $tagname$/p" < "$progpath"
+ done
+ exit $EXIT_SUCCESS
+ ;;
+
+ --debug)
+ $echo "$progname: enabling shell trace mode"
+ set -x
+ preserve_args="$preserve_args $arg"
+ ;;
+
+ --dry-run | -n)
+ run=:
+ ;;
+
+ --features)
+ $echo "host: $host"
+ if test "$build_libtool_libs" = yes; then
+ $echo "enable shared libraries"
+ else
+ $echo "disable shared libraries"
+ fi
+ if test "$build_old_libs" = yes; then
+ $echo "enable static libraries"
+ else
+ $echo "disable static libraries"
+ fi
+ exit $EXIT_SUCCESS
+ ;;
+
+ --finish) mode="finish" ;;
+
+ --mode) prevopt="--mode" prev=mode ;;
+ --mode=*) mode="$optarg" ;;
+
+ --preserve-dup-deps) duplicate_deps="yes" ;;
+
+ --quiet | --silent)
+ show=:
+ preserve_args="$preserve_args $arg"
+ ;;
+
+ --tag) prevopt="--tag" prev=tag ;;
+ --tag=*)
+ set tag "$optarg" ${1+"$@"}
+ shift
+ prev=tag
+ preserve_args="$preserve_args --tag"
+ ;;
+
+ -dlopen)
+ prevopt="-dlopen"
+ prev=execute_dlfiles
+ ;;
+
+ -*)
+ $echo "$modename: unrecognized option \`$arg'" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+
+ *)
+ nonopt="$arg"
+ break
+ ;;
+ esac
+done
+
+if test -n "$prevopt"; then
+ $echo "$modename: option \`$prevopt' requires an argument" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+fi
+
+# If this variable is set in any of the actions, the command in it
+# will be execed at the end. This prevents here-documents from being
+# left over by shells.
+exec_cmd=
+
+if test -z "$show_help"; then
+
+ # Infer the operation mode.
+ if test -z "$mode"; then
+ $echo "*** Warning: inferring the mode of operation is deprecated." 1>&2
+ $echo "*** Future versions of Libtool will require -mode=MODE be specified." 1>&2
+ case $nonopt in
+ *cc | cc* | *++ | gcc* | *-gcc* | g++* | xlc*)
+ mode=link
+ for arg
+ do
+ case $arg in
+ -c)
+ mode=compile
+ break
+ ;;
+ esac
+ done
+ ;;
+ *db | *dbx | *strace | *truss)
+ mode=execute
+ ;;
+ *install*|cp|mv)
+ mode=install
+ ;;
+ *rm)
+ mode=uninstall
+ ;;
+ *)
+ # If we have no mode, but dlfiles were specified, then do execute mode.
+ test -n "$execute_dlfiles" && mode=execute
+
+ # Just use the default operation mode.
+ if test -z "$mode"; then
+ if test -n "$nonopt"; then
+ $echo "$modename: warning: cannot infer operation mode from \`$nonopt'" 1>&2
+ else
+ $echo "$modename: warning: cannot infer operation mode without MODE-ARGS" 1>&2
+ fi
+ fi
+ ;;
+ esac
+ fi
+
+ # Only execute mode is allowed to have -dlopen flags.
+ if test -n "$execute_dlfiles" && test "$mode" != execute; then
+ $echo "$modename: unrecognized option \`-dlopen'" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ # Change the help message to a mode-specific one.
+ generic_help="$help"
+ help="Try \`$modename --help --mode=$mode' for more information."
+
+ # These modes are in order of execution frequency so that they run quickly.
+ case $mode in
+ # libtool compile mode
+ compile)
+ modename="$modename: compile"
+ # Get the compilation command and the source file.
+ base_compile=
+ srcfile="$nonopt" # always keep a non-empty value in "srcfile"
+ suppress_opt=yes
+ suppress_output=
+ arg_mode=normal
+ libobj=
+ later=
+
+ for arg
+ do
+ case "$arg_mode" in
+ arg )
+ # do not "continue". Instead, add this to base_compile
+ lastarg="$arg"
+ arg_mode=normal
+ ;;
+
+ target )
+ libobj="$arg"
+ arg_mode=normal
+ continue
+ ;;
+
+ normal )
+ # Accept any command-line options.
+ case $arg in
+ -o)
+ if test -n "$libobj" ; then
+ $echo "$modename: you cannot specify \`-o' more than once" 1>&2
+ exit $EXIT_FAILURE
+ fi
+ arg_mode=target
+ continue
+ ;;
+
+ -static | -prefer-pic | -prefer-non-pic)
+ later="$later $arg"
+ continue
+ ;;
+
+ -no-suppress)
+ suppress_opt=no
+ continue
+ ;;
+
+ -Xcompiler)
+ arg_mode=arg # the next one goes into the "base_compile" arg list
+ continue # The current "srcfile" will either be retained or
+ ;; # replaced later. I would guess that would be a bug.
+
+ -Wc,*)
+ args=`$echo "X$arg" | $Xsed -e "s/^-Wc,//"`
+ lastarg=
+ save_ifs="$IFS"; IFS=','
+ for arg in $args; do
+ IFS="$save_ifs"
+
+ # Double-quote args containing other shell metacharacters.
+ # Many Bourne shells cannot handle close brackets correctly
+ # in scan sets, so we specify it separately.
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ arg="\"$arg\""
+ ;;
+ esac
+ lastarg="$lastarg $arg"
+ done
+ IFS="$save_ifs"
+ lastarg=`$echo "X$lastarg" | $Xsed -e "s/^ //"`
+
+ # Add the arguments to base_compile.
+ base_compile="$base_compile $lastarg"
+ continue
+ ;;
+
+ * )
+ # Accept the current argument as the source file.
+ # The previous "srcfile" becomes the current argument.
+ #
+ lastarg="$srcfile"
+ srcfile="$arg"
+ ;;
+ esac # case $arg
+ ;;
+ esac # case $arg_mode
+
+ # Aesthetically quote the previous argument.
+ lastarg=`$echo "X$lastarg" | $Xsed -e "$sed_quote_subst"`
+
+ case $lastarg in
+ # Double-quote args containing other shell metacharacters.
+ # Many Bourne shells cannot handle close brackets correctly
+ # in scan sets, so we specify it separately.
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ lastarg="\"$lastarg\""
+ ;;
+ esac
+
+ base_compile="$base_compile $lastarg"
+ done # for arg
+
+ case $arg_mode in
+ arg)
+ $echo "$modename: you must specify an argument for -Xcompile"
+ exit $EXIT_FAILURE
+ ;;
+ target)
+ $echo "$modename: you must specify a target with \`-o'" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ *)
+ # Get the name of the library object.
+ [ -z "$libobj" ] && libobj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%'`
+ ;;
+ esac
+
+ # Recognize several different file suffixes.
+ # If the user specifies -o file.o, it is replaced with file.lo
+ xform='[cCFSifmso]'
+ case $libobj in
+ *.ada) xform=ada ;;
+ *.adb) xform=adb ;;
+ *.ads) xform=ads ;;
+ *.asm) xform=asm ;;
+ *.c++) xform=c++ ;;
+ *.cc) xform=cc ;;
+ *.ii) xform=ii ;;
+ *.class) xform=class ;;
+ *.cpp) xform=cpp ;;
+ *.cxx) xform=cxx ;;
+ *.f90) xform=f90 ;;
+ *.for) xform=for ;;
+ *.java) xform=java ;;
+ esac
+
+ libobj=`$echo "X$libobj" | $Xsed -e "s/\.$xform$/.lo/"`
+
+ case $libobj in
+ *.lo) obj=`$echo "X$libobj" | $Xsed -e "$lo2o"` ;;
+ *)
+ $echo "$modename: cannot determine name of library object from \`$libobj'" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ esac
+
+ func_infer_tag $base_compile
+
+ for arg in $later; do
+ case $arg in
+ -static)
+ build_old_libs=yes
+ continue
+ ;;
+
+ -prefer-pic)
+ pic_mode=yes
+ continue
+ ;;
+
+ -prefer-non-pic)
+ pic_mode=no
+ continue
+ ;;
+ esac
+ done
+
+ objname=`$echo "X$obj" | $Xsed -e 's%^.*/%%'`
+ xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$xdir" = "X$obj"; then
+ xdir=
+ else
+ xdir=$xdir/
+ fi
+ lobj=${xdir}$objdir/$objname
+
+ if test -z "$base_compile"; then
+ $echo "$modename: you must specify a compilation command" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ # Delete any leftover library objects.
+ if test "$build_old_libs" = yes; then
+ removelist="$obj $lobj $libobj ${libobj}T"
+ else
+ removelist="$lobj $libobj ${libobj}T"
+ fi
+
+ $run $rm $removelist
+ trap "$run $rm $removelist; exit $EXIT_FAILURE" 1 2 15
+
+ # On Cygwin there's no "real" PIC flag so we must build both object types
+ case $host_os in
+ cygwin* | mingw* | pw32* | os2*)
+ pic_mode=default
+ ;;
+ esac
+ if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then
+ # non-PIC code in shared libraries is not supported
+ pic_mode=default
+ fi
+
+ # Calculate the filename of the output object if compiler does
+ # not support -o with -c
+ if test "$compiler_c_o" = no; then
+ output_obj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext}
+ lockfile="$output_obj.lock"
+ removelist="$removelist $output_obj $lockfile"
+ trap "$run $rm $removelist; exit $EXIT_FAILURE" 1 2 15
+ else
+ output_obj=
+ need_locks=no
+ lockfile=
+ fi
+
+ # Lock this critical section if it is needed
+ # We use this script file to make the link, it avoids creating a new file
+ if test "$need_locks" = yes; then
+ until $run ln "$progpath" "$lockfile" 2>/dev/null; do
+ $show "Waiting for $lockfile to be removed"
+ sleep 2
+ done
+ elif test "$need_locks" = warn; then
+ if test -f "$lockfile"; then
+ $echo "\
+*** ERROR, $lockfile exists and contains:
+`cat $lockfile 2>/dev/null`
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together. If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+ $run $rm $removelist
+ exit $EXIT_FAILURE
+ fi
+ $echo $srcfile > "$lockfile"
+ fi
+
+ if test -n "$fix_srcfile_path"; then
+ eval srcfile=\"$fix_srcfile_path\"
+ fi
+
+ $run $rm "$libobj" "${libobj}T"
+
+ # Create a libtool object file (analogous to a ".la" file),
+ # but don't create it if we're doing a dry run.
+ test -z "$run" && cat > ${libobj}T <<EOF
+# $libobj - a libtool object file
+# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+EOF
+
+ # Only build a PIC object if we are building libtool libraries.
+ if test "$build_libtool_libs" = yes; then
+ # Without this assignment, base_compile gets emptied.
+ fbsd_hideous_sh_bug=$base_compile
+
+ if test "$pic_mode" != no; then
+ command="$base_compile $srcfile $pic_flag"
+ else
+ # Don't build PIC code
+ command="$base_compile $srcfile"
+ fi
+
+ if test ! -d "${xdir}$objdir"; then
+ $show "$mkdir ${xdir}$objdir"
+ $run $mkdir ${xdir}$objdir
+ status=$?
+ if test "$status" -ne 0 && test ! -d "${xdir}$objdir"; then
+ exit $status
+ fi
+ fi
+
+ if test -z "$output_obj"; then
+ # Place PIC objects in $objdir
+ command="$command -o $lobj"
+ fi
+
+ $run $rm "$lobj" "$output_obj"
+
+ $show "$command"
+ if $run eval "$command"; then :
+ else
+ test -n "$output_obj" && $run $rm $removelist
+ exit $EXIT_FAILURE
+ fi
+
+ if test "$need_locks" = warn &&
+ test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+ $echo "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together. If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+ $run $rm $removelist
+ exit $EXIT_FAILURE
+ fi
+
+ # Just move the object if needed, then go on to compile the next one
+ if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then
+ $show "$mv $output_obj $lobj"
+ if $run $mv $output_obj $lobj; then :
+ else
+ error=$?
+ $run $rm $removelist
+ exit $error
+ fi
+ fi
+
+ # Append the name of the PIC object to the libtool object file.
+ test -z "$run" && cat >> ${libobj}T <<EOF
+pic_object='$objdir/$objname'
+
+EOF
+
+ # Allow error messages only from the first compilation.
+ if test "$suppress_opt" = yes; then
+ suppress_output=' >/dev/null 2>&1'
+ fi
+ else
+ # No PIC object so indicate it doesn't exist in the libtool
+ # object file.
+ test -z "$run" && cat >> ${libobj}T <<EOF
+pic_object=none
+
+EOF
+ fi
+
+ # Only build a position-dependent object if we build old libraries.
+ if test "$build_old_libs" = yes; then
+ if test "$pic_mode" != yes; then
+ # Don't build PIC code
+ command="$base_compile $srcfile"
+ else
+ command="$base_compile $srcfile $pic_flag"
+ fi
+ if test "$compiler_c_o" = yes; then
+ command="$command -o $obj"
+ fi
+
+ # Suppress compiler output if we already did a PIC compilation.
+ command="$command$suppress_output"
+ $run $rm "$obj" "$output_obj"
+ $show "$command"
+ if $run eval "$command"; then :
+ else
+ $run $rm $removelist
+ exit $EXIT_FAILURE
+ fi
+
+ if test "$need_locks" = warn &&
+ test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+ $echo "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together. If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+ $run $rm $removelist
+ exit $EXIT_FAILURE
+ fi
+
+ # Just move the object if needed
+ if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then
+ $show "$mv $output_obj $obj"
+ if $run $mv $output_obj $obj; then :
+ else
+ error=$?
+ $run $rm $removelist
+ exit $error
+ fi
+ fi
+
+ # Append the name of the non-PIC object the libtool object file.
+ # Only append if the libtool object file exists.
+ test -z "$run" && cat >> ${libobj}T <<EOF
+# Name of the non-PIC object.
+non_pic_object='$objname'
+
+EOF
+ else
+ # Append the name of the non-PIC object the libtool object file.
+ # Only append if the libtool object file exists.
+ test -z "$run" && cat >> ${libobj}T <<EOF
+# Name of the non-PIC object.
+non_pic_object=none
+
+EOF
+ fi
+
+ $run $mv "${libobj}T" "${libobj}"
+
+ # Unlock the critical section if it was locked
+ if test "$need_locks" != no; then
+ $run $rm "$lockfile"
+ fi
+
+ exit $EXIT_SUCCESS
+ ;;
+
+ # libtool link mode
+ link | relink)
+ modename="$modename: link"
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
+ # It is impossible to link a dll without this setting, and
+ # we shouldn't force the makefile maintainer to figure out
+ # which system we are compiling for in order to pass an extra
+ # flag for every libtool invocation.
+ # allow_undefined=no
+
+ # FIXME: Unfortunately, there are problems with the above when trying
+ # to make a dll which has undefined symbols, in which case not
+ # even a static library is built. For now, we need to specify
+ # -no-undefined on the libtool link line when we can be certain
+ # that all symbols are satisfied, otherwise we get a static library.
+ allow_undefined=yes
+ ;;
+ *)
+ allow_undefined=yes
+ ;;
+ esac
+ libtool_args="$nonopt"
+ base_compile="$nonopt $@"
+ compile_command="$nonopt"
+ finalize_command="$nonopt"
+
+ compile_rpath=
+ finalize_rpath=
+ compile_shlibpath=
+ finalize_shlibpath=
+ convenience=
+ old_convenience=
+ deplibs=
+ old_deplibs=
+ compiler_flags=
+ linker_flags=
+ dllsearchpath=
+ lib_search_path=`pwd`
+ inst_prefix_dir=
+
+ avoid_version=no
+ dlfiles=
+ dlprefiles=
+ dlself=no
+ export_dynamic=no
+ export_symbols=
+ export_symbols_regex=
+ generated=
+ libobjs=
+ ltlibs=
+ module=no
+ no_install=no
+ objs=
+ non_pic_objects=
+ precious_files_regex=
+ prefer_static_libs=no
+ preload=no
+ prev=
+ prevarg=
+ release=
+ rpath=
+ xrpath=
+ perm_rpath=
+ temp_rpath=
+ thread_safe=no
+ vinfo=
+ vinfo_number=no
+
+ func_infer_tag $base_compile
+
+ # We need to know -static, to get the right output filenames.
+ for arg
+ do
+ case $arg in
+ -all-static | -static)
+ if test "X$arg" = "X-all-static"; then
+ if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then
+ $echo "$modename: warning: complete static linking is impossible in this configuration" 1>&2
+ fi
+ if test -n "$link_static_flag"; then
+ dlopen_self=$dlopen_self_static
+ fi
+ else
+ if test -z "$pic_flag" && test -n "$link_static_flag"; then
+ dlopen_self=$dlopen_self_static
+ fi
+ fi
+ build_libtool_libs=no
+ build_old_libs=yes
+ prefer_static_libs=yes
+ break
+ ;;
+ esac
+ done
+
+ # See if our shared archives depend on static archives.
+ test -n "$old_archive_from_new_cmds" && build_old_libs=yes
+
+ # Go through the arguments, transforming them on the way.
+ while test "$#" -gt 0; do
+ arg="$1"
+ shift
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ qarg=\"`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`\" ### testsuite: skip nested quoting test
+ ;;
+ *) qarg=$arg ;;
+ esac
+ libtool_args="$libtool_args $qarg"
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$prev"; then
+ case $prev in
+ output)
+ compile_command="$compile_command @OUTPUT@"
+ finalize_command="$finalize_command @OUTPUT@"
+ ;;
+ esac
+
+ case $prev in
+ dlfiles|dlprefiles)
+ if test "$preload" = no; then
+ # Add the symbol object into the linking commands.
+ compile_command="$compile_command @SYMFILE@"
+ finalize_command="$finalize_command @SYMFILE@"
+ preload=yes
+ fi
+ case $arg in
+ *.la | *.lo) ;; # We handle these cases below.
+ force)
+ if test "$dlself" = no; then
+ dlself=needless
+ export_dynamic=yes
+ fi
+ prev=
+ continue
+ ;;
+ self)
+ if test "$prev" = dlprefiles; then
+ dlself=yes
+ elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then
+ dlself=yes
+ else
+ dlself=needless
+ export_dynamic=yes
+ fi
+ prev=
+ continue
+ ;;
+ *)
+ if test "$prev" = dlfiles; then
+ dlfiles="$dlfiles $arg"
+ else
+ dlprefiles="$dlprefiles $arg"
+ fi
+ prev=
+ continue
+ ;;
+ esac
+ ;;
+ expsyms)
+ export_symbols="$arg"
+ if test ! -f "$arg"; then
+ $echo "$modename: symbol file \`$arg' does not exist"
+ exit $EXIT_FAILURE
+ fi
+ prev=
+ continue
+ ;;
+ expsyms_regex)
+ export_symbols_regex="$arg"
+ prev=
+ continue
+ ;;
+ inst_prefix)
+ inst_prefix_dir="$arg"
+ prev=
+ continue
+ ;;
+ precious_regex)
+ precious_files_regex="$arg"
+ prev=
+ continue
+ ;;
+ release)
+ release="-$arg"
+ prev=
+ continue
+ ;;
+ objectlist)
+ if test -f "$arg"; then
+ save_arg=$arg
+ moreargs=
+ for fil in `cat $save_arg`
+ do
+# moreargs="$moreargs $fil"
+ arg=$fil
+ # A libtool-controlled object.
+
+ # Check to see that this really is a libtool object.
+ if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+ pic_object=
+ non_pic_object=
+
+ # Read the .lo file
+ # If there is no directory component, then add one.
+ case $arg in
+ */* | *\\*) . $arg ;;
+ *) . ./$arg ;;
+ esac
+
+ if test -z "$pic_object" || \
+ test -z "$non_pic_object" ||
+ test "$pic_object" = none && \
+ test "$non_pic_object" = none; then
+ $echo "$modename: cannot find name of object for \`$arg'" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ # Extract subdirectory from the argument.
+ xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$xdir" = "X$arg"; then
+ xdir=
+ else
+ xdir="$xdir/"
+ fi
+
+ if test "$pic_object" != none; then
+ # Prepend the subdirectory the object is found in.
+ pic_object="$xdir$pic_object"
+
+ if test "$prev" = dlfiles; then
+ if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+ dlfiles="$dlfiles $pic_object"
+ prev=
+ continue
+ else
+ # If libtool objects are unsupported, then we need to preload.
+ prev=dlprefiles
+ fi
+ fi
+
+ # CHECK ME: I think I busted this. -Ossama
+ if test "$prev" = dlprefiles; then
+ # Preload the old-style object.
+ dlprefiles="$dlprefiles $pic_object"
+ prev=
+ fi
+
+ # A PIC object.
+ libobjs="$libobjs $pic_object"
+ arg="$pic_object"
+ fi
+
+ # Non-PIC object.
+ if test "$non_pic_object" != none; then
+ # Prepend the subdirectory the object is found in.
+ non_pic_object="$xdir$non_pic_object"
+
+ # A standard non-PIC object
+ non_pic_objects="$non_pic_objects $non_pic_object"
+ if test -z "$pic_object" || test "$pic_object" = none ; then
+ arg="$non_pic_object"
+ fi
+ fi
+ else
+ # Only an error if not doing a dry-run.
+ if test -z "$run"; then
+ $echo "$modename: \`$arg' is not a valid libtool object" 1>&2
+ exit $EXIT_FAILURE
+ else
+ # Dry-run case.
+
+ # Extract subdirectory from the argument.
+ xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$xdir" = "X$arg"; then
+ xdir=
+ else
+ xdir="$xdir/"
+ fi
+
+ pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"`
+ non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"`
+ libobjs="$libobjs $pic_object"
+ non_pic_objects="$non_pic_objects $non_pic_object"
+ fi
+ fi
+ done
+ else
+ $echo "$modename: link input file \`$save_arg' does not exist"
+ exit $EXIT_FAILURE
+ fi
+ arg=$save_arg
+ prev=
+ continue
+ ;;
+ rpath | xrpath)
+ # We need an absolute path.
+ case $arg in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ $echo "$modename: only absolute run-paths are allowed" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ esac
+ if test "$prev" = rpath; then
+ case "$rpath " in
+ *" $arg "*) ;;
+ *) rpath="$rpath $arg" ;;
+ esac
+ else
+ case "$xrpath " in
+ *" $arg "*) ;;
+ *) xrpath="$xrpath $arg" ;;
+ esac
+ fi
+ prev=
+ continue
+ ;;
+ xcompiler)
+ compiler_flags="$compiler_flags $qarg"
+ prev=
+ compile_command="$compile_command $qarg"
+ finalize_command="$finalize_command $qarg"
+ continue
+ ;;
+ xlinker)
+ linker_flags="$linker_flags $qarg"
+ compiler_flags="$compiler_flags $wl$qarg"
+ prev=
+ compile_command="$compile_command $wl$qarg"
+ finalize_command="$finalize_command $wl$qarg"
+ continue
+ ;;
+ xcclinker)
+ linker_flags="$linker_flags $qarg"
+ compiler_flags="$compiler_flags $qarg"
+ prev=
+ compile_command="$compile_command $qarg"
+ finalize_command="$finalize_command $qarg"
+ continue
+ ;;
+ shrext)
+ shrext_cmds="$arg"
+ prev=
+ continue
+ ;;
+ *)
+ eval "$prev=\"\$arg\""
+ prev=
+ continue
+ ;;
+ esac
+ fi # test -n "$prev"
+
+ prevarg="$arg"
+
+ case $arg in
+ -all-static)
+ if test -n "$link_static_flag"; then
+ compile_command="$compile_command $link_static_flag"
+ finalize_command="$finalize_command $link_static_flag"
+ fi
+ continue
+ ;;
+
+ -allow-undefined)
+ # FIXME: remove this flag sometime in the future.
+ $echo "$modename: \`-allow-undefined' is deprecated because it is the default" 1>&2
+ continue
+ ;;
+
+ -avoid-version)
+ avoid_version=yes
+ continue
+ ;;
+
+ -dlopen)
+ prev=dlfiles
+ continue
+ ;;
+
+ -dlpreopen)
+ prev=dlprefiles
+ continue
+ ;;
+
+ -export-dynamic)
+ export_dynamic=yes
+ continue
+ ;;
+
+ -export-symbols | -export-symbols-regex)
+ if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
+ $echo "$modename: more than one -exported-symbols argument is not allowed"
+ exit $EXIT_FAILURE
+ fi
+ if test "X$arg" = "X-export-symbols"; then
+ prev=expsyms
+ else
+ prev=expsyms_regex
+ fi
+ continue
+ ;;
+
+ -inst-prefix-dir)
+ prev=inst_prefix
+ continue
+ ;;
+
+ # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:*
+ # so, if we see these flags be careful not to treat them like -L
+ -L[A-Z][A-Z]*:*)
+ case $with_gcc/$host in
+ no/*-*-irix* | /*-*-irix*)
+ compile_command="$compile_command $arg"
+ finalize_command="$finalize_command $arg"
+ ;;
+ esac
+ continue
+ ;;
+
+ -L*)
+ dir=`$echo "X$arg" | $Xsed -e 's/^-L//'`
+ # We need an absolute path.
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ absdir=`cd "$dir" && pwd`
+ if test -z "$absdir"; then
+ $echo "$modename: cannot determine absolute directory name of \`$dir'" 1>&2
+ exit $EXIT_FAILURE
+ fi
+ dir="$absdir"
+ ;;
+ esac
+ case "$deplibs " in
+ *" -L$dir "*) ;;
+ *)
+ deplibs="$deplibs -L$dir"
+ lib_search_path="$lib_search_path $dir"
+ ;;
+ esac
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
+ case :$dllsearchpath: in
+ *":$dir:"*) ;;
+ *) dllsearchpath="$dllsearchpath:$dir";;
+ esac
+ ;;
+ esac
+ continue
+ ;;
+
+ -l*)
+ if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then
+ case $host in
+ *-*-cygwin* | *-*-pw32* | *-*-beos*)
+ # These systems don't actually have a C or math library (as such)
+ continue
+ ;;
+ *-*-mingw* | *-*-os2*)
+ # These systems don't actually have a C library (as such)
+ test "X$arg" = "X-lc" && continue
+ ;;
+ *-*-openbsd* | *-*-freebsd*)
+ # Do not include libc due to us having libc/libc_r.
+ test "X$arg" = "X-lc" && continue
+ ;;
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # Rhapsody C and math libraries are in the System framework
+ deplibs="$deplibs -framework System"
+ continue
+ esac
+ elif test "X$arg" = "X-lc_r"; then
+ case $host in
+ *-*-openbsd* | *-*-freebsd*)
+ # Do not include libc_r directly, use -pthread flag.
+ continue
+ ;;
+ esac
+ fi
+ deplibs="$deplibs $arg"
+ continue
+ ;;
+
+ -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe)
+ deplibs="$deplibs $arg"
+ continue
+ ;;
+
+ -module)
+ module=yes
+ continue
+ ;;
+
+ # gcc -m* arguments should be passed to the linker via $compiler_flags
+ # in order to pass architecture information to the linker
+ # (e.g. 32 vs 64-bit). This may also be accomplished via -Wl,-mfoo
+ # but this is not reliable with gcc because gcc may use -mfoo to
+ # select a different linker, different libraries, etc, while
+ # -Wl,-mfoo simply passes -mfoo to the linker.
+ -m*)
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
+ arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ arg="\"$arg\""
+ ;;
+ esac
+ compile_command="$compile_command $arg"
+ finalize_command="$finalize_command $arg"
+ if test "$with_gcc" = "yes" ; then
+ compiler_flags="$compiler_flags $arg"
+ fi
+ continue
+ ;;
+
+ -shrext)
+ prev=shrext
+ continue
+ ;;
+
+ -no-fast-install)
+ fast_install=no
+ continue
+ ;;
+
+ -no-install)
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
+ # The PATH hackery in wrapper scripts is required on Windows
+ # in order for the loader to find any dlls it needs.
+ $echo "$modename: warning: \`-no-install' is ignored for $host" 1>&2
+ $echo "$modename: warning: assuming \`-no-fast-install' instead" 1>&2
+ fast_install=no
+ ;;
+ *) no_install=yes ;;
+ esac
+ continue
+ ;;
+
+ -no-undefined)
+ allow_undefined=no
+ continue
+ ;;
+
+ -objectlist)
+ prev=objectlist
+ continue
+ ;;
+
+ -o) prev=output ;;
+
+ -precious-files-regex)
+ prev=precious_regex
+ continue
+ ;;
+
+ -release)
+ prev=release
+ continue
+ ;;
+
+ -rpath)
+ prev=rpath
+ continue
+ ;;
+
+ -R)
+ prev=xrpath
+ continue
+ ;;
+
+ -R*)
+ dir=`$echo "X$arg" | $Xsed -e 's/^-R//'`
+ # We need an absolute path.
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ $echo "$modename: only absolute run-paths are allowed" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ esac
+ case "$xrpath " in
+ *" $dir "*) ;;
+ *) xrpath="$xrpath $dir" ;;
+ esac
+ continue
+ ;;
+
+ -static)
+ # The effects of -static are defined in a previous loop.
+ # We used to do the same as -all-static on platforms that
+ # didn't have a PIC flag, but the assumption that the effects
+ # would be equivalent was wrong. It would break on at least
+ # Digital Unix and AIX.
+ continue
+ ;;
+
+ -thread-safe)
+ thread_safe=yes
+ continue
+ ;;
+
+ -version-info)
+ prev=vinfo
+ continue
+ ;;
+ -version-number)
+ prev=vinfo
+ vinfo_number=yes
+ continue
+ ;;
+
+ -Wc,*)
+ args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wc,//'`
+ arg=
+ save_ifs="$IFS"; IFS=','
+ for flag in $args; do
+ IFS="$save_ifs"
+ case $flag in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ flag="\"$flag\""
+ ;;
+ esac
+ arg="$arg $wl$flag"
+ compiler_flags="$compiler_flags $flag"
+ done
+ IFS="$save_ifs"
+ arg=`$echo "X$arg" | $Xsed -e "s/^ //"`
+ ;;
+
+ -Wl,*)
+ args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wl,//'`
+ arg=
+ save_ifs="$IFS"; IFS=','
+ for flag in $args; do
+ IFS="$save_ifs"
+ case $flag in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ flag="\"$flag\""
+ ;;
+ esac
+ arg="$arg $wl$flag"
+ compiler_flags="$compiler_flags $wl$flag"
+ linker_flags="$linker_flags $flag"
+ done
+ IFS="$save_ifs"
+ arg=`$echo "X$arg" | $Xsed -e "s/^ //"`
+ ;;
+
+ -Xcompiler)
+ prev=xcompiler
+ continue
+ ;;
+
+ -Xlinker)
+ prev=xlinker
+ continue
+ ;;
+
+ -XCClinker)
+ prev=xcclinker
+ continue
+ ;;
+
+ # Some other compiler flag.
+ -* | +*)
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
+ arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ arg="\"$arg\""
+ ;;
+ esac
+ ;;
+
+ *.$objext)
+ # A standard object.
+ objs="$objs $arg"
+ ;;
+
+ *.lo)
+ # A libtool-controlled object.
+
+ # Check to see that this really is a libtool object.
+ if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+ pic_object=
+ non_pic_object=
+
+ # Read the .lo file
+ # If there is no directory component, then add one.
+ case $arg in
+ */* | *\\*) . $arg ;;
+ *) . ./$arg ;;
+ esac
+
+ if test -z "$pic_object" || \
+ test -z "$non_pic_object" ||
+ test "$pic_object" = none && \
+ test "$non_pic_object" = none; then
+ $echo "$modename: cannot find name of object for \`$arg'" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ # Extract subdirectory from the argument.
+ xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$xdir" = "X$arg"; then
+ xdir=
+ else
+ xdir="$xdir/"
+ fi
+
+ if test "$pic_object" != none; then
+ # Prepend the subdirectory the object is found in.
+ pic_object="$xdir$pic_object"
+
+ if test "$prev" = dlfiles; then
+ if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+ dlfiles="$dlfiles $pic_object"
+ prev=
+ continue
+ else
+ # If libtool objects are unsupported, then we need to preload.
+ prev=dlprefiles
+ fi
+ fi
+
+ # CHECK ME: I think I busted this. -Ossama
+ if test "$prev" = dlprefiles; then
+ # Preload the old-style object.
+ dlprefiles="$dlprefiles $pic_object"
+ prev=
+ fi
+
+ # A PIC object.
+ libobjs="$libobjs $pic_object"
+ arg="$pic_object"
+ fi
+
+ # Non-PIC object.
+ if test "$non_pic_object" != none; then
+ # Prepend the subdirectory the object is found in.
+ non_pic_object="$xdir$non_pic_object"
+
+ # A standard non-PIC object
+ non_pic_objects="$non_pic_objects $non_pic_object"
+ if test -z "$pic_object" || test "$pic_object" = none ; then
+ arg="$non_pic_object"
+ fi
+ fi
+ else
+ # Only an error if not doing a dry-run.
+ if test -z "$run"; then
+ $echo "$modename: \`$arg' is not a valid libtool object" 1>&2
+ exit $EXIT_FAILURE
+ else
+ # Dry-run case.
+
+ # Extract subdirectory from the argument.
+ xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$xdir" = "X$arg"; then
+ xdir=
+ else
+ xdir="$xdir/"
+ fi
+
+ pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"`
+ non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"`
+ libobjs="$libobjs $pic_object"
+ non_pic_objects="$non_pic_objects $non_pic_object"
+ fi
+ fi
+ ;;
+
+ *.$libext)
+ # An archive.
+ deplibs="$deplibs $arg"
+ old_deplibs="$old_deplibs $arg"
+ continue
+ ;;
+
+ *.la)
+ # A libtool-controlled library.
+
+ if test "$prev" = dlfiles; then
+ # This library was specified with -dlopen.
+ dlfiles="$dlfiles $arg"
+ prev=
+ elif test "$prev" = dlprefiles; then
+ # The library was specified with -dlpreopen.
+ dlprefiles="$dlprefiles $arg"
+ prev=
+ else
+ deplibs="$deplibs $arg"
+ fi
+ continue
+ ;;
+
+ # Some other compiler argument.
+ *)
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
+ arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ arg="\"$arg\""
+ ;;
+ esac
+ ;;
+ esac # arg
+
+ # Now actually substitute the argument into the commands.
+ if test -n "$arg"; then
+ compile_command="$compile_command $arg"
+ finalize_command="$finalize_command $arg"
+ fi
+ done # argument parsing loop
+
+ if test -n "$prev"; then
+ $echo "$modename: the \`$prevarg' option requires an argument" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then
+ eval arg=\"$export_dynamic_flag_spec\"
+ compile_command="$compile_command $arg"
+ finalize_command="$finalize_command $arg"
+ fi
+
+ oldlibs=
+ # calculate the name of the file, without its directory
+ outputname=`$echo "X$output" | $Xsed -e 's%^.*/%%'`
+ libobjs_save="$libobjs"
+
+ if test -n "$shlibpath_var"; then
+ # get the directories listed in $shlibpath_var
+ eval shlib_search_path=\`\$echo \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\`
+ else
+ shlib_search_path=
+ fi
+ eval sys_lib_search_path=\"$sys_lib_search_path_spec\"
+ eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\"
+
+ output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$output_objdir" = "X$output"; then
+ output_objdir="$objdir"
+ else
+ output_objdir="$output_objdir/$objdir"
+ fi
+ # Create the object directory.
+ if test ! -d "$output_objdir"; then
+ $show "$mkdir $output_objdir"
+ $run $mkdir $output_objdir
+ status=$?
+ if test "$status" -ne 0 && test ! -d "$output_objdir"; then
+ exit $status
+ fi
+ fi
+
+ # Determine the type of output
+ case $output in
+ "")
+ $echo "$modename: you must specify an output file" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ *.$libext) linkmode=oldlib ;;
+ *.lo | *.$objext) linkmode=obj ;;
+ *.la) linkmode=lib ;;
+ *) linkmode=prog ;; # Anything else should be a program.
+ esac
+
+ case $host in
+ *cygwin* | *mingw* | *pw32*)
+ # don't eliminate duplications in $postdeps and $predeps
+ duplicate_compiler_generated_deps=yes
+ ;;
+ *)
+ duplicate_compiler_generated_deps=$duplicate_deps
+ ;;
+ esac
+ specialdeplibs=
+
+ libs=
+ # Find all interdependent deplibs by searching for libraries
+ # that are linked more than once (e.g. -la -lb -la)
+ for deplib in $deplibs; do
+ if test "X$duplicate_deps" = "Xyes" ; then
+ case "$libs " in
+ *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+ esac
+ fi
+ libs="$libs $deplib"
+ done
+
+ if test "$linkmode" = lib; then
+ libs="$predeps $libs $compiler_lib_search_path $postdeps"
+
+ # Compute libraries that are listed more than once in $predeps
+ # $postdeps and mark them as special (i.e., whose duplicates are
+ # not to be eliminated).
+ pre_post_deps=
+ if test "X$duplicate_compiler_generated_deps" = "Xyes" ; then
+ for pre_post_dep in $predeps $postdeps; do
+ case "$pre_post_deps " in
+ *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;;
+ esac
+ pre_post_deps="$pre_post_deps $pre_post_dep"
+ done
+ fi
+ pre_post_deps=
+ fi
+
+ deplibs=
+ newdependency_libs=
+ newlib_search_path=
+ need_relink=no # whether we're linking any uninstalled libtool libraries
+ notinst_deplibs= # not-installed libtool libraries
+ notinst_path= # paths that contain not-installed libtool libraries
+ case $linkmode in
+ lib)
+ passes="conv link"
+ for file in $dlfiles $dlprefiles; do
+ case $file in
+ *.la) ;;
+ *)
+ $echo "$modename: libraries can \`-dlopen' only libtool libraries: $file" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ esac
+ done
+ ;;
+ prog)
+ compile_deplibs=
+ finalize_deplibs=
+ alldeplibs=no
+ newdlfiles=
+ newdlprefiles=
+ passes="conv scan dlopen dlpreopen link"
+ ;;
+ *) passes="conv"
+ ;;
+ esac
+ for pass in $passes; do
+ if test "$linkmode,$pass" = "lib,link" ||
+ test "$linkmode,$pass" = "prog,scan"; then
+ libs="$deplibs"
+ deplibs=
+ fi
+ if test "$linkmode" = prog; then
+ case $pass in
+ dlopen) libs="$dlfiles" ;;
+ dlpreopen) libs="$dlprefiles" ;;
+ link) libs="$deplibs %DEPLIBS% $dependency_libs" ;;
+ esac
+ fi
+ if test "$pass" = dlopen; then
+ # Collect dlpreopened libraries
+ save_deplibs="$deplibs"
+ deplibs=
+ fi
+ for deplib in $libs; do
+ lib=
+ found=no
+ case $deplib in
+ -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe)
+ if test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ deplibs="$deplib $deplibs"
+ fi
+ continue
+ ;;
+ -l*)
+ if test "$linkmode" != lib && test "$linkmode" != prog; then
+ $echo "$modename: warning: \`-l' is ignored for archives/objects" 1>&2
+ continue
+ fi
+ if test "$pass" = conv; then
+ deplibs="$deplib $deplibs"
+ continue
+ fi
+ name=`$echo "X$deplib" | $Xsed -e 's/^-l//'`
+ for searchdir in $newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path; do
+ for search_ext in .la $std_shrext .so .a; do
+ # Search the libtool library
+ lib="$searchdir/lib${name}${search_ext}"
+ if test -f "$lib"; then
+ if test "$search_ext" = ".la"; then
+ found=yes
+ else
+ found=no
+ fi
+ break 2
+ fi
+ done
+ done
+ if test "$found" != yes; then
+ # deplib doesn't seem to be a libtool library
+ if test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ deplibs="$deplib $deplibs"
+ test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
+ fi
+ continue
+ else # deplib is a libtool library
+ # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib,
+ # We need to do some special things here, and not later.
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $deplib "*)
+ if (${SED} -e '2q' $lib |
+ grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+ library_names=
+ old_library=
+ case $lib in
+ */* | *\\*) . $lib ;;
+ *) . ./$lib ;;
+ esac
+ for l in $old_library $library_names; do
+ ll="$l"
+ done
+ if test "X$ll" = "X$old_library" ; then # only static version available
+ found=no
+ ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'`
+ test "X$ladir" = "X$lib" && ladir="."
+ lib=$ladir/$old_library
+ if test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ deplibs="$deplib $deplibs"
+ test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
+ fi
+ continue
+ fi
+ fi
+ ;;
+ *) ;;
+ esac
+ fi
+ fi
+ ;; # -l
+ -L*)
+ case $linkmode in
+ lib)
+ deplibs="$deplib $deplibs"
+ test "$pass" = conv && continue
+ newdependency_libs="$deplib $newdependency_libs"
+ newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`
+ ;;
+ prog)
+ if test "$pass" = conv; then
+ deplibs="$deplib $deplibs"
+ continue
+ fi
+ if test "$pass" = scan; then
+ deplibs="$deplib $deplibs"
+ else
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ fi
+ newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`
+ ;;
+ *)
+ $echo "$modename: warning: \`-L' is ignored for archives/objects" 1>&2
+ ;;
+ esac # linkmode
+ continue
+ ;; # -L
+ -R*)
+ if test "$pass" = link; then
+ dir=`$echo "X$deplib" | $Xsed -e 's/^-R//'`
+ # Make sure the xrpath contains only unique directories.
+ case "$xrpath " in
+ *" $dir "*) ;;
+ *) xrpath="$xrpath $dir" ;;
+ esac
+ fi
+ deplibs="$deplib $deplibs"
+ continue
+ ;;
+ *.la) lib="$deplib" ;;
+ *.$libext)
+ if test "$pass" = conv; then
+ deplibs="$deplib $deplibs"
+ continue
+ fi
+ case $linkmode in
+ lib)
+ if test "$deplibs_check_method" != pass_all; then
+ $echo
+ $echo "*** Warning: Trying to link with static lib archive $deplib."
+ $echo "*** I have the capability to make that library automatically link in when"
+ $echo "*** you link to this library. But I can only do this if you have a"
+ $echo "*** shared version of the library, which you do not appear to have"
+ $echo "*** because the file extensions .$libext of this argument makes me believe"
+ $echo "*** that it is just a static archive that I should not used here."
+ else
+ $echo
+ $echo "*** Warning: Linking the shared library $output against the"
+ $echo "*** static library $deplib is not portable!"
+ deplibs="$deplib $deplibs"
+ fi
+ continue
+ ;;
+ prog)
+ if test "$pass" != link; then
+ deplibs="$deplib $deplibs"
+ else
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ fi
+ continue
+ ;;
+ esac # linkmode
+ ;; # *.$libext
+ *.lo | *.$objext)
+ if test "$pass" = conv; then
+ deplibs="$deplib $deplibs"
+ elif test "$linkmode" = prog; then
+ if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then
+ # If there is no dlopen support or we're linking statically,
+ # we need to preload.
+ newdlprefiles="$newdlprefiles $deplib"
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ newdlfiles="$newdlfiles $deplib"
+ fi
+ fi
+ continue
+ ;;
+ %DEPLIBS%)
+ alldeplibs=yes
+ continue
+ ;;
+ esac # case $deplib
+ if test "$found" = yes || test -f "$lib"; then :
+ else
+ $echo "$modename: cannot find the library \`$lib'" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ # Check to see that this really is a libtool archive.
+ if (${SED} -e '2q' $lib | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
+ else
+ $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'`
+ test "X$ladir" = "X$lib" && ladir="."
+
+ dlname=
+ dlopen=
+ dlpreopen=
+ libdir=
+ library_names=
+ old_library=
+ # If the library was installed with an old release of libtool,
+ # it will not redefine variables installed, or shouldnotlink
+ installed=yes
+ shouldnotlink=no
+
+ # Read the .la file
+ case $lib in
+ */* | *\\*) . $lib ;;
+ *) . ./$lib ;;
+ esac
+
+ if test "$linkmode,$pass" = "lib,link" ||
+ test "$linkmode,$pass" = "prog,scan" ||
+ { test "$linkmode" != prog && test "$linkmode" != lib; }; then
+ test -n "$dlopen" && dlfiles="$dlfiles $dlopen"
+ test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen"
+ fi
+
+ if test "$pass" = conv; then
+ # Only check for convenience libraries
+ deplibs="$lib $deplibs"
+ if test -z "$libdir"; then
+ if test -z "$old_library"; then
+ $echo "$modename: cannot find name of link library for \`$lib'" 1>&2
+ exit $EXIT_FAILURE
+ fi
+ # It is a libtool convenience library, so add in its objects.
+ convenience="$convenience $ladir/$objdir/$old_library"
+ old_convenience="$old_convenience $ladir/$objdir/$old_library"
+ tmp_libs=
+ for deplib in $dependency_libs; do
+ deplibs="$deplib $deplibs"
+ if test "X$duplicate_deps" = "Xyes" ; then
+ case "$tmp_libs " in
+ *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+ esac
+ fi
+ tmp_libs="$tmp_libs $deplib"
+ done
+ elif test "$linkmode" != prog && test "$linkmode" != lib; then
+ $echo "$modename: \`$lib' is not a convenience library" 1>&2
+ exit $EXIT_FAILURE
+ fi
+ continue
+ fi # $pass = conv
+
+
+ # Get the name of the library we link against.
+ linklib=
+ for l in $old_library $library_names; do
+ linklib="$l"
+ done
+ if test -z "$linklib"; then
+ $echo "$modename: cannot find name of link library for \`$lib'" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ # This library was specified with -dlopen.
+ if test "$pass" = dlopen; then
+ if test -z "$libdir"; then
+ $echo "$modename: cannot -dlopen a convenience library: \`$lib'" 1>&2
+ exit $EXIT_FAILURE
+ fi
+ if test -z "$dlname" ||
+ test "$dlopen_support" != yes ||
+ test "$build_libtool_libs" = no; then
+ # If there is no dlname, no dlopen support or we're linking
+ # statically, we need to preload. We also need to preload any
+ # dependent libraries so libltdl's deplib preloader doesn't
+ # bomb out in the load deplibs phase.
+ dlprefiles="$dlprefiles $lib $dependency_libs"
+ else
+ newdlfiles="$newdlfiles $lib"
+ fi
+ continue
+ fi # $pass = dlopen
+
+ # We need an absolute path.
+ case $ladir in
+ [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;;
+ *)
+ abs_ladir=`cd "$ladir" && pwd`
+ if test -z "$abs_ladir"; then
+ $echo "$modename: warning: cannot determine absolute directory name of \`$ladir'" 1>&2
+ $echo "$modename: passing it literally to the linker, although it might fail" 1>&2
+ abs_ladir="$ladir"
+ fi
+ ;;
+ esac
+ laname=`$echo "X$lib" | $Xsed -e 's%^.*/%%'`
+
+ # Find the relevant object directory and library name.
+ if test "X$installed" = Xyes; then
+ if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+ $echo "$modename: warning: library \`$lib' was moved." 1>&2
+ dir="$ladir"
+ absdir="$abs_ladir"
+ libdir="$abs_ladir"
+ else
+ dir="$libdir"
+ absdir="$libdir"
+ fi
+ else
+ dir="$ladir/$objdir"
+ absdir="$abs_ladir/$objdir"
+ # Remove this search path later
+ notinst_path="$notinst_path $abs_ladir"
+ fi # $installed = yes
+ name=`$echo "X$laname" | $Xsed -e 's/\.la$//' -e 's/^lib//'`
+
+ # This library was specified with -dlpreopen.
+ if test "$pass" = dlpreopen; then
+ if test -z "$libdir"; then
+ $echo "$modename: cannot -dlpreopen a convenience library: \`$lib'" 1>&2
+ exit $EXIT_FAILURE
+ fi
+ # Prefer using a static library (so that no silly _DYNAMIC symbols
+ # are required to link).
+ if test -n "$old_library"; then
+ newdlprefiles="$newdlprefiles $dir/$old_library"
+ # Otherwise, use the dlname, so that lt_dlopen finds it.
+ elif test -n "$dlname"; then
+ newdlprefiles="$newdlprefiles $dir/$dlname"
+ else
+ newdlprefiles="$newdlprefiles $dir/$linklib"
+ fi
+ fi # $pass = dlpreopen
+
+ if test -z "$libdir"; then
+ # Link the convenience library
+ if test "$linkmode" = lib; then
+ deplibs="$dir/$old_library $deplibs"
+ elif test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$dir/$old_library $compile_deplibs"
+ finalize_deplibs="$dir/$old_library $finalize_deplibs"
+ else
+ deplibs="$lib $deplibs" # used for prog,scan pass
+ fi
+ continue
+ fi
+
+
+ if test "$linkmode" = prog && test "$pass" != link; then
+ newlib_search_path="$newlib_search_path $ladir"
+ deplibs="$lib $deplibs"
+
+ linkalldeplibs=no
+ if test "$link_all_deplibs" != no || test -z "$library_names" ||
+ test "$build_libtool_libs" = no; then
+ linkalldeplibs=yes
+ fi
+
+ tmp_libs=
+ for deplib in $dependency_libs; do
+ case $deplib in
+ -L*) newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`;; ### testsuite: skip nested quoting test
+ esac
+ # Need to link against all dependency_libs?
+ if test "$linkalldeplibs" = yes; then
+ deplibs="$deplib $deplibs"
+ else
+ # Need to hardcode shared library paths
+ # or/and link against static libraries
+ newdependency_libs="$deplib $newdependency_libs"
+ fi
+ if test "X$duplicate_deps" = "Xyes" ; then
+ case "$tmp_libs " in
+ *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+ esac
+ fi
+ tmp_libs="$tmp_libs $deplib"
+ done # for deplib
+ continue
+ fi # $linkmode = prog...
+
+ if test "$linkmode,$pass" = "prog,link"; then
+ if test -n "$library_names" &&
+ { test "$prefer_static_libs" = no || test -z "$old_library"; }; then
+ # We need to hardcode the library path
+ if test -n "$shlibpath_var"; then
+ # Make sure the rpath contains only unique directories.
+ case "$temp_rpath " in
+ *" $dir "*) ;;
+ *" $absdir "*) ;;
+ *) temp_rpath="$temp_rpath $dir" ;;
+ esac
+ fi
+
+ # Hardcode the library path.
+ # Skip directories that are in the system default run-time
+ # search path.
+ case " $sys_lib_dlsearch_path " in
+ *" $absdir "*) ;;
+ *)
+ case "$compile_rpath " in
+ *" $absdir "*) ;;
+ *) compile_rpath="$compile_rpath $absdir"
+ esac
+ ;;
+ esac
+ case " $sys_lib_dlsearch_path " in
+ *" $libdir "*) ;;
+ *)
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_rpath="$finalize_rpath $libdir"
+ esac
+ ;;
+ esac
+ fi # $linkmode,$pass = prog,link...
+
+ if test "$alldeplibs" = yes &&
+ { test "$deplibs_check_method" = pass_all ||
+ { test "$build_libtool_libs" = yes &&
+ test -n "$library_names"; }; }; then
+ # We only need to search for static libraries
+ continue
+ fi
+ fi
+
+ link_static=no # Whether the deplib will be linked statically
+ if test -n "$library_names" &&
+ { test "$prefer_static_libs" = no || test -z "$old_library"; }; then
+ if test "$installed" = no; then
+ notinst_deplibs="$notinst_deplibs $lib"
+ need_relink=yes
+ fi
+ # This is a shared library
+
+ # Warn about portability, can't link against -module's on
+ # some systems (darwin)
+ if test "$shouldnotlink" = yes && test "$pass" = link ; then
+ $echo
+ if test "$linkmode" = prog; then
+ $echo "*** Warning: Linking the executable $output against the loadable module"
+ else
+ $echo "*** Warning: Linking the shared library $output against the loadable module"
+ fi
+ $echo "*** $linklib is not portable!"
+ fi
+ if test "$linkmode" = lib &&
+ test "$hardcode_into_libs" = yes; then
+ # Hardcode the library path.
+ # Skip directories that are in the system default run-time
+ # search path.
+ case " $sys_lib_dlsearch_path " in
+ *" $absdir "*) ;;
+ *)
+ case "$compile_rpath " in
+ *" $absdir "*) ;;
+ *) compile_rpath="$compile_rpath $absdir"
+ esac
+ ;;
+ esac
+ case " $sys_lib_dlsearch_path " in
+ *" $libdir "*) ;;
+ *)
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_rpath="$finalize_rpath $libdir"
+ esac
+ ;;
+ esac
+ fi
+
+ if test -n "$old_archive_from_expsyms_cmds"; then
+ # figure out the soname
+ set dummy $library_names
+ realname="$2"
+ shift; shift
+ libname=`eval \\$echo \"$libname_spec\"`
+ # use dlname if we got it. it's perfectly good, no?
+ if test -n "$dlname"; then
+ soname="$dlname"
+ elif test -n "$soname_spec"; then
+ # bleh windows
+ case $host in
+ *cygwin* | mingw*)
+ major=`expr $current - $age`
+ versuffix="-$major"
+ ;;
+ esac
+ eval soname=\"$soname_spec\"
+ else
+ soname="$realname"
+ fi
+
+ # Make a new name for the extract_expsyms_cmds to use
+ soroot="$soname"
+ soname=`$echo $soroot | ${SED} -e 's/^.*\///'`
+ newlib="libimp-`$echo $soname | ${SED} 's/^lib//;s/\.dll$//'`.a"
+
+ # If the library has no export list, then create one now
+ if test -f "$output_objdir/$soname-def"; then :
+ else
+ $show "extracting exported symbol list from \`$soname'"
+ save_ifs="$IFS"; IFS='~'
+ cmds=$extract_expsyms_cmds
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+ fi
+
+ # Create $newlib
+ if test -f "$output_objdir/$newlib"; then :; else
+ $show "generating import library for \`$soname'"
+ save_ifs="$IFS"; IFS='~'
+ cmds=$old_archive_from_expsyms_cmds
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+ fi
+ # make sure the library variables are pointing to the new library
+ dir=$output_objdir
+ linklib=$newlib
+ fi # test -n "$old_archive_from_expsyms_cmds"
+
+ if test "$linkmode" = prog || test "$mode" != relink; then
+ add_shlibpath=
+ add_dir=
+ add=
+ lib_linked=yes
+ case $hardcode_action in
+ immediate | unsupported)
+ if test "$hardcode_direct" = no; then
+ add="$dir/$linklib"
+ case $host in
+ *-*-sco3.2v5* ) add_dir="-L$dir" ;;
+ *-*-darwin* )
+ # if the lib is a module then we can not link against
+ # it, someone is ignoring the new warnings I added
+ if /usr/bin/file -L $add 2> /dev/null | $EGREP "bundle" >/dev/null ; then
+ $echo "** Warning, lib $linklib is a module, not a shared library"
+ if test -z "$old_library" ; then
+ $echo
+ $echo "** And there doesn't seem to be a static archive available"
+ $echo "** The link will probably fail, sorry"
+ else
+ add="$dir/$old_library"
+ fi
+ fi
+ esac
+ elif test "$hardcode_minus_L" = no; then
+ case $host in
+ *-*-sunos*) add_shlibpath="$dir" ;;
+ esac
+ add_dir="-L$dir"
+ add="-l$name"
+ elif test "$hardcode_shlibpath_var" = no; then
+ add_shlibpath="$dir"
+ add="-l$name"
+ else
+ lib_linked=no
+ fi
+ ;;
+ relink)
+ if test "$hardcode_direct" = yes; then
+ add="$dir/$linklib"
+ elif test "$hardcode_minus_L" = yes; then
+ add_dir="-L$dir"
+ # Try looking first in the location we're being installed to.
+ if test -n "$inst_prefix_dir"; then
+ case "$libdir" in
+ [\\/]*)
+ add_dir="$add_dir -L$inst_prefix_dir$libdir"
+ ;;
+ esac
+ fi
+ add="-l$name"
+ elif test "$hardcode_shlibpath_var" = yes; then
+ add_shlibpath="$dir"
+ add="-l$name"
+ else
+ lib_linked=no
+ fi
+ ;;
+ *) lib_linked=no ;;
+ esac
+
+ if test "$lib_linked" != yes; then
+ $echo "$modename: configuration error: unsupported hardcode properties"
+ exit $EXIT_FAILURE
+ fi
+
+ if test -n "$add_shlibpath"; then
+ case :$compile_shlibpath: in
+ *":$add_shlibpath:"*) ;;
+ *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;;
+ esac
+ fi
+ if test "$linkmode" = prog; then
+ test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs"
+ test -n "$add" && compile_deplibs="$add $compile_deplibs"
+ else
+ test -n "$add_dir" && deplibs="$add_dir $deplibs"
+ test -n "$add" && deplibs="$add $deplibs"
+ if test "$hardcode_direct" != yes && \
+ test "$hardcode_minus_L" != yes && \
+ test "$hardcode_shlibpath_var" = yes; then
+ case :$finalize_shlibpath: in
+ *":$libdir:"*) ;;
+ *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;;
+ esac
+ fi
+ fi
+ fi
+
+ if test "$linkmode" = prog || test "$mode" = relink; then
+ add_shlibpath=
+ add_dir=
+ add=
+ # Finalize command for both is simple: just hardcode it.
+ if test "$hardcode_direct" = yes; then
+ add="$libdir/$linklib"
+ elif test "$hardcode_minus_L" = yes; then
+ add_dir="-L$libdir"
+ add="-l$name"
+ elif test "$hardcode_shlibpath_var" = yes; then
+ case :$finalize_shlibpath: in
+ *":$libdir:"*) ;;
+ *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;;
+ esac
+ add="-l$name"
+ elif test "$hardcode_automatic" = yes; then
+ if test -n "$inst_prefix_dir" &&
+ test -f "$inst_prefix_dir$libdir/$linklib" ; then
+ add="$inst_prefix_dir$libdir/$linklib"
+ else
+ add="$libdir/$linklib"
+ fi
+ else
+ # We cannot seem to hardcode it, guess we'll fake it.
+ add_dir="-L$libdir"
+ # Try looking first in the location we're being installed to.
+ if test -n "$inst_prefix_dir"; then
+ case "$libdir" in
+ [\\/]*)
+ add_dir="$add_dir -L$inst_prefix_dir$libdir"
+ ;;
+ esac
+ fi
+ add="-l$name"
+ fi
+
+ if test "$linkmode" = prog; then
+ test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs"
+ test -n "$add" && finalize_deplibs="$add $finalize_deplibs"
+ else
+ test -n "$add_dir" && deplibs="$add_dir $deplibs"
+ test -n "$add" && deplibs="$add $deplibs"
+ fi
+ fi
+ elif test "$linkmode" = prog; then
+ # Here we assume that one of hardcode_direct or hardcode_minus_L
+ # is not unsupported. This is valid on all known static and
+ # shared platforms.
+ if test "$hardcode_direct" != unsupported; then
+ test -n "$old_library" && linklib="$old_library"
+ compile_deplibs="$dir/$linklib $compile_deplibs"
+ finalize_deplibs="$dir/$linklib $finalize_deplibs"
+ else
+ compile_deplibs="-l$name -L$dir $compile_deplibs"
+ finalize_deplibs="-l$name -L$dir $finalize_deplibs"
+ fi
+ elif test "$build_libtool_libs" = yes; then
+ # Not a shared library
+ if test "$deplibs_check_method" != pass_all; then
+ # We're trying link a shared library against a static one
+ # but the system doesn't support it.
+
+ # Just print a warning and add the library to dependency_libs so
+ # that the program can be linked against the static library.
+ $echo
+ $echo "*** Warning: This system can not link to static lib archive $lib."
+ $echo "*** I have the capability to make that library automatically link in when"
+ $echo "*** you link to this library. But I can only do this if you have a"
+ $echo "*** shared version of the library, which you do not appear to have."
+ if test "$module" = yes; then
+ $echo "*** But as you try to build a module library, libtool will still create "
+ $echo "*** a static module, that should work as long as the dlopening application"
+ $echo "*** is linked with the -dlopen flag to resolve symbols at runtime."
+ if test -z "$global_symbol_pipe"; then
+ $echo
+ $echo "*** However, this would only work if libtool was able to extract symbol"
+ $echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+ $echo "*** not find such a program. So, this module is probably useless."
+ $echo "*** \`nm' from GNU binutils and a full rebuild may help."
+ fi
+ if test "$build_old_libs" = no; then
+ build_libtool_libs=module
+ build_old_libs=yes
+ else
+ build_libtool_libs=no
+ fi
+ fi
+ else
+ convenience="$convenience $dir/$old_library"
+ old_convenience="$old_convenience $dir/$old_library"
+ deplibs="$dir/$old_library $deplibs"
+ link_static=yes
+ fi
+ fi # link shared/static library?
+
+ if test "$linkmode" = lib; then
+ if test -n "$dependency_libs" &&
+ { test "$hardcode_into_libs" != yes ||
+ test "$build_old_libs" = yes ||
+ test "$link_static" = yes; }; then
+ # Extract -R from dependency_libs
+ temp_deplibs=
+ for libdir in $dependency_libs; do
+ case $libdir in
+ -R*) temp_xrpath=`$echo "X$libdir" | $Xsed -e 's/^-R//'`
+ case " $xrpath " in
+ *" $temp_xrpath "*) ;;
+ *) xrpath="$xrpath $temp_xrpath";;
+ esac;;
+ *) temp_deplibs="$temp_deplibs $libdir";;
+ esac
+ done
+ dependency_libs="$temp_deplibs"
+ fi
+
+ newlib_search_path="$newlib_search_path $absdir"
+ # Link against this library
+ test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs"
+ # ... and its dependency_libs
+ tmp_libs=
+ for deplib in $dependency_libs; do
+ newdependency_libs="$deplib $newdependency_libs"
+ if test "X$duplicate_deps" = "Xyes" ; then
+ case "$tmp_libs " in
+ *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+ esac
+ fi
+ tmp_libs="$tmp_libs $deplib"
+ done
+
+ if test "$link_all_deplibs" != no; then
+ # Add the search paths of all dependency libraries
+ for deplib in $dependency_libs; do
+ case $deplib in
+ -L*) path="$deplib" ;;
+ *.la)
+ dir=`$echo "X$deplib" | $Xsed -e 's%/[^/]*$%%'`
+ test "X$dir" = "X$deplib" && dir="."
+ # We need an absolute path.
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;;
+ *)
+ absdir=`cd "$dir" && pwd`
+ if test -z "$absdir"; then
+ $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2
+ absdir="$dir"
+ fi
+ ;;
+ esac
+ if grep "^installed=no" $deplib > /dev/null; then
+ path="$absdir/$objdir"
+ else
+ eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
+ if test -z "$libdir"; then
+ $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2
+ exit $EXIT_FAILURE
+ fi
+ if test "$absdir" != "$libdir"; then
+ $echo "$modename: warning: \`$deplib' seems to be moved" 1>&2
+ fi
+ path="$absdir"
+ fi
+ depdepl=
+ case $host in
+ *-*-darwin*)
+ # we do not want to link against static libs,
+ # but need to link against shared
+ eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib`
+ if test -n "$deplibrary_names" ; then
+ for tmp in $deplibrary_names ; do
+ depdepl=$tmp
+ done
+ if test -f "$path/$depdepl" ; then
+ depdepl="$path/$depdepl"
+ fi
+ # do not add paths which are already there
+ case " $newlib_search_path " in
+ *" $path "*) ;;
+ *) newlib_search_path="$newlib_search_path $path";;
+ esac
+ fi
+ path=""
+ ;;
+ *)
+ path="-L$path"
+ ;;
+ esac
+ ;;
+ -l*)
+ case $host in
+ *-*-darwin*)
+ # Again, we only want to link against shared libraries
+ eval tmp_libs=`$echo "X$deplib" | $Xsed -e "s,^\-l,,"`
+ for tmp in $newlib_search_path ; do
+ if test -f "$tmp/lib$tmp_libs.dylib" ; then
+ eval depdepl="$tmp/lib$tmp_libs.dylib"
+ break
+ fi
+ done
+ path=""
+ ;;
+ *) continue ;;
+ esac
+ ;;
+ *) continue ;;
+ esac
+ case " $deplibs " in
+ *" $depdepl "*) ;;
+ *) deplibs="$depdepl $deplibs" ;;
+ esac
+ case " $deplibs " in
+ *" $path "*) ;;
+ *) deplibs="$deplibs $path" ;;
+ esac
+ done
+ fi # link_all_deplibs != no
+ fi # linkmode = lib
+ done # for deplib in $libs
+ dependency_libs="$newdependency_libs"
+ if test "$pass" = dlpreopen; then
+ # Link the dlpreopened libraries before other libraries
+ for deplib in $save_deplibs; do
+ deplibs="$deplib $deplibs"
+ done
+ fi
+ if test "$pass" != dlopen; then
+ if test "$pass" != conv; then
+ # Make sure lib_search_path contains only unique directories.
+ lib_search_path=
+ for dir in $newlib_search_path; do
+ case "$lib_search_path " in
+ *" $dir "*) ;;
+ *) lib_search_path="$lib_search_path $dir" ;;
+ esac
+ done
+ newlib_search_path=
+ fi
+
+ if test "$linkmode,$pass" != "prog,link"; then
+ vars="deplibs"
+ else
+ vars="compile_deplibs finalize_deplibs"
+ fi
+ for var in $vars dependency_libs; do
+ # Add libraries to $var in reverse order
+ eval tmp_libs=\"\$$var\"
+ new_libs=
+ for deplib in $tmp_libs; do
+ # FIXME: Pedantically, this is the right thing to do, so
+ # that some nasty dependency loop isn't accidentally
+ # broken:
+ #new_libs="$deplib $new_libs"
+ # Pragmatically, this seems to cause very few problems in
+ # practice:
+ case $deplib in
+ -L*) new_libs="$deplib $new_libs" ;;
+ -R*) ;;
+ *)
+ # And here is the reason: when a library appears more
+ # than once as an explicit dependence of a library, or
+ # is implicitly linked in more than once by the
+ # compiler, it is considered special, and multiple
+ # occurrences thereof are not removed. Compare this
+ # with having the same library being listed as a
+ # dependency of multiple other libraries: in this case,
+ # we know (pedantically, we assume) the library does not
+ # need to be listed more than once, so we keep only the
+ # last copy. This is not always right, but it is rare
+ # enough that we require users that really mean to play
+ # such unportable linking tricks to link the library
+ # using -Wl,-lname, so that libtool does not consider it
+ # for duplicate removal.
+ case " $specialdeplibs " in
+ *" $deplib "*) new_libs="$deplib $new_libs" ;;
+ *)
+ case " $new_libs " in
+ *" $deplib "*) ;;
+ *) new_libs="$deplib $new_libs" ;;
+ esac
+ ;;
+ esac
+ ;;
+ esac
+ done
+ tmp_libs=
+ for deplib in $new_libs; do
+ case $deplib in
+ -L*)
+ case " $tmp_libs " in
+ *" $deplib "*) ;;
+ *) tmp_libs="$tmp_libs $deplib" ;;
+ esac
+ ;;
+ *) tmp_libs="$tmp_libs $deplib" ;;
+ esac
+ done
+ eval $var=\"$tmp_libs\"
+ done # for var
+ fi
+ # Last step: remove runtime libs from dependency_libs
+ # (they stay in deplibs)
+ tmp_libs=
+ for i in $dependency_libs ; do
+ case " $predeps $postdeps $compiler_lib_search_path " in
+ *" $i "*)
+ i=""
+ ;;
+ esac
+ if test -n "$i" ; then
+ tmp_libs="$tmp_libs $i"
+ fi
+ done
+ dependency_libs=$tmp_libs
+ done # for pass
+ if test "$linkmode" = prog; then
+ dlfiles="$newdlfiles"
+ dlprefiles="$newdlprefiles"
+ fi
+
+ case $linkmode in
+ oldlib)
+ if test -n "$deplibs"; then
+ $echo "$modename: warning: \`-l' and \`-L' are ignored for archives" 1>&2
+ fi
+
+ if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+ $echo "$modename: warning: \`-dlopen' is ignored for archives" 1>&2
+ fi
+
+ if test -n "$rpath"; then
+ $echo "$modename: warning: \`-rpath' is ignored for archives" 1>&2
+ fi
+
+ if test -n "$xrpath"; then
+ $echo "$modename: warning: \`-R' is ignored for archives" 1>&2
+ fi
+
+ if test -n "$vinfo"; then
+ $echo "$modename: warning: \`-version-info/-version-number' is ignored for archives" 1>&2
+ fi
+
+ if test -n "$release"; then
+ $echo "$modename: warning: \`-release' is ignored for archives" 1>&2
+ fi
+
+ if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
+ $echo "$modename: warning: \`-export-symbols' is ignored for archives" 1>&2
+ fi
+
+ # Now set the variables for building old libraries.
+ build_libtool_libs=no
+ oldlibs="$output"
+ objs="$objs$old_deplibs"
+ ;;
+
+ lib)
+ # Make sure we only generate libraries of the form `libNAME.la'.
+ case $outputname in
+ lib*)
+ name=`$echo "X$outputname" | $Xsed -e 's/\.la$//' -e 's/^lib//'`
+ eval shared_ext=\"$shrext_cmds\"
+ eval libname=\"$libname_spec\"
+ ;;
+ *)
+ if test "$module" = no; then
+ $echo "$modename: libtool library \`$output' must begin with \`lib'" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+ if test "$need_lib_prefix" != no; then
+ # Add the "lib" prefix for modules if required
+ name=`$echo "X$outputname" | $Xsed -e 's/\.la$//'`
+ eval shared_ext=\"$shrext_cmds\"
+ eval libname=\"$libname_spec\"
+ else
+ libname=`$echo "X$outputname" | $Xsed -e 's/\.la$//'`
+ fi
+ ;;
+ esac
+
+ if test -n "$objs"; then
+ if test "$deplibs_check_method" != pass_all; then
+ $echo "$modename: cannot build libtool library \`$output' from non-libtool objects on this host:$objs" 2>&1
+ exit $EXIT_FAILURE
+ else
+ $echo
+ $echo "*** Warning: Linking the shared library $output against the non-libtool"
+ $echo "*** objects $objs is not portable!"
+ libobjs="$libobjs $objs"
+ fi
+ fi
+
+ if test "$dlself" != no; then
+ $echo "$modename: warning: \`-dlopen self' is ignored for libtool libraries" 1>&2
+ fi
+
+ set dummy $rpath
+ if test "$#" -gt 2; then
+ $echo "$modename: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2
+ fi
+ install_libdir="$2"
+
+ oldlibs=
+ if test -z "$rpath"; then
+ if test "$build_libtool_libs" = yes; then
+ # Building a libtool convenience library.
+ # Some compilers have problems with a `.al' extension so
+ # convenience libraries should have the same extension an
+ # archive normally would.
+ oldlibs="$output_objdir/$libname.$libext $oldlibs"
+ build_libtool_libs=convenience
+ build_old_libs=yes
+ fi
+
+ if test -n "$vinfo"; then
+ $echo "$modename: warning: \`-version-info/-version-number' is ignored for convenience libraries" 1>&2
+ fi
+
+ if test -n "$release"; then
+ $echo "$modename: warning: \`-release' is ignored for convenience libraries" 1>&2
+ fi
+ else
+
+ # Parse the version information argument.
+ save_ifs="$IFS"; IFS=':'
+ set dummy $vinfo 0 0 0
+ IFS="$save_ifs"
+
+ if test -n "$8"; then
+ $echo "$modename: too many parameters to \`-version-info'" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ # convert absolute version numbers to libtool ages
+ # this retains compatibility with .la files and attempts
+ # to make the code below a bit more comprehensible
+
+ case $vinfo_number in
+ yes)
+ number_major="$2"
+ number_minor="$3"
+ number_revision="$4"
+ #
+ # There are really only two kinds -- those that
+ # use the current revision as the major version
+ # and those that subtract age and use age as
+ # a minor version. But, then there is irix
+ # which has an extra 1 added just for fun
+ #
+ case $version_type in
+ darwin|linux|osf|windows)
+ current=`expr $number_major + $number_minor`
+ age="$number_minor"
+ revision="$number_revision"
+ ;;
+ freebsd-aout|freebsd-elf|sunos)
+ current="$number_major"
+ revision="$number_minor"
+ age="0"
+ ;;
+ irix|nonstopux)
+ current=`expr $number_major + $number_minor - 1`
+ age="$number_minor"
+ revision="$number_minor"
+ ;;
+ esac
+ ;;
+ no)
+ current="$2"
+ revision="$3"
+ age="$4"
+ ;;
+ esac
+
+ # Check that each of the things are valid numbers.
+ case $current in
+ [0-9]*) ;;
+ *)
+ $echo "$modename: CURRENT \`$current' is not a nonnegative integer" 1>&2
+ $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ esac
+
+ case $revision in
+ [0-9]*) ;;
+ *)
+ $echo "$modename: REVISION \`$revision' is not a nonnegative integer" 1>&2
+ $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ esac
+
+ case $age in
+ [0-9]*) ;;
+ *)
+ $echo "$modename: AGE \`$age' is not a nonnegative integer" 1>&2
+ $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ esac
+
+ if test "$age" -gt "$current"; then
+ $echo "$modename: AGE \`$age' is greater than the current interface number \`$current'" 1>&2
+ $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ # Calculate the version variables.
+ major=
+ versuffix=
+ verstring=
+ case $version_type in
+ none) ;;
+
+ darwin)
+ # Like Linux, but with the current version available in
+ # verstring for coding it into the library header
+ major=.`expr $current - $age`
+ versuffix="$major.$age.$revision"
+ # Darwin ld doesn't like 0 for these options...
+ minor_current=`expr $current + 1`
+ verstring="-compatibility_version $minor_current -current_version $minor_current.$revision"
+ ;;
+
+ freebsd-aout)
+ major=".$current"
+ versuffix=".$current.$revision";
+ ;;
+
+ freebsd-elf)
+ major=".$current"
+ versuffix=".$current";
+ ;;
+
+ irix | nonstopux)
+ major=`expr $current - $age + 1`
+
+ case $version_type in
+ nonstopux) verstring_prefix=nonstopux ;;
+ *) verstring_prefix=sgi ;;
+ esac
+ verstring="$verstring_prefix$major.$revision"
+
+ # Add in all the interfaces that we are compatible with.
+ loop=$revision
+ while test "$loop" -ne 0; do
+ iface=`expr $revision - $loop`
+ loop=`expr $loop - 1`
+ verstring="$verstring_prefix$major.$iface:$verstring"
+ done
+
+ # Before this point, $major must not contain `.'.
+ major=.$major
+ versuffix="$major.$revision"
+ ;;
+
+ linux)
+ major=.`expr $current - $age`
+ versuffix="$major.$age.$revision"
+ ;;
+
+ osf)
+ major=.`expr $current - $age`
+ versuffix=".$current.$age.$revision"
+ verstring="$current.$age.$revision"
+
+ # Add in all the interfaces that we are compatible with.
+ loop=$age
+ while test "$loop" -ne 0; do
+ iface=`expr $current - $loop`
+ loop=`expr $loop - 1`
+ verstring="$verstring:${iface}.0"
+ done
+
+ # Make executables depend on our current version.
+ verstring="$verstring:${current}.0"
+ ;;
+
+ sunos)
+ major=".$current"
+ versuffix=".$current.$revision"
+ ;;
+
+ windows)
+ # Use '-' rather than '.', since we only want one
+ # extension on DOS 8.3 filesystems.
+ major=`expr $current - $age`
+ versuffix="-$major"
+ ;;
+
+ *)
+ $echo "$modename: unknown library version type \`$version_type'" 1>&2
+ $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ esac
+
+ # Clear the version info if we defaulted, and they specified a release.
+ if test -z "$vinfo" && test -n "$release"; then
+ major=
+ case $version_type in
+ darwin)
+ # we can't check for "0.0" in archive_cmds due to quoting
+ # problems, so we reset it completely
+ verstring=
+ ;;
+ *)
+ verstring="0.0"
+ ;;
+ esac
+ if test "$need_version" = no; then
+ versuffix=
+ else
+ versuffix=".0.0"
+ fi
+ fi
+
+ # Remove version info from name if versioning should be avoided
+ if test "$avoid_version" = yes && test "$need_version" = no; then
+ major=
+ versuffix=
+ verstring=""
+ fi
+
+ # Check to see if the archive will have undefined symbols.
+ if test "$allow_undefined" = yes; then
+ if test "$allow_undefined_flag" = unsupported; then
+ $echo "$modename: warning: undefined symbols not allowed in $host shared libraries" 1>&2
+ build_libtool_libs=no
+ build_old_libs=yes
+ fi
+ else
+ # Don't allow undefined symbols.
+ allow_undefined_flag="$no_undefined_flag"
+ fi
+ fi
+
+ if test "$mode" != relink; then
+ # Remove our outputs, but don't remove object files since they
+ # may have been created when compiling PIC objects.
+ removelist=
+ tempremovelist=`$echo "$output_objdir/*"`
+ for p in $tempremovelist; do
+ case $p in
+ *.$objext)
+ ;;
+ $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*)
+ if test "X$precious_files_regex" != "X"; then
+ if echo $p | $EGREP -e "$precious_files_regex" >/dev/null 2>&1
+ then
+ continue
+ fi
+ fi
+ removelist="$removelist $p"
+ ;;
+ *) ;;
+ esac
+ done
+ if test -n "$removelist"; then
+ $show "${rm}r $removelist"
+ $run ${rm}r $removelist
+ fi
+ fi
+
+ # Now set the variables for building old libraries.
+ if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then
+ oldlibs="$oldlibs $output_objdir/$libname.$libext"
+
+ # Transform .lo files to .o files.
+ oldobjs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP`
+ fi
+
+ # Eliminate all temporary directories.
+ for path in $notinst_path; do
+ lib_search_path=`$echo "$lib_search_path " | ${SED} -e 's% $path % %g'`
+ deplibs=`$echo "$deplibs " | ${SED} -e 's% -L$path % %g'`
+ dependency_libs=`$echo "$dependency_libs " | ${SED} -e 's% -L$path % %g'`
+ done
+
+ if test -n "$xrpath"; then
+ # If the user specified any rpath flags, then add them.
+ temp_xrpath=
+ for libdir in $xrpath; do
+ temp_xrpath="$temp_xrpath -R$libdir"
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_rpath="$finalize_rpath $libdir" ;;
+ esac
+ done
+ if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then
+ dependency_libs="$temp_xrpath $dependency_libs"
+ fi
+ fi
+
+ # Make sure dlfiles contains only unique files that won't be dlpreopened
+ old_dlfiles="$dlfiles"
+ dlfiles=
+ for lib in $old_dlfiles; do
+ case " $dlprefiles $dlfiles " in
+ *" $lib "*) ;;
+ *) dlfiles="$dlfiles $lib" ;;
+ esac
+ done
+
+ # Make sure dlprefiles contains only unique files
+ old_dlprefiles="$dlprefiles"
+ dlprefiles=
+ for lib in $old_dlprefiles; do
+ case "$dlprefiles " in
+ *" $lib "*) ;;
+ *) dlprefiles="$dlprefiles $lib" ;;
+ esac
+ done
+
+ if test "$build_libtool_libs" = yes; then
+ if test -n "$rpath"; then
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos*)
+ # these systems don't actually have a c library (as such)!
+ ;;
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # Rhapsody C library is in the System framework
+ deplibs="$deplibs -framework System"
+ ;;
+ *-*-netbsd*)
+ # Don't link with libc until the a.out ld.so is fixed.
+ ;;
+ *-*-openbsd* | *-*-freebsd*)
+ # Do not include libc due to us having libc/libc_r.
+ test "X$arg" = "X-lc" && continue
+ ;;
+ *)
+ # Add libc to deplibs on all other systems if necessary.
+ if test "$build_libtool_need_lc" = "yes"; then
+ deplibs="$deplibs -lc"
+ fi
+ ;;
+ esac
+ fi
+
+ # Transform deplibs into only deplibs that can be linked in shared.
+ name_save=$name
+ libname_save=$libname
+ release_save=$release
+ versuffix_save=$versuffix
+ major_save=$major
+ # I'm not sure if I'm treating the release correctly. I think
+ # release should show up in the -l (ie -lgmp5) so we don't want to
+ # add it in twice. Is that correct?
+ release=""
+ versuffix=""
+ major=""
+ newdeplibs=
+ droppeddeps=no
+ case $deplibs_check_method in
+ pass_all)
+ # Don't check for shared/static. Everything works.
+ # This might be a little naive. We might want to check
+ # whether the library exists or not. But this is on
+ # osf3 & osf4 and I'm not really sure... Just
+ # implementing what was already the behavior.
+ newdeplibs=$deplibs
+ ;;
+ test_compile)
+ # This code stresses the "libraries are programs" paradigm to its
+ # limits. Maybe even breaks it. We compile a program, linking it
+ # against the deplibs as a proxy for the library. Then we can check
+ # whether they linked in statically or dynamically with ldd.
+ $rm conftest.c
+ cat > conftest.c <<EOF
+ int main() { return 0; }
+EOF
+ $rm conftest
+ $LTCC -o conftest conftest.c $deplibs
+ if test "$?" -eq 0 ; then
+ ldd_output=`ldd conftest`
+ for i in $deplibs; do
+ name="`expr $i : '-l\(.*\)'`"
+ # If $name is empty we are operating on a -L argument.
+ if test "$name" != "" && test "$name" -ne "0"; then
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $i "*)
+ newdeplibs="$newdeplibs $i"
+ i=""
+ ;;
+ esac
+ fi
+ if test -n "$i" ; then
+ libname=`eval \\$echo \"$libname_spec\"`
+ deplib_matches=`eval \\$echo \"$library_names_spec\"`
+ set dummy $deplib_matches
+ deplib_match=$2
+ if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+ newdeplibs="$newdeplibs $i"
+ else
+ droppeddeps=yes
+ $echo
+ $echo "*** Warning: dynamic linker does not accept needed library $i."
+ $echo "*** I have the capability to make that library automatically link in when"
+ $echo "*** you link to this library. But I can only do this if you have a"
+ $echo "*** shared version of the library, which I believe you do not have"
+ $echo "*** because a test_compile did reveal that the linker did not use it for"
+ $echo "*** its dynamic dependency list that programs get resolved with at runtime."
+ fi
+ fi
+ else
+ newdeplibs="$newdeplibs $i"
+ fi
+ done
+ else
+ # Error occurred in the first compile. Let's try to salvage
+ # the situation: Compile a separate program for each library.
+ for i in $deplibs; do
+ name="`expr $i : '-l\(.*\)'`"
+ # If $name is empty we are operating on a -L argument.
+ if test "$name" != "" && test "$name" != "0"; then
+ $rm conftest
+ $LTCC -o conftest conftest.c $i
+ # Did it work?
+ if test "$?" -eq 0 ; then
+ ldd_output=`ldd conftest`
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $i "*)
+ newdeplibs="$newdeplibs $i"
+ i=""
+ ;;
+ esac
+ fi
+ if test -n "$i" ; then
+ libname=`eval \\$echo \"$libname_spec\"`
+ deplib_matches=`eval \\$echo \"$library_names_spec\"`
+ set dummy $deplib_matches
+ deplib_match=$2
+ if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+ newdeplibs="$newdeplibs $i"
+ else
+ droppeddeps=yes
+ $echo
+ $echo "*** Warning: dynamic linker does not accept needed library $i."
+ $echo "*** I have the capability to make that library automatically link in when"
+ $echo "*** you link to this library. But I can only do this if you have a"
+ $echo "*** shared version of the library, which you do not appear to have"
+ $echo "*** because a test_compile did reveal that the linker did not use this one"
+ $echo "*** as a dynamic dependency that programs can get resolved with at runtime."
+ fi
+ fi
+ else
+ droppeddeps=yes
+ $echo
+ $echo "*** Warning! Library $i is needed by this library but I was not able to"
+ $echo "*** make it link in! You will probably need to install it or some"
+ $echo "*** library that it depends on before this library will be fully"
+ $echo "*** functional. Installing it before continuing would be even better."
+ fi
+ else
+ newdeplibs="$newdeplibs $i"
+ fi
+ done
+ fi
+ ;;
+ file_magic*)
+ set dummy $deplibs_check_method
+ file_magic_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"`
+ for a_deplib in $deplibs; do
+ name="`expr $a_deplib : '-l\(.*\)'`"
+ # If $name is empty we are operating on a -L argument.
+ if test "$name" != "" && test "$name" != "0"; then
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $a_deplib "*)
+ newdeplibs="$newdeplibs $a_deplib"
+ a_deplib=""
+ ;;
+ esac
+ fi
+ if test -n "$a_deplib" ; then
+ libname=`eval \\$echo \"$libname_spec\"`
+ for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+ potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
+ for potent_lib in $potential_libs; do
+ # Follow soft links.
+ if ls -lLd "$potent_lib" 2>/dev/null \
+ | grep " -> " >/dev/null; then
+ continue
+ fi
+ # The statement above tries to avoid entering an
+ # endless loop below, in case of cyclic links.
+ # We might still enter an endless loop, since a link
+ # loop can be closed while we follow links,
+ # but so what?
+ potlib="$potent_lib"
+ while test -h "$potlib" 2>/dev/null; do
+ potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'`
+ case $potliblink in
+ [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";;
+ *) potlib=`$echo "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";;
+ esac
+ done
+ if eval $file_magic_cmd \"\$potlib\" 2>/dev/null \
+ | ${SED} 10q \
+ | $EGREP "$file_magic_regex" > /dev/null; then
+ newdeplibs="$newdeplibs $a_deplib"
+ a_deplib=""
+ break 2
+ fi
+ done
+ done
+ fi
+ if test -n "$a_deplib" ; then
+ droppeddeps=yes
+ $echo
+ $echo "*** Warning: linker path does not have real file for library $a_deplib."
+ $echo "*** I have the capability to make that library automatically link in when"
+ $echo "*** you link to this library. But I can only do this if you have a"
+ $echo "*** shared version of the library, which you do not appear to have"
+ $echo "*** because I did check the linker path looking for a file starting"
+ if test -z "$potlib" ; then
+ $echo "*** with $libname but no candidates were found. (...for file magic test)"
+ else
+ $echo "*** with $libname and none of the candidates passed a file format test"
+ $echo "*** using a file magic. Last file checked: $potlib"
+ fi
+ fi
+ else
+ # Add a -L argument.
+ newdeplibs="$newdeplibs $a_deplib"
+ fi
+ done # Gone through all deplibs.
+ ;;
+ match_pattern*)
+ set dummy $deplibs_check_method
+ match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"`
+ for a_deplib in $deplibs; do
+ name="`expr $a_deplib : '-l\(.*\)'`"
+ # If $name is empty we are operating on a -L argument.
+ if test -n "$name" && test "$name" != "0"; then
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $a_deplib "*)
+ newdeplibs="$newdeplibs $a_deplib"
+ a_deplib=""
+ ;;
+ esac
+ fi
+ if test -n "$a_deplib" ; then
+ libname=`eval \\$echo \"$libname_spec\"`
+ for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+ potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
+ for potent_lib in $potential_libs; do
+ potlib="$potent_lib" # see symlink-check above in file_magic test
+ if eval $echo \"$potent_lib\" 2>/dev/null \
+ | ${SED} 10q \
+ | $EGREP "$match_pattern_regex" > /dev/null; then
+ newdeplibs="$newdeplibs $a_deplib"
+ a_deplib=""
+ break 2
+ fi
+ done
+ done
+ fi
+ if test -n "$a_deplib" ; then
+ droppeddeps=yes
+ $echo
+ $echo "*** Warning: linker path does not have real file for library $a_deplib."
+ $echo "*** I have the capability to make that library automatically link in when"
+ $echo "*** you link to this library. But I can only do this if you have a"
+ $echo "*** shared version of the library, which you do not appear to have"
+ $echo "*** because I did check the linker path looking for a file starting"
+ if test -z "$potlib" ; then
+ $echo "*** with $libname but no candidates were found. (...for regex pattern test)"
+ else
+ $echo "*** with $libname and none of the candidates passed a file format test"
+ $echo "*** using a regex pattern. Last file checked: $potlib"
+ fi
+ fi
+ else
+ # Add a -L argument.
+ newdeplibs="$newdeplibs $a_deplib"
+ fi
+ done # Gone through all deplibs.
+ ;;
+ none | unknown | *)
+ newdeplibs=""
+ tmp_deplibs=`$echo "X $deplibs" | $Xsed -e 's/ -lc$//' \
+ -e 's/ -[LR][^ ]*//g'`
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ for i in $predeps $postdeps ; do
+ # can't use Xsed below, because $i might contain '/'
+ tmp_deplibs=`$echo "X $tmp_deplibs" | ${SED} -e "1s,^X,," -e "s,$i,,"`
+ done
+ fi
+ if $echo "X $tmp_deplibs" | $Xsed -e 's/[ ]//g' \
+ | grep . >/dev/null; then
+ $echo
+ if test "X$deplibs_check_method" = "Xnone"; then
+ $echo "*** Warning: inter-library dependencies are not supported in this platform."
+ else
+ $echo "*** Warning: inter-library dependencies are not known to be supported."
+ fi
+ $echo "*** All declared inter-library dependencies are being dropped."
+ droppeddeps=yes
+ fi
+ ;;
+ esac
+ versuffix=$versuffix_save
+ major=$major_save
+ release=$release_save
+ libname=$libname_save
+ name=$name_save
+
+ case $host in
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # On Rhapsody replace the C library is the System framework
+ newdeplibs=`$echo "X $newdeplibs" | $Xsed -e 's/ -lc / -framework System /'`
+ ;;
+ esac
+
+ if test "$droppeddeps" = yes; then
+ if test "$module" = yes; then
+ $echo
+ $echo "*** Warning: libtool could not satisfy all declared inter-library"
+ $echo "*** dependencies of module $libname. Therefore, libtool will create"
+ $echo "*** a static module, that should work as long as the dlopening"
+ $echo "*** application is linked with the -dlopen flag."
+ if test -z "$global_symbol_pipe"; then
+ $echo
+ $echo "*** However, this would only work if libtool was able to extract symbol"
+ $echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+ $echo "*** not find such a program. So, this module is probably useless."
+ $echo "*** \`nm' from GNU binutils and a full rebuild may help."
+ fi
+ if test "$build_old_libs" = no; then
+ oldlibs="$output_objdir/$libname.$libext"
+ build_libtool_libs=module
+ build_old_libs=yes
+ else
+ build_libtool_libs=no
+ fi
+ else
+ $echo "*** The inter-library dependencies that have been dropped here will be"
+ $echo "*** automatically added whenever a program is linked with this library"
+ $echo "*** or is declared to -dlopen it."
+
+ if test "$allow_undefined" = no; then
+ $echo
+ $echo "*** Since this library must not contain undefined symbols,"
+ $echo "*** because either the platform does not support them or"
+ $echo "*** it was explicitly requested with -no-undefined,"
+ $echo "*** libtool will only create a static version of it."
+ if test "$build_old_libs" = no; then
+ oldlibs="$output_objdir/$libname.$libext"
+ build_libtool_libs=module
+ build_old_libs=yes
+ else
+ build_libtool_libs=no
+ fi
+ fi
+ fi
+ fi
+ # Done checking deplibs!
+ deplibs=$newdeplibs
+ fi
+
+ # All the library-specific variables (install_libdir is set above).
+ library_names=
+ old_library=
+ dlname=
+
+ # Test again, we may have decided not to build it any more
+ if test "$build_libtool_libs" = yes; then
+ if test "$hardcode_into_libs" = yes; then
+ # Hardcode the library paths
+ hardcode_libdirs=
+ dep_rpath=
+ rpath="$finalize_rpath"
+ test "$mode" != relink && rpath="$compile_rpath$rpath"
+ for libdir in $rpath; do
+ if test -n "$hardcode_libdir_flag_spec"; then
+ if test -n "$hardcode_libdir_separator"; then
+ if test -z "$hardcode_libdirs"; then
+ hardcode_libdirs="$libdir"
+ else
+ # Just accumulate the unique libdirs.
+ case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+ ;;
+ *)
+ hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+ ;;
+ esac
+ fi
+ else
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ dep_rpath="$dep_rpath $flag"
+ fi
+ elif test -n "$runpath_var"; then
+ case "$perm_rpath " in
+ *" $libdir "*) ;;
+ *) perm_rpath="$perm_rpath $libdir" ;;
+ esac
+ fi
+ done
+ # Substitute the hardcoded libdirs into the rpath.
+ if test -n "$hardcode_libdir_separator" &&
+ test -n "$hardcode_libdirs"; then
+ libdir="$hardcode_libdirs"
+ if test -n "$hardcode_libdir_flag_spec_ld"; then
+ eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\"
+ else
+ eval dep_rpath=\"$hardcode_libdir_flag_spec\"
+ fi
+ fi
+ if test -n "$runpath_var" && test -n "$perm_rpath"; then
+ # We should set the runpath_var.
+ rpath=
+ for dir in $perm_rpath; do
+ rpath="$rpath$dir:"
+ done
+ eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var"
+ fi
+ test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs"
+ fi
+
+ shlibpath="$finalize_shlibpath"
+ test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath"
+ if test -n "$shlibpath"; then
+ eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var"
+ fi
+
+ # Get the real and link names of the library.
+ eval shared_ext=\"$shrext_cmds\"
+ eval library_names=\"$library_names_spec\"
+ set dummy $library_names
+ realname="$2"
+ shift; shift
+
+ if test -n "$soname_spec"; then
+ eval soname=\"$soname_spec\"
+ else
+ soname="$realname"
+ fi
+ if test -z "$dlname"; then
+ dlname=$soname
+ fi
+
+ lib="$output_objdir/$realname"
+ for link
+ do
+ linknames="$linknames $link"
+ done
+
+ # Use standard objects if they are pic
+ test -z "$pic_flag" && libobjs=`$echo "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+
+ # Prepare the list of exported symbols
+ if test -z "$export_symbols"; then
+ if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then
+ $show "generating symbol list for \`$libname.la'"
+ export_symbols="$output_objdir/$libname.exp"
+ $run $rm $export_symbols
+ cmds=$export_symbols_cmds
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ if len=`expr "X$cmd" : ".*"` &&
+ test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ skipped_export=false
+ else
+ # The command line is too long to execute in one step.
+ $show "using reloadable object file for export list..."
+ skipped_export=:
+ fi
+ done
+ IFS="$save_ifs"
+ if test -n "$export_symbols_regex"; then
+ $show "$EGREP -e \"$export_symbols_regex\" \"$export_symbols\" > \"${export_symbols}T\""
+ $run eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+ $show "$mv \"${export_symbols}T\" \"$export_symbols\""
+ $run eval '$mv "${export_symbols}T" "$export_symbols"'
+ fi
+ fi
+ fi
+
+ if test -n "$export_symbols" && test -n "$include_expsyms"; then
+ $run eval '$echo "X$include_expsyms" | $SP2NL >> "$export_symbols"'
+ fi
+
+ tmp_deplibs=
+ for test_deplib in $deplibs; do
+ case " $convenience " in
+ *" $test_deplib "*) ;;
+ *)
+ tmp_deplibs="$tmp_deplibs $test_deplib"
+ ;;
+ esac
+ done
+ deplibs="$tmp_deplibs"
+
+ if test -n "$convenience"; then
+ if test -n "$whole_archive_flag_spec"; then
+ save_libobjs=$libobjs
+ eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+ else
+ gentop="$output_objdir/${outputname}x"
+ $show "${rm}r $gentop"
+ $run ${rm}r "$gentop"
+ $show "$mkdir $gentop"
+ $run $mkdir "$gentop"
+ status=$?
+ if test "$status" -ne 0 && test ! -d "$gentop"; then
+ exit $status
+ fi
+ generated="$generated $gentop"
+
+ for xlib in $convenience; do
+ # Extract the objects.
+ case $xlib in
+ [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;;
+ *) xabs=`pwd`"/$xlib" ;;
+ esac
+ xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'`
+ xdir="$gentop/$xlib"
+
+ $show "${rm}r $xdir"
+ $run ${rm}r "$xdir"
+ $show "$mkdir $xdir"
+ $run $mkdir "$xdir"
+ status=$?
+ if test "$status" -ne 0 && test ! -d "$xdir"; then
+ exit $status
+ fi
+ # We will extract separately just the conflicting names and we will no
+ # longer touch any unique names. It is faster to leave these extract
+ # automatically by $AR in one run.
+ $show "(cd $xdir && $AR x $xabs)"
+ $run eval "(cd \$xdir && $AR x \$xabs)" || exit $?
+ if ($AR t "$xabs" | sort | sort -uc >/dev/null 2>&1); then
+ :
+ else
+ $echo "$modename: warning: object name conflicts; renaming object files" 1>&2
+ $echo "$modename: warning: to ensure that they will not overwrite" 1>&2
+ $AR t "$xabs" | sort | uniq -cd | while read -r count name
+ do
+ i=1
+ while test "$i" -le "$count"
+ do
+ # Put our $i before any first dot (extension)
+ # Never overwrite any file
+ name_to="$name"
+ while test "X$name_to" = "X$name" || test -f "$xdir/$name_to"
+ do
+ name_to=`$echo "X$name_to" | $Xsed -e "s/\([^.]*\)/\1-$i/"`
+ done
+ $show "(cd $xdir && $AR xN $i $xabs '$name' && $mv '$name' '$name_to')"
+ $run eval "(cd \$xdir && $AR xN $i \$xabs '$name' && $mv '$name' '$name_to')" || exit $?
+ i=`expr $i + 1`
+ done
+ done
+ fi
+
+ libobjs="$libobjs "`find $xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP`
+ done
+ fi
+ fi
+
+ if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then
+ eval flag=\"$thread_safe_flag_spec\"
+ linker_flags="$linker_flags $flag"
+ fi
+
+ # Make a backup of the uninstalled library when relinking
+ if test "$mode" = relink; then
+ $run eval '(cd $output_objdir && $rm ${realname}U && $mv $realname ${realname}U)' || exit $?
+ fi
+
+ # Do each of the archive commands.
+ if test "$module" = yes && test -n "$module_cmds" ; then
+ if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+ eval test_cmds=\"$module_expsym_cmds\"
+ cmds=$module_expsym_cmds
+ else
+ eval test_cmds=\"$module_cmds\"
+ cmds=$module_cmds
+ fi
+ else
+ if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+ eval test_cmds=\"$archive_expsym_cmds\"
+ cmds=$archive_expsym_cmds
+ else
+ eval test_cmds=\"$archive_cmds\"
+ cmds=$archive_cmds
+ fi
+ fi
+
+ if test "X$skipped_export" != "X:" && len=`expr "X$test_cmds" : ".*"` &&
+ test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+ :
+ else
+ # The command line is too long to link in one step, link piecewise.
+ $echo "creating reloadable object files..."
+
+ # Save the value of $output and $libobjs because we want to
+ # use them later. If we have whole_archive_flag_spec, we
+ # want to use save_libobjs as it was before
+ # whole_archive_flag_spec was expanded, because we can't
+ # assume the linker understands whole_archive_flag_spec.
+ # This may have to be revisited, in case too many
+ # convenience libraries get linked in and end up exceeding
+ # the spec.
+ if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then
+ save_libobjs=$libobjs
+ fi
+ save_output=$output
+
+ # Clear the reloadable object creation command queue and
+ # initialize k to one.
+ test_cmds=
+ concat_cmds=
+ objlist=
+ delfiles=
+ last_robj=
+ k=1
+ output=$output_objdir/$save_output-${k}.$objext
+ # Loop over the list of objects to be linked.
+ for obj in $save_libobjs
+ do
+ eval test_cmds=\"$reload_cmds $objlist $last_robj\"
+ if test "X$objlist" = X ||
+ { len=`expr "X$test_cmds" : ".*"` &&
+ test "$len" -le "$max_cmd_len"; }; then
+ objlist="$objlist $obj"
+ else
+ # The command $test_cmds is almost too long, add a
+ # command to the queue.
+ if test "$k" -eq 1 ; then
+ # The first file doesn't have a previous command to add.
+ eval concat_cmds=\"$reload_cmds $objlist $last_robj\"
+ else
+ # All subsequent reloadable object files will link in
+ # the last one created.
+ eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist $last_robj\"
+ fi
+ last_robj=$output_objdir/$save_output-${k}.$objext
+ k=`expr $k + 1`
+ output=$output_objdir/$save_output-${k}.$objext
+ objlist=$obj
+ len=1
+ fi
+ done
+ # Handle the remaining objects by creating one last
+ # reloadable object file. All subsequent reloadable object
+ # files will link in the last one created.
+ test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+ eval concat_cmds=\"\${concat_cmds}$reload_cmds $objlist $last_robj\"
+
+ if ${skipped_export-false}; then
+ $show "generating symbol list for \`$libname.la'"
+ export_symbols="$output_objdir/$libname.exp"
+ $run $rm $export_symbols
+ libobjs=$output
+ # Append the command to create the export file.
+ eval concat_cmds=\"\$concat_cmds~$export_symbols_cmds\"
+ fi
+
+ # Set up a command to remove the reloadale object files
+ # after they are used.
+ i=0
+ while test "$i" -lt "$k"
+ do
+ i=`expr $i + 1`
+ delfiles="$delfiles $output_objdir/$save_output-${i}.$objext"
+ done
+
+ $echo "creating a temporary reloadable object file: $output"
+
+ # Loop through the commands generated above and execute them.
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $concat_cmds; do
+ IFS="$save_ifs"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+
+ libobjs=$output
+ # Restore the value of output.
+ output=$save_output
+
+ if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then
+ eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+ fi
+ # Expand the library linking commands again to reset the
+ # value of $libobjs for piecewise linking.
+
+ # Do each of the archive commands.
+ if test "$module" = yes && test -n "$module_cmds" ; then
+ if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+ cmds=$module_expsym_cmds
+ else
+ cmds=$module_cmds
+ fi
+ else
+ if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+ cmds=$archive_expsym_cmds
+ else
+ cmds=$archive_cmds
+ fi
+ fi
+
+ # Append the command to remove the reloadable object files
+ # to the just-reset $cmds.
+ eval cmds=\"\$cmds~\$rm $delfiles\"
+ fi
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+
+ # Restore the uninstalled library and exit
+ if test "$mode" = relink; then
+ $run eval '(cd $output_objdir && $rm ${realname}T && $mv $realname ${realname}T && $mv "$realname"U $realname)' || exit $?
+ exit $EXIT_SUCCESS
+ fi
+
+ # Create links to the real library.
+ for linkname in $linknames; do
+ if test "$realname" != "$linkname"; then
+ $show "(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)"
+ $run eval '(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)' || exit $?
+ fi
+ done
+
+ # If -module or -export-dynamic was specified, set the dlname.
+ if test "$module" = yes || test "$export_dynamic" = yes; then
+ # On all known operating systems, these are identical.
+ dlname="$soname"
+ fi
+ fi
+ ;;
+
+ obj)
+ if test -n "$deplibs"; then
+ $echo "$modename: warning: \`-l' and \`-L' are ignored for objects" 1>&2
+ fi
+
+ if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+ $echo "$modename: warning: \`-dlopen' is ignored for objects" 1>&2
+ fi
+
+ if test -n "$rpath"; then
+ $echo "$modename: warning: \`-rpath' is ignored for objects" 1>&2
+ fi
+
+ if test -n "$xrpath"; then
+ $echo "$modename: warning: \`-R' is ignored for objects" 1>&2
+ fi
+
+ if test -n "$vinfo"; then
+ $echo "$modename: warning: \`-version-info' is ignored for objects" 1>&2
+ fi
+
+ if test -n "$release"; then
+ $echo "$modename: warning: \`-release' is ignored for objects" 1>&2
+ fi
+
+ case $output in
+ *.lo)
+ if test -n "$objs$old_deplibs"; then
+ $echo "$modename: cannot build library object \`$output' from non-libtool objects" 1>&2
+ exit $EXIT_FAILURE
+ fi
+ libobj="$output"
+ obj=`$echo "X$output" | $Xsed -e "$lo2o"`
+ ;;
+ *)
+ libobj=
+ obj="$output"
+ ;;
+ esac
+
+ # Delete the old objects.
+ $run $rm $obj $libobj
+
+ # Objects from convenience libraries. This assumes
+ # single-version convenience libraries. Whenever we create
+ # different ones for PIC/non-PIC, this we'll have to duplicate
+ # the extraction.
+ reload_conv_objs=
+ gentop=
+ # reload_cmds runs $LD directly, so let us get rid of
+ # -Wl from whole_archive_flag_spec
+ wl=
+
+ if test -n "$convenience"; then
+ if test -n "$whole_archive_flag_spec"; then
+ eval reload_conv_objs=\"\$reload_objs $whole_archive_flag_spec\"
+ else
+ gentop="$output_objdir/${obj}x"
+ $show "${rm}r $gentop"
+ $run ${rm}r "$gentop"
+ $show "$mkdir $gentop"
+ $run $mkdir "$gentop"
+ status=$?
+ if test "$status" -ne 0 && test ! -d "$gentop"; then
+ exit $status
+ fi
+ generated="$generated $gentop"
+
+ for xlib in $convenience; do
+ # Extract the objects.
+ case $xlib in
+ [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;;
+ *) xabs=`pwd`"/$xlib" ;;
+ esac
+ xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'`
+ xdir="$gentop/$xlib"
+
+ $show "${rm}r $xdir"
+ $run ${rm}r "$xdir"
+ $show "$mkdir $xdir"
+ $run $mkdir "$xdir"
+ status=$?
+ if test "$status" -ne 0 && test ! -d "$xdir"; then
+ exit $status
+ fi
+ # We will extract separately just the conflicting names and we will no
+ # longer touch any unique names. It is faster to leave these extract
+ # automatically by $AR in one run.
+ $show "(cd $xdir && $AR x $xabs)"
+ $run eval "(cd \$xdir && $AR x \$xabs)" || exit $?
+ if ($AR t "$xabs" | sort | sort -uc >/dev/null 2>&1); then
+ :
+ else
+ $echo "$modename: warning: object name conflicts; renaming object files" 1>&2
+ $echo "$modename: warning: to ensure that they will not overwrite" 1>&2
+ $AR t "$xabs" | sort | uniq -cd | while read -r count name
+ do
+ i=1
+ while test "$i" -le "$count"
+ do
+ # Put our $i before any first dot (extension)
+ # Never overwrite any file
+ name_to="$name"
+ while test "X$name_to" = "X$name" || test -f "$xdir/$name_to"
+ do
+ name_to=`$echo "X$name_to" | $Xsed -e "s/\([^.]*\)/\1-$i/"`
+ done
+ $show "(cd $xdir && $AR xN $i $xabs '$name' && $mv '$name' '$name_to')"
+ $run eval "(cd \$xdir && $AR xN $i \$xabs '$name' && $mv '$name' '$name_to')" || exit $?
+ i=`expr $i + 1`
+ done
+ done
+ fi
+
+ reload_conv_objs="$reload_objs "`find $xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP`
+ done
+ fi
+ fi
+
+ # Create the old-style object.
+ reload_objs="$objs$old_deplibs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test
+
+ output="$obj"
+ cmds=$reload_cmds
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+
+ # Exit if we aren't doing a library object file.
+ if test -z "$libobj"; then
+ if test -n "$gentop"; then
+ $show "${rm}r $gentop"
+ $run ${rm}r $gentop
+ fi
+
+ exit $EXIT_SUCCESS
+ fi
+
+ if test "$build_libtool_libs" != yes; then
+ if test -n "$gentop"; then
+ $show "${rm}r $gentop"
+ $run ${rm}r $gentop
+ fi
+
+ # Create an invalid libtool object if no PIC, so that we don't
+ # accidentally link it into a program.
+ # $show "echo timestamp > $libobj"
+ # $run eval "echo timestamp > $libobj" || exit $?
+ exit $EXIT_SUCCESS
+ fi
+
+ if test -n "$pic_flag" || test "$pic_mode" != default; then
+ # Only do commands if we really have different PIC objects.
+ reload_objs="$libobjs $reload_conv_objs"
+ output="$libobj"
+ cmds=$reload_cmds
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+ fi
+
+ if test -n "$gentop"; then
+ $show "${rm}r $gentop"
+ $run ${rm}r $gentop
+ fi
+
+ exit $EXIT_SUCCESS
+ ;;
+
+ prog)
+ case $host in
+ *cygwin*) output=`$echo $output | ${SED} -e 's,.exe$,,;s,$,.exe,'` ;;
+ esac
+ if test -n "$vinfo"; then
+ $echo "$modename: warning: \`-version-info' is ignored for programs" 1>&2
+ fi
+
+ if test -n "$release"; then
+ $echo "$modename: warning: \`-release' is ignored for programs" 1>&2
+ fi
+
+ if test "$preload" = yes; then
+ if test "$dlopen_support" = unknown && test "$dlopen_self" = unknown &&
+ test "$dlopen_self_static" = unknown; then
+ $echo "$modename: warning: \`AC_LIBTOOL_DLOPEN' not used. Assuming no dlopen support."
+ fi
+ fi
+
+ case $host in
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # On Rhapsody replace the C library is the System framework
+ compile_deplibs=`$echo "X $compile_deplibs" | $Xsed -e 's/ -lc / -framework System /'`
+ finalize_deplibs=`$echo "X $finalize_deplibs" | $Xsed -e 's/ -lc / -framework System /'`
+ ;;
+ esac
+
+ case $host in
+ *darwin*)
+ # Don't allow lazy linking, it breaks C++ global constructors
+ if test "$tagname" = CXX ; then
+ compile_command="$compile_command ${wl}-bind_at_load"
+ finalize_command="$finalize_command ${wl}-bind_at_load"
+ fi
+ ;;
+ esac
+
+ compile_command="$compile_command $compile_deplibs"
+ finalize_command="$finalize_command $finalize_deplibs"
+
+ if test -n "$rpath$xrpath"; then
+ # If the user specified any rpath flags, then add them.
+ for libdir in $rpath $xrpath; do
+ # This is the magic to use -rpath.
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_rpath="$finalize_rpath $libdir" ;;
+ esac
+ done
+ fi
+
+ # Now hardcode the library paths
+ rpath=
+ hardcode_libdirs=
+ for libdir in $compile_rpath $finalize_rpath; do
+ if test -n "$hardcode_libdir_flag_spec"; then
+ if test -n "$hardcode_libdir_separator"; then
+ if test -z "$hardcode_libdirs"; then
+ hardcode_libdirs="$libdir"
+ else
+ # Just accumulate the unique libdirs.
+ case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+ ;;
+ *)
+ hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+ ;;
+ esac
+ fi
+ else
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ rpath="$rpath $flag"
+ fi
+ elif test -n "$runpath_var"; then
+ case "$perm_rpath " in
+ *" $libdir "*) ;;
+ *) perm_rpath="$perm_rpath $libdir" ;;
+ esac
+ fi
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
+ case :$dllsearchpath: in
+ *":$libdir:"*) ;;
+ *) dllsearchpath="$dllsearchpath:$libdir";;
+ esac
+ ;;
+ esac
+ done
+ # Substitute the hardcoded libdirs into the rpath.
+ if test -n "$hardcode_libdir_separator" &&
+ test -n "$hardcode_libdirs"; then
+ libdir="$hardcode_libdirs"
+ eval rpath=\" $hardcode_libdir_flag_spec\"
+ fi
+ compile_rpath="$rpath"
+
+ rpath=
+ hardcode_libdirs=
+ for libdir in $finalize_rpath; do
+ if test -n "$hardcode_libdir_flag_spec"; then
+ if test -n "$hardcode_libdir_separator"; then
+ if test -z "$hardcode_libdirs"; then
+ hardcode_libdirs="$libdir"
+ else
+ # Just accumulate the unique libdirs.
+ case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+ ;;
+ *)
+ hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+ ;;
+ esac
+ fi
+ else
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ rpath="$rpath $flag"
+ fi
+ elif test -n "$runpath_var"; then
+ case "$finalize_perm_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;;
+ esac
+ fi
+ done
+ # Substitute the hardcoded libdirs into the rpath.
+ if test -n "$hardcode_libdir_separator" &&
+ test -n "$hardcode_libdirs"; then
+ libdir="$hardcode_libdirs"
+ eval rpath=\" $hardcode_libdir_flag_spec\"
+ fi
+ finalize_rpath="$rpath"
+
+ if test -n "$libobjs" && test "$build_old_libs" = yes; then
+ # Transform all the library objects into standard objects.
+ compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+ finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+ fi
+
+ dlsyms=
+ if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+ if test -n "$NM" && test -n "$global_symbol_pipe"; then
+ dlsyms="${outputname}S.c"
+ else
+ $echo "$modename: not configured to extract global symbols from dlpreopened files" 1>&2
+ fi
+ fi
+
+ if test -n "$dlsyms"; then
+ case $dlsyms in
+ "") ;;
+ *.c)
+ # Discover the nlist of each of the dlfiles.
+ nlist="$output_objdir/${outputname}.nm"
+
+ $show "$rm $nlist ${nlist}S ${nlist}T"
+ $run $rm "$nlist" "${nlist}S" "${nlist}T"
+
+ # Parse the name list into a source file.
+ $show "creating $output_objdir/$dlsyms"
+
+ test -z "$run" && $echo > "$output_objdir/$dlsyms" "\
+/* $dlsyms - symbol resolution table for \`$outputname' dlsym emulation. */
+/* Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP */
+
+#ifdef __cplusplus
+extern \"C\" {
+#endif
+
+/* Prevent the only kind of declaration conflicts we can make. */
+#define lt_preloaded_symbols some_other_symbol
+
+/* External symbol declarations for the compiler. */\
+"
+
+ if test "$dlself" = yes; then
+ $show "generating symbol list for \`$output'"
+
+ test -z "$run" && $echo ': @PROGRAM@ ' > "$nlist"
+
+ # Add our own program objects to the symbol list.
+ progfiles=`$echo "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+ for arg in $progfiles; do
+ $show "extracting global C symbols from \`$arg'"
+ $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'"
+ done
+
+ if test -n "$exclude_expsyms"; then
+ $run eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T'
+ $run eval '$mv "$nlist"T "$nlist"'
+ fi
+
+ if test -n "$export_symbols_regex"; then
+ $run eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T'
+ $run eval '$mv "$nlist"T "$nlist"'
+ fi
+
+ # Prepare the list of exported symbols
+ if test -z "$export_symbols"; then
+ export_symbols="$output_objdir/$output.exp"
+ $run $rm $export_symbols
+ $run eval "${SED} -n -e '/^: @PROGRAM@$/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"'
+ else
+ $run eval "${SED} -e 's/\([][.*^$]\)/\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$output.exp"'
+ $run eval 'grep -f "$output_objdir/$output.exp" < "$nlist" > "$nlist"T'
+ $run eval 'mv "$nlist"T "$nlist"'
+ fi
+ fi
+
+ for arg in $dlprefiles; do
+ $show "extracting global C symbols from \`$arg'"
+ name=`$echo "$arg" | ${SED} -e 's%^.*/%%'`
+ $run eval '$echo ": $name " >> "$nlist"'
+ $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'"
+ done
+
+ if test -z "$run"; then
+ # Make sure we have at least an empty file.
+ test -f "$nlist" || : > "$nlist"
+
+ if test -n "$exclude_expsyms"; then
+ $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T
+ $mv "$nlist"T "$nlist"
+ fi
+
+ # Try sorting and uniquifying the output.
+ if grep -v "^: " < "$nlist" |
+ if sort -k 3 </dev/null >/dev/null 2>&1; then
+ sort -k 3
+ else
+ sort +2
+ fi |
+ uniq > "$nlist"S; then
+ :
+ else
+ grep -v "^: " < "$nlist" > "$nlist"S
+ fi
+
+ if test -f "$nlist"S; then
+ eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$dlsyms"'
+ else
+ $echo '/* NONE */' >> "$output_objdir/$dlsyms"
+ fi
+
+ $echo >> "$output_objdir/$dlsyms" "\
+
+#undef lt_preloaded_symbols
+
+#if defined (__STDC__) && __STDC__
+# define lt_ptr void *
+#else
+# define lt_ptr char *
+# define const
+#endif
+
+/* The mapping between symbol names and symbols. */
+const struct {
+ const char *name;
+ lt_ptr address;
+}
+lt_preloaded_symbols[] =
+{\
+"
+
+ eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$dlsyms"
+
+ $echo >> "$output_objdir/$dlsyms" "\
+ {0, (lt_ptr) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+ return lt_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif\
+"
+ fi
+
+ pic_flag_for_symtable=
+ case $host in
+ # compiling the symbol table file with pic_flag works around
+ # a FreeBSD bug that causes programs to crash when -lm is
+ # linked before any other PIC object. But we must not use
+ # pic_flag when linking with -static. The problem exists in
+ # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1.
+ *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*)
+ case "$compile_command " in
+ *" -static "*) ;;
+ *) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND";;
+ esac;;
+ *-*-hpux*)
+ case "$compile_command " in
+ *" -static "*) ;;
+ *) pic_flag_for_symtable=" $pic_flag";;
+ esac
+ esac
+
+ # Now compile the dynamic symbol file.
+ $show "(cd $output_objdir && $LTCC -c$no_builtin_flag$pic_flag_for_symtable \"$dlsyms\")"
+ $run eval '(cd $output_objdir && $LTCC -c$no_builtin_flag$pic_flag_for_symtable "$dlsyms")' || exit $?
+
+ # Clean up the generated files.
+ $show "$rm $output_objdir/$dlsyms $nlist ${nlist}S ${nlist}T"
+ $run $rm "$output_objdir/$dlsyms" "$nlist" "${nlist}S" "${nlist}T"
+
+ # Transform the symbol file into the correct name.
+ compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"`
+ finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"`
+ ;;
+ *)
+ $echo "$modename: unknown suffix for \`$dlsyms'" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ esac
+ else
+ # We keep going just in case the user didn't refer to
+ # lt_preloaded_symbols. The linker will fail if global_symbol_pipe
+ # really was required.
+
+ # Nullify the symbol file.
+ compile_command=`$echo "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"`
+ finalize_command=`$echo "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"`
+ fi
+
+ if test "$need_relink" = no || test "$build_libtool_libs" != yes; then
+ # Replace the output file specification.
+ compile_command=`$echo "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'`
+ link_command="$compile_command$compile_rpath"
+
+ # We have no uninstalled library dependencies, so finalize right now.
+ $show "$link_command"
+ $run eval "$link_command"
+ status=$?
+
+ # Delete the generated files.
+ if test -n "$dlsyms"; then
+ $show "$rm $output_objdir/${outputname}S.${objext}"
+ $run $rm "$output_objdir/${outputname}S.${objext}"
+ fi
+
+ exit $status
+ fi
+
+ if test -n "$shlibpath_var"; then
+ # We should set the shlibpath_var
+ rpath=
+ for dir in $temp_rpath; do
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*)
+ # Absolute path.
+ rpath="$rpath$dir:"
+ ;;
+ *)
+ # Relative path: add a thisdir entry.
+ rpath="$rpath\$thisdir/$dir:"
+ ;;
+ esac
+ done
+ temp_rpath="$rpath"
+ fi
+
+ if test -n "$compile_shlibpath$finalize_shlibpath"; then
+ compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command"
+ fi
+ if test -n "$finalize_shlibpath"; then
+ finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command"
+ fi
+
+ compile_var=
+ finalize_var=
+ if test -n "$runpath_var"; then
+ if test -n "$perm_rpath"; then
+ # We should set the runpath_var.
+ rpath=
+ for dir in $perm_rpath; do
+ rpath="$rpath$dir:"
+ done
+ compile_var="$runpath_var=\"$rpath\$$runpath_var\" "
+ fi
+ if test -n "$finalize_perm_rpath"; then
+ # We should set the runpath_var.
+ rpath=
+ for dir in $finalize_perm_rpath; do
+ rpath="$rpath$dir:"
+ done
+ finalize_var="$runpath_var=\"$rpath\$$runpath_var\" "
+ fi
+ fi
+
+ if test "$no_install" = yes; then
+ # We don't need to create a wrapper script.
+ link_command="$compile_var$compile_command$compile_rpath"
+ # Replace the output file specification.
+ link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'`
+ # Delete the old output file.
+ $run $rm $output
+ # Link the executable and exit
+ $show "$link_command"
+ $run eval "$link_command" || exit $?
+ exit $EXIT_SUCCESS
+ fi
+
+ if test "$hardcode_action" = relink; then
+ # Fast installation is not supported
+ link_command="$compile_var$compile_command$compile_rpath"
+ relink_command="$finalize_var$finalize_command$finalize_rpath"
+
+ $echo "$modename: warning: this platform does not like uninstalled shared libraries" 1>&2
+ $echo "$modename: \`$output' will be relinked during installation" 1>&2
+ else
+ if test "$fast_install" != no; then
+ link_command="$finalize_var$compile_command$finalize_rpath"
+ if test "$fast_install" = yes; then
+ relink_command=`$echo "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'`
+ else
+ # fast_install is set to needless
+ relink_command=
+ fi
+ else
+ link_command="$compile_var$compile_command$compile_rpath"
+ relink_command="$finalize_var$finalize_command$finalize_rpath"
+ fi
+ fi
+
+ # Replace the output file specification.
+ link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'`
+
+ # Delete the old output files.
+ $run $rm $output $output_objdir/$outputname $output_objdir/lt-$outputname
+
+ $show "$link_command"
+ $run eval "$link_command" || exit $?
+
+ # Now create the wrapper script.
+ $show "creating $output"
+
+ # Quote the relink command for shipping.
+ if test -n "$relink_command"; then
+ # Preserve any variables that may affect compiler behavior
+ for var in $variables_saved_for_relink; do
+ if eval test -z \"\${$var+set}\"; then
+ relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command"
+ elif eval var_value=\$$var; test -z "$var_value"; then
+ relink_command="$var=; export $var; $relink_command"
+ else
+ var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"`
+ relink_command="$var=\"$var_value\"; export $var; $relink_command"
+ fi
+ done
+ relink_command="(cd `pwd`; $relink_command)"
+ relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"`
+ fi
+
+ # Quote $echo for shipping.
+ if test "X$echo" = "X$SHELL $progpath --fallback-echo"; then
+ case $progpath in
+ [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $progpath --fallback-echo";;
+ *) qecho="$SHELL `pwd`/$progpath --fallback-echo";;
+ esac
+ qecho=`$echo "X$qecho" | $Xsed -e "$sed_quote_subst"`
+ else
+ qecho=`$echo "X$echo" | $Xsed -e "$sed_quote_subst"`
+ fi
+
+ # Only actually do things if our run command is non-null.
+ if test -z "$run"; then
+ # win32 will think the script is a binary if it has
+ # a .exe suffix, so we strip it off here.
+ case $output in
+ *.exe) output=`$echo $output|${SED} 's,.exe$,,'` ;;
+ esac
+ # test for cygwin because mv fails w/o .exe extensions
+ case $host in
+ *cygwin*)
+ exeext=.exe
+ outputname=`$echo $outputname|${SED} 's,.exe$,,'` ;;
+ *) exeext= ;;
+ esac
+ case $host in
+ *cygwin* | *mingw* )
+ cwrappersource=`$echo ${objdir}/lt-${output}.c`
+ cwrapper=`$echo ${output}.exe`
+ $rm $cwrappersource $cwrapper
+ trap "$rm $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15
+
+ cat > $cwrappersource <<EOF
+
+/* $cwrappersource - temporary wrapper executable for $objdir/$outputname
+ Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
+
+ The $output program cannot be directly executed until all the libtool
+ libraries that it depends on are installed.
+
+ This wrapper executable should never be moved out of the build directory.
+ If it is, it will not operate correctly.
+
+ Currently, it simply execs the wrapper *script* "/bin/sh $output",
+ but could eventually absorb all of the scripts functionality and
+ exec $objdir/$outputname directly.
+*/
+EOF
+ cat >> $cwrappersource<<"EOF"
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <malloc.h>
+#include <stdarg.h>
+#include <assert.h>
+
+#if defined(PATH_MAX)
+# define LT_PATHMAX PATH_MAX
+#elif defined(MAXPATHLEN)
+# define LT_PATHMAX MAXPATHLEN
+#else
+# define LT_PATHMAX 1024
+#endif
+
+#ifndef DIR_SEPARATOR
+#define DIR_SEPARATOR '/'
+#endif
+
+#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \
+ defined (__OS2__)
+#define HAVE_DOS_BASED_FILE_SYSTEM
+#ifndef DIR_SEPARATOR_2
+#define DIR_SEPARATOR_2 '\\'
+#endif
+#endif
+
+#ifndef DIR_SEPARATOR_2
+# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR)
+#else /* DIR_SEPARATOR_2 */
+# define IS_DIR_SEPARATOR(ch) \
+ (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
+#endif /* DIR_SEPARATOR_2 */
+
+#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type)))
+#define XFREE(stale) do { \
+ if (stale) { free ((void *) stale); stale = 0; } \
+} while (0)
+
+const char *program_name = NULL;
+
+void * xmalloc (size_t num);
+char * xstrdup (const char *string);
+char * basename (const char *name);
+char * fnqualify(const char *path);
+char * strendzap(char *str, const char *pat);
+void lt_fatal (const char *message, ...);
+
+int
+main (int argc, char *argv[])
+{
+ char **newargz;
+ int i;
+
+ program_name = (char *) xstrdup ((char *) basename (argv[0]));
+ newargz = XMALLOC(char *, argc+2);
+EOF
+
+ cat >> $cwrappersource <<EOF
+ newargz[0] = "$SHELL";
+EOF
+
+ cat >> $cwrappersource <<"EOF"
+ newargz[1] = fnqualify(argv[0]);
+ /* we know the script has the same name, without the .exe */
+ /* so make sure newargz[1] doesn't end in .exe */
+ strendzap(newargz[1],".exe");
+ for (i = 1; i < argc; i++)
+ newargz[i+1] = xstrdup(argv[i]);
+ newargz[argc+1] = NULL;
+EOF
+
+ cat >> $cwrappersource <<EOF
+ execv("$SHELL",newargz);
+EOF
+
+ cat >> $cwrappersource <<"EOF"
+}
+
+void *
+xmalloc (size_t num)
+{
+ void * p = (void *) malloc (num);
+ if (!p)
+ lt_fatal ("Memory exhausted");
+
+ return p;
+}
+
+char *
+xstrdup (const char *string)
+{
+ return string ? strcpy ((char *) xmalloc (strlen (string) + 1), string) : NULL
+;
+}
+
+char *
+basename (const char *name)
+{
+ const char *base;
+
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+ /* Skip over the disk name in MSDOS pathnames. */
+ if (isalpha (name[0]) && name[1] == ':')
+ name += 2;
+#endif
+
+ for (base = name; *name; name++)
+ if (IS_DIR_SEPARATOR (*name))
+ base = name + 1;
+ return (char *) base;
+}
+
+char *
+fnqualify(const char *path)
+{
+ size_t size;
+ char *p;
+ char tmp[LT_PATHMAX + 1];
+
+ assert(path != NULL);
+
+ /* Is it qualified already? */
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+ if (isalpha (path[0]) && path[1] == ':')
+ return xstrdup (path);
+#endif
+ if (IS_DIR_SEPARATOR (path[0]))
+ return xstrdup (path);
+
+ /* prepend the current directory */
+ /* doesn't handle '~' */
+ if (getcwd (tmp, LT_PATHMAX) == NULL)
+ lt_fatal ("getcwd failed");
+ size = strlen(tmp) + 1 + strlen(path) + 1; /* +2 for '/' and '\0' */
+ p = XMALLOC(char, size);
+ sprintf(p, "%s%c%s", tmp, DIR_SEPARATOR, path);
+ return p;
+}
+
+char *
+strendzap(char *str, const char *pat)
+{
+ size_t len, patlen;
+
+ assert(str != NULL);
+ assert(pat != NULL);
+
+ len = strlen(str);
+ patlen = strlen(pat);
+
+ if (patlen <= len)
+ {
+ str += len - patlen;
+ if (strcmp(str, pat) == 0)
+ *str = '\0';
+ }
+ return str;
+}
+
+static void
+lt_error_core (int exit_status, const char * mode,
+ const char * message, va_list ap)
+{
+ fprintf (stderr, "%s: %s: ", program_name, mode);
+ vfprintf (stderr, message, ap);
+ fprintf (stderr, ".\n");
+
+ if (exit_status >= 0)
+ exit (exit_status);
+}
+
+void
+lt_fatal (const char *message, ...)
+{
+ va_list ap;
+ va_start (ap, message);
+ lt_error_core (EXIT_FAILURE, "FATAL", message, ap);
+ va_end (ap);
+}
+EOF
+ # we should really use a build-platform specific compiler
+ # here, but OTOH, the wrappers (shell script and this C one)
+ # are only useful if you want to execute the "real" binary.
+ # Since the "real" binary is built for $host, then this
+ # wrapper might as well be built for $host, too.
+ $run $LTCC -s -o $cwrapper $cwrappersource
+ ;;
+ esac
+ $rm $output
+ trap "$rm $output; exit $EXIT_FAILURE" 1 2 15
+
+ $echo > $output "\
+#! $SHELL
+
+# $output - temporary wrapper script for $objdir/$outputname
+# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
+#
+# The $output program cannot be directly executed until all the libtool
+# libraries that it depends on are installed.
+#
+# This wrapper script should never be moved out of the build directory.
+# If it is, it will not operate correctly.
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed='${SED} -e 1s/^X//'
+sed_quote_subst='$sed_quote_subst'
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+if test \"\${CDPATH+set}\" = set; then CDPATH=:; export CDPATH; fi
+
+relink_command=\"$relink_command\"
+
+# This environment variable determines our operation mode.
+if test \"\$libtool_install_magic\" = \"$magic\"; then
+ # install mode needs the following variable:
+ notinst_deplibs='$notinst_deplibs'
+else
+ # When we are sourced in execute mode, \$file and \$echo are already set.
+ if test \"\$libtool_execute_magic\" != \"$magic\"; then
+ echo=\"$qecho\"
+ file=\"\$0\"
+ # Make sure echo works.
+ if test \"X\$1\" = X--no-reexec; then
+ # Discard the --no-reexec flag, and continue.
+ shift
+ elif test \"X\`(\$echo '\t') 2>/dev/null\`\" = 'X\t'; then
+ # Yippee, \$echo works!
+ :
+ else
+ # Restart under the correct shell, and then maybe \$echo will work.
+ exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"}
+ fi
+ fi\
+"
+ $echo >> $output "\
+
+ # Find the directory that this script lives in.
+ thisdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\`
+ test \"x\$thisdir\" = \"x\$file\" && thisdir=.
+
+ # Follow symbolic links until we get to the real thisdir.
+ file=\`ls -ld \"\$file\" | ${SED} -n 's/.*-> //p'\`
+ while test -n \"\$file\"; do
+ destdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\`
+
+ # If there was a directory component, then change thisdir.
+ if test \"x\$destdir\" != \"x\$file\"; then
+ case \"\$destdir\" in
+ [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;;
+ *) thisdir=\"\$thisdir/\$destdir\" ;;
+ esac
+ fi
+
+ file=\`\$echo \"X\$file\" | \$Xsed -e 's%^.*/%%'\`
+ file=\`ls -ld \"\$thisdir/\$file\" | ${SED} -n 's/.*-> //p'\`
+ done
+
+ # Try to get the absolute directory name.
+ absdir=\`cd \"\$thisdir\" && pwd\`
+ test -n \"\$absdir\" && thisdir=\"\$absdir\"
+"
+
+ if test "$fast_install" = yes; then
+ $echo >> $output "\
+ program=lt-'$outputname'$exeext
+ progdir=\"\$thisdir/$objdir\"
+
+ if test ! -f \"\$progdir/\$program\" || \\
+ { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\
+ test \"X\$file\" != \"X\$progdir/\$program\"; }; then
+
+ file=\"\$\$-\$program\"
+
+ if test ! -d \"\$progdir\"; then
+ $mkdir \"\$progdir\"
+ else
+ $rm \"\$progdir/\$file\"
+ fi"
+
+ $echo >> $output "\
+
+ # relink executable if necessary
+ if test -n \"\$relink_command\"; then
+ if relink_command_output=\`eval \$relink_command 2>&1\`; then :
+ else
+ $echo \"\$relink_command_output\" >&2
+ $rm \"\$progdir/\$file\"
+ exit $EXIT_FAILURE
+ fi
+ fi
+
+ $mv \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null ||
+ { $rm \"\$progdir/\$program\";
+ $mv \"\$progdir/\$file\" \"\$progdir/\$program\"; }
+ $rm \"\$progdir/\$file\"
+ fi"
+ else
+ $echo >> $output "\
+ program='$outputname'
+ progdir=\"\$thisdir/$objdir\"
+"
+ fi
+
+ $echo >> $output "\
+
+ if test -f \"\$progdir/\$program\"; then"
+
+ # Export our shlibpath_var if we have one.
+ if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+ $echo >> $output "\
+ # Add our own library path to $shlibpath_var
+ $shlibpath_var=\"$temp_rpath\$$shlibpath_var\"
+
+ # Some systems cannot cope with colon-terminated $shlibpath_var
+ # The second colon is a workaround for a bug in BeOS R4 sed
+ $shlibpath_var=\`\$echo \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\`
+
+ export $shlibpath_var
+"
+ fi
+
+ # fixup the dll searchpath if we need to.
+ if test -n "$dllsearchpath"; then
+ $echo >> $output "\
+ # Add the dll search path components to the executable PATH
+ PATH=$dllsearchpath:\$PATH
+"
+ fi
+
+ $echo >> $output "\
+ if test \"\$libtool_execute_magic\" != \"$magic\"; then
+ # Run the actual program with our arguments.
+"
+ case $host in
+ # Backslashes separate directories on plain windows
+ *-*-mingw | *-*-os2*)
+ $echo >> $output "\
+ exec \$progdir\\\\\$program \${1+\"\$@\"}
+"
+ ;;
+
+ *)
+ $echo >> $output "\
+ exec \$progdir/\$program \${1+\"\$@\"}
+"
+ ;;
+ esac
+ $echo >> $output "\
+ \$echo \"\$0: cannot exec \$program \${1+\"\$@\"}\"
+ exit $EXIT_FAILURE
+ fi
+ else
+ # The program doesn't exist.
+ \$echo \"\$0: error: \$progdir/\$program does not exist\" 1>&2
+ \$echo \"This script is just a wrapper for \$program.\" 1>&2
+ $echo \"See the $PACKAGE documentation for more information.\" 1>&2
+ exit $EXIT_FAILURE
+ fi
+fi\
+"
+ chmod +x $output
+ fi
+ exit $EXIT_SUCCESS
+ ;;
+ esac
+
+ # See if we need to build an old-fashioned archive.
+ for oldlib in $oldlibs; do
+
+ if test "$build_libtool_libs" = convenience; then
+ oldobjs="$libobjs_save"
+ addlibs="$convenience"
+ build_libtool_libs=no
+ else
+ if test "$build_libtool_libs" = module; then
+ oldobjs="$libobjs_save"
+ build_libtool_libs=no
+ else
+ oldobjs="$old_deplibs $non_pic_objects"
+ fi
+ addlibs="$old_convenience"
+ fi
+
+ if test -n "$addlibs"; then
+ gentop="$output_objdir/${outputname}x"
+ $show "${rm}r $gentop"
+ $run ${rm}r "$gentop"
+ $show "$mkdir $gentop"
+ $run $mkdir "$gentop"
+ status=$?
+ if test "$status" -ne 0 && test ! -d "$gentop"; then
+ exit $status
+ fi
+ generated="$generated $gentop"
+
+ # Add in members from convenience archives.
+ for xlib in $addlibs; do
+ # Extract the objects.
+ case $xlib in
+ [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;;
+ *) xabs=`pwd`"/$xlib" ;;
+ esac
+ xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'`
+ xdir="$gentop/$xlib"
+
+ $show "${rm}r $xdir"
+ $run ${rm}r "$xdir"
+ $show "$mkdir $xdir"
+ $run $mkdir "$xdir"
+ status=$?
+ if test "$status" -ne 0 && test ! -d "$xdir"; then
+ exit $status
+ fi
+ # We will extract separately just the conflicting names and we will no
+ # longer touch any unique names. It is faster to leave these extract
+ # automatically by $AR in one run.
+ $show "(cd $xdir && $AR x $xabs)"
+ $run eval "(cd \$xdir && $AR x \$xabs)" || exit $?
+ if ($AR t "$xabs" | sort | sort -uc >/dev/null 2>&1); then
+ :
+ else
+ $echo "$modename: warning: object name conflicts; renaming object files" 1>&2
+ $echo "$modename: warning: to ensure that they will not overwrite" 1>&2
+ $AR t "$xabs" | sort | uniq -cd | while read -r count name
+ do
+ i=1
+ while test "$i" -le "$count"
+ do
+ # Put our $i before any first dot (extension)
+ # Never overwrite any file
+ name_to="$name"
+ while test "X$name_to" = "X$name" || test -f "$xdir/$name_to"
+ do
+ name_to=`$echo "X$name_to" | $Xsed -e "s/\([^.]*\)/\1-$i/"`
+ done
+ $show "(cd $xdir && $AR xN $i $xabs '$name' && $mv '$name' '$name_to')"
+ $run eval "(cd \$xdir && $AR xN $i \$xabs '$name' && $mv '$name' '$name_to')" || exit $?
+ i=`expr $i + 1`
+ done
+ done
+ fi
+
+ oldobjs="$oldobjs "`find $xdir -name \*.${objext} -print -o -name \*.lo -print | $NL2SP`
+ done
+ fi
+
+ # Do each command in the archive commands.
+ if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then
+ cmds=$old_archive_from_new_cmds
+ else
+ eval cmds=\"$old_archive_cmds\"
+
+ if len=`expr "X$cmds" : ".*"` &&
+ test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+ cmds=$old_archive_cmds
+ else
+ # the command line is too long to link in one step, link in parts
+ $echo "using piecewise archive linking..."
+ save_RANLIB=$RANLIB
+ RANLIB=:
+ objlist=
+ concat_cmds=
+ save_oldobjs=$oldobjs
+ # GNU ar 2.10+ was changed to match POSIX; thus no paths are
+ # encoded into archives. This makes 'ar r' malfunction in
+ # this piecewise linking case whenever conflicting object
+ # names appear in distinct ar calls; check, warn and compensate.
+ if (for obj in $save_oldobjs
+ do
+ $echo "X$obj" | $Xsed -e 's%^.*/%%'
+ done | sort | sort -uc >/dev/null 2>&1); then
+ :
+ else
+ $echo "$modename: warning: object name conflicts; overriding AR_FLAGS to 'cq'" 1>&2
+ $echo "$modename: warning: to ensure that POSIX-compatible ar will work" 1>&2
+ AR_FLAGS=cq
+ fi
+ # Is there a better way of finding the last object in the list?
+ for obj in $save_oldobjs
+ do
+ last_oldobj=$obj
+ done
+ for obj in $save_oldobjs
+ do
+ oldobjs="$objlist $obj"
+ objlist="$objlist $obj"
+ eval test_cmds=\"$old_archive_cmds\"
+ if len=`expr "X$test_cmds" : ".*"` &&
+ test "$len" -le "$max_cmd_len"; then
+ :
+ else
+ # the above command should be used before it gets too long
+ oldobjs=$objlist
+ if test "$obj" = "$last_oldobj" ; then
+ RANLIB=$save_RANLIB
+ fi
+ test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+ eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\"
+ objlist=
+ fi
+ done
+ RANLIB=$save_RANLIB
+ oldobjs=$objlist
+ if test "X$oldobjs" = "X" ; then
+ eval cmds=\"\$concat_cmds\"
+ else
+ eval cmds=\"\$concat_cmds~\$old_archive_cmds\"
+ fi
+ fi
+ fi
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ eval cmd=\"$cmd\"
+ IFS="$save_ifs"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+ done
+
+ if test -n "$generated"; then
+ $show "${rm}r$generated"
+ $run ${rm}r$generated
+ fi
+
+ # Now create the libtool archive.
+ case $output in
+ *.la)
+ old_library=
+ test "$build_old_libs" = yes && old_library="$libname.$libext"
+ $show "creating $output"
+
+ # Preserve any variables that may affect compiler behavior
+ for var in $variables_saved_for_relink; do
+ if eval test -z \"\${$var+set}\"; then
+ relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command"
+ elif eval var_value=\$$var; test -z "$var_value"; then
+ relink_command="$var=; export $var; $relink_command"
+ else
+ var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"`
+ relink_command="$var=\"$var_value\"; export $var; $relink_command"
+ fi
+ done
+ # Quote the link command for shipping.
+ relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)"
+ relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"`
+ if test "$hardcode_automatic" = yes ; then
+ relink_command=
+ fi
+
+
+ # Only create the output if not a dry run.
+ if test -z "$run"; then
+ for installed in no yes; do
+ if test "$installed" = yes; then
+ if test -z "$install_libdir"; then
+ break
+ fi
+ output="$output_objdir/$outputname"i
+ # Replace all uninstalled libtool libraries with the installed ones
+ newdependency_libs=
+ for deplib in $dependency_libs; do
+ case $deplib in
+ *.la)
+ name=`$echo "X$deplib" | $Xsed -e 's%^.*/%%'`
+ eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
+ if test -z "$libdir"; then
+ $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2
+ exit $EXIT_FAILURE
+ fi
+ newdependency_libs="$newdependency_libs $libdir/$name"
+ ;;
+ *) newdependency_libs="$newdependency_libs $deplib" ;;
+ esac
+ done
+ dependency_libs="$newdependency_libs"
+ newdlfiles=
+ for lib in $dlfiles; do
+ name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'`
+ eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+ if test -z "$libdir"; then
+ $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
+ exit $EXIT_FAILURE
+ fi
+ newdlfiles="$newdlfiles $libdir/$name"
+ done
+ dlfiles="$newdlfiles"
+ newdlprefiles=
+ for lib in $dlprefiles; do
+ name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'`
+ eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+ if test -z "$libdir"; then
+ $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
+ exit $EXIT_FAILURE
+ fi
+ newdlprefiles="$newdlprefiles $libdir/$name"
+ done
+ dlprefiles="$newdlprefiles"
+ else
+ newdlfiles=
+ for lib in $dlfiles; do
+ case $lib in
+ [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
+ *) abs=`pwd`"/$lib" ;;
+ esac
+ newdlfiles="$newdlfiles $abs"
+ done
+ dlfiles="$newdlfiles"
+ newdlprefiles=
+ for lib in $dlprefiles; do
+ case $lib in
+ [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
+ *) abs=`pwd`"/$lib" ;;
+ esac
+ newdlprefiles="$newdlprefiles $abs"
+ done
+ dlprefiles="$newdlprefiles"
+ fi
+ $rm $output
+ # place dlname in correct position for cygwin
+ tdlname=$dlname
+ case $host,$output,$installed,$module,$dlname in
+ *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;;
+ esac
+ $echo > $output "\
+# $outputname - a libtool library file
+# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# The name that we can dlopen(3).
+dlname='$tdlname'
+
+# Names of this library.
+library_names='$library_names'
+
+# The name of the static archive.
+old_library='$old_library'
+
+# Libraries that this one depends upon.
+dependency_libs='$dependency_libs'
+
+# Version information for $libname.
+current=$current
+age=$age
+revision=$revision
+
+# Is this an already installed library?
+installed=$installed
+
+# Should we warn about portability when linking against -modules?
+shouldnotlink=$module
+
+# Files to dlopen/dlpreopen
+dlopen='$dlfiles'
+dlpreopen='$dlprefiles'
+
+# Directory that this library needs to be installed in:
+libdir='$install_libdir'"
+ if test "$installed" = no && test "$need_relink" = yes; then
+ $echo >> $output "\
+relink_command=\"$relink_command\""
+ fi
+ done
+ fi
+
+ # Do a symbolic link so that the libtool archive can be found in
+ # LD_LIBRARY_PATH before the program is installed.
+ $show "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)"
+ $run eval '(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)' || exit $?
+ ;;
+ esac
+ exit $EXIT_SUCCESS
+ ;;
+
+ # libtool install mode
+ install)
+ modename="$modename: install"
+
+ # There may be an optional sh(1) argument at the beginning of
+ # install_prog (especially on Windows NT).
+ if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh ||
+ # Allow the use of GNU shtool's install command.
+ $echo "X$nonopt" | $Xsed | grep shtool > /dev/null; then
+ # Aesthetically quote it.
+ arg=`$echo "X$nonopt" | $Xsed -e "$sed_quote_subst"`
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*)
+ arg="\"$arg\""
+ ;;
+ esac
+ install_prog="$arg "
+ arg="$1"
+ shift
+ else
+ install_prog=
+ arg="$nonopt"
+ fi
+
+ # The real first argument should be the name of the installation program.
+ # Aesthetically quote it.
+ arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*)
+ arg="\"$arg\""
+ ;;
+ esac
+ install_prog="$install_prog$arg"
+
+ # We need to accept at least all the BSD install flags.
+ dest=
+ files=
+ opts=
+ prev=
+ install_type=
+ isdir=no
+ stripme=
+ for arg
+ do
+ if test -n "$dest"; then
+ files="$files $dest"
+ dest="$arg"
+ continue
+ fi
+
+ case $arg in
+ -d) isdir=yes ;;
+ -f) prev="-f" ;;
+ -g) prev="-g" ;;
+ -m) prev="-m" ;;
+ -o) prev="-o" ;;
+ -s)
+ stripme=" -s"
+ continue
+ ;;
+ -*) ;;
+
+ *)
+ # If the previous option needed an argument, then skip it.
+ if test -n "$prev"; then
+ prev=
+ else
+ dest="$arg"
+ continue
+ fi
+ ;;
+ esac
+
+ # Aesthetically quote the argument.
+ arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*)
+ arg="\"$arg\""
+ ;;
+ esac
+ install_prog="$install_prog $arg"
+ done
+
+ if test -z "$install_prog"; then
+ $echo "$modename: you must specify an install program" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ if test -n "$prev"; then
+ $echo "$modename: the \`$prev' option requires an argument" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ if test -z "$files"; then
+ if test -z "$dest"; then
+ $echo "$modename: no file or destination specified" 1>&2
+ else
+ $echo "$modename: you must specify a destination" 1>&2
+ fi
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ # Strip any trailing slash from the destination.
+ dest=`$echo "X$dest" | $Xsed -e 's%/$%%'`
+
+ # Check to see that the destination is a directory.
+ test -d "$dest" && isdir=yes
+ if test "$isdir" = yes; then
+ destdir="$dest"
+ destname=
+ else
+ destdir=`$echo "X$dest" | $Xsed -e 's%/[^/]*$%%'`
+ test "X$destdir" = "X$dest" && destdir=.
+ destname=`$echo "X$dest" | $Xsed -e 's%^.*/%%'`
+
+ # Not a directory, so check to see that there is only one file specified.
+ set dummy $files
+ if test "$#" -gt 2; then
+ $echo "$modename: \`$dest' is not a directory" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+ fi
+ case $destdir in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ for file in $files; do
+ case $file in
+ *.lo) ;;
+ *)
+ $echo "$modename: \`$destdir' must be an absolute directory name" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ esac
+ done
+ ;;
+ esac
+
+ # This variable tells wrapper scripts just to set variables rather
+ # than running their programs.
+ libtool_install_magic="$magic"
+
+ staticlibs=
+ future_libdirs=
+ current_libdirs=
+ for file in $files; do
+
+ # Do each installation.
+ case $file in
+ *.$libext)
+ # Do the static libraries later.
+ staticlibs="$staticlibs $file"
+ ;;
+
+ *.la)
+ # Check to see that this really is a libtool archive.
+ if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
+ else
+ $echo "$modename: \`$file' is not a valid libtool archive" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ library_names=
+ old_library=
+ relink_command=
+ # If there is no directory component, then add one.
+ case $file in
+ */* | *\\*) . $file ;;
+ *) . ./$file ;;
+ esac
+
+ # Add the libdir to current_libdirs if it is the destination.
+ if test "X$destdir" = "X$libdir"; then
+ case "$current_libdirs " in
+ *" $libdir "*) ;;
+ *) current_libdirs="$current_libdirs $libdir" ;;
+ esac
+ else
+ # Note the libdir as a future libdir.
+ case "$future_libdirs " in
+ *" $libdir "*) ;;
+ *) future_libdirs="$future_libdirs $libdir" ;;
+ esac
+ fi
+
+ dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`/
+ test "X$dir" = "X$file/" && dir=
+ dir="$dir$objdir"
+
+ if test -n "$relink_command"; then
+ # Determine the prefix the user has applied to our future dir.
+ inst_prefix_dir=`$echo "$destdir" | $SED "s%$libdir\$%%"`
+
+ # Don't allow the user to place us outside of our expected
+ # location b/c this prevents finding dependent libraries that
+ # are installed to the same prefix.
+ # At present, this check doesn't affect windows .dll's that
+ # are installed into $libdir/../bin (currently, that works fine)
+ # but it's something to keep an eye on.
+ if test "$inst_prefix_dir" = "$destdir"; then
+ $echo "$modename: error: cannot install \`$file' to a directory not ending in $libdir" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ if test -n "$inst_prefix_dir"; then
+ # Stick the inst_prefix_dir data into the link command.
+ relink_command=`$echo "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"`
+ else
+ relink_command=`$echo "$relink_command" | $SED "s%@inst_prefix_dir@%%"`
+ fi
+
+ $echo "$modename: warning: relinking \`$file'" 1>&2
+ $show "$relink_command"
+ if $run eval "$relink_command"; then :
+ else
+ $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2
+ exit $EXIT_FAILURE
+ fi
+ fi
+
+ # See the names of the shared library.
+ set dummy $library_names
+ if test -n "$2"; then
+ realname="$2"
+ shift
+ shift
+
+ srcname="$realname"
+ test -n "$relink_command" && srcname="$realname"T
+
+ # Install the shared library and build the symlinks.
+ $show "$install_prog $dir/$srcname $destdir/$realname"
+ $run eval "$install_prog $dir/$srcname $destdir/$realname" || exit $?
+ if test -n "$stripme" && test -n "$striplib"; then
+ $show "$striplib $destdir/$realname"
+ $run eval "$striplib $destdir/$realname" || exit $?
+ fi
+
+ if test "$#" -gt 0; then
+ # Delete the old symlinks, and create new ones.
+ for linkname
+ do
+ if test "$linkname" != "$realname"; then
+ $show "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)"
+ $run eval "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)"
+ fi
+ done
+ fi
+
+ # Do each command in the postinstall commands.
+ lib="$destdir/$realname"
+ cmds=$postinstall_cmds
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+ fi
+
+ # Install the pseudo-library for information purposes.
+ name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+ instname="$dir/$name"i
+ $show "$install_prog $instname $destdir/$name"
+ $run eval "$install_prog $instname $destdir/$name" || exit $?
+
+ # Maybe install the static library, too.
+ test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library"
+ ;;
+
+ *.lo)
+ # Install (i.e. copy) a libtool object.
+
+ # Figure out destination file name, if it wasn't already specified.
+ if test -n "$destname"; then
+ destfile="$destdir/$destname"
+ else
+ destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+ destfile="$destdir/$destfile"
+ fi
+
+ # Deduce the name of the destination old-style object file.
+ case $destfile in
+ *.lo)
+ staticdest=`$echo "X$destfile" | $Xsed -e "$lo2o"`
+ ;;
+ *.$objext)
+ staticdest="$destfile"
+ destfile=
+ ;;
+ *)
+ $echo "$modename: cannot copy a libtool object to \`$destfile'" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ esac
+
+ # Install the libtool object if requested.
+ if test -n "$destfile"; then
+ $show "$install_prog $file $destfile"
+ $run eval "$install_prog $file $destfile" || exit $?
+ fi
+
+ # Install the old object if enabled.
+ if test "$build_old_libs" = yes; then
+ # Deduce the name of the old-style object file.
+ staticobj=`$echo "X$file" | $Xsed -e "$lo2o"`
+
+ $show "$install_prog $staticobj $staticdest"
+ $run eval "$install_prog \$staticobj \$staticdest" || exit $?
+ fi
+ exit $EXIT_SUCCESS
+ ;;
+
+ *)
+ # Figure out destination file name, if it wasn't already specified.
+ if test -n "$destname"; then
+ destfile="$destdir/$destname"
+ else
+ destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+ destfile="$destdir/$destfile"
+ fi
+
+ # If the file is missing, and there is a .exe on the end, strip it
+ # because it is most likely a libtool script we actually want to
+ # install
+ stripped_ext=""
+ case $file in
+ *.exe)
+ if test ! -f "$file"; then
+ file=`$echo $file|${SED} 's,.exe$,,'`
+ stripped_ext=".exe"
+ fi
+ ;;
+ esac
+
+ # Do a test to see if this is really a libtool program.
+ case $host in
+ *cygwin*|*mingw*)
+ wrapper=`$echo $file | ${SED} -e 's,.exe$,,'`
+ ;;
+ *)
+ wrapper=$file
+ ;;
+ esac
+ if (${SED} -e '4q' $wrapper | grep "^# Generated by .*$PACKAGE")>/dev/null 2>&1; then
+ notinst_deplibs=
+ relink_command=
+
+ # To insure that "foo" is sourced, and not "foo.exe",
+ # finese the cygwin/MSYS system by explicitly sourcing "foo."
+ # which disallows the automatic-append-.exe behavior.
+ case $build in
+ *cygwin* | *mingw*) wrapperdot=${wrapper}. ;;
+ *) wrapperdot=${wrapper} ;;
+ esac
+ # If there is no directory component, then add one.
+ case $file in
+ */* | *\\*) . ${wrapperdot} ;;
+ *) . ./${wrapperdot} ;;
+ esac
+
+ # Check the variables that should have been set.
+ if test -z "$notinst_deplibs"; then
+ $echo "$modename: invalid libtool wrapper script \`$wrapper'" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ finalize=yes
+ for lib in $notinst_deplibs; do
+ # Check to see that each library is installed.
+ libdir=
+ if test -f "$lib"; then
+ # If there is no directory component, then add one.
+ case $lib in
+ */* | *\\*) . $lib ;;
+ *) . ./$lib ;;
+ esac
+ fi
+ libfile="$libdir/"`$echo "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test
+ if test -n "$libdir" && test ! -f "$libfile"; then
+ $echo "$modename: warning: \`$lib' has not been installed in \`$libdir'" 1>&2
+ finalize=no
+ fi
+ done
+
+ relink_command=
+ # To insure that "foo" is sourced, and not "foo.exe",
+ # finese the cygwin/MSYS system by explicitly sourcing "foo."
+ # which disallows the automatic-append-.exe behavior.
+ case $build in
+ *cygwin* | *mingw*) wrapperdot=${wrapper}. ;;
+ *) wrapperdot=${wrapper} ;;
+ esac
+ # If there is no directory component, then add one.
+ case $file in
+ */* | *\\*) . ${wrapperdot} ;;
+ *) . ./${wrapperdot} ;;
+ esac
+
+ outputname=
+ if test "$fast_install" = no && test -n "$relink_command"; then
+ if test "$finalize" = yes && test -z "$run"; then
+ tmpdir="/tmp"
+ test -n "$TMPDIR" && tmpdir="$TMPDIR"
+ tmpdir="$tmpdir/libtool-$$"
+ save_umask=`umask`
+ umask 0077
+ if $mkdir "$tmpdir"; then
+ umask $save_umask
+ else
+ umask $save_umask
+ $echo "$modename: error: cannot create temporary directory \`$tmpdir'" 1>&2
+ continue
+ fi
+ file=`$echo "X$file$stripped_ext" | $Xsed -e 's%^.*/%%'`
+ outputname="$tmpdir/$file"
+ # Replace the output file specification.
+ relink_command=`$echo "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'`
+
+ $show "$relink_command"
+ if $run eval "$relink_command"; then :
+ else
+ $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2
+ ${rm}r "$tmpdir"
+ continue
+ fi
+ file="$outputname"
+ else
+ $echo "$modename: warning: cannot relink \`$file'" 1>&2
+ fi
+ else
+ # Install the binary that we compiled earlier.
+ file=`$echo "X$file$stripped_ext" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"`
+ fi
+ fi
+
+ # remove .exe since cygwin /usr/bin/install will append another
+ # one anyways
+ case $install_prog,$host in
+ */usr/bin/install*,*cygwin*)
+ case $file:$destfile in
+ *.exe:*.exe)
+ # this is ok
+ ;;
+ *.exe:*)
+ destfile=$destfile.exe
+ ;;
+ *:*.exe)
+ destfile=`$echo $destfile | ${SED} -e 's,.exe$,,'`
+ ;;
+ esac
+ ;;
+ esac
+ $show "$install_prog$stripme $file $destfile"
+ $run eval "$install_prog\$stripme \$file \$destfile" || exit $?
+ test -n "$outputname" && ${rm}r "$tmpdir"
+ ;;
+ esac
+ done
+
+ for file in $staticlibs; do
+ name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+
+ # Set up the ranlib parameters.
+ oldlib="$destdir/$name"
+
+ $show "$install_prog $file $oldlib"
+ $run eval "$install_prog \$file \$oldlib" || exit $?
+
+ if test -n "$stripme" && test -n "$old_striplib"; then
+ $show "$old_striplib $oldlib"
+ $run eval "$old_striplib $oldlib" || exit $?
+ fi
+
+ # Do each command in the postinstall commands.
+ cmds=$old_postinstall_cmds
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+ done
+
+ if test -n "$future_libdirs"; then
+ $echo "$modename: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2
+ fi
+
+ if test -n "$current_libdirs"; then
+ # Maybe just do a dry run.
+ test -n "$run" && current_libdirs=" -n$current_libdirs"
+ exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs'
+ else
+ exit $EXIT_SUCCESS
+ fi
+ ;;
+
+ # libtool finish mode
+ finish)
+ modename="$modename: finish"
+ libdirs="$nonopt"
+ admincmds=
+
+ if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
+ for dir
+ do
+ libdirs="$libdirs $dir"
+ done
+
+ for libdir in $libdirs; do
+ if test -n "$finish_cmds"; then
+ # Do each command in the finish commands.
+ cmds=$finish_cmds
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ $show "$cmd"
+ $run eval "$cmd" || admincmds="$admincmds
+ $cmd"
+ done
+ IFS="$save_ifs"
+ fi
+ if test -n "$finish_eval"; then
+ # Do the single finish_eval.
+ eval cmds=\"$finish_eval\"
+ $run eval "$cmds" || admincmds="$admincmds
+ $cmds"
+ fi
+ done
+ fi
+
+ # Exit here if they wanted silent mode.
+ test "$show" = : && exit $EXIT_SUCCESS
+
+ $echo "----------------------------------------------------------------------"
+ $echo "Libraries have been installed in:"
+ for libdir in $libdirs; do
+ $echo " $libdir"
+ done
+ $echo
+ $echo "If you ever happen to want to link against installed libraries"
+ $echo "in a given directory, LIBDIR, you must either use libtool, and"
+ $echo "specify the full pathname of the library, or use the \`-LLIBDIR'"
+ $echo "flag during linking and do at least one of the following:"
+ if test -n "$shlibpath_var"; then
+ $echo " - add LIBDIR to the \`$shlibpath_var' environment variable"
+ $echo " during execution"
+ fi
+ if test -n "$runpath_var"; then
+ $echo " - add LIBDIR to the \`$runpath_var' environment variable"
+ $echo " during linking"
+ fi
+ if test -n "$hardcode_libdir_flag_spec"; then
+ libdir=LIBDIR
+ eval flag=\"$hardcode_libdir_flag_spec\"
+
+ $echo " - use the \`$flag' linker flag"
+ fi
+ if test -n "$admincmds"; then
+ $echo " - have your system administrator run these commands:$admincmds"
+ fi
+ if test -f /etc/ld.so.conf; then
+ $echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'"
+ fi
+ $echo
+ $echo "See any operating system documentation about shared libraries for"
+ $echo "more information, such as the ld(1) and ld.so(8) manual pages."
+ $echo "----------------------------------------------------------------------"
+ exit $EXIT_SUCCESS
+ ;;
+
+ # libtool execute mode
+ execute)
+ modename="$modename: execute"
+
+ # The first argument is the command name.
+ cmd="$nonopt"
+ if test -z "$cmd"; then
+ $echo "$modename: you must specify a COMMAND" 1>&2
+ $echo "$help"
+ exit $EXIT_FAILURE
+ fi
+
+ # Handle -dlopen flags immediately.
+ for file in $execute_dlfiles; do
+ if test ! -f "$file"; then
+ $echo "$modename: \`$file' is not a file" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ dir=
+ case $file in
+ *.la)
+ # Check to see that this really is a libtool archive.
+ if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
+ else
+ $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ # Read the libtool library.
+ dlname=
+ library_names=
+
+ # If there is no directory component, then add one.
+ case $file in
+ */* | *\\*) . $file ;;
+ *) . ./$file ;;
+ esac
+
+ # Skip this library if it cannot be dlopened.
+ if test -z "$dlname"; then
+ # Warn if it was a shared library.
+ test -n "$library_names" && $echo "$modename: warning: \`$file' was not linked with \`-export-dynamic'"
+ continue
+ fi
+
+ dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
+ test "X$dir" = "X$file" && dir=.
+
+ if test -f "$dir/$objdir/$dlname"; then
+ dir="$dir/$objdir"
+ else
+ $echo "$modename: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2
+ exit $EXIT_FAILURE
+ fi
+ ;;
+
+ *.lo)
+ # Just add the directory containing the .lo file.
+ dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
+ test "X$dir" = "X$file" && dir=.
+ ;;
+
+ *)
+ $echo "$modename: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2
+ continue
+ ;;
+ esac
+
+ # Get the absolute pathname.
+ absdir=`cd "$dir" && pwd`
+ test -n "$absdir" && dir="$absdir"
+
+ # Now add the directory to shlibpath_var.
+ if eval "test -z \"\$$shlibpath_var\""; then
+ eval "$shlibpath_var=\"\$dir\""
+ else
+ eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\""
+ fi
+ done
+
+ # This variable tells wrapper scripts just to set shlibpath_var
+ # rather than running their programs.
+ libtool_execute_magic="$magic"
+
+ # Check if any of the arguments is a wrapper script.
+ args=
+ for file
+ do
+ case $file in
+ -*) ;;
+ *)
+ # Do a test to see if this is really a libtool program.
+ if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+ # If there is no directory component, then add one.
+ case $file in
+ */* | *\\*) . $file ;;
+ *) . ./$file ;;
+ esac
+
+ # Transform arg to wrapped name.
+ file="$progdir/$program"
+ fi
+ ;;
+ esac
+ # Quote arguments (to preserve shell metacharacters).
+ file=`$echo "X$file" | $Xsed -e "$sed_quote_subst"`
+ args="$args \"$file\""
+ done
+
+ if test -z "$run"; then
+ if test -n "$shlibpath_var"; then
+ # Export the shlibpath_var.
+ eval "export $shlibpath_var"
+ fi
+
+ # Restore saved environment variables
+ if test "${save_LC_ALL+set}" = set; then
+ LC_ALL="$save_LC_ALL"; export LC_ALL
+ fi
+ if test "${save_LANG+set}" = set; then
+ LANG="$save_LANG"; export LANG
+ fi
+
+ # Now prepare to actually exec the command.
+ exec_cmd="\$cmd$args"
+ else
+ # Display what would be done.
+ if test -n "$shlibpath_var"; then
+ eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\""
+ $echo "export $shlibpath_var"
+ fi
+ $echo "$cmd$args"
+ exit $EXIT_SUCCESS
+ fi
+ ;;
+
+ # libtool clean and uninstall mode
+ clean | uninstall)
+ modename="$modename: $mode"
+ rm="$nonopt"
+ files=
+ rmforce=
+ exit_status=0
+
+ # This variable tells wrapper scripts just to set variables rather
+ # than running their programs.
+ libtool_install_magic="$magic"
+
+ for arg
+ do
+ case $arg in
+ -f) rm="$rm $arg"; rmforce=yes ;;
+ -*) rm="$rm $arg" ;;
+ *) files="$files $arg" ;;
+ esac
+ done
+
+ if test -z "$rm"; then
+ $echo "$modename: you must specify an RM program" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ rmdirs=
+
+ origobjdir="$objdir"
+ for file in $files; do
+ dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$dir" = "X$file"; then
+ dir=.
+ objdir="$origobjdir"
+ else
+ objdir="$dir/$origobjdir"
+ fi
+ name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+ test "$mode" = uninstall && objdir="$dir"
+
+ # Remember objdir for removal later, being careful to avoid duplicates
+ if test "$mode" = clean; then
+ case " $rmdirs " in
+ *" $objdir "*) ;;
+ *) rmdirs="$rmdirs $objdir" ;;
+ esac
+ fi
+
+ # Don't error if the file doesn't exist and rm -f was used.
+ if (test -L "$file") >/dev/null 2>&1 \
+ || (test -h "$file") >/dev/null 2>&1 \
+ || test -f "$file"; then
+ :
+ elif test -d "$file"; then
+ exit_status=1
+ continue
+ elif test "$rmforce" = yes; then
+ continue
+ fi
+
+ rmfiles="$file"
+
+ case $name in
+ *.la)
+ # Possibly a libtool archive, so verify it.
+ if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+ . $dir/$name
+
+ # Delete the libtool libraries and symlinks.
+ for n in $library_names; do
+ rmfiles="$rmfiles $objdir/$n"
+ done
+ test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library"
+ test "$mode" = clean && rmfiles="$rmfiles $objdir/$name $objdir/${name}i"
+
+ if test "$mode" = uninstall; then
+ if test -n "$library_names"; then
+ # Do each command in the postuninstall commands.
+ cmds=$postuninstall_cmds
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ $show "$cmd"
+ $run eval "$cmd"
+ if test "$?" -ne 0 && test "$rmforce" != yes; then
+ exit_status=1
+ fi
+ done
+ IFS="$save_ifs"
+ fi
+
+ if test -n "$old_library"; then
+ # Do each command in the old_postuninstall commands.
+ cmds=$old_postuninstall_cmds
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ $show "$cmd"
+ $run eval "$cmd"
+ if test "$?" -ne 0 && test "$rmforce" != yes; then
+ exit_status=1
+ fi
+ done
+ IFS="$save_ifs"
+ fi
+ # FIXME: should reinstall the best remaining shared library.
+ fi
+ fi
+ ;;
+
+ *.lo)
+ # Possibly a libtool object, so verify it.
+ if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+
+ # Read the .lo file
+ . $dir/$name
+
+ # Add PIC object to the list of files to remove.
+ if test -n "$pic_object" \
+ && test "$pic_object" != none; then
+ rmfiles="$rmfiles $dir/$pic_object"
+ fi
+
+ # Add non-PIC object to the list of files to remove.
+ if test -n "$non_pic_object" \
+ && test "$non_pic_object" != none; then
+ rmfiles="$rmfiles $dir/$non_pic_object"
+ fi
+ fi
+ ;;
+
+ *)
+ if test "$mode" = clean ; then
+ noexename=$name
+ case $file in
+ *.exe)
+ file=`$echo $file|${SED} 's,.exe$,,'`
+ noexename=`$echo $name|${SED} 's,.exe$,,'`
+ # $file with .exe has already been added to rmfiles,
+ # add $file without .exe
+ rmfiles="$rmfiles $file"
+ ;;
+ esac
+ # Do a test to see if this is a libtool program.
+ if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+ relink_command=
+ . $dir/$noexename
+
+ # note $name still contains .exe if it was in $file originally
+ # as does the version of $file that was added into $rmfiles
+ rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}"
+ if test "$fast_install" = yes && test -n "$relink_command"; then
+ rmfiles="$rmfiles $objdir/lt-$name"
+ fi
+ if test "X$noexename" != "X$name" ; then
+ rmfiles="$rmfiles $objdir/lt-${noexename}.c"
+ fi
+ fi
+ fi
+ ;;
+ esac
+ $show "$rm $rmfiles"
+ $run $rm $rmfiles || exit_status=1
+ done
+ objdir="$origobjdir"
+
+ # Try to remove the ${objdir}s in the directories where we deleted files
+ for dir in $rmdirs; do
+ if test -d "$dir"; then
+ $show "rmdir $dir"
+ $run rmdir $dir >/dev/null 2>&1
+ fi
+ done
+
+ exit $exit_status
+ ;;
+
+ "")
+ $echo "$modename: you must specify a MODE" 1>&2
+ $echo "$generic_help" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ esac
+
+ if test -z "$exec_cmd"; then
+ $echo "$modename: invalid operation mode \`$mode'" 1>&2
+ $echo "$generic_help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+fi # test -z "$show_help"
+
+if test -n "$exec_cmd"; then
+ eval exec $exec_cmd
+ exit $EXIT_FAILURE
+fi
+
+# We need to display help for each of the modes.
+case $mode in
+"") $echo \
+"Usage: $modename [OPTION]... [MODE-ARG]...
+
+Provide generalized library-building support services.
+
+ --config show all configuration variables
+ --debug enable verbose shell tracing
+-n, --dry-run display commands without modifying any files
+ --features display basic configuration information and exit
+ --finish same as \`--mode=finish'
+ --help display this help message and exit
+ --mode=MODE use operation mode MODE [default=inferred from MODE-ARGS]
+ --quiet same as \`--silent'
+ --silent don't print informational messages
+ --tag=TAG use configuration variables from tag TAG
+ --version print version information
+
+MODE must be one of the following:
+
+ clean remove files from the build directory
+ compile compile a source file into a libtool object
+ execute automatically set library path, then run a program
+ finish complete the installation of libtool libraries
+ install install libraries or executables
+ link create a library or an executable
+ uninstall remove libraries from an installed directory
+
+MODE-ARGS vary depending on the MODE. Try \`$modename --help --mode=MODE' for
+a more detailed description of MODE.
+
+Report bugs to <bug-libtool at gnu.org>."
+ exit $EXIT_SUCCESS
+ ;;
+
+clean)
+ $echo \
+"Usage: $modename [OPTION]... --mode=clean RM [RM-OPTION]... FILE...
+
+Remove files from the build directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, object or program, all the files associated
+with it are deleted. Otherwise, only FILE itself is deleted using RM."
+ ;;
+
+compile)
+ $echo \
+"Usage: $modename [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE
+
+Compile a source file into a libtool library object.
+
+This mode accepts the following additional options:
+
+ -o OUTPUT-FILE set the output file name to OUTPUT-FILE
+ -prefer-pic try to building PIC objects only
+ -prefer-non-pic try to building non-PIC objects only
+ -static always build a \`.o' file suitable for static linking
+
+COMPILE-COMMAND is a command to be used in creating a \`standard' object file
+from the given SOURCEFILE.
+
+The output file name is determined by removing the directory component from
+SOURCEFILE, then substituting the C source code suffix \`.c' with the
+library object suffix, \`.lo'."
+ ;;
+
+execute)
+ $echo \
+"Usage: $modename [OPTION]... --mode=execute COMMAND [ARGS]...
+
+Automatically set library path, then run a program.
+
+This mode accepts the following additional options:
+
+ -dlopen FILE add the directory containing FILE to the library path
+
+This mode sets the library path environment variable according to \`-dlopen'
+flags.
+
+If any of the ARGS are libtool executable wrappers, then they are translated
+into their corresponding uninstalled binary, and any of their required library
+directories are added to the library path.
+
+Then, COMMAND is executed, with ARGS as arguments."
+ ;;
+
+finish)
+ $echo \
+"Usage: $modename [OPTION]... --mode=finish [LIBDIR]...
+
+Complete the installation of libtool libraries.
+
+Each LIBDIR is a directory that contains libtool libraries.
+
+The commands that this mode executes may require superuser privileges. Use
+the \`--dry-run' option if you just want to see what would be executed."
+ ;;
+
+install)
+ $echo \
+"Usage: $modename [OPTION]... --mode=install INSTALL-COMMAND...
+
+Install executables or libraries.
+
+INSTALL-COMMAND is the installation command. The first component should be
+either the \`install' or \`cp' program.
+
+The rest of the components are interpreted as arguments to that command (only
+BSD-compatible install options are recognized)."
+ ;;
+
+link)
+ $echo \
+"Usage: $modename [OPTION]... --mode=link LINK-COMMAND...
+
+Link object files or libraries together to form another library, or to
+create an executable program.
+
+LINK-COMMAND is a command using the C compiler that you would use to create
+a program from several object files.
+
+The following components of LINK-COMMAND are treated specially:
+
+ -all-static do not do any dynamic linking at all
+ -avoid-version do not add a version suffix if possible
+ -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime
+ -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols
+ -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3)
+ -export-symbols SYMFILE
+ try to export only the symbols listed in SYMFILE
+ -export-symbols-regex REGEX
+ try to export only the symbols matching REGEX
+ -LLIBDIR search LIBDIR for required installed libraries
+ -lNAME OUTPUT-FILE requires the installed library libNAME
+ -module build a library that can dlopened
+ -no-fast-install disable the fast-install mode
+ -no-install link a not-installable executable
+ -no-undefined declare that a library does not refer to external symbols
+ -o OUTPUT-FILE create OUTPUT-FILE from the specified objects
+ -objectlist FILE Use a list of object files found in FILE to specify objects
+ -precious-files-regex REGEX
+ don't remove output files matching REGEX
+ -release RELEASE specify package release information
+ -rpath LIBDIR the created library will eventually be installed in LIBDIR
+ -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries
+ -static do not do any dynamic linking of libtool libraries
+ -version-info CURRENT[:REVISION[:AGE]]
+ specify library version info [each variable defaults to 0]
+
+All other options (arguments beginning with \`-') are ignored.
+
+Every other argument is treated as a filename. Files ending in \`.la' are
+treated as uninstalled libtool libraries, other files are standard or library
+object files.
+
+If the OUTPUT-FILE ends in \`.la', then a libtool library is created,
+only library objects (\`.lo' files) may be specified, and \`-rpath' is
+required, except when creating a convenience library.
+
+If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created
+using \`ar' and \`ranlib', or on Windows using \`lib'.
+
+If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file
+is created, otherwise an executable program is created."
+ ;;
+
+uninstall)
+ $echo \
+"Usage: $modename [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE...
+
+Remove libraries from an installation directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, all the files associated with it are deleted.
+Otherwise, only FILE itself is deleted using RM."
+ ;;
+
+*)
+ $echo "$modename: invalid operation mode \`$mode'" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+esac
+
+$echo
+$echo "Try \`$modename --help' for more information about other modes."
+
+exit $EXIT_SUCCESS
+
+# The TAGs below are defined such that we never get into a situation
+# in which we disable both kinds of libraries. Given conflicting
+# choices, we go for a static library, that is the most portable,
+# since we can't tell whether shared libraries were disabled because
+# the user asked for that or because the platform doesn't support
+# them. This is particularly important on AIX, because we don't
+# support having both static and shared libraries enabled at the same
+# time on that platform, so we default to a shared-only configuration.
+# If a disable-shared tag is given, we'll fallback to a static-only
+# configuration. But we'll never go from static-only to shared-only.
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-shared
+build_libtool_libs=no
+build_old_libs=yes
+# ### END LIBTOOL TAG CONFIG: disable-shared
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-static
+build_old_libs=`case $build_libtool_libs in yes) $echo no;; *) $echo yes;; esac`
+# ### END LIBTOOL TAG CONFIG: disable-static
+
+# Local Variables:
+# mode:shell-script
+# sh-indentation:2
+# End:
Added: freeswitch/trunk/libs/sofia-sip/m4/sac-general.m4
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/m4/sac-general.m4 Thu Dec 21 01:30:28 2006
@@ -0,0 +1,418 @@
+dnl =====================================================================
+dnl This file contains autoconf macros shared by Sofia modules.
+dnl
+dnl Author: Pekka Pessi <Pekka.Pessi at nokia.com>
+dnl
+dnl License:
+dnl
+dnl Copyright (c) 2001,2004 Nokia and others. All Rights Reserved.
+dnl
+dnl Please note that every macro contained in this file is copyrighted by
+dnl its respective author, unless the macro source explicitely says
+dnl otherwise. Permission has been granted, though, to use and distribute
+dnl all macros under the following license, which is a modified version of
+dnl the GNU General Public License version 2:
+dnl
+dnl Each Autoconf macro in this file is free software; you can redistribute it
+dnl and/or modify it under the terms of the GNU General Public License as
+dnl published by the Free Software Foundation; either version 2, or (at your
+dnl option) any later version.
+dnl
+dnl They are distributed in the hope that they will be useful, but WITHOUT ANY
+dnl WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+dnl FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+dnl details. (You should have received a copy of the GNU General Public License
+dnl along with this program; if not, write to the Free Software Foundation,
+dnl Inc., 59 Temple Place -- Suite 330, Boston, MA 02111-1307, USA.)
+dnl
+dnl As a special exception, the Free Software Foundation gives unlimited
+dnl permission to copy, distribute and modify the configure scripts that are
+dnl the output of Autoconf. You need not follow the terms of the GNU General
+dnl Public License when using or distributing such scripts, even though
+dnl portions of the text of Autoconf appear in them. The GNU General Public
+dnl License (GPL) does govern all other use of the material that constitutes
+dnl the Autoconf program.
+dnl
+dnl Certain portions of the Autoconf source text are designed to be copied
+dnl (in certain cases, depending on the input) into the output of Autoconf.
+dnl We call these the "data" portions. The rest of the Autoconf source text
+dnl consists of comments plus executable code that decides which of the data
+dnl portions to output in any given case. We call these comments and
+dnl executable code the "non-data" portions. Autoconf never copies any of
+dnl the non-data portions into its output.
+dnl
+dnl This special exception to the GPL applies to versions of Autoconf
+dnl released by the Free Software Foundation. When you make and distribute a
+dnl modified version of Autoconf, you may extend this special exception to
+dnl the GPL to apply to your modified version as well, *unless* your
+dnl modified version has the potential to copy into its output some of the
+dnl text that was the non-data portion of the version that you started with.
+dnl (In other words, unless your change moves or copies text from the
+dnl non-data portions to the data portions.) If your modification has such
+dnl potential, you must delete any notice of this special exception to the
+dnl GPL from your modified version.
+dnl
+dnl =====================================================================
+
+dnl ===================================================================
+dnl Get host, target and build variables filled with appropriate info,
+dnl and check the validity of the cache
+dnl ===================================================================
+
+AC_DEFUN([SAC_CANONICAL_SYSTEM_CACHE_CHECK], [
+
+dnl Get host, target and build variables filled with appropriate info.
+
+AC_CANONICAL_TARGET([])
+
+dnl Check to assure the cached information is valid.
+
+AC_MSG_CHECKING(cached information)
+hostcheck="$host"
+AC_CACHE_VAL(ac_cv_hostcheck, [ ac_cv_hostcheck="$hostcheck" ])
+if test "$ac_cv_hostcheck" != "$hostcheck"; then
+ AC_MSG_RESULT(changed)
+ AC_MSG_WARN(config.cache exists!)
+ AC_MSG_ERROR([you must do 'make distclean' first to compile
+ for different host or different parameters.])
+else
+ AC_MSG_RESULT(ok)
+fi
+
+dnl SOSXXX: AC_PATH_ADJUST
+
+])
+
+dnl ======================================================================
+dnl Find C compiler
+dnl ======================================================================
+
+AC_DEFUN([SAC_TOOL_CC], [
+AC_REQUIRE([SAC_CANONICAL_SYSTEM_CACHE_CHECK])
+AC_BEFORE([$0], [AC_PROG_CPP])dnl
+
+AC_CHECK_TOOL(CC, gcc, gcc)
+if test -z "$CC"; then
+ AC_CHECK_TOOL(CC, cc, cc, , , /usr/ucb/cc)
+ if test -z "$CC"; then
+ case "`uname -s`" in
+ *win32* | *WIN32* ) AC_CHECK_PROG(CC, cl, cl) ;;
+ esac
+ fi
+ test -z "$CC" && AC_MSG_ERROR([no acceptable cc found in \$PATH])
+fi
+
+AC_PROG_CC
+
+#
+# Wall
+#
+AC_CACHE_CHECK([for maximum warnings compiler flag],
+ ac_cv_cwflag,
+[case "${CC-cc}" in
+ *gcc*) ac_cv_cwflag=-Wall;;
+ *) case "$host" in
+ *irix*) ac_cv_cwflag=-fullwarn ;;
+ *solaris*) ac_cv_cwflag="-erroff=%none,E_END_OF_LOOP_CODE_NOT_REACHED -xCC"
+ ;;
+ *) ac_cv_cwflag=;;
+ esac
+ ;;
+esac])
+AC_SUBST([CWFLAG], [$ac_cv_cwflag])
+
+AC_ARG_VAR([SOFIA_CFLAGS], [CFLAGS not used during configure])
+
+#
+# GCoverage
+#
+AC_ARG_ENABLE(coverage,
+[ --enable-coverage compile test-coverage (disabled)],
+ , enable_coverage=no)
+
+if test X$enable_coverage != Xno ; then
+case "${CC-cc}" in
+ *gcc*)
+ SOFIA_CFLAGS="$SOFIA_CFLAGS -fprofile-arcs -ftest-coverage"
+ ;;
+ *) AC_MSG_ERROR([--enable-coverage requires gcc])
+esac
+fi
+
+AM_CONDITIONAL([ENABLE_COVERAGE], test X$enable_coverage != Xno)
+
+AC_SUBST([MOSTLYCLEANFILES], "*.bb *.bbg *.da *.gcov *.gcda *.gcno")
+])
+
+dnl ======================================================================
+dnl Check for sockaddr_in6
+dnl ======================================================================
+AC_DEFUN([AC_STRUCT_SIN6], [
+AC_CACHE_CHECK([for sockaddr_in6],
+ ac_cv_sin6,
+[AC_EGREP_HEADER(struct sockaddr_in6, netinet/in.h,
+ ac_cv_sin6=yes, ac_cv_sin6=no)])
+if test $ac_cv_sin6 = yes ;then
+ AC_DEFINE([HAVE_SIN6], 1,
+ [Define to 1 if you have IPv6 structures and constants])
+fi
+])
+
+dnl ======================================================================
+dnl Check for sa_len in struct sockaddr
+dnl ======================================================================
+AC_DEFUN([AC_SYS_SA_LEN], [
+AC_CACHE_CHECK([for sa_len],
+ ac_cv_sa_len,
+[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>
+#include <sys/socket.h>]], [[
+ struct sockaddr t;t.sa_len = 0;]])],[ac_cv_sa_len=yes],[ac_cv_sa_len=no])])
+if test "$ac_cv_sa_len" = yes ;then
+ AC_DEFINE([HAVE_SA_LEN], 1,
+ [Define to 1 if you have sa_len in struct sockaddr])
+fi
+])
+
+dnl ======================================================================
+dnl Check for MSG_NOSIGNAL flag
+dnl ======================================================================
+AC_DEFUN([AC_FLAG_MSG_NOSIGNAL], [
+AC_REQUIRE([AC_PROG_CC])
+AC_CACHE_CHECK([for MSG_NOSIGNAL],
+ ac_cv_flag_msg_nosignal, [
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/types.h>
+#include <sys/socket.h>]], [[
+ int flags = MSG_NOSIGNAL;
+]])],[ac_cv_flag_msg_nosignal=yes],[ac_cv_flag_msg_nosignal=no])])
+if test "$ac_cv_flag_msg_nosignal" = yes ; then
+ AC_DEFINE([HAVE_MSG_NOSIGNAL], 1,
+ [Define to 1 if you have MSG_NOSIGNAL flag for send()])
+fi
+])dnl
+
+dnl ======================================================================
+dnl Check for MSG_ERRQUEUE flag
+dnl ======================================================================
+AC_DEFUN([AC_SYS_MSG_ERRQUEUE], [
+AC_REQUIRE([AC_PROG_CC])
+AC_CACHE_CHECK([for MSG_ERRQUEUE],
+ ac_cv_flag_msg_errqueue, [
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/types.h>
+#include <sys/socket.h>]], [[
+ int flags = MSG_ERRQUEUE;
+]])],[ac_cv_flag_msg_errqueue=yes],[ac_cv_flag_msg_errqueue=no])])
+if test "$ac_cv_flag_msg_errqueue" = yes; then
+ AC_DEFINE([HAVE_MSG_ERRQUEUE], 1,
+ [Define to 1 if you have MSG_ERRQUEUE flag for send()])
+fi
+])dnl
+
+dnl ======================================================================
+dnl Check for IP_RECVERR option
+dnl ======================================================================
+AC_DEFUN([AC_SYS_IP_RECVERR], [
+AC_REQUIRE([AC_PROG_CC])
+AC_CACHE_CHECK([for IP_RECVERR],
+ ac_cv_sys_ip_recverr, [
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+]], [[
+ int one = 1;
+ int s = 0;
+ setsockopt(s, SOL_IP, IP_RECVERR, &one, sizeof(one));
+]])],[ac_cv_sys_ip_recverr=yes],[ac_cv_sys_ip_recverr=no])])
+if test "$ac_cv_sys_ip_recverr" = yes ; then
+ AC_DEFINE([HAVE_IP_RECVERR], 1,
+ [Define to 1 if you have IP_RECVERR in <netinet/in.h>])
+fi
+])dnl
+
+dnl ======================================================================
+dnl Check for IPV6_RECVERR option
+dnl ======================================================================
+AC_DEFUN([AC_SYS_IPV6_RECVERR], [
+AC_REQUIRE([AC_PROG_CC])
+AC_CACHE_CHECK([for IPV6_RECVERR],
+ ac_cv_sys_ipv6_recverr, [
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+]], [[
+ int one = 1;
+ int s = 0;
+ setsockopt(s, SOL_IPV6, IPV6_RECVERR, &one, sizeof(one));
+]])],[ac_cv_sys_ipv6_recverr=yes],[ac_cv_sys_ipv6_recverr=no])])
+if test "$ac_cv_sys_ipv6_recverr" = yes ; then
+ AC_DEFINE([HAVE_IPV6_RECVERR], 1,
+ [Define to 1 if you have IPV6_RECVERR in <netinet/in6.h>])
+fi
+])dnl
+
+dnl ======================================================================
+dnl @synopsis AC_C_VAR_FUNC
+dnl
+dnl This macro tests if the C compiler supports the C99 standard
+dnl __func__ indentifier.
+dnl
+dnl The new C99 standard for the C language stipulates that the
+dnl identifier __func__ shall be implictly declared by the compiler
+dnl as if, immediately following the opening brace of each function
+dnl definition, the declaration
+dnl
+dnl static const char __func__[] = "function-name";
+dnl
+dnl appeared, where function-name is the name of the function where
+dnl the __func__ identifier is used.
+dnl
+dnl @author Christopher Currie <christopher at currie.com>
+dnl @author Pekka Pessi <Pekka.Pessi at nokia.com>
+dnl ======================================================================
+
+AC_DEFUN([AC_C_VAR_FUNC],
+[AC_REQUIRE([AC_PROG_CC])
+AC_CACHE_CHECK(whether $CC recognizes __func__, ac_cv_c_var_func,
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[char *s = __func__;
+]])],[ac_cv_c_var_func=yes],[ac_cv_c_var_func=no]))
+if test $ac_cv_c_var_func = "yes"; then
+AC_DEFINE([HAVE_FUNC], 1, [Define to 1 if the C compiler supports __func__])
+fi
+])dnl
+
+AC_DEFUN([AC_C_MACRO_FUNCTION],
+[AC_REQUIRE([AC_PROG_CC])
+AC_CACHE_CHECK(whether $CC recognizes __FUNCTION__, ac_cv_c_macro_function,
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[
+char *s = __FUNCTION__;
+]])],[ac_cv_c_macro_function=yes],[ac_cv_c_macro_function=no]))
+if test $ac_cv_c_macro_function = "yes"; then
+AC_DEFINE([HAVE_FUNCTION], 1, [Define to 1 if the C compiler supports __FUNCTION__])
+fi
+])dnl
+
+dnl ======================================================================
+dnl AC_C_INLINE_DEFINE
+dnl ======================================================================
+AC_DEFUN([AC_C_INLINE_DEFINE], [
+AC_C_INLINE
+case "$ac_cv_c_inline" in *inline* | yes)
+ AC_DEFINE([HAVE_INLINE], 1, [Define to 1 if you have inlining compiler]) ;;
+esac
+])
+
+dnl ======================================================================
+dnl AC_C_KEYWORD_STRUCT
+dnl ======================================================================
+AC_DEFUN([AC_C_KEYWORD_STRUCT], [
+AC_REQUIRE([AC_PROG_CC])
+AC_CACHE_CHECK(whether $CC recognizes field names in struct initialization, ac_cv_c_keyword_struct,
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[
+ struct { int foo; char *bar; } test = { foo: 1, bar: "bar" };
+ return 0;
+]])],[ac_cv_c_keyword_struct=yes],[ac_cv_c_keyword_struct=no]))
+if test $ac_cv_c_keyword_struct = "yes"; then
+AC_DEFINE([HAVE_STRUCT_KEYWORDS], 1, [
+Define to 1 if your CC supports C99 struct initialization])
+fi
+])
+
+dnl ======================================================================
+dnl autoconf-version
+dnl should be removed after automake conversion is finished
+dnl ======================================================================
+
+AC_DEFUN([AC_AUTOCONF_PARAM],
+[
+if autoconf --version | fgrep '2.13' > /dev/null ; then
+ AUTOCONF_PARAM="-l"
+else
+ AUTOCONF_PARAM="-I"
+fi
+AC_SUBST(AUTOCONF_PARAM)
+])
+
+dnl ======================================================================
+dnl SAC_ENABLE_NDEBUG
+dnl ======================================================================
+AC_DEFUN([SAC_ENABLE_NDEBUG],[
+AC_REQUIRE([SAC_TOOL_CC])
+AC_ARG_ENABLE(ndebug,
+[ --enable-ndebug compile with NDEBUG (disabled)],
+ , enable_ndebug=no)
+AM_CONDITIONAL(NDEBUG, test x$enable_ndebug = yes)
+SOFIA_CFLAGS="$SOFIA_CFLAGS -DNDEBUG"
+])
+
+dnl ======================================================================
+dnl SAC_ENABLE_EXPENSIVE_CHECKS
+dnl ======================================================================
+AC_DEFUN([SAC_ENABLE_EXPENSIVE_CHECKS],[
+AC_ARG_ENABLE(expensive-checks,
+[ --enable-expensive-checks run also expensive checks (disabled)],
+ , enable_expensive_checks=no)
+if test $enable_expensive_checks != no; then
+AC_SUBST([TESTS_ENVIRONMENT], [EXPENSIVE_CHECKS=1])
+fi
+AM_CONDITIONAL(EXPENSIVE_CHECKS, test x$enable_expensive_checks != no)
+])
+
+
+dnl ======================================================================
+dnl Check if we are using Windows with MinGW compiler
+dnl ======================================================================
+
+AC_DEFUN([AC_CHECK_COMPILATION_ENVIRONMENT], [
+AC_REQUIRE([AC_PROG_CC])
+AC_CACHE_CHECK([for compilation environment],
+ ac_cc_environment, [
+machine=`$CC -dumpmachine`
+if test "$machine" = mingw32 ; then
+ ac_cc_environment=$machine
+fi
+])
+
+if test "$ac_cc_environment" = mingw32 ; then
+CFLAGS="$CFLAGS -I\$(top_srcdir)/win32/pthread -DWINVER=0x0501 \
+ -D_WIN32_WINNT=0x0501 -DIN_LIBSOFIA_SIP_UA -DIN_LIBSOFIA_SRES \
+ -mms-bitfields \
+ -pipe -mno-cygwin -mwindows -mconsole -Wall -g -O0"
+LDFLAGS="$LDFLAGS -Wl,--enable-auto-image-base"
+LIBS="-L\$(top_srcdir)/win32/pthread -lpthreadVC2 -lws2_32 \
+ -lwsock32"
+MINGW_ENVIRONMENT=1
+AC_SUBST(MINGW_ENVIRONMENT)
+AC_DEFINE([HAVE_MINGW], [1], [Define to 1 if you are compiling in MinGW environment])
+AC_DEFINE([HAVE_WIN32], [1], [Define to 1 if you have WIN32])
+fi
+AM_CONDITIONAL([HAVE_MINGW32], [test "x$ac_cc_environment" != x])
+])dnl
+
+
+dnl ======================================================================
+dnl Find long long (at least 64 bits)
+dnl ======================================================================
+
+AC_DEFUN([AC_TYPE_LONGLONG],[dnl
+AC_CHECK_TYPE([long long],[dnl
+AC_DEFINE([longlong], [long long], [Define to a at least 64-bit int type])dnl
+ifelse([$1], ,:, [$1])],[ifelse([$2], ,:, [$2])])])
+
+dnl ======================================================================
+dnl Check for /dev/urandom
+dnl ======================================================================
+
+AC_DEFUN([AC_DEV_URANDOM],[
+AC_CACHE_CHECK([/dev/urandom], [ac_cv_dev_urandom],
+ [ac_cv_dev_urandom=no
+ if test -r /dev/urandom; then ac_cv_dev_urandom=yes; fi])
+if test $ac_cv_dev_urandom = yes; then
+ AC_DEFINE([HAVE_DEV_URANDOM], 1,
+ [Define to 1 if you have /dev/urandom.])
+ AC_DEFINE([DEV_URANDOM], 1,
+ [Define to the random number source name.])
+fi
+])
Added: freeswitch/trunk/libs/sofia-sip/m4/sac-openssl.m4
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/m4/sac-openssl.m4 Thu Dec 21 01:30:28 2006
@@ -0,0 +1,36 @@
+dnl ======================================================================
+dnl SAC_OPENSSL
+dnl ======================================================================
+AC_DEFUN([SAC_OPENSSL], [
+
+AC_ARG_WITH(openssl,
+[ --with-openssl use OpenSSL (enabled)],, with_openssl=yes)
+
+dnl SOSXXX:SAC_ASSERT_DEF([openssl libraries])
+
+if test "$with_openssl" != no ;then
+ AC_CHECK_HEADERS(openssl/tls1.h, [
+
+ HAVE_OPENSSL=1 HAVE_TLS=1
+
+ AC_CHECK_LIB(crypto, BIO_new,,
+ HAVE_OPENSSL=0
+ AC_MSG_WARN(OpenSSL crypto library was not found))
+
+ AC_CHECK_LIB(ssl, TLSv1_method,,
+ HAVE_TLS=0
+ AC_MSG_WARN(OpenSSL protocol library was not found))
+
+ if test x$HAVE_OPENSSL = x1; then
+ AC_DEFINE([HAVE_OPENSSL], 1, [Define to 1 if you have OpenSSL])
+ fi
+
+ if test x$HAVE_TLS = x1; then
+ AC_DEFINE([HAVE_TLS], 1, [Define to 1 if you have TLS])
+ fi
+ ],
+ AC_MSG_WARN(OpenSSL include files were not found))
+fi
+
+AM_CONDITIONAL(HAVE_TLS, test x$HAVE_TLS = x1)
+])
Added: freeswitch/trunk/libs/sofia-sip/m4/sac-su.m4
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/m4/sac-su.m4 Thu Dec 21 01:30:28 2006
@@ -0,0 +1,36 @@
+dnl ======================================================================
+dnl su module
+dnl ======================================================================
+
+dnl The macro SAC_SOFIA_SU is in a separate file, sofia-su2.m4, because
+dnl SAC_SOFIA_SU creates a separate configuration file <su/su_configure.h>.
+dnl If SAC_SOFIA_SU is included to a aclocal.m4 of another package,
+dnl autoheader returns a spurious error and automake complains about missing
+dnl su/su_configure.h.
+
+dnl ======================================================================
+dnl SAC_WITH_RT - check for POSIX realtime library
+dnl ======================================================================
+AC_DEFUN([SAC_WITH_RT],[
+AC_ARG_WITH(rt,
+[ --with-rt use POSIX realtime library (used by default)])
+])
+
+dnl ======================================================================
+dnl SAC_CHECK_SU_LIBS - check for libraries used by su
+dnl ======================================================================
+AC_DEFUN([SAC_CHECK_SU_LIBS], [
+AC_REQUIRE([SAC_WITH_RT])
+AC_CHECK_LIB(pthread, pthread_create)
+AC_CHECK_LIB(socket, socketpair,,,-lnsl)
+if test "${with_rt}" != no; then
+ AC_SEARCH_LIBS(clock_gettime, rt)
+fi
+])dnl
+
+dnl ======================================================================
+dnl SAC_SU - main macro for checking su dependencies
+dnl ======================================================================
+AC_DEFUN([SAC_SU], [
+AC_REQUIRE([SAC_CHECK_SU_LIBS])
+])
Added: freeswitch/trunk/libs/sofia-sip/m4/sac-su2.m4
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/m4/sac-su2.m4 Thu Dec 21 01:30:28 2006
@@ -0,0 +1,550 @@
+dnl ======================================================================
+dnl su module
+dnl ======================================================================
+
+AC_DEFUN([SAC_SOFIA_SU], [
+# Beginning of SAC_SOFIA_SU
+
+AC_REQUIRE([SAC_WITH_RT])
+
+# ======================================================================
+# Check for features used by su
+
+dnl Define compilation options for su_configure.h
+
+case "$target" in
+*-*-solaris?.* )
+ SAC_SU_DEFINE(__EXTENSIONS__, 1, [Define to 1 in Solaris in order to get POSIX extensions.])
+;;
+esac
+
+# Check includes used by su includes
+AC_CHECK_HEADER(sys/types.h,
+ SAC_SU_DEFINE([SU_HAVE_SYS_TYPES], 1,
+ [Define to 1 if Sofia uses sys/types.h]))
+
+ax_inttypes=false
+AC_CHECK_HEADER(stdint.h, [
+ ax_inttypes=true
+ SAC_SU_DEFINE([SU_HAVE_STDINT], 1,
+ [Define to 1 if Sofia uses stdint.h])])
+AC_CHECK_HEADER(inttypes.h,[
+ ax_inttypes=true
+ SAC_SU_DEFINE([SU_HAVE_INTTYPES], 1,
+ [Define to 1 if Sofia uses inttypes.h])])
+
+if $ax_inttypes; then : ; else
+ AC_MSG_ERROR("No <stdint.h> or <inttypes.h> found.")
+fi
+
+if test "x$MINGW_ENVIRONMENT" != x1 ; then
+ AC_CHECK_HEADER(pthread.h,
+ HAVE_PTHREADS=1;
+ SAC_SU_DEFINE([SU_HAVE_PTHREADS], 1, [Sofia SU uses pthreads]))
+else
+ HAVE_PTHREADS=1;
+ SAC_SU_DEFINE([SU_HAVE_PTHREADS], 1, [Sofia SU uses pthreads])
+fi
+
+dnl ===========================================================================
+dnl Checks for typedefs, headers, structures, and compiler characteristics.
+dnl ===========================================================================
+
+AC_REQUIRE([AC_C_CONST])
+AC_REQUIRE([AC_HEADER_TIME])
+AC_REQUIRE([AC_TYPE_SIZE_T])
+AC_REQUIRE([AC_C_VAR_FUNC])
+AC_REQUIRE([AC_C_MACRO_FUNCTION])
+
+AC_REQUIRE([AC_C_INLINE])
+
+case "$ac_cv_c_inline" in
+ yes) SAC_SU_DEFINE(su_inline, static inline, [
+ Define to declarator for static inline functions.
+ ])dnl
+ SAC_SU_DEFINE(SU_INLINE, inline, [
+ Define to declarator for inline functions.
+ ])dnl
+ SAC_SU_DEFINE(SU_HAVE_INLINE, 1, [
+ Define to 1 if you have inline functions.
+ ])dnl
+ ;;
+ no) SAC_SU_DEFINE(su_inline, static)dnl
+ SAC_SU_DEFINE(SU_INLINE)dnl
+ SAC_SU_DEFINE(SU_HAVE_INLINE)dnl
+ ;;
+ *) SAC_SU_DEFINE_UNQUOTED(su_inline, static $ac_cv_c_inline)dnl
+ SAC_SU_DEFINE_UNQUOTED(SU_INLINE, $ac_cv_c_inline)dnl
+ SAC_SU_DEFINE(SU_HAVE_INLINE, 1)dnl
+ ;;
+esac
+
+AC_ARG_ENABLE(size-compat,
+[ --disable-size-compat use compatibility size_t types (enabled)],
+ , enable_size_compat=yes)
+
+if test X$enable_size_compat != Xyes; then
+ SAC_SU_DEFINE(SOFIA_ISIZE_T, size_t)dnl
+ SAC_SU_DEFINE(ISIZE_MAX, SIZE_MAX)dnl
+ SAC_SU_DEFINE(SOFIA_ISSIZE_T, ssize_t)dnl
+ SAC_SU_DEFINE(ISSIZE_MAX, SSIZE_MAX)dnl
+ SAC_SU_DEFINE(SOFIA_USIZE_T, size_t)dnl
+ SAC_SU_DEFINE(USIZE_MAX, SIZE_MAX)dnl
+else
+ SAC_SU_DEFINE(SOFIA_ISIZE_T, int)dnl
+ SAC_SU_DEFINE(ISIZE_MAX, INT_MAX)dnl
+ SAC_SU_DEFINE(SOFIA_ISSIZE_T, int)dnl
+ SAC_SU_DEFINE(ISSIZE_MAX, INT_MAX)dnl
+ SAC_SU_DEFINE(SOFIA_USIZE_T, unsigned)dnl
+ SAC_SU_DEFINE(USIZE_MAX, UINT_MAX)dnl
+fi
+
+
+dnl ======================================================================
+dnl SAC_ENABLE_COREFOUNDATION
+dnl ======================================================================
+AC_ARG_ENABLE(corefoundation,
+[ --enable-corefoundation compile with OSX COREFOUNDATION (disabled)],
+ , enable_corefoundation=no)
+AM_CONDITIONAL(COREFOUNDATION, test $enable_corefoundation = yes)
+
+if test $enable_corefoundation = yes ; then
+ SAC_SU_DEFINE([SU_HAVE_OSX_CF_API], 1, [
+Define as 1 if you have OSX CoreFoundation interface])
+ LIBS="-framework CoreFoundation -framework SystemConfiguration $LIBS"
+fi
+
+
+### ======================================================================
+### Test if we have stack suitable for handling tags directly
+###
+
+test -z "$ac_cv_tagstack" &&
+case "$target" in
+i?86-*-* ) ac_cv_tagstack=yes ;;
+esac
+
+AC_CACHE_CHECK([for stack suitable for tags],[ac_cv_tagstack],[
+ac_cv_tagstack=no
+
+AC_RUN_IFELSE([
+#if HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+#if HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#include <stdarg.h>
+
+typedef void *tp;
+typedef intptr_t tv;
+
+int test1(tv l, tv h, ...)
+{
+ va_list ap;
+ tv i, *p = &l;
+
+ va_start(ap, h);
+
+ if (*p++ != l || *p++ != h) return 1;
+
+ for (i = l; i <= h; i++) {
+ if (*p++ != i)
+ return 1;
+ }
+
+ for (i = l; i <= h; i++) {
+ if (va_arg(ap, tv) != i)
+ return 1;
+ }
+
+ va_end(ap);
+
+ return 0;
+}
+
+int main(int avc, char **av)
+{
+ return test1((tv)1, (tv)10,
+ (tv)1, (tv)2, (tv)3, (tv)4, (tv)5,
+ (tv)6, (tv)7, (tv)8, (tv)9, (tv)10);
+}
+],[ac_cv_tagstack=yes],[ac_cv_tagstack=no],[ac_cv_tagstack=no])])
+
+if test $ac_cv_tagstack = yes ; then
+SAC_SU_DEFINE([SU_HAVE_TAGSTACK], 1, [
+Define this as 1 if your compiler puts the variable argument list nicely in memory])
+fi
+
+dnl ======================================================================
+dnl Socket features
+
+AC_REQUIRE([AC_SYS_SA_LEN])
+if test "$ac_cv_sa_len" = yes ;then
+ SAC_SU_DEFINE([SU_HAVE_SOCKADDR_SA_LEN], 1,
+ [Define to 1 if you have sa_len in struct sockaddr])
+fi
+
+AC_REQUIRE([AC_STRUCT_SIN6])
+case $ac_cv_sin6 in
+yes) SAC_SU_DEFINE(SU_HAVE_IN6, 1, [
+ Define to 1 if you have struct sockaddr_in6]) ;;
+ no) ;;
+ *) AC_MSG_ERROR([Inconsistent struct sockaddr_sin6 test]) ;;
+esac
+
+AC_CHECK_HEADERS([unistd.h sys/time.h])
+
+AC_CHECK_HEADERS([fcntl.h dirent.h])
+
+AC_CHECK_HEADERS([winsock2.h], [
+ AC_DEFINE([HAVE_WIN32], 1, [Define to 1 you have WIN32])
+ SAC_SU_DEFINE([SU_HAVE_WINSOCK], 1, [Define to 1 you have WinSock])
+ SAC_SU_DEFINE([SU_HAVE_WINSOCK2], 1, [Define to 1 you have WinSock2])
+ SAC_SU_DEFINE([SU_HAVE_SOCKADDR_STORAGE], 1,
+ [Define to 1 if you have struct sockaddr_storage])
+ AC_DEFINE([HAVE_ADDRINFO], 1,
+ [Define to 1 if you have addrinfo structure.])
+ AC_DEFINE([HAVE_GETADDRINFO], 1,
+ [Define to 1 if you have addrinfo structure.])
+ AC_DEFINE([HAVE_FREEADDRINFO], 1,
+ [Define to 1 if you have addrinfo structure.])
+ SAC_SU_DEFINE([SU_HAVE_ADDRINFO], 1,
+ [Define to 1 if you have addrinfo structure.])
+ AC_CHECK_HEADERS([windef.h ws2tcpip.h])
+ AC_CHECK_HEADERS([iphlpapi.h], [
+ AC_DEFINE([HAVE_INTERFACE_INFO_EX], 1, [
+ Define to 1 if you have WIN32 INTERFACE_INFO_EX type.])
+ AC_DEFINE([HAVE_SIO_ADDRESS_LIST_QUERY], 1, [
+ Define to 1 if you have WIN32 WSAIoctl SIO_ADDRESS_LIST_QUERY.])
+ ], [], [#if HAVE_WINDEF_H
+#include <windef.h>
+#include <winbase.h>
+#endif
+ ])
+ AC_DEFINE([HAVE_FILETIME], 1, [
+ Define to 1 if you have WIN32 FILETIME type and
+ GetSystemTimeAsFileTime().])
+],[
+dnl no winsock2
+SAC_SU_DEFINE([SU_HAVE_BSDSOCK], 1, [Define to 1 if you have BSD socket interface])
+AC_CHECK_HEADERS([sys/socket.h sys/ioctl.h sys/filio.h sys/sockio.h \
+ sys/select.h])
+AC_CHECK_HEADERS([netinet/in.h arpa/inet.h netdb.h \
+ net/if.h net/if_types.h ifaddr.h netpacket/packet.h],,,
+ [
+#include <sys/types.h>
+#include <sys/socket.h>])
+
+AC_CHECK_DECL([MSG_TRUNC],
+AC_DEFINE([HAVE_MSG_TRUNC],1,[Define to 1 if you have MSG_TRUNC flag]),,[
+#include <sys/types.h>
+#include <sys/socket.h>])
+
+AC_CACHE_CHECK([for struct addrinfo],
+[ac_cv_struct_addrinfo],[
+ac_cv_struct_addrinfo=no
+if test "$ac_cv_header_sys_socket_h" = yes; then
+ AC_EGREP_HEADER([struct.+addrinfo], [netdb.h], [
+ ac_cv_struct_addrinfo=yes])
+else
+ ac_cv_struct_addrinfo='sys/socket.h missing'
+fi])
+
+if test "$ac_cv_struct_addrinfo" = yes; then
+ SAC_SU_DEFINE([SU_HAVE_ADDRINFO], 1,
+ [Define to 1 if you have struct addrinfo.])
+fi
+
+AC_CACHE_CHECK([for struct sockaddr_storage],
+[ac_cv_struct_sockaddr_storage],[
+ac_cv_struct_sockaddr_storage=no
+if test "$ac_cv_header_sys_socket_h" = yes; then
+ AC_EGREP_HEADER([struct.+sockaddr_storage], [sys/socket.h], [
+ ac_cv_struct_sockaddr_storage=yes])
+else
+ ac_cv_struct_sockaddr_storage='sys/socket.h missing'
+fi])
+if test "$ac_cv_struct_sockaddr_storage" = yes; then
+ SAC_SU_DEFINE(SU_HAVE_SOCKADDR_STORAGE, 1,
+ [Define to 1 if you have struct sockaddr_storage])
+fi
+
+AC_CACHE_CHECK([for field ifr_index in struct ifreq],
+[ac_cv_struct_ifreq_ifr_index],[
+ac_cv_struct_ifreq_ifr_index=no
+if test "1${ac_cv_header_arpa_inet_h}2${ac_cv_header_netdb_h}3${ac_cv_header_sys_socket_h}4${ac_cv_header_net_if_h}" = 1yes2yes3yes4yes; then
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <net/if.h>]], [[
+struct ifreq ifreq; int index; index = ifreq.ifr_index;
+]])],[ac_cv_struct_ifreq_ifr_index=yes],[])
+else
+ ac_cv_struct_ifreq_ifr_index='net/if.h missing'
+fi # arpa/inet.h && netdb.h && sys/socket.h && net/if.h
+])
+if test "$ac_cv_struct_ifreq_ifr_index" = yes ; then
+ :
+ AC_DEFINE(HAVE_IFR_INDEX, 1, [Define to 1 if you have ifr_index in <net/if.h>])
+else
+AC_CACHE_CHECK([for field ifr_ifindex in struct ifreq],
+[ac_cv_struct_ifreq_ifr_ifindex],[
+ac_cv_struct_ifreq_ifr_ifindex=no
+if test "1${ac_cv_header_arpa_inet_h}2${ac_cv_header_netdb_h}3${ac_cv_header_sys_socket_h}4${ac_cv_header_net_if_h}" = 1yes2yes3yes4yes; then
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <net/if.h>]], [[
+struct ifreq ifreq; int index; index = ifreq.ifr_ifindex;
+]])],[ac_cv_struct_ifreq_ifr_ifindex=yes],[])
+else
+ ac_cv_struct_ifreq_ifr_ifindex='net/if.h missing'
+fi # arpa/inet.h && netdb.h && sys/socket.h && net/if.h
+])
+if test "$ac_cv_struct_ifreq_ifr_ifindex" = yes; then
+ :
+ AC_DEFINE(HAVE_IFR_IFINDEX, 1, [Define to 1 if you have ifr_ifindex in <net/if.h>])
+fi
+
+fi # ifr_index in struct ifreq
+
+dnl SIOGCIFCONF & struct ifconf
+AC_CACHE_CHECK([for struct ifconf],
+[ac_cv_struct_ifconf],[
+ac_cv_struct_ifconf=no
+if test "$ac_cv_header_net_if_h" = yes; then
+ AC_EGREP_HEADER(struct.+ifconf, net/if.h, ac_cv_struct_ifconf=yes)
+else
+ ac_cv_struct_ifconf='net/if.h missing'
+fi])
+if test "$ac_cv_struct_ifconf" = yes; then
+ AC_DEFINE(HAVE_IFCONF, 1, [Define to 1 if you have SIOCGIFCONF])
+fi
+
+AC_CACHE_CHECK([for ioctl SIOCGIFNUM],
+[ac_cv_ioctl_siocgifnum],[
+ac_cv_ioctl_siocgifnum=no
+if test "$ac_cv_header_sys_sockio_h" = yes; then
+AC_EGREP_CPP(yes, [
+#include <sys/sockio.h>
+#ifdef SIOCGIFNUM
+ yes
+#endif
+], [ac_cv_ioctl_siocgifnum=yes])
+else
+ ac_cv_ioctl_siocgifnum='sys/sockio.h missing'
+fi])
+if test "$ac_cv_ioctl_siocgifnum" = yes; then
+ HAVE_IFNUM=1
+ AC_DEFINE(HAVE_IFNUM, 1, [Define to 1 if you have SIOCGIFNUM ioctl])
+else
+ HAVE_IFNUM=0
+fi
+
+]) dnl AC_CHECK_HEADERS([winsock2.h ... ])
+
+
+# ===========================================================================
+# Checks for libraries
+# ===========================================================================
+
+SAC_CHECK_SU_LIBS
+
+# No GLib path explicitly defined, use pkg-config
+AC_ARG_WITH(glib,
+[ --with-glib=version use GLib (default=2.0)], [
+case "$with_glib" in
+yes | "" ) with_glib=2.0 ;;
+esac
+], [with_glib=2.0])
+
+AC_ARG_WITH(glib-dir,
+[ --with-glib-dir=PREFIX explicitly define GLib path],,
+ with_glib_dir="pkg-config")
+
+if test "$with_glib" = no || test "$with_glib_dir" = "no" ; then
+
+ : # No glib
+
+elif test "$with_glib_dir" = "pkg-config" ; then
+
+ PKG_CHECK_MODULES(GLIB, glib-$with_glib, [HAVE_GLIB=yes], [HAVE_GLIB=no])
+
+else # GLib path is explicitly defined
+
+ gprefix=$with_glib_dir
+ GLIB_VERSION="$with_glib"
+ GLIBXXX=glib-$with_glib
+
+ if test "$gprefix" = "yes" ; then
+ for gprefix in /usr /usr/local /opt/$GLIBXXX
+ do
+ test -d $gprefix/include/$GLIBXXX && break
+ done
+ fi
+
+ if ! test -d $gprefix/include/$GLIBXXX ; then
+ AC_MSG_ERROR("No $GLIBXXX in --with-glib=$with_glib_dir")
+ else
+ exec_gprefix=${gprefix}
+ glibdir=${exec_gprefix}/lib
+ gincludedir=${gprefix}/include
+
+ # glib_genmarshal=glib-genmarshal
+ # glib_mkenums=glib-mkenums
+
+ HAVE_GLIB=yes
+
+ if test "x$MINGW_ENVIRONMENT" = x1 ; then
+ GLIB_LIBS="${glibdir}/lib$GLIBXXX.dll.a ${glibdir}/libintl.a ${glibdir}/libiconv.a"
+ else
+ GLIB_LIBS="-L${glibdir} -l$GLIBXXX -lintl -liconv"
+ fi
+ GLIB_CFLAGS="-I${gincludedir}/$GLIBXXX -I${glibdir}/$GLIBXXX/include"
+ fi
+
+fi # GLib path is explicitly defined
+
+if test "x$HAVE_GLIB" = xyes ; then
+ SAC_COMMA_APPEND([SOFIA_GLIB_PKG_REQUIRES],[glib-2.0])
+fi
+
+AM_CONDITIONAL([HAVE_GLIB], [test "x$HAVE_GLIB" = xyes])
+AC_SUBST([GLIB_LIBS])
+AC_SUBST([GLIB_CFLAGS])
+AC_SUBST([GLIB_VERSION])
+AC_SUBST([SOFIA_GLIB_PKG_REQUIRES])
+
+# ===========================================================================
+# Checks for library functions.
+# ===========================================================================
+
+AC_SEARCH_LIBS(socket, xnet socket)
+AC_SEARCH_LIBS(inet_ntop, socket nsl)
+dnl AC_SEARCH_LIBS(inet_pton, socket nsl)
+AC_SEARCH_LIBS(getipnodebyname, xnet socket nsl)
+AC_SEARCH_LIBS(gethostbyname, xnet nsl)
+AC_SEARCH_LIBS(getaddrinfo, xnet socket nsl)
+
+AC_CHECK_FUNCS([gettimeofday strerror random initstate tcsetattr flock alarm \
+ socketpair gethostname gethostbyname getipnodebyname \
+ poll epoll_create select if_nameindex \
+ getaddrinfo getnameinfo freeaddrinfo gai_strerror getifaddrs \
+ getline getdelim getpass])
+# getline getdelim getpass are _GNU_SOURCE stuff
+
+if test $ac_cv_func_poll = yes ; then
+ SAC_SU_DEFINE([SU_HAVE_POLL], 1, [Define to 1 if you have poll().])
+fi
+
+if test $ac_cv_func_epoll_create = yes ; then
+ AC_DEFINE([HAVE_EPOLL], 1, [Define to 1 if you have epoll interface.])
+fi
+
+if test $ac_cv_func_if_nameindex = yes ; then
+ SAC_SU_DEFINE([SU_HAVE_IF_NAMEINDEX], 1,
+ [Define to 1 if you have if_nameindex().])
+fi
+
+AC_REQUIRE([SAC_WITH_RT])
+if test "${with_rt}" != no; then
+ AC_CHECK_FUNCS([clock_gettime clock_getcpuclockid])
+fi
+
+SAC_REPLACE_FUNCS([memmem memccpy memspn memcspn strcasestr strtoull \
+ inet_ntop inet_pton])
+
+
+# ===========================================================================
+# Check pthread_rwlock_unlock()
+# ===========================================================================
+
+AC_DEFUN([AC_DEFINE_HAVE_PTHREAD_RWLOCK],[dnl
+AC_DEFINE([HAVE_PTHREAD_RWLOCK], 1,[
+Define to 1 if you have working pthread_rwlock_t implementation.
+
+ A thread may hold multiple concurrent read locks on rwlock - that is,
+ successfully call the pthread_rwlock_rdlock() function n times. If
+ so, the application shall ensure that the thread performs matching
+ unlocks - that is, it calls the pthread_rwlock_unlock() function n
+ times.
+])])
+
+if test x$HAVE_PTHREADS = x1 ; then
+
+AC_RUN_IFELSE([
+#define _XOPEN_SOURCE (500)
+
+#include <pthread.h>
+
+pthread_rwlock_t rw;
+
+int main()
+{
+ pthread_rwlock_init(&rw, NULL);
+ pthread_rwlock_rdlock(&rw);
+ pthread_rwlock_rdlock(&rw);
+ pthread_rwlock_unlock(&rw);
+ /* pthread_rwlock_trywrlock() should fail (not return 0) */
+ return pthread_rwlock_trywrlock(&rw) != 0 ? 0 : 1;
+}
+],[AC_DEFINE_HAVE_PTHREAD_RWLOCK],[
+AC_MSG_WARN([Recursive pthread_rwlock_rdlock() does not work!!! ])
+],[AC_DEFINE_HAVE_PTHREAD_RWLOCK])
+
+fi
+
+# ===========================================================================
+# Check IPv6 addresss configuration
+# ===========================================================================
+case "$target" in
+ *-*-linux*) AC_DEFINE([HAVE_PROC_NET_IF_INET6], 1,
+ [Define to 1 if you have /proc/net/if_inet6 control file]) ;;
+esac
+
+AC_CONFIG_HEADERS([libsofia-sip-ua/su/sofia-sip/su_configure.h])
+
+# End of SAC_SOFIA_SU
+])
+
+dnl
+dnl Append a value $2 to a variable, separating values with comma
+dnl
+AC_DEFUN([SAC_COMMA_APPEND],[$1="`test -n "$$1" && echo "$$1, "`$2"])
+
+# SAC_SU_DEFINE(VARIABLE, [VALUE], [DESCRIPTION])
+# -------------------------------------------
+# Set VARIABLE to VALUE, verbatim, or 1. Remember the value
+# and if VARIABLE is affected the same VALUE, do nothing, else
+# die. The third argument is used by autoheader.
+
+m4_define([SAC_SU_DEFINE],[
+cat >>confdefs.h <<\_AXEOF
+[@%:@define] $1 m4_if($#, 2, [$2], $#, 3, [$2], 1)
+_AXEOF
+])
+
+# SAC_SU_DEFINE_UNQUOTED(VARIABLE, [VALUE], [DESCRIPTION])
+# ----------------------------------------------------
+# Similar, but perform shell substitutions $ ` \ once on VALUE.
+m4_define([SAC_SU_DEFINE_UNQUOTED],[
+cat >>confdefs.h <<_ACEOF
+[@%:@define] $1 m4_if($#, 2, [$2], $#, 3, [$2], 1)
+_ACEOF
+])
+
+AC_DEFUN([SAC_REPLACE_FUNCS],[dnl
+AC_CHECK_FUNCS([$1],ifelse([$2], , :,[$2]),[dnl
+case "$REPLACE_LIBADD" in
+ "$ac_func.lo" | \
+ *" $ac_func.lo" | \
+ "$ac_func.lo "* | \
+ *" $ac_func.lo "* ) ;;
+ *) REPLACE_LIBADD="$REPLACE_LIBADD $ac_func.lo" ;;
+esac])
+AC_SUBST([REPLACE_LIBADD])
+ifelse([$3], , :, [$3])
+])
Added: freeswitch/trunk/libs/sofia-sip/m4/sac-tport.m4
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/m4/sac-tport.m4 Thu Dec 21 01:30:28 2006
@@ -0,0 +1,39 @@
+dnl ======================================================================
+dnl SAC_TPORT - perform checks for tport
+dnl ======================================================================
+AC_DEFUN([SAC_TPORT], [
+
+AC_ARG_WITH(sigcomp,
+[ --with-sigcomp=dir use Sofia SigComp package (not used by default)],,
+ with_sigcomp=no)
+
+if test -n "${with_sigcomp}" && test "${with_sigcomp}" != no ; then
+ if test "${with_sigcomp}" != yes ; then
+ CPPFLAGS="-I${with_sigcomp}/include $CPPFLAGS"
+ LIBS="-L${with_sigcomp}/lib -lsigcomp $LIBS"
+ else
+ LIBS="-lsigcomp $LIBS"
+ fi
+
+ AC_CHECK_HEADERS(sigcomp.h,,AC_MSG_ERROR([cannot find Sofia SigComp includes]))
+
+ AC_CHECK_FUNC(sigcomp_library_2_5,
+ [AC_DEFINE([HAVE_SIGCOMP], 1, [Define to 1 if you have Sofia sigcomp >= 2.5])
+ AC_DEFINE([HAVE_SOFIA_SIGCOMP], 1, [Define to 1 if you have Sofia sigcomp >= 2.5])],
+ AC_MSG_ERROR(Sofia SigComp API >= 2.5 was not found))
+fi
+
+# Check for features used by tport.
+AC_SYS_IP_RECVERR
+AC_SYS_IPV6_RECVERR
+
+AC_CHECK_HEADERS(netinet/tcp.h netinet/sctp.h)
+
+AC_ARG_WITH(sctp,
+[ --enable-sctp use LK-SCTP (not used by default)],,
+ enable_sigcomp=no)
+
+if test x$enable_sctp = xyes; then
+AC_DEFINE(HAVE_SCTP, 1, [Define to 1 if you have SCTP])
+fi
+])
Added: freeswitch/trunk/libs/sofia-sip/missing
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/missing Thu Dec 21 01:30:28 2006
@@ -0,0 +1,353 @@
+#! /bin/sh
+# Common stub for a few missing GNU programs while installing.
+
+scriptversion=2004-09-07.08
+
+# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004
+# Free Software Foundation, Inc.
+# Originally by Fran,cois Pinard <pinard at iro.umontreal.ca>, 1996.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program 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 General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+if test $# -eq 0; then
+ echo 1>&2 "Try \`$0 --help' for more information"
+ exit 1
+fi
+
+run=:
+
+# In the cases where this matters, `missing' is being run in the
+# srcdir already.
+if test -f configure.ac; then
+ configure_ac=configure.ac
+else
+ configure_ac=configure.in
+fi
+
+msg="missing on your system"
+
+case "$1" in
+--run)
+ # Try to run requested program, and just exit if it succeeds.
+ run=
+ shift
+ "$@" && exit 0
+ # Exit code 63 means version mismatch. This often happens
+ # when the user try to use an ancient version of a tool on
+ # a file that requires a minimum version. In this case we
+ # we should proceed has if the program had been absent, or
+ # if --run hadn't been passed.
+ if test $? = 63; then
+ run=:
+ msg="probably too old"
+ fi
+ ;;
+
+ -h|--h|--he|--hel|--help)
+ echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
+error status if there is no known handling for PROGRAM.
+
+Options:
+ -h, --help display this help and exit
+ -v, --version output version information and exit
+ --run try to run the given command, and emulate it if it fails
+
+Supported PROGRAM values:
+ aclocal touch file \`aclocal.m4'
+ autoconf touch file \`configure'
+ autoheader touch file \`config.h.in'
+ automake touch all \`Makefile.in' files
+ bison create \`y.tab.[ch]', if possible, from existing .[ch]
+ flex create \`lex.yy.c', if possible, from existing .c
+ help2man touch the output file
+ lex create \`lex.yy.c', if possible, from existing .c
+ makeinfo touch the output file
+ tar try tar, gnutar, gtar, then tar without non-portable flags
+ yacc create \`y.tab.[ch]', if possible, from existing .[ch]
+
+Send bug reports to <bug-automake at gnu.org>."
+ exit 0
+ ;;
+
+ -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+ echo "missing $scriptversion (GNU Automake)"
+ exit 0
+ ;;
+
+ -*)
+ echo 1>&2 "$0: Unknown \`$1' option"
+ echo 1>&2 "Try \`$0 --help' for more information"
+ exit 1
+ ;;
+
+esac
+
+# Now exit if we have it, but it failed. Also exit now if we
+# don't have it and --version was passed (most likely to detect
+# the program).
+case "$1" in
+ lex|yacc)
+ # Not GNU programs, they don't have --version.
+ ;;
+
+ tar)
+ if test -n "$run"; then
+ echo 1>&2 "ERROR: \`tar' requires --run"
+ exit 1
+ elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
+ exit 1
+ fi
+ ;;
+
+ *)
+ if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+ # We have it, but it failed.
+ exit 1
+ elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
+ # Could not run --version or --help. This is probably someone
+ # running `$TOOL --version' or `$TOOL --help' to check whether
+ # $TOOL exists and not knowing $TOOL uses missing.
+ exit 1
+ fi
+ ;;
+esac
+
+# If it does not exist, or fails to run (possibly an outdated version),
+# try to emulate it.
+case "$1" in
+ aclocal*)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`acinclude.m4' or \`${configure_ac}'. You might want
+ to install the \`Automake' and \`Perl' packages. Grab them from
+ any GNU archive site."
+ touch aclocal.m4
+ ;;
+
+ autoconf)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`${configure_ac}'. You might want to install the
+ \`Autoconf' and \`GNU m4' packages. Grab them from any GNU
+ archive site."
+ touch configure
+ ;;
+
+ autoheader)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`acconfig.h' or \`${configure_ac}'. You might want
+ to install the \`Autoconf' and \`GNU m4' packages. Grab them
+ from any GNU archive site."
+ files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}`
+ test -z "$files" && files="config.h"
+ touch_files=
+ for f in $files; do
+ case "$f" in
+ *:*) touch_files="$touch_files "`echo "$f" |
+ sed -e 's/^[^:]*://' -e 's/:.*//'`;;
+ *) touch_files="$touch_files $f.in";;
+ esac
+ done
+ touch $touch_files
+ ;;
+
+ automake*)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'.
+ You might want to install the \`Automake' and \`Perl' packages.
+ Grab them from any GNU archive site."
+ find . -type f -name Makefile.am -print |
+ sed 's/\.am$/.in/' |
+ while read f; do touch "$f"; done
+ ;;
+
+ autom4te)
+ echo 1>&2 "\
+WARNING: \`$1' is needed, but is $msg.
+ You might have modified some files without having the
+ proper tools for further handling them.
+ You can get \`$1' as part of \`Autoconf' from any GNU
+ archive site."
+
+ file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'`
+ test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'`
+ if test -f "$file"; then
+ touch $file
+ else
+ test -z "$file" || exec >$file
+ echo "#! /bin/sh"
+ echo "# Created by GNU Automake missing as a replacement of"
+ echo "# $ $@"
+ echo "exit 0"
+ chmod +x $file
+ exit 1
+ fi
+ ;;
+
+ bison|yacc)
+ echo 1>&2 "\
+WARNING: \`$1' $msg. You should only need it if
+ you modified a \`.y' file. You may need the \`Bison' package
+ in order for those modifications to take effect. You can get
+ \`Bison' from any GNU archive site."
+ rm -f y.tab.c y.tab.h
+ if [ $# -ne 1 ]; then
+ eval LASTARG="\${$#}"
+ case "$LASTARG" in
+ *.y)
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" y.tab.c
+ fi
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" y.tab.h
+ fi
+ ;;
+ esac
+ fi
+ if [ ! -f y.tab.h ]; then
+ echo >y.tab.h
+ fi
+ if [ ! -f y.tab.c ]; then
+ echo 'main() { return 0; }' >y.tab.c
+ fi
+ ;;
+
+ lex|flex)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified a \`.l' file. You may need the \`Flex' package
+ in order for those modifications to take effect. You can get
+ \`Flex' from any GNU archive site."
+ rm -f lex.yy.c
+ if [ $# -ne 1 ]; then
+ eval LASTARG="\${$#}"
+ case "$LASTARG" in
+ *.l)
+ SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" lex.yy.c
+ fi
+ ;;
+ esac
+ fi
+ if [ ! -f lex.yy.c ]; then
+ echo 'main() { return 0; }' >lex.yy.c
+ fi
+ ;;
+
+ help2man)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified a dependency of a manual page. You may need the
+ \`Help2man' package in order for those modifications to take
+ effect. You can get \`Help2man' from any GNU archive site."
+
+ file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
+ if test -z "$file"; then
+ file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'`
+ fi
+ if [ -f "$file" ]; then
+ touch $file
+ else
+ test -z "$file" || exec >$file
+ echo ".ab help2man is required to generate this page"
+ exit 1
+ fi
+ ;;
+
+ makeinfo)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified a \`.texi' or \`.texinfo' file, or any other file
+ indirectly affecting the aspect of the manual. The spurious
+ call might also be the consequence of using a buggy \`make' (AIX,
+ DU, IRIX). You might want to install the \`Texinfo' package or
+ the \`GNU make' package. Grab either from any GNU archive site."
+ file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
+ if test -z "$file"; then
+ file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
+ file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file`
+ fi
+ touch $file
+ ;;
+
+ tar)
+ shift
+
+ # We have already tried tar in the generic part.
+ # Look for gnutar/gtar before invocation to avoid ugly error
+ # messages.
+ if (gnutar --version > /dev/null 2>&1); then
+ gnutar "$@" && exit 0
+ fi
+ if (gtar --version > /dev/null 2>&1); then
+ gtar "$@" && exit 0
+ fi
+ firstarg="$1"
+ if shift; then
+ case "$firstarg" in
+ *o*)
+ firstarg=`echo "$firstarg" | sed s/o//`
+ tar "$firstarg" "$@" && exit 0
+ ;;
+ esac
+ case "$firstarg" in
+ *h*)
+ firstarg=`echo "$firstarg" | sed s/h//`
+ tar "$firstarg" "$@" && exit 0
+ ;;
+ esac
+ fi
+
+ echo 1>&2 "\
+WARNING: I can't seem to be able to run \`tar' with the given arguments.
+ You may want to install GNU tar or Free paxutils, or check the
+ command line arguments."
+ exit 1
+ ;;
+
+ *)
+ echo 1>&2 "\
+WARNING: \`$1' is needed, and is $msg.
+ You might have modified some files without having the
+ proper tools for further handling them. Check the \`README' file,
+ it often tells you about the needed prerequisites for installing
+ this package. You may also peek at any GNU archive site, in case
+ some other package would contain this missing \`$1' program."
+ exit 1
+ ;;
+esac
+
+exit 0
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
Added: freeswitch/trunk/libs/sofia-sip/packages/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/packages/ChangeLog Thu Dec 21 01:30:28 2006
@@ -0,0 +1,26 @@
+2005-11-15 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * sofia-sip.spec.in: Removed the --includedir parameter.
+ The public headers are now installed under
+ includedir/sofia-sip-MAJOR.MINOR/
+
+2005-10-06 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Added debian example directory from M Mela.
+
+ A ./packages/debian/
+ A ./packages/debian/README.Debian
+ A ./packages/debian/changelog
+ A ./packages/debian/compat
+ A ./packages/debian/control
+ A ./packages/debian/copyright
+ A ./packages/debian/docs
+ A ./packages/debian/files
+ A ./packages/debian/postinst.ex
+ A ./packages/debian/postrm.ex
+ A ./packages/debian/preinst.ex
+ A ./packages/debian/prerm.ex
+ A ./packages/debian/rules
+ A ./packages/debian/sofia-sip-default.ex
+ A ./packages/debian/sofia-sip.postinst.debhelper
+ A ./packages/debian/sofia-sip.postrm.debhelper
Added: freeswitch/trunk/libs/sofia-sip/packages/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/packages/Makefile.am Thu Dec 21 01:30:28 2006
@@ -0,0 +1,21 @@
+#
+# Makefile.am for sofia-sip/packages
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+# Install pkg-config file here
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = sofia-sip-ua.pc
+
+if HAVE_GLIB
+# We should probably have something here telling
+# if we have gobject support or not
+pkgconfig_DATA += sofia-sip-ua-glib.pc
+endif
+
+EXTRA_DIST = sofia-sip-${PACKAGE_VERSION}.spec sofia-sip.spec.in
+EXTRA_DIST += sofia-sip-ua.pc.in sofia-sip-ua-glib.pc.in
+
+DISTCLEANFILES = sofia-sip-*.spec sofia-sip.spec
Added: freeswitch/trunk/libs/sofia-sip/packages/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/packages/Makefile.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1,424 @@
+# 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.
+
+ at SET_MAKE@
+
+#
+# Makefile.am for sofia-sip/packages
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+
+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@
+
+# We should probably have something here telling
+# if we have gobject support or not
+ at HAVE_GLIB_TRUE@am__append_1 = sofia-sip-ua-glib.pc
+subdir = packages
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+ $(srcdir)/sofia-sip-ua-glib.pc.in $(srcdir)/sofia-sip-ua.pc.in \
+ $(srcdir)/sofia-sip.spec.in ChangeLog
+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 = sofia-sip-ua.pc sofia-sip-ua-glib.pc \
+ sofia-sip-${PACKAGE_VERSION}.spec
+SOURCES =
+DIST_SOURCES =
+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|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(pkgconfigdir)"
+pkgconfigDATA_INSTALL = $(INSTALL_DATA)
+DATA = $(pkgconfig_DATA)
+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@
+
+# Install pkg-config file here
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = sofia-sip-ua.pc $(am__append_1)
+EXTRA_DIST = sofia-sip-${PACKAGE_VERSION}.spec sofia-sip.spec.in \
+ sofia-sip-ua.pc.in sofia-sip-ua-glib.pc.in
+DISTCLEANFILES = sofia-sip-*.spec sofia-sip.spec
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.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 packages/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu packages/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
+sofia-sip-ua.pc: $(top_builddir)/config.status $(srcdir)/sofia-sip-ua.pc.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+sofia-sip-ua-glib.pc: $(top_builddir)/config.status $(srcdir)/sofia-sip-ua-glib.pc.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+sofia-sip-${PACKAGE_VERSION}.spec: $(top_builddir)/config.status $(srcdir)/sofia-sip.spec.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+uninstall-info-am:
+install-pkgconfigDATA: $(pkgconfig_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(pkgconfigdir)" || $(mkdir_p) "$(DESTDIR)$(pkgconfigdir)"
+ @list='$(pkgconfig_DATA)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ f=$(am__strip_dir) \
+ echo " $(pkgconfigDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgconfigdir)/$$f'"; \
+ $(pkgconfigDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgconfigdir)/$$f"; \
+ done
+
+uninstall-pkgconfigDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkgconfig_DATA)'; for p in $$list; do \
+ f=$(am__strip_dir) \
+ echo " rm -f '$(DESTDIR)$(pkgconfigdir)/$$f'"; \
+ rm -f "$(DESTDIR)$(pkgconfigdir)/$$f"; \
+ done
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+distdir: $(DISTFILES)
+ @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
+check: check-am
+all-am: Makefile $(DATA)
+installdirs:
+ for dir in "$(DESTDIR)$(pkgconfigdir)"; do \
+ test -z "$$dir" || $(mkdir_p) "$$dir"; \
+ done
+install: 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."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-libtool
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pkgconfigDATA
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-pkgconfigDATA
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ distclean distclean-generic distclean-libtool distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-exec install-exec-am \
+ install-info install-info-am install-man install-pkgconfigDATA \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ uninstall uninstall-am uninstall-info-am \
+ uninstall-pkgconfigDATA
+
+# 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:
Added: freeswitch/trunk/libs/sofia-sip/packages/sofia-sip-ua-glib.pc.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/packages/sofia-sip-ua-glib.pc.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1,14 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+libexecdir=@libexecdir@
+includedir=@includedir@
+include_sofiadir=@include_sofiadir@
+gobject=@HAVE_GOBJECT@
+
+Name: sofia-sip-ua-glib
+Description: Sofia-SIP library bindings for glib
+Version: @PACKAGE_VERSION@
+Requires: sofia-sip-ua, @SOFIA_GLIB_PKG_REQUIRES@
+Libs: -L${libdir} -lsofia-sip-ua-glib
+Cflags: -I at include_sofiadir@
Added: freeswitch/trunk/libs/sofia-sip/packages/sofia-sip-ua.pc.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/packages/sofia-sip-ua.pc.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1,15 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+libexecdir=@libexecdir@
+includedir=@includedir@
+include_sofiadir=@include_sofiadir@
+sofiaawkdir=@datadir@/@PACKAGE@
+
+Name: sofia-sip-ua
+Description: Sofia-SIP - a RFC3261 compliant SIP User-Agent library
+Version: @VERSION@
+Libs: -L${libdir} -lsofia-sip-ua
+Libs.private: @LIBS@
+Cflags: -I at include_sofiadir@
+
Added: freeswitch/trunk/libs/sofia-sip/packages/sofia-sip.spec.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/packages/sofia-sip.spec.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1,247 @@
+# Sofia SIP UA Library
+
+Summary: Sofia SIP User-Agent library
+Name: sofia-sip
+Version: @VERSION@
+Release: 1%{?dist}
+License: LGPL
+Group: System Environment/Libraries
+URL: http://sf.net/projects/sofia-sip
+Source0: %{name}-%{version}.tar.gz
+BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root
+
+BuildRequires: pkgconfig
+
+%{!?bcond_with:%define bcond_with() %{expand:%%{?_with_%{1}:%%global with_%{1} 1}}}
+%{!?bcond_without:%define bcond_without() %{expand:%%{!?_without_%{1}:%%global with_%{1} 1}}}
+
+# Options:
+%bcond_with doxygen - Generate documents using doxygen and dot
+%bcond_with check - Run tests
+%bcond_with openssl - Always use OpenSSL (TLS)
+%bcond_with glib - Always use glib-2.0 (>= 2.2)
+%bcond_with sctp - Include SCTP transport
+
+%define have_doxygen %{?_with_doxygen:1}%{!?_with_doxygen:0}
+%define have_openssl %(%{?!_with_openssl:pkg-config 'openssl >= 0.9.7'&&}echo 1||echo 0)
+%define have_glib %(%{?!_with_glib:pkg-config 'glib-2.0 >= 2.2'&&}echo 1||echo 0)
+
+%if %{have_doxygen}
+BuildRequires: doxygen >= 1.3, graphviz
+%endif
+%if %{have_openssl}
+BuildRequires: openssl-devel >= 0.9.7
+%endif
+%if %{have_glib}
+BuildRequires: glib2-devel >= 2.2
+%endif
+
+%description
+Sofia SIP is a RFC-3261-compliant library for SIP user agents and other
+network elements.
+
+%prep
+%setup -q
+
+%build
+options="--disable-dependency-tracking"
+options="$options --with-pic --enable-shared --disable-static"
+%if !%{have_glib}
+options="$options --without-glib"
+%endif
+%if %{with sctp}
+options="$options --enable-sctp"
+%endif
+
+%configure $options
+
+make %{_smp_mflags}
+%if %{have_doxygen}
+make doxygen
+%endif
+
+# XXX comment next line to build with non-check aware rpmbuild.
+%check
+%if %{with check}
+make check
+%endif
+
+%install
+rm -rf $RPM_BUILD_ROOT
+make install DESTDIR=$RPM_BUILD_ROOT
+
+# Remove extra files
+find $RPM_BUILD_ROOT -type f -name *.la -print0 | xargs -0 rm
+
+%if %{have_doxygen}
+# Manually install development docs into manual
+cp -p -r libsofia-sip-ua/docs/html manual
+%endif
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%post -p /sbin/ldconfig
+
+%postun -p /sbin/ldconfig
+
+%files
+%defattr(-,root,root,-)
+%{_libdir}/libsofia-sip-ua.so.*
+%doc AUTHORS COPYING COPYRIGHTS README
+
+%if %{have_glib}
+# note: soname in pkgname allows install of multiple library versions
+# The glib interface is still a bit unstable
+%package glib at LIBVER_SOFIA_SIP_UA_GLIB_SOVER@
+Summary: GLIB bindings for Sofia-SIP
+Group: System Environment/Libraries
+Requires: sofia-sip
+Obsoletes: sofia-sip-glib < %{version}-%{release}
+Provides: sofia-sip-glib = %{version}-%{release}
+
+%description glib at LIBVER_SOFIA_SIP_UA_GLIB_SOVER@
+GLib interface to Sofia SIP User Agent library.
+
+%files glib at LIBVER_SOFIA_SIP_UA_GLIB_SOVER@
+%defattr(-,root,root,-)
+%{_libdir}/libsofia-sip-ua-glib.so.*
+%doc AUTHORS COPYING COPYRIGHTS README libsofia-sip-ua-glib/ChangeLog
+
+%post glib at LIBVER_SOFIA_SIP_UA_GLIB_SOVER@ -p /sbin/ldconfig
+%postun glib at LIBVER_SOFIA_SIP_UA_GLIB_SOVER@ -p /sbin/ldconfig
+
+%endif
+
+%package devel
+Summary: Sofia-SIP Development Package
+Group: Development/Libraries
+Requires: sofia-sip = %{version}-%{release}
+Obsoletes: sofia-devel < %{version}-%{release}
+Provides: sofia-devel = %{version}-%{release}
+
+Requires: pkgconfig
+
+%description devel
+Development package for Sofia SIP UA library. This package includes
+static libraries and include files.
+
+%if %{without doxygen}
+The reference documentation for Sofia SIP UA library is available at
+<http://sofia-sip.sourceforge.net/development.html>
+%endif
+
+%files devel
+%defattr(-,root,root,-)
+%dir %{_includedir}/sofia-sip*
+%dir %{_includedir}/sofia-sip*/sofia-sip
+%{_includedir}/sofia-sip*/sofia-sip/*.h
+%{_includedir}/sofia-sip*/sofia-sip/*.h.in
+%dir %{_includedir}/sofia-sip*/sofia-resolv
+%{_includedir}/sofia-sip*/sofia-resolv/*.h
+%dir %{_datadir}/sofia-sip
+%{_datadir}/sofia-sip/tag_dll.awk
+%{_datadir}/sofia-sip/msg_parser.awk
+%{_libdir}/libsofia-sip-ua.so
+%{_libdir}/pkgconfig/sofia-sip-ua.pc
+%doc TODO README.developers
+
+%if %{have_glib}
+# note: no soname here as no multiple glib-devel packages can co-exist in peace
+%package glib-devel
+Summary: GLIB bindings for Sofia SIP development files
+Group: Development/Libraries
+Requires: sofia-sip-glib at LIBVER_SOFIA_SIP_UA_GLIB_SOVER@ = %{version}-%{release}
+Requires: sofia-sip-devel >= 1.12
+BuildRequires: glib2-devel >= 2.2
+
+%description glib-devel
+Development package for Sofia SIP UA Glib library. This package includes
+static libraries and include files for developing glib programs using Sofia
+SIP.
+
+%files glib-devel
+%defattr(-,root,root,-)
+%{_includedir}/sofia-sip*/sofia-sip/su_source.h
+%{_libdir}/libsofia-sip-ua-glib.so
+%{_libdir}/pkgconfig/sofia-sip-ua-glib.pc
+%endif
+
+%package docs
+Summary: Sofia-SIP Development Manual Package
+Group: Documentation
+%description docs
+HTML reference documentation for Sofia SIP UA library.
+
+%if %{have_doxygen}
+%files docs
+%defattr(-,root,root,-)
+%doc manual
+%endif
+
+%package utils
+Summary: Sofia-SIP Command Line Utilities
+Group: Applications/Internet
+Requires: sofia-sip = %{version}-%{release}
+Obsoletes: sofia-utils < %{version}-%{release}
+Provides: sofia-utils = %{version}-%{release}
+%description utils
+Command line utilities for Sofia SIP UA library.
+
+%files utils
+%defattr(-,root,root,-)
+%{_bindir}/localinfo
+%{_bindir}/addrinfo
+%{_bindir}/sip-options
+%{_bindir}/sip-date
+%{_bindir}/sip-dig
+%{_bindir}/stunc
+%{_mandir}/man?/*
+
+%changelog
+* Thu Dec 7 2006 Pekka Pessi <ppessi at gmail.com> - 1.12.4-1
+- Silenced all rpmlint warnings on FC6.
+
+* Wed Dec 6 2006 Pekka Pessi <ppessi at gmail.com> - 1.12.4-0
+- Fixing optional values on Fedora. rpmlinted. No doxygen docs.
+
+* Tue Dec 5 2006 Pekka Pessi <ppessi at gmail.com> - 1.12.4
+- Bumped version. rpmlinted.
+
+* Tue Dec 5 2006 Kai Vehmanen <first.lastname at nokia.com>
+- The 'nua-glib' module, and the related dependency to gobject, has been
+ removed from the sofia-sip package
+
+* Fri Oct 6 2006 Pekka Pessi <ppessi at gmail.com> - 1.12.3
+- Autodetecting openssl, glib and gobject support with pkg-config
+ (use --with openssl --with glib and --with gobject to force them)
+
+* Mon Sep 18 2006 Kai Vehmanen <first.lastname at nokia.com>
+- Removed *.m4 files from the distribution package.
+
+* Fri Aug 11 2006 Kai Vehmanen <first.lastname at nokia.com>
+- Modified the install location of the awk scripts.
+
+* Thu Jun 15 2006 Kai Vehmanen <first.lastname at nokia.com>
+- Added library soname to sofia-sip-glib package name.
+- Modified dependencies - the glib subpackages do not depend
+ on a specific version of sofia-sip anymore.
+
+* Wed Mar 08 2006 Kai Vehmanen <first.lastname at nokia.com>
+- Added libsofia-sip-ua-glib to the package.
+
+* Tue Nov 15 2005 Kai Vehmanen <first.lastname at nokia.com>
+- Removed the --includedir parameter. The public headers are
+ now installed under includedir/sofia-sip-MAJOR.MINOR/
+
+* Thu Oct 20 2005 Pekka Pessi <first.lastname at nokia.com>
+- Using %%{_lib} instead of lib
+
+* Thu Oct 6 2005 Pekka Pessi <first.lastname at nokia.com>
+- Added sub-package utils
+
+* Thu Oct 6 2005 Pekka Pessi <first.lastname at nokia.com> - 1.11.0
+- Added %%{?dist} to release
+
+* Sat Jul 23 2005 Pekka Pessi <first.lastname at nokia.com> - 1.10.1
+- Initial build.
Added: freeswitch/trunk/libs/sofia-sip/scripts/coverage
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/scripts/coverage Thu Dec 21 01:30:28 2006
@@ -0,0 +1,114 @@
+#!/bin/sh
+#
+# Calculate coverage of source files
+#
+
+gcovflags=-n
+
+usage ()
+{
+ cat <<EOF
+usage: coverage [OPTIONS] [output-files]
+ where OPTIONS are:
+ --output generate .gcov files
+ --help -h -? print this message
+EOF
+ exit $1
+}
+
+while true; do
+case "$1" in
+--output ) gcovflags= ; shift ;;
+'-?' | -h | --help ) usage ;;
+- ) shift ; break ;;
+-* ) usage 1 ;;
+* ) break ;;
+esac
+done
+
+{
+for f in *.bb
+do
+ test "$f" = "*.bb" && { echo "run 'make check' first"; exit 1; }
+ gcov $gcovflags "$f" 2>/dev/null
+done
+for f in $@
+do
+ gcov $gcovflags "$f" 2>/dev/null
+done
+} |
+awk '
+BEGIN {
+'"$(for f in "$@"; do echo 'include["'$f'"] = 1;'; done)"'
+}
+
+/^File/ {
+ if (sub(/^File `\/home\/ppessi\/sofia-proxy\/(proxy\/..\/)?/, "")) {
+ sub(/.$/, "");
+ file=$0;
+ if (file ~ /torture/) file = "";
+ }
+ else
+ file = "";
+}
+file ~ /\.[hc]$/ && /Lines executed/ {
+ sub(/Lines executed:/, "");
+ covered = int($3*$1/100 + 0.5);
+
+# printf "%-5u %-5u %-5u %-7s %s\n", $3, covered, $3 - covered, $1, file;
+ if ($3 == 0) {
+ /* skip */
+ }
+ else if (!lines[file]) {
+ names[i++] = file; lines[file] = $3; coverage[file] = covered;
+ coverage[file] = $3*$1/100;
+ }
+ else if (coverage[file] < covered) {
+ lines[file] = $3; coverage[file] = covered;
+ coverage[file] = $3*$1/100;
+ }
+}
+
+/torture/ { next; }
+/test/ { next; }
+/\/usr\/include/ { next; }
+
+/(source )?lines executed in file (.*\/)?[-A-Za-z_0-9]+\.[ch]/ {
+ file = $0;
+ sub(/.* in file /, "", file);
+ sub(/.*\//, "", file);
+ covered = int($3*$1/100 + 0.5);
+ #printf "%-5u %-5u %-5u %-7s %s\n", $3, covered, $3 - covered, $1, file;
+
+ if ($3 == 0) {
+ /* skip */
+ }
+ else if (!file in lines) {
+ lines[file] = $3; coverage[file] = $3*$1/100;
+ }
+ else if (coverage[file] <= $3*$1/100) {
+ lines[file] = $3; coverage[file] = $3*$1/100;
+ }
+}
+
+END {
+ for (file in lines) {
+ if (!(file in include))
+ continue;
+ l = lines[file]; c = coverage[file];
+ covered = int(c + 0.5);
+ total += l; total_coverage += c;
+ printf "%-5u %-5u %-5u %6.2f%% %s\n",
+ l, covered, l - covered, 100.0 * c / l, file;
+ }
+ if (total) {
+ module = ENVIRON["PWD"];
+ gsub(/\/+$/, "", module);
+ gsub(/.*\//, "", module);
+ printf "%-5u %-5u %-5u %6.2f%% %s in %s\n",
+ total, total_coverage, total - total_coverage,
+ 100.0 * total_coverage / total, "TOTAL", module;
+ }
+}
+' |
+sort -n
Added: freeswitch/trunk/libs/sofia-sip/scripts/fix-include-sofia-sip
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/scripts/fix-include-sofia-sip Thu Dec 21 01:30:28 2006
@@ -0,0 +1,209 @@
+#! /bin/sed -f
+#
+# Run this script like
+#
+# fix-include-sofia-sip -i.bak source.h source.c
+#
+# or
+#
+# find . -name '*.[hc]' -print0 | xargs -0 fix-include-sofia-sip -i.bak
+#
+/^ *# *include/ {
+# Not using features.h...
+s!include *<sofia-sip/features.h>!include <sofia-sip/sofia_features.h>!
+s!include *"sofia-sip/features.h"!include "sofia-sip/sofia_features.h"!
+s!include *<bnf.h>!include <sofia-sip/bnf.h>!
+s!include *<sofia_sip_features.h>!include <sofia-sip/sofia_features.h>!
+s!include *<http.h>!include <sofia-sip/http.h>!
+s!include *<http_hclasses.h>!include <sofia-sip/http_hclasses.h>!
+s!include *<http_header.h>!include <sofia-sip/http_header.h>!
+s!include *<http_parser.h>!include <sofia-sip/http_parser.h>!
+s!include *<http_protos.h>!include <sofia-sip/http_protos.h>!
+s!include *<http_status.h>!include <sofia-sip/http_status.h>!
+s!include *<http_tag.h>!include <sofia-sip/http_tag.h>!
+s!include *<http_tag_class.h>!include <sofia-sip/http_tag_class.h>!
+s!include *<base64.h>!include <sofia-sip/base64.h>!
+s!include *<rc4.h>!include <sofia-sip/rc4.h>!
+s!include *<sha1.h>!include <sofia-sip/sha1.h>!
+s!include *<string0.h>!include <sofia-sip/string0.h>!
+s!include *<token64.h>!include <sofia-sip/token64.h>!
+s!include *<uniqueid.h>!include <sofia-sip/uniqueid.h>!
+s!include *<utf8.h>!include <sofia-sip/utf8.h>!
+s!include *<auth_client.h>!include <sofia-sip/auth_client.h>!
+s!include *<auth_digest.h>!include <sofia-sip/auth_digest.h>!
+s!include *<auth_module.h>!include <sofia-sip/auth_module.h>!
+s!include *<auth_plugin.h>!include <sofia-sip/auth_plugin.h>!
+s!include *<msg.h>!include <sofia-sip/msg.h>!
+s!include *<msg_addr.h>!include <sofia-sip/msg_addr.h>!
+s!include *<msg_buffer.h>!include <sofia-sip/msg_buffer.h>!
+s!include *<msg_date.h>!include <sofia-sip/msg_date.h>!
+s!include *<msg_header.h>!include <sofia-sip/msg_header.h>!
+s!include *<msg_mclass.h>!include <sofia-sip/msg_mclass.h>!
+s!include *<msg_mclass_hash.h>!include <sofia-sip/msg_mclass_hash.h>!
+s!include *<msg_mime.h>!include <sofia-sip/msg_mime.h>!
+s!include *<msg_mime_protos.h>!include <sofia-sip/msg_mime_protos.h>!
+s!include *<msg_parser.h>!include <sofia-sip/msg_parser.h>!
+s!include *<msg_protos.h>!include <sofia-sip/msg_protos.h>!
+s!include *<msg_tag_class.h>!include <sofia-sip/msg_tag_class.h>!
+s!include *<msg_types.h>!include <sofia-sip/msg_types.h>!
+s!include *<nea.h>!include <sofia-sip/nea.h>!
+s!include *<nea_tag.h>!include <sofia-sip/nea_tag.h>!
+s!include *<nta.h>!include <sofia-sip/nta.h>!
+s!include *<nta_stateless.h>!include <sofia-sip/nta_stateless.h>!
+s!include *<nta_tag.h>!include <sofia-sip/nta_tag.h>!
+s!include *<nta_tport.h>!include <sofia-sip/nta_tport.h>!
+s!include *<sl_utils.h>!include <sofia-sip/sl_utils.h>!
+s!include *<nth.h>!include <sofia-sip/nth.h>!
+s!include *<nth_tag.h>!include <sofia-sip/nth_tag.h>!
+s!include *<nua.h>!include <sofia-sip/nua.h>!
+s!include *<nua_tag.h>!include <sofia-sip/nua_tag.h>!
+s!include *<sdp.h>!include <sofia-sip/sdp.h>!
+s!include *<sdp_tag.h>!include <sofia-sip/sdp_tag.h>!
+s!include *<sip.h>!include <sofia-sip/sip.h>!
+s!include *<sip_hclasses.h>!include <sofia-sip/sip_hclasses.h>!
+s!include *<sip_header.h>!include <sofia-sip/sip_header.h>!
+s!include *<sip_parser.h>!include <sofia-sip/sip_parser.h>!
+s!include *<sip_protos.h>!include <sofia-sip/sip_protos.h>!
+s!include *<sip_status.h>!include <sofia-sip/sip_status.h>!
+s!include *<sip_tag.h>!include <sofia-sip/sip_tag.h>!
+s!include *<sip_tag_class.h>!include <sofia-sip/sip_tag_class.h>!
+s!include *<sip_util.h>!include <sofia-sip/sip_util.h>!
+s!include *<soa.h>!include <sofia-sip/soa.h>!
+s!include *<soa_add.h>!include <sofia-sip/soa_add.h>!
+s!include *<soa_session.h>!include <sofia-sip/soa_session.h>!
+s!include *<soa_tag.h>!include <sofia-sip/soa_tag.h>!
+s!include *<sresolv.h>!include <sofia-sip/sresolv.h>!
+s!include *<stun.h>!include <sofia-sip/stun.h>!
+s!include *<stun_common.h>!include <sofia-sip/stun_common.h>!
+s!include *<stun_tag.h>!include <sofia-sip/stun_tag.h>!
+s!include *<htable.h>!include <sofia-sip/htable.h>!
+s!include *<htable2.h>!include <sofia-sip/htable2.h>!
+s!include *<rbtree.h>!include <sofia-sip/rbtree.h>!
+s!include *<su.h>!include <sofia-sip/su.h>!
+s!include *<su_addrinfo.h>!include <sofia-sip/su_addrinfo.h>!
+s!include *<su_alloc.h>!include <sofia-sip/su_alloc.h>!
+s!include *<su_alloc_stat.h>!include <sofia-sip/su_alloc_stat.h>!
+s!include *<su_memmem.h>!include <sofia-sip/su_bm.h>!
+s!include *<su_config.h>!include <sofia-sip/su_config.h>!
+s!include *<su_configure.h>!include <sofia-sip/su_configure.h>!
+s!include *<su_debug.h>!include <sofia-sip/su_debug.h>!
+s!include *<su_errno.h>!include <sofia-sip/su_errno.h>!
+s!include *<su_localinfo.h>!include <sofia-sip/su_localinfo.h>!
+s!include *<su_log.h>!include <sofia-sip/su_log.h>!
+s!include *<su_md5.h>!include <sofia-sip/su_md5.h>!
+s!include *<su_source.h>!include <sofia-sip/su_source.h>!
+s!include *<su_strlst.h>!include <sofia-sip/su_strlst.h>!
+s!include *<su_tag.h>!include <sofia-sip/su_tag.h>!
+s!include *<su_tag_class.h>!include <sofia-sip/su_tag_class.h>!
+s!include *<su_tag_inline.h>!include <sofia-sip/su_tag_inline.h>!
+s!include *<su_tag_io.h>!include <sofia-sip/su_tag_io.h>!
+s!include *<su_tagarg.h>!include <sofia-sip/su_tagarg.h>!
+s!include *<su_time.h>!include <sofia-sip/su_time.h>!
+s!include *<su_types.h>!include <sofia-sip/su_types.h>!
+s!include *<su_uniqueid.h>!include <sofia-sip/su_uniqueid.h>!
+s!include *<su_vector.h>!include <sofia-sip/su_vector.h>!
+s!include *<su_wait.h>!include <sofia-sip/su_wait.h>!
+s!include *<tstdef.h>!include <sofia-sip/tstdef.h>!
+s!include *<tport.h>!include <sofia-sip/tport.h>!
+s!include *<tport_tag.h>!include <sofia-sip/tport_tag.h>!
+s!include *<url.h>!include <sofia-sip/url.h>!
+s!include *<url_tag.h>!include <sofia-sip/url_tag.h>!
+s!include *<url_tag_class.h>!include <sofia-sip/url_tag_class.h>!
+s!include *"bnf.h"!include "sofia-sip/bnf.h"!
+s!include *"sofia_sip_features.h"!include "sofia-sip/sofia_features.h"!
+s!include *"http.h"!include "sofia-sip/http.h"!
+s!include *"http_hclasses.h"!include "sofia-sip/http_hclasses.h"!
+s!include *"http_header.h"!include "sofia-sip/http_header.h"!
+s!include *"http_parser.h"!include "sofia-sip/http_parser.h"!
+s!include *"http_protos.h"!include "sofia-sip/http_protos.h"!
+s!include *"http_status.h"!include "sofia-sip/http_status.h"!
+s!include *"http_tag.h"!include "sofia-sip/http_tag.h"!
+s!include *"http_tag_class.h"!include "sofia-sip/http_tag_class.h"!
+s!include *"base64.h"!include "sofia-sip/base64.h"!
+s!include *"rc4.h"!include "sofia-sip/rc4.h"!
+s!include *"sha1.h"!include "sofia-sip/sha1.h"!
+s!include *"string0.h"!include "sofia-sip/string0.h"!
+s!include *"token64.h"!include "sofia-sip/token64.h"!
+s!include *"uniqueid.h"!include "sofia-sip/uniqueid.h"!
+s!include *"utf8.h"!include "sofia-sip/utf8.h"!
+s!include *"auth_client.h"!include "sofia-sip/auth_client.h"!
+s!include *"auth_digest.h"!include "sofia-sip/auth_digest.h"!
+s!include *"auth_module.h"!include "sofia-sip/auth_module.h"!
+s!include *"auth_plugin.h"!include "sofia-sip/auth_plugin.h"!
+s!include *"msg.h"!include "sofia-sip/msg.h"!
+s!include *"msg_addr.h"!include "sofia-sip/msg_addr.h"!
+s!include *"msg_buffer.h"!include "sofia-sip/msg_buffer.h"!
+s!include *"msg_date.h"!include "sofia-sip/msg_date.h"!
+s!include *"msg_header.h"!include "sofia-sip/msg_header.h"!
+s!include *"msg_mclass.h"!include "sofia-sip/msg_mclass.h"!
+s!include *"msg_mclass_hash.h"!include "sofia-sip/msg_mclass_hash.h"!
+s!include *"msg_mime.h"!include "sofia-sip/msg_mime.h"!
+s!include *"msg_mime_protos.h"!include "sofia-sip/msg_mime_protos.h"!
+s!include *"msg_parser.h"!include "sofia-sip/msg_parser.h"!
+s!include *"msg_protos.h"!include "sofia-sip/msg_protos.h"!
+s!include *"msg_tag_class.h"!include "sofia-sip/msg_tag_class.h"!
+s!include *"msg_types.h"!include "sofia-sip/msg_types.h"!
+s!include *"nea.h"!include "sofia-sip/nea.h"!
+s!include *"nea_tag.h"!include "sofia-sip/nea_tag.h"!
+s!include *"nta.h"!include "sofia-sip/nta.h"!
+s!include *"nta_stateless.h"!include "sofia-sip/nta_stateless.h"!
+s!include *"nta_tag.h"!include "sofia-sip/nta_tag.h"!
+s!include *"nta_tport.h"!include "sofia-sip/nta_tport.h"!
+s!include *"sl_utils.h"!include "sofia-sip/sl_utils.h"!
+s!include *"nth.h"!include "sofia-sip/nth.h"!
+s!include *"nth_tag.h"!include "sofia-sip/nth_tag.h"!
+s!include *"nua.h"!include "sofia-sip/nua.h"!
+s!include *"nua_tag.h"!include "sofia-sip/nua_tag.h"!
+s!include *"sdp.h"!include "sofia-sip/sdp.h"!
+s!include *"sdp_tag.h"!include "sofia-sip/sdp_tag.h"!
+s!include *"sip.h"!include "sofia-sip/sip.h"!
+s!include *"sip_hclasses.h"!include "sofia-sip/sip_hclasses.h"!
+s!include *"sip_header.h"!include "sofia-sip/sip_header.h"!
+s!include *"sip_parser.h"!include "sofia-sip/sip_parser.h"!
+s!include *"sip_protos.h"!include "sofia-sip/sip_protos.h"!
+s!include *"sip_status.h"!include "sofia-sip/sip_status.h"!
+s!include *"sip_tag.h"!include "sofia-sip/sip_tag.h"!
+s!include *"sip_tag_class.h"!include "sofia-sip/sip_tag_class.h"!
+s!include *"sip_util.h"!include "sofia-sip/sip_util.h"!
+s!include *"soa.h"!include "sofia-sip/soa.h"!
+s!include *"soa_add.h"!include "sofia-sip/soa_add.h"!
+s!include *"soa_session.h"!include "sofia-sip/soa_session.h"!
+s!include *"soa_tag.h"!include "sofia-sip/soa_tag.h"!
+s!include *"sresolv.h"!include "sofia-sip/sresolv.h"!
+s!include *"stun.h"!include "sofia-sip/stun.h"!
+s!include *"stun_common.h"!include "sofia-sip/stun_common.h"!
+s!include *"stun_tag.h"!include "sofia-sip/stun_tag.h"!
+s!include *"htable.h"!include "sofia-sip/htable.h"!
+s!include *"htable2.h"!include "sofia-sip/htable2.h"!
+s!include *"rbtree.h"!include "sofia-sip/rbtree.h"!
+s!include *"su.h"!include "sofia-sip/su.h"!
+s!include *"su_addrinfo.h"!include "sofia-sip/su_addrinfo.h"!
+s!include *"su_alloc.h"!include "sofia-sip/su_alloc.h"!
+s!include *"su_alloc_stat.h"!include "sofia-sip/su_alloc_stat.h"!
+s!include *"su_memmem.h"!include "sofia-sip/su_bm.h"!
+s!include *"su_config.h"!include "sofia-sip/su_config.h"!
+s!include *"su_configure.h"!include "sofia-sip/su_configure.h"!
+s!include *"su_debug.h"!include "sofia-sip/su_debug.h"!
+s!include *"su_errno.h"!include "sofia-sip/su_errno.h"!
+s!include *"su_localinfo.h"!include "sofia-sip/su_localinfo.h"!
+s!include *"su_log.h"!include "sofia-sip/su_log.h"!
+s!include *"su_md5.h"!include "sofia-sip/su_md5.h"!
+s!include *"su_source.h"!include "sofia-sip/su_source.h"!
+s!include *"su_strlst.h"!include "sofia-sip/su_strlst.h"!
+s!include *"su_tag.h"!include "sofia-sip/su_tag.h"!
+s!include *"su_tag_class.h"!include "sofia-sip/su_tag_class.h"!
+s!include *"su_tag_inline.h"!include "sofia-sip/su_tag_inline.h"!
+s!include *"su_tag_io.h"!include "sofia-sip/su_tag_io.h"!
+s!include *"su_tagarg.h"!include "sofia-sip/su_tagarg.h"!
+s!include *"su_time.h"!include "sofia-sip/su_time.h"!
+s!include *"su_types.h"!include "sofia-sip/su_types.h"!
+s!include *"su_uniqueid.h"!include "sofia-sip/su_uniqueid.h"!
+s!include *"su_vector.h"!include "sofia-sip/su_vector.h"!
+s!include *"su_wait.h"!include "sofia-sip/su_wait.h"!
+s!include *"tstdef.h"!include "sofia-sip/tstdef.h"!
+s!include *"tport.h"!include "sofia-sip/tport.h"!
+s!include *"tport_tag.h"!include "sofia-sip/tport_tag.h"!
+s!include *"url.h"!include "sofia-sip/url.h"!
+s!include *"url_tag.h"!include "sofia-sip/url_tag.h"!
+s!include *"url_tag_class.h"!include "sofia-sip/url_tag_class.h"!
+}
\ No newline at end of file
Added: freeswitch/trunk/libs/sofia-sip/scripts/rpmbuild-snaphot
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/scripts/rpmbuild-snaphot Thu Dec 21 01:30:28 2006
@@ -0,0 +1,129 @@
+#!/usr/bin/env bash
+#
+# This script builds a snapshot RPM package of already existing Sofia-SIP
+# build tree
+#
+# Copyright (C) 2006 Nokia Corporation.
+#
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+#
+# Created: Fri May 23 17:16:54 EEST 2003 ppessi
+#
+
+function usage
+{
+ echo "usage: snapshot.sh [-bc|-bb] [-c|--configure] [rpmbuild options]"
+ exit $@
+}
+
+bb=-bb
+configure=0
+
+case "$1" in -b? ) bb=$1 ; shift ;; esac
+
+while true ; do
+ case "$1" in
+ -c | --configure | --co ) configure=1; shift; ;;
+ '-?' | --help | -h ) usage 0 ;;
+ *) break ;;
+ esac
+done
+
+test -z "$srcdir" && srcdir=.
+RPMROOT=${RPMROOT:-`rpmbuild --eval='%_topdir' --quiet 2> /dev/null`}
+
+c=$srcdir/configure.ac
+
+PACKAGE_NAME=$(sed -n '/^AC_INIT/ { s/[^[]*\[//; s/\].*//; p;}' $c)
+NAME=$(echo $PACKAGE_NAME | tr 'A-Z ' 'a-z-')
+VERSION=$(sed -n '/^AC_INIT/ { s/.*\], \[//; s/\].*//; p;}' $c)
+GLIB_SOVER=$(sed -n '/^AC_SUBST[(]LIBVER_SOFIA_SIP_UA_GLIB_SOVER/ { s/.*, \[//; s/\].*//; p;}' $c)
+
+# Find spec in
+if test -r $NAME.spec.in ; then
+ specin=$NAME.spec.in
+elif test -r packages/$NAME.spec.in ; then
+ specin=packages/$NAME.spec.in
+else
+ echo $NAME.spec.in: not found
+ exit 2
+fi
+
+specversion=$(sed -n -e '/^Version:/ { s/Version: //; p }' ${specin%.in})
+
+if [ "$VERSION" != "$specversion" ]; then
+ configure=1
+fi
+
+RELEASE=${RELEASE:-SNAP.$(date +"%Y%m%d.%H%M")}
+
+test -r config.status &&
+prefix=$(sed -n '/^s, at prefix@,/ { s/^s,[^,]*,//; s/,.*//; p;}' config.status)
+
+test -z "$prefix" && prefix=/usr
+
+wd=${TEMPDIR:=/tmp}/sofia-snapshot-$$
+spec=$wd/$NAME-${VERSION}-${RELEASE}.spec
+dummy=${NAME}-${VERSION}-${RELEASE}.tar.gz
+
+test -x ./configure || sh ./autogen.sh
+
+install -d ${RPMROOT}/{SOURCES/SNAP,SPECS,BUILD,RPMS,SRPMS} $wd &&
+echo Creating $spec &&
+awk '
+/@VERSION@/ { sub(/@VERSION@/, version); }
+/@PACKAGE@/ { sub(/@PACKAGE@/, package); }
+/@PACKAGE_NAME@/ { sub(/@PACKAGE_NAME@/, package_name); }
+/@LIBVER_SOFIA_SIP_UA_GLIB_SOVER@/ {
+ sub(/@LIBVER_SOFIA_SIP_UA_GLIB_SOVER@/, glib_sover);
+}
+/^Release:/ {
+ print "Release: " release "%{?dist}\n";
+ print "Prefix: " prefix "\n";
+ next;
+}
+/^Source0:/ { print "Source0:" dummy "\n"; next; }
+/disable-dependency-tracking/ {
+ sub(/--disable-dependency-tracking/, "");
+}
+/^%configure/ {
+ print "cd " "\"" pwd "\"";
+ if (!configure) { $1="echo skipping configure"; }
+ $1=$1 "-C --enable-maintainer-mode";
+ print $0;
+ next;
+}
+# Do not make documentation
+/^make doc/ { print "echo skipping " $0; next; }
+# Ignore CFLAGS set by RPM
+/^make/ { print "CFLAGS= " $0; next; }
+{ print; }' \
+pwd=$PWD \
+configure=$configure dummy=$dummy \
+package=$NAME package_name="$PACKAGE_NAME" \
+version=$VERSION release=$RELEASE glib_sover=$GLIB_SOVER prefix=$prefix \
+$specin > $spec &&
+ln -s `pwd` $wd/${NAME}-${VERSION} &&
+tar cfz ${RPMROOT}/SOURCES/SNAP/$dummy -C $wd ${NAME}-${VERSION} &&
+rpmbuild $bb $spec --define '__os_install_post /usr/lib/rpm/brp-compress' --without docs -D"_sourcedir ${RPMROOT}/SOURCES/SNAP" "$@"
+rc=$?
+
+rm -rf $wd
+rm ${RPMROOT}/SOURCES/SNAP/$dummy
+
+exit $rc
Added: freeswitch/trunk/libs/sofia-sip/utils/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/utils/ChangeLog Thu Dec 21 01:30:28 2006
@@ -0,0 +1,28 @@
+2006-02-08 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * Makefile.am, nua_cli.c: nua_cli example add removed from the
+ distribution package.
+
+2005-09-29 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Printing all events.
+
+ M ./utils/nua_cli.c -4 +15
+
+ * Not using MSS-related tags.
+
+ M ./utils/nua_cli.c +2
+
+2005-09-28 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Not using soa directly anymore.
+
+ M ./utils/nua_cli.c -5 +3
+
+2005-09-07 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * nua_cli.c: Cleaned up unused ifdefs.
+
+2005-09-07 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * ChangeLog: File created.
Added: freeswitch/trunk/libs/sofia-sip/utils/Doxyfile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/utils/Doxyfile Thu Dec 21 01:30:28 2006
@@ -0,0 +1,44 @@
+PROJECT_NAME = "sofia-sip"
+
+FILE_PATTERNS = *.h *.c
+
+EXCLUDE_PATTERNS = acconfig.h config.h confdefs.h \
+ test*.h test*.c torture*.c *test.c *torture.c \
+ *_tag_dll.c *_tag_ref.c
+
+TAGFILES =
+
+OUTPUT_LANGUAGE = English
+
+DETAILS_AT_TOP = YES
+OPTIMIZE_OUTPUT_FOR_C = YES
+SHOW_USED_FILES = NO
+
+QUIET = YES
+WARNINGS = YES
+DISABLE_INDEX = NO
+
+HAVE_DOT = YES
+INCLUDE_GRAPH = NO
+INCLUDED_BY_GRAPH = NO
+
+EXTRACT_ALL = NO
+EXTRACT_PRIVATE = NO
+HIDE_UNDOC_MEMBERS = YES
+HIDE_UNDOC_CLASSES = YES
+HIDE_SCOPE_NAMES = YES
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+JAVADOC_AUTOBRIEF = YES
+MAX_INITIALIZER_LINES = 0
+ENUM_VALUES_PER_LINE = 1
+
+ENABLE_PREPROCESSING = NO
+
+GENERATE_MAN = YES
+MAN_OUTPUT = .
+MAN_EXTENSION = .1
+MAN_LINKS = NO
+
+GENERATE_HTML = NO
+GENERATE_LATEX = NO
Added: freeswitch/trunk/libs/sofia-sip/utils/Doxyfile.build.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/utils/Doxyfile.build.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1,22 @@
+#
+# Template for Doxyfile.build
+#
+# Copyright (C) 2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+#
+
+PROJECT_NUMBER = @VERSION@
+
+INPUT = @srcdir@
+INPUT += @top_srcdir@/libsofia-sip-ua/su/localinfo.c
+INPUT += @top_srcdir@/libsofia-sip-ua/su/addrinfo.c
+INPUT += @top_srcdir@/libsofia-sip-ua/stun/stunc.c
+
+OUTPUT_DIRECTORY = ../man
+
+ at INCLUDE_PATH = . @srcdir@
+
+ at INCLUDE = ../libsofia-sip-ua/docs/Doxyfile.aliases
+ at INCLUDE = ../libsofia-sip-ua/docs/Doxyfile.rfc
+ at INCLUDE = Doxyfile
Added: freeswitch/trunk/libs/sofia-sip/utils/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/utils/Makefile.am Thu Dec 21 01:30:28 2006
@@ -0,0 +1,48 @@
+#
+# Makefile.am for sofia-sip/utils
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+#
+# ref: http://www.gnu.org/software/automake/manual/automake.html
+
+# ----------------------------------------------------------------------
+# Header paths
+
+sofiasrc=$(top_srcdir)/libsofia-sip-ua
+sofiabld=$(top_builddir)/libsofia-sip-ua
+
+INCLUDES = -I$(sofiasrc)/features -I$(sofiabld)/features \
+ -I$(sofiasrc)/ipt -I$(sofiabld)/ipt \
+ -I$(sofiasrc)/iptsec -I$(sofiabld)/iptsec \
+ -I$(sofiasrc)/bnf -I$(sofiabld)/bnf \
+ -I$(sofiasrc)/http -I$(sofiabld)/http \
+ -I$(sofiasrc)/msg -I$(sofiabld)/msg \
+ -I$(sofiasrc)/nth -I$(sofiabld)/nth \
+ -I$(sofiasrc)/nta -I$(sofiabld)/nta \
+ -I$(sofiasrc)/nea -I$(sofiabld)/nea \
+ -I$(sofiasrc)/nua -I$(sofiabld)/nua \
+ -I$(sofiasrc)/soa -I$(sofiabld)/soa \
+ -I$(sofiasrc)/sdp -I$(sofiabld)/sdp \
+ -I$(sofiasrc)/sip -I$(sofiabld)/sip \
+ -I$(sofiasrc)/soa -I$(sofiabld)/soa \
+ -I$(sofiasrc)/sresolv -I$(sofiabld)/sresolv \
+ -I$(sofiasrc)/tport -I$(sofiabld)/tport \
+ -I$(sofiasrc)/stun -I$(sofiabld)/stun \
+ -I$(sofiasrc)/url -I$(sofiabld)/url \
+ -I$(sofiasrc)/su -I$(sofiabld)/su
+
+
+AM_CFLAGS = $(SOFIA_CFLAGS)
+
+# ----------------------------------------------------------------------
+# Build targets
+
+noinst_HEADERS = apps_utils.h
+
+bin_PROGRAMS = sip-options sip-date sip-dig
+
+LDADD = ../libsofia-sip-ua/libsofia-sip-ua.la $(GLIB_LIBS)
+
+EXTRA_DIST = Doxyfile
Added: freeswitch/trunk/libs/sofia-sip/utils/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/utils/Makefile.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1,566 @@
+# 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.
+
+ at SET_MAKE@
+
+#
+# Makefile.am for sofia-sip/utils
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+#
+# ref: http://www.gnu.org/software/automake/manual/automake.html
+
+# ----------------------------------------------------------------------
+# Header paths
+
+
+SOURCES = sip-date.c sip-dig.c sip-options.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@
+bin_PROGRAMS = sip-options$(EXEEXT) sip-date$(EXEEXT) sip-dig$(EXEEXT)
+subdir = utils
+DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Doxyfile.build.in \
+ $(srcdir)/Makefile.am $(srcdir)/Makefile.in ChangeLog
+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 = Doxyfile.build
+am__installdirs = "$(DESTDIR)$(bindir)"
+binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+PROGRAMS = $(bin_PROGRAMS)
+sip_date_SOURCES = sip-date.c
+sip_date_OBJECTS = sip-date.$(OBJEXT)
+sip_date_LDADD = $(LDADD)
+am__DEPENDENCIES_1 =
+sip_date_DEPENDENCIES = ../libsofia-sip-ua/libsofia-sip-ua.la \
+ $(am__DEPENDENCIES_1)
+sip_dig_SOURCES = sip-dig.c
+sip_dig_OBJECTS = sip-dig.$(OBJEXT)
+sip_dig_LDADD = $(LDADD)
+sip_dig_DEPENDENCIES = ../libsofia-sip-ua/libsofia-sip-ua.la \
+ $(am__DEPENDENCIES_1)
+sip_options_SOURCES = sip-options.c
+sip_options_OBJECTS = sip-options.$(OBJEXT)
+sip_options_LDADD = $(LDADD)
+sip_options_DEPENDENCIES = ../libsofia-sip-ua/libsofia-sip-ua.la \
+ $(am__DEPENDENCIES_1)
+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 = sip-date.c sip-dig.c sip-options.c
+DIST_SOURCES = sip-date.c sip-dig.c sip-options.c
+HEADERS = $(noinst_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@
+sofiasrc = $(top_srcdir)/libsofia-sip-ua
+sofiabld = $(top_builddir)/libsofia-sip-ua
+INCLUDES = -I$(sofiasrc)/features -I$(sofiabld)/features \
+ -I$(sofiasrc)/ipt -I$(sofiabld)/ipt \
+ -I$(sofiasrc)/iptsec -I$(sofiabld)/iptsec \
+ -I$(sofiasrc)/bnf -I$(sofiabld)/bnf \
+ -I$(sofiasrc)/http -I$(sofiabld)/http \
+ -I$(sofiasrc)/msg -I$(sofiabld)/msg \
+ -I$(sofiasrc)/nth -I$(sofiabld)/nth \
+ -I$(sofiasrc)/nta -I$(sofiabld)/nta \
+ -I$(sofiasrc)/nea -I$(sofiabld)/nea \
+ -I$(sofiasrc)/nua -I$(sofiabld)/nua \
+ -I$(sofiasrc)/soa -I$(sofiabld)/soa \
+ -I$(sofiasrc)/sdp -I$(sofiabld)/sdp \
+ -I$(sofiasrc)/sip -I$(sofiabld)/sip \
+ -I$(sofiasrc)/soa -I$(sofiabld)/soa \
+ -I$(sofiasrc)/sresolv -I$(sofiabld)/sresolv \
+ -I$(sofiasrc)/tport -I$(sofiabld)/tport \
+ -I$(sofiasrc)/stun -I$(sofiabld)/stun \
+ -I$(sofiasrc)/url -I$(sofiabld)/url \
+ -I$(sofiasrc)/su -I$(sofiabld)/su
+
+AM_CFLAGS = $(SOFIA_CFLAGS)
+
+# ----------------------------------------------------------------------
+# Build targets
+noinst_HEADERS = apps_utils.h
+LDADD = ../libsofia-sip-ua/libsofia-sip-ua.la $(GLIB_LIBS)
+EXTRA_DIST = Doxyfile
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.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 utils/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu utils/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
+Doxyfile.build: $(top_builddir)/config.status $(srcdir)/Doxyfile.build.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)"
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ if test -f $$p \
+ || test -f $$p1 \
+ ; then \
+ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \
+ else :; fi; \
+ done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \
+ rm -f "$(DESTDIR)$(bindir)/$$f"; \
+ done
+
+clean-binPROGRAMS:
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f $$p $$f"; \
+ rm -f $$p $$f ; \
+ done
+sip-date$(EXEEXT): $(sip_date_OBJECTS) $(sip_date_DEPENDENCIES)
+ @rm -f sip-date$(EXEEXT)
+ $(LINK) $(sip_date_LDFLAGS) $(sip_date_OBJECTS) $(sip_date_LDADD) $(LIBS)
+sip-dig$(EXEEXT): $(sip_dig_OBJECTS) $(sip_dig_DEPENDENCIES)
+ @rm -f sip-dig$(EXEEXT)
+ $(LINK) $(sip_dig_LDFLAGS) $(sip_dig_OBJECTS) $(sip_dig_LDADD) $(LIBS)
+sip-options$(EXEEXT): $(sip_options_OBJECTS) $(sip_options_DEPENDENCIES)
+ @rm -f sip-options$(EXEEXT)
+ $(LINK) $(sip_options_LDFLAGS) $(sip_options_OBJECTS) $(sip_options_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip-date.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip-dig.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/sip-options.Po at am__quote@
+
+.c.o:
+ at am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+ at am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ at am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at 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:
+
+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
+
+distdir: $(DISTFILES)
+ @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
+check: check-am
+all-am: Makefile $(PROGRAMS) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(bindir)"; do \
+ test -z "$$dir" || $(mkdir_p) "$$dir"; \
+ done
+install: 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)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic clean-libtool 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-exec-am: install-binPROGRAMS
+
+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-binPROGRAMS uninstall-info-am
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \
+ clean-generic clean-libtool ctags distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-binPROGRAMS install-data install-data-am install-exec \
+ install-exec-am install-info install-info-am install-man \
+ 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-binPROGRAMS uninstall-info-am
+
+# 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:
Added: freeswitch/trunk/libs/sofia-sip/utils/apps_utils.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/utils/apps_utils.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,129 @@
+#ifndef APPS_UTILS_H /** Defined when apps_utils.h has been included. */
+#define APPS_UTILS_H
+
+/**
+ * @nofile apps_utils.h
+ * @brief
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Written by Pekka Pessi <pekka -dot pessi -at- nokia -dot- com>
+ *
+ * @STARTLGPL@
+ * 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
+ * @ENDLGPL@
+ *
+ * @date Created: Thu Apr 8 15:55:15 2004 ppessi
+ *
+ */
+
+SOFIA_BEGIN_DECLS
+
+static inline
+int proxy_authenticate(context_t *c,
+ nta_outgoing_t *oreq,
+ sip_t const *sip,
+ nta_response_f response_function)
+{
+ if (sip && sip->sip_status->st_status == 407 &&
+ sip->sip_proxy_authenticate &&
+ c->c_proxy_auth_retries++ < 3 &&
+ c->c_proxy && c->c_proxy->url_user && c->c_proxy->url_password) {
+ url_t *u = c->c_proxy;
+ msg_t *rmsg = nta_outgoing_getrequest(oreq);
+ sip_t *rsip = sip_object(rmsg);
+
+ if (auc_challenge(&c->c_proxy_auth, c->c_home, sip->sip_proxy_authenticate,
+ sip_proxy_authorization_class) >= 0
+ &&
+ auc_all_credentials(&c->c_proxy_auth, NULL, NULL,
+ u->url_user, u->url_password) > 0
+ &&
+ auc_authorization(&c->c_proxy_auth, rmsg, (msg_pub_t *)rsip,
+ rsip->sip_request->rq_method_name,
+ rsip->sip_request->rq_url,
+ rsip->sip_payload) > 0) {
+ nta_outgoing_destroy(c->c_orq);
+ sip_header_remove(rmsg, rsip, (sip_header_t *)rsip->sip_via);
+ nta_msg_request_complete(rmsg, c->c_leg, 0, NULL, NULL);
+ c->c_orq = nta_outgoing_tmcreate(c->c_agent, response_function, c, NULL,
+ rmsg, TAG_END());
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static inline
+int server_authenticate(context_t *c,
+ nta_outgoing_t *oreq,
+ sip_t const *sip,
+ nta_response_f response_function)
+{
+ if (sip && sip->sip_status->st_status == 401 &&
+ sip->sip_www_authenticate &&
+ c->c_auth_retries++ < 3 &&
+ c->c_password && c->c_username) {
+ msg_t *rmsg = nta_outgoing_getrequest(oreq);
+ sip_t *rsip = sip_object(rmsg);
+
+ if (auc_challenge(&c->c_auth, c->c_home, sip->sip_www_authenticate,
+ sip_authorization_class) >= 0
+ &&
+ auc_all_credentials(&c->c_auth, NULL, NULL, c->c_username, c->c_password) > 0
+ &&
+ auc_authorization(&c->c_auth, rmsg, (msg_pub_t *)rsip,
+ rsip->sip_request->rq_method_name,
+ rsip->sip_request->rq_url,
+ rsip->sip_payload) > 0) {
+ nta_outgoing_destroy(c->c_orq);
+ sip_header_remove(rmsg, rsip, (sip_header_t *)rsip->sip_via);
+ nta_msg_request_complete(rmsg, c->c_leg, 0, NULL, NULL);
+ c->c_orq = nta_outgoing_tmcreate(c->c_agent, response_function, c, NULL,
+ rmsg, TAG_END());
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static inline
+int tag_from_header(nta_agent_t *nta,
+ su_home_t *home,
+ sip_from_t *f)
+{
+ char *env = getenv("SIPTAG");
+ char *t = (void *)nta_agent_newtag(home, NULL, nta);
+ int retval;
+
+ if (env) {
+ char *t1 = su_sprintf(home, "tag=%s-%s", env, t);
+ su_free(home, t);
+ t = t1;
+ }
+
+ retval = sip_from_tag(home, f, t);
+
+ su_free(home, t);
+
+ return retval;
+}
+
+SOFIA_END_DECLS
+
+#endif /* !defined APPS_UTILS_H */
Added: freeswitch/trunk/libs/sofia-sip/utils/sip-date.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/utils/sip-date.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,172 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@page sip-date Print or parse SIP date
+ *
+ * @section synopsis Synopsis
+ *
+ * <tt>sip-date [-n] [SIP-date | [YYYYy] [DDd] [HHh] [MMm] [SS[s]]]</tt>
+ *
+ * @section description Description
+ *
+ * @em sip-date is an utility for printing a SIP date (in the format
+ * specified by RFC 1123, but the timezone must always be GMT) or parsing a
+ * given SIP date. The date can be given as a SIP date or by giving year,
+ * day, hour, minutes and seconds separately.
+ *
+ * @section options Options
+ *
+ * The @em sip-date utility takes options as follows:
+ * <dl>
+ * <dt>-n</dt>
+ * <dd>The @em sip-date utility prints the date as seconds elapsed since
+ * epoch (01 Jan 1900 00:00:00).
+ * </dd>
+ * </dl>
+ *
+ * @section examples Examples
+ *
+ * You want to convert current time to SIP date:
+ * @code
+ * $ sip-date
+ * @endcode
+ * You want to find out how many seconds there was in 1900's:
+ * @code
+ * $ siptime -n 2000y
+ * 3155673600
+ * @endcode
+ *
+ * @section bugs Reporting Bugs
+ * Report bugs to <sofia-sip-devel at lists.sourceforge.net>.
+ *
+ * @section author Author
+ * Pekka Pessi <Pekka -dot- Pessi -at- nokia -dot- com>
+ *
+ * @section copyright Copyright
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * This program is free software; see the source for copying conditions.
+ * There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#include <sofia-sip/sip.h>
+#include <sofia-sip/sip_header.h>
+#include <sofia-sip/msg_date.h>
+
+void usage(void)
+{
+ fprintf(stderr,
+ "usage: sip-date [-n] "
+ "[SIP-date | [YYYYy] [DDd] [HHh] [MMm] [SS[s]]]\n");
+ exit(1);
+}
+
+/* Epoch year. */
+#define EPOCH 1900
+/* Day number of New Year Day of given year */
+#define YEAR_DAYS(y) \
+ (((y)-1) * 365 + ((y)-1) / 4 - ((y)-1) / 100 + ((y)-1) / 400)
+
+int main(int ac, char *av[])
+{
+ int numeric = 0;
+ sip_time_t t, t2;
+ char const *s;
+ char buf[1024];
+
+ if (av[1] && strcmp(av[1], "-n") == 0)
+ av++, numeric = 1;
+
+ if (av[1] && (strcmp(av[1], "-?") == 0 || strcmp(av[1], "-h") == 0))
+ usage();
+
+ if ((s = av[1])) {
+ size_t n, m;
+ /* Concatenate all arguments with a space in between them */
+ for (n = 0; (s = av[1]); av++) {
+ m = strlen(s);
+ if (n + m + 2 > sizeof(buf))
+ exit(1);
+ memcpy(buf + n, s, m);
+ buf[n + m] = ' ';
+ n += m + 1;
+ }
+ buf[n] = '\0';
+
+ s = buf;
+
+ if (s[0] < '0' || s[0] > '9') {
+ if (msg_date_d(&s, &t) < 0) {
+ fprintf(stderr, "sip-date: %s is not valid time\n", s);
+ exit(1);
+ }
+ }
+ else {
+ for (; *s; ) {
+ t2 = 0;
+
+ if (msg_delta_d(&s, &t2) < 0)
+ usage();
+
+ switch (*s) {
+ case 'y': t2 = YEAR_DAYS(t2) - YEAR_DAYS(EPOCH);
+ /*FALLTHROUGH*/
+ case 'd': t += t2 * 24 * 60 * 60; s++; break;
+ case 'h': t += t2 * 60 * 60; s++; break;
+ case 'm': t += t2 * 60; s++; break;
+ case 's':
+ s++;
+ default:
+ t += t2;
+ break;
+ }
+
+ while (*s && *s == ' ')
+ s++;
+ }
+ }
+ }
+ else {
+ t = sip_now();
+ }
+
+ if (numeric) {
+ msg_delta_e(buf, sizeof(buf), t);
+ }
+ else {
+ msg_date_e(buf, sizeof(buf), t);
+ }
+
+ puts(buf);
+
+ return 0;
+}
Added: freeswitch/trunk/libs/sofia-sip/utils/sip-dig.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/utils/sip-dig.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,827 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**
+ * This is an example program for @b sresolv library in synchronous mode.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Original Created: Tue Jul 16 18:50:14 2002 ppessi
+ */
+
+/**@page sip-dig Resolve SIP URIs.
+ *
+ * @section sip_dig_synopsis Synopsis
+ * <tt>sip-dig [OPTIONS] uri...</tt>
+ *
+ * @section sip_dig_description Description
+ * The @em sip-dig utility resolves SIP URIs as described in @RFC3263. It
+ * queries NAPTR, SRV and A/AAAA records and prints out the resulting
+ * transport addresses.
+ *
+ * The default transports are: UDP, TCP, SCTP, TLS and TLS-SCTP. The SIPS
+ * URIs are resolved using only TLS transports, TLS and TLS-SCTP. If not
+ * otherwise indicated by NAPTR or SRV records, the sip-dig uses UDP and TCP
+ * as transports for SIP and TLS for SIPS URIs.
+ *
+ * The results are printed intended, with a preference followed by weight,
+ * then protocol name, port number and IP address in numeric format.
+ *
+ * @section sip_dig_options Command Line Options
+ * The @e sip-dig utility accepts following command line options:
+ * <dl>
+ * <dt>-p <em>protoname</em></dt>
+
+ * <dd>Use named transport protocol. The <em>protoname</em> can be either
+ * well-known, e.g., "udp", or it can specify NAPTR service and SRV
+ * identifier, e.g., "tls-udp/SIPS+D2U/_sips._udp.".
+ * </dd>
+ * <dt>--udp</dt>
+ * <dd>Use UDP transport protocol.
+ * </dd>
+ * <dt>--tcp</dt>
+ * <dd>Use TCP transport protocol.
+ * </dd>
+ * <dt>--tls</dt>
+ * <dd>Use TLS over TCP transport protocol.
+ * </dd>
+ * <dt>--sctp</dt>
+ * <dd>Use SCTP transport protocol.
+ * </dd>
+ * <dt>--tls-sctp</dt>
+ * <dd>Use TLS over SCTP transport protocol.
+ * </dd>
+ * <dt>--no-sctp</dt>
+ * <dd>Ignore SCTP or TLS-SCTP records in the list of default transports.
+ * This option has no effect if transport protocols has been explicitly
+ * listed.
+ * </dd>
+ * <dt>-4</dt>
+ * <dd>Query IP4 addresses (A records)
+ * </dd>
+ * <dt>-6</dt>
+ * <dd>Query IP6 addresses (AAAA records).
+ * </dd>
+ * <dt>-v</dt>
+ * <dd>Be verbatim.
+ * </dd>
+ * <dt></dt>
+ * <dd>
+ * </dd>
+ * </dl>
+ *
+ * @section sip_dig_return Return Codes
+ * <table>
+ * <tr><td>0<td>when successful (a 2XX-series response is received)
+ * <tr><td>1<td>when unsuccessful (a 3XX..6XX-series response is received)
+ * <tr><td>2<td>initialization failure
+ * </table>
+ *
+ * @section sip_dig_examples Examples
+ *
+ * Resolve sip:openlaboratory.net, prefer TLS over TCP, TCP over UDP:
+ * @code
+ * $ sip-dig --tls --tcp --udp sip:openlaboratory.net
+ * 1 0.333 tls 5061 212.213.221.127
+ * 2 0.333 tcp 5060 212.213.221.127
+ * 3 0.333 udp 5060 212.213.221.127
+ * @endcode
+ *
+ * Resolve sips:example.net with TLS over SCTP (TLS-SCTP) and TLS:
+ * @code
+ * $ sip-dig -p tls-sctp --tls sips:example.net
+ * 1 0.500 tls-udp 5061 172.21.55.26
+ * 2 0.500 tls 5061 172.21.55.26
+ * @endcode
+ *
+ * @section sip_dig_environment Environment
+ * #SRESOLV_DEBUG, SRESOLV_CONF
+ *
+ * @section sip_dig_bugs Reporting Bugs
+ * Report bugs to <sofia-sip-devel at lists.sourceforge.net>.
+ *
+ * @section sip_dig_author Author
+ * Written by Pekka Pessi <pekka -dot pessi -at- nokia -dot- com>
+ *
+ * @section sip_dig_copyright Copyright
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * This program is free software; see the source for copying conditions.
+ * There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.
+ */
+
+#include "config.h"
+
+#if !defined(HAVE_WIN32)
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+
+#include "sofia-sip/su.h"
+
+#include "sofia-resolv/sres.h"
+#include "sofia-resolv/sres_record.h"
+
+#include "sofia-sip/url.h"
+#include "sofia-sip/su_alloc.h"
+#include "sofia-sip/hostdomain.h"
+
+char const name[] = "sip-dig";
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+enum { N_TPORT = 16 };
+
+struct transport { char const *name, *service, *srv; };
+
+struct dig {
+ sres_resolver_t *sres;
+
+ unsigned preference, ip4, ip6, sips, print;
+
+ struct transport tports[N_TPORT];
+};
+
+int dig_naptr(struct dig *dig, char const *host, double weight);
+
+int dig_all_srvs(struct dig *dig, char const *tport, char const *host,
+ double weight);
+
+int dig_srv(struct dig *dig, char const *tport, char const *host,
+ double weight);
+
+int dig_srv_at(struct dig *dig,
+ char const *tport, sres_record_t **answers,
+ double weight, int pweight,
+ int priority);
+
+int dig_addr(struct dig *dig,
+ char const *tport, char const *host, char const *port,
+ double weight);
+
+void print_addr_results(struct transport const *tports,
+ char const *tport, char const *tport2,
+ sres_record_t **answers, int type, int af,
+ char const *port,
+ double weight, int preference);
+
+void print_result(char const *addr, char const *port, char const *tport,
+ double weight,
+ unsigned preference);
+
+int prepare_transport(struct dig *dig, char const *tport);
+
+int count_transports(struct dig *dig,
+ char const *tp1,
+ char const *tp2);
+
+void usage(int exitcode)
+{
+ fprintf(stderr, "usage: %s [OPTIONS] [@dnsserver] uri\n", name);
+ exit(exitcode);
+}
+
+int main(int argc, char *argv[])
+{
+ int exitcode = 0;
+ int o_sctp = 1, o_tls_sctp = 1, o_verbatim = 1;
+ int family = 0, multiple = 0;
+ char const *dnsserver = NULL;
+ char const *string;
+ url_t *uri = NULL;
+
+ char const *host;
+ char const *port;
+ char *transport = NULL, tport[32];
+
+ struct dig dig[1] = {{ NULL }};
+
+ if (su_init() != 0)
+ return -1;
+
+ while (argv[1] && argv[1][0] == '-') {
+ if (strcmp(argv[1], "-v") == 0)
+ o_verbatim++;
+ else if (strcmp(argv[1], "-6") == 0)
+ dig->ip6 = ++family;
+ else if (strcmp(argv[1], "-4") == 0)
+ dig->ip4 = ++family;
+ else if (strncmp(argv[1], "-p", 2) == 0) {
+ char const *proto;
+
+ if (argv[1][2] == '=')
+ proto = argv[1] + 3;
+ else if (argv[1][2])
+ proto = argv[1] + 2;
+ else
+ proto = argv++[2];
+
+ if (proto == NULL)
+ usage(2);
+
+ if (prepare_transport(dig, proto) < 0)
+ exit(2);
+ }
+ else if (strcmp(argv[1], "--udp") == 0)
+ prepare_transport(dig, "udp");
+ else if (strcmp(argv[1], "--tcp") == 0)
+ prepare_transport(dig, "tcp");
+ else if (strcmp(argv[1], "--tls") == 0)
+ prepare_transport(dig, "tls");
+ else if (strcmp(argv[1], "--sctp") == 0)
+ prepare_transport(dig, "sctp");
+ else if (strcmp(argv[1], "--tls-sctp") == 0)
+ prepare_transport(dig, "tls-sctp");
+ else if (strcmp(argv[1], "--tls-udp") == 0)
+ prepare_transport(dig, "tls-udp");
+ else if (strcmp(argv[1], "--no-sctp") == 0)
+ o_sctp = 0, o_tls_sctp = 0;
+ else if (strcmp(argv[1], "--help") == 0)
+ usage(0);
+ else if (strcmp(argv[1], "-h") == 0)
+ usage(0);
+ else if (strcmp(argv[1], "-?") == 0)
+ usage(0);
+ else if (strcmp(argv++[1], "-") == 0)
+ break;
+ else
+ usage(2);
+ argv++;
+ }
+
+ if (!family)
+ dig->ip4 = 1, dig->ip6 = 2;
+
+ if (argv[1] && argv[1][0] == '@')
+ dnsserver = argv++[1] + 1;
+
+ if (!argv[1])
+ usage(2);
+
+ multiple = argv[1] && argv[2];
+
+ if (!count_transports(dig, NULL, NULL)) {
+ prepare_transport(dig, "udp");
+ prepare_transport(dig, "tcp");
+ if (o_sctp)
+ prepare_transport(dig, "sctp");
+ prepare_transport(dig, "tls");
+ if (o_tls_sctp)
+ prepare_transport(dig, "tls-sctp");
+ }
+
+ dig->sres = sres_resolver_new(getenv("SRESOLV_CONF"));
+ if (!dig->sres)
+ perror("sres_resolver_new"), exit(1);
+
+ for (; (string = argv[1]); argv++) {
+ if (multiple)
+ puts(string);
+
+ uri = url_hdup(NULL, (void *)string);
+
+ if (uri && uri->url_type == url_unknown)
+ url_sanitize(uri);
+
+ if (uri->url_type == url_any)
+ continue;
+
+ if (!uri || (uri->url_type != url_sip && uri->url_type != url_sips)) {
+ fprintf(stderr, "%s: invalid uri\n", string);
+ exitcode = 1;
+ continue;
+ }
+
+ port = url_port(uri);
+ if (port && !port[0]) port = NULL;
+ if (url_param(uri->url_params, "transport=", tport, sizeof tport) > 0)
+ transport = tport;
+
+ host = uri->url_host;
+
+ if (host_is_ip_address(host)) {
+ if (transport) {
+ print_result(host, port, transport, 1.0, 1);
+ }
+ else if (uri->url_type == url_sips) {
+ print_result(host, port, "tls", 1.0, 1);
+ }
+ else {
+ print_result(host, port, "udp", 1.0, 1);
+ print_result(host, port, "tcp", 1.0, 2);
+ }
+ continue;
+ }
+
+ if (!host_is_domain(host)) {
+ fprintf(stderr, "%s: invalid host\n", string);
+ exitcode = 1;
+ continue;
+ }
+
+ dig->sips = uri->url_type == url_sips;
+ dig->preference = 1;
+
+ if (!port && !transport && dig_naptr(dig, host, 1.0))
+ continue /* resolved naptr */;
+ else if (!port && dig_all_srvs(dig, transport, host, 1.0))
+ continue /* resolved srv */;
+ else if (dig_addr(dig, transport, host, port, 1.0))
+ continue /* resolved a/aaaa */;
+
+ fprintf(stderr, "%s: not found\n", string);
+ exitcode = 1;
+ }
+
+ sres_resolver_unref(dig->sres);
+
+ return exitcode;
+}
+
+
+int transport_is_secure(char const *tportname)
+{
+ return tportname && strncasecmp(tportname, "tls", 3) == 0;
+}
+
+int prepare_transport(struct dig *dig, char const *tport)
+{
+ struct transport *tports = dig->tports;
+ int j;
+
+ for (j = 0; j < N_TPORT - 1; j++) {
+ if (!tports[j].name)
+ break;
+ if (strcasecmp(tports[j].name, tport) == 0)
+ return 1;
+ }
+
+ if (j == N_TPORT)
+ return 0;
+
+ if (strchr(tport, '/')) {
+ char *service = strchr(tport, '/');
+ char *srv = strchr(service + 1, '/');
+
+ if (!srv || srv[strlen(srv) - 1] != '.') {
+ fprintf(stderr, "%s: invalid transport specifier \"%s\"\n", name, tport);
+ fputs(
+"\tspecifier should have name/service/srv-id\n"
+"\twhere name is protocol name (e.g, \"tls-udp\")\n"
+"\t service specifies service as per RFC 2915 (e.g., \"SIPS+D2U\")\n"
+"\t srv-id is prefix for SRV lookup (e.g., \"_sips._udp.\")\n",
+ stderr);
+ if (srv)
+ fputs("\t and it should end with a dot \".\"\n", stderr);
+ return -1;
+ }
+
+ *service++ = '\0', *srv++ = '\0';
+
+ tports[j].name = tport,
+ tports[j].service = service;
+ tports[j].srv = srv;
+ }
+ else if (strcasecmp(tport, "udp") == 0) {
+ tports[j].name = "udp";
+ tports[j].service = "SIP+D2U";
+ tports[j].srv = "_sip._udp.";
+ }
+ else if (strcasecmp(tport, "tcp") == 0) {
+ tports[j].name = "tcp";
+ tports[j].service = "SIP+D2T";
+ tports[j].srv = "_sip._tcp.";
+ }
+ else if (strcasecmp(tport, "tls") == 0) {
+ tports[j].name = "tls";
+ tports[j].service = "SIPS+D2T";
+ tports[j].srv = "_sips._tcp.";
+ }
+ else if (strcasecmp(tport, "sctp") == 0) {
+ tports[j].name = "sctp";
+ tports[j].service = "SIP+D2S";
+ tports[j].srv = "_sip._sctp.";
+ }
+ else if (strcasecmp(tport, "tls-sctp") == 0) {
+ tports[j].name = "tls-sctp";
+ tports[j].service = "SIPS+D2S";
+ tports[j].srv = "_sips._sctp.";
+ }
+ else {
+ fprintf(stderr, "%s: unknown transport \"%s\"\n", name, tport);
+ return -1;
+ }
+
+ j++;
+
+ tports[j].service = tports[j].srv = tports[j].name = NULL;
+
+ return 1;
+}
+
+int
+count_transports(struct dig *dig,
+ char const *tport,
+ char const *tport2)
+{
+
+ int i, tcount = 0;
+ struct transport const *tports = dig->tports;
+
+ for (i = 0; tports[i].name; i++) {
+ if (dig->sips && !transport_is_secure(tports[i].name))
+ continue;
+ if (!tport || strcasecmp(tport, tports[i].name) == 0)
+ tcount++;
+ if (tport2 && strcasecmp(tport2, tports[i].name) == 0)
+ tcount++;
+ }
+
+ return tcount;
+}
+
+struct transport const *
+transport_by_service(struct transport const *tports, char const *s)
+{
+ int i;
+
+ for (i = 0; tports[i].name; i++) {
+ if (strcasecmp(tports[i].service, s) == 0)
+ return tports + i;
+ }
+
+ return NULL;
+}
+
+int dig_naptr(struct dig *dig,
+ char const *host,
+ double weight)
+{
+ sres_record_t **answers = NULL;
+ struct transport const *tp;
+ int i, error;
+ int order = 0, count = 0, nacount = 0, scount = 0;
+
+ error = sres_blocking_query(dig->sres, sres_type_naptr, host, 0, &answers);
+ if (error < 0)
+ return 0;
+
+ /* Sort by priority */
+ sres_sort_answers(dig->sres, answers);
+
+ /* Count number of matching naptrs */
+ for (i = 0; answers[i]; i++) {
+ sres_naptr_record_t const *na = answers[i]->sr_naptr;
+
+ if (na->na_record->r_type != sres_type_naptr || na->na_record->r_status)
+ continue;
+
+ if (dig->print)
+ printf("%s\n\t%d IN NAPTR %u %u \"%s\" \"%s\" \"%s\" %s\n",
+ na->na_record->r_name, na->na_record->r_ttl,
+ na->na_order, na->na_prefer,
+ na->na_flags, na->na_services,
+ na->na_regexp, na->na_replace);
+
+ if (strcasecmp(na->na_flags, "s") && strcasecmp(na->na_flags, "a"))
+ continue;
+
+ if (nacount && order != na->na_order)
+ continue;
+
+ if (dig->sips && strncasecmp(na->na_services, "SIPS+", 5))
+ continue;
+
+ if (!transport_by_service(dig->tports, na->na_services))
+ continue;
+
+ order = na->na_order, nacount++;
+ }
+
+ if (nacount == 0) {
+ sres_free_answers(dig->sres, answers);
+ return 0;
+ }
+
+ for (i = 0; answers[i]; i++) {
+ sres_naptr_record_t const *na = answers[i]->sr_naptr;
+
+ if (na->na_record->r_type != sres_type_naptr || na->na_record->r_status)
+ continue;
+ if (order != na->na_order)
+ continue;
+ if (strcasecmp(na->na_flags, "s") && strcasecmp(na->na_flags, "a"))
+ continue;
+ if (dig->sips && strncasecmp(na->na_services, "SIPS+", 5))
+ continue;
+
+ tp = transport_by_service(dig->tports, na->na_services);
+ if (!tp)
+ continue;
+
+ if (strcasecmp(na->na_flags, "s") == 0) {
+ scount = dig_srv(dig, tp->name, na->na_replace, weight / nacount);
+ }
+ else if (strcasecmp(na->na_flags, "a") == 0) {
+ scount = dig_addr(dig, tp->name, na->na_replace, NULL, weight / nacount);
+ }
+ else
+ scount = 0;
+
+ count += scount;
+ }
+
+ return count;
+}
+
+int dig_all_srvs(struct dig *dig,
+ char const *tport,
+ char const *host,
+ double weight)
+{
+ int i, j, n;
+ int tcount, count = 0, scount;
+ char *domain;
+
+ struct {
+ char const *proto; sres_record_t **answers;
+ } srvs[N_TPORT + 1] = {{ NULL }};
+
+ tcount = count_transports(dig, tport, NULL);
+ if (!tcount)
+ return 0;
+
+ for (i = 0, n = 0; dig->tports[i].name; i++) {
+ if (tport && strcasecmp(dig->tports[i].name, tport))
+ continue;
+
+ if (dig->sips && !transport_is_secure(dig->tports[i].name))
+ continue;
+
+ domain = su_strcat(NULL, dig->tports[i].srv, host);
+
+ if (domain) {
+ if (sres_blocking_query(dig->sres, sres_type_srv, domain, 0,
+ &srvs[n].answers) >= 0) {
+ srvs[n++].proto = dig->tports[i].name;
+ }
+ free(domain);
+ }
+ }
+
+ if (n == 0)
+ return 0;
+
+ for (i = 0; i < n; i++) {
+ unsigned priority = 0, pweight = 0, m = 0;
+ sres_record_t **answers = srvs[i].answers;
+ char const *tport = srvs[i].proto;
+
+ for (j = 0; answers[j]; j++) {
+ sres_srv_record_t const *srv = answers[j]->sr_srv;
+
+ if (srv->srv_record->r_type != sres_type_srv)
+ continue;
+ if (srv->srv_record->r_status != 0)
+ continue;
+
+ if (srv->srv_priority != priority && pweight != 0) {
+ scount = dig_srv_at(dig, tport, answers, weight / n, pweight,
+ priority);
+ if (scount) dig->preference++;
+ count += scount;
+ pweight = 0, m = 0;
+ }
+
+ priority = srv->srv_priority, pweight += srv->srv_weight, m++;
+ }
+
+ if (m) {
+ scount = dig_srv_at(dig, tport, answers, weight / n, pweight, priority);
+ if (scount)
+ dig->preference++;
+ count += scount;
+ }
+ }
+
+ return count;
+}
+
+int dig_srv(struct dig *dig,
+ char const *tport,
+ char const *domain,
+ double weight)
+{
+ sres_record_t **answers = NULL;
+ int j, n, error;
+ int count = 0, scount = 0;
+
+ uint32_t priority, pweight;
+
+ assert(tport && domain);
+
+ error = sres_blocking_query(dig->sres, sres_type_srv, domain, 0, &answers);
+ if (error < 0)
+ return 0;
+
+ /* Sort by priority */
+ sres_sort_answers(dig->sres, answers);
+
+ priority = 0; pweight = 0; n = 0;
+
+ for (j = 0; answers[j]; j++) {
+ sres_srv_record_t const *srv = answers[j]->sr_srv;
+
+ if (srv->srv_record->r_type != sres_type_srv)
+ continue;
+ if (srv->srv_record->r_status != 0)
+ continue;
+
+ if (srv->srv_priority != priority && pweight != 0) {
+ scount = dig_srv_at(dig, tport, answers, weight, pweight,
+ priority);
+ if (scount) dig->preference++;
+ count += scount;
+ pweight = 0, n = 0;
+ }
+
+ priority = srv->srv_priority, pweight += srv->srv_weight, n++;
+ }
+
+ if (n) {
+ scount = dig_srv_at(dig, tport, answers, weight, pweight, priority);
+ if (scount) dig->preference++;
+ count += scount;
+ }
+
+ sres_free_answers(dig->sres, answers);
+
+ return count;
+}
+
+int dig_srv_at(struct dig *dig,
+ char const *tport,
+ sres_record_t **answers,
+ double weight, int pweight,
+ int priority)
+{
+ int count = 0;
+ int i;
+ char port[8];
+
+ if (pweight == 0)
+ pweight = 1;
+
+ for (i = 0; answers[i]; i++) {
+ sres_srv_record_t const *srv = answers[i]->sr_srv;
+ if (srv->srv_record->r_type != sres_type_srv)
+ continue;
+ if (srv->srv_record->r_status != 0)
+ continue;
+ if (srv->srv_priority != priority)
+ continue;
+ snprintf(port, sizeof port, "%u", srv->srv_port);
+
+ count += dig_addr(dig, tport, srv->srv_target, port,
+ weight * srv->srv_weight / pweight);
+ }
+
+ return count;
+}
+
+int dig_addr(struct dig *dig,
+ char const *tport,
+ char const *host,
+ char const *port,
+ double weight)
+{
+ int error, i;
+ char const *tport2 = NULL;
+ sres_record_t **answers1 = NULL, **answers2 = NULL;
+ unsigned count1 = 0, count2 = 0, tcount = 0;
+ int type1 = 0, type2 = 0, family1 = 0, family2 = 0;
+
+ if (dig->ip6 > dig->ip4) {
+ type1 = sres_type_aaaa, family1 = AF_INET6;
+ if (dig->ip4)
+ type2 = sres_type_a, family2 = AF_INET;
+ }
+ else {
+ type1 = sres_type_a, family1 = AF_INET;
+ if (dig->ip6)
+ type2 = sres_type_aaaa, family2 = AF_INET6;
+ }
+
+ if (tport == NULL) {
+ if (dig->sips)
+ tport = "tls";
+ else
+ tport = "udp", tport2 = "tcp";
+ }
+
+ tcount = count_transports(dig, tport, tport2);
+ if (!tcount)
+ return 0;
+
+ if (type1) {
+ error = sres_blocking_query(dig->sres, type1, host, 0, &answers1);
+ if (error >= 0)
+ for (i = 0; answers1[i]; i++) {
+ sres_common_t *r = answers1[i]->sr_record;
+ count1 += r->r_type == type1 && r->r_status == 0;
+ }
+ }
+
+ if (type2) {
+ error = sres_blocking_query(dig->sres, type2, host, 0, &answers2);
+ if (error >= 0)
+ for (i = 0; answers2[i]; i++) {
+ sres_common_t *r = answers2[i]->sr_record;
+ count2 += r->r_type == type2 && r->r_status == 0;
+ }
+ }
+
+ if (count1 + count2) {
+ double w = weight / (count1 + count2) / tcount;
+
+ if (count1)
+ print_addr_results(dig->tports, tport, tport2,
+ answers1, type1, family1, port,
+ w, dig->preference);
+ if (count2)
+ print_addr_results(dig->tports, tport, tport2,
+ answers2, type2, family2, port,
+ w, dig->preference);
+ }
+
+ sres_free_answers(dig->sres, answers1);
+ sres_free_answers(dig->sres, answers2);
+
+ return count1 + count2;
+}
+
+void
+print_addr_results(struct transport const *tports,
+ char const *tport, char const *tport2,
+ sres_record_t **answers, int type, int af,
+ char const *port,
+ double weight, int preference)
+{
+ int i, j;
+ char addr[64];
+
+ for (i = 0; answers[i]; i++) {
+ if (answers[i]->sr_record->r_type != type)
+ continue;
+ if (answers[i]->sr_record->r_status != 0)
+ continue;
+
+ inet_ntop(af, &answers[i]->sr_a->a_addr, addr, sizeof addr);
+
+ for (j = 0; tports[j].name; j++) {
+ if (strcasecmp(tport, tports[j].name) == 0)
+ print_result(addr, port, tport, weight, preference);
+ if (tport2 && strcasecmp(tport2, tports[j].name) == 0)
+ print_result(addr, port, tport2, weight, preference);
+ }
+ }
+}
+
+void print_result(char const *addr,
+ char const *port,
+ char const *tport,
+ double weight,
+ unsigned preference)
+{
+ if (!port || !port[0])
+ port = transport_is_secure(tport) ? "5061" : "5060";
+
+ printf("\t%u %.3f %s %s %s\n", preference, weight, tport, port, addr);
+}
Added: freeswitch/trunk/libs/sofia-sip/utils/sip-options.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/utils/sip-options.c Thu Dec 21 01:30:28 2006
@@ -0,0 +1,396 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@page sip-options Query SIP OPTIONS
+ *
+ * @section synopsis Synopsis
+ * <tt>sip-options [--bind=url] [--from=url] [-a|--all] to </tt>
+ *
+ * @section description Description
+ * The @em sip-options utility sends a SIP OPTIONS request (or any other SIP
+ * request) to a SIP server.
+ *
+ * The @em sip-options tool will print out status line and interesting headers
+ * from the response, excluding From, Via, Call-ID, and CSeq. The message
+ * body is also printed.
+ *
+ * @section options Command Line Options
+ * The @e options utility accepts following command line options:
+ * <dl>
+ * <dt>-m url | --contact=url | --bind=url</dt>
+ * <dd>Specifies the SIP URL to which the @em options utility binds.
+ * </dd>
+ * <dt>--1XX | -1</dt>
+ * <dd>Print also preliminary responses. If this option is not present,
+ * preliminary responses are silently discarded.
+ * </dd>
+ * <dt>--all | -a</dt>
+ * <dd>All SIP headers will be printed. If the --all option is given,
+ * the @em options utility also prints @b From, @b Via, @b Call-ID or
+ * @b CSeq headers.
+ * </dd>
+ * <dt>--from=url</dt>
+ * <dd>Specifies the @b From header. Unless this option is used or the
+ * environment variable @c SIPADDRESS is set, local Contact URL is used
+ * as @b From header as well.
+ * </dd>
+ * <dt>--mf=n</dt>
+ * <dd>Specify the initial Max-Forwards count (defaults to 70, stack default).
+ * </dd>
+ * <dt>--method=s</dt>
+ * <dd>Specify the request method (defaults to OPTIONS).
+ * </dd>
+ * </dl>
+ *
+ * @section return Return Codes
+ * <table>
+ * <tr><td>0<td>when successful (a 2XX-series response is received)
+ * <tr><td>1<td>when unsuccessful (a 3XX..6XX-series response is received)
+ * <tr><td>2<td>initialization failure
+ * </table>
+ *
+ * @section examples Examples
+ * You want to query supported features of sip:essip00net.nokia.com:
+ * @code
+ * $ options sip:essip00net.nokia.com
+ * @endcode
+ *
+ * @section environment Environment
+ * #SIPADDRESS, #sip_proxy, #NTA_DEBUG, #TPORT_DEBUG, #TPORT_LOG.
+ *
+ * @section bugs Reporting Bugs
+ * Report bugs to <sofia-sip-devel at lists.sourceforge.net>.
+ *
+ * @section author Author
+ * Written by Pekka Pessi <pekka -dot pessi -at- nokia -dot- com>
+ *
+ * @section copyright Copyright
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * This program is free software; see the source for copying conditions.
+ * There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+
+typedef struct context_s context_t;
+#define NTA_OUTGOING_MAGIC_T context_t
+
+#include <sofia-sip/nta.h>
+#include <sofia-sip/sip_header.h>
+#include <sofia-sip/sip_tag.h>
+#include <sofia-sip/sl_utils.h>
+#include <sofia-sip/sip_util.h>
+#include <sofia-sip/auth_client.h>
+#include <sofia-sip/tport_tag.h>
+
+struct context_s {
+ su_home_t c_home[1];
+ su_root_t *c_root;
+ nta_agent_t *c_agent;
+ url_t *c_proxy;
+ char const *c_username;
+ char const *c_password;
+ nta_leg_t *c_leg;
+ nta_outgoing_t *c_orq;
+ auth_client_t *c_proxy_auth;
+ auth_client_t *c_auth;
+ unsigned c_proxy_auth_retries;
+ unsigned c_auth_retries;
+ int c_all;
+ int c_pre;
+ int c_retval;
+};
+
+char const name[] = "sip-options";
+
+static
+void usage(int rc)
+{
+ fprintf(rc ? stderr : stdout,
+ "usage: %s OPTIONS url [extra-file]\n"
+ "where OPTIONS are\n"
+ " --mf=count | --max-forwards=count\n"
+ " --contact=url | --bind=url | -m=url\n"
+ " --from=url\n"
+ " --ua=user-agent\n"
+ " --all | -a\n"
+ " --1XX | -1\n"
+ " --x | --extra \n",
+ name);
+ exit(rc);
+}
+
+#include "apps_utils.h"
+
+static int response_to_options(context_t *context,
+ nta_outgoing_t *oreq,
+ sip_t const *sip);
+static char *readfile(FILE *f);
+
+int main(int argc, char *argv[])
+{
+ su_home_t *home;
+ context_t context[1] = {{{SU_HOME_INIT(context)}}};
+ char
+ *extra = NULL,
+ *o_bind = "sip:*:*",
+ *o_from = getenv("SIPADDRESS"),
+ *o_http_proxy = NULL,
+ *o_max_forwards = NULL,
+ *o_method = NULL,
+ *o_to = NULL;
+
+ char *s, *v;
+
+ sip_method_t method = sip_method_options;
+
+#define MATCH(s, o) \
+ ((strncmp(s, o, strlen(o)) == 0))
+#define MATCH1(s, o) \
+ ((strncmp(s, o, strlen(o)) == 0) && \
+ (v = (s[strlen(o)] ? s + strlen(o) : argv++[1])))
+#define MATCH2(s, o) \
+ ((strncmp(s, o, strlen(o)) == 0) && \
+ (s[strlen(o)] == '=' || s[strlen(o)] == '\0') && \
+ (v = s[strlen(o)] ? s + strlen(o) + 1 : argv++[1]))
+
+ while ((s = argv++[1])) {
+ if (!MATCH(s, "-")) { o_to = s; break; }
+ else if (strcmp(s, "") == 0) { o_to = argv++[1]; break; }
+ else if (MATCH(s, "-a") || MATCH(s, "--all"))
+ { context->c_all = 1; }
+ else if (MATCH(s, "-x") || MATCH(s, "--extra"))
+ { extra = "-"; }
+ else if (MATCH(s, "-1") || MATCH(s, "--1XX"))
+ { context->c_pre = 1; }
+ else if (MATCH2(s, "--mf")) { o_max_forwards = v; }
+ else if (MATCH2(s, "--http-proxy")) { o_http_proxy = v; }
+ else if (MATCH2(s, "--max-forwards")) { o_max_forwards = v; }
+ else if (MATCH2(s, "--bind")) { o_bind = v; }
+ else if (MATCH1(s, "-m")) { o_bind = v; }
+ else if (MATCH2(s, "--contact")){ o_bind = v; }
+ else if (MATCH2(s, "--from")) { o_from = v; }
+ else if (MATCH2(s, "--method")) { o_method = v; }
+ else if (MATCH(s, "--help")) { usage(0); }
+ else
+ usage(2);
+ }
+
+ if (!o_to)
+ usage(2);
+
+ if (argv[1])
+ extra = argv++[1];
+
+ su_init();
+
+ su_home_init(home = context->c_home);
+
+ context->c_root = su_root_create(context);
+ context->c_retval = 2;
+
+ if (context->c_root) {
+ url_string_t *r_uri;
+
+ context->c_agent =
+ nta_agent_create(context->c_root,
+ URL_STRING_MAKE(o_bind),
+ NULL, NULL, /* Ignore incoming messages */
+ TPTAG_HTTP_CONNECT(o_http_proxy),
+ TAG_END());
+
+ if (context->c_agent) {
+ sip_addr_t *from, *to;
+ sip_contact_t const *m = nta_agent_contact(context->c_agent);
+
+ to = sip_to_create(home, (url_string_t *)o_to);
+
+ if (o_from)
+ from = sip_from_make(home, o_from);
+ else
+ from = sip_from_create(home, (url_string_t const *)m->m_url);
+
+ if (!from) {
+ fprintf(stderr, "%s: no valid From address\n", name);
+ exit(2);
+ }
+
+ tag_from_header(context->c_agent, context->c_home, from);
+
+ if (o_method) {
+ method = sip_method_code(o_method);
+ } else {
+ isize_t len;
+ char const *params = to->a_url->url_params;
+
+ len = url_param(params, "method", NULL, 0);
+
+ if (len > 0) {
+ o_method = su_alloc(home, len + 1);
+ if (o_method == 0 ||
+ url_param(params, "method", o_method, len + 1) != len) {
+ fprintf(stderr, "%s: %s\n", name,
+ o_method ? "internal error" : strerror(errno));
+ exit(2);
+ }
+ method = sip_method_code(o_method);
+ }
+ }
+
+ r_uri = (url_string_t *)url_hdup(home, to->a_url);
+
+ sip_aor_strip(to->a_url);
+ sip_aor_strip(from->a_url);
+
+ context->c_username = from->a_url->url_user;
+ context->c_password = from->a_url->url_password;
+ from->a_url->url_password = NULL;
+
+ if (extra) {
+ FILE *hf;
+
+ if (strcmp(extra, "-"))
+ hf = fopen(extra, "rb");
+ else
+ hf = stdin;
+
+ extra = readfile(hf);
+ }
+
+ context->c_proxy = url_hdup(context->c_home,
+ (url_t *)getenv("sip_proxy"));
+
+ nta_agent_set_params(context->c_agent,
+ NTATAG_SIPFLAGS(MSG_FLG_EXTRACT_COPY),
+ NTATAG_DEFAULT_PROXY(context->c_proxy),
+ TAG_END());
+
+ context->c_leg =
+ nta_leg_tcreate(context->c_agent,
+ NULL, NULL, /* ignore incoming requests */
+ SIPTAG_FROM(from), /* who is sending OPTIONS? */
+ SIPTAG_TO(to), /* whom we are sending OPTIONS? */
+ TAG_END());
+
+ if (context->c_leg) {
+ context->c_orq =
+ nta_outgoing_tcreate(context->c_leg,
+ response_to_options, context,
+ NULL,
+ method, o_method, r_uri,
+ SIPTAG_USER_AGENT_STR("options"),
+ SIPTAG_MAX_FORWARDS_STR(o_max_forwards),
+ SIPTAG_HEADER_STR(extra),
+ TAG_END());
+
+ if (context->c_orq) {
+ su_root_run(context->c_root);
+ nta_outgoing_destroy(context->c_orq), context->c_orq = NULL;
+ }
+
+ nta_leg_destroy(context->c_leg), context->c_leg = NULL;
+ }
+
+ nta_agent_destroy(context->c_agent), context->c_agent = NULL;
+ }
+
+ su_root_destroy(context->c_root);
+ }
+
+ su_deinit();
+
+ return context->c_retval;
+}
+
+/** Handle responses to registration request */
+static
+int response_to_options(context_t *context,
+ nta_outgoing_t *oreq,
+ sip_t const *sip)
+{
+ if (proxy_authenticate(context, oreq, sip, response_to_options))
+ return 0;
+ if (server_authenticate(context, oreq, sip, response_to_options))
+ return 0;
+
+ if (sip->sip_status->st_status >= 200 || context->c_pre) {
+ sip_header_t *h = (sip_header_t *)sip->sip_status;
+ char hname[64];
+
+ for (; h; h = (sip_header_t *)h->sh_succ) {
+ if (!context->c_all) {
+ if (sip_is_from(h) ||
+ sip_is_via(h) ||
+ sip_is_call_id(h) ||
+ sip_is_cseq(h) ||
+ sip_is_content_length(h))
+ continue;
+ }
+ if (h->sh_class->hc_name) {
+ snprintf(hname, sizeof hname, "%s: %%s\n", h->sh_class->hc_name);
+ sl_header_print(stdout, hname, h);
+ }
+ else {
+ sl_header_print(stdout, NULL, h);
+ }
+ }
+ }
+
+ if (sip->sip_status->st_status >= 200) {
+ context->c_retval = sip->sip_status->st_status >= 300;
+ su_root_break(context->c_root);
+ }
+
+ return 0;
+}
+
+/* Read in whole (binary!) file */
+char *readfile(FILE *f)
+{
+ char *buffer = NULL;
+ long size;
+ size_t len;
+
+ if (f == NULL)
+ return NULL;
+
+ for (size = 8192, buffer = NULL, len = 0; !feof(f); size += 8192) {
+ buffer = realloc(buffer, size + 1);
+ if (!buffer)
+ exit(2);
+ len += fread(buffer + len, 1, 8192, f);
+ }
+
+ buffer[len] = '\0';
+
+ return buffer;
+}
Added: freeswitch/trunk/libs/sofia-sip/win32/ChangeLog
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/ChangeLog Thu Dec 21 01:30:28 2006
@@ -0,0 +1,44 @@
+2006-05-11 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Now building libsofia_sip_ua.dll on win32.
+
+ We define both IN_LIBSOFIA_SIP_UA and IN_LIBSOFIA_SRES in
+ libsofia_sip_ua.dsp.
+
+ Because of DLL linkage, we compile tags typedefs as C++
+ (see win32/tests/test_nua/test_nat_tags.cpp).
+
+ Removed LIBSOFIA_SIP_UA_STATIC from win32/sofia-sip/su_configure.h.
+
+ Added libsofia_sip_ua_static.lib, too. If you want to compile against
+ that, you need define LIBSOFIA_SIP_UA_STATIC by yourself.
+
+ Added libsofia-sip-ua-static/libsofia_sip_ua_static.dsp.
+
+ Using multithreaded DLL runtime for all projects.
+
+2006-05-03 Kai Vehmanen <kai.vehmanen at nokia.com>
+
+ * Added utils/sip_options example application to SofiaSIP.dsw.
+
+2006-04-17 Pekka Pessi <Pekka.Pessi at nokia.com>
+
+ * Added test_tport.dsp to SofiaSIP.dsw
+
+ * Added source files:
+
+ sres.c sres_blocking.c sres_cache.c stun.c stun_common.c stun_dns.c
+ stun_internal.h stun_mini.c nua_params.c nua_params.h tport_internal.h
+ tport_logging.c tport_stub_sigcomp.c tport_stub_stun.c
+ tport_threadpool.c tport_type_connect.c tport_type_tcp.c
+ tport_type_udp.c
+
+ and
+
+ sofia-resolv/sres.h sofia-resolv/sres_async.h
+ sofia-resolv/sres_cache.h sofia-resolv/sres_record.h
+ sofia-sip/tport_plugins.h
+
+ to libsofia_sip_ua.dsp.
+
+ * Added stat() as well as struct stat to compatibity win32/unistd.h.
Added: freeswitch/trunk/libs/sofia-sip/win32/Makefile.am
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/Makefile.am Thu Dec 21 01:30:28 2006
@@ -0,0 +1,57 @@
+#
+# Makefile.am for sofia-sip/win32
+#
+# This is used for including win32 files in dist
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+#
+# ref: http://www.gnu.org/software/automake/manual/automake.html
+
+# ----------------------------------------------------------------------
+
+noinst_HEADERS = sofia-sip/su_configure.h unistd.h config.h
+
+EXTRA_DIST = SofiaSIP.dsw \
+ libsofia-sip-ua/libsofia_sip_ua.dsp \
+ libsofia-sip-ua/sofia-sip-ua.def \
+ libsofia-sip-ua-static/libsofia_sip_ua_static.dsp \
+ tests/test_nua/test_nua.dsp \
+ tests/test_nua/test_nat_tags.cpp \
+ tests/test_nta/test_nta.dsp \
+ tests/test_tport/test_tport.dsp \
+ tests/test_tport/test_class.cpp \
+ tests/test_tport/test_table.cpp \
+ tests/torture_su_alloc/torture_su_alloc.dsp \
+ tests/torture_su_root/torture_su_root.dsp \
+ tests/torture_su_tag/torture_su_tag.dsp \
+ tests/test_su/test_su.dsp \
+ tests/torture_su_time/torture_su_time.dsp \
+ tests/torture_su_timer/torture_su_timer.dsp \
+ tests/torture_su/torture_su.dsp \
+ tests/test_memmem/test_memmem.dsp \
+ tests/test_htable/test_htable.dsp \
+ tests/torture_rbtree/torture_rbtree.dsp \
+ tests/torture_su_bm/torture_su_bm.dsp \
+ tests/torture_su_port/torture_su_port.dsp \
+ utils/localinfo/localinfo.dsp \
+ utils/sip_options/sip_options.dsp \
+ utils/sip_dig/sip_dig.dsp \
+ utils/stunc/stunc.dsp \
+ $(PTHREAD_DIST) \
+ README.txt \
+ autogen.cmd build_sources.cmd version_files.cmd version.awk \
+ install.cmd check.cmd
+
+PTHREAD_DIST = \
+ pthread/ChangeLog \
+ pthread/md5.sum.txt \
+ pthread/pthreadVC2.dll \
+ pthread/pthreadVC2.lib \
+ pthread/semaphore.h \
+ pthread/sched.h \
+ pthread/pthread.h
+
+mostlyclean-local:
+ test "$(top_builddir)" = "$(top_srcdir)" || rm -f config.h
Added: freeswitch/trunk/libs/sofia-sip/win32/Makefile.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/Makefile.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1,474 @@
+# 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.
+
+ at SET_MAKE@
+
+#
+# Makefile.am for sofia-sip/win32
+#
+# This is used for including win32 files in dist
+#
+# Copyright (C) 2005,2006 Nokia Corporation
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+# Licensed under LGPL. See file COPYING.
+#
+# ref: http://www.gnu.org/software/automake/manual/automake.html
+
+# ----------------------------------------------------------------------
+
+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@
+subdir = win32
+DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in $(srcdir)/config.h.in ChangeLog
+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 = config.h
+SOURCES =
+DIST_SOURCES =
+HEADERS = $(noinst_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@
+noinst_HEADERS = sofia-sip/su_configure.h unistd.h config.h
+EXTRA_DIST = SofiaSIP.dsw \
+ libsofia-sip-ua/libsofia_sip_ua.dsp \
+ libsofia-sip-ua/sofia-sip-ua.def \
+ libsofia-sip-ua-static/libsofia_sip_ua_static.dsp \
+ tests/test_nua/test_nua.dsp \
+ tests/test_nua/test_nat_tags.cpp \
+ tests/test_nta/test_nta.dsp \
+ tests/test_tport/test_tport.dsp \
+ tests/test_tport/test_class.cpp \
+ tests/test_tport/test_table.cpp \
+ tests/torture_su_alloc/torture_su_alloc.dsp \
+ tests/torture_su_root/torture_su_root.dsp \
+ tests/torture_su_tag/torture_su_tag.dsp \
+ tests/test_su/test_su.dsp \
+ tests/torture_su_time/torture_su_time.dsp \
+ tests/torture_su_timer/torture_su_timer.dsp \
+ tests/torture_su/torture_su.dsp \
+ tests/test_memmem/test_memmem.dsp \
+ tests/test_htable/test_htable.dsp \
+ tests/torture_rbtree/torture_rbtree.dsp \
+ tests/torture_su_bm/torture_su_bm.dsp \
+ tests/torture_su_port/torture_su_port.dsp \
+ utils/localinfo/localinfo.dsp \
+ utils/sip_options/sip_options.dsp \
+ utils/sip_dig/sip_dig.dsp \
+ utils/stunc/stunc.dsp \
+ $(PTHREAD_DIST) \
+ README.txt \
+ autogen.cmd build_sources.cmd version_files.cmd version.awk \
+ install.cmd check.cmd
+
+PTHREAD_DIST = \
+ pthread/ChangeLog \
+ pthread/md5.sum.txt \
+ pthread/pthreadVC2.dll \
+ pthread/pthreadVC2.lib \
+ pthread/semaphore.h \
+ pthread/sched.h \
+ pthread/pthread.h
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.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 win32/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu win32/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
+config.h: $(top_builddir)/config.status $(srcdir)/config.h.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+uninstall-info-am:
+
+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
+
+distdir: $(DISTFILES)
+ $(mkdir_p) $(distdir)/libsofia-sip-ua $(distdir)/libsofia-sip-ua-static $(distdir)/pthread $(distdir)/sofia-sip $(distdir)/tests/test_htable $(distdir)/tests/test_memmem $(distdir)/tests/test_nta $(distdir)/tests/test_nua $(distdir)/tests/test_su $(distdir)/tests/test_tport $(distdir)/tests/torture_rbtree $(distdir)/tests/torture_su $(distdir)/tests/torture_su_alloc $(distdir)/tests/torture_su_bm $(distdir)/tests/torture_su_port $(distdir)/tests/torture_su_root $(distdir)/tests/torture_su_tag $(distdir)/tests/torture_su_time $(distdir)/tests/torture_su_timer $(distdir)/utils/localinfo $(distdir)/utils/sip_dig $(distdir)/utils/sip_options $(distdir)/utils/stunc
+ @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
+check: check-am
+all-am: Makefile $(HEADERS)
+installdirs:
+install: 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)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-libtool \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool \
+ mostlyclean-local
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool ctags distclean 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-exec install-exec-am install-info \
+ install-info-am install-man install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool mostlyclean-local pdf pdf-am ps ps-am tags \
+ uninstall uninstall-am uninstall-info-am
+
+
+mostlyclean-local:
+ test "$(top_builddir)" = "$(top_srcdir)" || rm -f config.h
+# 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:
Added: freeswitch/trunk/libs/sofia-sip/win32/README.txt
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/README.txt Thu Dec 21 01:30:28 2006
@@ -0,0 +1,22 @@
+======================================
+win32/README.txt / Sofia-SIP for win32
+======================================
+
+The win32 subdirectory contains the build environment for Win32 environment
+using MSVC. In order to compile the code with Windows 2000 SDK you have to
+install so called "IPv6 Technology Preview for Windows 2000". The preview
+contains updated IPv6 API in <tpipv6.h> and <wspiapi.h> header files.
+
+http://msdn.microsoft.com/downloads/sdks/platform/tpipv6.asp
+
+There is a pthread implementation for Visual C on Win32 included.
+Source code and documentation for the pthread library can also be
+downloaded from http://sources.redhat.com/pthreads-win32/.
+
+The script autogen.cmd should be used to prepare source tree before
+compiling Sofia SIP. Note that it uses the gawk utility - see
+http://unxutils.sourceforge.net.
+
+Currently, the SofiaSIP.dsw workspace creates a shared library for
+sofia-sip-ua and a few test programs. The tests programs can be run
+with the script check.cmd.
Added: freeswitch/trunk/libs/sofia-sip/win32/SofiaSIP.dsw
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/SofiaSIP.dsw Thu Dec 21 01:30:28 2006
@@ -0,0 +1,341 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "libsofia_sip_ua"=".\libsofia-sip-ua\libsofia_sip_ua.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "libsofia_sip_ua_static"=".\libsofia-sip-ua-static\libsofia_sip_ua_static.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "localinfo"=".\utils\localinfo\localinfo.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libsofia_sip_ua
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "sip_dig"=".\utils\sip_dig\sip_dig.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libsofia_sip_ua
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "sip_options"=".\utils\sip_options\sip_options.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libsofia_sip_ua
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "sip_options_static"=".\utils\sip_options_static\sip_options_static.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libsofia_sip_ua_static
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "stunc"=".\utils\stunc\stunc.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libsofia_sip_ua
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "test_htable"=".\tests\test_htable\test_htable.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libsofia_sip_ua
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "test_memmem"=".\tests\test_memmem\test_memmem.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libsofia_sip_ua_static
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "test_nta"=".\tests\test_nta\test_nta.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libsofia_sip_ua
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "test_nua"=".\tests\test_nua\test_nua.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libsofia_sip_ua
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "test_su"=".\tests\test_su\test_su.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libsofia_sip_ua
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "test_tport"=".\tests\test_tport\test_tport.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libsofia_sip_ua
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "torture_rbtree"=".\tests\torture_rbtree\torture_rbtree.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libsofia_sip_ua
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "torture_su"=".\tests\torture_su\torture_su.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libsofia_sip_ua
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "torture_su_alloc"=".\tests\torture_su_alloc\torture_su_alloc.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libsofia_sip_ua
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "torture_su_bm"=".\tests\torture_su_bm\torture_su_bm.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libsofia_sip_ua_static
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "torture_su_port"=".\tests\torture_su_port\torture_su_port.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libsofia_sip_ua_static
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "torture_su_root"=".\tests\torture_su_root\torture_su_root.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libsofia_sip_ua
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "torture_su_tag"=".\tests\torture_su_tag\torture_su_tag.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libsofia_sip_ua
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "torture_su_time"=".\tests\torture_su_time\torture_su_time.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libsofia_sip_ua_static
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "torture_su_timer"=".\tests\torture_su_timer\torture_su_timer.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libsofia_sip_ua
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
Added: freeswitch/trunk/libs/sofia-sip/win32/autogen.cmd
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/autogen.cmd Thu Dec 21 01:30:28 2006
@@ -0,0 +1,39 @@
+::
+:: Prepare pristine Sofia SIP source tree for Visual C
+::
+:: NOTE: this script requires gawk - see http://unxutils.sourceforge.net
+::
+:: This file is part of the Sofia-SIP package
+::
+:: Copyright (C) 2006 Nokia Corporation.
+::
+:: Contact: Pekka Pessi <pekka.pessi at nokia.com>
+::
+:: This library is free software; you can redistribute it and/or
+:: modify it under the terms of the GNU Lesser General Public License
+:: as published by the Free Software Foundation; either version 2.1 of
+:: the License, or (at your option) any later version.
+::
+:: This library is distributed in the hope that it will be useful, but
+:: WITHOUT ANY WARRANTY; without even the implied warranty of
+:: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+:: Lesser General Public License for more details.
+::
+:: You should have received a copy of the GNU Lesser General Public
+:: License along with this library; if not, write to the Free Software
+:: Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+:: 02110-1301 USA
+::
+
+ at setlocal
+ at if x%AWK%==x set AWK=gawk
+
+ at call version_files.cmd
+
+ at call build_sources.cmd
+
+ at echo.
+ at echo NOTE:
+ at echo NOTE: Remember to install pthreadVC2.dll to your path, too!
+ at echo NOTE:
+ at endlocal
\ No newline at end of file
Added: freeswitch/trunk/libs/sofia-sip/win32/build_sources.cmd
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/build_sources.cmd Thu Dec 21 01:30:28 2006
@@ -0,0 +1,115 @@
+::
+:: Build sources on win32
+::
+
+ at setlocal
+ at if x%AWK%==x set AWK=gawk
+ at set CHECK=@IF errorlevel 1 GOTO failed
+
+:: Check that we really have awk
+@%AWK% "{ exit(0); }" < NUL >NUL
+ at if not errorlevel 9009 goto have_awk
+ at echo *** install %AWK% (GNU awk) into your PATH ***
+ at goto failed
+:have_awk
+
+ at set MSG_AWK=gawk -v BINMODE=rw -f ../libsofia-sip-ua/msg/msg_parser.awk
+:: in Win32 exit 0; from gawk 3.1.3 gets converted to errorlevel 1
+:: If you have gawk 3.1.3 uncomment the following line
+:: @set MSG_AWK=gawk -v BINMODE=rw -f ../libsofia-sip-ua/msg/msg_parser.awk success=-1
+ at set TAG_AWK=gawk -f ../libsofia-sip-ua/su/tag_dll.awk BINMODE=rw
+
+ at set IN=../libsofia-sip-ua/msg/test_class.h
+ at set PR=../libsofia-sip-ua/msg/test_protos.h
+ at set PT=../libsofia-sip-ua/msg/test_table.c
+
+%MSG_AWK% module=msg_test NO_MIDDLE=1 NO_LAST=1 ^
+ PR=%PR% %IN% < NUL
+%CHECK%
+%MSG_AWK% module=msg_test prefix=msg MC_HASH_SIZE=127 multipart=msg_multipart ^
+ PT=%PT% %IN% < NUL
+%CHECK%
+
+ at set IN=../libsofia-sip-ua/msg/sofia-sip/msg_mime.h
+ at set PR=../libsofia-sip-ua/msg/sofia-sip/msg_protos.h
+ at set PR2=../libsofia-sip-ua/msg/sofia-sip/msg_mime_protos.h
+ at set PT=../libsofia-sip-ua/msg/msg_mime_table.c
+
+%MSG_AWK% module=msg NO_FIRST=1 NO_MIDDLE=1 PR=%PR% %IN% < NUL
+%CHECK%
+%MSG_AWK% module=msg NO_FIRST=1 NO_LAST=1 PR=%PR2% %IN% < NUL
+%CHECK%
+%MSG_AWK% module=msg_multipart tprefix=msg prefix=mp MC_HASH_SIZE=127 ^
+ PT=%PT% %IN% < NUL
+%CHECK%
+
+ at set IN=../libsofia-sip-ua/sip/sofia-sip/sip.h
+ at set PR=../libsofia-sip-ua/sip/sip_tag.c
+ at set PR2=../libsofia-sip-ua/sip/sofia-sip/sip_hclasses.h
+ at set PR3=../libsofia-sip-ua/sip/sofia-sip/sip_protos.h
+ at set PR4=../libsofia-sip-ua/sip/sofia-sip/sip_tag.h
+ at set PT=../libsofia-sip-ua/sip/sip_parser_table.c
+
+%MSG_AWK% module=sip PR=%PR% %IN% < NUL
+%CHECK%
+%MSG_AWK% module=sip PR=%PR2% %IN% < NUL
+%CHECK%
+%MSG_AWK% module=sip PR=%PR3% %IN% < NUL
+%CHECK%
+%MSG_AWK% module=sip PR=%PR4% %IN% < NUL
+%CHECK%
+
+%MSG_AWK% module=sip MC_HASH_SIZE=127 MC_SHORT_SIZE=26 ^
+ FLAGFILE=../libsofia-sip-ua/sip/sip_bad_mask ^
+ PT=%PT% %IN% < NUL
+%CHECK%
+
+ at set IN=../libsofia-sip-ua/http/sofia-sip/http.h
+ at set PR=../libsofia-sip-ua/http/http_tag.c
+ at set PR2=../libsofia-sip-ua/http/sofia-sip/http_protos.h
+ at set PR3=../libsofia-sip-ua/http/sofia-sip/http_tag.h
+ at set PT=../libsofia-sip-ua/http/http_parser_table.c
+
+%MSG_AWK% module=http PR=%PR% %IN% < NUL
+%CHECK%
+%MSG_AWK% module=http PR=%PR2% %IN% < NUL
+%CHECK%
+%MSG_AWK% module=http PR=%PR3% %IN% < NUL
+%CHECK%
+%MSG_AWK% module=http MC_HASH_SIZE=127 PT=%PT% %IN% < NUL
+%CHECK%
+
+ at set P=../libsofia-sip-ua
+
+%TAG_AWK% NO_DLL=1 %P%/http/http_tag.c < NUL
+%CHECK%
+%TAG_AWK% NO_DLL=1 %P%/iptsec/auth_tag.c < NUL
+%CHECK%
+%TAG_AWK% NO_DLL=1 %P%/msg/msg_tag.c < NUL
+%CHECK%
+%TAG_AWK% NO_DLL=1 %P%/nea/nea_tag.c < NUL
+%CHECK%
+%TAG_AWK% NO_DLL=1 LIST=nta_tag_list %P%/nta/nta_tag.c < NUL
+%CHECK%
+%TAG_AWK% NO_DLL=1 %P%/nth/nth_tag.c < NUL
+%CHECK%
+%TAG_AWK% NO_DLL=1 LIST=nua_tag_list %P%/nua/nua_tag.c < NUL
+%CHECK%
+%TAG_AWK% NO_DLL=1 %P%/sdp/sdp_tag.c < NUL
+%CHECK%
+%TAG_AWK% NO_DLL=1 %P%/sip/sip_tag.c < NUL
+%CHECK%
+%TAG_AWK% NO_DLL=1 LIST=soa_tag_list %P%/soa/soa_tag.c < NUL
+%CHECK%
+%TAG_AWK% NO_DLL=1 LIST=stun_tag_list %P%/stun/stun_tag.c < NUL
+%CHECK%
+%TAG_AWK% NO_DLL=1 %P%/tport/tport_tag.c < NUL
+%CHECK%
+%TAG_AWK% NO_DLL=1 %P%/url/url_tag.c < NUL
+%CHECK%
+
+ at GOTO end
+:failed
+ at ECHO *** FAILED ***
+:end
+ at endlocal
Added: freeswitch/trunk/libs/sofia-sip/win32/check.cmd
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/check.cmd Thu Dec 21 01:30:28 2006
@@ -0,0 +1,67 @@
+:: Run test programs
+::
+:: This file is part of the Sofia-SIP package
+::
+:: Copyright (C) 2006 Nokia Corporation.
+::
+:: Contact: Pekka Pessi <pekka.pessi at nokia.com>
+::
+:: This library is free software; you can redistribute it and/or
+:: modify it under the terms of the GNU Lesser General Public License
+:: as published by the Free Software Foundation; either version 2.1 of
+:: the License, or (at your option) any later version.
+::
+:: This library is distributed in the hope that it will be useful, but
+:: WITHOUT ANY WARRANTY; without even the implied warranty of
+:: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+:: Lesser General Public License for more details.
+::
+:: You should have received a copy of the GNU Lesser General Public
+:: License along with this library; if not, write to the Free Software
+:: Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+:: 02110-1301 USA
+::
+tests\torture_su_alloc\Debug\torture_su_alloc.exe
+ at if errorlevel 1 ( echo torture_su_alloc: FAIL ) else echo torture_su_alloc: PASS
+
+tests\torture_su_root\Debug\torture_su_root.exe
+ at if errorlevel 1 ( echo torture_su_root: FAIL ) else echo torture_su_root: PASS
+
+tests\torture_su_tag\Debug\torture_su_tag.exe
+ at if errorlevel 1 ( echo torture_su_tag: FAIL ) else echo torture_su_tag: PASS
+
+tests\test_su\Debug\test_su.exe
+ at if errorlevel 1 ( echo test_su: FAIL ) else echo test_su: PASS
+
+tests\torture_su_time\Debug\torture_su_time.exe
+ at if errorlevel 1 ( echo torture_su_time: FAIL ) else echo torture_su_time: PASS
+
+tests\torture_su_timer\Debug\torture_su_timer.exe
+ at if errorlevel 1 ( echo torture_su_timer: FAIL ) else echo torture_su_timer: PASS
+
+tests\torture_su\Debug\torture_su.exe
+ at if errorlevel 1 ( echo torture_su: FAIL ) else echo torture_su: PASS
+
+tests\test_memmem\Debug\test_memmem.exe
+ at if errorlevel 1 ( echo test_memmem: FAIL ) else echo test_memmem: PASS
+
+tests\test_tport\Debug\test_tport.exe
+ at if errorlevel 1 ( echo test_tport: FAIL ) else echo test_tport: PASS
+
+tests\test_nta\Debug\test_nta.exe
+ at if errorlevel 1 ( echo test_nta: FAIL ) else echo test_nta: PASS
+
+tests\test_nua\Debug\test_nua.exe
+ at if errorlevel 1 ( echo test_nua: FAIL ) else echo test_nua: PASS
+
+tests\test_htable\Debug\test_htable.exe
+ at if errorlevel 1 ( echo test_htable: FAIL ) else echo test_htable: PASS
+
+tests\torture_rbtree\Debug\torture_rbtree.exe
+ at if errorlevel 1 ( echo torture_rbtree: FAIL ) else echo torture_rbtree: PASS
+
+tests\torture_su_bm\Debug\torture_su_bm.exe
+ at if errorlevel 1 ( echo torture_su_bm: FAIL ) else echo torture_su_bm: PASS
+
+tests\torture_su_port\Debug\torture_su_port.exe
+ at if errorlevel 1 ( echo torture_su_port: FAIL ) else echo torture_su_port: PASS
Added: freeswitch/trunk/libs/sofia-sip/win32/config.h.in
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/config.h.in Thu Dec 21 01:30:28 2006
@@ -0,0 +1,467 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@file win32/config.h.in
+ * @brief <config.h> used by Windows.
+ *
+ * Use this on WIN32.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Tue Sep 12 19:22:54 2000 ppessi
+ */
+
+/* Define this as the random number source name. */
+#undef DEV_URANDOM
+
+/* Define this as 1 if you have addrinfo structure. */
+#define HAVE_ADDRINFO 1
+
+/* Define to 1 if you have the `alarm' function. */
+#undef HAVE_ALARM
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#undef HAVE_ARPA_INET_H
+
+/* Define to 1 if you have the `clock_getcpuclockid' function. */
+#undef HAVE_CLOCK_GETCPUCLOCKID
+
+/* Define to 1 if you have the `clock_gettime' function. */
+#undef HAVE_CLOCK_GETTIME
+
+/* Define this as 1 if you have /dev/urandom. */
+#undef HAVE_DEV_URANDOM
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the `epoll' function. */
+#undef HAVE_EPOLL
+
+/* Define this as 1 if you have WIN32 FILETIME type and
+ GetSystemTimeAsFileTime(). */
+#define HAVE_FILETIME 1
+
+/* Define to 1 if you have the `flock' function. */
+#undef HAVE_FLOCK
+
+/* Define to 1 if you have the `freeaddrinfo' function. */
+#define HAVE_FREEADDRINFO 1
+
+/* Define as 1 if the C compiler supports __func__ */
+#undef HAVE_FUNC
+
+/* Define as 1 if the C compiler supports __FUNCTION__ */
+#undef HAVE_FUNCTION
+
+/* Define to 1 if you have the `gai_strerror' function. */
+#define HAVE_GAI_STRERROR 1
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#define HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `getdelim' function. */
+#undef HAVE_GETDELIM
+
+/* Define to 1 if you have the `gethostbyname' function. */
+#define HAVE_GETHOSTBYNAME 1
+
+/* Define to 1 if you have the `gethostname' function. */
+#define HAVE_GETHOSTNAME 1
+
+/* Define to 1 if you have the `getifaddrs' function. */
+#undef HAVE_GETIFADDRS
+
+/* Define to 1 if you have the `getipnodebyname' function. */
+#undef HAVE_GETIPNODEBYNAME
+
+/* Define to 1 if you have the `getline' function. */
+#undef HAVE_GETLINE
+
+/* Define to 1 if you have the `getnameinfo' function. */
+#define HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `getpass' function. */
+#undef HAVE_GETPASS
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#undef HAVE_GETTIMEOFDAY
+
+/* Define to 1 if you have the <ifaddr.h> header file. */
+#undef HAVE_IFADDR_H
+
+/* Define this as 1 if you have SIOCGIFCONF */
+#undef HAVE_IFCONF
+
+/* Define this as 1 if you have SIOCGIFNUM ioctl */
+#undef HAVE_IFNUM
+
+/* Define this as 1 if you have ifr_ifindex in <net/if.h> */
+#undef HAVE_IFR_IFINDEX
+
+/* Define this as 1 if you have ifr_index in <net/if.h> */
+#undef HAVE_IFR_INDEX
+
+/* Define to 1 if you have the `if_nameindex' function. */
+#undef HAVE_IF_NAMEINDEX
+
+/* Define to 1 if you have the `inet_ntop' function. */
+#undef HAVE_INET_NTOP
+
+/* Define to 1 if you have the `inet_pton' function. */
+#undef HAVE_INET_PTON
+
+/* Define to 1 if you have the `initstate' function. */
+#undef HAVE_INITSTATE
+
+/* Define this as 1 if you have inlining compiler */
+#define HAVE_INLINE 1
+
+/* Define this as 1 if you have WIN32 INTERFACE_INFO_EX type. */
+#undef HAVE_INTERFACE_INFO_EX
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define as 1 you have WIN32 <iphlpapi.h> */
+// XXX: vehmanek-win32-fix:
+#undef HAVE_IPHLPAPI_H
+
+/* Define this as 1 if you have IPV6_RECVERR in <netinet/in6.h> */
+#undef HAVE_IPV6_RECVERR
+
+/* Define this as 1 if you have IP_RECVERR in <netinet/in.h> */
+#undef HAVE_IP_RECVERR
+
+/* Define to 1 if you have the `crypto' library (-lcrypto). */
+#undef HAVE_LIBCRYPTO
+
+/* Define to 1 if you have the `pthread' library (-lpthread). */
+#define HAVE_LIBPTHREAD 1
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+#undef HAVE_LIBSOCKET
+
+/* Define to 1 if you have the `ssl' library (-lssl). */
+#undef HAVE_LIBSSL
+
+/* Define to 1 if you have the `memccpy' function. */
+#undef HAVE_MEMCCPY
+
+/* Define to 1 if you have the `memcspn' function. */
+#undef HAVE_MEMCSPN
+
+/* Define to 1 if you have the `memmem' function. */
+#undef HAVE_MEMMEM
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the `memspn' function. */
+#undef HAVE_MEMSPN
+
+/* Define this as 1 if you are compiling in MinGW environment */
+#undef HAVE_MINGW
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#undef HAVE_NETDB_H
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#undef HAVE_NETINET_IN_H
+
+/* Define to 1 if you have the <netinet/sctp.h> header file. */
+#undef HAVE_NETINET_SCTP_H
+
+/* Define to 1 if you have the <netinet/tcp.h> header file. */
+#undef HAVE_NETINET_TCP_H
+
+/* Define to 1 if you have the <netpacket/packet.h> header file. */
+#undef HAVE_NETPACKET_PACKET_H
+
+/* Define to 1 if you have the <net/if.h> header file. */
+#undef HAVE_NET_IF_H
+
+/* Define to 1 if you have the <net/if_types.h> header file. */
+#undef HAVE_NET_IF_TYPES_H
+
+/* Define this as 1 if you have OpenSSL */
+#undef HAVE_OPENSSL
+
+/* Define to 1 if you have the <openssl/tls1.h> header file. */
+#undef HAVE_OPENSSL_TLS1_H
+
+/* Define to 1 if you have the `poll' function. */
+#undef HAVE_POLL
+
+/* Define this as 1 if you have /proc/net/if_inet6 control file */
+#undef HAVE_PROC_NET_IF_INET6
+
+/* Define to 1 if you have the <pthread.h> header file. */
+#define HAVE_PTHREAD_H 1
+
+/* Define to 1 if you have the `random' function. */
+/* See later */
+#define HAVE_RANDOM 1
+
+/* Define this as 1 if you have sa_len in struct sockaddr */
+#undef HAVE_SA_LEN
+
+/* Define this a 1 if you have SCTP */
+#undef HAVE_SCTP
+
+/* Define to 1 if you have the `select' function. */
+#undef HAVE_SELECT
+
+/* Define this as 1 if you have Sofia sigcomp >= 2.5 */
+#undef HAVE_SIGCOMP
+
+/* Define to 1 if you have the <sigcomp.h> header file. */
+#undef HAVE_SIGCOMP_H
+
+/* Define as 1 if you have SIGPIPE */
+#undef HAVE_SIGPIPE
+
+/* Define this as 1 if you have IPv6 structures and constants */
+#define HAVE_SIN6 1
+
+/* Define this as 1 if you have WIN32 WSAIoctl SIO_ADDRESS_LIST_QUERY. */
+#define HAVE_SIO_ADDRESS_LIST_QUERY 1
+
+/* Define to 1 if you have the `socketpair' function. */
+#undef HAVE_SOCKETPAIR
+
+/* Define this as 1 if you have Sofia sigcomp >= 2.5 */
+#undef HAVE_SOFIA_SIGCOMP
+
+/* Define as 1 always */
+#define HAVE_SOFIA_SIP 1
+
+/* Define as 1 if we use S/MIME library */
+#undef HAVE_SOFIA_SMIME
+
+/* Define as 1 if we use DNS library */
+#define HAVE_SOFIA_SRESOLV 1
+
+/* Define as 1 if we use STUN library */
+#undef HAVE_SOFIA_STUN
+
+/* Define as 1 always */
+#define HAVE_SOFIA_SU 1
+
+/* Define as 1 if we use SRTP */
+#undef HAVE_SRTP
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the `strcasestr' function. */
+#undef HAVE_STRCASESTR
+
+/* Define to 1 if you have the `strerror' function. */
+#define HAVE_STRERROR 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strtoull' function. */
+#undef HAVE_STRTOULL
+
+/* Define this as 1 if your CC supports C99 struct initialization */
+#undef HAVE_STRUCT_KEYWORDS
+
+/* Define to 1 if you have the <sofia-sip/su_wait.h> header file. */
+#define HAVE_SU_WAIT_H 1
+
+/* Define to 1 if you have the <sys/filio.h> header file. */
+#undef HAVE_SYS_FILIO_H
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#undef HAVE_SYS_SELECT_H
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#undef HAVE_SYS_SOCKET_H
+
+/* Define to 1 if you have the <sys/sockio.h> header file. */
+#undef HAVE_SYS_SOCKIO_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the `tcsetattr' function. */
+#undef HAVE_TCSETATTR
+
+/* Define this as 1 if you have TLS */
+#undef HAVE_TLS
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define as 1 if we use UPnP */
+#undef HAVE_UPNP
+
+/* Define as 1 you have WIN32 */
+#define HAVE_WIN32 1
+
+/* Define to 1 if you have the <windef.h> header file. */
+#define HAVE_WINDEF_H 1
+
+/* Define to 1 if you have the <winsock2.h> header file. */
+#define HAVE_WINSOCK2_H 1
+
+/* Define to 1 if you have the <ws2tcpip.h> header file. */
+#define HAVE_WS2TCPIP_H 1
+
+/* Define as format (%lli) for long long */
+#define LLI "%I64i"
+
+/* Define as format (%llu) for unsigned long long */
+#define LLU "%I64u"
+
+/* Define as format (%llx) for long long hex */
+#define LLX "%I64x"
+
+/* Name of package */
+#define PACKAGE "@PACKAGE@"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "@PACKAGE_BUGREPORT@"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "@PACKAGE_NAME@"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "@PACKAGE_STRING@"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "@PACKAGE_TARNAME@"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "@PACKAGE_VERSION@"
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#define RETSIGTYPE void
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Version number of package */
+#define VERSION "@PACKAGE_VERSION@"
+
+/* Define to 1 if your processor stores words with the most significant byte
+ first (like Motorola and SPARC, unlike Intel and VAX). */
+#undef WORDS_BIGENDIAN
+
+/* Enable GNU extensions on systems that have them. */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef __cplusplus
+#define inline __inline
+#endif
+
+/* Define as at least 64-bit int type */
+#define longlong __int64
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+/* PPe: defined in stddef.h */
+#undef size_t
+
+#define HOSTTYPE "pc-xp-win32"
+/* #define HOSTTYPE "pc-98-win32" */
+/* #define HOSTTYPE "pc-nt-win32" */
+
+/* Define this as locale-independent strcmp(). */
+#define strcasecmp _stricmp
+
+/* Define this as locale-independent strncmp(). */
+#define strncasecmp _strnicmp
+
+#define snprintf _snprintf
+#define vsnprintf _vsnprintf
+
+#define srandom(x) srand((x))
+#define random() rand()
+
+/* This is GCC magic */
+#define __attribute__(x)
+
+/* Define this as 1 if you have TimeGetTime() */
+#define HAVE_TIMEGETTIME 1
+
+#define PATH_MAX _MAX_PATH
+
+#define HAVE_WINMM 1
+
+/* Define this as 1 if you have FILETIME */
+#define HAVE_FILETIME 1
+
+/* Define this as 1 if you have WinSock2 ioctl SIO_ADDRESS_LIST_QUERY */
+#define HAVE_SIO_ADDRESS_LIST_QUERY 1
+
+/* Define this as 1 if you have INTERFACE_INFO ioctl */
+#define HAVE_INTERFACE_INFO (1)
+
+/* Ignore certain warnings */
+#ifdef _MSC_VER
+#pragma warning( disable : 4090 4204 4244 4018 4514 4706 4761)
+/* VC does not grok const */
+#pragma warning( disable : 4022 4028 )
+/* Temporarily disable high frequency, low value warnings.
+ We may still want to re-enable and fix these */
+#pragma warning( disable : 4132 4100 4127 4152)
+#if (_MSC_VER >= 1400) // VC8+
+#ifndef _CRT_SECURE_NO_DEPRECATE
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
+#ifndef _CRT_NONSTDC_NO_DEPRECATE
+#define _CRT_NONSTDC_NO_DEPRECATE
+#endif
+#endif // VC8+
+#endif
+
+/* size_t/ssize_t modifiers
+ * ref: http://msdn2.microsoft.com/en-us/library/tcxf1dw6.aspx */
+#define MOD_ZD "%ld"
+#define MOD_ZU "%lu"
Added: freeswitch/trunk/libs/sofia-sip/win32/install.cmd
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/install.cmd Thu Dec 21 01:30:28 2006
@@ -0,0 +1,62 @@
+::
+:: Collect files to be installed to install directory
+::
+:: This file is part of the Sofia-SIP package
+::
+:: Copyright (C) 2006 Nokia Corporation.
+::
+:: Contact: Pekka Pessi <pekka.pessi at nokia.com>
+::
+:: This library is free software; you can redistribute it and/or
+:: modify it under the terms of the GNU Lesser General Public License
+:: as published by the Free Software Foundation; either version 2.1 of
+:: the License, or (at your option) any later version.
+::
+:: This library is distributed in the hope that it will be useful, but
+:: WITHOUT ANY WARRANTY; without even the implied warranty of
+:: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+:: Lesser General Public License for more details.
+::
+:: You should have received a copy of the GNU Lesser General Public
+:: License along with this library; if not, write to the Free Software
+:: Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+:: 02110-1301 USA
+::
+
+set name=sofia-sip
+set major=1.11
+set config=debug
+
+:: Uncomment this if you want release
+:: set config=release
+
+set destdir=..\..\%name%-%major%-%config%
+set includedir=%destdir%\include
+set sofiadir=%includedir%\sofia-sip
+set libdir=%destdir%\lib
+mkdir %destdir% %includedir% %sofiadir% %libdir%
+
+::
+:: Copy docs
+::
+set docs=README AUTHORS COPYING COPYRIGHTS README.developers RELEASE TODO ChangeLog
+for %%f in (%docs%) do xcopy /Y ..\%%f %destdir%
+
+::
+:: Copy headers
+::
+set SUBDIRS=su features bnf sresolv sdp url msg sip stun ipt soa tport http nta nea iptsec nth nua
+
+xcopy /Y sofia-sip\*.h %sofiadir%
+for %%s in (%SUBDIRS%) do xcopy /Y ..\libsofia-sip-ua\%%s\sofia-sip\*.h %sofiadir%
+
+xcopy /Y pthread\.*.h %includedir%
+
+::
+:: Copy libraries
+::
+
+::xcopy /Y libsofia-sip-ua\%config%\libsofia_sip_ua.dll %libdir%
+xcopy /Y libsofia-sip-ua\%config%\libsofia_sip_ua.lib %libdir%
+xcopy /Y Pthread\*.dll %libdir%
+xcopy /Y Pthread\*.lib %libdir%
Added: freeswitch/trunk/libs/sofia-sip/win32/libsofia-sip-ua-static/libsofia_sip_ua_static.dsp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/libsofia-sip-ua-static/libsofia_sip_ua_static.dsp Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1373 @@
+# Microsoft Developer Studio Project File - Name="libsofia_sip_ua_static" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=libsofia_sip_ua_static - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "libsofia_sip_ua_static.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "libsofia_sip_ua_static.mak" CFG="libsofia_sip_ua_static - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "libsofia_sip_ua_static - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "libsofia_sip_ua_static - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "libsofia_sip_ua_static - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /WX /GX /O2 /I ".." /I "..\..\libsofia-sip-ua\su" /I "..\..\libsofia-sip-ua\ipt" /I "..\..\libsofia-sip-ua\sresolv" /I "..\..\libsofia-sip-ua\bnf" /I "..\..\libsofia-sip-ua\url" /I "..\..\libsofia-sip-ua\msg" /I "..\..\libsofia-sip-ua\sip" /I "..\..\libsofia-sip-ua\nta" /I "..\..\libsofia-sip-ua\nua" /I "..\..\libsofia-sip-ua\iptsec" /I "..\..\libsofia-sip-ua\http" /I "..\..\libsofia-sip-ua\nth" /I "..\..\libsofia-sip-ua\nea" /I "..\..\libsofia-sip-ua\sdp" /I "..\..\libsofia-sip-ua\soa" /I "..\..\libsofia-sip-ua\stun" /I "..\..\libsofia-sip-ua\tport" /I "..\..\libsofia-sip-ua\features" /I "..\pthread" /I "." /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "IN_LIBSOFIA_SIP_UA_STATIC" /D "LIBSOFIA_SIP_UA_STATIC" /D "LIBSRES_STATIC" /FR /YX /FD /c
+# ADD BASE RSC /l 0x40b /d "NDEBUG"
+# ADD RSC /l 0x40b /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ELSEIF "$(CFG)" == "libsofia_sip_ua_static - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /D "HAVE_CONFIG_H" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /WX /Gm /GX /ZI /Od /I ".." /I "..\..\libsofia-sip-ua\su" /I "..\..\libsofia-sip-ua\ipt" /I "..\..\libsofia-sip-ua\sresolv" /I "..\..\libsofia-sip-ua\bnf" /I "..\..\libsofia-sip-ua\url" /I "..\..\libsofia-sip-ua\msg" /I "..\..\libsofia-sip-ua\sip" /I "..\..\libsofia-sip-ua\nta" /I "..\..\libsofia-sip-ua\nua" /I "..\..\libsofia-sip-ua\iptsec" /I "..\..\libsofia-sip-ua\http" /I "..\..\libsofia-sip-ua\nth" /I "..\..\libsofia-sip-ua\nea" /I "..\..\libsofia-sip-ua\sdp" /I "..\..\libsofia-sip-ua\soa" /I "..\..\libsofia-sip-ua\stun" /I "..\..\libsofia-sip-ua\tport" /I "..\..\libsofia-sip-ua\features" /I "..\pthread" /I "." /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /D "IN_LIBSOFIA_SIP_UA_STATIC" /D "LIBSOFIA_SIP_UA_STATIC" /D "LIBSRES_STATIC" /FR /FD /GZ /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x40b /d "_DEBUG"
+# ADD RSC /l 0x40b /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ENDIF
+
+# Begin Target
+
+# Name "libsofia_sip_ua_static - Win32 Release"
+# Name "libsofia_sip_ua_static - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Group "su"
+
+# PROP Default_Filter "su*.c"
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\inet_ntop.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\inet_pton.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_addrinfo.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_alloc.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_alloc_lock.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_bm.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_default_log.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_errno.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_global_log.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_localinfo.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_log.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_md5.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_os_nw.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_port.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_root.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_sprintf.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_strdup.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_strlst.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_tag_io.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_taglist.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_time.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_time0.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_timer.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_uniqueid.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_vector.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_wait.c"
+# End Source File
+# End Group
+# Begin Group "ipt"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\ipt\base64.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\ipt\rc4.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\ipt\string0.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\ipt\token64.c"
+# End Source File
+# End Group
+# Begin Group "url"
+
+# PROP Default_Filter "url*.c"
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\url\url.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\url\url_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\url\url_tag_ref.c"
+# End Source File
+# End Group
+# Begin Group "features"
+
+# PROP Default_Filter "features*.c"
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\features\features.c"
+# End Source File
+# End Group
+# Begin Group "bnf"
+
+# PROP Default_Filter "bnf*.c"
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\bnf\bnf.c"
+# End Source File
+# End Group
+# Begin Group "msg"
+
+# PROP Default_Filter "msg*.c"
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_auth.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_basic.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_date.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_generic.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_header_copy.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_header_make.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_mclass.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_mime.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_mime_table.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_parser.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_parser_util.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_tag.c"
+# End Source File
+# End Group
+# Begin Group "clib replacement"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\memcspn.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\memmem.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\memspn.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\strcasestr.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\strtoull.c"
+# End Source File
+# End Group
+# Begin Group "sip"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_basic.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_caller_prefs.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_event.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_extra.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_feature.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_header.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_mime.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_parser.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_parser_table.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_prack.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_pref_util.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_reason.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_refer.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_security.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_session.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_status.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_tag_class.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_tag_ref.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_time.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_util.c"
+# End Source File
+# End Group
+# Begin Group "http"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\http_basic.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\http_extra.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\http_header.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\http_parser.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\http_parser_table.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\http_status.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\http_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\http_tag_class.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\http_tag_ref.c"
+# End Source File
+# End Group
+# Begin Group "nth"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nth\nth_client.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nth\nth_server.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nth\nth_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nth\nth_tag_ref.c"
+# End Source File
+# End Group
+# Begin Group "sresolv"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sresolv\sres.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sresolv\sres_blocking.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sresolv\sres_cache.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sresolv\sresolv.c"
+# End Source File
+# End Group
+# Begin Group "nea"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nea\nea.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nea\nea_debug.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nea\nea_event.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nea\nea_server.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nea\nea_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nea\nea_tag_ref.c"
+# End Source File
+# End Group
+# Begin Group "iptsec"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\auth_client.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\auth_common.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\auth_digest.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\auth_module.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\auth_module_http.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\auth_module_sip.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\auth_plugin.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\auth_plugin_delayed.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\auth_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\auth_tag_ref.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\iptsec_debug.c"
+# End Source File
+# End Group
+# Begin Group "stun"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\stun\stun.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\stun\stun_common.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\stun\stun_dns.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\stun\stun_internal.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\stun\stun_mini.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\stun\stun_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\stun\stun_tag_ref.c"
+# End Source File
+# End Group
+# Begin Group "nua"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_common.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_dialog.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_dialog.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_event_server.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_extension.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_message.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_notifier.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_options.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_params.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_params.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_publish.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_register.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_registrar.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_session.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_stack.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_stack.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_subnotref.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_tag_ref.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\outbound.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\outbound.h"
+# End Source File
+# End Group
+# Begin Group "nta"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\nta.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\nta_check.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\nta_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\nta_tag_ref.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\sl_read_payload.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\sl_utils_log.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\sl_utils_print.c"
+# End Source File
+# End Group
+# Begin Group "tport"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\tport.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\tport_internal.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\tport_logging.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\tport_stub_sigcomp.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\tport_stub_stun.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\tport_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\tport_tag_ref.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\tport_type_connect.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\tport_type_tcp.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\tport_type_udp.c"
+# End Source File
+# End Group
+# Begin Group "sdp"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sdp\sdp.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sdp\sdp_parse.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sdp\sdp_print.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sdp\sdp_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sdp\sdp_tag_ref.c"
+# End Source File
+# End Group
+# Begin Group "soa"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\soa\soa.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\soa\sofia-sip\soa_session.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\soa\soa_static.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\soa\soa_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\soa\soa_tag_ref.c"
+# End Source File
+# End Group
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Group "su headers"
+
+# PROP Default_Filter "su*.h"
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\htable.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\htable2.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\rbtree.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_addrinfo.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_alloc.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_alloc_stat.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_bm.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_config.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_debug.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_errno.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_localinfo.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_log.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_md5.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_module_debug.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_os_nw.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_port.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_source.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_strlst.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_tag.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_tag_class.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_tag_inline.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_tag_io.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_tagarg.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_time.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_types.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_uniqueid.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_vector.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_wait.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\tstdef.h"
+# End Source File
+# End Group
+# Begin Group "win32 headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\config.h
+# End Source File
+# Begin Source File
+
+SOURCE="..\sofia-sip\su_configure.h"
+# End Source File
+# Begin Source File
+
+SOURCE=..\unistd.h
+# End Source File
+# End Group
+# Begin Group "ipt headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\ipt\sofia-sip\base64.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\ipt\sofia-sip\rc4.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\ipt\sofia-sip\string0.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\ipt\sofia-sip\token64.h"
+# End Source File
+# End Group
+# Begin Group "url headers"
+
+# PROP Default_Filter "url*.h"
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\url\sofia-sip\url.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\url\sofia-sip\url_tag.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\url\sofia-sip\url_tag_class.h"
+# End Source File
+# End Group
+# Begin Group "features headers"
+
+# PROP Default_Filter "features*.h"
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\features\sofia-sip\sofia_features.h"
+# End Source File
+# End Group
+# Begin Group "bnf headers"
+
+# PROP Default_Filter "bnf*.h"
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\bnf\sofia-sip\bnf.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\bnf\sofia-sip\hostdomain.h"
+# End Source File
+# End Group
+# Begin Group "msg headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_addr.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_bnf.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_buffer.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_date.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_header.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_internal.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_mclass.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_mclass_hash.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_mime.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_mime_protos.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_parser.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_protos.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_tag_class.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_types.h"
+# End Source File
+# End Group
+# Begin Group "sip headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sofia-sip\sip.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_extensions.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sofia-sip\sip_hclasses.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sofia-sip\sip_header.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_internal.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sofia-sip\sip_parser.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sofia-sip\sip_protos.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sofia-sip\sip_status.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sofia-sip\sip_tag.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sofia-sip\sip_tag_class.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sofia-sip\sip_util.h"
+# End Source File
+# End Group
+# Begin Group "http headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\sofia-sip\http.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\sofia-sip\http_hclasses.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\sofia-sip\http_header.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\sofia-sip\http_parser.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\sofia-sip\http_protos.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\sofia-sip\http_status.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\sofia-sip\http_tag.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\sofia-sip\http_tag_class.h"
+# End Source File
+# End Group
+# Begin Group "nth headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nth\sofia-sip\nth.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nth\sofia-sip\nth_tag.h"
+# End Source File
+# End Group
+# Begin Group "sresolv headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sresolv\sofia-resolv\sres.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sresolv\sofia-resolv\sres_async.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sresolv\sofia-resolv\sres_cache.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sresolv\sofia-resolv\sres_config.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sresolv\sofia-resolv\sres_record.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sresolv\sofia-sip\sresolv.h"
+# End Source File
+# End Group
+# Begin Group "nea headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nea\sofia-sip\nea.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nea\nea_debug.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nea\sofia-sip\nea_tag.h"
+# End Source File
+# End Group
+# Begin Group "iptsec headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\sofia-sip\auth_client.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\sofia-sip\auth_client_plugin.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\sofia-sip\auth_common.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\sofia-sip\auth_digest.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\sofia-sip\auth_module.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\sofia-sip\auth_ntlm.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\sofia-sip\auth_plugin.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\iptsec_debug.h"
+# End Source File
+# End Group
+# Begin Group "stun headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\stun\sofia-sip\stun.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\stun\sofia-sip\stun_common.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\stun\sofia-sip\stun_tag.h"
+# End Source File
+# End Group
+# Begin Group "nua headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\sofia-sip\nua.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\sofia-sip\nua_tag.h"
+# End Source File
+# End Group
+# Begin Group "nta headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\sofia-sip\nta.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\nta_internal.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\sofia-sip\nta_stateless.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\sofia-sip\nta_tag.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\sofia-sip\nta_tport.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\sofia-sip\sl_utils.h"
+# End Source File
+# End Group
+# Begin Group "tport headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\sofia-sip\tport.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\sofia-sip\tport_plugins.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\sofia-sip\tport_tag.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\tport_tls.h"
+# End Source File
+# End Group
+# Begin Group "sdp headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sdp\sofia-sip\sdp.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sdp\sofia-sip\sdp_tag.h"
+# End Source File
+# End Group
+# Begin Group "soa headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\soa\sofia-sip\soa.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\soa\sofia-sip\soa_add.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\soa\sofia-sip\soa_tag.h"
+# End Source File
+# End Group
+# End Group
+# End Target
+# End Project
Added: freeswitch/trunk/libs/sofia-sip/win32/libsofia-sip-ua/libsofia_sip_ua.dsp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/libsofia-sip-ua/libsofia_sip_ua.dsp Thu Dec 21 01:30:28 2006
@@ -0,0 +1,1389 @@
+# Microsoft Developer Studio Project File - Name="libsofia_sip_ua" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=libsofia_sip_ua - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "libsofia_sip_ua.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "libsofia_sip_ua.mak" CFG="libsofia_sip_ua - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "libsofia_sip_ua - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "libsofia_sip_ua - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "libsofia_sip_ua - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "HAVE_CONFIG_H" /D "_USRDLL" /D "LIBSOFIA_SIP_UA_EXPORTS" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /WX /GX /O2 /I ".." /I "..\..\libsofia-sip-ua\su" /I "..\..\libsofia-sip-ua\ipt" /I "..\..\libsofia-sip-ua\sresolv" /I "..\..\libsofia-sip-ua\bnf" /I "..\..\libsofia-sip-ua\url" /I "..\..\libsofia-sip-ua\msg" /I "..\..\libsofia-sip-ua\sip" /I "..\..\libsofia-sip-ua\nta" /I "..\..\libsofia-sip-ua\nua" /I "..\..\libsofia-sip-ua\iptsec" /I "..\..\libsofia-sip-ua\http" /I "..\..\libsofia-sip-ua\nth" /I "..\..\libsofia-sip-ua\nea" /I "..\..\libsofia-sip-ua\sdp" /I "..\..\libsofia-sip-ua\soa" /I "..\..\libsofia-sip-ua\stun" /I "..\..\libsofia-sip-ua\tport" /I "..\..\libsofia-sip-ua\features" /I "..\pthread" /I "." /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBSOFIA_SIP_UA_EXPORTS" /D IN_LIBSOFIA_SIP_UA=1 /D IN_LIBSOFIA_SRES=1 /FR /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x40b /d "NDEBUG"
+# ADD RSC /l 0x40b /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib advapi32.lib /nologo /dll /machine:I386
+
+!ELSEIF "$(CFG)" == "libsofia_sip_ua - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "HAVE_CONFIG_H" /D "_USRDLL" /D "LIBSOFIA_SIP_UA_EXPORTS" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /WX /Gm /GX /ZI /Od /I ".." /I "..\..\libsofia-sip-ua\su" /I "..\..\libsofia-sip-ua\ipt" /I "..\..\libsofia-sip-ua\sresolv" /I "..\..\libsofia-sip-ua\bnf" /I "..\..\libsofia-sip-ua\url" /I "..\..\libsofia-sip-ua\msg" /I "..\..\libsofia-sip-ua\sip" /I "..\..\libsofia-sip-ua\nta" /I "..\..\libsofia-sip-ua\nua" /I "..\..\libsofia-sip-ua\iptsec" /I "..\..\libsofia-sip-ua\http" /I "..\..\libsofia-sip-ua\nth" /I "..\..\libsofia-sip-ua\nea" /I "..\..\libsofia-sip-ua\sdp" /I "..\..\libsofia-sip-ua\soa" /I "..\..\libsofia-sip-ua\stun" /I "..\..\libsofia-sip-ua\tport" /I "..\..\libsofia-sip-ua\features" /I "..\pthread" /I "." /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBSOFIA_SIP_UA_EXPORTS" /D IN_LIBSOFIA_SIP_UA=1 /D IN_LIBSOFIA_SRES=1 /FR /FD /GZ /c
+# SUBTRACT CPP /YX
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x40b /d "_DEBUG"
+# ADD RSC /l 0x40b /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib advapi32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
+# Begin Special Build Tool
+SOURCE="$(InputPath)"
+PostBuild_Desc=Copy dll to win32 directory
+PostBuild_Cmds=copy Debug\libsofia_sip_ua.dll ..
+# End Special Build Tool
+
+!ENDIF
+
+# Begin Target
+
+# Name "libsofia_sip_ua - Win32 Release"
+# Name "libsofia_sip_ua - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Group "su"
+
+# PROP Default_Filter "su*.c"
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\inet_ntop.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\inet_pton.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_addrinfo.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_alloc.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_alloc_lock.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_bm.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_default_log.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_errno.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_global_log.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_localinfo.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_log.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_md5.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_os_nw.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_port.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_root.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_sprintf.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_strdup.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_strlst.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_tag_io.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_taglist.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_time.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_time0.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_timer.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_uniqueid.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_vector.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_wait.c"
+# End Source File
+# End Group
+# Begin Group "ipt"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\ipt\base64.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\ipt\rc4.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\ipt\string0.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\ipt\token64.c"
+# End Source File
+# End Group
+# Begin Group "url"
+
+# PROP Default_Filter "url*.c"
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\url\url.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\url\url_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\url\url_tag_ref.c"
+# End Source File
+# End Group
+# Begin Group "features"
+
+# PROP Default_Filter "features*.c"
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\features\features.c"
+# End Source File
+# End Group
+# Begin Group "bnf"
+
+# PROP Default_Filter "bnf*.c"
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\bnf\bnf.c"
+# End Source File
+# End Group
+# Begin Group "msg"
+
+# PROP Default_Filter "msg*.c"
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_auth.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_basic.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_date.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_generic.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_header_copy.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_header_make.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_mclass.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_mime.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_mime_table.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_parser.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_parser_util.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_tag.c"
+# End Source File
+# End Group
+# Begin Group "clib replacement"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\memcspn.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\memmem.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\memspn.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\strcasestr.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\strtoull.c"
+# End Source File
+# End Group
+# Begin Group "sip"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_basic.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_caller_prefs.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_event.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_extra.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_feature.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_header.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_mime.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_parser.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_parser_table.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_prack.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_pref_util.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_reason.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_refer.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_security.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_session.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_status.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_tag_class.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_tag_ref.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_time.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_util.c"
+# End Source File
+# End Group
+# Begin Group "http"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\http_basic.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\http_extra.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\http_header.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\http_parser.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\http_parser_table.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\http_status.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\http_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\http_tag_class.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\http_tag_ref.c"
+# End Source File
+# End Group
+# Begin Group "nth"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nth\nth_client.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nth\nth_server.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nth\nth_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nth\nth_tag_ref.c"
+# End Source File
+# End Group
+# Begin Group "sresolv"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sresolv\sres.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sresolv\sres_blocking.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sresolv\sres_cache.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sresolv\sresolv.c"
+# End Source File
+# End Group
+# Begin Group "nea"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nea\nea.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nea\nea_debug.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nea\nea_event.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nea\nea_server.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nea\nea_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nea\nea_tag_ref.c"
+# End Source File
+# End Group
+# Begin Group "iptsec"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\auth_client.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\auth_common.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\auth_digest.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\auth_module.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\auth_module_http.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\auth_module_sip.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\auth_plugin.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\auth_plugin_delayed.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\auth_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\auth_tag_ref.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\iptsec_debug.c"
+# End Source File
+# End Group
+# Begin Group "stun"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\stun\stun.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\stun\stun_common.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\stun\stun_dns.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\stun\stun_internal.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\stun\stun_mini.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\stun\stun_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\stun\stun_tag_ref.c"
+# End Source File
+# End Group
+# Begin Group "nua"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_common.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_dialog.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_dialog.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_event_server.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_extension.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_message.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_notifier.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_options.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_params.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_params.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_publish.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_register.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_registrar.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_session.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_stack.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_stack.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_subnotref.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\nua_tag_ref.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\outbound.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\outbound.h"
+# End Source File
+# End Group
+# Begin Group "nta"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\nta.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\nta_check.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\nta_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\nta_tag_ref.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\sl_read_payload.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\sl_utils_log.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\sl_utils_print.c"
+# End Source File
+# End Group
+# Begin Group "tport"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\tport.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\tport_internal.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\tport_logging.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\tport_stub_sigcomp.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\tport_stub_stun.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\tport_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\tport_tag_ref.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\tport_type_connect.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\tport_type_tcp.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\tport_type_udp.c"
+# End Source File
+# End Group
+# Begin Group "sdp"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sdp\sdp.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sdp\sdp_parse.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sdp\sdp_print.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sdp\sdp_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sdp\sdp_tag_ref.c"
+# End Source File
+# End Group
+# Begin Group "soa"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\soa\soa.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\soa\sofia-sip\soa_session.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\soa\soa_static.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\soa\soa_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\soa\soa_tag_ref.c"
+# End Source File
+# End Group
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Group "su headers"
+
+# PROP Default_Filter "su*.h"
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\htable.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\htable2.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\rbtree.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_addrinfo.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_alloc.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_alloc_stat.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_bm.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_config.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_debug.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_errno.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_localinfo.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_log.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_md5.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_module_debug.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_os_nw.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\su_port.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_source.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_strlst.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_tag.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_tag_class.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_tag_inline.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_tag_io.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_tagarg.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_time.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_types.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_uniqueid.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_vector.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\su_wait.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\su\sofia-sip\tstdef.h"
+# End Source File
+# End Group
+# Begin Group "win32 headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\config.h
+# End Source File
+# Begin Source File
+
+SOURCE="..\sofia-sip\su_configure.h"
+# End Source File
+# Begin Source File
+
+SOURCE=..\unistd.h
+# End Source File
+# End Group
+# Begin Group "ipt headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\ipt\sofia-sip\base64.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\ipt\sofia-sip\rc4.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\ipt\sofia-sip\string0.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\ipt\sofia-sip\token64.h"
+# End Source File
+# End Group
+# Begin Group "url headers"
+
+# PROP Default_Filter "url*.h"
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\url\sofia-sip\url.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\url\sofia-sip\url_tag.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\url\sofia-sip\url_tag_class.h"
+# End Source File
+# End Group
+# Begin Group "features headers"
+
+# PROP Default_Filter "features*.h"
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\features\sofia-sip\sofia_features.h"
+# End Source File
+# End Group
+# Begin Group "bnf headers"
+
+# PROP Default_Filter "bnf*.h"
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\bnf\sofia-sip\bnf.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\bnf\sofia-sip\hostdomain.h"
+# End Source File
+# End Group
+# Begin Group "msg headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_addr.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_bnf.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_buffer.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_date.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_header.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\msg_internal.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_mclass.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_mclass_hash.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_mime.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_mime_protos.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_parser.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_protos.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_tag_class.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\msg\sofia-sip\msg_types.h"
+# End Source File
+# End Group
+# Begin Group "sip headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sofia-sip\sip.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_extensions.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sofia-sip\sip_hclasses.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sofia-sip\sip_header.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sip_internal.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sofia-sip\sip_parser.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sofia-sip\sip_protos.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sofia-sip\sip_status.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sofia-sip\sip_tag.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sofia-sip\sip_tag_class.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sip\sofia-sip\sip_util.h"
+# End Source File
+# End Group
+# Begin Group "http headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\sofia-sip\http.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\sofia-sip\http_hclasses.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\sofia-sip\http_header.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\sofia-sip\http_parser.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\sofia-sip\http_protos.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\sofia-sip\http_status.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\sofia-sip\http_tag.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\http\sofia-sip\http_tag_class.h"
+# End Source File
+# End Group
+# Begin Group "nth headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nth\sofia-sip\nth.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nth\sofia-sip\nth_tag.h"
+# End Source File
+# End Group
+# Begin Group "sresolv headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sresolv\sofia-resolv\sres.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sresolv\sofia-resolv\sres_async.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sresolv\sofia-resolv\sres_cache.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sresolv\sofia-resolv\sres_config.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sresolv\sofia-resolv\sres_record.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sresolv\sofia-sip\sresolv.h"
+# End Source File
+# End Group
+# Begin Group "nea headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nea\sofia-sip\nea.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nea\nea_debug.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nea\sofia-sip\nea_tag.h"
+# End Source File
+# End Group
+# Begin Group "iptsec headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\sofia-sip\auth_client.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\sofia-sip\auth_client_plugin.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\sofia-sip\auth_common.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\sofia-sip\auth_digest.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\sofia-sip\auth_module.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\sofia-sip\auth_ntlm.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\sofia-sip\auth_plugin.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\iptsec\iptsec_debug.h"
+# End Source File
+# End Group
+# Begin Group "stun headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\stun\sofia-sip\stun.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\stun\sofia-sip\stun_common.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\stun\sofia-sip\stun_tag.h"
+# End Source File
+# End Group
+# Begin Group "nua headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\sofia-sip\nua.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nua\sofia-sip\nua_tag.h"
+# End Source File
+# End Group
+# Begin Group "nta headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\sofia-sip\nta.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\nta_internal.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\sofia-sip\nta_stateless.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\sofia-sip\nta_tag.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\sofia-sip\nta_tport.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\nta\sofia-sip\sl_utils.h"
+# End Source File
+# End Group
+# Begin Group "tport headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\sofia-sip\tport.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\sofia-sip\tport_plugins.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\sofia-sip\tport_tag.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\tport\tport_tls.h"
+# End Source File
+# End Group
+# Begin Group "sdp headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sdp\sofia-sip\sdp.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\sdp\sofia-sip\sdp_tag.h"
+# End Source File
+# End Group
+# Begin Group "soa headers"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\soa\sofia-sip\soa.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\soa\sofia-sip\soa_add.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\libsofia-sip-ua\soa\sofia-sip\soa_tag.h"
+# End Source File
+# End Group
+# End Group
+# Begin Source File
+
+SOURCE=..\pthread\pthreadVC2.lib
+# End Source File
+# End Target
+# End Project
Added: freeswitch/trunk/libs/sofia-sip/win32/libsofia-sip-ua/sofia-sip-ua.def
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/libsofia-sip-ua/sofia-sip-ua.def Thu Dec 21 01:30:28 2006
@@ -0,0 +1,573 @@
+LIBRARY "libsofia_sip_ua"
+DESCRIPTION 'Sofia-SIP-UA WIN32 DLL'
+EXPORTS
+auc_authorize
+auc_challenge
+auc_credentials
+auth_digest_challenge_get
+auth_digest_response
+auth_digest_response_get
+auth_digest_sessionkey
+auth_mod_challenge
+auth_mod_check
+auth_mod_check_ireq
+auth_mod_check_ireq2
+auth_mod_check_msg
+auth_mod_create
+auth_mod_destroy
+base64_d
+base64_e
+;inet_pton
+msg_addr
+msg_addr_copy
+msg_addr_zero
+msg_addrinfo
+msg_addrlen
+msg_auth_d
+msg_auth_dup_one
+msg_auth_dup_xtra
+msg_auth_e
+msg_buf_alloc
+msg_buf_commit
+msg_buf_committed
+msg_buf_move
+msg_buf_set
+msg_buf_size
+msg_clone
+msg_comment_d
+msg_copy_all
+msg_create
+msg_date_d
+msg_date_delta_d
+msg_date_e
+msg_default_dup_one
+msg_default_dup_xtra
+msg_delta_d
+msg_delta_e
+msg_destroy
+msg_dup
+msg_extract
+msg_extract_payload
+msg_extract_separator
+msg_find_hclass
+msg_firstline_d
+msg_generic_d
+msg_generic_dup_one
+msg_generic_dup_xtra
+msg_generic_e
+msg_hash_string
+msg_hclass_offset
+msg_header_add_dup
+msg_header_add_dup_as
+msg_header_add_str
+msg_header_alloc
+msg_header_alloc
+msg_header_alloc
+msg_header_copy
+msg_header_copy_as
+msg_header_d
+msg_header_dup
+msg_header_dup_as
+msg_header_e
+msg_header_insert
+msg_header_make
+msg_header_offset
+msg_header_remove
+msg_header_remove
+msg_header_vformat
+msg_hostport_d
+msg_iovec
+msg_list_d
+msg_list_dup_one
+msg_list_dup_one
+msg_list_dup_xtra
+msg_list_dup_xtra
+msg_list_e
+msg_list_e
+msg_mclass_clone
+msg_name_addr_d
+msg_name_addr_e
+msg_next
+msg_now
+msg_numeric_d
+msg_numeric_e
+msg_object
+msg_object_e
+msg_params_add
+msg_params_cmp
+msg_params_cmp
+msg_params_d
+msg_params_dup
+msg_params_e
+msg_params_find
+msg_params_find
+msg_params_find
+msg_params_find
+msg_params_replace
+msg_params_replace
+msg_payload_d
+msg_payload_dup_one
+msg_payload_dup_xtra
+msg_payload_e
+msg_prepare
+msg_public
+msg_quoted_d
+msg_recv_commit
+msg_recv_iovec
+msg_separator_d
+msg_separator_e
+msg_serialize
+msg_set_flags
+msg_token_d
+msg_unquote_dup
+msghdrtag_dup
+msghdrtag_snprintf
+msghdrtag_xtra
+msgobjtag_dup
+msgobjtag_snprintf
+msgobjtag_xtra
+nea_create
+nea_destroy
+nea_server_create
+nea_server_destroy
+nea_server_notify
+nea_server_update
+nta_agent_add_tport
+nta_agent_contact
+nta_agent_create
+nta_agent_destroy
+nta_agent_get_params
+nta_agent_get_stats
+nta_agent_magic
+nta_agent_newtag
+nta_agent_set_params
+nta_agent_version
+nta_agent_via
+nta_compartment_decref
+nta_incoming_bind
+nta_incoming_destroy
+nta_incoming_getrequest
+nta_incoming_getresponse
+nta_incoming_mreply
+nta_incoming_tag
+nta_incoming_treply
+nta_is_internal_msg
+nta_leg_bind
+nta_leg_by_dialog
+nta_leg_by_uri
+nta_leg_client_route
+nta_leg_destroy
+nta_leg_get_tag
+nta_leg_magic
+nta_leg_rtag
+nta_leg_server_route
+nta_leg_stateful
+nta_leg_tag
+nta_leg_tcreate
+nta_msg_ackbye
+nta_msg_complete
+nta_msg_create
+nta_msg_discard
+nta_msg_request_complete
+nta_msg_response_complete
+nta_msg_send
+nta_msg_treply
+nta_msg_tsend
+nta_outgoing_cancel
+nta_outgoing_compartment
+nta_outgoing_cseq
+nta_outgoing_delay
+nta_outgoing_destroy
+nta_outgoing_getrequest
+nta_outgoing_getrequest_ref
+nta_outgoing_getresponse
+nta_outgoing_getresponse_ref
+nta_outgoing_mcreate
+nta_outgoing_method
+nta_outgoing_method_name
+nta_outgoing_prack
+nta_outgoing_request_uri
+nta_outgoing_route_uri
+nta_outgoing_status
+nta_outgoing_tagged
+nta_outgoing_tcancel
+nta_outgoing_tcreate
+nta_outgoing_tmcreate
+nta_reliable_treply
+nua_authenticate
+nua_bye
+nua_cancel
+nua_create
+nua_destroy
+nua_get_params
+nua_handle
+nua_handle_bind
+nua_handle_destroy
+nua_invite
+nua_message
+nua_notify
+nua_options
+nua_redirect
+nua_refer
+nua_register
+nua_respond
+nua_set_params
+nua_shutdown
+nua_subscribe
+nua_unregister
+nua_unsubscribe
+nua_unsubscribe
+nutag_address
+nutag_allow
+nutag_auth
+nutag_authtime
+nutag_autoAlert
+nutag_autoAnswer
+nutag_enableInvite
+nutag_enableMessage
+nutag_event
+nutag_handle
+nutag_hold
+nutag_invite_timer
+nutag_notify_refer
+nutag_phrase
+nutag_registrar
+nutag_session_timer
+nutag_sip_parser
+nutag_status
+nutag_url
+nutag_use_dialog
+sdp_attribute_by_mode
+sdp_attribute_dup
+sdp_attribute_find
+sdp_attribute_find2
+sdp_attribute_mapped_find
+sdp_attribute_mode
+sdp_bandwidth_dup
+sdp_connection_dup
+sdp_key_dup
+sdp_list_dup
+sdp_media_dup
+sdp_message
+sdp_message
+sdp_message_size
+sdp_message_size
+sdp_origin_dup
+sdp_parse
+sdp_parser_free
+sdp_parsing_error
+sdp_print
+sdp_print
+sdp_printer_free
+sdp_printer_free
+sdp_printing_error
+sdp_repeat_dup
+sdp_repeat_dup
+sdp_rtpmap_dup
+sdp_session
+sdp_session_dup
+sdp_time_dup
+sdp_zone_dup
+sip_add_dup
+sip_add_headers
+sip_add_make
+sip_add_tl
+sip_allow_events_add
+sip_call_id_create
+sip_complete_message
+sip_complete_response
+sip_contact_add_param
+sip_contact_expires
+sip_content_length_create
+sip_copy_all
+sip_cseq_create
+sip_default_mclass
+sip_expires_create
+sip_from_create
+sip_from_tag
+sip_has_feature
+sip_header_as_string
+sip_header_d
+sip_header_dup
+sip_header_e
+sip_header_field_d
+sip_header_field_e
+sip_header_format
+sip_header_size
+sip_method_name
+sip_now
+sip_params_add
+sip_params_cmp
+sip_params_find
+sip_params_replace
+sip_payload_create
+sip_record_route_create
+sip_request_create
+sip_route_create
+sip_route_follow
+sip_route_remove
+sip_sanity_check
+sip_separator_create
+sip_serialize
+sip_status_create
+sip_status_phrase
+sip_to_add_param
+sip_to_create
+sip_to_tag
+sip_version_d
+sip_via_add_param
+sip_via_create
+sip_via_remove
+siptag_sip
+sl_allow_print
+sl_contact_print
+sl_contact_print
+sl_from_print
+sl_from_print
+sl_message_log
+sl_message_log
+sl_payload_print
+sl_to_print
+sl_to_print
+soa_activate
+soa_clone
+soa_create
+soa_deactivate
+soa_destroy
+soa_error_as_sip_reason
+soa_error_as_sip_response
+soa_generate_answer
+soa_generate_offer
+soa_get_capability_sdp
+soa_get_local_sdp
+soa_get_paramlist
+soa_get_params
+soa_get_remote_sdp
+soa_get_user_sdp
+soa_init_offer_answer
+soa_is_audio_active
+soa_is_chat_active
+soa_is_complete
+soa_is_image_active
+soa_is_remote_audio_active
+soa_is_remote_chat_active
+soa_is_remote_image_active
+soa_is_remote_video_active
+soa_is_video_active
+soa_media_features
+soa_process_answer
+soa_process_reject
+soa_remote_sip_features
+soa_set_capability_sdp
+soa_set_params
+soa_set_remote_sdp
+soa_set_user_sdp
+soa_sip_require
+soa_sip_supported
+soa_terminate
+soatag_active_audio
+soatag_active_audio_ref
+soatag_active_chat
+soatag_active_chat_ref
+soatag_active_image
+soatag_active_image_ref
+soatag_active_video
+soatag_active_video_ref
+soatag_address
+soatag_address_ref
+soatag_af
+soatag_af_ref
+soatag_caps_sdp
+soatag_caps_sdp_ref
+soatag_caps_sdp_str
+soatag_caps_sdp_str_ref
+soatag_hold
+soatag_hold_ref
+soatag_local_sdp
+soatag_local_sdp_ref
+soatag_local_sdp_str
+soatag_local_sdp_str_ref
+soatag_remote_sdp
+soatag_remote_sdp_ref
+soatag_remote_sdp_str
+soatag_remote_sdp_str_ref
+soatag_srtp_confidentiality
+soatag_srtp_confidentiality_ref
+soatag_srtp_enable
+soatag_srtp_enable_ref
+soatag_srtp_integrity
+soatag_srtp_integrity_ref
+soatag_user_sdp
+soatag_user_sdp_ref
+soatag_user_sdp_str
+soatag_user_sdp_str_ref
+srestag_resolv_conf
+strncspn
+strnspn
+su_alloc
+su_clone_forget
+su_clone_start
+su_clone_stop
+su_clone_task
+su_clone_wait
+su_close
+su_cmp_sockaddr
+su_counter
+su_deinit
+su_duration
+su_errno
+su_free
+su_freeaddrinfo
+su_freelocalinfo
+su_gai_strerror
+su_getaddrinfo
+su_getlocalinfo
+su_getlocalip
+su_getmsgsize
+su_gli_strerror
+su_guid_generate
+su_guid_sprintf
+su_home_check
+su_home_clone
+su_home_create
+su_home_deinit
+su_home_destroy
+su_home_init
+su_home_threadsafe
+su_init
+su_ioctl
+su_llog
+su_log
+su_log_default
+su_log_global
+su_log_init
+su_log_redirect
+su_log_set_level
+su_log_soft_set_level
+su_match_sockaddr
+su_md5_digest
+su_md5_init
+su_md5_iupdate
+su_md5_str0update
+su_md5_stri0update
+su_md5_striupdate
+su_md5_strupdate
+su_md5_update
+su_msg_create
+su_msg_data
+su_msg_destroy
+su_msg_from
+su_msg_reply
+su_msg_send
+su_msg_to
+su_now
+su_ntp_hi
+su_ntp_lo
+su_ntp_mw
+su_ntp_now
+su_ntp_sec
+su_perror
+su_perror2
+su_randint
+su_random
+su_realloc
+su_root_break
+su_root_create
+su_root_deregister
+su_root_destroy
+su_root_eventmask
+su_root_magic
+su_root_parent
+su_root_register
+su_root_run
+su_root_set_magic
+su_root_sleep
+su_root_step
+su_root_task
+su_root_threading
+su_root_unregister
+su_salloc
+su_setblocking
+su_seterrno
+su_setreuseaddr
+su_socket
+su_soerror
+su_sprintf
+su_strdup
+su_strerror
+su_strndup
+su_task_cmp
+su_task_copy
+su_task_deinit
+su_task_init
+su_task_is_running
+su_task_move
+su_task_null
+su_task_root
+su_time
+su_time_cmp
+su_time_diff
+su_time_print
+su_timer_create
+su_timer_destroy
+su_timer_reset
+su_timer_root
+su_timer_run
+su_timer_set
+su_timer_set_at
+su_vllog
+su_vsend
+su_wait
+su_wait_create
+su_wait_destroy
+su_wait_events
+su_wait_init
+su_wait_mask
+su_zalloc
+t_bool_snprintf
+t_int_snprintf
+t_ptr_snprintf
+t_str_dup
+t_str_snprintf
+t_str_xtra
+tag_any
+tag_next
+tag_null
+tag_skip
+tl_adup
+tl_afilter
+tl_dup
+tl_filter
+tl_find
+tl_gets
+tl_len
+tl_list
+tl_move
+tl_next
+tl_print
+tl_tfilter
+tl_tgets
+tl_tlist
+tl_tmove
+tl_tremove
+tl_vfree
+tl_vlen
+tl_vlist
+tl_vlist2
+tl_xtra
+token64_e
+tport_bind
+tport_by_name
+tport_create
+tport_destroy
+tport_hostport
+tport_is_reliable
+tport_magic
+tport_name
+tport_name_by_url
+tport_name_dup
+tport_next
+tport_send
+tport_set_magic
+tport_tbind
+tport_tsend
Added: freeswitch/trunk/libs/sofia-sip/win32/sofia-sip/su_configure.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/sofia-sip/su_configure.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,138 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@file su_configure_win32.h
+ *
+ * @b su library configuration for WIN32 (VC6/VC98)
+ *
+ * The file <su_configure_win32.h> contains configuration information needed
+ * by WIN32 programs using @b su library.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ *
+ * @date Created: Thu Jan 18 15:30:55 2001 ppessi
+ */
+
+#define WIN32_LEAN_AND_MEAN
+/* Remove this when building DLL */
+/* #define LIBSOFIA_SIP_UA_STATIC */
+
+#define SU_HAVE_WIN32 1
+#define SU_HAVE_WINSOCK 1
+#define SU_HAVE_WINSOCK2 1
+#define SU_HAVE_POLL 0
+#define SU_HAVE_BSDSOCK 0
+#define SU_HAVE_STDINT (0)
+#define SU_HAVE_NT 0
+#define SU_HAVE_IN6 1
+
+#define SU_HAVE_PTHREADS (1)
+
+/** Define as 1 if you have sa_len field in struct sockaddr */
+#undef SU_HAVE_SOCKADDR_SA_LEN
+
+/** Define as 1 if you have struct sockaddr_storage */
+#define SU_HAVE_SOCKADDR_STORAGE 1
+
+/* Define this as 1 if you have if_nameindex() */
+#undef SU_HAVE_IF_NAMEINDEX
+
+/* Define as 1 if you have struct getaddrinfo. */
+#define SU_HAVE_ADDRINFO 1
+
+#define SU_INLINE __inline
+#define su_inline static __inline
+#define SU_HAVE_INLINE (1)
+
+/** Define this as 1 if we can use tags directly from stack. */
+#define SU_HAVE_TAGSTACK (1)
+
+#define SU_S64_T __int64
+#define SU_U64_T unsigned __int64
+#define SU_S32_T __int32
+#define SU_U32_T unsigned __int32
+#define SU_S16_T __int16
+#define SU_U16_T unsigned __int16
+#define SU_S8_T __int8
+#define SU_U8_T unsigned __int8
+
+#define SU_LEAST64_T __int64
+#define SU_LEAST32_T __int32
+#define SU_LEAST16_T __int16
+#define SU_LEAST8_T __int8
+
+#define SU_S64_C(i) (SU_S64_T)(i ## L)
+#define SU_U64_C(i) (SU_U64_T)(i ## UL)
+#define SU_S32_C(i) (SU_S32_T)(i ## L)
+#define SU_U32_C(i) (SU_U32_T)(i ## UL)
+#define SU_S16_C(i) (SU_S16_T)(i)
+#define SU_U16_C(i) (SU_U16_T)(i ## U)
+#define SU_S8_C(i) (SU_S8_T)(i)
+#define SU_U8_C(i) (SU_U8_T)(i ## U)
+
+#ifndef strcasecmp
+#define strcasecmp _stricmp
+#endif
+#ifndef strncasecmp
+#define strncasecmp _strnicmp
+#endif
+#ifndef snprintf
+#define snprintf _snprintf
+#endif
+#ifndef vsnprintf
+#define vsnprintf _vsnprintf
+#endif
+
+#define srandom(x) srand((x))
+#define random() rand()
+
+#include <basetsd.h>
+
+#define SOFIA_ISIZE_T size_t
+#define SOFIA_USIZE_T size_t
+
+#ifdef _WIN64
+#define SOFIA_SSIZE_T __in64
+#define SOFIA_ISSIZE_T __int64
+#define SU_INTPTR_T __int64
+#elif _MSC_VER >= 1400
+#define SOFIA_SSIZE_T __int32 __w64
+#define SOFIA_ISSIZE_T __int32 __w64
+#define SU_INTPTR_T __int32 __w64
+#else
+#define SOFIA_SSIZE_T __int32
+#define SOFIA_ISSIZE_T __int32
+#define SU_INTPTR_T __int32
+#endif
+
+#ifndef SIZE_MAX
+#define SIZE_MAX MAXINT_PTR
+#endif
+#ifndef SSIZE_MAX
+#define SSIZE_MAX MAXUINT_PTR
+#endif
+
+#define ISIZE_MAX SIZE_MAX
+#define ISSIZE_MAX SSIZE_MAX
+#define USIZE_MAX SIZE_MAX
Added: freeswitch/trunk/libs/sofia-sip/win32/tests/test_htable/test_htable.dsp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/tests/test_htable/test_htable.dsp Thu Dec 21 01:30:28 2006
@@ -0,0 +1,95 @@
+# Microsoft Developer Studio Project File - Name="test_htable" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=test_htable - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "test_htable.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "test_htable.mak" CFG="test_htable - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "test_htable - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "test_htable - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "test_htable - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /WX /GX /O2 /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /c
+# ADD BASE RSC /l 0x40b /d "NDEBUG"
+# ADD RSC /l 0x40b /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF "$(CFG)" == "test_htable - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /WX /Gm /GX /ZI /Od /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /FD /GZ /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x40b /d "_DEBUG"
+# ADD RSC /l 0x40b /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "test_htable - Win32 Release"
+# Name "test_htable - Win32 Debug"
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\su\test_htable.c"
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\pthread\pthreadVC2.lib
+# End Source File
+# End Target
+# End Project
Added: freeswitch/trunk/libs/sofia-sip/win32/tests/test_memmem/test_memmem.dsp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/tests/test_memmem/test_memmem.dsp Thu Dec 21 01:30:28 2006
@@ -0,0 +1,95 @@
+# Microsoft Developer Studio Project File - Name="test_memmem" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=test_memmem - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "test_memmem.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "test_memmem.mak" CFG="test_memmem - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "test_memmem - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "test_memmem - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "test_memmem - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /WX /GX /O2 /I ".." /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /I "..\..\libsofia-sip-ua\ipt" /I "..\..\libsofia-sip-ua\sresolv" /I "..\..\libsofia-sip-ua\bnf" /I "..\..\libsofia-sip-ua\url" /I "..\..\libsofia-sip-ua\msg" /I "..\..\libsofia-sip-ua\sip" /I "..\..\libsofia-sip-ua\nta" /I "..\..\libsofia-sip-ua\nua" /I "..\..\libsofia-sip-ua\iptsec" /I "..\..\libsofia-sip-ua\http" /I "..\..\libsofia-sip-ua\nth" /I "..\..\libsofia-sip-ua\nea" /I "..\..\libsofia-sip-ua\sdp" /I "..\..\libsofia-sip-ua\soa" /I "..\..\libsofia-sip-ua\stun" /I "..\..\libsofia-sip-ua\tport" /I "..\pthread" /I "." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /c
+# ADD BASE RSC /l 0x40b /d "NDEBUG"
+# ADD RSC /l 0x40b /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF "$(CFG)" == "test_memmem - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /WX /Gm /GX /ZI /Od /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /I "..\..\pthread" /I "." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /FD /GZ /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x40b /d "_DEBUG"
+# ADD RSC /l 0x40b /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "test_memmem - Win32 Release"
+# Name "test_memmem - Win32 Debug"
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\su\test_memmem.c"
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\pthread\pthreadVC2.lib
+# End Source File
+# End Target
+# End Project
Added: freeswitch/trunk/libs/sofia-sip/win32/tests/test_nta/test_nta.dsp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/tests/test_nta/test_nta.dsp Thu Dec 21 01:30:28 2006
@@ -0,0 +1,94 @@
+# Microsoft Developer Studio Project File - Name="test_nta" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=test_nta - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "test_nta.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "test_nta.mak" CFG="test_nta - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "test_nta - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "test_nta - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "test_nta - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /WX /GX /O2 /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /I "..\..\..\libsofia-sip-ua\ipt" /I "..\..\..\libsofia-sip-ua\sresolv" /I "..\..\..\libsofia-sip-ua\bnf" /I "..\..\..\libsofia-sip-ua\url" /I "..\..\..\libsofia-sip-ua\msg" /I "..\..\..\libsofia-sip-ua\sip" /I "..\..\..\libsofia-sip-ua\nta" /I "..\..\..\libsofia-sip-ua\nua" /I "..\..\..\libsofia-sip-ua\iptsec" /I "..\..\..\libsofia-sip-ua\http" /I "..\..\..\libsofia-sip-ua\nth" /I "..\..\..\libsofia-sip-ua\nea" /I "..\..\..\libsofia-sip-ua\sdp" /I "..\..\..\libsofia-sip-ua\soa" /I "..\..\..\libsofia-sip-ua\stun" /I "..\..\..\libsofia-sip-ua\tport" /I "..\..\..\libsofia-sip-ua\features" /I "include" /I "." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib advapi32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF "$(CFG)" == "test_nta - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /WX /Gm /GX /ZI /Od /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /I "..\..\..\libsofia-sip-ua\ipt" /I "..\..\..\libsofia-sip-ua\sresolv" /I "..\..\..\libsofia-sip-ua\bnf" /I "..\..\..\libsofia-sip-ua\url" /I "..\..\..\libsofia-sip-ua\msg" /I "..\..\..\libsofia-sip-ua\sip" /I "..\..\..\libsofia-sip-ua\nta" /I "..\..\..\libsofia-sip-ua\nua" /I "..\..\..\libsofia-sip-ua\iptsec" /I "..\..\..\libsofia-sip-ua\http" /I "..\..\..\libsofia-sip-ua\nth" /I "..\..\..\libsofia-sip-ua\nea" /I "..\..\..\libsofia-sip-ua\sdp" /I "..\..\..\libsofia-sip-ua\soa" /I "..\..\..\libsofia-sip-ua\stun" /I "..\..\..\libsofia-sip-ua\tport" /I "..\..\..\libsofia-sip-ua\features" /I "include" /I "." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib advapi32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "test_nta - Win32 Release"
+# Name "test_nta - Win32 Debug"
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\nta\test_nta.c"
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\pthread\pthreadVC2.lib
+# End Source File
+# End Target
+# End Project
Added: freeswitch/trunk/libs/sofia-sip/win32/tests/test_nua/test_nat_tags.cpp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/tests/test_nua/test_nat_tags.cpp Thu Dec 21 01:30:28 2006
@@ -0,0 +1 @@
+#include "test_nat_tags.c"
Added: freeswitch/trunk/libs/sofia-sip/win32/tests/test_nua/test_nua.dsp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/tests/test_nua/test_nua.dsp Thu Dec 21 01:30:28 2006
@@ -0,0 +1,183 @@
+# Microsoft Developer Studio Project File - Name="test_nua" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=test_nua - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "test_nua.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "test_nua.mak" CFG="test_nua - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "test_nua - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "test_nua - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "test_nua - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /WX /GX /O2 /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /I "..\..\..\libsofia-sip-ua\ipt" /I "..\..\..\libsofia-sip-ua\sresolv" /I "..\..\..\libsofia-sip-ua\bnf" /I "..\..\..\libsofia-sip-ua\url" /I "..\..\..\libsofia-sip-ua\msg" /I "..\..\..\libsofia-sip-ua\sip" /I "..\..\..\libsofia-sip-ua\nta" /I "..\..\..\libsofia-sip-ua\nua" /I "..\..\..\libsofia-sip-ua\iptsec" /I "..\..\..\libsofia-sip-ua\http" /I "..\..\..\libsofia-sip-ua\nth" /I "..\..\..\libsofia-sip-ua\nea" /I "..\..\..\libsofia-sip-ua\sdp" /I "..\..\..\libsofia-sip-ua\soa" /I "..\..\..\libsofia-sip-ua\stun" /I "..\..\..\libsofia-sip-ua\tport" /I "include" /I "." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib advapi32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF "$(CFG)" == "test_nua - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /WX /Gm /GX /ZI /Od /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /I "..\..\..\libsofia-sip-ua\ipt" /I "..\..\..\libsofia-sip-ua\sresolv" /I "..\..\..\libsofia-sip-ua\bnf" /I "..\..\..\libsofia-sip-ua\url" /I "..\..\..\libsofia-sip-ua\msg" /I "..\..\..\libsofia-sip-ua\sip" /I "..\..\..\libsofia-sip-ua\nta" /I "..\..\..\libsofia-sip-ua\nua" /I "..\..\..\libsofia-sip-ua\iptsec" /I "..\..\..\libsofia-sip-ua\http" /I "..\..\..\libsofia-sip-ua\nth" /I "..\..\..\libsofia-sip-ua\nea" /I "..\..\..\libsofia-sip-ua\sdp" /I "..\..\..\libsofia-sip-ua\soa" /I "..\..\..\libsofia-sip-ua\stun" /I "..\..\..\libsofia-sip-ua\tport" /I "include" /I "." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /FD /GZ /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib advapi32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "test_nua - Win32 Release"
+# Name "test_nua - Win32 Debug"
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\su\memmem.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\nua\test_100rel.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\nua\test_basic_call.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\nua\test_call_hold.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\nua\test_call_reject.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\nua\test_cancel_bye.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\nua\test_extension.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\nua\test_init.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\nua\test_nat.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\nua\test_nat.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\test_nat_tags.cpp
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\nua\test_nua.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\nua\test_nua.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\nua\test_nua_api.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\nua\test_nua_params.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\nua\test_ops.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\nua\test_proxy.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\nua\test_proxy.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\nua\test_refer.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\nua\test_register.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\nua\test_session_timer.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\nua\test_simple.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\nua\test_sip_events.c"
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\pthread\pthreadVC2.lib
+# End Source File
+# End Target
+# End Project
Added: freeswitch/trunk/libs/sofia-sip/win32/tests/test_su/test_su.dsp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/tests/test_su/test_su.dsp Thu Dec 21 01:30:28 2006
@@ -0,0 +1,95 @@
+# Microsoft Developer Studio Project File - Name="test_su" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=test_su - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "test_su.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "test_su.mak" CFG="test_su - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "test_su - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "test_su - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "test_su - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /WX /GX /O2 /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /c
+# ADD BASE RSC /l 0x40b /d "NDEBUG"
+# ADD RSC /l 0x40b /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF "$(CFG)" == "test_su - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /WX /Gm /GX /ZI /Od /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /FD /GZ /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x40b /d "_DEBUG"
+# ADD RSC /l 0x40b /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "test_su - Win32 Release"
+# Name "test_su - Win32 Debug"
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\su\test_su.c"
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\pthread\pthreadVC2.lib
+# End Source File
+# End Target
+# End Project
Added: freeswitch/trunk/libs/sofia-sip/win32/tests/test_tport/test_class.cpp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/tests/test_tport/test_class.cpp Thu Dec 21 01:30:28 2006
@@ -0,0 +1 @@
+#include "test_class.c"
Added: freeswitch/trunk/libs/sofia-sip/win32/tests/test_tport/test_table.cpp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/tests/test_tport/test_table.cpp Thu Dec 21 01:30:28 2006
@@ -0,0 +1 @@
+#include "test_table.c"
Added: freeswitch/trunk/libs/sofia-sip/win32/tests/test_tport/test_tport.dsp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/tests/test_tport/test_tport.dsp Thu Dec 21 01:30:28 2006
@@ -0,0 +1,110 @@
+# Microsoft Developer Studio Project File - Name="test_tport" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=test_tport - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "test_tport.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "test_tport.mak" CFG="test_tport - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "test_tport - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "test_tport - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "test_tport - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /WX /GX /O2 /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /I "..\..\..\libsofia-sip-ua\ipt" /I "..\..\..\libsofia-sip-ua\sresolv" /I "..\..\..\libsofia-sip-ua\bnf" /I "..\..\..\libsofia-sip-ua\url" /I "..\..\..\libsofia-sip-ua\msg" /I "..\..\..\libsofia-sip-ua\sip" /I "..\..\..\libsofia-sip-ua\nta" /I "..\..\..\libsofia-sip-ua\nua" /I "..\..\..\libsofia-sip-ua\iptsec" /I "..\..\..\libsofia-sip-ua\http" /I "..\..\..\libsofia-sip-ua\nth" /I "..\..\..\libsofia-sip-ua\nea" /I "..\..\..\libsofia-sip-ua\sdp" /I "..\..\..\libsofia-sip-ua\soa" /I "..\..\..\libsofia-sip-ua\stun" /I "..\..\..\libsofia-sip-ua\tport" /I "..\..\..\libsofia-sip-ua\features" /I "include" /I "." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD BASE RSC /l 0x40b /d "NDEBUG"
+# ADD RSC /l 0x40b /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib advapi32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF "$(CFG)" == "test_tport - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /WX /Gm /GX /ZI /Od /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /I "..\..\..\libsofia-sip-ua\ipt" /I "..\..\..\libsofia-sip-ua\sresolv" /I "..\..\..\libsofia-sip-ua\bnf" /I "..\..\..\libsofia-sip-ua\url" /I "..\..\..\libsofia-sip-ua\msg" /I "..\..\..\libsofia-sip-ua\sip" /I "..\..\..\libsofia-sip-ua\nta" /I "..\..\..\libsofia-sip-ua\nua" /I "..\..\..\libsofia-sip-ua\iptsec" /I "..\..\..\libsofia-sip-ua\http" /I "..\..\..\libsofia-sip-ua\nth" /I "..\..\..\libsofia-sip-ua\nea" /I "..\..\..\libsofia-sip-ua\sdp" /I "..\..\..\libsofia-sip-ua\soa" /I "..\..\..\libsofia-sip-ua\stun" /I "..\..\..\libsofia-sip-ua\tport" /I "..\..\..\libsofia-sip-ua\features" /I "include" /I "." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x40b /d "_DEBUG"
+# ADD RSC /l 0x40b /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib advapi32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "test_tport - Win32 Release"
+# Name "test_tport - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\test_class.cpp
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\msg\test_class.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\msg\test_protos.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\test_table.cpp
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\tport\test_tport.c"
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\pthread\pthreadVC2.lib
+# End Source File
+# End Target
+# End Project
Added: freeswitch/trunk/libs/sofia-sip/win32/tests/torture_rbtree/torture_rbtree.dsp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/tests/torture_rbtree/torture_rbtree.dsp Thu Dec 21 01:30:28 2006
@@ -0,0 +1,95 @@
+# Microsoft Developer Studio Project File - Name="torture_rbtree" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=torture_rbtree - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "torture_rbtree.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "torture_rbtree.mak" CFG="torture_rbtree - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "torture_rbtree - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "torture_rbtree - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "torture_rbtree - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /WX /GX /O2 /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /c
+# ADD BASE RSC /l 0x40b /d "NDEBUG"
+# ADD RSC /l 0x40b /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF "$(CFG)" == "torture_rbtree - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /WX /WX /Gm /GX /ZI /Od /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /FD /GZ /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x40b /d "_DEBUG"
+# ADD RSC /l 0x40b /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "torture_rbtree - Win32 Release"
+# Name "torture_rbtree - Win32 Debug"
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\su\torture_rbtree.c"
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\pthread\pthreadVC2.lib
+# End Source File
+# End Target
+# End Project
Added: freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su/torture_su.dsp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su/torture_su.dsp Thu Dec 21 01:30:28 2006
@@ -0,0 +1,95 @@
+# Microsoft Developer Studio Project File - Name="torture_su" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=torture_su - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "torture_su.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "torture_su.mak" CFG="torture_su - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "torture_su - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "torture_su - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "torture_su - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /WX /GX /O2 /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /c
+# ADD BASE RSC /l 0x40b /d "NDEBUG"
+# ADD RSC /l 0x40b /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF "$(CFG)" == "torture_su - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /WX /Gm /GX /ZI /Od /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /FD /GZ /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x40b /d "_DEBUG"
+# ADD RSC /l 0x40b /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "torture_su - Win32 Release"
+# Name "torture_su - Win32 Debug"
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\su\torture_su.c"
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\pthread\pthreadVC2.lib
+# End Source File
+# End Target
+# End Project
Added: freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_alloc/torture_su_alloc.dsp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_alloc/torture_su_alloc.dsp Thu Dec 21 01:30:28 2006
@@ -0,0 +1,95 @@
+# Microsoft Developer Studio Project File - Name="torture_su_alloc" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=torture_su_alloc - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "torture_su_alloc.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "torture_su_alloc.mak" CFG="torture_su_alloc - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "torture_su_alloc - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "torture_su_alloc - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "torture_su_alloc - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /WX /GX /O2 /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /c
+# ADD BASE RSC /l 0x40b /d "NDEBUG"
+# ADD RSC /l 0x40b /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF "$(CFG)" == "torture_su_alloc - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /WX /Gm /GX /ZI /Od /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /FD /GZ /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x40b /d "_DEBUG"
+# ADD RSC /l 0x40b /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "torture_su_alloc - Win32 Release"
+# Name "torture_su_alloc - Win32 Debug"
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\su\torture_su_alloc.c"
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\pthread\pthreadVC2.lib
+# End Source File
+# End Target
+# End Project
Added: freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_bm/torture_su_bm.dsp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_bm/torture_su_bm.dsp Thu Dec 21 01:30:28 2006
@@ -0,0 +1,95 @@
+# Microsoft Developer Studio Project File - Name="torture_su_bm" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=torture_su_bm - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "torture_su_bm.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "torture_su_bm.mak" CFG="torture_su_bm - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "torture_su_bm - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "torture_su_bm - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "torture_su_bm - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /WX /GX /O2 /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "LIBSOFIA_SIP_UA_STATIC" /FR /YX /FD /c
+# ADD BASE RSC /l 0x40b /d "NDEBUG"
+# ADD RSC /l 0x40b /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF "$(CFG)" == "torture_su_bm - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /WX /Gm /GX /ZI /Od /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "LIBSOFIA_SIP_UA_STATIC" /FR /FD /GZ /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x40b /d "_DEBUG"
+# ADD RSC /l 0x40b /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "torture_su_bm - Win32 Release"
+# Name "torture_su_bm - Win32 Debug"
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\su\torture_su_bm.c"
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\pthread\pthreadVC2.lib
+# End Source File
+# End Target
+# End Project
Added: freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_port/torture_su_port.dsp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_port/torture_su_port.dsp Thu Dec 21 01:30:28 2006
@@ -0,0 +1,95 @@
+# Microsoft Developer Studio Project File - Name="torture_su_port" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=torture_su_port - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "torture_su_port.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "torture_su_port.mak" CFG="torture_su_port - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "torture_su_port - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "torture_su_port - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "torture_su_port - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /WX /GX /O2 /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /I "..\..\pthread" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "LIBSOFIA_SIP_UA_STATIC" /FR /YX /FD /c
+# ADD BASE RSC /l 0x40b /d "NDEBUG"
+# ADD RSC /l 0x40b /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF "$(CFG)" == "torture_su_port - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /WX /Gm /GX /ZI /Od /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /I "..\..\pthread" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "LIBSOFIA_SIP_UA_STATIC" /FR /FD /GZ /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x40b /d "_DEBUG"
+# ADD RSC /l 0x40b /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "torture_su_port - Win32 Release"
+# Name "torture_su_port - Win32 Debug"
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\su\torture_su_port.c"
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\pthread\pthreadVC2.lib
+# End Source File
+# End Target
+# End Project
Added: freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_root/torture_su_root.dsp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_root/torture_su_root.dsp Thu Dec 21 01:30:28 2006
@@ -0,0 +1,95 @@
+# Microsoft Developer Studio Project File - Name="torture_su_root" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=torture_su_root - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "torture_su_root.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "torture_su_root.mak" CFG="torture_su_root - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "torture_su_root - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "torture_su_root - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "torture_su_root - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /WX /GX /O2 /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /c
+# ADD BASE RSC /l 0x40b /d "NDEBUG"
+# ADD RSC /l 0x40b /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF "$(CFG)" == "torture_su_root - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /WX /Gm /GX /ZI /Od /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /FD /GZ /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x40b /d "_DEBUG"
+# ADD RSC /l 0x40b /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "torture_su_root - Win32 Release"
+# Name "torture_su_root - Win32 Debug"
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\su\torture_su_root.c"
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\pthread\pthreadVC2.lib
+# End Source File
+# End Target
+# End Project
Added: freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_tag/torture_su_tag.dsp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_tag/torture_su_tag.dsp Thu Dec 21 01:30:28 2006
@@ -0,0 +1,95 @@
+# Microsoft Developer Studio Project File - Name="torture_su_tag" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=torture_su_tag - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "torture_su_tag.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "torture_su_tag.mak" CFG="torture_su_tag - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "torture_su_tag - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "torture_su_tag - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "torture_su_tag - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /WX /GX /O2 /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /c
+# ADD BASE RSC /l 0x40b /d "NDEBUG"
+# ADD RSC /l 0x40b /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF "$(CFG)" == "torture_su_tag - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /WX /Gm /GX /ZI /Od /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /FD /GZ /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x40b /d "_DEBUG"
+# ADD RSC /l 0x40b /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "torture_su_tag - Win32 Release"
+# Name "torture_su_tag - Win32 Debug"
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\su\torture_su_tag.c"
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\pthread\pthreadVC2.lib
+# End Source File
+# End Target
+# End Project
Added: freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_time/torture_su_time.dsp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_time/torture_su_time.dsp Thu Dec 21 01:30:28 2006
@@ -0,0 +1,95 @@
+# Microsoft Developer Studio Project File - Name="torture_su_time" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=torture_su_time - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "torture_su_time.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "torture_su_time.mak" CFG="torture_su_time - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "torture_su_time - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "torture_su_time - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "torture_su_time - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /WX /GX /O2 /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "LIBSOFIA_SIP_UA_STATIC" /FR /YX /FD /c
+# ADD BASE RSC /l 0x40b /d "NDEBUG"
+# ADD RSC /l 0x40b /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF "$(CFG)" == "torture_su_time - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /WX /Gm /GX /ZI /Od /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "LIBSOFIA_SIP_UA_STATIC" /FR /FD /GZ /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x40b /d "_DEBUG"
+# ADD RSC /l 0x40b /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "torture_su_time - Win32 Release"
+# Name "torture_su_time - Win32 Debug"
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\su\torture_su_time.c"
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\pthread\pthreadVC2.lib
+# End Source File
+# End Target
+# End Project
Added: freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_timer/torture_su_timer.dsp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/tests/torture_su_timer/torture_su_timer.dsp Thu Dec 21 01:30:28 2006
@@ -0,0 +1,95 @@
+# Microsoft Developer Studio Project File - Name="torture_su_timer" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=torture_su_timer - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "torture_su_timer.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "torture_su_timer.mak" CFG="torture_su_timer - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "torture_su_timer - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "torture_su_timer - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "torture_su_timer - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /WX /GX /O2 /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /c
+# ADD BASE RSC /l 0x40b /d "NDEBUG"
+# ADD RSC /l 0x40b /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF "$(CFG)" == "torture_su_timer - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /WX /Gm /GX /ZI /Od /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /FD /GZ /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x40b /d "_DEBUG"
+# ADD RSC /l 0x40b /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "torture_su_timer - Win32 Release"
+# Name "torture_su_timer - Win32 Debug"
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\su\torture_su_timer.c"
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\pthread\pthreadVC2.lib
+# End Source File
+# End Target
+# End Project
Added: freeswitch/trunk/libs/sofia-sip/win32/unistd.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/unistd.h Thu Dec 21 01:30:28 2006
@@ -0,0 +1,49 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/* Dummy unistd.h for win32 */
+
+#include <io.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#define write(fd, buf, len) _write((fd), (buf), (unsigned int)(len))
+#define read(fd, buf, len) _read((fd), (buf), (len))
+#define close(fd) _close((fd))
+#define mktemp(template) _mktemp((template))
+#define mkstemp(template) _open(_mktemp(template), _O_RDWR|_O_CREAT, 0600)
+#define unlink(name) _unlink((name))
+#define stat _stat
+
+#define O_RDONLY _O_RDONLY
+#define O_WRONLY _O_WRONLY
+#define O_RDWR _O_RDWR
+#define O_APPEND _O_APPEND
+#define O_CREAT _O_CREAT
+#define O_TRUNC _O_TRUNC
+#define O_EXCL _O_EXCL
+
+#include <process.h>
+
+#define getpid() _getpid()
Added: freeswitch/trunk/libs/sofia-sip/win32/utils/localinfo/localinfo.dsp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/utils/localinfo/localinfo.dsp Thu Dec 21 01:30:28 2006
@@ -0,0 +1,118 @@
+# Microsoft Developer Studio Project File - Name="localinfo" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=localinfo - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "localinfo.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "localinfo.mak" CFG="localinfo - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "localinfo - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "localinfo - Win32 Debug" (based on "Win32 (x86) Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "localinfo - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD CPP /nologo /W3 /WX /GX /O2 /I ".." /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /I "..\..\..\libsofia-sip-ua\tport" /I "..\..\..\libsofia-sip-ua\iptsec" /I "..\..\..\libsofia-sip-ua\ipt" /I "..\..\..\libsofia-sip-ua\url" /I "..\..\..\libsofia-sip-ua\nta" /I "..\..\..\libsofia-sip-ua\msg" /I "..\..\..\libsofia-sip-ua\sip" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib advapi32.lib /nologo /subsystem:console /machine:I386
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "localinfo - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /GZ /c
+# ADD CPP /nologo /W3 /WX /Gm /GX /ZI /Od /I ".." /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /I "..\..\..\libsofia-sip-ua\tport" /I "..\..\..\libsofia-sip-ua\iptsec" /I "..\..\..\libsofia-sip-ua\ipt" /I "..\..\..\libsofia-sip-ua\url" /I "..\..\..\libsofia-sip-ua\nta" /I "..\..\..\libsofia-sip-ua\msg" /I "..\..\..\libsofia-sip-ua\sip" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FD /GZ /c
+# SUBTRACT CPP /YX
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib advapi32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# SUBTRACT LINK32 /pdb:none
+
+!ENDIF
+
+# Begin Target
+
+# Name "localinfo - Win32 Release"
+# Name "localinfo - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\su\getopt.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\su\localinfo.c"
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# Begin Source File
+
+SOURCE=..\..\pthread\pthreadVC2.lib
+# End Source File
+# End Target
+# End Project
Added: freeswitch/trunk/libs/sofia-sip/win32/utils/sip_dig/sip_dig.dsp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/utils/sip_dig/sip_dig.dsp Thu Dec 21 01:30:28 2006
@@ -0,0 +1,114 @@
+# Microsoft Developer Studio Project File - Name="sip_dig" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=sip_dig - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "sip_dig.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "sip_dig.mak" CFG="sip_dig - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "sip_dig - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "sip_dig - Win32 Debug" (based on "Win32 (x86) Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "sip_dig - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /WX /GX /O2 /I ".." /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /I "..\..\..\libsofia-sip-ua\tport" /I "..\..\..\libsofia-sip-ua\bnf" /I "..\..\..\libsofia-sip-ua\sresolv" /I "..\..\..\libsofia-sip-ua\iptsec" /I "..\..\..\libsofia-sip-ua\ipt" /I "..\..\..\libsofia-sip-ua\url" /I "..\..\..\libsofia-sip-ua\nta" /I "..\..\..\libsofia-sip-ua\msg" /I "..\..\..\libsofia-sip-ua\sip" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib advapi32.lib /nologo /subsystem:console /machine:I386
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "sip_dig - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /WX /Gm /GX /ZI /Od /I ".." /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /I "..\..\..\libsofia-sip-ua\tport" /I "..\..\..\libsofia-sip-ua\iptsec" /I "..\..\..\libsofia-sip-ua\ipt" /I "..\..\..\libsofia-sip-ua\url" /I "..\..\..\libsofia-sip-ua\sresolv" /I "..\..\..\libsofia-sip-ua\bnf" /I "..\..\..\libsofia-sip-ua\nta" /I "..\..\..\libsofia-sip-ua\msg" /I "..\..\..\libsofia-sip-ua\sip" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FD /GZ /c
+# SUBTRACT CPP /YX
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib advapi32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# SUBTRACT LINK32 /pdb:none
+
+!ENDIF
+
+# Begin Target
+
+# Name "sip_dig - Win32 Release"
+# Name "sip_dig - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE="..\..\..\utils\sip-dig.c"
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# Begin Source File
+
+SOURCE=..\..\pthread\pthreadVC2.lib
+# End Source File
+# End Target
+# End Project
Added: freeswitch/trunk/libs/sofia-sip/win32/utils/sip_options/sip_options.dsp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/utils/sip_options/sip_options.dsp Thu Dec 21 01:30:28 2006
@@ -0,0 +1,114 @@
+# Microsoft Developer Studio Project File - Name="sip_options" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=sip_options - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "sip_options.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "sip_options.mak" CFG="sip_options - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "sip_options - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "sip_options - Win32 Debug" (based on "Win32 (x86) Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "sip_options - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /WX /GX /O2 /I ".." /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /I "..\..\..\libsofia-sip-ua\tport" /I "..\..\..\libsofia-sip-ua\iptsec" /I "..\..\..\libsofia-sip-ua\ipt" /I "..\..\..\libsofia-sip-ua\url" /I "..\..\..\libsofia-sip-ua\nta" /I "..\..\..\libsofia-sip-ua\msg" /I "..\..\..\libsofia-sip-ua\sip" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib advapi32.lib /nologo /subsystem:console /machine:I386
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "sip_options - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /WX /Gm /GX /ZI /Od /I ".." /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /I "..\..\..\libsofia-sip-ua\tport" /I "..\..\..\libsofia-sip-ua\iptsec" /I "..\..\..\libsofia-sip-ua\ipt" /I "..\..\..\libsofia-sip-ua\url" /I "..\..\..\libsofia-sip-ua\nta" /I "..\..\..\libsofia-sip-ua\msg" /I "..\..\..\libsofia-sip-ua\sip" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FD /GZ /c
+# SUBTRACT CPP /YX
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib advapi32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# SUBTRACT LINK32 /pdb:none
+
+!ENDIF
+
+# Begin Target
+
+# Name "sip_options - Win32 Release"
+# Name "sip_options - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE="..\..\..\utils\sip-options.c"
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# Begin Source File
+
+SOURCE=..\..\pthread\pthreadVC2.lib
+# End Source File
+# End Target
+# End Project
Added: freeswitch/trunk/libs/sofia-sip/win32/utils/sip_options_static/sip_options_static.dsp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/utils/sip_options_static/sip_options_static.dsp Thu Dec 21 01:30:28 2006
@@ -0,0 +1,114 @@
+# Microsoft Developer Studio Project File - Name="sip_options_static" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=sip_options_static - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "sip_options_static.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "sip_options_static.mak" CFG="sip_options_static - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "sip_options_static - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "sip_options_static - Win32 Debug" (based on "Win32 (x86) Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "sip_options_static - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /WX /GX /O2 /I ".." /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /I "..\..\..\libsofia-sip-ua\tport" /I "..\..\..\libsofia-sip-ua\iptsec" /I "..\..\..\libsofia-sip-ua\ipt" /I "..\..\..\libsofia-sip-ua\url" /I "..\..\..\libsofia-sip-ua\nta" /I "..\..\..\libsofia-sip-ua\msg" /I "..\..\..\libsofia-sip-ua\sip" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "LIBSOFIA_SIP_UA_STATIC" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib advapi32.lib /nologo /subsystem:console /machine:I386
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "sip_options_static - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /WX /Gm /GX /ZI /Od /I ".." /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /I "..\..\..\libsofia-sip-ua\tport" /I "..\..\..\libsofia-sip-ua\iptsec" /I "..\..\..\libsofia-sip-ua\ipt" /I "..\..\..\libsofia-sip-ua\url" /I "..\..\..\libsofia-sip-ua\nta" /I "..\..\..\libsofia-sip-ua\msg" /I "..\..\..\libsofia-sip-ua\sip" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "LIBSOFIA_SIP_UA_STATIC" /FD /GZ /c
+# SUBTRACT CPP /YX
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib advapi32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# SUBTRACT LINK32 /pdb:none
+
+!ENDIF
+
+# Begin Target
+
+# Name "sip_options_static - Win32 Release"
+# Name "sip_options_static - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE="..\..\..\utils\sip-options.c"
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# Begin Source File
+
+SOURCE=..\..\pthread\pthreadVC2.lib
+# End Source File
+# End Target
+# End Project
Added: freeswitch/trunk/libs/sofia-sip/win32/utils/stunc/stunc.dsp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/utils/stunc/stunc.dsp Thu Dec 21 01:30:28 2006
@@ -0,0 +1,114 @@
+# Microsoft Developer Studio Project File - Name="stunc" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=stunc - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "stunc.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "stunc.mak" CFG="stunc - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "stunc - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "stunc - Win32 Debug" (based on "Win32 (x86) Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "stunc - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /WX /GX /O2 /I ".." /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /I "..\..\..\libsofia-sip-ua\features" /I "..\..\..\libsofia-sip-ua\tport" /I "..\..\..\libsofia-sip-ua\iptsec" /I "..\..\..\libsofia-sip-ua\ipt" /I "..\..\..\libsofia-sip-ua\url" /I "..\..\..\libsofia-sip-ua\nta" /I "..\..\..\libsofia-sip-ua\msg" /I "..\..\..\libsofia-sip-ua\sip" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib advapi32.lib /nologo /subsystem:console /machine:I386
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "stunc - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /WX /Gm /GX /ZI /Od /I ".." /I "..\.." /I "..\..\..\libsofia-sip-ua\su" /I "..\..\..\libsofia-sip-ua\features" /I "..\..\..\libsofia-sip-ua\tport" /I "..\..\..\libsofia-sip-ua\iptsec" /I "..\..\..\libsofia-sip-ua\ipt" /I "..\..\..\libsofia-sip-ua\url" /I "..\..\..\libsofia-sip-ua\nta" /I "..\..\..\libsofia-sip-ua\msg" /I "..\..\..\libsofia-sip-ua\sip" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /FD /GZ /c
+# SUBTRACT CPP /YX
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib ws2_32.lib advapi32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# SUBTRACT LINK32 /pdb:none
+
+!ENDIF
+
+# Begin Target
+
+# Name "stunc - Win32 Release"
+# Name "stunc - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE="..\..\..\libsofia-sip-ua\stun\stunc.c"
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# Begin Source File
+
+SOURCE=..\..\pthread\pthreadVC2.lib
+# End Source File
+# End Target
+# End Project
Added: freeswitch/trunk/libs/sofia-sip/win32/version.awk
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/version.awk Thu Dec 21 01:30:28 2006
@@ -0,0 +1,51 @@
+#! /bin/gawk
+#
+# This script extracts the version information from configure.ac
+# and re-generates win32/config.h and
+# libsofia-sip-ua/features/sofia_sip_features.h
+#
+# --------------------------------------------------------------------
+#
+# This file is part of the Sofia-SIP package
+#
+# Copyright (C) 2005 Nokia Corporation.
+#
+# Contact: Pekka Pessi <pekka.pessi at nokia.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+#
+# --------------------------------------------------------------------
+#
+# Contributor(s): Pekka.Pessi at nokia.com.
+#
+# Created: Wed Jan 25 15:57:10 2006 ppessi
+#
+
+BEGIN { IN=1; OUT=0; }
+
+IN && /^AC_INIT/ { version=$2; gsub(/[\]\[)]/, "", version); }
+
+OUT && /@[A-Z_]+@/ {
+ gsub(/@PACKAGE_VERSION@/, version);
+ gsub(/@PACKAGE_BUGREPORT@/, "sofia-sip-devel at lists.sourceforge.net");
+ gsub(/@PACKAGE_NAME@/, "sofia-sip");
+ gsub(/@PACKAGE@/, "sofia-sip");
+ gsub(/@PACKAGE_STRING@/, "sofia-sip");
+ gsub(/@PACKAGE_TARNAME@/, "sofia-sip");
+}
+
+OUT { print; }
+
Added: freeswitch/trunk/libs/sofia-sip/win32/version_files.cmd
==============================================================================
--- (empty file)
+++ freeswitch/trunk/libs/sofia-sip/win32/version_files.cmd Thu Dec 21 01:30:28 2006
@@ -0,0 +1,45 @@
+::
+:: Generate files usually generated by autoconf
+::
+:: NOTE: this script requires gawk - see http://unxutils.sourceforge.net
+::
+:: This file is part of the Sofia-SIP package
+::
+:: Copyright (C) 2005 Nokia Corporation.
+::
+:: Contact: Pekka Pessi <pekka.pessi at nokia.com>
+::
+:: This library is free software; you can redistribute it and/or
+:: modify it under the terms of the GNU Lesser General Public License
+:: as published by the Free Software Foundation; either version 2.1 of
+:: the License, or (at your option) any later version.
+::
+:: This library is distributed in the hope that it will be useful, but
+:: WITHOUT ANY WARRANTY; without even the implied warranty of
+:: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+:: Lesser General Public License for more details.
+::
+:: You should have received a copy of the GNU Lesser General Public
+:: License along with this library; if not, write to the Free Software
+:: Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+:: 02110-1301 USA
+::
+
+ at setlocal
+ at if x%AWK%==x set AWK=gawk
+ at set VERSION=%AWK% -v BINMODE="rw" -f version.awk
+ at set AC=..\configure.ac
+
+:: Check that we really have awk
+@%AWK% "{ exit(0); }" < NUL >NUL
+ at if not errorlevel 9009 goto have_awk
+ at echo *** install %AWK% (GNU awk) into your PATH ***
+ at goto end
+:have_awk
+
+for %%f in (config.h ..\libsofia-sip-ua\features\sofia-sip\sofia_features.h) ^
+do %VERSION% %AC% OUT=1 %%f.in > %%f
+ at if errorlevel 1 goto echo *** version_files failed ***
+
+:end
+ at endlocal
Modified: freeswitch/trunk/src/mod/endpoints/mod_sofia/Makefile
==============================================================================
--- freeswitch/trunk/src/mod/endpoints/mod_sofia/Makefile (original)
+++ freeswitch/trunk/src/mod/endpoints/mod_sofia/Makefile Thu Dec 21 01:30:28 2006
@@ -1,6 +1,5 @@
OS_ARCH := $(subst /,_,$(shell uname -s | sed /\ /s//_/))
VERSION = sofia-sip-1.12
-TARBALL = sofia-sip-1.12.4.tar.gz
CFLAGS += -I. -I$(PREFIX)/include/$(VERSION)
LDFLAGS += -lsofia-sip-ua
LINKER=$(CC)
@@ -10,7 +9,7 @@
all: depends $(MODNAME).$(DYNAMIC_LIB_EXTEN)
depends:
- MAKE=$(MAKE) $(BASE)/build/buildlib.sh $(BASE) install $(TARBALL) --prefix=$(PREFIX) --with-pic --with-glib=no
+ MAKE=$(MAKE) $(BASE)/build/buildlib.sh $(BASE) install sofia-sip --prefix=$(PREFIX) --with-pic --with-glib=no
%.o: %.c
$(CC) -fPIC $(CFLAGS) -c -o $@ $<
More information about the Freeswitch-svn
mailing list